Imported Upstream version 1.6.9p6
[debian/sudo] / auth / pam.c
index d289a06ef5c3510fdfd34211e5bfc1a6f831d64a..20dd82543d93a0f1db1ecbf7fcae0eb1fed9b6ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,7 @@
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <sys/types.h>
 #include <sys/param.h>
 #include "sudo_auth.h"
 
 /* Only OpenPAM and Linux PAM use const qualifiers. */
-#if defined(_OPENPAM) || defined(__LIBPAM_VERSION)
+#if defined(_OPENPAM) || defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__)
 # define PAM_CONST     const
 #else
 # define PAM_CONST
 #endif
 
 #ifndef lint
-static const char rcsid[] = "$Sudo: pam.c,v 1.43 2004/06/28 14:51:50 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: pam.c,v 1.43.2.7 2007/10/09 00:06:06 millert Exp $";
 #endif /* lint */
 
 static int sudo_conv __P((int, PAM_CONST struct pam_message **,
@@ -94,8 +94,15 @@ pam_init(pw, promptp, auth)
        log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM");
        return(AUTH_FATAL);
     }
-    if (strcmp(user_tty, "unknown"))
-       (void) pam_set_item(pamh, PAM_TTY, user_tty);
+    /*
+     * Some versions of pam_lastlog have a bug that
+     * will cause a crash if PAM_TTY is not set so if
+     * there is no tty, set PAM_TTY to the empty string.
+     */
+    if (user_ttypath == NULL)
+       (void) pam_set_item(pamh, PAM_TTY, "");
+    else
+       (void) pam_set_item(pamh, PAM_TTY, user_ttypath);
 
     return(AUTH_SUCCESS);
 }
@@ -175,15 +182,19 @@ int
 pam_prep_user(pw)
     struct passwd *pw;
 {
+    int eval;
+
     if (pamh == NULL)
        pam_init(pw, NULL, NULL);
 
     /*
      * Set PAM_USER to the user we are changing *to* and
      * set PAM_RUSER to the user we are coming *from*.
+     * We set PAM_RHOST to avoid a bug in Solaris 7 and below.
      */
     (void) pam_set_item(pamh, PAM_USER, pw->pw_name);
     (void) pam_set_item(pamh, PAM_RUSER, user_name);
+    (void) pam_set_item(pamh, PAM_RHOST, user_host);
 
     /*
      * Set credentials (may include resource limits, device ownership, etc).
@@ -195,6 +206,20 @@ pam_prep_user(pw)
      */
     (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
 
+#ifndef NO_PAM_SESSION
+    /*
+     * To fully utilize PAM sessions we would need to keep a
+     * sudo process around until the command exits.  However, we
+     * can at least cause pam_limits to be run by opening and then
+     * immediately closing the session.
+     */
+    if ((eval = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
+       (void) pam_end(pamh, eval | PAM_DATA_SILENT);
+       return(AUTH_FAILURE);
+    }
+    (void) pam_close_session(pamh, 0);
+#endif
+
     if (pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT) == PAM_SUCCESS)
        return(AUTH_SUCCESS);
     else
@@ -235,7 +260,12 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
                    p = pm->msg;
                /* Read the password. */
                pass = tgetpass(p, def_passwd_timeout * 60, flags);
-               pr->resp = estrdup(pass ? pass : "");
+               if (pass == NULL) {
+                   /* We got ^C instead of a password; abort quickly. */
+                   nil_pw = 1;
+                   goto err;
+               }
+               pr->resp = estrdup(pass);
                if (*pr->resp == '\0')
                    nil_pw = 1;         /* empty password */
                else
@@ -252,20 +282,23 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
                }
                break;
            default:
-               /* Zero and free allocated memory and return an error. */
-               for (pr = *response, n = num_msg; n--; pr++) {
-                   if (pr->resp != NULL) {
-                       zero_bytes(pr->resp, strlen(pr->resp));
-                       free(pr->resp);
-                       pr->resp = NULL;
-                   }
-               }
-               zero_bytes(*response, num_msg * sizeof(struct pam_response));
-               free(*response);
-               *response = NULL;
-               return(PAM_CONV_ERR);
+               goto err;
        }
     }
 
     return(PAM_SUCCESS);
+
+err:
+    /* Zero and free allocated memory and return an error. */
+    for (pr = *response, n = num_msg; n--; pr++) {
+       if (pr->resp != NULL) {
+           zero_bytes(pr->resp, strlen(pr->resp));
+           free(pr->resp);
+           pr->resp = NULL;
+       }
+    }
+    zero_bytes(*response, num_msg * sizeof(struct pam_response));
+    free(*response);
+    *response = NULL;
+    return(PAM_CONV_ERR);
 }