Bugzilla – Attachment 2588 Details for
Bug 2246
specify PAM service name, per authn-method service names
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
PAMServiceName/PAMServicePrefix enhancements (with bugfixes)
pam_enhancements_with_bugfixes.patch (text/plain), 19.75 KB, created by
huieying.lee
on 2015-04-16 09:31:51 AEST
(
hide
)
Description:
PAMServiceName/PAMServicePrefix enhancements (with bugfixes)
Filename:
MIME Type:
Creator:
huieying.lee
Created:
2015-04-16 09:31:51 AEST
Size:
19.75 KB
patch
obsolete
># ># This patch contains a couple of PAM enhancements: ># 1) Each SSHv2 userauth method has its own PAM service name so that PAM can ># be used to control what userauth methods are allowed. ># 2) The PAMServiceName and PAMServicePrefix options. ># ># Notes: ># - This patch also contains bug fixes to the PAM state and account problems ># that were found in the original patch file (submitted on 2014-06-19). ># - This patch applies to OpenSSH 6.5p1. ># >--- orig/auth-pam.c Wed Apr 15 15:11:13 2015 >+++ new/auth-pam.c Wed Apr 15 15:11:14 2015 >@@ -617,6 +617,72 @@ > sshpam_handle = NULL; > } > >+#ifdef PAM_ENHANCEMENT >+char * >+derive_pam_service_name(Authctxt *authctxt) >+{ >+ char *svcname = xmalloc(BUFSIZ); >+ >+ /* >+ * If PamServiceName is set we use that for everything, including >+ * SSHv1 >+ */ >+ if (options.pam_service_name != NULL) { >+ (void) strlcpy(svcname, options.pam_service_name, BUFSIZ); >+ return (svcname); >+ } >+ >+ if (compat20) { >+ char *method_name = authctxt->authmethod_name; >+ >+ if (!method_name) >+ fatal("Userauth method unknown while starting PAM"); >+ >+ /* >+ * For SSHv2 we use "sshd-<userauth name> >+ * The "sshd" prefix can be changed via the PAMServicePrefix >+ * sshd_config option. >+ */ >+ if (strcmp(method_name, "none") == 0) { >+ snprintf(svcname, BUFSIZ, "%s-none", >+ options.pam_service_prefix); >+ } >+ if (strcmp(method_name, "password") == 0) { >+ snprintf(svcname, BUFSIZ, "%s-password", >+ options.pam_service_prefix); >+ } >+ if (strcmp(method_name, "keyboard-interactive") == 0) { >+ /* "keyboard-interactive" is too long, shorten it */ >+ snprintf(svcname, BUFSIZ, "%s-kbdint", >+ options.pam_service_prefix); >+ } >+ if (strcmp(method_name, "publickey") == 0) { >+ /* "publickey" is too long, shorten it */ >+ snprintf(svcname, BUFSIZ, "%s-pubkey", >+ options.pam_service_prefix); >+ } >+ if (strcmp(method_name, "hostbased") == 0) { >+ snprintf(svcname, BUFSIZ, "%s-hostbased", >+ options.pam_service_prefix); >+ } >+ if (strncmp(method_name, "gssapi-", 7) == 0) { >+ /* >+ * Although OpenSSH only supports "gssapi-with-mic" >+ * for now. We will still map any userauth method >+ * prefixed with "gssapi-" to the gssapi PAM service. >+ */ >+ snprintf(svcname, BUFSIZ, "%s-gssapi", >+ options.pam_service_prefix); >+ } >+ return svcname; >+ } else { >+ /* SSHv1 doesn't get to be so cool */ >+ snprintf(svcname, BUFSIZ, "sshd-v1"); >+ } >+ return svcname; >+} >+#endif /* PAM_ENHANCEMENT */ >+ > static int > sshpam_init(Authctxt *authctxt) > { >@@ -624,18 +690,71 @@ > const char *pam_rhost, *pam_user, *user = authctxt->user; > const char **ptr_pam_user = &pam_user; > >+#ifdef PAM_ENHANCEMENT >+ const char *pam_service; >+ const char **ptr_pam_service = &pam_service; >+ char *svc = NULL; >+ >+ svc = derive_pam_service_name(authctxt); >+ debug3("PAM service is %s", svc); >+#endif >+ > if (sshpam_handle != NULL) { >+#ifdef PAM_ENHANCEMENT >+ /* get the pam service name */ >+ sshpam_err = pam_get_item(sshpam_handle, >+ PAM_SERVICE, (sshpam_const void **)ptr_pam_service); >+ if (sshpam_err != PAM_SUCCESS) >+ fatal("Failed to get the PAM service name"); >+ debug3("Previous pam_service is %s", pam_service ? >+ pam_service : "NULL"); >+ >+ /* get the pam user name */ >+ sshpam_err = pam_get_item(sshpam_handle, >+ PAM_USER, (sshpam_const void **)ptr_pam_user); >+ >+ /* >+ * only need to re-start if either user or service is >+ * different. >+ */ >+ if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0 >+ && strncmp(svc, pam_service, strlen(svc)) == 0) { >+ free(svc); >+ return (0); >+ } >+ >+ /* >+ * Clean up previous PAM state. No need to clean up session >+ * and creds. >+ */ >+ 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 */ >+#else /* Original */ > /* We already have a PAM context; check if the user matches */ > sshpam_err = pam_get_item(sshpam_handle, > PAM_USER, (sshpam_const void **)ptr_pam_user); > if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) > return (0); >+#endif /* PAM_ENHANCEMENT */ > pam_end(sshpam_handle, sshpam_err); > sshpam_handle = NULL; > } > debug("PAM: initializing for \"%s\"", user); >+ >+#ifdef PAM_ENHANCEMENT >+ debug3("Starting PAM service %s for user %s method %s", svc, user, >+ authctxt->authmethod_name); > sshpam_err = >+ pam_start(svc, user, &store_conv, &sshpam_handle); >+ free(svc); >+#else /* Original */ >+ sshpam_err = > pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); >+#endif > sshpam_authctxt = authctxt; > > if (sshpam_err != PAM_SUCCESS) { >--- orig/auth.h Wed Apr 15 15:11:13 2015 >+++ new/auth.h Wed Apr 15 15:11:14 2015 >@@ -76,6 +76,9 @@ > #endif > Buffer *loginmsg; > void *methoddata; >+#ifdef PAM_ENHANCEMENT >+ char *authmethod_name; >+#endif > }; > /* > * Every authentication method has to handle authentication requests for >--- orig/auth2.c Wed Apr 15 15:11:13 2015 >+++ new/auth2.c Wed Apr 15 15:11:14 2015 >@@ -249,10 +249,21 @@ > PRIVSEP(audit_event(SSH_INVALID_USER)); > #endif > } >+ >+ > #ifdef USE_PAM >+#ifdef PAM_ENHANCEMENT >+ /* >+ * Start PAM here and once only, if each userauth does not >+ * has its own PAM service. >+ */ >+ if (options.use_pam && !options.pam_service_per_authmethod) >+ PRIVSEP(start_pam(authctxt)); >+#else > if (options.use_pam) > PRIVSEP(start_pam(authctxt)); > #endif >+#endif > setproctitle("%s%s", authctxt->valid ? user : "unknown", > use_privsep ? " [net]" : ""); > authctxt->service = xstrdup(service); >@@ -286,6 +297,18 @@ > /* try to authenticate user */ > m = authmethod_lookup(authctxt, method); > if (m != NULL && authctxt->failures < options.max_authtries) { >+ >+#if defined(USE_PAM) && defined(PAM_ENHANCEMENT) >+ /* start PAM service for each userauth */ >+ if (options.use_pam && options.pam_service_per_authmethod) { >+ if (authctxt->authmethod_name != NULL) >+ free(authctxt->authmethod_name); >+ authctxt->authmethod_name = xstrdup(method); >+ if (use_privsep) >+ mm_inform_authmethod(method); >+ PRIVSEP(start_pam(authctxt)); >+ } >+#endif > debug2("input_userauth_request: try method %s", method); > authenticated = m->userauth(authctxt); > } >@@ -303,6 +326,10 @@ > char *methods; > int partial = 0; > >+#ifdef PAM_ENHANCEMENT >+ debug3("%s: entering", __func__); >+#endif >+ > if (!authctxt->valid && authenticated) > fatal("INTERNAL ERROR: authenticated invalid user %s", > authctxt->user); >@@ -319,6 +346,25 @@ > } > > if (authenticated && options.num_auth_methods != 0) { >+ >+#if defined(USE_PAM) && defined(PAM_ENHANCEMENT) >+ /* >+ * If each userauth has its own PAM service, then PAM need to >+ * perform account check for this service. >+ */ >+ if (options.use_pam && options.pam_service_per_authmethod && >+ !PRIVSEP(do_pam_account())) { >+ /* if PAM returned a message, send it to the user */ >+ if (buffer_len(&loginmsg) > 0) { >+ buffer_append(&loginmsg, "\0", 1); >+ userauth_send_banner(buffer_ptr(&loginmsg)); >+ packet_write_wait(); >+ } >+ >+ fatal("Access denied for user %s by PAM account " >+ "configuration", authctxt->user); >+ } >+#endif > if (!auth2_update_methods_lists(authctxt, method, submethod)) { > authenticated = 0; > partial = 1; >@@ -332,7 +378,20 @@ > return; > > #ifdef USE_PAM >+ >+#ifdef PAM_ENHANCEMENT >+ /* >+ * PAM needs to perform account checks after auth. However, if each >+ * userauth has its own PAM service and options.num_auth_methods != 0, >+ * then no need to perform account checking, because it was done >+ * already. >+ */ >+ if (options.use_pam && authenticated && >+ !(options.num_auth_methods != 0 && >+ options.pam_service_per_authmethod)){ >+#else > if (options.use_pam && authenticated) { >+#endif > if (!PRIVSEP(do_pam_account())) { > /* if PAM returned a message, send it to the user */ > if (buffer_len(&loginmsg) > 0) { >@@ -623,5 +682,3 @@ > fatal("%s: method not in AuthenticationMethods", __func__); > return 0; > } >- >- >--- orig/monitor_wrap.c Wed Apr 15 15:11:13 2015 >+++ new/monitor_wrap.c Wed Apr 15 15:11:14 2015 >@@ -338,6 +338,24 @@ > buffer_free(&m); > } > >+#ifdef PAM_ENHANCEMENT >+/* Inform the privileged process about the authentication method */ >+void >+mm_inform_authmethod(char *authmethod) >+{ >+ Buffer m; >+ >+ debug3("%s entering", __func__); >+ >+ buffer_init(&m); >+ buffer_put_cstring(&m, authmethod); >+ >+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHMETHOD, &m); >+ >+ buffer_free(&m); >+} >+#endif >+ > /* Do the password authentication */ > int > mm_auth_password(Authctxt *authctxt, char *password) >--- orig/monitor.c Wed Apr 15 15:11:13 2015 >+++ new/monitor.c Wed Apr 15 15:11:14 2015 >@@ -146,6 +146,9 @@ > int mm_answer_pwnamallow(int, Buffer *); > int mm_answer_auth2_read_banner(int, Buffer *); > int mm_answer_authserv(int, Buffer *); >+#ifdef PAM_ENHANCEMENT >+int mm_answer_authmethod(int, Buffer *); >+#endif > int mm_answer_authpassword(int, Buffer *); > int mm_answer_bsdauthquery(int, Buffer *); > int mm_answer_bsdauthrespond(int, Buffer *); >@@ -225,10 +228,17 @@ > {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, > {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, > {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, >+#ifdef PAM_ENHANCEMENT >+ {MONITOR_REQ_AUTHMETHOD, MON_ISAUTH, mm_answer_authmethod}, >+#endif > {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, > {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, > #ifdef USE_PAM >+#ifdef PAM_ENHANCEMENT >+ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, >+#else > {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, >+#endif > {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, > {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, > {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, >@@ -391,6 +401,24 @@ > if (!compat20) > fatal("AuthenticationMethods is not supported" > "with SSH protocol 1"); >+ >+#if defined(USE_PAM) && defined(PAM_ENHANCEMENT) >+ /* >+ * If each userauth has its own PAM service, then PAM >+ * need to perform account check for this service. >+ */ >+ if (options.use_pam && authenticated && >+ options.pam_service_per_authmethod) { >+ Buffer m; >+ >+ buffer_init(&m); >+ mm_request_receive_expect(pmonitor->m_sendfd, >+ MONITOR_REQ_PAM_ACCOUNT, &m); >+ authenticated = >+ mm_answer_pam_account(pmonitor->m_sendfd, &m); >+ buffer_free(&m); >+ } >+#endif > if (authenticated && > !auth2_update_methods_lists(authctxt, > auth_method, auth_submethod)) { >@@ -409,8 +437,21 @@ > !auth_root_allowed(auth_method)) > authenticated = 0; > #ifdef USE_PAM >+#ifdef PAM_ENHANCEMENT >+ /* >+ * PAM needs to perform account checks after auth. >+ * However, if each userauth has its own PAM service >+ * and options.num_auth_methods != 0, then no need to >+ * perform account checking, because it was done >+ * already. >+ */ >+ if (options.use_pam && authenticated && >+ !(options.num_auth_methods != 0 && >+ options.pam_service_per_authmethod)) { >+#else > /* PAM needs to perform account checks after auth */ > if (options.use_pam && authenticated) { >+#endif > Buffer m; > > buffer_init(&m); >@@ -828,6 +869,10 @@ > /* Allow service/style information on the auth context */ > monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); > monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); >+#ifdef PAM_ENHANCEMENT >+ /* Allow authmethod information on the auth context */ >+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHMETHOD, 1); >+#endif > } > #ifdef USE_PAM > if (options.use_pam) >@@ -868,7 +913,25 @@ > return (0); > } > >+#ifdef PAM_ENHANCEMENT > int >+mm_answer_authmethod(int sock, Buffer *m) >+{ >+ monitor_permit_authentications(1); >+ >+ authctxt->authmethod_name = buffer_get_string(m, NULL); >+ debug3("%s: authmethod_name=%s", __func__, authctxt->authmethod_name); >+ >+ if (strlen(authctxt->authmethod_name) == 0) { >+ free(authctxt->authmethod_name); >+ authctxt->authmethod_name = NULL; >+ } >+ >+ return (0); >+} >+#endif >+ >+int > mm_answer_authpassword(int sock, Buffer *m) > { > static int call_count; >--- orig/monitor.h Wed Apr 15 15:11:13 2015 >+++ new/monitor.h Wed Apr 15 15:11:14 2015 >@@ -70,6 +70,9 @@ > MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, > MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, > >+#ifdef PAM_ENHANCEMENT >+ MONITOR_REQ_AUTHMETHOD = 114, >+#endif > }; > > struct mm_master; >--- orig/servconf.c Wed Apr 15 15:11:13 2015 >+++ new/servconf.c Wed Apr 15 15:11:14 2015 >@@ -154,6 +154,18 @@ > options->ip_qos_interactive = -1; > options->ip_qos_bulk = -1; > options->version_addendum = NULL; >+#ifdef PAM_ENHANCEMENT >+ options->pam_service_name = NULL; >+ options->pam_service_prefix = NULL; >+ >+ /* >+ * Each user method will have its own PAM service by default. >+ * However, if PAMServiceName is specified or the protocal version >+ * is not compat20, then there will be only one PAM service for the >+ * entire user authentication. >+ */ >+ options->pam_service_per_authmethod = 1; >+#endif > } > > void >@@ -303,6 +315,12 @@ > options->ip_qos_bulk = IPTOS_THROUGHPUT; > if (options->version_addendum == NULL) > options->version_addendum = xstrdup(""); >+ >+#ifdef PAM_ENHANCEMENT >+ if (options->pam_service_prefix == NULL) >+ options->pam_service_prefix = _SSH_PAM_SERVICE_PREFIX; >+#endif >+ > /* Turn privilege separation on by default */ > if (use_privsep == -1) > use_privsep = PRIVSEP_NOSANDBOX; >@@ -351,6 +369,9 @@ > sKexAlgorithms, sIPQoS, sVersionAddendum, > sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, > sAuthenticationMethods, sHostKeyAgent, >+#ifdef PAM_ENHANCEMENT >+ sPAMServicePrefix, sPAMServiceName, >+#endif > sDeprecated, sUnsupported > } ServerOpCodes; > >@@ -482,6 +503,10 @@ > { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, > { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, > { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, >+#ifdef PAM_ENHANCEMENT >+ { "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL }, >+ { "pamservicename", sPAMServiceName, SSHCFG_GLOBAL }, >+#endif > { NULL, sBadOption, 0 } > }; > >@@ -1632,6 +1657,37 @@ > } > return 0; > >+ case sPAMServicePrefix: >+ arg = strdelim(&cp); >+ if (!arg || *arg == '\0') >+ fatal("%s line %d: Missing argument.", >+ filename, linenum); >+ if (options->pam_service_name != NULL) >+ fatal("%s line %d: PAMServiceName and PAMServicePrefix" >+ " are mutually exclusive.", filename, linenum); >+ if (options->pam_service_prefix == NULL) >+ options->pam_service_prefix = xstrdup(arg); >+ break; >+ >+ case sPAMServiceName: >+ arg = strdelim(&cp); >+ if (!arg || *arg == '\0') >+ fatal("%s line %d: Missing argument.", >+ filename, linenum); >+ if (options->pam_service_prefix != NULL) >+ fatal("%s line %d: PAMServiceName and PAMServicePrefix" >+ " are mutually exclusive.", filename, linenum); >+ if (options->pam_service_name == NULL) { >+ options->pam_service_name = xstrdup(arg); >+ >+ /* >+ * When this option is specified, we will not have >+ * PAM service for each auth method. >+ */ >+ options->pam_service_per_authmethod = 0; >+ } >+ break; >+ > case sDeprecated: > logit("%s line %d: Deprecated option %s", > filename, linenum, arg); >--- orig/servconf.h Wed Apr 15 15:11:13 2015 >+++ new/servconf.h Wed Apr 15 15:11:14 2015 >@@ -54,6 +54,10 @@ > /* Magic name for internal sftp-server */ > #define INTERNAL_SFTP_NAME "internal-sftp" > >+#ifdef PAM_ENHANCEMENT >+#define _SSH_PAM_SERVICE_PREFIX "sshd" >+#endif >+ > typedef struct { > u_int num_ports; > u_int ports_from_cmdline; >@@ -185,6 +189,13 @@ > > u_int num_auth_methods; > char *auth_methods[MAX_AUTH_METHODS]; >+ >+#ifdef PAM_ENHANCEMENT >+ char *pam_service_prefix; >+ char *pam_service_name; >+ int pam_service_per_authmethod; >+#endif >+ > } ServerOptions; > > /* Information about the incoming connection as used by Match */ >--- orig/sshd_config.5 Wed Apr 15 15:11:13 2015 >+++ new/sshd_config.5 Wed Apr 15 15:14:50 2015 >@@ -868,6 +868,21 @@ > are refused if the number of unauthenticated connections reaches > .Dq full > (60). >+.It Cm PAMServiceName >+Specifies the PAM service name for the PAM session. The PAMServiceName and >+PAMServicePrefix options are mutually exclusive and if both set, sshd does not >+start. If this option is set the service name is the same for all user >+authentication methods. The option has no default value. See PAMServicePrefix >+for more information. >+.It Cm PAMServicePrefix >+Specifies the PAM service name prefix for service names used for individual >+user authentication methods. The default is sshd. The PAMServiceName and >+PAMServicePrefix options are mutually exclusive and if both set, sshd does not >+start. >+.Pp >+For example, if this option is set to admincli, the service name for the >+keyboard-interactive authentication method is admincli-kbdint instead of the >+default sshd-kbdint. > .It Cm PasswordAuthentication > Specifies whether password authentication is allowed. > The default is >--- orig/sshd.8 Wed Apr 15 15:11:13 2015 >+++ new/sshd.8 Wed Apr 15 15:11:14 2015 >@@ -951,6 +951,33 @@ > started last). > The content of this file is not sensitive; it can be world-readable. > .El >+ >+.Sh SECURITY >+sshd uses pam(3PAM) for password and keyboard-interactive methods as well as >+for account management, session management, and the password management for all >+authentication methods. >+.Pp >+Each SSHv2 userauth type has its own PAM service name: >+ >+.Bd -literal -offset 3n >+ >+----------------------------------------------- >+| SSHv2 Userauth | PAM Service Name | >+----------------------------------------------- >+| none | sshd-none | >+----------------------------------------------- >+| password | sshd-password | >+----------------------------------------------- >+| keyboard-interactive | sshd-kbdint | >+----------------------------------------------- >+| pubkey | sshd-pubkey | >+----------------------------------------------- >+| hostbased | sshd-hostbased | >+----------------------------------------------- >+| gssapi-with-mic | sshd-gssapi | >+----------------------------------------------- >+.Ed >+ > .Sh SEE ALSO > .Xr scp 1 , > .Xr sftp 1 , >--- orig/sshd.c Wed Apr 15 15:11:13 2015 >+++ new/sshd.c Wed Apr 15 15:11:14 2015 >@@ -2065,6 +2065,11 @@ > > sshd_exchange_identification(sock_in, sock_out); > >+#ifdef PAM_ENHANCEMENT >+ if (!compat20) >+ options.pam_service_per_authmethod = 0; >+#endif >+ > /* In inetd mode, generate ephemeral key only for proto 1 connections */ > if (!compat20 && inetd_flag && sensitive_data.server_key == NULL) > generate_ephemeral_server_key();
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 2246
:
2441
|
2504
| 2588