I would like to allow pam_setcred/pam_sm_setcred to override the gid
that is normally set for a user. Currently the openssh code calls
do_pam_setcred then it sets the gid to the user's gid as listed in
/etc/passwd, LDAP, or whatever regardless of what the pam module set it
to. I would instead like a pam module to be able to set the gid with
setgid() and not have it overwritten by openssh.
I wrote a patch that does just that by comparing getgid() before and
after calling do_pam_setcred. If the gid changes it sets pw->gid to the
new gid, which is used in later functions. I don't know if this is
considered the proper way to achieve that behavior in a safe way but it
seemed logical to me. The behavior is optional; PermitGidOverride=no is
the default.
As for the reasoning, this is for a scheduled environment using Slurm.
I am developing a pam module that "adopts" ssh processes into the
appropriate batch job on the node. Users can launch jobs via Slurm that
run with their gid as one of their supplementary groups. As part of the
adoption of the ssh process, I would like to set the ssh process's gid
equal to that of the job it is being adopted into.
Ryan
diff --git a/auth-pam.c b/auth-pam.c
index d789bad..24edac0 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -929,14 +929,17 @@ do_pam_set_tty(const char *tty)
fatal("PAM: failed to set PAM_TTY: %s",
pam_strerror(sshpam_handle, sshpam_err));
}
}
void
-do_pam_setcred(int init)
+do_pam_setcred(int init, struct passwd *pw)
{
+ gid_t gid_pre_setcred, gid_post_setcred;
+
+ gid_pre_setcred = getgid();
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
(const void *)&store_conv);
if (sshpam_err != PAM_SUCCESS)
fatal("PAM: failed to set PAM_CONV: %s",
pam_strerror(sshpam_handle, sshpam_err));
if (init) {
@@ -945,12 +948,23 @@ do_pam_setcred(int init)
} else {
debug("PAM: reinitializing credentials");
sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
}
if (sshpam_err == PAM_SUCCESS) {
sshpam_cred_established = 1;
+ gid_post_setcred = getgid();
+
+ /* If PermitGidOverride=yes, persist the new gid if a PAM module
+ * overrides it */
+ if (options.permit_gid_override &&
+ gid_pre_setcred != gid_post_setcred) {
+ verbose("Overriding gid to %u from %u",
+ (u_int)gid_post_setcred,
+ (u_int)gid_pre_setcred);
+ pw->pw_gid = gid_post_setcred;
+ }
return;
}
if (sshpam_authenticated)
fatal("PAM: pam_setcred(): %s",
pam_strerror(sshpam_handle, sshpam_err));
else
diff --git a/auth-pam.h b/auth-pam.h
index a1a2b52..58ee0bb 100644
--- a/auth-pam.h
+++ b/auth-pam.h
@@ -33,13 +33,13 @@
void start_pam(Authctxt *);
void finish_pam(void);
u_int do_pam_account(void);
void do_pam_session(void);
void do_pam_set_tty(const char *);
-void do_pam_setcred(int );
+void do_pam_setcred(int, struct passwd *);
void do_pam_chauthtok(void);
int do_pam_putenv(char *, char *);
char ** fetch_pam_environment(void);
char ** fetch_pam_child_environment(void);
void free_pam_environment(char **);
void sshpam_thread_cleanup(void);
diff --git a/platform.c b/platform.c
index ee313da..3fe688d 100644
--- a/platform.c
+++ b/platform.c
@@ -121,13 +121,13 @@ platform_setusercontext(struct passwd *pw)
/*
* If we have both LOGIN_CAP and PAM, we want to establish creds
* before calling setusercontext (in session.c:do_setusercontext).
*/
if (getuid() == 0 || geteuid() == 0) {
if (options.use_pam) {
- do_pam_setcred(use_privsep);
+ do_pam_setcred(use_privsep, pw);
}
}
# endif /* USE_PAM */
#if !defined(HAVE_LOGIN_CAP) && defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
if (getuid() == 0 || geteuid() == 0) {
@@ -149,13 +149,13 @@ platform_setusercontext_post_groups(struct passwd *pw)
/*
* PAM credentials may take the form of supplementary groups.
* These will have been wiped by the above initgroups() call.
* Reestablish them here.
*/
if (options.use_pam) {
- do_pam_setcred(use_privsep);
+ do_pam_setcred(use_privsep, pw);
}
#endif /* USE_PAM */
#if !defined(HAVE_LOGIN_CAP) && (defined(WITH_IRIX_PROJECT) || \
defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY))
irix_setusercontext(pw);
diff --git a/servconf.c b/servconf.c
index 3185462..a6e6fe7 100644
--- a/servconf.c
+++ b/servconf.c
@@ -71,12 +71,13 @@ void
initialize_server_options(ServerOptions *options)
{
memset(options, 0, sizeof(*options));
/* Portable-specific options */
options->use_pam = -1;
+ options->permit_gid_override = -1;
/* Standard Options */
options->num_ports = 0;
options->ports_from_cmdline = 0;
options->listen_addrs = NULL;
options->address_family = -1;
@@ -177,12 +178,14 @@ fill_default_server_options(ServerOptions *options)
{
int i;
/* Portable-specific options */
if (options->use_pam == -1)
options->use_pam = 0;
+ if (options->permit_gid_override == -1)
+ options->permit_gid_override = 0;
/* Standard Options */
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_2;
if (options->num_host_key_files == 0) {
/* fill default hostkeys for protocols */
@@ -367,13 +370,13 @@ fill_default_server_options(ServerOptions *options)
}
/* Keyword tokens. */
typedef enum {
sBadOption, /* == unknown option */
/* Portable-specific options */
- sUsePAM,
+ sUsePAM, sPermitGidOverride,
/* Standard Options */
sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime,
sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel,
sRhostsRSAAuthentication, sRSAAuthentication,
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
sKerberosGetAFSToken,
@@ -414,12 +417,13 @@ static struct {
ServerOpCodes opcode;
u_int flags;
} keywords[] = {
/* Portable-specific options */
#ifdef USE_PAM
{ "usepam", sUsePAM, SSHCFG_GLOBAL },
+ { "permitgidoverride", sPermitGidOverride, SSHCFG_GLOBAL },
#else
{ "usepam", sUnsupported, SSHCFG_GLOBAL },
#endif
{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
/* Standard Options */
{ "port", sPort, SSHCFG_GLOBAL },
@@ -1227,12 +1231,16 @@ process_server_config_line(ServerOptions *options, char *line,
goto parse_flag;
case sPermitUserEnvironment:
intptr = &options->permit_user_env;
goto parse_flag;
+ case sPermitGidOverride:
+ intptr = &options->permit_gid_override;
+ goto parse_flag;
+
case sUseLogin:
intptr = &options->use_login;
goto parse_flag;
case sCompression:
intptr = &options->compression;
@@ -2092,12 +2100,13 @@ dump_config(ServerOptions *o)
}
}
/* integer arguments */
#ifdef USE_PAM
dump_cfg_int(sUsePAM, o->use_pam);
+ dump_cfg_fmtint(sPermitGidOverride, o->permit_gid_override);
#endif
dump_cfg_int(sServerKeyBits, o->server_key_bits);
dump_cfg_int(sLoginGraceTime, o->login_grace_time);
dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
dump_cfg_int(sMaxAuthTries, o->max_authtries);
diff --git a/servconf.h b/servconf.h
index 9922f0c..630fb67 100644
--- a/servconf.h
+++ b/servconf.h
@@ -120,12 +120,13 @@ typedef struct {
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
int challenge_response_authentication;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int permit_user_env; /* If true, read ~/.ssh/environment */
+ int permit_gid_override; /* Allow gid to be overriden by PAM */
int use_login; /* If true, login(1) is used */
int compression; /* If true, compression is allowed */
int allow_tcp_forwarding; /* One of FORWARD_* */
int allow_streamlocal_forwarding; /* One of FORWARD_* */
int allow_agent_forwarding;
u_int num_allow_users;
diff --git a/sshd.c b/sshd.c
index 6aa17fa..d1edfd0 100644
--- a/sshd.c
+++ b/sshd.c
@@ -2217,13 +2217,13 @@ main(int ac, char **av)
ssh_gssapi_storecreds();
restore_uid();
}
#endif
#ifdef USE_PAM
if (options.use_pam) {
- do_pam_setcred(1);
+ do_pam_setcred(1, authctxt->pw);
do_pam_session();
}
#endif
/*
* In privilege separation, we fork another child and prepare
diff --git a/sshd_config b/sshd_config
index c9042ac..216e941 100644
--- a/sshd_config
+++ b/sshd_config
@@ -93,12 +93,15 @@ AuthorizedKeysFile .ssh/authorized_keys
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
#UsePAM no
+# Allow PAM to override the process's gid
+#PermitGidOverride no
+
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
diff --git a/sshd_config.5 b/sshd_config.5
index 6dce0c7..52d0a52 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -990,12 +990,13 @@ Available keywords are
.Cm KbdInteractiveAuthentication ,
.Cm KerberosAuthentication ,
.Cm MaxAuthTries ,
.Cm MaxSessions ,
.Cm PasswordAuthentication ,
.Cm PermitEmptyPasswords ,
+.Cm PermitGidOverride ,
.Cm PermitOpen ,
.Cm PermitRootLogin ,
.Cm PermitTTY ,
.Cm PermitTunnel ,
.Cm PermitUserRC ,
.Cm PubkeyAcceptedKeyTypes ,
@@ -1050,12 +1051,15 @@ The default is
.Dq yes .
.It Cm PermitEmptyPasswords
When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings.
The default is
.Dq no .
+.It Cm PermitGidOverride
+Allow PAM modules to override the gid of a process. The default is
+.Dq no .
.It Cm PermitOpen
Specifies the destinations to which TCP port forwarding is permitted.
The forwarding specification must be one of the following forms:
.Pp
.Bl -item -offset indent -compact
.It
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev