| /* |
| * 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 2008-08-04 06:11:52 winfred Exp $" |
| |
| #include <string.h> |
| #include <netinet/in.h> |
| |
| #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); |
| } |