PSARC 2012/335 OpenSSH migration
PSARC 2013/115 Shared configuration for SunSSH & OpenSSH
PSARC 2014/078 OpenSSH 6.5
PSARC 2014/342 pam_unix_session lastlog support
15769261 SUNBT7135649 Deliver OpenSSH 6.0P1 in the userland gate
18205826 upgrade OpenSSH to 6.5p1
19579776 OpenSSH doesn't need to reference lastlog anymore now that PAM session mgmt does
18267729 Delegating credentials in OpenSSH
18828925 migrate the disablebanner feature from SunSSH to OpenSSH
18890096 migrate PAM enhancements from SunSSH to OpenSSH
19629847 OpenSSH does not support Solaris Audit for login/logout.
17997193 misc. problems in Makefile and openssh.p5m
18268681 openssh has non-existent /usr/local/lib in its runpath
18528305 /var/empty should be delivered readonly
19034156 PAM coversation function for passwd auth method has an incorrect assumption
19906401 should set AUTHTOK to NULL after pam_authenticate in sshpam_auth_passwd()
19517432 OpenSSH does not update utmpx on login
19570656 GSSAPIAuthentication option should default to yes
19591379 X11Forwarding and ForwardX11Trusted should default to yes
19465507 Deprecate SunSSH-only server options (e.g. iMaxAuthTriesLog) in OpenSSH
18898794 ssh connections fail with openssh, same config works with sunssh
20549448 OpenSSH X86 server core dump at audit_event
20656125 OpenSSH ed25519 algorithm signature verification failure
18435439 problem in UTILITY/OPENSSH
18491957 problem in UTILITY/OPENSSH
#
# 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 ,