X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fauth.c;h=716d849ae8546a51a0cefc12e5bac2fb44873d78;hp=e26d36af94aefd947d6cfcc1c8d63d54245fcf96;hb=31b4bba68d46b38119fd8620ee09ff7f8831f4b5;hpb=768532f702f8af685d29ed278f352e1c79141112 diff --git a/pppd/auth.c b/pppd/auth.c index e26d36a..716d849 100644 --- a/pppd/auth.c +++ b/pppd/auth.c @@ -32,9 +32,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static char rcsid[] = "$Id: auth.c,v 1.49 1999/03/31 05:39:42 paulus Exp $"; -#endif +#define RCSID "$Id: auth.c,v 1.57 1999/08/13 06:46:10 paulus Exp $" #include #include @@ -78,11 +76,7 @@ static char rcsid[] = "$Id: auth.c,v 1.49 1999/03/31 05:39:42 paulus Exp $"; #endif #include "pathnames.h" -/* Used for storing a sequence of words. Usually malloced. */ -struct wordlist { - struct wordlist *next; - char *word; -}; +static const char rcsid[] = RCSID; /* Bits in scan_authfile return value */ #define NONWILD_SERVER 1 @@ -102,6 +96,9 @@ static int logged_in; /* List of addresses which the peer may use. */ static struct permitted_ip *addresses[NUM_PPP]; +/* Extra options to apply, from the secrets file entry for the peer. */ +static struct wordlist *extra_options; + /* Number of network protocols which we have opened. */ static int num_np_open; @@ -208,6 +205,9 @@ option_t auth_options[] = { "PAP passwords are encrypted", 1 }, { "+ua", o_special, setupapfile, "Get PAP user and password from file" }, + { "password", o_string, passwd, + "Password for authenticating us to the peer", OPT_STATIC, + NULL, MAXSECRETLEN }, { "privgroup", o_special, privgroup, "Allow group members to use privileged options", OPT_PRIV }, { NULL } @@ -367,6 +367,7 @@ link_established(unit) if (!wo->neg_upap || !null_login(unit)) { warn("peer refused to authenticate: terminating link"); lcp_close(unit, "peer refused to authenticate"); + status = EXIT_PEER_AUTH_FAILED; return; } } @@ -405,8 +406,6 @@ static void network_phase(unit) int unit; { - int i; - struct protent *protp; lcp_options *go = &lcp_gotoptions[unit]; /* @@ -431,6 +430,23 @@ network_phase(unit) } #endif + /* + * Process extra options from the secrets file + */ + if (extra_options) { + options_from_list(extra_options, 1); + free_wordlist(extra_options); + extra_options = 0; + } + start_networks(); +} + +void +start_networks() +{ + int i; + struct protent *protp; + phase = PHASE_NETWORK; #if 0 if (!demand) @@ -439,7 +455,7 @@ network_phase(unit) for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { - (*protp->open)(unit); + (*protp->open)(0); if (protp->protocol != PPP_CCP) ++num_np_open; } @@ -460,6 +476,7 @@ auth_peer_fail(unit, protocol) * Authentication failure: take the link down */ lcp_close(unit, "Authentication failed"); + status = EXIT_PEER_AUTH_FAILED; } /* @@ -513,9 +530,12 @@ auth_withpeer_fail(unit, protocol) BZERO(passwd, MAXSECRETLEN); /* * We've failed to authenticate ourselves to our peer. - * He'll probably take the link down, and there's not much - * we can do except wait for that. + * Some servers keep sending CHAP challenges, but there + * is no point in persisting without any way to get updated + * authentication secrets. */ + lcp_close(unit, "Failed to authenticate ourselves to peer"); + status = EXIT_AUTH_TOPEER_FAILED; } /* @@ -561,7 +581,8 @@ np_up(unit, proto) /* * At this point we consider that the link has come up successfully. */ - need_holdoff = 0; + status = EXIT_OK; + unsuccess = 0; if (idle_time_limit > 0) TIMEOUT(check_idle, NULL, idle_time_limit); @@ -623,8 +644,10 @@ check_idle(arg) itime = MIN(idle.xmit_idle, idle.recv_idle); if (itime >= idle_time_limit) { /* link is idle: shut it down. */ - info("Terminating connection due to lack of activity."); + notice("Terminating connection due to lack of activity."); lcp_close(0, "Link inactive"); + need_holdoff = 0; + status = EXIT_IDLE_TIMEOUT; } else { TIMEOUT(check_idle, NULL, idle_time_limit - itime); } @@ -639,6 +662,7 @@ connect_time_expired(arg) { info("Connect time expired"); lcp_close(0, "Connect time expired"); /* Close connection */ + status = EXIT_CONNECT_TIME; } /* @@ -720,8 +744,9 @@ auth_reset(unit) ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL)); ao->neg_chap = !refuse_chap - && have_chap_secret(user, (explicit_remote? remote_name: NULL), - 0, NULL); + && (passwd[0] != 0 + || have_chap_secret(user, (explicit_remote? remote_name: NULL), + 0, NULL)); if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) go->neg_upap = 0; @@ -776,30 +801,34 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) */ filename = _PATH_UPAPFILE; addrs = NULL; - ret = UPAP_AUTHACK; + ret = UPAP_AUTHNAK; f = fopen(filename, "r"); if (f == NULL) { error("Can't open PAP password file %s: %m", filename); - ret = UPAP_AUTHNAK; } else { check_access(f, filename); - if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0 - || (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0) - && strcmp(crypt(passwd, secret), secret) != 0)) { - warn("PAP authentication failure for %s", user); - ret = UPAP_AUTHNAK; + if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0) { + warn("no PAP secret found for %s", user); + } else if (secret[0] != 0) { + /* password given in pap-secrets - must match */ + if ((!cryptpap && strcmp(passwd, secret) == 0) + || strcmp(crypt(passwd, secret), secret) == 0) + ret = UPAP_AUTHACK; + else + warn("PAP authentication failure for %s", user); + } else if (uselogin) { + /* empty password in pap-secrets and login option */ + ret = plogin(user, passwd, msg, msglen); + if (ret == UPAP_AUTHNAK) + warn("PAP login failure for %s", user); + } else { + /* empty password in pap-secrets and login option not used */ + ret = UPAP_AUTHACK; } fclose(f); } - if (uselogin && ret == UPAP_AUTHACK) { - ret = plogin(user, passwd, msg, msglen); - if (ret == UPAP_AUTHNAK) { - warn("PAP login failure for %s", user); - } - } - if (ret == UPAP_AUTHNAK) { if (*msg == (char *) 0) *msg = "Login incorrect"; @@ -1016,7 +1045,7 @@ plogin(user, passwd, msg, msglen) (void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET); memset((void *)&ll, 0, sizeof(ll)); (void)time(&ll.ll_time); - (void)strlcpy(ll.ll_line, tty, sizeof(ll.ll_line)); + (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); (void)write(fd, (char *)&ll, sizeof(ll)); (void)close(fd); } @@ -1213,13 +1242,13 @@ have_chap_secret(client, server, need_ip, lacks_ipp) * (We could be either client or server). */ int -get_secret(unit, client, server, secret, secret_len, save_addrs) +get_secret(unit, client, server, secret, secret_len, am_server) int unit; char *client; char *server; char *secret; int *secret_len; - int save_addrs; + int am_server; { FILE *f; int ret, len; @@ -1227,24 +1256,28 @@ get_secret(unit, client, server, secret, secret_len, save_addrs) struct wordlist *addrs; char secbuf[MAXWORDLEN]; - filename = _PATH_CHAPFILE; - addrs = NULL; - secbuf[0] = 0; - - f = fopen(filename, "r"); - if (f == NULL) { - error("Can't open chap secret file %s: %m", filename); - return 0; - } - check_access(f, filename); + if (!am_server && passwd[0] != 0) { + strlcpy(secbuf, passwd, sizeof(secbuf)); + } else { + filename = _PATH_CHAPFILE; + addrs = NULL; + secbuf[0] = 0; + + f = fopen(filename, "r"); + if (f == NULL) { + error("Can't open chap secret file %s: %m", filename); + return 0; + } + check_access(f, filename); - ret = scan_authfile(f, client, server, secbuf, &addrs, filename); - fclose(f); - if (ret < 0) - return 0; + ret = scan_authfile(f, client, server, secbuf, &addrs, filename); + fclose(f); + if (ret < 0) + return 0; - if (save_addrs) - set_allowed_addrs(unit, addrs); + if (am_server) + set_allowed_addrs(unit, addrs); + } len = strlen(secbuf); if (len > MAXSECRETLEN) { @@ -1260,28 +1293,44 @@ get_secret(unit, client, server, secret, secret_len, save_addrs) /* * set_allowed_addrs() - set the list of allowed addresses. + * Also looks for `--' indicating options to apply for this peer + * and leaves the following words in extra_options. */ static void set_allowed_addrs(unit, addrs) int unit; struct wordlist *addrs; { - int n = 0; - struct wordlist *ap; + int n; + struct wordlist *ap, **pap; struct permitted_ip *ip; char *ptr_word, *ptr_mask; struct hostent *hp; struct netent *np; - u_int32_t a, mask, ah; + u_int32_t a, mask, ah, offset; struct ipcp_options *wo = &ipcp_wantoptions[unit]; u_int32_t suggested_ip = 0; if (addresses[unit] != NULL) free(addresses[unit]); addresses[unit] = NULL; + if (extra_options != NULL) + free_wordlist(extra_options); + extra_options = NULL; - for (ap = addrs; ap != NULL; ap = ap->next) - ++n; + /* + * Count the number of IP addresses given, and chop off + * any extra options for this peer. + */ + for (n = 0, pap = &addrs; (ap = *pap) != NULL; pap = &ap->next, ++n) { + if (strcmp(ap->word, "--") == 0) { + /* rest are options */ + *pap = 0; + extra_options = ap->next; + free(ap); + break; + } + } if (n == 0) return; ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); @@ -1308,18 +1357,29 @@ set_allowed_addrs(unit, addrs) } mask = ~ (u_int32_t) 0; + offset = 0; ptr_mask = strchr (ptr_word, '/'); if (ptr_mask != NULL) { int bit_count; + char *endp; - bit_count = (int) strtol (ptr_mask+1, (char **) 0, 10); + bit_count = (int) strtol (ptr_mask+1, &endp, 10); if (bit_count <= 0 || bit_count > 32) { warn("invalid address length %v in auth. address list", - ptr_mask); + ptr_mask+1); + continue; + } + bit_count = 32 - bit_count; /* # bits in host part */ + if (*endp == '+') { + offset = ifunit + 1; + ++endp; + } + if (*endp != 0) { + warn("invalid address length syntax: %v", ptr_mask+1); continue; } *ptr_mask = '\0'; - mask <<= 32 - bit_count; + mask <<= bit_count; } hp = gethostbyname(ptr_word); @@ -1347,15 +1407,24 @@ set_allowed_addrs(unit, addrs) if (ptr_mask != NULL) *ptr_mask = '/'; - if (a == (u_int32_t)-1L) + if (a == (u_int32_t)-1L) { warn("unknown host %s in auth. address list", ap->word); - else { - ip[n].mask = htonl(mask); - ip[n].base = a & ip[n].mask; - ++n; - if (~mask == 0 && suggested_ip == 0) - suggested_ip = a; + continue; + } + if (offset != 0) { + if (offset >= ~mask) { + warn("interface unit %d too large for subnet %v", + ifunit, ptr_word); + continue; + } + a = htonl((ntohl(a) & mask) + offset); + mask = ~(u_int32_t)0; } + ip[n].mask = htonl(mask); + ip[n].base = a & ip[n].mask; + ++n; + if (~mask == 0 && suggested_ip == 0) + suggested_ip = a; } ip[n].permit = 0; /* make the last entry forbid all addresses */