]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
This enables plugins called via hooks/notifiers triggered
[ppp.git] / pppd / auth.c
index 9a5e17e97b3d3b894429b132793ae0f729f5ea01..8e1180ddaa49c7894051e95c08a9fe048890cecf 100644 (file)
  * 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(s) of the authors of this software must not be used to
+ * 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.
  *
- * 4. Redistributions of any form whatsoever must retain the following
+ * 3. Redistributions of any form whatsoever must retain the following
  *    acknowledgment:
  *    "This product includes software developed by Paul Mackerras
  *     <paulus@samba.org>".
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: auth.c,v 1.96 2004/10/24 23:26:19 paulus Exp $"
+#define RCSID  "$Id: auth.c,v 1.109 2006/05/22 00:04:07 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>
@@ -530,7 +526,6 @@ set_permitted_number(argv)
 
 /*
  * 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)
@@ -538,6 +533,66 @@ 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.
@@ -546,16 +601,67 @@ void
 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 (the_channel->cleanup)
+       (*the_channel->cleanup)();
+
+    if (doing_multilink && multilink_master) {
+       if (!bundle_terminating)
+           new_phase(PHASE_MASTER);
+       else
+           mp_bundle_terminated();
+    } else
+       new_phase(PHASE_DEAD);
 }
 
 /*
@@ -564,17 +670,30 @@ link_terminated(unit)
 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;
@@ -585,8 +704,6 @@ link_down(unit)
     }
     num_np_open = 0;
     num_np_up = 0;
-    if (phase != PHASE_DEAD)
-       new_phase(PHASE_ESTABLISH);
 }
 
 /*
@@ -607,10 +724,12 @@ link_established(unit)
     /*
      * 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);
@@ -627,8 +746,8 @@ link_established(unit)
            set_allowed_addrs(unit, NULL, NULL);
        } else if (!wo->neg_upap || uselogin || !null_login(unit)) {
            warn("peer refused to authenticate: terminating link");
-           lcp_close(unit, "peer refused to authenticate");
            status = EXIT_PEER_AUTH_FAILED;
+           lcp_close(unit, "peer refused to authenticate");
            return;
        }
     }
@@ -787,8 +906,8 @@ auth_peer_fail(unit, protocol)
     /*
      * Authentication failure: take the link down
      */
-    lcp_close(unit, "Authentication failed");
     status = EXIT_PEER_AUTH_FAILED;
+    lcp_close(unit, "Authentication failed");
 }
 
 /*
@@ -865,8 +984,8 @@ auth_withpeer_fail(unit, protocol)
      * 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;
+    lcp_close(unit, "Failed to authenticate ourselves to peer");
 }
 
 /*
@@ -877,10 +996,12 @@ auth_withpeer_success(unit, protocol, prot_flavor)
     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_MD5:
            bit |= CHAP_MD5_WITHPEER;
@@ -899,15 +1020,19 @@ auth_withpeer_success(unit, protocol, prot_flavor)
        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;
 
@@ -1024,9 +1149,9 @@ check_maxoctets(arg)
     diff = maxoctets - used;
     if(diff < 0) {
        notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used);
+       status = EXIT_TRAFFIC_LIMIT;
        lcp_close(0, "Traffic limit");
        need_holdoff = 0;
-       status = EXIT_TRAFFIC_LIMIT;
     } else {
         TIMEOUT(check_maxoctets, NULL, maxoctets_timeout);
     }
@@ -1056,9 +1181,9 @@ check_idle(arg)
     if (tlim <= 0) {
        /* link is idle: shut it down. */
        notice("Terminating connection due to lack of activity.");
+       status = EXIT_IDLE_TIMEOUT;
        lcp_close(0, "Link inactive");
        need_holdoff = 0;
-       status = EXIT_IDLE_TIMEOUT;
     } else {
        TIMEOUT(check_idle, NULL, tlim);
     }
@@ -1072,8 +1197,8 @@ connect_time_expired(arg)
     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 */
 }
 
 /*
@@ -1109,12 +1234,14 @@ auth_check_options()
     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;
     }
@@ -1539,6 +1666,7 @@ plogin(user, passwd, msg)
 static void
 plogout()
 {
+    char *tty;
 #ifdef USE_PAM
     int pam_error;
 
@@ -1549,14 +1677,12 @@ plogout()
     }
     /* 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;
 }
 
@@ -2434,5 +2560,5 @@ auth_script(script)
     argv[5] = strspeed;
     argv[6] = NULL;
 
-    auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL);
+    auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL, 0);
 }