📄 auth.c
字号:
case PPP_EAP: bit = EAP_WITHPEER; prot = "EAP"; break; default: warn("auth_withpeer_success: unknown protocol %x", protocol); bit = 0; } notice("%s authentication succeeded", prot); /* Save the authentication method for later. */ auth_done[unit] |= bit; /* * If there is no more authentication still being done, * proceed to the network (or callback) phase. */ if ((auth_pending[unit] &= ~bit) == 0) network_phase(unit);}/* * np_up - a network protocol has come up. */voidnp_up(unit, proto) int unit, proto;{ int tlim; if (num_np_up == 0) { /* * At this point we consider that the link has come up successfully. */ status = EXIT_OK; unsuccess = 0; new_phase(PHASE_RUNNING); if (idle_time_hook != 0) tlim = (*idle_time_hook)(NULL); else tlim = idle_time_limit; if (tlim > 0) TIMEOUT(check_idle, NULL, tlim); /* * Set a timeout to close the connection once the maximum * connect time has expired. */ if (maxconnect > 0) TIMEOUT(connect_time_expired, 0, maxconnect);#ifdef MAXOCTETS if (maxoctets > 0) TIMEOUT(check_maxoctets, NULL, maxoctets_timeout);#endif /* * Detach now, if the updetach option was given. */ if (updetach && !nodetach) detach(); } ++num_np_up;}/* * np_down - a network protocol has gone down. */voidnp_down(unit, proto) int unit, proto;{ if (--num_np_up == 0) { UNTIMEOUT(check_idle, NULL); UNTIMEOUT(connect_time_expired, NULL);#ifdef MAXOCTETS UNTIMEOUT(check_maxoctets, NULL);#endif new_phase(PHASE_NETWORK); }}/* * np_finished - a network protocol has finished using the link. */voidnp_finished(unit, proto) int unit, proto;{ if (--num_np_open <= 0) { /* no further use for the link: shut up shop. */ lcp_close(0, "No network protocols running"); }}#ifdef MAXOCTETSstatic voidcheck_maxoctets(arg) void *arg;{ int diff; unsigned int used; update_link_stats(ifunit); link_stats_valid=0; switch(maxoctets_dir) { case PPP_OCTETS_DIRECTION_IN: used = link_stats.bytes_in; break; case PPP_OCTETS_DIRECTION_OUT: used = link_stats.bytes_out; break; case PPP_OCTETS_DIRECTION_MAXOVERAL: case PPP_OCTETS_DIRECTION_MAXSESSION: used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out; break; default: used = link_stats.bytes_in+link_stats.bytes_out; break; } diff = maxoctets - used; if(diff < 0) { notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used); status = EXIT_TRAFFIC_LIMIT; lcp_close(0, "Traffic limit"); need_holdoff = 0; } else { TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); }}#endif/* * check_idle - check whether the link has been idle for long * enough that we can shut it down. */static voidcheck_idle(arg) void *arg;{ struct ppp_idle idle; time_t itime; int tlim; if (!get_idle_time(0, &idle)) return; if (idle_time_hook != 0) { tlim = idle_time_hook(&idle); } else { itime = MIN(idle.xmit_idle, idle.recv_idle); tlim = idle_time_limit - itime; } if (tlim <= 0) { /* link is idle: shut it down. */ notice("Terminating connection due to lack of activity."); status = EXIT_IDLE_TIMEOUT; lcp_close(0, "Link inactive"); need_holdoff = 0; } else { TIMEOUT(check_idle, NULL, tlim); }}/* * connect_time_expired - log a message and close the connection. */static voidconnect_time_expired(arg) void *arg;{ info("Connect time expired"); status = EXIT_CONNECT_TIME; lcp_close(0, "Connect time expired"); /* Close connection */}#ifdef INCLUDE/* * auth_check_options - called to check authentication options. */voidauth_check_options(){ lcp_options *wo = &lcp_wantoptions[0]; int can_auth; int lacks_ip; /* Default our_name to hostname, and user to our_name */ if (our_name[0] == 0 || usehostname) strlcpy(our_name, hostname, sizeof(our_name)); if (user[0] == 0) strlcpy(user, our_name, sizeof(user)); /* * If we have a default route, require the peer to authenticate * unless the noauth option was given or the real user is root. */ if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) { auth_required = 1; default_auth = 1; } /* If we selected any CHAP flavors, we should probably negotiate it. :-) */ if (wo->chap_mdtype) wo->neg_chap = 1; /* If authentication is required, ask peer for CHAP, PAP, or EAP. */ if (auth_required) { allow_any_ip = 0; if (!wo->neg_chap && !wo->neg_upap && !wo->neg_eap) { //wo->neg_chap = chap_mdtype_all != MDTYPE_NONE; //wo->chap_mdtype = chap_mdtype_all; wo->neg_upap = 1; wo->neg_eap = 1; } } else { wo->neg_chap = 0; wo->chap_mdtype = MDTYPE_NONE; wo->neg_upap = 0; wo->neg_eap = 0; } /* * Check whether we have appropriate secrets to use * to authenticate the peer. Note that EAP can authenticate by way * of a CHAP-like exchanges as well as SRP. */ lacks_ip = 0; can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip)); if (!can_auth && (wo->neg_chap || wo->neg_eap)) { can_auth = have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, &lacks_ip); } if (!can_auth && wo->neg_eap) { can_auth = have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, &lacks_ip); } if (auth_required && !can_auth && noauth_addrs == NULL) { if (default_auth) { option_error("By default the remote system is required to authenticate itself"); option_error("(because this system has a default route to the internet)"); } else if (explicit_remote) option_error("The remote system (%s) is required to authenticate itself", remote_name); else option_error("The remote system is required to authenticate itself"); option_error("but I couldn't find any suitable secret (password) for it to use to do so."); if (lacks_ip) option_error("(None of the available passwords would let it use an IP address.)"); exit(1); } /* * Early check for remote number authorization. */ if (!auth_number()) { warn("calling number %q is not authorized", remote_number); exit(EXIT_CNID_AUTH_FAILED); }}/* * auth_reset - called when LCP is starting negotiations to recheck * authentication options, i.e. whether we have appropriate secrets * to use for authenticating ourselves and/or the peer. */voidauth_reset(unit) int unit;{ lcp_options *go = &lcp_gotoptions[unit]; lcp_options *ao = &lcp_allowoptions[unit]; int hadchap; hadchap = -1; ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL)); ao->neg_chap = (!refuse_chap || !refuse_mschap || !refuse_mschap_v2) && (passwd[0] != 0 || (hadchap = have_chap_secret(user, (explicit_remote? remote_name: NULL), 0, NULL))); ao->neg_eap = !refuse_eap && ( passwd[0] != 0 || (hadchap == 1 || (hadchap == -1 && have_chap_secret(user, (explicit_remote? remote_name: NULL), 0, NULL))) || have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL)); hadchap = -1; if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) go->neg_upap = 0; if (go->neg_chap) { if (!(hadchap = have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL))) go->neg_chap = 0; } if (go->neg_eap && (hadchap == 0 || (hadchap == -1 && !have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL))) && !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL)) go->neg_eap = 0;}/* * 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. */intcheck_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]; char secret[MAXWORDLEN]; static int attempts = 0; /* * 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 = ""; /* * Check if a plugin wants to handle this. */ if (pap_auth_hook) { ret = (*pap_auth_hook)(user, passwd, msg, &addrs, &opts); if (ret >= 0) { /* note: set_allowed_addrs() saves opts (but not addrs): don't free it! */ if (ret) set_allowed_addrs(unit, addrs, opts); else if (opts != 0) free_wordlist(opts); if (addrs != 0) free_wordlist(addrs); BZERO(passwd, sizeof(passwd)); return ret? UPAP_AUTHACK: UPAP_AUTHNAK; } } /* * 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 { /* * 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) && strcmp(crypt(passwd, secret), secret) != 0) ret = UPAP_AUTHNAK; } } fclose(f); } if (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) { 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 { 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;}/* * This function is needed for PAM. */#ifdef USE_PAM/* Static variables used to communicate between the conversation function * and the server_login function */static char *PAM_username;static char *PAM_password;static int PAM_error = 0;static pam_handle_t *pamh = NULL;/* PAM conversation function * Here we assume (for now, at least) that echo on means login name, and * echo off means password. */static int PAM_conv (int num_msg,#ifndef SOL2 const#endif struct pam_message **msg, struct pam_response **resp, void *appdata_ptr){ int replies = 0; struct pam_response *reply = NULL;#define COPY_STRING(s) (s) ? strdup(s) : NULL reply = malloc(sizeof(struct pam_response) * num_msg); if (!reply) return PAM_CONV_ERR; for (replies = 0; replies < num_msg; replies++) { switch (msg[replies]->msg_style) { case PAM_PROMPT_ECHO_ON: reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = COPY_STRING(PAM_username); /* PAM frees resp */ break; case PAM_PROMPT_ECHO_OFF: reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = COPY_STRING(PAM_password); /* PAM frees resp */ break; case PAM_TEXT_INFO: /* fall through */ case PAM_ERROR_MSG: /* ignore it, but pam still wants a NULL response... */ reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = NULL; break; default: /* Must be an error of some sort... */ free (reply); PAM_error = 1; return PAM_CONV_ERR; } } *resp = reply; return PAM_SUCCESS;}static struct pam_conv PAM_conversation = { &PAM_conv, NULL};#endif /* USE_PAM *//* * plogin - Check the user name and password against the system * password database, and login the user if OK. * * returns: * UPAP_AUTHNAK: Login failed. * UPAP_AUTHACK: Login succeeded.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -