X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fauth.c;h=a92d9e93be1869de4a0687c1a0dfd019718414d8;hp=cf042686a33557e14fb1f81ce29b83c7a28c787b;hb=a6821a67474c981767ba5c1ca1d1f85a77037c2d;hpb=fd25394d146bb83043189608d30dd0eeb983186d diff --git a/pppd/auth.c b/pppd/auth.c index cf04268..a92d9e9 100644 --- a/pppd/auth.c +++ b/pppd/auth.c @@ -1,38 +1,79 @@ /* * auth.c - PPP authentication and phase control. * - * Copyright (c) 1993 The Australian National University. - * All rights reserved. + * Copyright (c) 1993-2002 Paul Mackerras. All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the Australian National University. The name of the University - * may not be used to endorse or promote products derived from this - * software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Derived from main.c, which is: + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: auth.c,v 1.88 2002/10/27 12:56:26 fcusack Exp $" +#define RCSID "$Id: auth.c,v 1.91 2003/02/16 22:25:49 paulus Exp $" #include #include @@ -74,6 +115,7 @@ #include "ipcp.h" #include "upap.h" #include "chap.h" +#include "eap.h" #ifdef CBCP_SUPPORT #include "cbcp.h" #endif @@ -180,6 +222,7 @@ bool uselogin = 0; /* Use /etc/passwd for checking PAP */ bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ +bool refuse_eap = 0; /* Don't wanna auth. ourselves with EAP */ #ifdef CHAPMS bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */ bool refuse_mschap_v2 = 0; /* Don't wanna auth. ourselves with MS-CHAPv2 */ @@ -208,10 +251,12 @@ static int null_login __P((int)); static int get_pap_passwd __P((char *)); static int have_pap_secret __P((int *)); static int have_chap_secret __P((char *, char *, int, int *)); +static int have_srp_secret __P((char *client, char *server, int need_ip, + int *lacks_ipp)); static int ip_addr_check __P((u_int32_t, struct permitted_ip *)); static int scan_authfile __P((FILE *, char *, char *, char *, struct wordlist **, struct wordlist **, - char *)); + char *, int)); static void free_wordlist __P((struct wordlist *)); static void auth_script __P((char *)); static void auth_script_done __P((void *)); @@ -301,6 +346,12 @@ option_t auth_options[] = { &lcp_allowoptions[0].chap_mdtype }, #endif + { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap, + "Require EAP authentication from peer", OPT_PRIOSUB | 1, + &auth_required }, + { "refuse-eap", o_bool, &refuse_eap, + "Don't agree to authenticate to peer with EAP", 1 }, + { "name", o_string, our_name, "Set local name for authentication", OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN }, @@ -554,7 +605,10 @@ link_established(unit) && protp->lowerup != NULL) (*protp->lowerup)(unit); - if (auth_required && !(go->neg_upap || go->neg_chap)) { + if (!auth_required && noauth_addrs != NULL) + set_allowed_addrs(unit, NULL, NULL) + + if (auth_required && !(go->neg_upap || go->neg_chap || go->neg_eap)) { /* * We wanted the peer to authenticate itself, and it refused: * if we have some address(es) it can use without auth, fine, @@ -575,14 +629,20 @@ link_established(unit) new_phase(PHASE_AUTHENTICATE); used_login = 0; auth = 0; - if (go->neg_chap) { + if (go->neg_eap) { + eap_authpeer(unit, our_name); + auth |= EAP_PEER; + } else if (go->neg_chap) { ChapAuthPeer(unit, our_name, CHAP_DIGEST(go->chap_mdtype)); auth |= CHAP_PEER; } else if (go->neg_upap) { upap_authpeer(unit); auth |= PAP_PEER; } - if (ho->neg_chap) { + if (ho->neg_eap) { + eap_authwithpeer(unit, user); + auth |= EAP_WITHPEER; + } else if (ho->neg_chap) { ChapAuthWithPeer(unit, user, CHAP_DIGEST(ho->chap_mdtype)); auth |= CHAP_WITHPEER; } else if (ho->neg_upap) { @@ -617,7 +677,7 @@ network_phase(unit) /* * If the peer had to authenticate, run the auth-up script now. */ - if (go->neg_chap || go->neg_upap) { + if (go->neg_chap || go->neg_upap || go->neg_eap) { notify(auth_up_notifier, 0); auth_state = s_up; if (auth_script_state == s_down && auth_script_pid == 0) { @@ -755,6 +815,9 @@ auth_peer_success(unit, protocol, prot_flavor, name, namelen) case PPP_PAP: bit = PAP_PEER; break; + case PPP_EAP: + bit = EAP_PEER; + break; default: warn("auth_peer_success: unknown protocol %x", protocol); return; @@ -830,6 +893,9 @@ auth_withpeer_success(unit, protocol, prot_flavor) BZERO(passwd, MAXSECRETLEN); bit = PAP_WITHPEER; break; + case PPP_EAP: + bit = EAP_WITHPEER; + break; default: warn("auth_withpeer_success: unknown protocol %x", protocol); bit = 0; @@ -1032,28 +1098,35 @@ auth_check_options() if (wo->chap_mdtype) wo->neg_chap = 1; - /* If authentication is required, ask peer for CHAP or PAP. */ + /* 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) { + if (!wo->neg_chap && !wo->neg_upap && !wo->neg_eap) { wo->neg_chap = 1; wo->chap_mdtype = 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. + * 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)) { + 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) { @@ -1088,21 +1161,36 @@ auth_reset(unit) int unit; { lcp_options *go = &lcp_gotoptions[unit]; - lcp_options *ao = &lcp_allowoptions[0]; + 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 - || have_chap_secret(user, (explicit_remote? remote_name: NULL), - 0, NULL)); - + && (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 (!have_chap_secret((explicit_remote? remote_name: NULL), - our_name, 1, NULL)) + 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; } @@ -1173,7 +1261,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) } else { check_access(f, filename); - if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename) < 0) { + if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename, 0) < 0) { warn("no PAP secret found for %s", user); } else { /* @@ -1248,8 +1336,12 @@ static pam_handle_t *pamh = NULL; * echo off means password. */ -static int PAM_conv (int num_msg, const struct pam_message **msg, - struct pam_response **resp, void *appdata_ptr) +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; @@ -1486,7 +1578,7 @@ null_login(unit) return 0; check_access(f, filename); - i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename); + i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename, 0); ret = i >= 0 && secret[0] == 0; BZERO(secret, sizeof(secret)); fclose(f); @@ -1534,7 +1626,7 @@ get_pap_passwd(passwd) check_access(f, filename); ret = scan_authfile(f, user, (remote_name[0]? remote_name: NULL), - secret, NULL, NULL, filename); + secret, NULL, NULL, filename, 0); fclose(f); if (ret < 0) return 0; @@ -1571,7 +1663,7 @@ have_pap_secret(lacks_ipp) return 0; ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name, - NULL, &addrs, NULL, filename); + NULL, &addrs, NULL, filename, 0); fclose(f); if (ret >= 0 && !some_ip_ok(addrs)) { if (lacks_ipp != 0) @@ -1620,7 +1712,49 @@ have_chap_secret(client, server, need_ip, lacks_ipp) else if (server != NULL && server[0] == 0) server = NULL; - ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename); + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); + fclose(f); + if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { + if (lacks_ipp != 0) + *lacks_ipp = 1; + ret = -1; + } + if (addrs != 0) + free_wordlist(addrs); + + return ret >= 0; +} + + +/* + * have_srp_secret - check whether we have a SRP file with a + * secret that we could possibly use for authenticating `client' + * on `server'. Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_srp_secret(client, server, need_ip, lacks_ipp) + char *client; + char *server; + int need_ip; + int *lacks_ipp; +{ + FILE *f; + int ret; + char *filename; + struct wordlist *addrs; + + filename = _PATH_SRPFILE; + f = fopen(filename, "r"); + if (f == NULL) + return 0; + + if (client != NULL && client[0] == 0) + client = NULL; + else if (server != NULL && server[0] == 0) + server = NULL; + + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); fclose(f); if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { if (lacks_ipp != 0) @@ -1674,7 +1808,7 @@ get_secret(unit, client, server, secret, secret_len, am_server) } check_access(f, filename); - ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename); + ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename, 0); fclose(f); if (ret < 0) return 0; @@ -1699,6 +1833,56 @@ get_secret(unit, client, server, secret, secret_len, am_server) return 1; } + +/* + * get_srp_secret - open the SRP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int +get_srp_secret(unit, client, server, secret, am_server) + int unit; + char *client; + char *server; + char *secret; + int am_server; +{ + FILE *fp; + int ret; + char *filename; + struct wordlist *addrs, *opts; + + if (!am_server && passwd[0] != '\0') { + strlcpy(secret, passwd, MAXWORDLEN); + } else { + filename = _PATH_SRPFILE; + addrs = NULL; + + fp = fopen(filename, "r"); + if (fp == NULL) { + error("Can't open srp secret file %s: %m", filename); + return 0; + } + check_access(fp, filename); + + secret[0] = '\0'; + ret = scan_authfile(fp, client, server, secret, &addrs, &opts, + filename, am_server); + fclose(fp); + if (ret < 0) + return 0; + + if (am_server) + set_allowed_addrs(unit, addrs, opts); + else if (opts != NULL) + free_wordlist(opts); + if (addrs != NULL) + free_wordlist(addrs); + } + + return 1; +} + /* * set_allowed_addrs() - set the list of allowed addresses. * Also looks for `--' indicating options to apply for this peer @@ -1986,9 +2170,11 @@ check_access(f, filename) * following words (extra options) are placed in a wordlist and * returned in *opts. * We assume secret is NULL or points to MAXWORDLEN bytes of space. + * Flags are non-zero if we need two colons in the secret in order to + * match. */ static int -scan_authfile(f, client, server, secret, addrs, opts, filename) +scan_authfile(f, client, server, secret, addrs, opts, filename, flags) FILE *f; char *client; char *server; @@ -1996,6 +2182,7 @@ scan_authfile(f, client, server, secret, addrs, opts, filename) struct wordlist **addrs; struct wordlist **opts; char *filename; + int flags; { int newline, xxx; int got_flag, best_flag; @@ -2004,6 +2191,7 @@ scan_authfile(f, client, server, secret, addrs, opts, filename) char word[MAXWORDLEN]; char atfile[MAXWORDLEN]; char lsecret[MAXWORDLEN]; + char *cp; if (addrs != NULL) *addrs = NULL; @@ -2062,6 +2250,14 @@ scan_authfile(f, client, server, secret, addrs, opts, filename) if (newline) continue; + /* + * SRP-SHA1 authenticator should never be reading secrets from + * a file. (Authenticatee may, though.) + */ + if (flags && ((cp = strchr(word, ':')) == NULL || + strchr(cp + 1, ':') == NULL)) + continue; + if (secret != NULL) { /* * Special syntax: @/pathname means read secret from file.