]> andersk Git - gssapi-openssh.git/commitdiff
enable PAM user switching
authorbasney <basney>
Wed, 19 Aug 2009 19:59:13 +0000 (19:59 +0000)
committerbasney <basney>
Wed, 19 Aug 2009 19:59:13 +0000 (19:59 +0000)
https://bugzilla.mcs.anl.gov/globus/show_bug.cgi?id=6839

openssh/auth-pam.c
openssh/auth-pam.h
openssh/auth.c
openssh/misc.c
openssh/misc.h
openssh/servconf.c
openssh/servconf.h
openssh/sshd_config
openssh/sshd_config.5

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",
index 93a1eca4f66c14e20fda903c6b9e50384c041a55..c2cb6dc6e0ceef900819f99b5cc772b4ea89323c 100644 (file)
@@ -46,5 +46,6 @@ void sshpam_thread_cleanup(void);
 void sshpam_cleanup(void);
 int sshpam_auth_passwd(Authctxt *, const char *);
 int is_pam_session_open(void);
+struct passwd *sshpam_getpw(const char *);
 
 #endif /* USE_PAM */
index 2106dfccf8e64c61ebc21b2a60c0982e1c265e3a..010e550ac7dcdd1ce1d596c8b034442a95ecbe8a 100644 (file)
@@ -527,6 +527,10 @@ getpwnamallow(const char *user)
            get_canonical_hostname(options.use_dns), get_remote_ipaddr());
 
        pw = getpwnam(user);
