/*
* 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. 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.
+ *
+ * 3. 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.89 2002/11/02 19:48:12 carlsonj Exp $"
+#define RCSID "$Id: auth.c,v 1.106 2005/07/13 10:41:58 paulus Exp $"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
+#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include "ecp.h"
#include "ipcp.h"
#include "upap.h"
-#include "chap.h"
+#include "chap-new.h"
#include "eap.h"
#ifdef CBCP_SUPPORT
#include "cbcp.h"
/* Hook for a plugin to get the PAP password for authenticating us */
int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */
+int (*chap_check_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the CHAP password for authenticating us */
+int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
/* Hook for a plugin to say whether it is OK if the peer
refuses to authenticate. */
int (*null_auth_hook) __P((struct wordlist **paddrs,
/* get username */
if (fgets(u, MAXNAMELEN - 1, ufile) == NULL
- || fgets(p, MAXSECRETLEN - 1, ufile) == NULL){
+ || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) {
+ fclose(ufile);
option_error("unable to read user login data file %s", fname);
return 0;
}
/*
* An Open on LCP has requested a change from Dead to Establish phase.
- * Do what's necessary to bring the physical layer up.
*/
void
link_required(unit)
{
}
+/*
+ * Bring the link up to the point of being able to do ppp.
+ */
+void start_link(unit)
+ int unit;
+{
+ char *msg;
+
+ new_phase(PHASE_SERIALCONN);
+
+ devfd = the_channel->connect();
+ msg = "Connect script failed";
+ if (devfd < 0)
+ goto fail;
+
+ /* set up the serial device as a ppp interface */
+ /*
+ * N.B. we used to do tdb_writelock/tdb_writeunlock around this
+ * (from establish_ppp to set_ifunit). However, we won't be
+ * doing the set_ifunit in multilink mode, which is the only time
+ * we need the atomicity that the tdb_writelock/tdb_writeunlock
+ * gives us. Thus we don't need the tdb_writelock/tdb_writeunlock.
+ */
+ fd_ppp = the_channel->establish_ppp(devfd);
+ msg = "ppp establishment failed";
+ if (fd_ppp < 0) {
+ status = EXIT_FATAL_ERROR;
+ goto disconnect;
+ }
+
+ if (!demand && ifunit >= 0)
+ set_ifunit(1);
+
+ /*
+ * Start opening the connection and wait for
+ * incoming events (reply, timeout, etc.).
+ */
+ if (ifunit >= 0)
+ notice("Connect: %s <--> %s", ifname, ppp_devnam);
+ else
+ notice("Starting negotiation on %s", ppp_devnam);
+ add_fd(fd_ppp);
+
+ status = EXIT_NEGOTIATION_FAILED;
+ new_phase(PHASE_ESTABLISH);
+
+ lcp_lowerup(0);
+ return;
+
+ disconnect:
+ new_phase(PHASE_DISCONNECT);
+ if (the_channel->disconnect)
+ the_channel->disconnect();
+
+ fail:
+ new_phase(PHASE_DEAD);
+ if (the_channel->cleanup)
+ (*the_channel->cleanup)();
+}
+
/*
* LCP has terminated the link; go to the Dead phase and take the
* physical layer down.
link_terminated(unit)
int unit;
{
- if (phase == PHASE_DEAD)
+ if (phase == PHASE_DEAD || phase == PHASE_MASTER)
return;
+ new_phase(PHASE_DISCONNECT);
+
if (pap_logout_hook) {
pap_logout_hook();
} else {
if (logged_in)
plogout();
}
- new_phase(PHASE_DEAD);
- notice("Connection terminated.");
+
+ if (!doing_multilink) {
+ notice("Connection terminated.");
+ print_link_stats();
+ } else
+ notice("Link terminated.");
+
+ /*
+ * Delete pid files before disestablishing ppp. Otherwise it
+ * can happen that another pppd gets the same unit and then
+ * we delete its pid file.
+ */
+ if (!doing_multilink && !demand)
+ remove_pidfiles();
+
+ /*
+ * If we may want to bring the link up again, transfer
+ * the ppp unit back to the loopback. Set the
+ * real serial device back to its normal mode of operation.
+ */
+ if (fd_ppp >= 0) {
+ remove_fd(fd_ppp);
+ clean_check();
+ the_channel->disestablish_ppp(devfd);
+ if (doing_multilink)
+ mp_exit_bundle();
+ fd_ppp = -1;
+ }
+ if (!hungup)
+ lcp_lowerdown(0);
+ if (!doing_multilink && !demand)
+ script_unsetenv("IFNAME");
+
+ /*
+ * Run disconnector script, if requested.
+ * XXX we may not be able to do this if the line has hung up!
+ */
+ if (devfd >= 0 && the_channel->disconnect) {
+ the_channel->disconnect();
+ devfd = -1;
+ }
+
+ if (doing_multilink && multilink_master) {
+ if (!bundle_terminating)
+ new_phase(PHASE_MASTER);
+ else
+ mp_bundle_terminated();
+ } else
+ new_phase(PHASE_DEAD);
}
/*
void
link_down(unit)
int unit;
+{
+ if (auth_state != s_down) {
+ notify(link_down_notifier, 0);
+ auth_state = s_down;
+ if (auth_script_state == s_up && auth_script_pid == 0) {
+ update_link_stats(unit);
+ auth_script_state = s_down;
+ auth_script(_PATH_AUTHDOWN);
+ }
+ }
+ if (!doing_multilink) {
+ upper_layers_down(unit);
+ if (phase != PHASE_DEAD && phase != PHASE_MASTER)
+ new_phase(PHASE_ESTABLISH);
+ }
+ /* XXX if doing_multilink, should do something to stop
+ network-layer traffic on the link */
+}
+
+void upper_layers_down(int unit)
{
int i;
struct protent *protp;
- notify(link_down_notifier, 0);
- auth_state = s_down;
- if (auth_script_state == s_up && auth_script_pid == 0) {
- update_link_stats(unit);
- auth_script_state = s_down;
- auth_script(_PATH_AUTHDOWN);
- }
for (i = 0; (protp = protocols[i]) != NULL; ++i) {
if (!protp->enabled_flag)
continue;
}
num_np_open = 0;
num_np_up = 0;
- if (phase != PHASE_DEAD)
- new_phase(PHASE_ESTABLISH);
}
/*
/*
* Tell higher-level protocols that LCP is up.
*/
- for (i = 0; (protp = protocols[i]) != NULL; ++i)
- if (protp->protocol != PPP_LCP && protp->enabled_flag
- && protp->lowerup != NULL)
- (*protp->lowerup)(unit);
+ if (!doing_multilink) {
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol != PPP_LCP && protp->enabled_flag
+ && protp->lowerup != NULL)
+ (*protp->lowerup)(unit);
+ }
+
+ if (!auth_required && noauth_addrs != NULL)
+ set_allowed_addrs(unit, NULL, NULL);
if (auth_required && !(go->neg_upap || go->neg_chap || 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));
+ chap_auth_peer(unit, our_name, CHAP_DIGEST(go->chap_mdtype));
auth |= CHAP_PEER;
} else if (go->neg_upap) {
upap_authpeer(unit);
eap_authwithpeer(unit, user);
auth |= EAP_WITHPEER;
} else if (ho->neg_chap) {
- ChapAuthWithPeer(unit, user, CHAP_DIGEST(ho->chap_mdtype));
+ chap_auth_with_peer(unit, user, CHAP_DIGEST(ho->chap_mdtype));
auth |= CHAP_WITHPEER;
} else if (ho->neg_upap) {
if (passwd[0] == 0) {
case PPP_CHAP:
bit = CHAP_PEER;
switch (prot_flavor) {
- case CHAP_DIGEST_MD5:
+ case CHAP_MD5:
bit |= CHAP_MD5_PEER;
break;
#ifdef CHAPMS
int unit, protocol, prot_flavor;
{
int bit;
+ const char *prot = "";
switch (protocol) {
case PPP_CHAP:
bit = CHAP_WITHPEER;
+ prot = "CHAP";
switch (prot_flavor) {
- case CHAP_DIGEST_MD5:
+ case CHAP_MD5:
bit |= CHAP_MD5_WITHPEER;
break;
#ifdef CHAPMS
if (passwd_from_file)
BZERO(passwd, MAXSECRETLEN);
bit = PAP_WITHPEER;
+ prot = "PAP";
break;
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;
void *arg;
{
info("Connect time expired");
- lcp_close(0, "Connect time expired"); /* Close connection */
status = EXIT_CONNECT_TIME;
+ lcp_close(0, "Connect time expired"); /* Close connection */
}
/*
if (auth_required) {
allow_any_ip = 0;
if (!wo->neg_chap && !wo->neg_upap && !wo->neg_eap) {
- wo->neg_chap = 1; wo->chap_mdtype = MDTYPE_ALL;
+ 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_chap = 0;
+ wo->chap_mdtype = MDTYPE_NONE;
wo->neg_upap = 0;
wo->neg_eap = 0;
}
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);
+ }
}
/*
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);
- BZERO(passwd, sizeof(passwd));
+ else if (opts != 0)
+ free_wordlist(opts);
if (addrs != 0)
free_wordlist(addrs);
- if (opts != 0) {
- free_wordlist(opts);
- }
+ BZERO(passwd, sizeof(passwd));
return ret? UPAP_AUTHACK: UPAP_AUTHNAK;
}
}
static void
plogout()
{
+ char *tty;
#ifdef USE_PAM
int pam_error;
}
/* Apparently the pam stuff does closelog(). */
reopen_log();
-#else /* ! USE_PAM */
- char *tty;
+#endif /* USE_PAM */
tty = devnam;
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
logwtmp(tty, "", ""); /* Wipe out utmp logout entry */
-#endif /* ! USE_PAM */
logged_in = 0;
}
} else {
np = getnetbyname (ptr_word);
if (np != NULL && np->n_addrtype == AF_INET) {
- a = htonl (*(u_int32_t *)np->n_net);
+ a = htonl ((u_int32_t)np->n_net);
if (ptr_mask == NULL) {
/* calculate appropriate mask for net */
ah = ntohl(a);