--- hpn-ssh-hpn-18.4.2/auth-pam.c.orig
+++ hpn-ssh-hpn-18.4.2/auth-pam.c
@@ -689,6 +689,66 @@
 	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);
+	}
+
+	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;
+}
+#endif /* PAM_ENHANCEMENT */
+
 static int
 sshpam_init(struct ssh *ssh, Authctxt *authctxt)
 {
@@ -702,23 +762,76 @@
 		fatal("Username too long from %s port %d",
 		    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
 #endif
+
+#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) {
 		if (ssh == NULL) {
 			fatal("%s: called initially with no "
 			    "packet context", __func__);
 		}
 	} 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) {
--- hpn-ssh-hpn-18.4.2/auth.h.orig
+++ hpn-ssh-hpn-18.4.2/auth.h
@@ -95,6 +95,9 @@
 
 	/* Information exposed to session */
 	struct sshbuf	*session_info;	/* Auth info for environment */
+#ifdef PAM_ENHANCEMENT
+	char		*authmethod_name;
+#endif
 };
 
 /*
--- hpn-ssh-hpn-18.4.2/auth2.c.orig
+++ hpn-ssh-hpn-18.4.2/auth2.c
@@ -317,9 +317,17 @@
 #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)
+#else
 		if (options.use_pam)
+#endif /* PAM_ENHANCEMENT */
 			PRIVSEP(start_pam(ssh));
-#endif
+#endif /* USE_PAM */
 		ssh_packet_set_log_preamble(ssh, "%suser %s",
 		    authctxt->valid ? "authenticating " : "invalid ", user);
 		setproctitle("%s%s", authctxt->valid ? user : "unknown",
@@ -356,6 +364,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(ssh, method);
 	}
@@ -381,6 +401,10 @@
 	char *methods;
 	int r, partial = 0;
 
+#ifdef  PAM_ENHANCEMENT
+	debug3("%s: entering", __func__);
+#endif
+
 	if (authenticated) {
 		if (!authctxt->valid) {
 			fatal("INTERNAL ERROR: authenticated invalid user %s",
@@ -404,6 +428,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 needs to
+                 * perform the 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 (sshbuf_len(loginmsg) > 0) {
+                                sshbuf_put(loginmsg, "\0", 1);
+                                userauth_send_banner(ssh, sshbuf_ptr(loginmsg));
+                                ssh_packet_write_wait(ssh);
+                        }
+
+                        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;
@@ -421,7 +464,19 @@
 		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
 		int r, success = PRIVSEP(do_pam_account());
 
 		/* If PAM returned a message, send it to the user. */
--- hpn-ssh-hpn-18.4.2/monitor.c.orig
+++ hpn-ssh-hpn-18.4.2/monitor.c
@@ -117,6 +117,9 @@
 int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *);
 int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *);
 int mm_answer_authserv(struct ssh *, int, struct sshbuf *);
+#ifdef PAM_ENHANCEMENT
+int mm_answer_authmethod(struct ssh *, int, struct sshbuf *);
+#endif
 int mm_answer_authpassword(struct ssh *, int, struct sshbuf *);
 int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *);
 int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *);
@@ -190,10 +193,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_ONCE, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query},
@@ -300,6 +310,25 @@
 
 		/* Special handling for multiple required authentications */
 		if (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 && authenticated &&
+			    options.pam_service_per_authmethod) {
+				struct sshbuf *m;
+				if ((m = sshbuf_new()) == NULL)
+				    fatal("%s: sshbuf_new", __func__);
+				mm_request_receive_expect(pmonitor->m_sendfd,
+				    MONITOR_REQ_PAM_ACCOUNT, m);
+				authenticated = mm_answer_pam_account(ssh,
+				    pmonitor->m_sendfd, m);
+				sshbuf_free(m);
+			}
+#endif
+
 			if (authenticated &&
 			    !auth2_update_methods_lists(authctxt,
 			    auth_method, auth_submethod)) {
@@ -317,8 +346,21 @@
 			    !auth_root_allowed(ssh, 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
 				struct sshbuf *m;
 
 				if ((m = sshbuf_new()) == NULL)
@@ -802,6 +844,11 @@
 	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)
 		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1);
@@ -825,6 +872,27 @@
 	return (0);
 }
 
+#ifdef PAM_ENHANCEMENT
+int
+mm_answer_authmethod(struct ssh *ssh, int sock, struct sshbuf *m)
+{
+	Authctxt *authctxt = ssh->authctxt;
+
+	monitor_permit_authentications(1);
+	/*sshbuf_dump(m, stderr);*/
+	sshbuf_get_cstring(m, &authctxt->authmethod_name, NULL);
+	debug3("%s: authmethod_name=%s", __func__, authctxt->authmethod_name);
+
+	if (authctxt->authmethod_name &&
+	    strlen(authctxt->authmethod_name) == 0) {
+		free(authctxt->authmethod_name);
+		authctxt->authmethod_name = NULL;
+	}
+
+	return (0);
+}
+#endif
+
 int
 mm_answer_authserv(struct ssh *ssh, int sock, struct sshbuf *m)
 {
--- hpn-ssh-hpn-18.4.2/monitor.h.orig
+++ hpn-ssh-hpn-18.4.2/monitor.h
@@ -63,6 +63,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 ssh;
--- hpn-ssh-hpn-18.4.2/monitor_wrap.c.orig
+++ hpn-ssh-hpn-18.4.2/monitor_wrap.c
@@ -396,6 +396,24 @@
 	sshbuf_free(m);
 }
 
