pam: Password is const in setcred
[openafs.git] / src / pam / afs_setcred.c
index daf1781..7077ec9 100644 (file)
@@ -1,22 +1,22 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
+#include <afs/param.h>
+
+#include <roken.h>
+
 #include <security/pam_appl.h>
 #include <security/pam_modules.h>
-#include <syslog.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pwd.h>
-#include <unistd.h>
-#include <afs/param.h>
-#include <sys/param.h>
+
 #include <afs/kautils.h>
+
 #include "afs_message.h"
 #include "afs_util.h"
 
@@ -29,36 +29,36 @@ extern char *ktc_tkt_string();
 #endif
 
 extern int
-pam_sm_setcred(
-       pam_handle_t    *pamh,
-       int             flags,
-       int             argc,
-       const char      **argv)
+pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv)
 {
     int retcode = PAM_SUCCESS;
     int errcode = PAM_SUCCESS;
     int origmask;
     int logmask = LOG_UPTO(LOG_INFO);
     int nowarn = 0;
-    int use_first_pass = 1; /* use the password passed in by auth */
+    int use_first_pass = 1;    /* use the password passed in by auth */
     int try_first_pass = 0;
     int got_authtok = 0;
-    int ignore_root = 0;
-    int trust_root = 0;
-    int set_expires = 0; /* the default is to not to set the env variable */
+    int ignore_uid = 0;
+    int no_unlog = 0;
+    uid_t ignore_uid_id = 0;
+    int refresh_token = 0;
+    int set_expires = 0;       /* the default is to not to set the env variable */
+    int use_klog = 0;
     int i;
-    struct pam_conv *pam_convp = NULL;
+    PAM_CONST struct pam_conv *pam_convp = NULL;
     char my_password_buf[256];
+    char *cell_ptr = NULL;
     char sbuffer[100];
-    char *password = NULL;
     int torch_password = 1;
     int auth_ok = 0;
-    char*      lh;
-    char *user = NULL;
-    long password_expires= -1;
-    char*      reason = NULL;
+    char *lh;
+    PAM_CONST char *user = NULL;
+    const char *password = NULL;
+    int password_expires = -1;
+    char *reason = NULL;
     struct passwd unix_pwd, *upwd = NULL;
-    char upwd_buf[2048];        /* size is a guess. */
+    char upwd_buf[2048];       /* size is a guess. */
 
 #ifndef AFS_SUN56_ENV
     openlog(pam_afs_ident, LOG_CONS, LOG_AUTH);
@@ -69,98 +69,136 @@ pam_sm_setcred(
      * Parse the user options.  Log an error for any unknown options.
      */
     for (i = 0; i < argc; i++) {
-       if (       strcasecmp(argv[i], "debug"         ) == 0) {
+       if (strcasecmp(argv[i], "debug") == 0) {
            logmask |= LOG_MASK(LOG_DEBUG);
-           (void) setlogmask(logmask);
-       } else if (strcasecmp(argv[i], "nowarn"        ) == 0) {
+           (void)setlogmask(logmask);
+       } else if (strcasecmp(argv[i], "nowarn") == 0) {
            nowarn = 1;
        } else if (strcasecmp(argv[i], "use_first_pass") == 0) {
-           use_first_pass = 1; /* practically redundant */
+           use_first_pass = 1; /* practically redundant */
        } else if (strcasecmp(argv[i], "try_first_pass") == 0) {
            try_first_pass = 1;
-        } else if (strcasecmp(argv[i], "ignore_root"   ) == 0) {
-            ignore_root = 1;
-        } else if (strcasecmp(argv[i], "trust_root"   ) == 0) {
-            trust_root = 1;
-        } else if (strcasecmp(argv[i], "catch_su"   ) == 0) {
-            use_first_pass = 0;
-       } else if (strcasecmp(argv[i], "setenv_password_expires")==0) {
+       } else if (strcasecmp(argv[i], "ignore_root") == 0) {
+           ignore_uid = 1;
+           ignore_uid_id = 0;
+       } else if (strcasecmp(argv[i], "ignore_uid") == 0) {
+           i++;
+           if (i == argc) {
+               pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID,
+                              "ignore_uid missing argument");
+               ignore_uid = 0;
+           } else {
+               ignore_uid = 1;
+               ignore_uid_id = (uid_t) strtol(argv[i], (char **)NULL, 10);
+               if ((0 > ignore_uid_id) || (ignore_uid_id > IGNORE_MAX)) {
+                   ignore_uid = 0;
+                   pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, argv[i]);
+               }
+           }
+       } else if (strcasecmp(argv[i], "cell") == 0) {
+           i++;
+           if (i == argc) {
+               pam_afs_syslog(LOG_ERR, PAMAFS_OTHERCELL,
+                              "cell missing argument");
+           } else {
+               cell_ptr = (char *)argv[i];
+               pam_afs_syslog(LOG_INFO, PAMAFS_OTHERCELL, cell_ptr);
+           }
+       } else if (strcasecmp(argv[i], "no_unlog") == 0) {
+           no_unlog = 1;
+       } else if (strcasecmp(argv[i], "refresh_token") == 0) {
+           refresh_token = 1;
+       } else if (strcasecmp(argv[i], "set_token") == 0) {
+           ;
+       } else if (strcasecmp(argv[i], "dont_fork") == 0) {
+           ;
+       } else if (strcasecmp(argv[i], "use_klog") == 0) {
+           use_klog = 1;
+       } else if (strcasecmp(argv[i], "setenv_password_expires") == 0) {
            set_expires = 1;
        } else {
            pam_afs_syslog(LOG_ERR, PAMAFS_UNKNOWNOPT, argv[i]);
        }
     }
 
-    if (use_first_pass) try_first_pass = 0;
+    if (use_first_pass)
+       try_first_pass = 0;
 
-    pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass, try_first_pass);
+    if (logmask && LOG_MASK(LOG_DEBUG))
+       pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass,
+                      try_first_pass, ignore_uid, ignore_uid_id, 8, 8, 8, 8);
     /* Try to get the user-interaction info, if available. */
