--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openssh/patches/016-pam_enhancement.patch Tue Jul 01 13:51:11 2014 -0700
@@ -0,0 +1,478 @@
+#
+# 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.
+#
+# We have contributed back this feature to the OpenSSH upstream community.
+# For more information, see https://bugzilla.mindrot.org/show_bug.cgi?id=2246
+# In the future, if these enhancements are accepted by the upsteam in a
+# later release, we will remove this patch when we upgrade to that release.
+#
+--- orig/auth-pam.c Fri Jun 20 15:39:05 2014
++++ new/auth-pam.c Fri Jun 20 16:47:09 2014
+@@ -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,61 @@
+ 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);
++ }
++
++#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 Fri Jun 20 15:39:05 2014
++++ new/auth.h Fri Jun 20 15:39:05 2014
+@@ -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 Fri Jun 20 15:39:05 2014
++++ new/auth2.c Fri Jun 20 15:39:05 2014
+@@ -249,10 +249,13 @@
+ PRIVSEP(audit_event(SSH_INVALID_USER));
+ #endif
+ }
++
++#ifndef PAM_ENHANCEMENT
+ #ifdef USE_PAM
+ 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 +289,14 @@
+ /* try to authenticate user */
+ m = authmethod_lookup(authctxt, method);
+ if (m != NULL && authctxt->failures < options.max_authtries) {
++
++#ifdef PAM_ENHANCEMENT
++ authctxt->authmethod_name = xstrdup(method);
++ if (use_privsep)
++ mm_inform_authmethod(method);
++ if (options.use_pam)
++ PRIVSEP(start_pam(authctxt));
++#endif
+ debug2("input_userauth_request: try method %s", method);
+ authenticated = m->userauth(authctxt);
+ }
+@@ -303,6 +314,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);
+@@ -623,5 +638,3 @@
+ fatal("%s: method not in AuthenticationMethods", __func__);
+ return 0;
+ }
+-
+-
+--- orig/monitor_wrap.c Fri Jun 20 15:39:05 2014
++++ new/monitor_wrap.c Fri Jun 20 15:39:05 2014
+@@ -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 Fri Jun 20 15:39:05 2014
++++ new/monitor.c Fri Jun 20 15:39:05 2014
+@@ -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},
+@@ -828,6 +838,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 +882,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 Fri Jun 20 15:39:05 2014
++++ new/monitor.h Fri Jun 20 15:39:05 2014
+@@ -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 Fri Jun 20 15:39:05 2014
++++ new/servconf.c Fri Jun 20 15:39:05 2014
+@@ -154,6 +154,10 @@
+ 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;
++#endif
+ }
+
+ void
+@@ -303,6 +307,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 +361,9 @@
+ sKexAlgorithms, sIPQoS, sVersionAddendum,
+ sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
+ sAuthenticationMethods, sHostKeyAgent,
++#ifdef PAM_ENHANCEMENT
++ sPAMServicePrefix, sPAMServiceName,
++#endif
+ sDeprecated, sUnsupported
+ } ServerOpCodes;
+
+@@ -482,6 +495,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 +1649,30 @@
+ }
+ 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);
++ break;
++
+ case sDeprecated:
+ logit("%s line %d: Deprecated option %s",
+ filename, linenum, arg);
+--- orig/servconf.h Fri Jun 20 15:39:05 2014
++++ new/servconf.h Fri Jun 20 15:39:05 2014
+@@ -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,12 @@
+
+ u_int num_auth_methods;
+ char *auth_methods[MAX_AUTH_METHODS];
++
++#ifdef PAM_ENHANCEMENT
++ char *pam_service_prefix;
++ char *pam_service_name;
++#endif
++
+ } ServerOptions;
+
+ /* Information about the incoming connection as used by Match */
+--- orig/sshd_config.5 Fri Jun 20 15:39:05 2014
++++ new/sshd_config.5 Fri Jun 20 15:39:05 2014
+@@ -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 Fri Jun 20 15:39:05 2014
++++ new/sshd.8 Fri Jun 20 15:39:05 2014
+@@ -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 ,