+#ifdef PAM_ENHANCEMENT
+/* Inform the privileged process about the authentication method */
+void
+mm_inform_authmethod(char *authmethod)
+{
+	struct sshbuf *m;
+
+	debug3("%s entering", __func__);
+	if ((m = sshbuf_new()) == NULL)
+	    fatal("%s: sshbuf_new", __func__);
+	sshbuf_put_cstring(m, authmethod);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHMETHOD, m);
+
+	sshbuf_free(m);
+}
+#endif
+
 /* Do the password authentication */
 int
 mm_auth_password(struct ssh *ssh, char *password)
--- hpn-ssh-hpn-18.4.2/servconf.c.orig
+++ hpn-ssh-hpn-18.4.2/servconf.c
@@ -202,6 +202,18 @@
 	options->channel_timeouts = NULL;
 	options->num_channel_timeouts = 0;
 	options->unused_connection_timeout = -1;
+#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
+	 * then there will be only one PAM service for the
+	 * entire user authentication.
+	 */
+	options->pam_service_per_authmethod = 1;
+#endif
 }
 
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -451,6 +463,12 @@
 		options->ip_qos_bulk = IPTOS_DSCP_CS1;
 	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
+
 	if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
 		options->fwd_opts.streamlocal_bind_mask = 0177;
 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
@@ -543,6 +561,9 @@
 	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
 	sHostCertificate, sInclude,
+#ifdef PAM_ENHANCEMENT
+	sPAMServicePrefix, sPAMServiceName,
+#endif
 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
 	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
 	sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
@@ -694,6 +715,10 @@
 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
+#ifdef PAM_ENHANCEMENT
+	{ "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
+	{ "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
+#endif
 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
@@ -2649,6 +2674,37 @@
 		}
 		goto parse_time;
 
+	case sPAMServicePrefix:
+		arg = strdelim(&str);
+		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(&str);
+		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:
 	case sIgnore:
 	case sUnsupported:
--- hpn-ssh-hpn-18.4.2/servconf.h.orig
+++ hpn-ssh-hpn-18.4.2/servconf.h
@@ -71,6 +71,10 @@
 	struct addrinfo *addrs;
 };
 
+#ifdef PAM_ENHANCEMENT
+#define _SSH_PAM_SERVICE_PREFIX "sshd"
+#endif
+
 typedef struct {
 	u_int	num_ports;
 	u_int	ports_from_cmdline;
@@ -227,6 +231,12 @@
 	u_int	num_auth_methods;
 	char   **auth_methods;
 
+#ifdef PAM_ENHANCEMENT
+	char   *pam_service_prefix;
+	char   *pam_service_name;
+	int	pam_service_per_authmethod;
+#endif
+
 	int	fingerprint_hash;
 	int	expose_userauth_info;
 	u_int64_t timing_secret;
--- hpn-ssh-hpn-18.4.2/hpnsshd.8.orig
+++ hpn-ssh-hpn-18.4.2/hpnsshd.8
@@ -1017,6 +1017,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 hpnscp 1 ,
 .Xr hpnsftp 1 ,
--- hpn-ssh-hpn-18.4.2/hpnsshd_config.5.orig
+++ hpn-ssh-hpn-18.4.2/hpnsshd_config.5
@@ -1400,6 +1400,35 @@
 protection against man-in-the-middle attacks. As with NoneEnabled all authentication
 remains encrypted and integrity is ensured. Default is 
 .Cm no.
+.It Cm PAMServiceName
+Specifies the PAM service name for the PAM session.
+The
+.Cm PAMServiceName
+and
+.Cm PAMServicePrefix
+options are mutually exclusive and if both are 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
+.Cm 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
+.Cm PAMServiceName
+and
+.Cm PAMServicePrefix
+options are mutually exclusive and if both are set, sshd does not start.
+.Pp
+For example, if this option is set to
+.Cm admincli ,
+the service name for the keyboard-interactive authentication method is
+.Sy admincli-kbdint
+instead of the default
+.Sy sshd-kbdint .
 .It Cm PasswordAuthentication
 Specifies whether password authentication is allowed.
 The default is
@@ -1950,8 +1979,7 @@
 is enabled, you will not be able to run
 .Xr sshd 8
 as a non-root user.
-The default is
-.Cm no .
+On OpenIndiana, the option is always enabled.
 .It Cm VersionAddendum
 Optionally specifies additional text to append to the SSH protocol banner
 sent by the server upon connection.
