--- openssh-10.0p1/auth-pam.c.orig
+++ openssh-10.0p1/auth-pam.c
@@ -683,6 +683,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)
 {
@@ -690,8 +750,17 @@
 	const char **ptr_pam_user = &pam_user;
 	int r;
 
+#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);
+#else
 	if (options.pam_service_name == NULL)
 		fatal_f("internal error: NULL PAM service name");
+#endif
 #if defined(PAM_SUN_CODEBASE) && defined(PAM_MAX_RESP_SIZE)
 	/* Protect buggy PAM implementations from excessively long usernames */
 	if (strlen(user) >= PAM_MAX_RESP_SIZE)
@@ -705,18 +774,62 @@
 		}
 	}
 	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
 		/* 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_end(sshpam_handle, sshpam_err);
 		sshpam_handle = NULL;
 	}
+#ifdef PAM_ENHANCEMENT
+	debug("PAM: initializing for \"%s\" with service \"%s\"", user, svc);
+	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
 	debug("PAM: initializing for \"%s\" with service \"%s\"", user,
 	    options.pam_service_name);
 	sshpam_err = pam_start(options.pam_service_name, user,
 	    &store_conv, &sshpam_handle);
+#endif
 	sshpam_authctxt = authctxt;
 
 	if (sshpam_err != PAM_SUCCESS) {
--- openssh-10.0p1/auth.h.orig
+++ openssh-10.0p1/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
 };
 
 /*
--- openssh-10.0p1/auth2.c.orig
+++ openssh-10.0p1/auth2.c
@@ -305,9 +305,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 */
 			mm_start_pam(ssh);
-#endif
+#endif /* USE_PAM */
 		ssh_packet_set_log_preamble(ssh, "%suser %s",
 		    authctxt->valid ? "authenticating " : "invalid ", user);
 		setproctitle("%s [net]", authctxt->valid ? user : "unknown");
@@ -342,6 +350,17 @@
 	/* 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) {
+			extern void mm_inform_authmethod(char *);
+			if (authctxt->authmethod_name != NULL)
+				free(authctxt->authmethod_name);
+			authctxt->authmethod_name = xstrdup(method);
+			mm_inform_authmethod(method);
+			mm_start_pam(ssh);
+		}
+#endif
 		debug2("input_userauth_request: try method %s", method);
 		authenticated =	m->userauth(ssh, method);
 	}
@@ -367,6 +386,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",
@@ -390,6 +413,31 @@
 	}
 
 	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) {
+			int r, success = mm_do_pam_account();
+
+			/* If PAM returned a message, send it to the user. */
+			if (sshbuf_len(loginmsg) > 0) {
+				if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0)
+					fatal("%s: buffer error: %s",
+					    __func__, ssh_err(r));
+				userauth_send_banner(ssh, sshbuf_ptr(loginmsg));
+				if ((r = ssh_packet_write_wait(ssh)) != 0) {
+					sshpkt_fatal(ssh, r,
+					    "%s: send PAM banner", __func__);
+				}
+			}
+			if (!success) {
+				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;
@@ -407,7 +455,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 /* PAM_ENHANCEMENT */
 		int r, success = mm_do_pam_account();
 
 		/* If PAM returned a message, send it to the user. */
--- openssh-10.0p1/monitor.c.orig
+++ openssh-10.0p1/monitor.c
@@ -120,6 +120,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 *);
@@ -194,10 +197,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},
@@ -310,6 +320,23 @@
 
 		/* 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)) {
@@ -327,8 +354,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)
@@ -913,6 +953,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)
@@ -937,6 +981,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)
 {
--- openssh-10.0p1/monitor.h.orig
+++ openssh-10.0p1/monitor.h
@@ -63,6 +63,9 @@
 	MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109,
 	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
 
 };
 
--- openssh-10.0p1/monitor_wrap.c.orig
+++ openssh-10.0p1/monitor_wrap.c
@@ -442,6 +442,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 /* PAM_ENHANCEMENT */
+
 /* Do the password authentication */
 int
 mm_auth_password(struct ssh *ssh, char *password)
--- openssh-10.0p1/servconf.c.orig
+++ openssh-10.0p1/servconf.c
@@ -94,6 +94,17 @@
 	/* Portable-specific options */
 	options->use_pam = -1;
 	options->pam_service_name = NULL;
+#ifdef PAM_ENHANCEMENT
+	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
 
 	/* Standard Options */
 	options->num_ports = 0;
@@ -305,8 +316,13 @@
 #else
 		options->use_pam = 0;
 #endif
