]> andersk Git - gssapi-openssh.git/blobdiff - openssh/auth-pam.c
enable PAM user switching
[gssapi-openssh.git] / openssh / auth-pam.c
index ccdb9937e364af74197f31a1a1f62ab0feaabb52..582c463a1fa596680052990e83f4db8180c233bc 100644 (file)
@@ -30,7 +30,7 @@
  */
 /*
  * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
- * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
+ * Copyright (c) 2003,2004,2006 Darren Tucker <dtucker@zip.com.au>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -272,6 +272,49 @@ sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
 # define pam_chauthtok(a,b)    (sshpam_chauthtok_ruid((a), (b)))
 #endif
 
+struct passwd *
+sshpam_getpw(const char *user)
+{
+       struct passwd *pw;
+
+       if ((pw = getpwnam(user)) != NULL)
+               return(pw);
+
+       debug("PAM: faking passwd struct for user '%.100s'", user);
+       if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)
+               return NULL;
+       pw->pw_name = xstrdup(user);    /* XXX leak */
+       pw->pw_shell = "/bin/true";
+       pw->pw_gecos = "sshd fake PAM user";
+       return (pw);
+}
+
+void
+sshpam_check_userchanged(void)
+{
+       int sshpam_err;
+       struct passwd *pw;
+       const char *user;
+
+       debug("sshpam_check_userchanged");
+       sshpam_err = pam_get_item(sshpam_handle, PAM_USER, &user);
+       if (sshpam_err != PAM_SUCCESS)
+               fatal("PAM: could not get PAM_USER: %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+       if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) {
+               debug("PAM: user mapped from '%.100s' to '%.100s'",
+                   sshpam_authctxt->pw->pw_name, user);
+               if ((pw = getpwnam(user)) == NULL)
+                       fatal("PAM: could not get passwd entry for user "
+                           "'%.100s' provided by PAM_USER", user);
+               pwfree(sshpam_authctxt->pw);
+               sshpam_authctxt->pw = pw;
+               sshpam_authctxt->valid = allowed_user(pw);
+               debug("PAM: user '%.100s' now %svalid", user,
+                   sshpam_authctxt->valid ? "" : "in");
+       }
+}
+
 void
 sshpam_password_change_required(int reqd)
 {
@@ -294,7 +337,7 @@ sshpam_password_change_required(int reqd)
 static void
 import_environments(Buffer *b)
 {
-       char *env;
+       char *env, *user;
        u_int i, num_env;
        int err;
 
@@ -304,6 +347,15 @@ import_environments(Buffer *b)
        /* Import variables set by do_pam_account */
        sshpam_account_status = buffer_get_int(b);
        sshpam_password_change_required(buffer_get_int(b));
+       if (options.permit_pam_user_change) {
+        user = buffer_get_string(b, NULL);
+        debug("PAM: got username '%.100s' from thread", user);
+        if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS)
+            fatal("PAM: failed to set PAM_USER: %s",
+                  pam_strerror(sshpam_handle, err));
+        pwfree(sshpam_authctxt->pw);
+        sshpam_authctxt->pw = pwcopy(sshpam_getpw(user));
+    }
 
        /* Import environment from subprocess */
        num_env = buffer_get_int(b);
@@ -469,6 +521,9 @@ sshpam_thread(void *ctxtp)
        if (sshpam_err != PAM_SUCCESS)
                goto auth_fail;
 
+       if (options.permit_pam_user_change) {
+        sshpam_check_userchanged();
+    }
        if (compat20) {
                if (!do_pam_account()) {
                        sshpam_err = PAM_ACCT_EXPIRED;
@@ -489,6 +544,9 @@ sshpam_thread(void *ctxtp)
        /* Export variables set by do_pam_account */
        buffer_put_int(&buffer, sshpam_account_status);
        buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
+       if (options.permit_pam_user_change) {
+        buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name);
+    }
 
        /* Export any environment strings set in child */
        for(i = 0; environ[i] != NULL; i++)
@@ -907,6 +965,12 @@ do_pam_account(void)
        debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
            pam_strerror(sshpam_handle, sshpam_err));
 
+       if (options.permit_pam_user_change) {
+        sshpam_check_userchanged();
+        if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL)
+            fatal("PAM: completed authentication but PAM account invalid");
+    }
+
        if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
                sshpam_account_status = 0;
                return (sshpam_account_status);
@@ -1206,6 +1270,9 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password)
                    pam_strerror(sshpam_handle, sshpam_err));
 
        sshpam_err = pam_authenticate(sshpam_handle, flags);
+       if (options.permit_pam_user_change) {
+        sshpam_check_userchanged();
+    }
        sshpam_password = NULL;
        if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
                debug("PAM: password authentication accepted for %.100s",
This page took 0.037289 seconds and 4 git commands to generate.