- 论坛徽章:
- 0
|
PPPD中pap认证部分的代码
PPPD中pap认证部分的代码:
upap.h里的结构,感觉客户端用户名和密码应该保存在这里面,但是还要找是谁把用户名/密码保存进去,以及谁调用了这个结构:
<!--more-->
- /*
- * Each interface is described by upap structure.
- */
- typedef struct upap_state {
- int us_unit; /* Interface unit number */
- char *us_user; /* User */
- int us_userlen; /* User length */
- char *us_passwd; /* Password */
- int us_passwdlen; /* Password length */
- int us_clientstate; /* Client state */
- int us_serverstate; /* Server state */
- u_char us_id; /* Current id */
- int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */
- int us_transmits; /* Number of auth-reqs sent */
- int us_maxtransmits; /* Maximum number of auth-reqs to send */
- int us_reqtimeout; /* Time to wait for auth-req from peer */
- } upap_state;
复制代码
auth.c的check_passwd()函数,实际证明下来客户端传来的用户名和密码被做为这个函数的参数,即auser和apasswd。
- /* check_passwd - Check the user name and passwd against the PAP secrets
- * file. If requested, also check against the system password database,
- * and login the user if OK.
- *
- * returns:
- * UPAP_AUTHNAK: Authentication failed.
- * UPAP_AUTHACK: Authentication succeeded.
- * In either case, msg points to an appropriate message. */
- int check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
- int unit;
- char *auser;
- int userlen;
- char *apasswd;
- int passwdlen;
- char **msg;
- {
- int ret;
- char *filename;
- FILE *f;
- struct wordlist *addrs = NULL, *opts = NULL;
- char passwd[256], user[256]; /* 从这两个数组的定义可以猜到pppd可以接收的用户名和密码的最大长度都是256个字节*/
- char secret[MAXWORDLEN];
- static int attempts = 0;
- /* 下面把用户名和密码复制到user/passwd数组 */
- /*
- * Make copies of apasswd and auser, then null-terminate them.
- * If there are unprintable characters in the password, make
- * them visible.
- */
- slprintf(passwd, sizeof(passwd), "%.*v", passwdlen, apasswd);
- slprintf(user, sizeof(user), "%.*v", userlen, auser);
- *msg = "";
- /* 接下来打开pap认证的密码文件/etc/ppp/pap-secrets,这个文件在_PATH_UPAPFILE中定义 */
- /*
- * Open the file of pap secrets and scan for a suitable secret
- * for authenticating this user.
- */
- filename = _PATH_UPAPFILE;
- addrs = opts = NULL;
- ret = UPAP_AUTHNAK;
- f = fopen(filename, "r");
- if (f == NULL) {
- error("Can't open PAP password file %s: %m", filename);
- } else {
- check_access(f, filename); /* 检查文件是否可读 */
- if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename, 0) < 0) { /* 查找文件中是否有某用户的密码 */
- warn("no PAP secret found for %s", user);
- } else { /* 如果密码字段设置为"@login“,那么就在login database中检查密码,这个login database就是系统的用户/密码文件 */
- /*
- * If the secret is "@login", it means to check
- * the password against the login database.
- */
- int login_secret = strcmp(secret, "@login") == 0;
- ret = UPAP_AUTHACK;
- if (uselogin || login_secret) {
- /* login option or secret is @login */
- if ((ret = plogin(user, passwd, msg)) == UPAP_AUTHACK)
- used_login = 1;
- }
- if (secret[0] != 0 && !login_secret) {
- /* password given in pap-secrets - must match */
- if ((cryptpap || strcmp(passwd, secret) != 0) /* 如果密码不匹配,就设置ret的值为UPAP_AUTHNAK */
- && strcmp(crypt(passwd, secret), secret) != 0)
- ret = UPAP_AUTHNAK;
- }
- }
- fclose(f);
- }
- if (ret == UPAP_AUTHNAK) { /* ret的值为UPAP_AUTHNAK表示登录不成功 */
- if (**msg == 0)
- *msg = "Login incorrect";
- /*
- * XXX can we ever get here more than once??
- * Frustrate passwd stealer programs.
- * Allow 10 tries, but start backing off after 3 (stolen from login).
- * On 10'th, drop the connection.
- */
- if (attempts++ >= 10) { /* 登录次数超过10次 */
- warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user);
- lcp_close(unit, "login failed");
- }
- if (attempts > 3)
- sleep((u_int) (attempts - 3) * 5);
- if (opts != NULL)
- free_wordlist(opts);
- } else { /* ret的值不为UPAP_AUTHNAK表示登录成功 */
- attempts = 0; /* Reset count */
- if (**msg == 0)
- *msg = "Login ok";
- set_allowed_addrs(unit, addrs, opts);
- }
- if (addrs != NULL)
- free_wordlist(addrs);
- BZERO(passwd, sizeof(passwd)); /* 清空来自客户端的密码 */
- BZERO(secret, sizeof(secret)); /* 清空来自配置文件的密码 */
- return ret;
- }
复制代码
upap.c的upap_rauthreq()函数调用了上面的check_passwd()函数,客户端用户名和密码存放在指针inp里:
- /* upap_rauth - Receive Authenticate. */
- static void
- upap_rauthreq(u, inp, id, len)
- upap_state *u;
- u_char *inp;
- int id;
- int len;
- {
- u_char ruserlen, rpasswdlen;
- char *ruser, *rpasswd;
- char rhostname[256];
- int retcode;
- char *msg;
- int msglen;
- ......
- GETCHAR(ruserlen, inp);
- /* 我觉得很奇怪,ruserlen是u_char,即无符号字符型,但它实际存放的是用户名的长度,为什么不把它设置为int型呢?不知道有谁能解决我的问题?
- GETCHAR()的原型:
- #define GETCHAR(c, cp) { \
- (c) = *(cp)++; \
- }
- 从程序这里判断,给ruserlen赋的值正好是inp指向内存区域的第一个地址,这个地址存放的是一个控制字符,在putty里显示为"^B", 不知道为什么这个值就是用户名长度,我还没想通。
- */
- ruser = (char *) inp; /* 指针ruser指向指针inp指向的地址的第二个字节开始的部分,就是用户名 */
- INCPTR(ruserlen, inp); /* 指针inp向前移,移的数量就是用户名的长度,相当于把指针移到用户名后面一个字节 */
- GETCHAR(rpasswdlen, inp); /* 和ruserlen一样,给rpasswdlen赋值,这个值就是密码的长度,也看不懂。。。 */
- if (len < rpasswdlen) { /* 如果len < rpasswdlen,那么这个数据是不正常的 */
- UPAPDEBUG(("pap_rauth: rcvd short packet."));
- return;
- }
- rpasswd = (char *) inp; /* rpasswd指向客户端密码 */
- /* Check the username and password given. */
- /* 调用check_passwd函数检查用户名和密码,ruser是用户名,rpasswd是密码 */
- retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
- rpasswdlen, &msg);
- BZERO(rpasswd, rpasswdlen);
复制代码
调试下来发现参数inp指向的字符串里存放着用户名和密码,例如用户名是st,密码是abcdef,它的存放方式是:
^B和^F是两个控制字符,我觉得它们是用来分隔用户名和密码的。
参数len是两个控制字符(各占一个字节)加用户名及密码的长度的总和。
同文件的upap_input()调用了上面的upap_rauthreq():
- /*
- * upap_input - Input UPAP packet.
- */
- static void
- upap_input(unit, inpacket, l)
- int unit;
- u_char *inpacket;
- int l;
- {
- upap_state *u = &upap[unit];
- u_char *inp;
- u_char code, id;
- int len;
- /*
- * Parse header (code, id and length).
- * If packet too short, drop it.
- */
- inp = inpacket; /* 把inpacket赋给inp,用户名/密码保存在inpacket中 */
- ......
- switch (code) {
- case UPAP_AUTHREQ:
- upap_rauthreq(u, inp, id, len); /* 调用upap_rauthreq()函数,并且传递了inp参数 */
- break;
复制代码
没有一个函数显式的调用upap_input()函数,应该是在某个地方通过下面的结构来调用它。
-----------------------------------------------------------
所有和pap认证相关的函数都放在同文件的结构里:
- struct protent pap_protent = {
- PPP_PAP,
- upap_init,
- upap_input, /* 这个函数接收了客户端用户名和密码 */
- upap_protrej,
- upap_lowerup,
- upap_lowerdown,
- NULL,
- NULL,
- upap_printpkt,
- NULL,
- 1,
- "PAP",
- NULL,
- pap_option_list,
- NULL,
- NULL,
- NULL
- };
复制代码
main.c定义了protocols结构数组:
- /*
- * PPP Data Link Layer "protocol" table.
- * One entry per supported protocol.
- * The last entry must be NULL.
- */
- struct protent *protocols[] = {
- &lcp_protent,
- &pap_protent, /* pap认证相关结构 */
- &chap_protent,
- #ifdef CBCP_SUPPORT
- &cbcp_protent,
- #endif
- &ipcp_protent,
- #ifdef INET6
- &ipv6cp_protent,
- #endif
- &ccp_protent,
- &ecp_protent,
- #ifdef IPX_CHANGE
- &ipxcp_protent,
- #endif
- #ifdef AT_CHANGE
- &atcp_protent,
- #endif
- &eap_protent,
- NULL
- };
复制代码
接下来,在main()里把protocols结构的值赋给protp结构数组:
- /*
- * Initialize each protocol.
- */
- for (i = 0; (protp = protocols[i]) != NULL; ++i)
- (*protp->init)(0);
复制代码
pppd.h中定义protent结构:
- /*
- * The following struct gives the addresses of procedures to call
- * for a particular protocol.
- */
- struct protent {
- u_short protocol; /* PPP protocol number */
- /* Initialization procedure */
- void (*init) __P((int unit));
- /* Process a received packet */
- void (*input) __P((int unit, u_char *pkt, int len));
- /* Process a received protocol-reject */
- void (*protrej) __P((int unit));
- /* Lower layer has come up */
- void (*lowerup) __P((int unit));
- /* Lower layer has gone down */
- void (*lowerdown) __P((int unit));
- /* Open the protocol */
- void (*open) __P((int unit));
- /* Close the protocol */
- void (*close) __P((int unit, char *reason));
- /* Print a packet in readable form */
- int (*printpkt) __P((u_char *pkt, int len,
- void (*printer) __P((void *, char *, ...)),
- void *arg));
- /* Process a received data packet */
- void (*datainput) __P((int unit, u_char *pkt, int len));
- bool enabled_flag; /* 0 iff protocol is disabled */
- char *name; /* Text name of protocol */
- char *data_name; /* Text name of corresponding data protocol */
- option_t *options; /* List of command-line options */
- /* Check requested options, assign defaults */
- void (*check_options) __P((void));
- /* Configure interface for demand-dial */
- int (*demand_conf) __P((int unit));
- /* Say whether to bring up link for this pkt */
- int (*active_pkt) __P((u_char *pkt, int len));
- };
复制代码
-----------------------------------------
upap.c的upap_rauthreq()函数做PAP认证,成功以后调用auth_peer_success()函数:
- if (retcode == UPAP_AUTHACK) {
- u->us_serverstate = UPAPSS_OPEN;
- notice("PAP peer authentication succeeded for %q", rhostname);
- auth_peer_success(u->us_unit, PPP_PAP, 0, ruser, ruserlen);
- } else {
复制代码
上面函数中的u->us_unit:u是fsm结构,us_unit是第一个元素,在fsm.h中定义:
- typedef struct fsm {
- int unit; /* Interface unit number */
复制代码
auth.c文件下auth_peer_success()函数:
- /*
- * The peer has been successfully authenticated using `protocol'.
- */
- void
- auth_peer_success(unit, protocol, prot_flavor, name, namelen)
- int unit, protocol, prot_flavor;
- char *name;
- int namelen;
- {
- switch (protocol) {
- ......
- case PPP_PAP: /* 如果使用pap认证方式 */
- bit = PAP_PEER;
- break;
- ......
- /*
- * Save the authenticated name of the peer for later.
- */
- if (namelen > sizeof(peer_authname) - 1)
- namelen = sizeof(peer_authname) - 1;
- BCOPY(name, peer_authname, namelen); /* 把用户名保存在peer_authname中,以备将来使用,什么地方使用这个变量还没看到 */
- peer_authname[namelen] = 0;
- script_setenv("PEERNAME", peer_authname, 0);
- /* Save the authentication method for later. */
- auth_done[unit] |= bit;
- /*
- * If there is no more authentication still to be done,
- * proceed to the network (or callback) phase.
- */
- if ((auth_pending[unit] &= ~bit) == 0)
- network_phase(unit);
- }
复制代码
[ 本帖最后由 sailer_sh 于 2006-2-10 21:48 编辑 ] |
|