]> andersk Git - gssapi-openssh.git/blobdiff - openssh/auth-pam.c
The man2html from jbasney on pkilab2 works whereas the standard one doesn't.
[gssapi-openssh.git] / openssh / auth-pam.c
index c08d4722912da474a5a6b8951310b168d9c161c1..90ec372c05309cebdf1a84f97797b4eaa1da0254 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
@@ -161,9 +161,9 @@ sshpam_sigchld_handler(int sig)
            WTERMSIG(sshpam_thread_status) == SIGTERM)
                return; /* terminated by pthread_cancel */
        if (!WIFEXITED(sshpam_thread_status))
-               fatal("PAM: authentication thread exited unexpectedly");
+               sigdie("PAM: authentication thread exited unexpectedly");
        if (WEXITSTATUS(sshpam_thread_status) != 0)
-               fatal("PAM: authentication thread exited uncleanly");
+               sigdie("PAM: authentication thread exited uncleanly");
 }
 
 /* ARGSUSED */
@@ -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++)
@@ -598,18 +656,20 @@ static struct pam_conv store_conv = { sshpam_store_conv, NULL };
 void
 sshpam_cleanup(void)
 {
-       debug("PAM: cleanup");
-       if (sshpam_handle == NULL)
+       if (sshpam_handle == NULL || (use_privsep && !mm_is_monitor()))
                return;
+       debug("PAM: cleanup");
        pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
-       if (sshpam_cred_established) {
-               pam_setcred(sshpam_handle, PAM_DELETE_CRED);
-               sshpam_cred_established = 0;
-       }
        if (sshpam_session_open) {
+               debug("PAM: closing session");
                pam_close_session(sshpam_handle, PAM_SILENT);
                sshpam_session_open = 0;
        }
+       if (sshpam_cred_established) {
+               debug("PAM: deleting credentials");
+               pam_setcred(sshpam_handle, PAM_DELETE_CRED);
+               sshpam_cred_established = 0;
+       }
        sshpam_authenticated = 0;
        pam_end(sshpam_handle, sshpam_err);
        sshpam_handle = NULL;
@@ -686,8 +746,7 @@ sshpam_init_ctx(Authctxt *authctxt)
                return (NULL);
        }
 
-       ctxt = xmalloc(sizeof *ctxt);
-       memset(ctxt, 0, sizeof(*ctxt));
+       ctxt = xcalloc(1, sizeof *ctxt);
 
        /* Start the authentication thread */
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
@@ -906,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);
@@ -985,7 +1050,8 @@ sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
                        break;
                case PAM_PROMPT_ECHO_ON:
                        fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
-                       fgets(input, sizeof input, stdin);
+                       if (fgets(input, sizeof input, stdin) == NULL)
+                               input[0] = '\0';
                        if ((reply[i].resp = strdup(input)) == NULL)
                                goto fail;
                        reply[i].resp_retcode = PAM_SUCCESS;
@@ -1130,9 +1196,8 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
        if (n <= 0 || n > PAM_MAX_NUM_MSG)
                return (PAM_CONV_ERR);
 
-       if ((reply = malloc(n * sizeof(*reply))) == NULL)
+       if ((reply = calloc(n, sizeof(*reply))) == NULL)
                return (PAM_CONV_ERR);
-       memset(reply, 0, n * sizeof(*reply));
 
        for (i = 0; i < n; ++i) {
                switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
@@ -1205,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.040565 seconds and 4 git commands to generate.