/*
* 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
+ * <paulus@samba.org>".
+ *
+ * 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.75 2002/03/05 15:14:04 dfs Exp $"
+#define RCSID "$Id: auth.c,v 1.92 2003/02/16 22:29:50 paulus Exp $"
#include <stdio.h>
#include <stddef.h>
#include <sys/socket.h>
#include <utmp.h>
#include <fcntl.h>
-#if defined(_PATH_LASTLOG) && defined(_linux_)
+#if defined(_PATH_LASTLOG) && defined(__linux__)
#include <lastlog.h>
#endif
#include "pppd.h"
#include "fsm.h"
#include "lcp.h"
+#include "ccp.h"
+#include "ecp.h"
#include "ipcp.h"
#include "upap.h"
#include "chap.h"
+#include "eap.h"
#ifdef CBCP_SUPPORT
#include "cbcp.h"
#endif
/* Records which authentication operations haven't completed yet. */
static int auth_pending[NUM_PPP];
+/* Records which authentication operations have been completed. */
+int auth_done[NUM_PPP];
+
/* Set if we have successfully called plogin() */
static int logged_in;
without authenticating itself. */
static struct wordlist *noauth_addrs;
+/* Remote telephone number, if available */
+char remote_number[MAXNAMELEN];
+
+/* Wordlist giving remote telephone numbers which may connect. */
+static struct wordlist *permitted_numbers;
+
/* Extra options to apply, from the secrets file entry for the peer. */
static struct wordlist *extra_options;
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 */
static char *uafname; /* name of most recent +ua file */
-/* Bits in auth_pending[] */
-#define PAP_WITHPEER 1
-#define PAP_PEER 2
-#define CHAP_WITHPEER 4
-#define CHAP_PEER 8
-
extern char *crypt __P((const char *, const char *));
/* Prototypes for procedures local to this file. */
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 *));
static int setupapfile __P((char **));
static int privgroup __P((char **));
static int set_noauth_addr __P((char **));
+static int set_permitted_number __P((char **));
static void check_access __P((FILE *, char *));
static int wordlist_count __P((struct wordlist *));
+#ifdef MAXOCTETS
+static void check_maxoctets __P((void *));
+#endif
+
/*
* Authentication-related options.
*/
{ "auth", o_bool, &auth_required,
"Require authentication from peer", OPT_PRIO | 1 },
{ "noauth", o_bool, &auth_required,
- "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV | OPT_A2COPY,
+ "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
&allow_any_ip },
{ "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
"Require PAP authentication from peer",
- OPT_PRIOSUB | OPT_A2COPY | 1, &auth_required },
+ OPT_PRIOSUB | 1, &auth_required },
{ "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
"Require PAP authentication from peer",
- OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | 1, &auth_required },
- { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
+ OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+ { "require-chap", o_bool, &auth_required,
"Require CHAP authentication from peer",
- OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MD5,
- &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
- { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
+ OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "+chap", o_bool, &auth_required,
"Require CHAP authentication from peer",
- OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MD5,
- &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
+ &lcp_wantoptions[0].chap_mdtype },
#ifdef CHAPMS
- { "require-mschap", o_bool, &lcp_wantoptions[0].neg_chap,
+ { "require-mschap", o_bool, &auth_required,
"Require MS-CHAP authentication from peer",
- OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT,
- &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
- { "+mschap", o_bool, &lcp_wantoptions[0].neg_chap,
+ OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "+mschap", o_bool, &auth_required,
"Require MS-CHAP authentication from peer",
- OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT,
- &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
- { "require-mschap-v2", o_bool, &lcp_wantoptions[0].neg_chap,
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "require-mschap-v2", o_bool, &auth_required,
"Require MS-CHAPv2 authentication from peer",
- OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT_V2,
- &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
- { "+mschap-v2", o_bool, &lcp_wantoptions[0].neg_chap,
+ OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "+mschap-v2", o_bool, &auth_required,
"Require MS-CHAPv2 authentication from peer",
- OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT_V2,
- &auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
+ &lcp_wantoptions[0].chap_mdtype },
#endif
{ "refuse-pap", o_bool, &refuse_pap,
{ "-pap", o_bool, &refuse_pap,
"Don't allow PAP authentication with peer", OPT_ALIAS | 1 },
{ "refuse-chap", o_bool, &refuse_chap,
- "Don't agree to auth to peer with CHAP", OPT_A2CLRB | MDTYPE_MD5,
+ "Don't agree to auth to peer with CHAP",
+ OPT_A2CLRB | MDTYPE_MD5,
&lcp_allowoptions[0].chap_mdtype },
{ "-chap", o_bool, &refuse_chap,
"Don't allow CHAP authentication with peer",
#ifdef CHAPMS
{ "refuse-mschap", o_bool, &refuse_mschap,
"Don't agree to auth to peer with MS-CHAP",
- OPT_A2CLRB | MDTYPE_MICROSOFT, &lcp_allowoptions[0].chap_mdtype },
+ OPT_A2CLRB | MDTYPE_MICROSOFT,
+ &lcp_allowoptions[0].chap_mdtype },
{ "-mschap", o_bool, &refuse_mschap,
"Don't allow MS-CHAP authentication with peer",
OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
&lcp_allowoptions[0].chap_mdtype },
{ "refuse-mschap-v2", o_bool, &refuse_mschap_v2,
"Don't agree to auth to peer with MS-CHAPv2",
- OPT_A2CLRB | MDTYPE_MICROSOFT_V2, &lcp_allowoptions[0].chap_mdtype },
+ OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
+ &lcp_allowoptions[0].chap_mdtype },
{ "-mschap-v2", o_bool, &refuse_mschap_v2,
"Don't allow MS-CHAPv2 authentication with peer",
OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
&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 },
"Set IP address(es) which can be used without authentication",
OPT_PRIV | OPT_A2LIST },
+ { "remotenumber", o_string, remote_number,
+ "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC,
+ NULL, MAXNAMELEN },
+
+ { "allow-number", o_special, (void *)set_permitted_number,
+ "Set telephone number(s) which are allowed to connect",
+ OPT_PRIV | OPT_A2LIST },
+
{ NULL }
};
}
+/*
+ * set_permitted_number - set remote telephone number(s) that may connect.
+ */
+static int
+set_permitted_number(argv)
+ char **argv;
+{
+ char *number = *argv;
+ int l = strlen(number) + 1;
+ struct wordlist *wp;
+
+ wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l);
+ if (wp == NULL)
+ novm("allow-number argument");
+ wp->word = (char *) (wp + 1);
+ wp->next = permitted_numbers;
+ BCOPY(number, wp->word, l);
+ permitted_numbers = wp;
+ return 1;
+}
+
+
/*
* An Open on LCP has requested a change from Dead to Establish phase.
* Do what's necessary to bring the physical layer up.
&& 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,
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) {
auth |= PAP_WITHPEER;
}
auth_pending[unit] = auth;
+ auth_done[unit] = 0;
if (!auth)
network_phase(unit);
{
lcp_options *go = &lcp_gotoptions[unit];
+ /* Log calling number. */
+ if (*remote_number)
+ notice("peer from calling number %q authorized", remote_number);
+
/*
* 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) {
free_wordlist(extra_options);
extra_options = 0;
}
- start_networks();
+ start_networks(unit);
}
void
-start_networks()
+start_networks(unit)
+ int unit;
{
int i;
struct protent *protp;
+ int ecp_required, mppe_required;
new_phase(PHASE_NETWORK);
if (!demand)
set_filters(&pass_filter, &active_filter);
#endif
+ /* Start CCP and ECP */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if ((protp->protocol == PPP_ECP || protp->protocol == PPP_CCP)
+ && protp->enabled_flag && protp->open != NULL)
+ (*protp->open)(0);
+
+ /*
+ * Bring up other network protocols iff encryption is not required.
+ */
+ ecp_required = ecp_gotoptions[unit].required;
+ mppe_required = ccp_gotoptions[unit].mppe;
+ if (!ecp_required && !mppe_required)
+ continue_networks(unit);
+}
+
+void
+continue_networks(unit)
+ int unit;
+{
+ int i;
+ struct protent *protp;
+
+ /*
+ * Start the "real" network protocols.
+ */
for (i = 0; (protp = protocols[i]) != NULL; ++i)
- if (protp->protocol < 0xC000 && protp->enabled_flag
- && protp->open != NULL) {
+ if (protp->protocol < 0xC000
+ && protp->protocol != PPP_CCP && protp->protocol != PPP_ECP
+ && protp->enabled_flag && protp->open != NULL) {
(*protp->open)(0);
- if (protp->protocol != PPP_CCP)
- ++num_np_open;
+ ++num_np_open;
}
if (num_np_open == 0)
* The peer has been successfully authenticated using `protocol'.
*/
void
-auth_peer_success(unit, protocol, name, namelen)
- int unit, protocol;
+auth_peer_success(unit, protocol, prot_flavor, name, namelen)
+ int unit, protocol, prot_flavor;
char *name;
int namelen;
{
switch (protocol) {
case PPP_CHAP:
bit = CHAP_PEER;
+ switch (prot_flavor) {
+ case CHAP_DIGEST_MD5:
+ bit |= CHAP_MD5_PEER;
+ break;
+#ifdef CHAPMS
+ case CHAP_MICROSOFT:
+ bit |= CHAP_MS_PEER;
+ break;
+ case CHAP_MICROSOFT_V2:
+ bit |= CHAP_MS2_PEER;
+ break;
+#endif
+ }
break;
case PPP_PAP:
bit = PAP_PEER;
break;
+ case PPP_EAP:
+ bit = EAP_PEER;
+ break;
default:
warn("auth_peer_success: unknown protocol %x", protocol);
return;
peer_authname[namelen] = 0;
script_setenv("PEERNAME", peer_authname, 0);
+ /* Save the authentication method for later. */
+ auth_done[unit] |= bit;
+
/*
* If there is no more authentication still to be done,
* proceed to the network (or callback) phase.
* We have successfully authenticated ourselves with the peer using `protocol'.
*/
void
-auth_withpeer_success(unit, protocol)
- int unit, protocol;
+auth_withpeer_success(unit, protocol, prot_flavor)
+ int unit, protocol, prot_flavor;
{
int bit;
switch (protocol) {
case PPP_CHAP:
bit = CHAP_WITHPEER;
+ switch (prot_flavor) {
+ case CHAP_DIGEST_MD5:
+ bit |= CHAP_MD5_WITHPEER;
+ break;
+#ifdef CHAPMS
+ case CHAP_MICROSOFT:
+ bit |= CHAP_MS_WITHPEER;
+ break;
+ case CHAP_MICROSOFT_V2:
+ bit |= CHAP_MS2_WITHPEER;
+ break;
+#endif
+ }
break;
case PPP_PAP:
if (passwd_from_file)
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;
}
+ /* 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 (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 (--num_np_up == 0) {
UNTIMEOUT(check_idle, NULL);
UNTIMEOUT(connect_time_expired, NULL);
+#ifdef MAXOCTETS
+ UNTIMEOUT(check_maxoctets, NULL);
+#endif
new_phase(PHASE_NETWORK);
}
}
}
}
+#ifdef MAXOCTETS
+static void
+check_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);
+ lcp_close(0, "Traffic limit");
+ need_holdoff = 0;
+ status = EXIT_TRAFFIC_LIMIT;
+ } 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.
default_auth = 1;
}
- /* If authentication is required, ask peer for CHAP or PAP. */
+ /* 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) {
+ 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) {
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;
}
} 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 {
/*
ret = UPAP_AUTHACK;
if (uselogin || login_secret) {
/* login option or secret is @login */
- ret = plogin(user, passwd, msg);
- if (ret == UPAP_AUTHNAK)
- warn("PAP login failure for %s", user);
- else
+ 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) {
+ && strcmp(crypt(passwd, secret), secret) != 0)
ret = UPAP_AUTHNAK;
- warn("PAP authentication failure for %s", user);
- }
}
}
fclose(f);
* 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;
tty = devnam;
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
- logwtmp(tty, user, remote_name); /* Add wtmp login entry */
+ logwtmp(tty, user, ifname); /* Add wtmp login entry */
#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
if (pw != (struct passwd *)NULL) {
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);
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;
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)
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)
}
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;
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
return 0;
}
+/*
+ * auth_number - check whether the remote number is allowed to connect.
+ * Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_number()
+{
+ struct wordlist *wp = permitted_numbers;
+ int l;
+
+ /* Allow all if no authorization list. */
+ if (!wp)
+ return 1;
+
+ /* Allow if we have a match in the authorization list. */
+ while (wp) {
+ /* trailing '*' wildcard */
+ l = strlen(wp->word);
+ if ((wp->word)[l - 1] == '*')
+ l--;
+ if (!strncasecmp(wp->word, remote_number, l))
+ return 1;
+ wp = wp->next;
+ }
+
+ return 0;
+}
+
/*
* check_access - complain if a secret file has too-liberal permissions.
*/
* 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;
struct wordlist **addrs;
struct wordlist **opts;
char *filename;
+ int flags;
{
int newline, xxx;
int got_flag, best_flag;
char word[MAXWORDLEN];
char atfile[MAXWORDLEN];
char lsecret[MAXWORDLEN];
+ char *cp;
if (addrs != NULL)
*addrs = NULL;
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.