-    errcode = pam_get_item(pamh, PAM_CONV, (void **) &pam_convp);
+    errcode = pam_get_item(pamh, PAM_CONV, (PAM_CONST void **)&pam_convp);
     if (errcode != PAM_SUCCESS) {
-       pam_afs_syslog(LOG_DEBUG, PAMAFS_NO_USER_INT);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_NO_USER_INT);
        pam_convp = NULL;
     }
 
     /* Who are we trying to authenticate here? */
-    if ((errcode = pam_get_user(pamh, &user, "AFS username:")) != PAM_SUCCESS) {
-        pam_afs_syslog(LOG_ERR, PAMAFS_NOUSER, errcode);
-        RET(PAM_USER_UNKNOWN);
+    if ((errcode =
+        pam_get_user(pamh, (PAM_CONST char **)&user,
+                     "AFS username:")) != PAM_SUCCESS) {
+       pam_afs_syslog(LOG_ERR, PAMAFS_NOUSER, errcode);
+       RET(PAM_USER_UNKNOWN);
     }
     /*
      * If the user has a "local" (or via nss, possibly nss_dce) pwent,
      * and its uid==0, and "ignore_root" was given in pam.conf,
      * ignore the user.
      */
-#if    defined(AFS_HPUX_ENV)
-#if     defined(AFS_HPUX110_ENV)
+    /* enhanced: use "ignore_uid <number>" to specify the largest uid
+     * which should be ignored by this module
+     */
+#if    defined(AFS_HPUX_ENV) || defined(AFS_DARWIN100_ENV) || defined(AFS_SUN58_ENV)
+#if     defined(AFS_HPUX110_ENV) || defined(AFS_DARWIN100_ENV) || defined(AFS_SUN58_ENV)
     i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd);
-#else   /* AFS_HPUX110_ENV */
+#else /* AFS_HPUX110_ENV */
     i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf));
-    if ( i == 0 )                       /* getpwnam_r success */
-        upwd = &unix_pwd;
-#endif  /* AFS_HPUX110_ENV */
-    if (ignore_root && i == 0 && upwd->pw_uid == 0) {
-        pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
-        RET(PAM_AUTH_ERR);
+    if (i == 0)                        /* getpwnam_r success */
+       upwd = &unix_pwd;
+#endif /* AFS_HPUX110_ENV */
+    if (ignore_uid && i == 0 && upwd && upwd->pw_uid <= ignore_uid_id) {
+       pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
+       RET(PAM_AUTH_ERR);
     }
 #else
-#ifdef AFS_LINUX20_ENV
+#if     defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_NBSD_ENV)
     upwd = getpwnam(user);
 #else
     upwd = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf));
 #endif
-    if (upwd != NULL && upwd->pw_uid == 0) {
-       if (ignore_root) { 
-               pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
-               RET(PAM_AUTH_ERR);
-       } else if (trust_root) {
-               pam_afs_syslog(LOG_INFO, PAMAFS_TRUSTROOT, user);
-               RET(PAM_SUCCESS);
-       }
+    if (ignore_uid && upwd != NULL && upwd->pw_uid <= ignore_uid_id) {
+       pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
+       RET(PAM_AUTH_ERR);
     }
 #endif
 
     if (flags & PAM_DELETE_CRED) {
-       pam_afs_syslog(LOG_DEBUG, PAMAFS_DELCRED, user);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_DELCRED, user);
 
        RET(PAM_SUCCESS);
     } else if (flags & PAM_REINITIALIZE_CRED) {
 
-        pam_afs_syslog(LOG_DEBUG, PAMAFS_REINITCRED, user);
-        RET(PAM_SUCCESS);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_REINITCRED, user);
+       RET(PAM_SUCCESS);
 
