remove xtrans tsol patch
[unleashed-userland.git] / components / network / openssh / patches / 0011-PAM-enhancements-for-Solaris.patch
blobaa4897a5ce51f410b0f9f78274ff28e73a615c75
1 From 44ace33bdb8ac3a8033dabcde4d5c8242fcec169 Mon Sep 17 00:00:00 2001
2 From: oracle <solaris@oracle.com>
3 Date: Mon, 3 Aug 2015 14:36:19 -0700
4 Subject: [PATCH 11/34] PAM enhancements for Solaris
7 # This patch contains a couple of PAM enhancements:
8 # 1) Each SSHv2 userauth method has its own PAM service name so that PAM can
9 # be used to control what userauth methods are allowed.
10 # 2) The PAMServiceName and PAMServicePrefix options.
12 # We have contributed back this feature to the OpenSSH upstream community.
13 # For more information, see https://bugzilla.mindrot.org/show_bug.cgi?id=2246
14 # In the future, if these enhancements are accepted by the upsteam in a
15 # later release, we will remove this patch when we upgrade to that release.
17 ---
18 auth-pam.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 auth.h | 3 ++
20 auth2.c | 61 ++++++++++++++++++++++++++++-
21 monitor.c | 63 ++++++++++++++++++++++++++++++
22 monitor.h | 3 ++
23 monitor_wrap.c | 18 +++++++++
24 servconf.c | 56 +++++++++++++++++++++++++++
25 servconf.h | 10 +++++
26 sshd.8 | 27 +++++++++++++
27 sshd.c | 5 +++
28 sshd_config.5 | 18 ++++++++-
29 11 files changed, 379 insertions(+), 4 deletions(-)
31 diff --git a/auth-pam.c b/auth-pam.c
32 index 92c3b1c..4ca0a58 100644
33 --- a/auth-pam.c
34 +++ b/auth-pam.c
35 @@ -618,6 +618,72 @@ sshpam_cleanup(void)
36 sshpam_handle = NULL;
39 +#ifdef PAM_ENHANCEMENT
40 +char *
41 +derive_pam_service_name(Authctxt *authctxt)
43 + char *svcname = xmalloc(BUFSIZ);
45 + /*
46 + * If PamServiceName is set we use that for everything, including
47 + * SSHv1
48 + */
49 + if (options.pam_service_name != NULL) {
50 + (void) strlcpy(svcname, options.pam_service_name, BUFSIZ);
51 + return (svcname);
52 + }
54 + if (compat20) {
55 + char *method_name = authctxt->authmethod_name;
57 + if (!method_name)
58 + fatal("Userauth method unknown while starting PAM");
60 + /*
61 + * For SSHv2 we use "sshd-<userauth name>
62 + * The "sshd" prefix can be changed via the PAMServicePrefix
63 + * sshd_config option.
64 + */
65 + if (strcmp(method_name, "none") == 0) {
66 + snprintf(svcname, BUFSIZ, "%s-none",
67 + options.pam_service_prefix);
68 + }
69 + if (strcmp(method_name, "password") == 0) {
70 + snprintf(svcname, BUFSIZ, "%s-password",
71 + options.pam_service_prefix);
72 + }
73 + if (strcmp(method_name, "keyboard-interactive") == 0) {
74 + /* "keyboard-interactive" is too long, shorten it */
75 + snprintf(svcname, BUFSIZ, "%s-kbdint",
76 + options.pam_service_prefix);
77 + }
78 + if (strcmp(method_name, "publickey") == 0) {
79 + /* "publickey" is too long, shorten it */
80 + snprintf(svcname, BUFSIZ, "%s-pubkey",
81 + options.pam_service_prefix);
82 + }
83 + if (strcmp(method_name, "hostbased") == 0) {
84 + snprintf(svcname, BUFSIZ, "%s-hostbased",
85 + options.pam_service_prefix);
86 + }
87 + if (strncmp(method_name, "gssapi-", 7) == 0) {
88 + /*
89 + * Although OpenSSH only supports "gssapi-with-mic"
90 + * for now. We will still map any userauth method
91 + * prefixed with "gssapi-" to the gssapi PAM service.
92 + */
93 + snprintf(svcname, BUFSIZ, "%s-gssapi",
94 + options.pam_service_prefix);
95 + }
96 + return svcname;
97 + } else {
98 + /* SSHv1 doesn't get to be so cool */
99 + snprintf(svcname, BUFSIZ, "sshd-v1");
101 + return svcname;
103 +#endif /* PAM_ENHANCEMENT */
105 static int
106 sshpam_init(Authctxt *authctxt)
108 @@ -625,18 +691,71 @@ sshpam_init(Authctxt *authctxt)
109 const char *pam_rhost, *pam_user, *user = authctxt->user;
110 const char **ptr_pam_user = &pam_user;
112 +#ifdef PAM_ENHANCEMENT
113 + const char *pam_service;
114 + const char **ptr_pam_service = &pam_service;
115 + char *svc = NULL;
117 + svc = derive_pam_service_name(authctxt);
118 + debug3("PAM service is %s", svc);
119 +#endif
121 if (sshpam_handle != NULL) {
122 +#ifdef PAM_ENHANCEMENT
123 + /* get the pam service name */
124 + sshpam_err = pam_get_item(sshpam_handle,
125 + PAM_SERVICE, (sshpam_const void **)ptr_pam_service);
126 + if (sshpam_err != PAM_SUCCESS)
127 + fatal("Failed to get the PAM service name");
128 + debug3("Previous pam_service is %s", pam_service ?
129 + pam_service : "NULL");
131 + /* get the pam user name */
132 + sshpam_err = pam_get_item(sshpam_handle,
133 + PAM_USER, (sshpam_const void **)ptr_pam_user);
135 + /*
136 + * only need to re-start if either user or service is
137 + * different.
138 + */
139 + if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0
140 + && strncmp(svc, pam_service, strlen(svc)) == 0) {
141 + free(svc);
142 + return (0);
145 + /*
146 + * Clean up previous PAM state. No need to clean up session
147 + * and creds.
148 + */
149 + sshpam_authenticated = 0;
150 + sshpam_account_status = -1;
152 + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, NULL);
153 + if (sshpam_err != PAM_SUCCESS)
154 + debug3("Cannot remove PAM conv"); /* a warning only */
155 +#else /* Original */
156 /* We already have a PAM context; check if the user matches */
157 sshpam_err = pam_get_item(sshpam_handle,
158 PAM_USER, (sshpam_const void **)ptr_pam_user);
159 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
160 return (0);
161 +#endif /* PAM_ENHANCEMENT */
162 pam_end(sshpam_handle, sshpam_err);
163 sshpam_handle = NULL;
165 debug("PAM: initializing for \"%s\"", user);
167 +#ifdef PAM_ENHANCEMENT
168 + debug3("Starting PAM service %s for user %s method %s", svc, user,
169 + authctxt->authmethod_name);
170 + sshpam_err =
171 + pam_start(svc, user, &store_conv, &sshpam_handle);
172 + free(svc);
173 +#else /* Original */
174 sshpam_err =
175 pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
176 +#endif
177 sshpam_authctxt = authctxt;
179 if (sshpam_err != PAM_SUCCESS) {
180 diff --git a/auth.h b/auth.h
181 index 2160154..985053c 100644
182 --- a/auth.h
183 +++ b/auth.h
184 @@ -81,6 +81,9 @@ struct Authctxt {
186 struct sshkey **prev_userkeys;
187 u_int nprev_userkeys;
188 +#ifdef PAM_ENHANCEMENT
189 + char *authmethod_name;
190 +#endif
193 * Every authentication method has to handle authentication requests for
194 diff --git a/auth2.c b/auth2.c
195 index 7177962..32ba663 100644
196 --- a/auth2.c
197 +++ b/auth2.c
198 @@ -243,10 +243,21 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
199 PRIVSEP(audit_event(SSH_INVALID_USER));
200 #endif
204 #ifdef USE_PAM
205 +#ifdef PAM_ENHANCEMENT
206 + /*
207 + * Start PAM here and once only, if each userauth does not
208 + * has its own PAM service.
209 + */
210 + if (options.use_pam && !options.pam_service_per_authmethod)
211 + PRIVSEP(start_pam(authctxt));
212 +#else
213 if (options.use_pam)
214 PRIVSEP(start_pam(authctxt));
215 #endif
216 +#endif
217 setproctitle("%s%s", authctxt->valid ? user : "unknown",
218 use_privsep ? " [net]" : "");
219 authctxt->service = xstrdup(service);
220 @@ -277,6 +288,18 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
221 /* try to authenticate user */
222 m = authmethod_lookup(authctxt, method);
223 if (m != NULL && authctxt->failures < options.max_authtries) {
225 +#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
226 + /* start PAM service for each userauth */
227 + if (options.use_pam && options.pam_service_per_authmethod) {
228 + if (authctxt->authmethod_name != NULL)
229 + free(authctxt->authmethod_name);
230 + authctxt->authmethod_name = xstrdup(method);
231 + if (use_privsep)
232 + mm_inform_authmethod(method);
233 + PRIVSEP(start_pam(authctxt));
235 +#endif
236 debug2("input_userauth_request: try method %s", method);
237 authenticated = m->userauth(authctxt);
239 @@ -295,6 +318,10 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
240 char *methods;
241 int partial = 0;
243 +#ifdef PAM_ENHANCEMENT
244 + debug3("%s: entering", __func__);
245 +#endif
247 if (!authctxt->valid && authenticated)
248 fatal("INTERNAL ERROR: authenticated invalid user %s",
249 authctxt->user);
250 @@ -311,6 +338,25 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
253 if (authenticated && options.num_auth_methods != 0) {
255 +#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
256 + /*
257 + * If each userauth has its own PAM service, then PAM need to
258 + * perform account check for this service.
259 + */
260 + if (options.use_pam && options.pam_service_per_authmethod &&
261 + !PRIVSEP(do_pam_account())) {
262 + /* if PAM returned a message, send it to the user */
263 + if (buffer_len(&loginmsg) > 0) {
264 + buffer_append(&loginmsg, "\0", 1);
265 + userauth_send_banner(buffer_ptr(&loginmsg));
266 + packet_write_wait();
269 + fatal("Access denied for user %s by PAM account "
270 + "configuration", authctxt->user);
272 +#endif
273 if (!auth2_update_methods_lists(authctxt, method, submethod)) {
274 authenticated = 0;
275 partial = 1;
276 @@ -324,7 +370,20 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
277 return;
279 #ifdef USE_PAM
281 +#ifdef PAM_ENHANCEMENT
282 + /*
283 + * PAM needs to perform account checks after auth. However, if each
284 + * userauth has its own PAM service and options.num_auth_methods != 0,
285 + * then no need to perform account checking, because it was done
286 + * already.
287 + */
288 + if (options.use_pam && authenticated &&
289 + !(options.num_auth_methods != 0 &&
290 + options.pam_service_per_authmethod)){
291 +#else
292 if (options.use_pam && authenticated) {
293 +#endif
294 if (!PRIVSEP(do_pam_account())) {
295 /* if PAM returned a message, send it to the user */
296 if (buffer_len(&loginmsg) > 0) {
297 @@ -615,5 +674,3 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
298 fatal("%s: method not in AuthenticationMethods", __func__);
299 return 0;
303 diff --git a/monitor.c b/monitor.c
304 index ac7dd30..63bde62 100644
305 --- a/monitor.c
306 +++ b/monitor.c
307 @@ -126,6 +126,9 @@ int mm_answer_sign(int, Buffer *);
308 int mm_answer_pwnamallow(int, Buffer *);
309 int mm_answer_auth2_read_banner(int, Buffer *);
310 int mm_answer_authserv(int, Buffer *);
311 +#ifdef PAM_ENHANCEMENT
312 +int mm_answer_authmethod(int, Buffer *);
313 +#endif
314 int mm_answer_authpassword(int, Buffer *);
315 int mm_answer_bsdauthquery(int, Buffer *);
316 int mm_answer_bsdauthrespond(int, Buffer *);
317 @@ -205,10 +208,17 @@ struct mon_table mon_dispatch_proto20[] = {
318 {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
319 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
320 {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
321 +#ifdef PAM_ENHANCEMENT
322 + {MONITOR_REQ_AUTHMETHOD, MON_ISAUTH, mm_answer_authmethod},
323 +#endif
324 {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
325 {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
326 #ifdef USE_PAM
327 +#ifdef PAM_ENHANCEMENT
328 + {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
329 +#else
330 {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
331 +#endif
332 {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
333 {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
334 {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
335 @@ -370,6 +380,24 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
336 if (!compat20)
337 fatal("AuthenticationMethods is not supported"
338 "with SSH protocol 1");
340 +#if defined(USE_PAM) && defined(PAM_ENHANCEMENT)
341 + /*
342 + * If each userauth has its own PAM service, then PAM
343 + * need to perform account check for this service.
344 + */
345 + if (options.use_pam && authenticated &&
346 + options.pam_service_per_authmethod) {
347 + Buffer m;
349 + buffer_init(&m);
350 + mm_request_receive_expect(pmonitor->m_sendfd,
351 + MONITOR_REQ_PAM_ACCOUNT, &m);
352 + authenticated =
353 + mm_answer_pam_account(pmonitor->m_sendfd, &m);
354 + buffer_free(&m);
356 +#endif
357 if (authenticated &&
358 !auth2_update_methods_lists(authctxt,
359 auth_method, auth_submethod)) {
360 @@ -388,8 +416,21 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
361 !auth_root_allowed(auth_method))
362 authenticated = 0;
363 #ifdef USE_PAM
364 +#ifdef PAM_ENHANCEMENT
365 + /*
366 + * PAM needs to perform account checks after auth.
367 + * However, if each userauth has its own PAM service
368 + * and options.num_auth_methods != 0, then no need to
369 + * perform account checking, because it was done
370 + * already.
371 + */
372 + if (options.use_pam && authenticated &&
373 + !(options.num_auth_methods != 0 &&
374 + options.pam_service_per_authmethod)) {
375 +#else
376 /* PAM needs to perform account checks after auth */
377 if (options.use_pam && authenticated) {
378 +#endif
379 Buffer m;
381 buffer_init(&m);
382 @@ -859,6 +900,10 @@ mm_answer_pwnamallow(int sock, Buffer *m)
383 /* Allow service/style information on the auth context */
384 monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
385 monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
386 +#ifdef PAM_ENHANCEMENT
387 + /* Allow authmethod information on the auth context */
388 + monitor_permit(mon_dispatch, MONITOR_REQ_AUTHMETHOD, 1);
389 +#endif
391 #ifdef USE_PAM
392 if (options.use_pam)
393 @@ -899,6 +944,24 @@ mm_answer_authserv(int sock, Buffer *m)
394 return (0);
397 +#ifdef PAM_ENHANCEMENT
398 +int
399 +mm_answer_authmethod(int sock, Buffer *m)
401 + monitor_permit_authentications(1);
403 + authctxt->authmethod_name = buffer_get_string(m, NULL);
404 + debug3("%s: authmethod_name=%s", __func__, authctxt->authmethod_name);
406 + if (strlen(authctxt->authmethod_name) == 0) {
407 + free(authctxt->authmethod_name);
408 + authctxt->authmethod_name = NULL;
411 + return (0);
413 +#endif
416 mm_answer_authpassword(int sock, Buffer *m)
418 diff --git a/monitor.h b/monitor.h
419 index 93b8b66..da63e7d 100644
420 --- a/monitor.h
421 +++ b/monitor.h
422 @@ -65,6 +65,9 @@ enum monitor_reqtype {
423 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
424 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
426 +#ifdef PAM_ENHANCEMENT
427 + MONITOR_REQ_AUTHMETHOD = 114,
428 +#endif
431 struct mm_master;
432 diff --git a/monitor_wrap.c b/monitor_wrap.c
433 index c5db6df..30e3c15 100644
434 --- a/monitor_wrap.c
435 +++ b/monitor_wrap.c
436 @@ -345,6 +345,24 @@ mm_inform_authserv(char *service, char *style)
437 buffer_free(&m);
440 +#ifdef PAM_ENHANCEMENT
441 +/* Inform the privileged process about the authentication method */
442 +void
443 +mm_inform_authmethod(char *authmethod)
445 + Buffer m;
447 + debug3("%s entering", __func__);
449 + buffer_init(&m);
450 + buffer_put_cstring(&m, authmethod);
452 + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHMETHOD, &m);
454 + buffer_free(&m);
456 +#endif
458 /* Do the password authentication */
460 mm_auth_password(Authctxt *authctxt, char *password)
461 diff --git a/servconf.c b/servconf.c
462 index 1872661..b16a8be 100644
463 --- a/servconf.c
464 +++ b/servconf.c
465 @@ -169,6 +169,18 @@ initialize_server_options(ServerOptions *options)
466 options->ip_qos_bulk = -1;
467 options->version_addendum = NULL;
468 options->fingerprint_hash = -1;
469 +#ifdef PAM_ENHANCEMENT
470 + options->pam_service_name = NULL;
471 + options->pam_service_prefix = NULL;
473 + /*
474 + * Each user method will have its own PAM service by default.
475 + * However, if PAMServiceName is specified or the protocal version
476 + * is not compat20, then there will be only one PAM service for the
477 + * entire user authentication.
478 + */
479 + options->pam_service_per_authmethod = 1;
480 +#endif
483 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
484 @@ -352,6 +364,12 @@ fill_default_server_options(ServerOptions *options)
485 options->ip_qos_bulk = IPTOS_THROUGHPUT;
486 if (options->version_addendum == NULL)
487 options->version_addendum = xstrdup("");
489 +#ifdef PAM_ENHANCEMENT
490 + if (options->pam_service_prefix == NULL)
491 + options->pam_service_prefix = _SSH_PAM_SERVICE_PREFIX;
492 +#endif
494 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
495 options->fwd_opts.streamlocal_bind_mask = 0177;
496 if (options->fwd_opts.streamlocal_bind_unlink == -1)
497 @@ -428,6 +446,9 @@ typedef enum {
498 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
499 sUsePrivilegeSeparation, sAllowAgentForwarding,
500 sHostCertificate,
501 +#ifdef PAM_ENHANCEMENT
502 + sPAMServicePrefix, sPAMServiceName,
503 +#endif
504 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
505 sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
506 sKexAlgorithms, sIPQoS, sVersionAddendum,
507 @@ -566,6 +587,10 @@ static struct {
508 { "forcecommand", sForceCommand, SSHCFG_ALL },
509 { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
510 { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
511 +#ifdef PAM_ENHANCEMENT
512 + { "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
513 + { "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
514 +#endif
515 { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
516 { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
517 { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
518 @@ -1868,6 +1893,37 @@ process_server_config_line(ServerOptions *options, char *line,
519 options->fingerprint_hash = value;
520 break;
522 + case sPAMServicePrefix:
523 + arg = strdelim(&cp);
524 + if (!arg || *arg == '\0')
525 + fatal("%s line %d: Missing argument.",
526 + filename, linenum);
527 + if (options->pam_service_name != NULL)
528 + fatal("%s line %d: PAMServiceName and PAMServicePrefix"
529 + " are mutually exclusive.", filename, linenum);
530 + if (options->pam_service_prefix == NULL)
531 + options->pam_service_prefix = xstrdup(arg);
532 + break;
534 + case sPAMServiceName:
535 + arg = strdelim(&cp);
536 + if (!arg || *arg == '\0')
537 + fatal("%s line %d: Missing argument.",
538 + filename, linenum);
539 + if (options->pam_service_prefix != NULL)
540 + fatal("%s line %d: PAMServiceName and PAMServicePrefix"
541 + " are mutually exclusive.", filename, linenum);
542 + if (options->pam_service_name == NULL) {
543 + options->pam_service_name = xstrdup(arg);
545 + /*
546 + * When this option is specified, we will not have
547 + * PAM service for each auth method.
548 + */
549 + options->pam_service_per_authmethod = 0;
551 + break;
553 case sDeprecated:
554 logit("%s line %d: Deprecated option %s",
555 filename, linenum, arg);
556 diff --git a/servconf.h b/servconf.h
557 index f4137af..8c86b57 100644
558 --- a/servconf.h
559 +++ b/servconf.h
560 @@ -54,6 +54,10 @@
561 /* Magic name for internal sftp-server */
562 #define INTERNAL_SFTP_NAME "internal-sftp"
564 +#ifdef PAM_ENHANCEMENT
565 +#define _SSH_PAM_SERVICE_PREFIX "sshd"
566 +#endif
568 typedef struct {
569 u_int num_ports;
570 u_int ports_from_cmdline;
571 @@ -194,6 +198,12 @@ typedef struct {
572 u_int num_auth_methods;
573 char *auth_methods[MAX_AUTH_METHODS];
575 +#ifdef PAM_ENHANCEMENT
576 + char *pam_service_prefix;
577 + char *pam_service_name;
578 + int pam_service_per_authmethod;
579 +#endif
581 int fingerprint_hash;
582 } ServerOptions;
584 diff --git a/sshd.8 b/sshd.8
585 index dac5c14..500c4d5 100644
586 --- a/sshd.8
587 +++ b/sshd.8
588 @@ -977,6 +977,33 @@ concurrently for different ports, this contains the process ID of the one
589 started last).
590 The content of this file is not sensitive; it can be world-readable.
593 +.Sh SECURITY
594 +sshd uses pam(3PAM) for password and keyboard-interactive methods as well as
595 +for account management, session management, and the password management for all
596 +authentication methods.
597 +.Pp
598 +Each SSHv2 userauth type has its own PAM service name:
600 +.Bd -literal -offset 3n
602 +-----------------------------------------------
603 +| SSHv2 Userauth | PAM Service Name |
604 +-----------------------------------------------
605 +| none | sshd-none |
606 +-----------------------------------------------
607 +| password | sshd-password |
608 +-----------------------------------------------
609 +| keyboard-interactive | sshd-kbdint |
610 +-----------------------------------------------
611 +| pubkey | sshd-pubkey |
612 +-----------------------------------------------
613 +| hostbased | sshd-hostbased |
614 +-----------------------------------------------
615 +| gssapi-with-mic | sshd-gssapi |
616 +-----------------------------------------------
617 +.Ed
619 .Sh SEE ALSO
620 .Xr scp 1 ,
621 .Xr sftp 1 ,
622 diff --git a/sshd.c b/sshd.c
623 index 68fd1ea..418e1fd 100644
624 --- a/sshd.c
625 +++ b/sshd.c
626 @@ -2165,6 +2165,11 @@ main(int ac, char **av)
628 sshd_exchange_identification(sock_in, sock_out);
630 +#ifdef PAM_ENHANCEMENT
631 + if (!compat20)
632 + options.pam_service_per_authmethod = 0;
633 +#endif
635 /* In inetd mode, generate ephemeral key only for proto 1 connections */
636 if (!compat20 && inetd_flag && sensitive_data.server_key == NULL)
637 generate_ephemeral_server_key();
638 diff --git a/sshd_config.5 b/sshd_config.5
639 index 6351b43..f45ddef 100644
640 --- a/sshd_config.5
641 +++ b/sshd_config.5
642 @@ -1168,6 +1168,21 @@ The probability increases linearly and all connection attempts
643 are refused if the number of unauthenticated connections reaches
644 .Dq full
645 (60).
646 +.It Cm PAMServiceName
647 +Specifies the PAM service name for the PAM session. The PAMServiceName and
648 +PAMServicePrefix options are mutually exclusive and if both set, sshd does not
649 +start. If this option is set the service name is the same for all user
650 +authentication methods. The option has no default value. See PAMServicePrefix
651 +for more information.
652 +.It Cm PAMServicePrefix
653 +Specifies the PAM service name prefix for service names used for individual
654 +user authentication methods. The default is sshd. The PAMServiceName and
655 +PAMServicePrefix options are mutually exclusive and if both set, sshd does not
656 +start.
657 +.Pp
658 +For example, if this option is set to admincli, the service name for the
659 +keyboard-interactive authentication method is admincli-kbdint instead of the
660 +default sshd-kbdint.
661 .It Cm PasswordAuthentication
662 Specifies whether password authentication is allowed.
663 The default is
664 @@ -1582,8 +1597,7 @@ If
665 is enabled, you will not be able to run
666 .Xr sshd 1M
667 as a non-root user.
668 -The default is
669 -.Dq no .
670 +On Solaris, the option is always enabled.
671 .It Cm UsePrivilegeSeparation
672 Specifies whether
673 .Xr sshd 1M
675 2.5.4 (Apple Git-61)