+#ifdef PAM_ENHANCEMENT
+	if (options->pam_service_prefix == NULL)
+		options->pam_service_prefix = xstrdup(SSHD_PAM_SERVICE);
+#else
 	if (options->pam_service_name == NULL)
 		options->pam_service_name = xstrdup(SSHD_PAM_SERVICE);
+#endif
 
 	/* Standard Options */
 	if (options->num_host_key_files == 0) {
@@ -553,6 +569,9 @@
 	sBadOption,		/* == unknown option */
 	/* Portable-specific options */
 	sUsePAM, sPAMServiceName,
+#ifdef PAM_ENHANCEMENT
+	sPAMServicePrefix,
+#endif
 	/* Standard Options */
 	sPort, sHostKeyFile, sLoginGraceTime,
 	sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
@@ -605,10 +624,20 @@
 	/* Portable-specific options */
 #ifdef USE_PAM
 	{ "usepam", sUsePAM, SSHCFG_GLOBAL },
+#ifdef PAM_ENHANCEMENT
+	{ "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
+	{ "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
+#else
 	{ "pamservicename", sPAMServiceName, SSHCFG_ALL },
+#endif /* PAM_ENHANCEMENT */
 #else
 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
+#ifdef PAM_ENHANCEMENT
+	{ "pamserviceprefix", sUnsupported, SSHCFG_GLOBAL },
+	{ "pamservicename", sUnsupported, SSHCFG_GLOBAL },
+#else
 	{ "pamservicename", sUnsupported, SSHCFG_ALL },
+#endif /* PAM_ENHANCEMENT */
 #endif
 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
 	/* Standard Options */
@@ -1409,6 +1438,21 @@
 		intptr = &options->use_pam;
 		goto parse_flag;
 #endif
+#ifdef PAM_ENHANCEMENT
+	case sPAMServicePrefix:
+		charptr = &options->pam_service_prefix;
+		arg = argv_next(&ac, &av);
+		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 (*charptr == NULL)
+			*charptr = xstrdup(arg);
+		break;
+#endif /* PAM_ENHANCEMENT */
 	case sPAMServiceName:
 		charptr = &options->pam_service_name;
 		arg = argv_next(&ac, &av);
@@ -1416,8 +1460,20 @@
 			fatal("%s line %d: missing argument.",
 			    filename, linenum);
 		}
+#ifdef PAM_ENHANCEMENT
+		if (options->pam_service_prefix != NULL)
+			fatal("%s line %d: PAMServiceName and PAMServicePrefix"
+			    " are mutually exclusive.", filename, linenum);
+#endif /* PAM_ENHANCEMENT */
 		if (*activep && *charptr == NULL)
 			*charptr = xstrdup(arg);
+#ifdef PAM_ENHANCEMENT
+		/*
+		 * When this option is specified, we will not have
+		 * PAM service for each auth method.
+		 */
+		options->pam_service_per_authmethod = 0;
+#endif
 		break;
 
 	/* Standard Options */
--- openssh-10.0p1/servconf.h.orig
+++ openssh-10.0p1/servconf.h
@@ -212,6 +212,10 @@
 
 	int	use_pam;		/* Enable auth via PAM */
 	char   *pam_service_name;
+#ifdef PAM_ENHANCEMENT
+	char   *pam_service_prefix;
+	int     pam_service_per_authmethod;
+#endif
 
 	int	permit_tun;
 
--- openssh-10.0p1/sshd.8.orig
+++ openssh-10.0p1/sshd.8
@@ -1018,6 +1018,31 @@
 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 ,
--- openssh-10.0p1/sshd_config.5.orig
+++ openssh-10.0p1/sshd_config.5
@@ -1320,6 +1320,7 @@
 .Cm MaxAuthTries ,
 .Cm MaxSessions ,
 .Cm PAMServiceName ,
+.Cm PAMServicePrefix ,
 .Cm PasswordAuthentication ,
 .Cm PermitEmptyPasswords ,
 .Cm PermitListen ,
@@ -1388,12 +1389,34 @@
 The default is
 .Pa /etc/moduli .
 .It Cm PAMServiceName
-Specifies the service name used for Pluggable Authentication Modules (PAM)
-authentication, authorisation and session controls when
-.Cm UsePAM
-is enabled.
-The default is
-.Cm sshd .
+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
@@ -2048,8 +2071,7 @@
 is enabled, you will not be able to run
 .Xr sshd 8
 as a non-root user.
-The default is
-.Cm no .
+On OmniOS, 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.