]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/auth.c
Added net/ppp_defs.h to fix for compilation on Solaris, where u_int32_t
[ppp.git] / pppd / auth.c
index e435e6c7fea0d540e875f05a6cdf26f051f0f9b2..8189787b198f26c13b90d8b5dd2c3d207edc5777 100644 (file)
@@ -68,7 +68,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: auth.c,v 1.105 2005/07/12 01:07:59 paulus Exp $"
+#define RCSID  "$Id: auth.c,v 1.113 2007/06/19 02:08:35 carlsonj Exp $"
 
 #include <stdio.h>
 #include <stddef.h>
@@ -91,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>
 #include "cbcp.h"
 #endif
 #include "pathnames.h"
+#include "session.h"
 
 static const char rcsid[] = RCSID;
 
@@ -134,9 +132,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];
 
@@ -215,12 +210,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 */
@@ -247,8 +241,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 *));
@@ -377,7 +369,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 },
@@ -409,6 +404,7 @@ setupapfile(argv)
 {
     FILE *ufile;
     int l;
+    uid_t euid;
     char u[MAXNAMELEN], p[MAXSECRETLEN];
     char *fname;
 
@@ -418,9 +414,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;
@@ -607,10 +608,8 @@ link_terminated(unit)
 
     if (pap_logout_hook) {
        pap_logout_hook();
-    } else {
-       if (logged_in)
-           plogout();
     }
+    session_end(devnam);
 
     if (!doing_multilink) {
        notice("Connection terminated.");
@@ -652,6 +651,8 @@ link_terminated(unit)
        the_channel->disconnect();
        devfd = -1;
     }
+    if (the_channel->cleanup)
+       (*the_channel->cleanup)();
 
     if (doing_multilink && multilink_master) {
        if (!bundle_terminating)
@@ -744,14 +745,13 @@ 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);
@@ -904,8 +904,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");
 }
 
 /*
@@ -982,8 +982,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");
 }
 
 /*
@@ -994,10 +994,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;
@@ -1016,15 +1018,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;
 
@@ -1141,9 +1147,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);
     }
@@ -1173,9 +1179,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);
     }
@@ -1407,8 +1413,14 @@ 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 */
@@ -1453,232 +1465,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()
-{
-    char *tty;
-#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();
-#endif /* USE_PAM */
-
-    tty = devnam;
-    if (strncmp(tty, "/dev/", 5) == 0)
-       tty += 5;
-    logwtmp(tty, "", "");              /* Wipe out utmp logout entry */
-    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
@@ -2552,5 +2338,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);
 }