]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
Use systemd's sd_notify with option up_sdnotify
[ppp.git] / pppd / auth.c
index b0bcdcf4a9d59349dd2872f344a4450c7bb0fdae..7457eda227bf19c2d09b79dd4e0b031da6bc1bf9 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.94 2003/03/09 09:52:19 etbe Exp $"
+#define RCSID  "$Id: auth.c,v 1.117 2008/07/01 12:27:56 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>
@@ -95,9 +91,6 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-#endif
 
 #ifdef HAS_SHADOW
 #include <shadow.h>
 #endif
 #include <time.h>
 
+#ifdef SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
 #include "pppd.h"
 #include "fsm.h"
 #include "lcp.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"
 #endif
 #include "pathnames.h"
+#include "session.h"
 
 static const char rcsid[] = RCSID;
 
@@ -138,9 +136,6 @@ 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;
-
 /* List of addresses which the peer may use. */
 static struct permitted_ip *addresses[NUM_PPP];
 
@@ -186,6 +181,12 @@ void (*pap_logout_hook) __P((void)) = NULL;
 /* 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,
@@ -193,6 +194,11 @@ int (*null_auth_hook) __P((struct wordlist **paddrs,
 
 int (*allowed_address_hook) __P((u_int32_t addr)) = NULL;
 
+#ifdef HAVE_MULTILINK
+/* Hook for plugin to hear when an interface joins a multilink bundle */
+void (*multilink_join_hook) __P((void)) = NULL;
+#endif
+
 /* A notifier for when the peer has authenticated itself,
    and we are proceeding to the network phase. */
 struct notifier *auth_up_notifier = NULL;
@@ -213,12 +219,11 @@ static enum script_state auth_state = s_down;
 static enum script_state auth_script_state = s_down;
 static pid_t auth_script_pid = 0;
 
-static int used_login;         /* peer authenticated against login database */
-
 /*
  * Option variables.
  */
 bool uselogin = 0;             /* Use /etc/passwd for checking PAP */
+bool session_mgmt = 0;         /* Do session management (login records) */
 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 */
@@ -234,6 +239,8 @@ 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 */
+bool explicit_user = 0;                /* Set if "user" option supplied */
+bool explicit_passwd = 0;      /* Set if "password" option supplied */
 char remote_name[MAXNAMELEN];  /* Peer's name for authentication */
 
 static char *uafname;          /* name of most recent +ua file */
@@ -245,8 +252,6 @@ extern char *crypt __P((const char *, const char *));
 static void network_phase __P((int));
 static void check_idle __P((void *));
 static void connect_time_expired __P((void *));
-static int  plogin __P((char *, char *, char **));
-static void plogout __P((void));
 static int  null_login __P((int));
 static int  get_pap_passwd __P((char *));
 static int  have_pap_secret __P((int *));
@@ -361,11 +366,13 @@ option_t auth_options[] = {
       OPT_PRIO | OPT_A2STRVAL, &uafname },
 
     { "user", o_string, user,
-      "Set name for auth with peer", OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN },
+      "Set name for auth with peer", OPT_PRIO | OPT_STATIC,
+      &explicit_user, MAXNAMELEN },
 
     { "password", o_string, passwd,
       "Password for authenticating us to the peer",
-      OPT_PRIO | OPT_STATIC | OPT_HIDE, NULL, MAXSECRETLEN },
+      OPT_PRIO | OPT_STATIC | OPT_HIDE,
+      &explicit_passwd, MAXSECRETLEN },
 
     { "usehostname", o_bool, &usehostname,
       "Must use hostname for authentication", 1 },
@@ -375,7 +382,10 @@ option_t auth_options[] = {
       &explicit_remote, MAXNAMELEN },
 
     { "login", o_bool, &uselogin,
-      "Use system password database for PAP", 1 },
+      "Use system password database for PAP", OPT_A2COPY | 1 ,
+      &session_mgmt },
+    { "enable-session", o_bool, &session_mgmt,
+      "Enable session accounting for remote peers", OPT_PRIV | 1 },
 
     { "papcrypt", o_bool, &cryptpap,
       "PAP passwords are encrypted", 1 },
