/* * auth.c - PPP authentication and phase control. * * Copyright (c) 1993 The Australian National University. * 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. * * Copyright (c) 1989 Carnegie Mellon University. * 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 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. */ #define RCSID "$Id: auth.c,v 1.1.1.1 2008/10/15 03:30:13 james26_jang Exp $" #include #include #include "pppd.h" #include "fsm.h" #include "lcp.h" #include "ipcp.h" #include "upap.h" #include "chap.h" /* The name by which the peer authenticated itself to us. */ char peer_authname[MAXNAMELEN]; /* Records which authentication operations haven't completed yet. */ static int auth_pending[NUM_PPP]; /* Number of network protocols which we have opened. */ static int num_np_open; /* Number of network protocols which have come up. */ static int num_np_up; /* * Option variables. */ 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 usehostname = 0; /* Use hostname for our_name */ bool auth_required = 0; /* Always require authentication from peer */ bool allow_any_ip = 0; /* Allow peer to use any IP address */ bool explicit_remote = 0; /* User specified explicit remote name */ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ /* Bits in auth_pending[] */ #define PAP_WITHPEER 1 #define PAP_PEER 2 #define CHAP_WITHPEER 4 #define CHAP_PEER 8 /* Prototypes for procedures local to this file. */ static void network_phase __P((int)); static void check_idle __P((void *)); static void connect_time_expired __P((void *)); /* * LCP has terminated the link; go to the Dead phase and take the * physical layer down. */ void link_terminated(unit) int unit; { if (phase == PHASE_DEAD) return; new_phase(PHASE_DEAD); notice("Connection terminated."); } /* * LCP has gone down; it will either die or try to re-establish. */ void link_down(unit) int unit; { int i; struct protent *protp; for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (!protp->enabled_flag) continue; if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) (*protp->lowerdown)(unit); if (protp->protocol < 0xC000 && protp->close != NULL) (*protp->close)(unit, "LCP down"); } num_np_open = 0; num_np_up = 0; if (phase != PHASE_DEAD) new_phase(PHASE_TERMINATE); } /* * The link is established. * Proceed to the Dead, Authenticate or Network phase as appropriate. */ void link_established(unit) int unit; { int auth; lcp_options *ho = &lcp_hisoptions[unit]; int i; struct protent *protp; /* * 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); new_phase(PHASE_AUTHENTICATE); auth = 0; if (ho->neg_chap) { #ifdef CHAP_SUPPORT ChapAuthWithPeer(unit, user, ho->chap_mdtype); auth |= CHAP_WITHPEER; #else error("CHAP unsupported"); #endif } else if (ho->neg_upap) { if (passwd[0] == 0) { error("No secret found for PAP login"); } upap_authwithpeer(unit, user, passwd); auth |= PAP_WITHPEER; } auth_pending[unit] = auth; if (!auth) network_phase(unit); } /* * Proceed to the network phase. */ static void network_phase(unit) int unit; { start_networks(); } void start_networks() { int i; struct protent *protp; new_phase(PHASE_NETWORK); for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { (*protp->open)(0); if (protp->protocol != PPP_CCP) ++num_np_open; } if (num_np_open == 0) /* nothing to do */ lcp_close(0, "No network protocols running"); } /* * The peer has failed to authenticate himself using `protocol'. */ void auth_peer_fail(unit, protocol) int unit, protocol; { /* * Authentication failure: take the link down */ lcp_close(unit, "Authentication failed"); status = EXIT_PEER_AUTH_FAILED; } /* * The peer has been successfully authenticated using `protocol'. */ void auth_peer_success(unit, protocol, name, namelen) int unit, protocol; char *name; int namelen; { int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_PEER; break; case PPP_PAP: bit = PAP_PEER; break; default: warn("auth_peer_success: unknown protocol %x", protocol); return; } /* * Save the authenticated name of the peer for later. */ if (namelen > sizeof(peer_authname) - 1) namelen = sizeof(peer_authname) - 1; BCOPY(name, peer_authname, namelen); peer_authname[namelen] = 0; script_setenv("PEERNAME", peer_authname, 0); /* * If there is no more authentication still to be done, * proceed to the network (or callback) phase. */ if ((auth_pending[unit] &= ~bit) == 0) network_phase(unit); } /* * We have failed to authenticate ourselves to the peer using `protocol'. */ void auth_withpeer_fail(unit, protocol) int unit, protocol; { /* * We've failed to authenticate ourselves to our peer. * 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; } /* * We have successfully authenticated ourselves with the peer using `protocol'. */ void auth_withpeer_success(unit, protocol) int unit, protocol; { int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_WITHPEER; break; case PPP_PAP: bit = PAP_WITHPEER; break; default: warn("auth_withpeer_success: unknown protocol %x", protocol); bit = 0; } /* * 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. */ void np_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); 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); /* * Detach now, if the updetach option was given. */ if (updetach && !nodetach) detach(); } ++num_np_up; } /* * np_down - a network protocol has gone down. */ void np_down(unit, proto) int unit, proto; { if (--num_np_up == 0) { UNTIMEOUT(check_idle, NULL); new_phase(PHASE_NETWORK); } } /* * np_finished - a network protocol has finished using the link. */ void np_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"); } } /* * check_idle - check whether the link has been idle for long * enough that we can shut it down. */ static void check_idle(arg) void *arg; { struct ppp_idle idle; time_t itime; int tlim; if (!get_idle_time(0, &idle)) return; 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."); lcp_close(0, "Link inactive"); need_holdoff = 0; status = EXIT_IDLE_TIMEOUT; } else { TIMEOUT(check_idle, NULL, tlim); } } /* * connect_time_expired - log a message and close the connection. */ static void connect_time_expired(arg) void *arg; { info("Connect time expired"); lcp_close(0, "Connect time expired"); /* Close connection */ status = EXIT_CONNECT_TIME; } /* * 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. */ void auth_reset(unit) int unit; { lcp_options *ao = &lcp_allowoptions[0]; ao->neg_upap = !refuse_pap && (passwd[0] != 0); ao->neg_chap = !refuse_chap && (passwd[0] != 0); } /* * get_secret - open the CHAP secret file and return the secret * for authenticating the given client on the given server. * (We could be either client or server). */ int get_secret(unit, client, server, secret, secret_len, am_server) int unit; char *client; char *server; char *secret; int *secret_len; int am_server; { *secret_len = strlen(passwd); BCOPY(passwd, secret, *secret_len); return 1; } /* * bad_ip_adrs - return 1 if the IP address is one we don't want * to use, such as an address in the loopback net or a multicast address. * addr is in network byte order. */ int bad_ip_adrs(addr) u_int32_t addr; { addr = ntohl(addr); return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || IN_MULTICAST(addr) || IN_BADCLASS(addr); }