免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 12136 | 回复: 7

[vpn] 分析pptpd程序中关于执行pptpd和pppd程序的部分源代码 [复制链接]

论坛徽章:
0
发表于 2006-02-10 20:57 |显示全部楼层

PPPD中pap认证部分的代码

PPPD中pap认证部分的代码:


upap.h里的结构,感觉客户端用户名和密码应该保存在这里面,但是还要找是谁把用户名/密码保存进去,以及谁调用了这个结构:
<!--more-->
  1. /*
  2. * Each interface is described by upap structure.
  3. */
  4. typedef struct upap_state {
  5.     int us_unit;                /* Interface unit number */
  6.     char *us_user;                /* User */
  7.     int us_userlen;                /* User length */
  8.     char *us_passwd;                /* Password */
  9.     int us_passwdlen;                /* Password length */
  10.     int us_clientstate;                /* Client state */
  11.     int us_serverstate;                /* Server state */
  12.     u_char us_id;                /* Current id */
  13.     int us_timeouttime;                /* Timeout (seconds) for auth-req retrans. */
  14.     int us_transmits;                /* Number of auth-reqs sent */
  15.     int us_maxtransmits;        /* Maximum number of auth-reqs to send */
  16.     int us_reqtimeout;                /* Time to wait for auth-req from peer */
  17. } upap_state;
复制代码


auth.c的check_passwd()函数,实际证明下来客户端传来的用户名和密码被做为这个函数的参数,即auser和apasswd。
  1. /* check_passwd - Check the user name and passwd against the PAP secrets
  2. * file.  If requested, also check against the system password database,
  3. * and login the user if OK.
  4. *
  5. * returns:
  6. *        UPAP_AUTHNAK: Authentication failed.
  7. *        UPAP_AUTHACK: Authentication succeeded.
  8. * In either case, msg points to an appropriate message. */
  9. int check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
  10.     int unit;
  11.     char *auser;
  12.     int userlen;
  13.     char *apasswd;
  14.     int passwdlen;
  15.     char **msg;
  16. {
  17.     int ret;
  18.     char *filename;
  19.     FILE *f;
  20.     struct wordlist *addrs = NULL, *opts = NULL;
  21.     char passwd[256], user[256];   /* 从这两个数组的定义可以猜到pppd可以接收的用户名和密码的最大长度都是256个字节*/
  22.     char secret[MAXWORDLEN];
  23.     static int attempts = 0;

  24.     /* 下面把用户名和密码复制到user/passwd数组 */
  25.     /*
  26.      * Make copies of apasswd and auser, then null-terminate them.
  27.      * If there are unprintable characters in the password, make
  28.      * them visible.
  29.      */
  30.     slprintf(passwd, sizeof(passwd), "%.*v", passwdlen, apasswd);
  31.     slprintf(user, sizeof(user), "%.*v", userlen, auser);
  32.     *msg = "";

  33.     /* 接下来打开pap认证的密码文件/etc/ppp/pap-secrets,这个文件在_PATH_UPAPFILE中定义 */
  34.     /*
  35.      * Open the file of pap secrets and scan for a suitable secret
  36.      * for authenticating this user.
  37.      */
  38.     filename = _PATH_UPAPFILE;
  39.     addrs = opts = NULL;
  40.     ret = UPAP_AUTHNAK;
  41.     f = fopen(filename, "r");
  42.     if (f == NULL) {
  43.         error("Can't open PAP password file %s: %m", filename);
  44.     } else {
  45.         check_access(f, filename);  /* 检查文件是否可读 */
  46.         if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename, 0) < 0) {  /* 查找文件中是否有某用户的密码 */
  47.             warn("no PAP secret found for %s", user);
  48.         } else {   /* 如果密码字段设置为"@login“,那么就在login database中检查密码,这个login database就是系统的用户/密码文件 */
  49.             /*
  50.              * If the secret is "@login", it means to check
  51.              * the password against the login database.
  52.              */
  53.             int login_secret = strcmp(secret, "@login") == 0;
  54.             ret = UPAP_AUTHACK;
  55.             if (uselogin || login_secret) {
  56.                 /* login option or secret is @login */
  57.                 if ((ret = plogin(user, passwd, msg)) == UPAP_AUTHACK)
  58.                     used_login = 1;
  59.             }
  60.             if (secret[0] != 0 && !login_secret) {
  61.                 /* password given in pap-secrets - must match */
  62.                 if ((cryptpap || strcmp(passwd, secret) != 0)   /* 如果密码不匹配,就设置ret的值为UPAP_AUTHNAK */
  63.                     && strcmp(crypt(passwd, secret), secret) != 0)
  64.                     ret = UPAP_AUTHNAK;
  65.             }
  66.         }
  67.         fclose(f);
  68.     }

  69.     if (ret == UPAP_AUTHNAK) {  /* ret的值为UPAP_AUTHNAK表示登录不成功 */
  70.         if (**msg == 0)
  71.             *msg = "Login incorrect";
  72.         /*
  73.          * XXX can we ever get here more than once??
  74.          * Frustrate passwd stealer programs.
  75.          * Allow 10 tries, but start backing off after 3 (stolen from login).
  76.          * On 10'th, drop the connection.
  77.          */
  78.         if (attempts++ >= 10) {   /* 登录次数超过10次 */
  79.             warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user);
  80.             lcp_close(unit, "login failed");
  81.         }
  82.         if (attempts > 3)
  83.             sleep((u_int) (attempts - 3) * 5);
  84.         if (opts != NULL)
  85.             free_wordlist(opts);

  86.     } else {   /* ret的值不为UPAP_AUTHNAK表示登录成功 */
  87.         attempts = 0;                        /* Reset count */
  88.         if (**msg == 0)
  89.             *msg = "Login ok";
  90.         set_allowed_addrs(unit, addrs, opts);
  91.     }

  92.     if (addrs != NULL)
  93.         free_wordlist(addrs);
  94.     BZERO(passwd, sizeof(passwd));  /* 清空来自客户端的密码 */
  95.     BZERO(secret, sizeof(secret));  /* 清空来自配置文件的密码 */

  96.     return ret;
  97. }