@@ -407,6 +417,7 @@ setupapfile(argv)
 {
     FILE *ufile;
     int l;
+    uid_t euid;
     char u[MAXNAMELEN], p[MAXSECRETLEN];
     char *fname;
 
@@ -416,9 +427,14 @@ setupapfile(argv)
     fname = strdup(*argv);
     if (fname == NULL)
        novm("+ua file name");
-    seteuid(getuid());
+    euid = geteuid();
+    if (seteuid(getuid()) == -1) {
+       option_error("unable to reset uid before opening %s: %m", fname);
+       return 0;
+    }
     ufile = fopen(fname, "r");
-    seteuid(0);
+    if (seteuid(euid) == -1)
+       fatal("unable to regain privileges: %m");
     if (ufile == NULL) {
        option_error("unable to open user login data file %s", fname);
        return 0;
@@ -443,10 +459,14 @@ setupapfile(argv)
     if (l > 0 && p[l-1] == '\n')
        p[l-1] = 0;
 
-    if (override_value("user", option_priority, fname))
+    if (override_value("user", option_priority, fname)) {
        strlcpy(user, u, sizeof(user));
-    if (override_value("passwd", option_priority, fname))
+       explicit_user = 1;
+    }
+    if (override_value("passwd", option_priority, fname)) {
        strlcpy(passwd, p, sizeof(passwd));
+       explicit_passwd = 1;
+    }
 
     return (1);
 }
@@ -524,7 +544,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)
@@ -532,6 +551,64 @@ link_required(unit)
 {
 }
 
+/*
+ * Bring the link up to the point of being able to do ppp.
+ */
+void start_link(unit)
+    int unit;
+{
+    status = EXIT_CONNECT_FAILED;
+    new_phase(PHASE_SERIALCONN);
+
+    hungup = 0;
+    devfd = the_channel->connect();
+    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);
+    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.
@@ -540,16 +617,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.");
+    session_end(devnam);
+
+    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);
+           if (master_detach && !detached)
+               detach();
+       } else
+           mp_bundle_terminated();
+    } else
+       new_phase(PHASE_DEAD);
 }
 
 /*
@@ -558,17 +686,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;
@@ -579,8 +720,6 @@ link_down(unit)
     }
     num_np_open = 0;
     num_np_up = 0;
-    if (phase != PHASE_DEAD)
-       new_phase(PHASE_ESTABLISH);
 }
 
 /*
@@ -601,10 +740,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);
@@ -621,20 +762,19 @@ 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;
        }
     }
 
     new_phase(PHASE_AUTHENTICATE);
-    used_login = 0;
     auth = 0;
     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));
+       chap_auth_peer(unit, our_name, CHAP_DIGEST(go->chap_mdtype));
        auth |= CHAP_PEER;
     } else if (go->neg_upap) {
        upap_authpeer(unit);
@@ -644,10 +784,12 @@ link_established(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) {
+       /* If a blank password was explicitly given as an option, trust
+          the user and don't try to look up one. */
+       if (passwd[0] == 0 && !explicit_passwd) {
            passwd_from_file = 1;
            if (!get_pap_passwd(passwd))
                error("No secret found for PAP login");
@@ -722,6 +864,8 @@ start_networks(unit)
 #ifdef HAVE_MULTILINK
     if (multilink) {
        if (mp_join_bundle()) {
+           if (multilink_join_hook)
+               (*multilink_join_hook)();
            if (updetach && !nodetach)
                detach();
            return;
@@ -781,8 +925,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");
 }
 
 /*
@@ -800,7 +944,7 @@ auth_peer_success(unit, protocol, prot_flavor, name, namelen)
     case PPP_CHAP:
        bit = CHAP_PEER;
        switch (prot_flavor) {
-       case CHAP_DIGEST_MD5:
+       case CHAP_MD5:
            bit |= CHAP_MD5_PEER;
            break;
 #ifdef CHAPMS
@@ -859,8 +1003,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");
 }
 
 /*
@@ -871,12 +1015,14 @@ 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_DIGEST_MD5:
+       case CHAP_MD5:
            bit |= CHAP_MD5_WITHPEER;
            break;
 #ifdef CHAPMS
@@ -893,15 +1039,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;
 
@@ -953,8 +1103,15 @@ np_up(unit, proto)
        /*
         * Detach now, if the updetach option was given.
         */
-       if (updetach && !nodetach)
+       if (updetach && !nodetach) {
+           dbglog("updetach is set. Now detaching.");
            detach();
+#ifdef SYSTEMD
+       } else if (nodetach && up_sdnotify) {
+           dbglog("up_sdnotify is set. Now notifying systemd: READY=1");
+           sd_notify(0, "READY=1");
+#endif
+       }
     }
     ++num_np_up;
 }
