NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
auth.c
00001 /***************************************************************************** 00002 * auth.c - Network Authentication and Phase Control program file. 00003 * 00004 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. 00005 * Copyright (c) 1997 by Global Election Systems Inc. All rights reserved. 00006 * 00007 * The authors hereby grant permission to use, copy, modify, distribute, 00008 * and license this software and its documentation for any purpose, provided 00009 * that existing copyright notices are retained in all copies and that this 00010 * notice and the following disclaimer are included verbatim in any 00011 * distributions. No written agreement, license, or royalty fee is required 00012 * for any of the authorized uses. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR 00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00017 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00024 * 00025 ****************************************************************************** 00026 * REVISION HISTORY 00027 * 00028 * 03-01-01 Marc Boucher <marc@mbsi.ca> 00029 * Ported to lwIP. 00030 * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. 00031 * Ported from public pppd code. 00032 *****************************************************************************/ 00033 /* 00034 * auth.c - PPP authentication and phase control. 00035 * 00036 * Copyright (c) 1993 The Australian National University. 00037 * All rights reserved. 00038 * 00039 * Redistribution and use in source and binary forms are permitted 00040 * provided that the above copyright notice and this paragraph are 00041 * duplicated in all such forms and that any documentation, 00042 * advertising materials, and other materials related to such 00043 * distribution and use acknowledge that the software was developed 00044 * by the Australian National University. The name of the University 00045 * may not be used to endorse or promote products derived from this 00046 * software without specific prior written permission. 00047 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 00048 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 00049 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00050 * 00051 * Copyright (c) 1989 Carnegie Mellon University. 00052 * All rights reserved. 00053 * 00054 * Redistribution and use in source and binary forms are permitted 00055 * provided that the above copyright notice and this paragraph are 00056 * duplicated in all such forms and that any documentation, 00057 * advertising materials, and other materials related to such 00058 * distribution and use acknowledge that the software was developed 00059 * by Carnegie Mellon University. The name of the 00060 * University may not be used to endorse or promote products derived 00061 * from this software without specific prior written permission. 00062 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 00063 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 00064 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00065 */ 00066 00067 #include "lwip/opt.h" 00068 00069 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ 00070 00071 #include "ppp.h" 00072 #include "pppdebug.h" 00073 00074 #include "fsm.h" 00075 #include "lcp.h" 00076 #include "pap.h" 00077 #include "chap.h" 00078 #include "auth.h" 00079 #include "ipcp.h" 00080 00081 #if CBCP_SUPPORT 00082 #include "cbcp.h" 00083 #endif /* CBCP_SUPPORT */ 00084 00085 #include "lwip/inet.h" 00086 00087 #include <string.h> 00088 00089 #if 0 /* UNUSED */ 00090 /* Bits in scan_authfile return value */ 00091 #define NONWILD_SERVER 1 00092 #define NONWILD_CLIENT 2 00093 00094 #define ISWILD(word) (word[0] == '*' && word[1] == 0) 00095 #endif /* UNUSED */ 00096 00097 #if PAP_SUPPORT || CHAP_SUPPORT 00098 /* The name by which the peer authenticated itself to us. */ 00099 static char peer_authname[MAXNAMELEN]; 00100 #endif /* PAP_SUPPORT || CHAP_SUPPORT */ 00101 00102 /* Records which authentication operations haven't completed yet. */ 00103 static int auth_pending[NUM_PPP]; 00104 00105 /* Set if we have successfully called plogin() */ 00106 static int logged_in; 00107 00108 /* Set if we have run the /etc/ppp/auth-up script. */ 00109 static int did_authup; /* @todo, we don't need this in lwip*/ 00110 00111 /* List of addresses which the peer may use. */ 00112 static struct wordlist *addresses[NUM_PPP]; 00113 00114 #if 0 /* UNUSED */ 00115 /* Wordlist giving addresses which the peer may use 00116 without authenticating itself. */ 00117 static struct wordlist *noauth_addrs; 00118 00119 /* Extra options to apply, from the secrets file entry for the peer. */ 00120 static struct wordlist *extra_options; 00121 #endif /* UNUSED */ 00122 00123 /* Number of network protocols which we have opened. */ 00124 static int num_np_open; 00125 00126 /* Number of network protocols which have come up. */ 00127 static int num_np_up; 00128 00129 #if PAP_SUPPORT || CHAP_SUPPORT 00130 /* Set if we got the contents of passwd[] from the pap-secrets file. */ 00131 static int passwd_from_file; 00132 #endif /* PAP_SUPPORT || CHAP_SUPPORT */ 00133 00134 #if 0 /* UNUSED */ 00135 /* Set if we require authentication only because we have a default route. */ 00136 static bool default_auth; 00137 00138 /* Hook to enable a plugin to control the idle time limit */ 00139 int (*idle_time_hook) __P((struct ppp_idle *)) = NULL; 00140 00141 /* Hook for a plugin to say whether we can possibly authenticate any peer */ 00142 int (*pap_check_hook) __P((void)) = NULL; 00143 00144 /* Hook for a plugin to check the PAP user and password */ 00145 int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp, 00146 struct wordlist **paddrs, 00147 struct wordlist **popts)) = NULL; 00148 00149 /* Hook for a plugin to know about the PAP user logout */ 00150 void (*pap_logout_hook) __P((void)) = NULL; 00151 00152 /* Hook for a plugin to get the PAP password for authenticating us */ 00153 int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL; 00154 00155 /* 00156 * This is used to ensure that we don't start an auth-up/down 00157 * script while one is already running. 00158 */ 00159 enum script_state { 00160 s_down, 00161 s_up 00162 }; 00163 00164 static enum script_state auth_state = s_down; 00165 static enum script_state auth_script_state = s_down; 00166 static pid_t auth_script_pid = 0; 00167 00168 /* 00169 * Option variables. 00170 * lwip: some of these are present in the ppp_settings structure 00171 */ 00172 bool uselogin = 0; /* Use /etc/passwd for checking PAP */ 00173 bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ 00174 bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ 00175 bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ 00176 bool usehostname = 0; /* Use hostname for our_name */ 00177 bool auth_required = 0; /* Always require authentication from peer */ 00178 bool allow_any_ip = 0; /* Allow peer to use any IP address */ 00179 bool explicit_remote = 0; /* User specified explicit remote name */ 00180 char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ 00181 00182 #endif /* UNUSED */ 00183 00184 /* Bits in auth_pending[] */ 00185 #define PAP_WITHPEER 1 00186 #define PAP_PEER 2 00187 #define CHAP_WITHPEER 4 00188 #define CHAP_PEER 8 00189 00190 /* @todo, move this somewhere */ 00191 /* Used for storing a sequence of words. Usually malloced. */ 00192 struct wordlist { 00193 struct wordlist *next; 00194 char word[1]; 00195 }; 00196 00197 00198 extern char *crypt (const char *, const char *); 00199 00200 /* Prototypes for procedures local to this file. */ 00201 00202 static void network_phase (int); 00203 static void check_idle (void *); 00204 static void connect_time_expired (void *); 00205 #if 0 00206 static int plogin (char *, char *, char **, int *); 00207 #endif 00208 static void plogout (void); 00209 static int null_login (int); 00210 static int get_pap_passwd (int, char *, char *); 00211 static int have_pap_secret (void); 00212 static int have_chap_secret (char *, char *, u32_t); 00213 static int ip_addr_check (u32_t, struct wordlist *); 00214 00215 #if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ 00216 static int scan_authfile (FILE *, char *, char *, char *, 00217 struct wordlist **, struct wordlist **, 00218 char *); 00219 static void free_wordlist (struct wordlist *); 00220 static void auth_script (char *); 00221 static void auth_script_done (void *); 00222 static void set_allowed_addrs (int unit, struct wordlist *addrs); 00223 static int some_ip_ok (struct wordlist *); 00224 static int setupapfile (char **); 00225 static int privgroup (char **); 00226 static int set_noauth_addr (char **); 00227 static void check_access (FILE *, char *); 00228 #endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ 00229 00230 #if 0 /* UNUSED */ 00231 /* 00232 * Authentication-related options. 00233 */ 00234 option_t auth_options[] = { 00235 { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, 00236 "Require PAP authentication from peer", 1, &auth_required }, 00237 { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, 00238 "Require PAP authentication from peer", 1, &auth_required }, 00239 { "refuse-pap", o_bool, &refuse_pap, 00240 "Don't agree to auth to peer with PAP", 1 }, 00241 { "-pap", o_bool, &refuse_pap, 00242 "Don't allow PAP authentication with peer", 1 }, 00243 { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap, 00244 "Require CHAP authentication from peer", 1, &auth_required }, 00245 { "+chap", o_bool, &lcp_wantoptions[0].neg_chap, 00246 "Require CHAP authentication from peer", 1, &auth_required }, 00247 { "refuse-chap", o_bool, &refuse_chap, 00248 "Don't agree to auth to peer with CHAP", 1 }, 00249 { "-chap", o_bool, &refuse_chap, 00250 "Don't allow CHAP authentication with peer", 1 }, 00251 { "name", o_string, our_name, 00252 "Set local name for authentication", 00253 OPT_PRIV|OPT_STATIC, NULL, MAXNAMELEN }, 00254 { "user", o_string, user, 00255 "Set name for auth with peer", OPT_STATIC, NULL, MAXNAMELEN }, 00256 { "usehostname", o_bool, &usehostname, 00257 "Must use hostname for authentication", 1 }, 00258 { "remotename", o_string, remote_name, 00259 "Set remote name for authentication", OPT_STATIC, 00260 &explicit_remote, MAXNAMELEN }, 00261 { "auth", o_bool, &auth_required, 00262 "Require authentication from peer", 1 }, 00263 { "noauth", o_bool, &auth_required, 00264 "Don't require peer to authenticate", OPT_PRIV, &allow_any_ip }, 00265 { "login", o_bool, &uselogin, 00266 "Use system password database for PAP", 1 }, 00267 { "papcrypt", o_bool, &cryptpap, 00268 "PAP passwords are encrypted", 1 }, 00269 { "+ua", o_special, (void *)setupapfile, 00270 "Get PAP user and password from file" }, 00271 { "password", o_string, passwd, 00272 "Password for authenticating us to the peer", OPT_STATIC, 00273 NULL, MAXSECRETLEN }, 00274 { "privgroup", o_special, (void *)privgroup, 00275 "Allow group members to use privileged options", OPT_PRIV }, 00276 { "allow-ip", o_special, (void *)set_noauth_addr, 00277 "Set IP address(es) which can be used without authentication", 00278 OPT_PRIV }, 00279 { NULL } 00280 }; 00281 #endif /* UNUSED */ 00282 #if 0 /* UNUSED */ 00283 /* 00284 * setupapfile - specifies UPAP info for authenticating with peer. 00285 */ 00286 static int 00287 setupapfile(char **argv) 00288 { 00289 FILE * ufile; 00290 int l; 00291 00292 lcp_allowoptions[0].neg_upap = 1; 00293 00294 /* open user info file */ 00295 seteuid(getuid()); 00296 ufile = fopen(*argv, "r"); 00297 seteuid(0); 00298 if (ufile == NULL) { 00299 option_error("unable to open user login data file %s", *argv); 00300 return 0; 00301 } 00302 check_access(ufile, *argv); 00303 00304 /* get username */ 00305 if (fgets(user, MAXNAMELEN - 1, ufile) == NULL 00306 || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){ 00307 option_error("unable to read user login data file %s", *argv); 00308 return 0; 00309 } 00310 fclose(ufile); 00311 00312 /* get rid of newlines */ 00313 l = strlen(user); 00314 if (l > 0 && user[l-1] == '\n') 00315 user[l-1] = 0; 00316 l = strlen(passwd); 00317 if (l > 0 && passwd[l-1] == '\n') 00318 passwd[l-1] = 0; 00319 00320 return (1); 00321 } 00322 #endif /* UNUSED */ 00323 00324 #if 0 /* UNUSED */ 00325 /* 00326 * privgroup - allow members of the group to have privileged access. 00327 */ 00328 static int 00329 privgroup(char **argv) 00330 { 00331 struct group *g; 00332 int i; 00333 00334 g = getgrnam(*argv); 00335 if (g == 0) { 00336 option_error("group %s is unknown", *argv); 00337 return 0; 00338 } 00339 for (i = 0; i < ngroups; ++i) { 00340 if (groups[i] == g->gr_gid) { 00341 privileged = 1; 00342 break; 00343 } 00344 } 00345 return 1; 00346 } 00347 #endif 00348 00349 #if 0 /* UNUSED */ 00350 /* 00351 * set_noauth_addr - set address(es) that can be used without authentication. 00352 * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. 00353 */ 00354 static int 00355 set_noauth_addr(char **argv) 00356 { 00357 char *addr = *argv; 00358 int l = strlen(addr); 00359 struct wordlist *wp; 00360 00361 wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l + 1); 00362 if (wp == NULL) 00363 novm("allow-ip argument"); 00364 wp->word = (char *) (wp + 1); 00365 wp->next = noauth_addrs; 00366 BCOPY(addr, wp->word, l); 00367 noauth_addrs = wp; 00368 return 1; 00369 } 00370 #endif /* UNUSED */ 00371 00372 /* 00373 * An Open on LCP has requested a change from Dead to Establish phase. 00374 * Do what's necessary to bring the physical layer up. 00375 */ 00376 void 00377 link_required(int unit) 00378 { 00379 LWIP_UNUSED_ARG(unit); 00380 00381 AUTHDEBUG(LOG_INFO, ("link_required: %d\n", unit)); 00382 } 00383 00384 /* 00385 * LCP has terminated the link; go to the Dead phase and take the 00386 * physical layer down. 00387 */ 00388 void 00389 link_terminated(int unit) 00390 { 00391 AUTHDEBUG(LOG_INFO, ("link_terminated: %d\n", unit)); 00392 if (lcp_phase[unit] == PHASE_DEAD) { 00393 return; 00394 } 00395 if (logged_in) { 00396 plogout(); 00397 } 00398 lcp_phase[unit] = PHASE_DEAD; 00399 AUTHDEBUG(LOG_NOTICE, ("Connection terminated.\n")); 00400 pppLinkTerminated(unit); 00401 } 00402 00403 /* 00404 * LCP has gone down; it will either die or try to re-establish. 00405 */ 00406 void 00407 link_down(int unit) 00408 { 00409 int i; 00410 struct protent *protp; 00411 00412 AUTHDEBUG(LOG_INFO, ("link_down: %d\n", unit)); 00413 00414 if (did_authup) { 00415 /* XXX Do link down processing. */ 00416 did_authup = 0; 00417 } 00418 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { 00419 if (!protp->enabled_flag) { 00420 continue; 00421 } 00422 if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) { 00423 (*protp->lowerdown)(unit); 00424 } 00425 if (protp->protocol < 0xC000 && protp->close != NULL) { 00426 (*protp->close)(unit, "LCP down"); 00427 } 00428 } 00429 num_np_open = 0; /* number of network protocols we have opened */ 00430 num_np_up = 0; /* Number of network protocols which have come up */ 00431 00432 if (lcp_phase[unit] != PHASE_DEAD) { 00433 lcp_phase[unit] = PHASE_TERMINATE; 00434 } 00435 pppLinkDown(unit); 00436 } 00437 00438 /* 00439 * The link is established. 00440 * Proceed to the Dead, Authenticate or Network phase as appropriate. 00441 */ 00442 void 00443 link_established(int unit) 00444 { 00445 int auth; 00446 int i; 00447 struct protent *protp; 00448 lcp_options *wo = &lcp_wantoptions[unit]; 00449 lcp_options *go = &lcp_gotoptions[unit]; 00450 #if PAP_SUPPORT || CHAP_SUPPORT 00451 lcp_options *ho = &lcp_hisoptions[unit]; 00452 #endif /* PAP_SUPPORT || CHAP_SUPPORT */ 00453 00454 AUTHDEBUG(LOG_INFO, ("link_established: unit %d; Lowering up all protocols...\n", unit)); 00455 /* 00456 * Tell higher-level protocols that LCP is up. 00457 */ 00458 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { 00459 if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) { 00460 (*protp->lowerup)(unit); 00461 } 00462 } 00463 if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) { 00464 /* 00465 * We wanted the peer to authenticate itself, and it refused: 00466 * treat it as though it authenticated with PAP using a username 00467 * of "" and a password of "". If that's not OK, boot it out. 00468 */ 00469 if (!wo->neg_upap || !null_login(unit)) { 00470 AUTHDEBUG(LOG_WARNING, ("peer refused to authenticate\n")); 00471 lcp_close(unit, "peer refused to authenticate"); 00472 return; 00473 } 00474 } 00475 00476 lcp_phase[unit] = PHASE_AUTHENTICATE; 00477 auth = 0; 00478 #if CHAP_SUPPORT 00479 if (go->neg_chap) { 00480 ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype); 00481 auth |= CHAP_PEER; 00482 } 00483 #endif /* CHAP_SUPPORT */ 00484 #if PAP_SUPPORT && CHAP_SUPPORT 00485 else 00486 #endif /* PAP_SUPPORT && CHAP_SUPPORT */ 00487 #if PAP_SUPPORT 00488 if (go->neg_upap) { 00489 upap_authpeer(unit); 00490 auth |= PAP_PEER; 00491 } 00492 #endif /* PAP_SUPPORT */ 00493 #if CHAP_SUPPORT 00494 if (ho->neg_chap) { 00495 ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype); 00496 auth |= CHAP_WITHPEER; 00497 } 00498 #endif /* CHAP_SUPPORT */ 00499 #if PAP_SUPPORT && CHAP_SUPPORT 00500 else 00501 #endif /* PAP_SUPPORT && CHAP_SUPPORT */ 00502 #if PAP_SUPPORT 00503 if (ho->neg_upap) { 00504 if (ppp_settings.passwd[0] == 0) { 00505 passwd_from_file = 1; 00506 if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) { 00507 AUTHDEBUG(LOG_ERR, ("No secret found for PAP login\n")); 00508 } 00509 } 00510 upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd); 00511 auth |= PAP_WITHPEER; 00512 } 00513 #endif /* PAP_SUPPORT */ 00514 auth_pending[unit] = auth; 00515 00516 if (!auth) { 00517 network_phase(unit); 00518 } 00519 } 00520 00521 /* 00522 * Proceed to the network phase. 00523 */ 00524 static void 00525 network_phase(int unit) 00526 { 00527 int i; 00528 struct protent *protp; 00529 lcp_options *go = &lcp_gotoptions[unit]; 00530 00531 /* 00532 * If the peer had to authenticate, run the auth-up script now. 00533 */ 00534 if ((go->neg_chap || go->neg_upap) && !did_authup) { 00535 /* XXX Do setup for peer authentication. */ 00536 did_authup = 1; 00537 } 00538 00539 #if CBCP_SUPPORT 00540 /* 00541 * If we negotiated callback, do it now. 00542 */ 00543 if (go->neg_cbcp) { 00544 lcp_phase[unit] = PHASE_CALLBACK; 00545 (*cbcp_protent.open)(unit); 00546 return; 00547 } 00548 #endif /* CBCP_SUPPORT */ 00549 00550 lcp_phase[unit] = PHASE_NETWORK; 00551 for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { 00552 if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { 00553 (*protp->open)(unit); 00554 if (protp->protocol != PPP_CCP) { 00555 ++num_np_open; 00556 } 00557 } 00558 } 00559 00560 if (num_np_open == 0) { 00561 /* nothing to do */ 00562 lcp_close(0, "No network protocols running"); 00563 } 00564 } 00565 /* @todo: add void start_networks(void) here (pppd 2.3.11) */ 00566 00567 /* 00568 * The peer has failed to authenticate himself using `protocol'. 00569 */ 00570 void 00571 auth_peer_fail(int unit, u16_t protocol) 00572 { 00573 LWIP_UNUSED_ARG(protocol); 00574 00575 AUTHDEBUG(LOG_INFO, ("auth_peer_fail: %d proto=%X\n", unit, protocol)); 00576 /* 00577 * Authentication failure: take the link down 00578 */ 00579 lcp_close(unit, "Authentication failed"); 00580 } 00581 00582 00583 #if PAP_SUPPORT || CHAP_SUPPORT 00584 /* 00585 * The peer has been successfully authenticated using `protocol'. 00586 */ 00587 void 00588 auth_peer_success(int unit, u16_t protocol, char *name, int namelen) 00589 { 00590 int pbit; 00591 00592 AUTHDEBUG(LOG_INFO, ("auth_peer_success: %d proto=%X\n", unit, protocol)); 00593 switch (protocol) { 00594 case PPP_CHAP: 00595 pbit = CHAP_PEER; 00596 break; 00597 case PPP_PAP: 00598 pbit = PAP_PEER; 00599 break; 00600 default: 00601 AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol)); 00602 return; 00603 } 00604 00605 /* 00606 * Save the authenticated name of the peer for later. 00607 */ 00608 if (namelen > (int)sizeof(peer_authname) - 1) { 00609 namelen = sizeof(peer_authname) - 1; 00610 } 00611 BCOPY(name, peer_authname, namelen); 00612 peer_authname[namelen] = 0; 00613 00614 /* 00615 * If there is no more authentication still to be done, 00616 * proceed to the network (or callback) phase. 00617 */ 00618 if ((auth_pending[unit] &= ~pbit) == 0) { 00619 network_phase(unit); 00620 } 00621 } 00622 00623 /* 00624 * We have failed to authenticate ourselves to the peer using `protocol'. 00625 */ 00626 void 00627 auth_withpeer_fail(int unit, u16_t protocol) 00628 { 00629 int errCode = PPPERR_AUTHFAIL; 00630 00631 LWIP_UNUSED_ARG(protocol); 00632 00633 AUTHDEBUG(LOG_INFO, ("auth_withpeer_fail: %d proto=%X\n", unit, protocol)); 00634 if (passwd_from_file) { 00635 BZERO(ppp_settings.passwd, MAXSECRETLEN); 00636 } 00637 00638 /* 00639 * We've failed to authenticate ourselves to our peer. 00640 * He'll probably take the link down, and there's not much 00641 * we can do except wait for that. 00642 */ 00643 pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); 00644 lcp_close(unit, "Failed to authenticate ourselves to peer"); 00645 } 00646 00647 /* 00648 * We have successfully authenticated ourselves with the peer using `protocol'. 00649 */ 00650 void 00651 auth_withpeer_success(int unit, u16_t protocol) 00652 { 00653 int pbit; 00654 00655 AUTHDEBUG(LOG_INFO, ("auth_withpeer_success: %d proto=%X\n", unit, protocol)); 00656 switch (protocol) { 00657 case PPP_CHAP: 00658 pbit = CHAP_WITHPEER; 00659 break; 00660 case PPP_PAP: 00661 if (passwd_from_file) { 00662 BZERO(ppp_settings.passwd, MAXSECRETLEN); 00663 } 00664 pbit = PAP_WITHPEER; 00665 break; 00666 default: 00667 AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol)); 00668 pbit = 0; 00669 } 00670 00671 /* 00672 * If there is no more authentication still being done, 00673 * proceed to the network (or callback) phase. 00674 */ 00675 if ((auth_pending[unit] &= ~pbit) == 0) { 00676 network_phase(unit); 00677 } 00678 } 00679 #endif /* PAP_SUPPORT || CHAP_SUPPORT */ 00680 00681 00682 /* 00683 * np_up - a network protocol has come up. 00684 */ 00685 void 00686 np_up(int unit, u16_t proto) 00687 { 00688 LWIP_UNUSED_ARG(unit); 00689 LWIP_UNUSED_ARG(proto); 00690 00691 AUTHDEBUG(LOG_INFO, ("np_up: %d proto=%X\n", unit, proto)); 00692 if (num_np_up == 0) { 00693 AUTHDEBUG(LOG_INFO, ("np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit)); 00694 /* 00695 * At this point we consider that the link has come up successfully. 00696 */ 00697 if (ppp_settings.idle_time_limit > 0) { 00698 TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit); 00699 } 00700 00701 /* 00702 * Set a timeout to close the connection once the maximum 00703 * connect time has expired. 00704 */ 00705 if (ppp_settings.maxconnect > 0) { 00706 TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect); 00707 } 00708 } 00709 ++num_np_up; 00710 } 00711 00712 /* 00713 * np_down - a network protocol has gone down. 00714 */ 00715 void 00716 np_down(int unit, u16_t proto) 00717 { 00718 LWIP_UNUSED_ARG(unit); 00719 LWIP_UNUSED_ARG(proto); 00720 00721 AUTHDEBUG(LOG_INFO, ("np_down: %d proto=%X\n", unit, proto)); 00722 if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) { 00723 UNTIMEOUT(check_idle, NULL); 00724 } 00725 } 00726 00727 /* 00728 * np_finished - a network protocol has finished using the link. 00729 */ 00730 void 00731 np_finished(int unit, u16_t proto) 00732 { 00733 LWIP_UNUSED_ARG(unit); 00734 LWIP_UNUSED_ARG(proto); 00735 00736 AUTHDEBUG(LOG_INFO, ("np_finished: %d proto=%X\n", unit, proto)); 00737 if (--num_np_open <= 0) { 00738 /* no further use for the link: shut up shop. */ 00739 lcp_close(0, "No network protocols running"); 00740 } 00741 } 00742 00743 /* 00744 * check_idle - check whether the link has been idle for long 00745 * enough that we can shut it down. 00746 */ 00747 static void 00748 check_idle(void *arg) 00749 { 00750 struct ppp_idle idle; 00751 u_short itime; 00752 00753 LWIP_UNUSED_ARG(arg); 00754 if (!get_idle_time(0, &idle)) { 00755 return; 00756 } 00757 itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); 00758 if (itime >= ppp_settings.idle_time_limit) { 00759 /* link is idle: shut it down. */ 00760 AUTHDEBUG(LOG_INFO, ("Terminating connection due to lack of activity.\n")); 00761 lcp_close(0, "Link inactive"); 00762 } else { 00763 TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime); 00764 } 00765 } 00766 00767 /* 00768 * connect_time_expired - log a message and close the connection. 00769 */ 00770 static void 00771 connect_time_expired(void *arg) 00772 { 00773 LWIP_UNUSED_ARG(arg); 00774 00775 AUTHDEBUG(LOG_INFO, ("Connect time expired\n")); 00776 lcp_close(0, "Connect time expired"); /* Close connection */ 00777 } 00778 00779 #if 0 /* UNUSED */ 00780 /* 00781 * auth_check_options - called to check authentication options. 00782 */ 00783 void 00784 auth_check_options(void) 00785 { 00786 lcp_options *wo = &lcp_wantoptions[0]; 00787 int can_auth; 00788 ipcp_options *ipwo = &ipcp_wantoptions[0]; 00789 u32_t remote; 00790 00791 /* Default our_name to hostname, and user to our_name */ 00792 if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) { 00793 strcpy(ppp_settings.our_name, ppp_settings.hostname); 00794 } 00795 00796 if (ppp_settings.user[0] == 0) { 00797 strcpy(ppp_settings.user, ppp_settings.our_name); 00798 } 00799 00800 /* If authentication is required, ask peer for CHAP or PAP. */ 00801 if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) { 00802 wo->neg_chap = 1; 00803 wo->neg_upap = 1; 00804 } 00805 00806 /* 00807 * Check whether we have appropriate secrets to use 00808 * to authenticate the peer. 00809 */ 00810 can_auth = wo->neg_upap && have_pap_secret(); 00811 if (!can_auth && wo->neg_chap) { 00812 remote = ipwo->accept_remote? 0: ipwo->hisaddr; 00813 can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote); 00814 } 00815 00816 if (ppp_settings.auth_required && !can_auth) { 00817 ppp_panic("No auth secret"); 00818 } 00819 } 00820 #endif /* UNUSED */ 00821 00822 /* 00823 * auth_reset - called when LCP is starting negotiations to recheck 00824 * authentication options, i.e. whether we have appropriate secrets 00825 * to use for authenticating ourselves and/or the peer. 00826 */ 00827 void 00828 auth_reset(int unit) 00829 { 00830 lcp_options *go = &lcp_gotoptions[unit]; 00831 lcp_options *ao = &lcp_allowoptions[0]; 00832 ipcp_options *ipwo = &ipcp_wantoptions[0]; 00833 u32_t remote; 00834 00835 AUTHDEBUG(LOG_INFO, ("auth_reset: %d\n", unit)); 00836 ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL)); 00837 ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/; 00838 00839 if (go->neg_upap && !have_pap_secret()) { 00840 go->neg_upap = 0; 00841 } 00842 if (go->neg_chap) { 00843 remote = ipwo->accept_remote? 0: ipwo->hisaddr; 00844 if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) { 00845 go->neg_chap = 0; 00846 } 00847 } 00848 } 00849 00850 #if PAP_SUPPORT 00851 /* 00852 * check_passwd - Check the user name and passwd against the PAP secrets 00853 * file. If requested, also check against the system password database, 00854 * and login the user if OK. 00855 * 00856 * returns: 00857 * UPAP_AUTHNAK: Authentication failed. 00858 * UPAP_AUTHACK: Authentication succeeded. 00859 * In either case, msg points to an appropriate message. 00860 */ 00861 u_char 00862 check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen) 00863 { 00864 #if 1 /* XXX Assume all entries OK. */ 00865 LWIP_UNUSED_ARG(unit); 00866 LWIP_UNUSED_ARG(auser); 00867 LWIP_UNUSED_ARG(userlen); 00868 LWIP_UNUSED_ARG(apasswd); 00869 LWIP_UNUSED_ARG(passwdlen); 00870 LWIP_UNUSED_ARG(msglen); 00871 *msg = (char *) 0; 00872 return UPAP_AUTHACK; /* XXX Assume all entries OK. */ 00873 #else 00874 u_char ret = 0; 00875 struct wordlist *addrs = NULL; 00876 char passwd[256], user[256]; 00877 char secret[MAXWORDLEN]; 00878 static u_short attempts = 0; 00879 00880 /* 00881 * Make copies of apasswd and auser, then null-terminate them. 00882 */ 00883 BCOPY(apasswd, passwd, passwdlen); 00884 passwd[passwdlen] = '\0'; 00885 BCOPY(auser, user, userlen); 00886 user[userlen] = '\0'; 00887 *msg = (char *) 0; 00888 00889 /* XXX Validate user name and password. */ 00890 ret = UPAP_AUTHACK; /* XXX Assume all entries OK. */ 00891 00892 if (ret == UPAP_AUTHNAK) { 00893 if (*msg == (char *) 0) { 00894 *msg = "Login incorrect"; 00895 } 00896 *msglen = strlen(*msg); 00897 /* 00898 * Frustrate passwd stealer programs. 00899 * Allow 10 tries, but start backing off after 3 (stolen from login). 00900 * On 10'th, drop the connection. 00901 */ 00902 if (attempts++ >= 10) { 00903 AUTHDEBUG(LOG_WARNING, ("%d LOGIN FAILURES BY %s\n", attempts, user)); 00904 /*ppp_panic("Excess Bad Logins");*/ 00905 } 00906 if (attempts > 3) { 00907 /* @todo: this was sleep(), i.e. seconds, not milliseconds 00908 * I don't think we really need this in lwIP - we would block tcpip_thread! 00909 */ 00910 /*sys_msleep((attempts - 3) * 5);*/ 00911 } 00912 if (addrs != NULL) { 00913 free_wordlist(addrs); 00914 } 00915 } else { 00916 attempts = 0; /* Reset count */ 00917 if (*msg == (char *) 0) { 00918 *msg = "Login ok"; 00919 } 00920 *msglen = strlen(*msg); 00921 set_allowed_addrs(unit, addrs); 00922 } 00923 00924 BZERO(passwd, sizeof(passwd)); 00925 BZERO(secret, sizeof(secret)); 00926 00927 return ret; 00928 #endif 00929 } 00930 #endif /* PAP_SUPPORT */ 00931 00932 #if 0 /* UNUSED */ 00933 /* 00934 * This function is needed for PAM. 00935 */ 00936 00937 #ifdef USE_PAM 00938 00939 /* lwip does not support PAM*/ 00940 00941 #endif /* USE_PAM */ 00942 00943 #endif /* UNUSED */ 00944 00945 00946 #if 0 /* UNUSED */ 00947 /* 00948 * plogin - Check the user name and password against the system 00949 * password database, and login the user if OK. 00950 * 00951 * returns: 00952 * UPAP_AUTHNAK: Login failed. 00953 * UPAP_AUTHACK: Login succeeded. 00954 * In either case, msg points to an appropriate message. 00955 */ 00956 static int 00957 plogin(char *user, char *passwd, char **msg, int *msglen) 00958 { 00959 00960 LWIP_UNUSED_ARG(user); 00961 LWIP_UNUSED_ARG(passwd); 00962 LWIP_UNUSED_ARG(msg); 00963 LWIP_UNUSED_ARG(msglen); 00964 00965 00966 /* The new lines are here align the file when 00967 * compared against the pppd 2.3.11 code */ 00968 00969 00970 00971 00972 00973 00974 00975 00976 00977 00978 00979 00980 00981 00982 00983 00984 /* XXX Fail until we decide that we want to support logins. */ 00985 return (UPAP_AUTHNAK); 00986 } 00987 #endif 00988 00989 00990 00991 /* 00992 * plogout - Logout the user. 00993 */ 00994 static void 00995 plogout(void) 00996 { 00997 logged_in = 0; 00998 } 00999 01000 /* 01001 * null_login - Check if a username of "" and a password of "" are 01002 * acceptable, and iff so, set the list of acceptable IP addresses 01003 * and return 1. 01004 */ 01005 static int 01006 null_login(int unit) 01007 { 01008 LWIP_UNUSED_ARG(unit); 01009 /* XXX Fail until we decide that we want to support logins. */ 01010 return 0; 01011 } 01012 01013 01014 /* 01015 * get_pap_passwd - get a password for authenticating ourselves with 01016 * our peer using PAP. Returns 1 on success, 0 if no suitable password 01017 * could be found. 01018 */ 01019 static int 01020 get_pap_passwd(int unit, char *user, char *passwd) 01021 { 01022 LWIP_UNUSED_ARG(unit); 01023 /* normally we would reject PAP if no password is provided, 01024 but this causes problems with some providers (like CHT in Taiwan) 01025 who incorrectly request PAP and expect a bogus/empty password, so 01026 always provide a default user/passwd of "none"/"none" 01027 01028 @todo: This should be configured by the user, instead of being hardcoded here! 01029 */ 01030 if(user) { 01031 strcpy(user, "none"); 01032 } 01033 if(passwd) { 01034 strcpy(passwd, "none"); 01035 } 01036 return 1; 01037 } 01038 01039 /* 01040 * have_pap_secret - check whether we have a PAP file with any 01041 * secrets that we could possibly use for authenticating the peer. 01042 */ 01043 static int 01044 have_pap_secret(void) 01045 { 01046 /* XXX Fail until we set up our passwords. */ 01047 return 0; 01048 } 01049 01050 /* 01051 * have_chap_secret - check whether we have a CHAP file with a 01052 * secret that we could possibly use for authenticating `client' 01053 * on `server'. Either can be the null string, meaning we don't 01054 * know the identity yet. 01055 */ 01056 static int 01057 have_chap_secret(char *client, char *server, u32_t remote) 01058 { 01059 LWIP_UNUSED_ARG(client); 01060 LWIP_UNUSED_ARG(server); 01061 LWIP_UNUSED_ARG(remote); 01062 01063 /* XXX Fail until we set up our passwords. */ 01064 return 0; 01065 } 01066 #if CHAP_SUPPORT 01067 01068 /* 01069 * get_secret - open the CHAP secret file and return the secret 01070 * for authenticating the given client on the given server. 01071 * (We could be either client or server). 01072 */ 01073 int 01074 get_secret(int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs) 01075 { 01076 #if 1 01077 int len; 01078 struct wordlist *addrs; 01079 01080 LWIP_UNUSED_ARG(unit); 01081 LWIP_UNUSED_ARG(server); 01082 LWIP_UNUSED_ARG(save_addrs); 01083 01084 addrs = NULL; 01085 01086 if(!client || !client[0] || strcmp(client, ppp_settings.user)) { 01087 return 0; 01088 } 01089 01090 len = (int)strlen(ppp_settings.passwd); 01091 if (len > MAXSECRETLEN) { 01092 AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server)); 01093 len = MAXSECRETLEN; 01094 } 01095 01096 BCOPY(ppp_settings.passwd, secret, len); 01097 *secret_len = len; 01098 01099 return 1; 01100 #else 01101 int ret = 0, len; 01102 struct wordlist *addrs; 01103 char secbuf[MAXWORDLEN]; 01104 01105 addrs = NULL; 01106 secbuf[0] = 0; 01107 01108 /* XXX Find secret. */ 01109 if (ret < 0) { 01110 return 0; 01111 } 01112 01113 if (save_addrs) { 01114 set_allowed_addrs(unit, addrs); 01115 } 01116 01117 len = strlen(secbuf); 01118 if (len > MAXSECRETLEN) { 01119 AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server)); 01120 len = MAXSECRETLEN; 01121 } 01122 01123 BCOPY(secbuf, secret, len); 01124 BZERO(secbuf, sizeof(secbuf)); 01125 *secret_len = len; 01126 01127 return 1; 01128 #endif 01129 } 01130 #endif /* CHAP_SUPPORT */ 01131 01132 01133 #if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ 01134 /* 01135 * set_allowed_addrs() - set the list of allowed addresses. 01136 */ 01137 static void 01138 set_allowed_addrs(int unit, struct wordlist *addrs) 01139 { 01140 if (addresses[unit] != NULL) { 01141 free_wordlist(addresses[unit]); 01142 } 01143 addresses[unit] = addrs; 01144 01145 #if 0 01146 /* 01147 * If there's only one authorized address we might as well 01148 * ask our peer for that one right away 01149 */ 01150 if (addrs != NULL && addrs->next == NULL) { 01151 char *p = addrs->word; 01152 struct ipcp_options *wo = &ipcp_wantoptions[unit]; 01153 u32_t a; 01154 struct hostent *hp; 01155 01156 if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) { 01157 hp = gethostbyname(p); 01158 if (hp != NULL && hp->h_addrtype == AF_INET) { 01159 a = *(u32_t *)hp->h_addr; 01160 } else { 01161 a = inet_addr(p); 01162 } 01163 if (a != (u32_t) -1) { 01164 wo->hisaddr = a; 01165 } 01166 } 01167 } 01168 #endif 01169 } 01170 #endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ 01171 01172 /* 01173 * auth_ip_addr - check whether the peer is authorized to use 01174 * a given IP address. Returns 1 if authorized, 0 otherwise. 01175 */ 01176 int 01177 auth_ip_addr(int unit, u32_t addr) 01178 { 01179 return ip_addr_check(addr, addresses[unit]); 01180 } 01181 01182 static int /* @todo: integrate this funtion into auth_ip_addr()*/ 01183 ip_addr_check(u32_t addr, struct wordlist *addrs) 01184 { 01185 /* don't allow loopback or multicast address */ 01186 if (bad_ip_adrs(addr)) { 01187 return 0; 01188 } 01189 01190 if (addrs == NULL) { 01191 return !ppp_settings.auth_required; /* no addresses authorized */ 01192 } 01193 01194 /* XXX All other addresses allowed. */ 01195 return 1; 01196 } 01197 01198 /* 01199 * bad_ip_adrs - return 1 if the IP address is one we don't want 01200 * to use, such as an address in the loopback net or a multicast address. 01201 * addr is in network byte order. 01202 */ 01203 int 01204 bad_ip_adrs(u32_t addr) 01205 { 01206 addr = ntohl(addr); 01207 return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET 01208 || IN_MULTICAST(addr) || IN_BADCLASS(addr); 01209 } 01210 01211 #if 0 /* UNUSED */ /* PAP_SUPPORT || CHAP_SUPPORT */ 01212 /* 01213 * some_ip_ok - check a wordlist to see if it authorizes any 01214 * IP address(es). 01215 */ 01216 static int 01217 some_ip_ok(struct wordlist *addrs) 01218 { 01219 for (; addrs != 0; addrs = addrs->next) { 01220 if (addrs->word[0] == '-') 01221 break; 01222 if (addrs->word[0] != '!') 01223 return 1; /* some IP address is allowed */ 01224 } 01225 return 0; 01226 } 01227 01228 /* 01229 * check_access - complain if a secret file has too-liberal permissions. 01230 */ 01231 static void 01232 check_access(FILE *f, char *filename) 01233 { 01234 struct stat sbuf; 01235 01236 if (fstat(fileno(f), &sbuf) < 0) { 01237 warn("cannot stat secret file %s: %m", filename); 01238 } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { 01239 warn("Warning - secret file %s has world and/or group access", 01240 filename); 01241 } 01242 } 01243 01244 01245 /* 01246 * scan_authfile - Scan an authorization file for a secret suitable 01247 * for authenticating `client' on `server'. The return value is -1 01248 * if no secret is found, otherwise >= 0. The return value has 01249 * NONWILD_CLIENT set if the secret didn't have "*" for the client, and 01250 * NONWILD_SERVER set if the secret didn't have "*" for the server. 01251 * Any following words on the line up to a "--" (i.e. address authorization 01252 * info) are placed in a wordlist and returned in *addrs. Any 01253 * following words (extra options) are placed in a wordlist and 01254 * returned in *opts. 01255 * We assume secret is NULL or points to MAXWORDLEN bytes of space. 01256 */ 01257 static int 01258 scan_authfile(FILE *f, char *client, char *server, char *secret, struct wordlist **addrs, struct wordlist **opts, char *filename) 01259 { 01260 /* We do not (currently) need this in lwip */ 01261 return 0; /* dummy */ 01262 } 01263 /* 01264 * free_wordlist - release memory allocated for a wordlist. 01265 */ 01266 static void 01267 free_wordlist(struct wordlist *wp) 01268 { 01269 struct wordlist *next; 01270 01271 while (wp != NULL) { 01272 next = wp->next; 01273 free(wp); 01274 wp = next; 01275 } 01276 } 01277 01278 /* 01279 * auth_script_done - called when the auth-up or auth-down script 01280 * has finished. 01281 */ 01282 static void 01283 auth_script_done(void *arg) 01284 { 01285 auth_script_pid = 0; 01286 switch (auth_script_state) { 01287 case s_up: 01288 if (auth_state == s_down) { 01289 auth_script_state = s_down; 01290 auth_script(_PATH_AUTHDOWN); 01291 } 01292 break; 01293 case s_down: 01294 if (auth_state == s_up) { 01295 auth_script_state = s_up; 01296 auth_script(_PATH_AUTHUP); 01297 } 01298 break; 01299 } 01300 } 01301 01302 /* 01303 * auth_script - execute a script with arguments 01304 * interface-name peer-name real-user tty speed 01305 */ 01306 static void 01307 auth_script(char *script) 01308 { 01309 char strspeed[32]; 01310 struct passwd *pw; 01311 char struid[32]; 01312 char *user_name; 01313 char *argv[8]; 01314 01315 if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL) 01316 user_name = pw->pw_name; 01317 else { 01318 slprintf(struid, sizeof(struid), "%d", getuid()); 01319 user_name = struid; 01320 } 01321 slprintf(strspeed, sizeof(strspeed), "%d", baud_rate); 01322 01323 argv[0] = script; 01324 argv[1] = ifname; 01325 argv[2] = peer_authname; 01326 argv[3] = user_name; 01327 argv[4] = devnam; 01328 argv[5] = strspeed; 01329 argv[6] = NULL; 01330 01331 auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL); 01332 } 01333 #endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ 01334 #endif /* PPP_SUPPORT */
Generated on Tue Jul 12 2022 11:52:56 by
![doxygen](doxygen.png)