+#ifdef USE_PAM
+       if (options.use_pam && options.permit_pam_user_change && pw == NULL)
+               pw = sshpam_getpw(user);
+#endif
        if (pw == NULL) {
                logit("Invalid user %.100s from %.100s",
                      (user && user[0]) ? user : "unknown",
index 83efdedb0a653fcbd00e5827565f3754737a5b8e..c447d234cc3f83a7e360fb5ca280a7b1dde91799 100644 (file)
@@ -237,6 +237,20 @@ pwcopy(struct passwd *pw)
        return copy;
 }
 
+void
+pwfree(struct passwd *pw)
+{
+       xfree(pw->pw_name);
+       xfree(pw->pw_passwd);
+       xfree(pw->pw_gecos);
+#ifdef HAVE_PW_CLASS_IN_PASSWD
+       xfree(pw->pw_class);
+#endif
+       xfree(pw->pw_dir);
+       xfree(pw->pw_shell);
+       xfree(pw);
+}
+
 /*
  * Convert ASCII string to TCP/IP port number.
  * Port must be >=0 and <=65535.
index fc564527140dc443b6fab6bf9adafb8fbe713a96..b7299e3f52494f778afff483728ee5db35d969f5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: misc.h,v 1.10 2001/06/26 17:27:24 markus Exp $        */
+/* $OpenBSD: misc.h,v 1.38 2008/06/12 20:38:28 dtucker Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * called by a name other than "ssh" or "Secure Shell".
  */
 
+#ifndef _MISC_H
+#define _MISC_H
+
+/* misc.c */
+
 char   *chop(char *);
 char   *strdelim(char **);
-void    set_nonblock(int);
-void    unset_nonblock(int);
+int     set_nonblock(int);
+int     unset_nonblock(int);
+void    set_nodelay(int);
 int     a2port(const char *);
+int     a2tun(const char *, int *);
+char   *put_host_port(const char *, u_short);
+char   *hpdelim(char **);
 char   *cleanhostname(char *);
 char   *colon(char *);
 long    convtime(const char *);
+char   *tilde_expand_filename(const char *, uid_t);
+char   *percent_expand(const char *, ...) __attribute__((__sentinel__));
+char   *tohex(const void *, size_t);
+void    sanitise_stdfd(void);
+void    ms_subtract_diff(struct timeval *, int *);
+void    ms_to_timeval(struct timeval *, int);
 
 struct passwd *pwcopy(struct passwd *);
+void    pwfree(struct passwd *);
+const char *ssh_gai_strerror(int);
 
 typedef struct arglist arglist;
 struct arglist {
-        char    **list;
-        int     num;
-        int     nalloc;
+       char    **list;
+       u_int   num;
+       u_int   nalloc;
 };
-void    addargs(arglist *, char *, ...) __attribute__((format(printf, 2, 3)));
+void    addargs(arglist *, char *, ...)
+            __attribute__((format(printf, 2, 3)));
+void    replacearg(arglist *, u_int, char *, ...)
+            __attribute__((format(printf, 3, 4)));
+void    freeargs(arglist *);
+
+int     tun_open(int, int);
+
+/* Common definitions for ssh tunnel device forwarding */
+#define SSH_TUNMODE_NO         0x00
+#define SSH_TUNMODE_POINTOPOINT        0x01
+#define SSH_TUNMODE_ETHERNET   0x02
+#define SSH_TUNMODE_DEFAULT    SSH_TUNMODE_POINTOPOINT
+#define SSH_TUNMODE_YES                (SSH_TUNMODE_POINTOPOINT|SSH_TUNMODE_ETHERNET)
+
+#define SSH_TUNID_ANY          0x7fffffff
+#define SSH_TUNID_ERR          (SSH_TUNID_ANY - 1)
+#define SSH_TUNID_MAX          (SSH_TUNID_ANY - 2)
+
+/* Functions to extract or store big-endian words of various sizes */
+u_int64_t      get_u64(const void *)
+    __attribute__((__bounded__( __minbytes__, 1, 8)));
+u_int32_t      get_u32(const void *)
+    __attribute__((__bounded__( __minbytes__, 1, 4)));
+u_int16_t      get_u16(const void *)
+    __attribute__((__bounded__( __minbytes__, 1, 2)));
+void           put_u64(void *, u_int64_t)
+    __attribute__((__bounded__( __minbytes__, 1, 8)));
+void           put_u32(void *, u_int32_t)
+    __attribute__((__bounded__( __minbytes__, 1, 4)));
+void           put_u16(void *, u_int16_t)
+    __attribute__((__bounded__( __minbytes__, 1, 2)));
+
+
+/* readpass.c */
+
+#define RP_ECHO                        0x0001
+#define RP_ALLOW_STDIN         0x0002
+#define RP_ALLOW_EOF           0x0004
+#define RP_USE_ASKPASS         0x0008
+
+char   *read_passphrase(const char *, int);
+int     ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
+int     read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
 
-/* wrapper for signal interface */
-typedef void (*mysig_t)(int);
-mysig_t mysignal(int sig, mysig_t act);
+#endif /* _MISC_H */
index a693e05aa71b1e9ca6d647b6a7293d099ea6fad7..90c0eb7cc7edc6402e38a16a133c1ebf3b7a1bda 100644 (file)
@@ -58,6 +58,7 @@ initialize_server_options(ServerOptions *options)
 
        /* Portable-specific options */
        options->use_pam = -1;
+       options->permit_pam_user_change = -1;
 
        /* Standard Options */
        options->num_ports = 0;
@@ -154,6 +155,8 @@ fill_default_server_options(ServerOptions *options)
        /* Portable-specific options */
        if (options->use_pam == -1)
                options->use_pam = 0;
+       if (options->permit_pam_user_change == -1)
+               options->permit_pam_user_change = 0;
 
        /* Standard Options */
        if (options->protocol == SSH_PROTO_UNKNOWN)
@@ -343,7 +346,7 @@ fill_default_server_options(ServerOptions *options)
 typedef enum {
        sBadOption,             /* == unknown option */
        /* Portable-specific options */
-       sUsePAM,
+       sUsePAM, sPermitPAMUserChange,
        /* Standard Options */
        sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
        sPermitRootLogin, sLogFacility, sLogLevel,
@@ -394,8 +397,10 @@ static struct {
        /* Portable-specific options */
 #ifdef USE_PAM
        { "usepam", sUsePAM, SSHCFG_GLOBAL },
+       { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL }
 #else
        { "usepam", sUnsupported, SSHCFG_GLOBAL },
+       { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL },
 #endif
        { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
        /* Standard Options */
@@ -777,6 +782,10 @@ process_server_config_line(ServerOptions *options, char *line,
                intptr = &options->use_pam;
                goto parse_flag;
 
+       case sPermitPAMUserChange:
+               intptr = &options->permit_pam_user_change;
+               goto parse_flag;
+
        /* Standard Options */
        case sBadOption:
                return -1;
index 6ca0980ca166b45c76ad021f8949b45d7902d463..fd8b90975c7d5331b477e8a12817c183d3b181e0 100644 (file)
@@ -155,6 +155,7 @@ typedef struct {
        char   *adm_forced_command;
 
        int     use_pam;                /* Enable auth via PAM */
+       int     permit_pam_user_change; /* Allow PAM to change user name */
         int     none_enabled;           /* enable NONE cipher switch */
         int     tcp_rcv_buf_poll;       /* poll tcp rcv window in autotuning kernels*/
        int     hpn_disabled;           /* disable hpn functionality. false by default */
index cf5d1d05862a2c68d4cb93cedaf123bf389f14fb..f1f4a100619e51528082e7d16eede9fc4a84a78e 100644 (file)
@@ -93,6 +93,10 @@ Protocol 2
 # and ChallengeResponseAuthentication to 'no'.
 #UsePAM no
 
+# Set to 'yes' to allow the PAM stack to change the user name during
+# calls to authentication
+#PermitPAMUserChange no
+
 #AllowAgentForwarding yes
 #AllowTcpForwarding yes
 #GatewayPorts no
index 6649d329d8f34b24b51dc330cdbe1affff094c7d..414be2458674427f39da00a692afab994890bd8e 100644 (file)
@@ -966,6 +966,12 @@ is enabled, you will not be able to run
 as a non-root user.
 The default is
 .Dq no .
+.It Cm PermitPAMUserChange
+If set to
+.Dq yes
+this will enable PAM authentication to change the name of the user being
+authenticated.  The default is
+.Dq no .
 .It Cm UsePrivilegeSeparation
 Specifies whether
 .Xr sshd 8
This page took 0.169141 seconds and 5 git commands to generate.