Bugzilla – Attachment 3253 Details for
Bug 2980
New feature: Configure PAM Service Name in sshd_config
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch including session handling fixes
full.patch (text/plain), 14.05 KB, created by
Eric Price
on 2019-03-14 21:50:44 AEDT
(
hide
)
Description:
patch including session handling fixes
Filename:
MIME Type:
Creator:
Eric Price
Created:
2019-03-14 21:50:44 AEDT
Size:
14.05 KB
patch
obsolete
>diff --git a/auth-pam.c b/auth-pam.c >index bde0a8f..d3efd22 100644 >--- a/auth-pam.c >+++ b/auth-pam.c >@@ -239,6 +239,7 @@ pthread_join(sp_pthread_t thread, void **value) > > > static pam_handle_t *sshpam_handle = NULL; >+static pam_handle_t *sshpam_password_handle = NULL; > static int sshpam_err = 0; > static int sshpam_authenticated = 0; > static int sshpam_session_open = 0; >@@ -652,53 +653,82 @@ static struct pam_conv store_conv = { sshpam_store_conv, NULL }; > void > sshpam_cleanup(void) > { >- 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_session_open) { >- debug("PAM: closing session"); >- pam_close_session(sshpam_handle, PAM_SILENT); >- sshpam_session_open = 0; >+ if (!(sshpam_handle == NULL || (use_privsep && !mm_is_monitor()))) { >+ debug("PAM: cleanup"); >+ pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv); >+ 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; > } >- if (sshpam_cred_established) { >- debug("PAM: deleting credentials"); >- pam_setcred(sshpam_handle, PAM_DELETE_CRED); >- sshpam_cred_established = 0; >+ if (!(sshpam_password_handle == NULL)) { >+ pam_end(sshpam_password_handle, sshpam_err); >+ sshpam_password_handle = NULL; > } >- sshpam_authenticated = 0; >- pam_end(sshpam_handle, sshpam_err); >- sshpam_handle = NULL; > } > > static int >-sshpam_init(struct ssh *ssh, Authctxt *authctxt) >+sshpam_init(struct ssh *ssh, Authctxt *authctxt, char * service_name, pam_handle_t **sshpam_phandle ) > { > const char *pam_user, *user = authctxt->user; > const char **ptr_pam_user = &pam_user; >+ const char *pam_service; >+ const char **ptr_pam_service = &pam_service; > >- if (sshpam_handle == NULL) { >- if (ssh == NULL) { >+ if (*sshpam_phandle == NULL) { >+ if (ssh == NULL && sshpam_rhost == NULL) { > fatal("%s: called initially with no " > "packet context", __func__); > } >- } if (sshpam_handle != NULL) { >- /* We already have a PAM context; check if the user matches */ >- sshpam_err = pam_get_item(sshpam_handle, >+ } >+ if (*sshpam_phandle != NULL) { >+ /* We already have a PAM context; >+ * check if the user and service name matches */ >+ sshpam_err = pam_get_item(*sshpam_phandle, > PAM_USER, (sshpam_const void **)ptr_pam_user); >- if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) >- return (0); >- pam_end(sshpam_handle, sshpam_err); >- sshpam_handle = NULL; >+ if (sshpam_err == PAM_SUCCESS >+ && strcmp(user, pam_user) == 0 ) { >+ sshpam_err = pam_get_item(*sshpam_phandle, >+ PAM_SERVICE, (sshpam_const void **)ptr_pam_service); >+ if (sshpam_err == PAM_SUCCESS >+ && strncmp(service_name, pam_service, strlen(service_name)) == 0 ) { >+ // full match. no reinit needed. >+ return (0); >+ } >+ } >+ /* >+ * Clean up previous PAM state. No need to clean up session >+ * and creds. >+ */ >+ if (sshpam_phandle == &sshpam_handle) { >+ /* (This is not needed for password auth, it does not change or read these states) */ >+ sshpam_authenticated = 0; >+ sshpam_account_status = -1; >+ } >+ sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, NULL); >+ if (sshpam_err != PAM_SUCCESS) >+ debug3("Cannot remove PAM conv"); /* a warning only */ >+ >+ pam_end(*sshpam_phandle, sshpam_err); >+ *sshpam_phandle = NULL; > } >- debug("PAM: initializing for \"%s\"", user); >+ debug("PAM: (%s) initializing for \"%s\"", service_name, user); > sshpam_err = >- pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); >+ pam_start(service_name, user, &store_conv, sshpam_phandle); > sshpam_authctxt = authctxt; > > if (sshpam_err != PAM_SUCCESS) { >- pam_end(sshpam_handle, sshpam_err); >- sshpam_handle = NULL; >+ pam_end(*sshpam_phandle, sshpam_err); >+ *sshpam_phandle = NULL; > return (-1); > } > >@@ -717,15 +747,15 @@ sshpam_init(struct ssh *ssh, Authctxt *authctxt) > } > if (sshpam_rhost != NULL) { > debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); >- sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, >+ sshpam_err = pam_set_item(*sshpam_phandle, PAM_RHOST, > sshpam_rhost); > if (sshpam_err != PAM_SUCCESS) { >- pam_end(sshpam_handle, sshpam_err); >- sshpam_handle = NULL; >+ pam_end(*sshpam_phandle, sshpam_err); >+ *sshpam_phandle = NULL; > return (-1); > } > /* Put SSH_CONNECTION in the PAM environment too */ >- pam_putenv(sshpam_handle, sshpam_conninfo); >+ pam_putenv(*sshpam_phandle, sshpam_conninfo); > } > > #ifdef PAM_TTY_KLUDGE >@@ -735,10 +765,10 @@ sshpam_init(struct ssh *ssh, Authctxt *authctxt) > * may not even set one (for tty-less connections) > */ > debug("PAM: setting PAM_TTY to \"ssh\""); >- sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh"); >+ sshpam_err = pam_set_item(*sshpam_phandle, PAM_TTY, "ssh"); > if (sshpam_err != PAM_SUCCESS) { >- pam_end(sshpam_handle, sshpam_err); >- sshpam_handle = NULL; >+ pam_end(*sshpam_phandle, sshpam_err); >+ *sshpam_phandle = NULL; > return (-1); > } > #endif >@@ -771,6 +801,7 @@ sshpam_init_ctx(Authctxt *authctxt) > { > struct pam_ctxt *ctxt; > int socks[2]; >+ char *service_name = SSHD_PAM_SERVICE; > > debug3("PAM: %s entering", __func__); > /* >@@ -780,8 +811,11 @@ sshpam_init_ctx(Authctxt *authctxt) > if (!options.use_pam || sshpam_account_status == 0) > return NULL; > >+ if (!( options.pam_service_name == NULL || strcasecmp(options.pam_service_name, "none") == 0)) >+ service_name = options.pam_service_name; >+ > /* Initialize PAM */ >- if (sshpam_init(NULL, authctxt) == -1) { >+ if (sshpam_init(NULL, authctxt, service_name, &sshpam_handle) == -1) { > error("PAM: initialization failed"); > return (NULL); > } >@@ -1022,11 +1056,15 @@ void > start_pam(struct ssh *ssh) > { > Authctxt *authctxt = (Authctxt *)ssh->authctxt; >+ char *service_name = SSHD_PAM_SERVICE; > > if (!options.use_pam) > fatal("PAM: initialisation requested when UsePAM=no"); > >- if (sshpam_init(ssh, authctxt) == -1) >+ if (!( options.pam_service_name == NULL || strcasecmp(options.pam_service_name, "none") == 0)) >+ service_name = options.pam_service_name; >+ >+ if (sshpam_init(ssh, authctxt, service_name, &sshpam_handle) == -1) > fatal("PAM: initialisation failed"); > } > >@@ -1316,10 +1354,19 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) > int flags = (options.permit_empty_passwd == 0 ? > PAM_DISALLOW_NULL_AUTHTOK : 0); > char *fake = NULL; >+ char *service_name = SSHD_PAM_SERVICE; > >- if (!options.use_pam || sshpam_handle == NULL) >- fatal("PAM: %s called when PAM disabled or failed to " >- "initialise.", __func__); >+ if (!options.use_pam) >+ fatal("PAM: %s called when PAM disabled.", __func__); >+ >+ if (!( options.pam_service_name == NULL || strcasecmp(options.pam_service_name, "none") == 0)) >+ service_name = options.pam_service_name; >+ >+ if (!( options.password_pam_service_name == NULL || strcasecmp(options.password_pam_service_name, "none") == 0)) >+ service_name = options.password_pam_service_name; >+ >+ if (sshpam_init(NULL, authctxt, service_name, &sshpam_password_handle) == -1) >+ fatal("PAM: initialisation for password authentication failed"); > > sshpam_password = password; > sshpam_authctxt = authctxt; >@@ -1333,13 +1380,13 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) > options.permit_root_login != PERMIT_YES)) > sshpam_password = fake = fake_password(password); > >- sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, >+ sshpam_err = pam_set_item(sshpam_password_handle, PAM_CONV, > (const void *)&passwd_conv); > if (sshpam_err != PAM_SUCCESS) > fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, >- pam_strerror(sshpam_handle, sshpam_err)); >+ pam_strerror(sshpam_password_handle, sshpam_err)); > >- sshpam_err = pam_authenticate(sshpam_handle, flags); >+ sshpam_err = pam_authenticate(sshpam_password_handle, flags); > sshpam_password = NULL; > free(fake); > if (sshpam_err == PAM_MAXTRIES) >@@ -1351,7 +1398,7 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) > } else { > debug("PAM: password authentication failed for %.100s: %s", > authctxt->valid ? authctxt->user : "an illegal user", >- pam_strerror(sshpam_handle, sshpam_err)); >+ pam_strerror(sshpam_password_handle, sshpam_err)); > return 0; > } > } >diff --git a/servconf.c b/servconf.c >index a7bfba8..5389a2e 100644 >--- a/servconf.c >+++ b/servconf.c >@@ -83,6 +83,8 @@ initialize_server_options(ServerOptions *options) > > /* Portable-specific options */ > options->use_pam = -1; >+ options->pam_service_name = NULL; >+ options->password_pam_service_name = NULL; > > /* Standard Options */ > options->num_ports = 0; >@@ -439,6 +441,10 @@ fill_default_server_options(ServerOptions *options) > v = NULL; \ > } \ > } while(0) >+ /* Portable-specific options */ >+ CLEAR_ON_NONE(options->pam_service_name); >+ CLEAR_ON_NONE(options->password_pam_service_name); >+ /* Standard Options */ > CLEAR_ON_NONE(options->pid_file); > CLEAR_ON_NONE(options->xauth_location); > CLEAR_ON_NONE(options->banner); >@@ -478,6 +484,8 @@ typedef enum { > sBadOption, /* == unknown option */ > /* Portable-specific options */ > sUsePAM, >+ sPAMServiceName, >+ sPasswordPAMServiceName, > /* Standard Options */ > sPort, sHostKeyFile, sLoginGraceTime, > sPermitRootLogin, sLogFacility, sLogLevel, >@@ -527,8 +535,12 @@ static struct { > /* Portable-specific options */ > #ifdef USE_PAM > { "usepam", sUsePAM, SSHCFG_GLOBAL }, >+ { "pamservicename", sPAMServiceName, SSHCFG_ALL }, >+ { "passwordpamservicename", sPasswordPAMServiceName, SSHCFG_ALL }, > #else > { "usepam", sUnsupported, SSHCFG_GLOBAL }, >+ { "pamservicename", sUnsupported, SSHCFG_ALL }, >+ { "passwordpamservicename", sUnsupported, SSHCFG_ALL }, > #endif > { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, > /* Standard Options */ >@@ -1270,6 +1282,22 @@ process_server_config_line(ServerOptions *options, char *line, > intptr = &options->use_pam; > goto parse_flag; > >+ case sPAMServiceName: >+ charptr = &options->pam_service_name; >+parse_string: >+ arg = strdelim(&cp); >+ if (!arg || *arg == '\0') >+ fatal("%s line %d: missing string argument.", >+ filename, linenum); >+ if (*activep && *charptr == NULL) { >+ *charptr = xstrdup(arg); >+ } >+ break; >+ >+ case sPasswordPAMServiceName: >+ charptr = &options->password_pam_service_name; >+ goto parse_string; >+ > /* Standard Options */ > case sBadOption: > return -1; >@@ -2345,6 +2373,17 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) > } \ > } while(0) > >+ M_CP_STROPT(pam_service_name); >+ if (option_clear_or_none(dst->pam_service_name)) { >+ free(dst->pam_service_name); >+ dst->pam_service_name = NULL; >+ } >+ M_CP_STROPT(password_pam_service_name); >+ if (option_clear_or_none(dst->password_pam_service_name)) { >+ free(dst->password_pam_service_name); >+ dst->password_pam_service_name = NULL; >+ } >+ > /* See comment in servconf.h */ > COPY_MATCH_STRING_OPTS(); > >@@ -2552,6 +2591,10 @@ dump_config(ServerOptions *o) > /* integer arguments */ > #ifdef USE_PAM > dump_cfg_fmtint(sUsePAM, o->use_pam); >+ dump_cfg_string(sPAMServiceName, *o->pam_service_name == '\0' >+ ? "none" : o->pam_service_name); >+ dump_cfg_string(sPasswordPAMServiceName, *o->password_pam_service_name == '\0' >+ ? "none" : o->password_pam_service_name); > #endif > dump_cfg_int(sLoginGraceTime, o->login_grace_time); > dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); >diff --git a/servconf.h b/servconf.h >index 54e0a8d..1657a7e 100644 >--- a/servconf.h >+++ b/servconf.h >@@ -183,6 +183,8 @@ typedef struct { > char *adm_forced_command; > > int use_pam; /* Enable auth via PAM */ >+ char *pam_service_name; >+ char *password_pam_service_name; > > int permit_tun; > >diff --git a/sshd_config.5 b/sshd_config.5 >index 142f84a..9eb6ec4 100644 >--- a/sshd_config.5 >+++ b/sshd_config.5 >@@ -1137,7 +1137,9 @@ Available keywords are > .Cm LogLevel , > .Cm MaxAuthTries , > .Cm MaxSessions , >+.Cm PAMServiceName , > .Cm PasswordAuthentication , >+.Cm PasswordPAMServiceName , > .Cm PermitEmptyPasswords , > .Cm PermitListen , > .Cm PermitOpen , >@@ -1191,10 +1193,57 @@ will refuse connection attempts with a probability of rate/100 (30%) > if there are currently start (10) unauthenticated connections. > The probability increases linearly and all connection attempts > are refused if the number of unauthenticated connections reaches full (60). >+.It Cm PAMServiceName >+Specifies the service identifier to be used for pluggable authentication >+modules (PAM). >+If set to >+.Cm none , >+the sshd executable name (usually sshd) is used. >+If set to >+.Ar name , >+authentication options can be configured in a matching file in >+.Ar /etc/pam.d/name . >+The default is >+.Cm none . > .It Cm PasswordAuthentication > Specifies whether password authentication is allowed. > The default is > .Cm yes . >+.It Cm PasswordPAMServiceName >+Specifies the service identifier to be used for pluggable authentication >+modules (PAM) for >+.Cm PasswordAuthentication >+only. This is only used for the authentication (auth) PAM aspect. For account and >+session management, as well as >+.Cm ChallengeResponseAuthentication , >+the service name set in >+.Cm PAMServiceName >+is applied. This can be helpful to implement 2 factor authentication. >+Example: >+.Pp >+.Bl -item -offset indent -compact >+.It >+.Cm AuthenticationMethods >+.Qq publickey,keyboard-interactive password,keyboard-interactive >+.It >+.Cm PAMServiceName >+sshd_2factor >+.It >+.Cm PasswordPAMServiceName >+sshd_password >+.El >+.Pp >+In this example, the challenge response authentication would ask the user for >+the second factor, for example an OATH token, while the first factor could be >+either provided by ssh-key or password. This requires two different PAM >+configurations to be used, in this example /etc/pam.d/sshd_2factor and >+/etc/pam.d/sshd_password. If set to >+.Cm none , >+the value of >+.Cm PAMServiceName >+is used. >+The default is >+.Cm none . > .It Cm PermitEmptyPasswords > When password authentication is allowed, it specifies whether the > server allows login to accounts with empty password strings.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2980
:
3252
| 3253