-    } else { /* flags are PAM_REFRESH_CRED, PAM_ESTABLISH_CRED, unknown */
+    } else {                   /* flags are PAM_REFRESH_CRED, PAM_ESTABLISH_CRED, unknown */
 
-       pam_afs_syslog(LOG_DEBUG, PAMAFS_ESTABCRED, user);
+       if (logmask && LOG_MASK(LOG_DEBUG))
+           pam_afs_syslog(LOG_DEBUG, PAMAFS_ESTABCRED, user);
 
-       errcode = pam_get_data(pamh, pam_afs_lh, (const void **) &password);
+       errcode = pam_get_data(pamh, pam_afs_lh, (const void **)&password);
        if (errcode != PAM_SUCCESS || password == NULL) {
            if (use_first_pass) {
                pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user);
                RET(PAM_AUTH_ERR);
            }
            password = NULL;    /* In case it isn't already NULL */
-           pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
+           if (logmask && LOG_MASK(LOG_DEBUG))
+               pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
        } else if (password[0] == '\0') {
            /* Actually we *did* get one but it was empty. */
            got_authtok = 1;
@@ -171,9 +209,11 @@ pam_sm_setcred(
                pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user);
                RET(PAM_NEW_AUTHTOK_REQD);
            }
-           pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD, user);
+           if (logmask && LOG_MASK(LOG_DEBUG))
+               pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD, user);
        } else {
-           pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
+           if (logmask && LOG_MASK(LOG_DEBUG))
+               pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
            torch_password = 0;
            got_authtok = 1;
        }
@@ -181,8 +221,9 @@ pam_sm_setcred(
            password = NULL;
        }
 
-    try_auth:
+      try_auth:
        if (password == NULL) {
+           char *prompt_password;
 
            torch_password = 1;
 
@@ -190,19 +231,21 @@ pam_sm_setcred(
                RET(PAM_AUTH_ERR);      /* shouldn't happen */
            if (try_first_pass)
                try_first_pass = 0;     /* we come back if try_first_pass==1 below */
-           
+
            if (pam_convp == NULL || pam_convp->conv == NULL) {
                pam_afs_syslog(LOG_ERR, PAMAFS_CANNOT_PROMPT);
                RET(PAM_AUTH_ERR);
            }
-           
-           errcode = pam_afs_prompt(pam_convp, &password, 0, PAMAFS_PWD_PROMPT);
-           if (errcode != PAM_SUCCESS || password == NULL) {
+
+           errcode =
+               pam_afs_prompt(pam_convp, &prompt_password, 0, PAMAFS_PWD_PROMPT);
+           if (errcode != PAM_SUCCESS || prompt_password == NULL) {
                pam_afs_syslog(LOG_ERR, PAMAFS_GETPASS_FAILED);
                RET(PAM_AUTH_ERR);
            }
-           if (password[0] == '\0') {
-               pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD);
+           if (prompt_password[0] == '\0') {
+               if (logmask && LOG_MASK(LOG_DEBUG))
+                   pam_afs_syslog(LOG_DEBUG, PAMAFS_NILPASSWORD);
                RET(PAM_NEW_AUTHTOK_REQD);
            }
            /*
@@ -212,44 +255,63 @@ pam_sm_setcred(
             * this storage, copy it to a buffer that won't need to be freed
             * later, and free this storage now.
             */
-           strncpy(my_password_buf, password, sizeof(my_password_buf));
-           my_password_buf[sizeof(my_password_buf)-1] = '\0';
-           memset(password, 0, strlen(password));
-           free(password);
+
+           strncpy(my_password_buf, prompt_password, sizeof(my_password_buf));
+           my_password_buf[sizeof(my_password_buf) - 1] = '\0';
+           memset(prompt_password, 0, strlen(prompt_password));
+           free(prompt_password);
            password = my_password_buf;
        }
+       /*
+        * We only set a PAG here, if we haven't got one before in
+        * pam_sm_authenticate() or if it was destroyed by the application
+        */
+       if ((!refresh_token) && (getPAG() == -1)) {
+           if (logmask && LOG_MASK(LOG_DEBUG))
+               syslog(LOG_DEBUG, "New PAG created in pam_setcred()");
+           setpag();
+#ifdef AFS_KERBEROS_ENV
+           ktc_newpag();
+#endif
+       }
 
-       if ( flags & PAM_REFRESH_CRED ) {
-            if ( ka_VerifyUserPassword(
-                           KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,
-                           user, /* kerberos name */
-                           (char *)0, /* instance */
-                           (char *)0, /* realm */
-                            password, /* password */
-                            0, /* spare 2 */
-                            &reason /* error string */
-                            )) {
-               pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason);
+       if (flags & PAM_REFRESH_CRED) {
+           if (use_klog) {
+               auth_ok = !do_klog(user, password, "00:00:01", cell_ptr);
+               ktc_ForgetAllTokens();
            } else {
-               auth_ok = 1;
-           }   
+               if (ka_VerifyUserPassword(KA_USERAUTH_VERSION, (char *)user,    /* kerberos name */
+                                         NULL, /* instance */
+                                         cell_ptr,     /* realm */
+                                         (char*)password,      /* password */
+                                         0,    /* spare 2 */
+                                         &reason       /* error string */
+                   )) {
+                   pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user,
+                                  reason);
+               } else {
+                   auth_ok = 1;
+               }
+           }
        }
-           
-       if (  flags & PAM_ESTABLISH_CRED ) {
-           if ( ka_UserAuthenticateGeneral(
-                           KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,
-                           user, /* kerberos name */
-                           (char *)0, /* instance */
-                           (char *)0, /* realm */
-                            password, /* password */
-                            0, /* default lifetime */
-                            &password_expires,
-                            0, /* spare 2 */
-                            &reason /* error string */
-                            )) {
-               pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason);
-           } else {
-              auth_ok = 1;
+
+       if (flags & PAM_ESTABLISH_CRED) {
+           if (use_klog)
+               auth_ok = !do_klog(user, password, NULL, cell_ptr);
+           else {
+               if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, (char *)user,       /* kerberos name */
+                                              NULL,    /* instance */
+                                              cell_ptr,        /* realm */
+                                              (char*)password, /* password */
+                                              0,       /* default lifetime */
+                                              &password_expires, 0,    /* spare 2 */
+                                              &reason  /* error string */
+                   )) {
+                   pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user,
+                                  reason);
+               } else {
+                   auth_ok = 1;
+               }
            }
        }
 