@@ -994,7 +1151,6 @@ static void
 check_maxoctets(arg)
     void *arg;
 {
-    int diff;
     unsigned int used;
 
     update_link_stats(ifunit);
@@ -1015,12 +1171,11 @@ check_maxoctets(arg)
            used = link_stats.bytes_in+link_stats.bytes_out;
            break;
     }
-    diff = maxoctets - used;
-    if(diff < 0) {
+    if (used > maxoctets) {
        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);
     }
@@ -1050,9 +1205,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);
     }
@@ -1066,8 +1221,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 */
 }
 
 /*
@@ -1083,7 +1238,9 @@ auth_check_options()
     /* Default our_name to hostname, and user to our_name */
     if (our_name[0] == 0 || usehostname)
        strlcpy(our_name, hostname, sizeof(our_name));
-    if (user[0] == 0)
+    /* If a blank username was explicitly given as an option, trust
+       the user and don't use our_name */
+    if (user[0] == 0 && !explicit_user)
        strlcpy(user, our_name, sizeof(user));
 
     /*
@@ -1103,12 +1260,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;
     }
@@ -1245,14 +1404,15 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
     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;
        }
     }
@@ -1281,14 +1441,22 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
            ret = UPAP_AUTHACK;
            if (uselogin || login_secret) {
                /* login option or secret is @login */
-               if ((ret = plogin(user, passwd, msg)) == UPAP_AUTHACK)
-                   used_login = 1;
+               if (session_full(user, passwd, devnam, msg) == 0) {
+                   ret = UPAP_AUTHNAK;
+               }
+           } else if (session_mgmt) {
+               if (session_check(user, NULL, devnam, NULL) == 0) {
+                   warn("Peer %q failed PAP Session verification", user);
+                   ret = UPAP_AUTHNAK;
+               }
            }
            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)
-                   ret = UPAP_AUTHNAK;
+               if (cryptpap || strcmp(passwd, secret) != 0) {
+                   char *cbuf = crypt(passwd, secret);
+                   if (!cbuf || strcmp(cbuf, secret) != 0)
+                       ret = UPAP_AUTHNAK;
+               }
            }
        }
        fclose(f);
@@ -1327,233 +1495,6 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
     return ret;
 }
 