复制代码


upap.c的upap_rauthreq()函数调用了上面的check_passwd()函数,客户端用户名和密码存放在指针inp里:
  1. /* upap_rauth - Receive Authenticate. */
  2. static void
  3. upap_rauthreq(u, inp, id, len)
  4.     upap_state *u;
  5.     u_char *inp;
  6.     int id;
  7.     int len;
  8. {
  9.     u_char ruserlen, rpasswdlen;
  10.     char *ruser, *rpasswd;
  11.     char rhostname[256];
  12.     int retcode;
  13.     char *msg;
  14.     int msglen;

  15.     ......

  16.     GETCHAR(ruserlen, inp);
  17. /*  我觉得很奇怪,ruserlen是u_char,即无符号字符型,但它实际存放的是用户名的长度,为什么不把它设置为int型呢?不知道有谁能解决我的问题?
  18.     GETCHAR()的原型:
  19.         #define GETCHAR(c, cp) { \
  20.                 (c) = *(cp)++; \
  21.         }
  22.     从程序这里判断,给ruserlen赋的值正好是inp指向内存区域的第一个地址,这个地址存放的是一个控制字符,在putty里显示为"^B", 不知道为什么这个值就是用户名长度,我还没想通。
  23. */
  24.     ruser = (char *) inp;   /* 指针ruser指向指针inp指向的地址的第二个字节开始的部分,就是用户名 */
  25.     INCPTR(ruserlen, inp);  /* 指针inp向前移,移的数量就是用户名的长度,相当于把指针移到用户名后面一个字节 */
  26.     GETCHAR(rpasswdlen, inp);  /* 和ruserlen一样,给rpasswdlen赋值,这个值就是密码的长度,也看不懂。。。 */
  27.     if (len < rpasswdlen) {    /* 如果len < rpasswdlen,那么这个数据是不正常的 */
  28.         UPAPDEBUG(("pap_rauth: rcvd short packet."));
  29.         return;
  30.     }
  31.     rpasswd = (char *) inp;  /* rpasswd指向客户端密码 */

  32.     /* Check the username and password given.   */
  33.     /* 调用check_passwd函数检查用户名和密码,ruser是用户名,rpasswd是密码 */
  34.     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
  35.                            rpasswdlen, &msg);
  36.     BZERO(rpasswd, rpasswdlen);