@@ -258,29 +320,30 @@ pam_sm_setcred(
            goto try_auth;
        }
 
-       if (auth_ok && !got_authtok) {
-           torch_password = 0;
-           (void) pam_set_item(pamh, PAM_AUTHTOK, password);
-       }
+       /* pam_sm_authenticate should have set this
+        * if (auth_ok && !got_authtok) {
+        *     torch_password = 0;
+        *     (void) pam_set_item(pamh, PAM_AUTHTOK, password);
+        * }
+        */
 
        if (auth_ok) {
-           if (set_expires &&  (password_expires >= 0) ) {
+           if (set_expires && !use_klog && (password_expires >= 0)) {
                strcpy(sbuffer, "PASSWORD_EXPIRES=");
                strcat(sbuffer, cv2string(&sbuffer[100], password_expires));
-               errcode = pam_putenv( pamh, sbuffer); 
-               if ( errcode != PAM_SUCCESS )
+               errcode = pam_putenv(pamh, sbuffer);
+               if (errcode != PAM_SUCCESS)
                    pam_afs_syslog(LOG_ERR, PAMAFS_PASSEXPFAIL, user);
            }
 #if defined(AFS_KERBEROS_ENV)
-           if (upwd)
-           {
-               if ( chown(ktc_tkt_string(), upwd->pw_uid, upwd->pw_gid) < 0 )
+           if (upwd) {
+               if (chown(ktc_tkt_string(), upwd->pw_uid, upwd->pw_gid) < 0)
                    pam_afs_syslog(LOG_ERR, PAMAFS_CHOWNKRB, user);
                sprintf(sbuffer, "KRBTKFILE=%s", ktc_tkt_string());
-               errcode = pam_putenv( pamh, sbuffer);
-                if ( errcode != PAM_SUCCESS )
-                    pam_afs_syslog(LOG_ERR, PAMAFS_KRBFAIL, user);
-           }
+               errcode = pam_putenv(pamh, sbuffer);
+               if (errcode != PAM_SUCCESS)
+                   pam_afs_syslog(LOG_ERR, PAMAFS_KRBFAIL, user);
+           }
 #endif
 
            RET(PAM_SUCCESS);
@@ -289,9 +352,10 @@ pam_sm_setcred(
        }
     }
 
- out:
-    if (password && torch_password) memset(password, 0, strlen(password));
-    (void) setlogmask(origmask);
+  out:
+    if (password && torch_password)
+       memset((char*)password, 0, strlen(password));
+    (void)setlogmask(origmask);
 #ifndef AFS_SUN56_ENV
     closelog();
 #endif