-/*
- * This function is needed for PAM.
- */
-
-#ifdef USE_PAM
-/* Static variables used to communicate between the conversation function
- * and the server_login function 
- */
-static char *PAM_username;
-static char *PAM_password;
-static int PAM_error = 0;
-static pam_handle_t *pamh = NULL;
-
-/* PAM conversation function
- * Here we assume (for now, at least) that echo on means login name, and
- * echo off means password.
- */
-
-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;
-
-#define COPY_STRING(s) (s) ? strdup(s) : NULL
-
-    reply = malloc(sizeof(struct pam_response) * num_msg);
-    if (!reply) return PAM_CONV_ERR;
-
-    for (replies = 0; replies < num_msg; replies++) {
-        switch (msg[replies]->msg_style) {
-            case PAM_PROMPT_ECHO_ON:
-                reply[replies].resp_retcode = PAM_SUCCESS;
-                reply[replies].resp = COPY_STRING(PAM_username);
-                /* PAM frees resp */
-                break;
-            case PAM_PROMPT_ECHO_OFF:
-                reply[replies].resp_retcode = PAM_SUCCESS;
-                reply[replies].resp = COPY_STRING(PAM_password);
-                /* PAM frees resp */
-                break;
-            case PAM_TEXT_INFO:
-                /* fall through */
-            case PAM_ERROR_MSG:
-                /* ignore it, but pam still wants a NULL response... */
-                reply[replies].resp_retcode = PAM_SUCCESS;
-                reply[replies].resp = NULL;
-                break;
-            default:       
-                /* Must be an error of some sort... */
-                free (reply);
-                PAM_error = 1;
-                return PAM_CONV_ERR;
-        }
-    }
-    *resp = reply;     
-    return PAM_SUCCESS;
-}
-
-static struct pam_conv PAM_conversation = {
-    &PAM_conv,
-    NULL
-};
-#endif  /* USE_PAM */
-
-/*
- * plogin - Check the user name and password against the system
- * password database, and login the user if OK.
- *
- * returns:
- *     UPAP_AUTHNAK: Login failed.
- *     UPAP_AUTHACK: Login succeeded.
- * In either case, msg points to an appropriate message.
- */
-
-static int
-plogin(user, passwd, msg)
-    char *user;
-    char *passwd;
-    char **msg;
-{
-    char *tty;
-
-#ifdef USE_PAM
-    int pam_error;
-
-    pam_error = pam_start ("ppp", user, &PAM_conversation, &pamh);
-    if (pam_error != PAM_SUCCESS) {
-        *msg = (char *) pam_strerror (pamh, pam_error);
-       reopen_log();
-       return UPAP_AUTHNAK;
-    }
-    /*
-     * Define the fields for the credential validation
-     */
-     
-    PAM_username = user;
-    PAM_password = passwd;
-    PAM_error = 0;
-    pam_set_item (pamh, PAM_TTY, devnam); /* this might be useful to some modules */
-
-    /*
-     * Validate the user
-     */
-    pam_error = pam_authenticate (pamh, PAM_SILENT);
-    if (pam_error == PAM_SUCCESS && !PAM_error) {    
-        pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
-        if (pam_error == PAM_SUCCESS)
-           pam_error = pam_open_session (pamh, PAM_SILENT);
-    }
-
-    *msg = (char *) pam_strerror (pamh, pam_error);
-
-    /*
-     * Clean up the mess
-     */
-    reopen_log();      /* apparently the PAM stuff does closelog() */
-    PAM_username = NULL;
-    PAM_password = NULL;
-    if (pam_error != PAM_SUCCESS)
-        return UPAP_AUTHNAK;
-#else /* #ifdef USE_PAM */
-
-/*
- * Use the non-PAM methods directly
- */
-
-#ifdef HAS_SHADOW
-    struct spwd *spwd;
-    struct spwd *getspnam();
-#endif
-    struct passwd *pw = getpwnam(user);
-
-    endpwent();
-    if (pw == NULL)
-       return (UPAP_AUTHNAK);
-
-#ifdef HAS_SHADOW
-    spwd = getspnam(user);
-    endspent();
-    if (spwd) {
-       /* check the age of the password entry */
-       long now = time(NULL) / 86400L;
-
-       if ((spwd->sp_expire > 0 && now >= spwd->sp_expire)
-           || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
-               && spwd->sp_lstchg >= 0
-               && now >= spwd->sp_lstchg + spwd->sp_max)) {
-           warn("Password for %s has expired", user);
-           return (UPAP_AUTHNAK);
-       }
-       pw->pw_passwd = spwd->sp_pwdp;
-    }
-#endif
-
-    /*
-     * If no passwd, don't let them login.
-     */
-    if (pw->pw_passwd == NULL || strlen(pw->pw_passwd) < 2
-       || strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
-       return (UPAP_AUTHNAK);
-
-#endif /* #ifdef USE_PAM */
-
-    /*
-     * Write a wtmp entry for this user.
-     */
-
-    tty = devnam;
-    if (strncmp(tty, "/dev/", 5) == 0)
-       tty += 5;
-    logwtmp(tty, user, ifname);                /* Add wtmp login entry */
-
-#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
-    if (pw != (struct passwd *)NULL) {
-           struct lastlog ll;
-           int fd;
-
-           if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
-               (void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
-               memset((void *)&ll, 0, sizeof(ll));
-               (void)time(&ll.ll_time);
-               (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
-               (void)write(fd, (char *)&ll, sizeof(ll));
-               (void)close(fd);
-           }
-    }
-#endif /* _PATH_LASTLOG and not USE_PAM */
-
-    info("user %s logged in", user);
-    logged_in = 1;
-
-    return (UPAP_AUTHACK);
-}
-
-/*
- * plogout - Logout the user.
- */
-static void
-plogout()
-{
-#ifdef USE_PAM
-    int pam_error;
-
-    if (pamh != NULL) {
-       pam_error = pam_close_session (pamh, PAM_SILENT);
-       pam_end (pamh, pam_error);
-       pamh = NULL;
-    }
-    /* Apparently the pam stuff does closelog(). */
-    reopen_log();
-#else /* ! USE_PAM */   
-    char *tty;
-
-    tty = devnam;
-    if (strncmp(tty, "/dev/", 5) == 0)
-       tty += 5;
-    logwtmp(tty, "", "");              /* Wipe out utmp logout entry */
-#endif /* ! USE_PAM */
-    logged_in = 0;
-}
-
-
 /*
  * null_login - Check if a username of "" and a password of "" are
  * acceptable, and iff so, set the list of acceptable IP addresses
@@ -2427,5 +2368,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);
 }