复制代码

调试下来发现参数inp指向的字符串里存放着用户名和密码,例如用户名是st,密码是abcdef,它的存放方式是:
  1. ^Bst^Fabcdef
复制代码

^B和^F是两个控制字符,我觉得它们是用来分隔用户名和密码的。
参数len是两个控制字符(各占一个字节)加用户名及密码的长度的总和。


同文件的upap_input()调用了上面的upap_rauthreq():
  1. /*
  2. * upap_input - Input UPAP packet.
  3. */
  4. static void
  5. upap_input(unit, inpacket, l)
  6.     int unit;
  7.     u_char *inpacket;
  8.     int l;
  9. {
  10.     upap_state *u = &upap[unit];
  11.     u_char *inp;
  12.     u_char code, id;
  13.     int len;
  14.     /*
  15.      * Parse header (code, id and length).
  16.      * If packet too short, drop it.
  17.      */
  18.     inp = inpacket;     /* 把inpacket赋给inp,用户名/密码保存在inpacket中 */

  19.     ......

  20.     switch (code) {
  21.     case UPAP_AUTHREQ:
  22.         upap_rauthreq(u, inp, id, len);   /* 调用upap_rauthreq()函数,并且传递了inp参数 */
  23.         break;
复制代码


没有一个函数显式的调用upap_input()函数,应该是在某个地方通过下面的结构来调用它。

-----------------------------------------------------------

所有和pap认证相关的函数都放在同文件的结构里:
  1. struct protent pap_protent = {
  2.     PPP_PAP,
  3.     upap_init,
  4.     upap_input,  /* 这个函数接收了客户端用户名和密码 */
  5.     upap_protrej,
  6.     upap_lowerup,
  7.     upap_lowerdown,
  8.     NULL,
  9.     NULL,
  10.     upap_printpkt,
  11.     NULL,
  12.     1,
  13.     "PAP",
  14.     NULL,
  15.     pap_option_list,
  16.     NULL,
  17.     NULL,
  18.     NULL
  19. };
复制代码


main.c定义了protocols结构数组:
  1. /*
  2. * PPP Data Link Layer "protocol" table.
  3. * One entry per supported protocol.
  4. * The last entry must be NULL.
  5. */
  6. struct protent *protocols[] = {
  7.     &lcp_protent,
  8.     &pap_protent,    /* pap认证相关结构 */
  9.     &chap_protent,
  10. #ifdef CBCP_SUPPORT
  11.     &cbcp_protent,
  12. #endif
  13.     &ipcp_protent,
  14. #ifdef INET6
  15.     &ipv6cp_protent,
  16. #endif
  17.     &ccp_protent,
  18.     &ecp_protent,
  19. #ifdef IPX_CHANGE
  20.     &ipxcp_protent,
  21. #endif
  22. #ifdef AT_CHANGE
  23.     &atcp_protent,
  24. #endif
  25.     &eap_protent,
  26.     NULL
  27. };
复制代码


接下来,在main()里把protocols结构的值赋给protp结构数组:
  1.     /*
  2.      * Initialize each protocol.
  3.      */
  4.     for (i = 0; (protp = protocols[i]) != NULL; ++i)
  5.         (*protp->init)(0);
复制代码


pppd.h中定义protent结构:
  1. /*
  2. * The following struct gives the addresses of procedures to call
  3. * for a particular protocol.
  4. */
  5. struct protent {
  6.     u_short protocol;                /* PPP protocol number */
  7.     /* Initialization procedure */
  8.     void (*init) __P((int unit));
  9.     /* Process a received packet */
  10.     void (*input) __P((int unit, u_char *pkt, int len));
  11.     /* Process a received protocol-reject */
  12.     void (*protrej) __P((int unit));
  13.     /* Lower layer has come up */
  14.     void (*lowerup) __P((int unit));
  15.     /* Lower layer has gone down */
  16.     void (*lowerdown) __P((int unit));
  17.     /* Open the protocol */
  18.     void (*open) __P((int unit));
  19.     /* Close the protocol */
  20.     void (*close) __P((int unit, char *reason));
  21.     /* Print a packet in readable form */
  22.     int  (*printpkt) __P((u_char *pkt, int len,
  23.                           void (*printer) __P((void *, char *, ...)),
  24.                           void *arg));
  25.     /* Process a received data packet */
  26.     void (*datainput) __P((int unit, u_char *pkt, int len));
  27.     bool enabled_flag;                /* 0 iff protocol is disabled */
  28.     char *name;                        /* Text name of protocol */
  29.     char *data_name;                /* Text name of corresponding data protocol */
  30.     option_t *options;                /* List of command-line options */
  31.     /* Check requested options, assign defaults */
  32.     void (*check_options) __P((void));
  33.     /* Configure interface for demand-dial */
  34.     int  (*demand_conf) __P((int unit));
  35.     /* Say whether to bring up link for this pkt */
  36.     int  (*active_pkt) __P((u_char *pkt, int len));
  37. };
复制代码



-----------------------------------------


upap.c的upap_rauthreq()函数做PAP认证,成功以后调用auth_peer_success()函数:
  1.     if (retcode == UPAP_AUTHACK) {
  2.         u->us_serverstate = UPAPSS_OPEN;
  3.         notice("PAP peer authentication succeeded for %q", rhostname);
  4.         auth_peer_success(u->us_unit, PPP_PAP, 0, ruser, ruserlen);
  5.     } else {
复制代码

上面函数中的u->us_unit:u是fsm结构,us_unit是第一个元素,在fsm.h中定义:
  1. typedef struct fsm {
  2.     int unit;                        /* Interface unit number */
复制代码


auth.c文件下auth_peer_success()函数:
  1. /*
  2. * The peer has been successfully authenticated using `protocol'.
  3. */
  4. void
  5. auth_peer_success(unit, protocol, prot_flavor, name, namelen)
  6.     int unit, protocol, prot_flavor;
  7.     char *name;
  8.     int namelen;
  9. {

  10.     switch (protocol) {

  11.     ......

  12.     case PPP_PAP:    /* 如果使用pap认证方式 */
  13.         bit = PAP_PEER;
  14.         break;

  15.     ......

  16.     /*
  17.      * Save the authenticated name of the peer for later.
  18.      */
  19.     if (namelen > sizeof(peer_authname) - 1)
  20.         namelen = sizeof(peer_authname) - 1;
  21.     BCOPY(name, peer_authname, namelen);   /* 把用户名保存在peer_authname中,以备将来使用,什么地方使用这个变量还没看到 */
  22.     peer_authname[namelen] = 0;
  23.     script_setenv("PEERNAME", peer_authname, 0);

  24.     /* Save the authentication method for later. */
  25.     auth_done[unit] |= bit;

  26.     /*
  27.      * If there is no more authentication still to be done,
  28.      * proceed to the network (or callback) phase.
  29.      */
  30.     if ((auth_pending[unit] &= ~bit) == 0)
  31.         network_phase(unit);
  32. }
复制代码

[ 本帖最后由 sailer_sh 于 2006-2-10 21:48 编辑 ]

论坛徽章:
0
发表于 2006-12-30 13:21 |显示全部楼层
精品   还有继续写吗? 我也在做linux ppp拨号 很多地方还不懂 想学习下

论坛徽章:
0
发表于 2007-01-20 09:06 |显示全部楼层
好好学习下。现在也正在看这个东西呢。

论坛徽章:
1
CU十二周年纪念徽章
日期:2013-10-24 15:41:34
发表于 2008-07-30 11:31 |显示全部楼层
精彩!!!!!

论坛徽章:
0
发表于 2011-04-25 17:11 |显示全部楼层
pppd命令怎么用啊!让它登陆adsl?急求。。

论坛徽章:
0
发表于 2012-11-22 19:09 |显示全部楼层
我在一个车载项目中,使用GPRS和PPPD 出现一些问题,数据接收有问题,请求有偿技术帮助,急急

我的联系:

mail:zhuweizz@126.com

qq:723974437

tel:13502865241
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP