Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/su Rewrite PAMification of su.



details:   https://anonhg.NetBSD.org/src/rev/2fb5a5877642
branches:  trunk
changeset: 572652:2fb5a5877642
user:      manu <manu%NetBSD.org@localhost>
date:      Sun Jan 09 21:32:38 2005 +0000

description:
Rewrite PAMification of su.
- don't try to fallback to plain old authentication. It could lead to unix
  authentication to be used while the administrator wanted to forbid it.
  Moreover, a broken PAM setup can be fixed by just rebooting in single user.
- In order to make the code more readable, make two main(), with and aithout
  PAM.
- Outstanding issues that seem impossible to fix:
  The -K flag die with PAM.
  -c cause PAM credentials to be ignored.

diffstat:

 usr.bin/su/su.c |  601 ++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 439 insertions(+), 162 deletions(-)

diffs (truncated from 745 to 300 lines):

diff -r 06616012b65d -r 2fb5a5877642 usr.bin/su/su.c
--- a/usr.bin/su/su.c   Sun Jan 09 21:32:08 2005 +0000
+++ b/usr.bin/su/su.c   Sun Jan 09 21:32:38 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: su.c,v 1.62 2005/01/08 22:16:23 manu Exp $     */
+/*     $NetBSD: su.c,v 1.63 2005/01/09 21:32:38 manu Exp $     */
 
 /*
  * Copyright (c) 1988 The Regents of the University of California.
@@ -40,16 +40,16 @@
 #if 0
 static char sccsid[] = "@(#)su.c       8.3 (Berkeley) 4/2/94";*/
 #else
-__RCSID("$NetBSD: su.c,v 1.62 2005/01/08 22:16:23 manu Exp $");
+__RCSID("$NetBSD: su.c,v 1.63 2005/01/09 21:32:38 manu Exp $");
 #endif
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/time.h>
+#include <sys/resource.h>
 #ifdef USE_PAM
 #include <sys/wait.h>
 #endif
-#include <sys/resource.h>
 #include <err.h>
 #include <errno.h>
 #include <grp.h>
@@ -69,32 +69,16 @@
 #ifdef USE_PAM
 #include <security/pam_appl.h>
 #include <security/openpam.h>   /* for openpam_ttyconv() */
-
-static pam_handle_t *pamh;
-static struct pam_conv pamc;
-
-#define fatal(x) do { \
-       if (pam_err == PAM_SUCCESS) \
-               pam_end(pamh, pam_err); \
-       err x;  \
-} while (/*CONSTCOND*/ 0)
-#define fatalx(x) do { \
-       if (pam_err == PAM_SUCCESS) \
-               pam_end(pamh, pam_err); \
-       errx x; \
-} while (/*CONSTCOND*/ 0)
-
-#else
-#define fatal(x) err x
-#define fatalx(x) errx x
-
+ 
+static pam_handle_t *pamh = NULL;
+static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
 #endif
 
 #ifdef LOGIN_CAP
 #include <login_cap.h>
 #endif
 
-#ifdef KERBEROS
+#if defined(KERBEROS) && !defined(USE_PAM)
 #include <des.h>
 #include <krb.h>
 #include <netdb.h>
@@ -104,7 +88,7 @@
 
 #endif
 
-#ifdef KERBEROS5
+#if defined(KERBEROS5) && !defined(USE_PAM)
 #include <krb5.h>
 
 static int kerberos5 __P((char *, char *, int));
@@ -135,9 +119,12 @@
 
 static int chshell __P((const char *));
 static char *ontty __P((void));
+#ifndef USE_PAM
 static int check_ingroup __P((int, const char *, const char *, int));
+#endif
 
 
+#ifndef USE_PAM
 int
 main(argc, argv)
        int argc;
@@ -159,18 +146,6 @@
 #ifdef LOGIN_CAP
        login_cap_t *lc;
 #endif
-#ifdef USE_PAM
-       char **pam_envlist, **pam_env;
-       char hostname[MAXHOSTNAMELEN];
-       const char **usernamep;
-       char *tty; 
-       int pam_err, status;
-       pid_t pid;
-#ifdef notdef
-       extern int _openpam_debug;
-       _openpam_debug = 1;
-#endif
-#endif
 
        asme = asthem = fastlogin = 0;
        gohome = 1;
@@ -225,99 +200,16 @@
        /* get current login name and shell */
        ruid = getuid();
        username = getlogin();
-       /* get target login information, default to root */
-       user = *argv ? *argv : "root";
-
-#ifdef USE_PAM
-       pamc.conv = &openpam_ttyconv;
-       pam_start("su", user, &pamc, &pamh);
-
-       /* Fill in hostname, username and tty */        
-       if ((pam_err = pam_set_item(pamh, PAM_RUSER, username)) != PAM_SUCCESS)
-               goto pam_failed;
-
-       gethostname(hostname, sizeof(hostname));
-       if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
-               goto pam_failed;
-       
-       tty = ttyname(STDERR_FILENO);
-       if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
-               goto pam_failed;
-
-       /* authentication */
-       if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
-               goto pam_failed;
-
-       if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
-               pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
-       if (pam_err != PAM_SUCCESS)
-               goto pam_failed;
-
-       /* Get user credentials */
-       if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
-               goto pam_failed;
-
-       /* Open the session */
-       if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
-               goto pam_failed;
-
-       /* New user name? */
-       usernamep = (const char **)&username;
-       pam_err = pam_get_item(pamh, PAM_USER, (const void **)usernamep);
-       if (pam_err != PAM_SUCCESS)
-               goto pam_failed;
-
-pam_failed:
-       /*
-        * If PAM is broken, fallback to plain old authentication.
-        * Do not do that on authentication errors.
-        */     
-       switch(pam_err) {
-       case PAM_SUCCESS:
-               break;
-
-       case PAM_ABORT:
-       case PAM_BUF_ERR:
-       case PAM_SYMBOL_ERR:
-       case PAM_SYSTEM_ERR:
-               warnx("PAM failed: %s", pam_strerror(pamh, pam_err));
-               warnx("fallback to plain old authentication");
-               pam_end(pamh, pam_err);
-               username = getlogin();
-               break;
-
-       default:
-               fatalx((1, "Sorry: %s\n", pam_strerror(pamh, pam_err)));
-               break;
-       }       
-
-       /* 
-        * Now any failure should use fatal/fatalx instead of err/errx
-        * so that pam_end() is called on errors.
-        */
-#endif
        if (username == NULL || (pwd = getpwnam(username)) == NULL ||
            pwd->pw_uid != ruid)
                pwd = getpwuid(ruid);
        if (pwd == NULL)
-               fatalx((1, "who are you?"));
-
+               errx(1, "who are you?");
        username = strdup(pwd->pw_name);
        userpass = strdup(pwd->pw_passwd);
        if (username == NULL || userpass == NULL)
-               fatal((1, "strdup"));
+               err(1, "strdup");
 
-#ifdef USE_PAM
-       /* Get PAM environment */
-       if ((pam_err == PAM_SUCCESS) && 
-           ((pam_envlist = pam_getenvlist(pamh)) != NULL)) {
-               for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
-                       putenv(*pam_env);
-                       free(*pam_env);
-               }
-               free(pam_envlist);
-       }
-#endif
 
        if (asme) {
                if (pwd->pw_shell && *pwd->pw_shell) {
@@ -328,20 +220,23 @@
                        iscsh = NO;
                }
        }
+       /* get target login information, default to root */
+       user = *argv ? *argv : "root";
        np = *argv ? argv : argv-1;
 
        if ((pwd = getpwnam(user)) == NULL)
-               fatalx((1, "unknown login %s", user));
+               errx(1, "unknown login %s", user);
 
 #ifdef LOGIN_CAP
        /* force the usage of specified class */
        if (class) {
                if (ruid)
-                       fatalx((1, "Only root may use -c"));
+                       errx(1, "Only root may use -c");
 
                pwd->pw_class = class;
        }
-       lc = login_getclass(pwd->pw_class);
+       if ((lc = login_getclass(pwd->pw_class)) == NULL)
+               errx(1, "Unknown class %s\n", pwd->pw_class);
 
        pw_warntime = login_getcaptime(lc, "password-warn",  
                                     _PASSWORD_WARNDAYS * SECSPERDAY,
@@ -349,9 +244,6 @@
 #endif
 
        if (ruid
-#ifdef USE_PAM 
-           && (pam_err != PAM_SUCCESS)
-#endif
 #ifdef KERBEROS5
            && (!use_kerberos || kerberos5(username, user, pwd->pw_uid))
 #endif
@@ -383,18 +275,17 @@
                        ok = check_ingroup(-1, SU_GROUP, username, 1);
                }
                if (!ok)
-                       fatalx((1,
+                       errx(1,
            "you are not listed in the correct secondary group (%s) to su %s.",
-                                           SU_GROUP, user));
+                                           SU_GROUP, user);
                /* if target requires a password, verify it */
                if (*pass) {
                        p = getpass("Password:");
 #ifdef SKEY
                        if (strcasecmp(p, "s/key") == 0) {
-                               if (skey_haskey(user)) {
-                                       fatalx((1, 
-                                           "Sorry, you have no s/key."));
-                               } else {
+                               if (skey_haskey(user))
+                                       errx(1, "Sorry, you have no s/key.");
+                               else {
                                        if (skey_authenticate(user)) {
                                                goto badlogin;
                                        }
@@ -418,7 +309,7 @@
        if (asme) {
                /* if asme and non-standard target shell, must be root */
                if (!chshell(pwd->pw_shell) && ruid)
-                       fatalx((1,"permission denied (shell)."));
+                       errx(1,"permission denied (shell).");
        } else if (pwd->pw_shell && *pwd->pw_shell) {
                shell = pwd->pw_shell;
                iscsh = UNSET;
@@ -436,34 +327,6 @@
        if (iscsh == UNSET)
                iscsh = strstr(avshell, "csh") ? YES : NO;
 
-#ifdef USE_PAM
-       /* 
-        * If PAM is in use, we must release PAM resources and close
-        * the session after su child exits. That requires a fork now,
-        * before we drop the root privs (needed for PAM)
-        */
-       if (pam_err == PAM_SUCCESS) {
-               switch(pid = fork()) {
-               case -1:
-                       fatal((1, "fork"));
-                       break;
-               case 0:         /* child */
-                       break;
-               default:        /* parent */
-                       waitpid(pid, &status, 0);       
-                       pam_err = pam_close_session(pamh, 0);
-                       pam_end(pamh, pam_err);
-



Home | Main Index | Thread Index | Old Index