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