2 * Copyright (c) 2002 Networks Associates Technology, Inc.
5 * This software was developed for the FreeBSD Project by ThinkSec AS and
6 * NAI Labs, the Security Research Division of Network Associates, Inc.
7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8 * DARPA CHATS research program.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
33 * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
35 * Permission to use, copy, modify, and distribute this software for any
36 * purpose with or without fee is hereby granted, provided that the above
37 * copyright notice and this permission notice appear in all copies.
39 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
40 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
41 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
42 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
43 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
44 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
45 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48 /* Based on FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des */
52 #include <sys/types.h>
64 #if defined(HAVE_SECURITY_PAM_APPL_H)
65 #include <security/pam_appl.h>
66 #elif defined (HAVE_PAM_PAM_APPL_H)
67 #include <pam/pam_appl.h>
70 #if !defined(SSHD_PAM_SERVICE)
71 extern char *__progname
;
72 # define SSHD_PAM_SERVICE __progname
75 /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
76 #ifdef PAM_SUN_CODEBASE
77 # define sshpam_const /* Solaris, HP-UX, SunOS */
79 # define sshpam_const const /* LinuxPAM, OpenPAM, AIX */
82 /* Ambiguity in spec: is it an array of pointers or a pointer to an array? */
83 #ifdef PAM_SUN_CODEBASE
84 # define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
86 # define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
100 #include "servconf.h"
102 #include "auth-options.h"
107 #include "monitor_wrap.h"
109 extern ServerOptions options
;
110 extern struct sshbuf
*loginmsg
;
111 extern u_int utmp_len
;
113 /* so we don't silently change behaviour */
114 #ifdef USE_POSIX_THREADS
115 # error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
119 * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
120 * and generally a bad idea. Use at own risk and do not expect support if
123 #ifdef UNSUPPORTED_POSIX_THREADS_HACK
126 * Avoid namespace clash when *not* using pthreads for systems *with*
127 * pthreads, which unconditionally define pthread_t via sys/types.h
130 typedef pthread_t sp_pthread_t
;
132 typedef pid_t sp_pthread_t
;
133 #define pthread_exit fake_pthread_exit
134 #define pthread_create fake_pthread_create
135 #define pthread_cancel fake_pthread_cancel
136 #define pthread_join fake_pthread_join
140 sp_pthread_t pam_thread
;
146 static void sshpam_free_ctx(void *);
147 static struct pam_ctxt
*cleanup_ctxt
;
149 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
151 * Simulate threads with processes.
154 static int sshpam_thread_status
= -1;
155 static sshsig_t sshpam_oldsig
;
158 sshpam_sigchld_handler(int sig
)
160 ssh_signal(SIGCHLD
, SIG_DFL
);
161 if (cleanup_ctxt
== NULL
)
162 return; /* handler called after PAM cleanup, shouldn't happen */
163 if (waitpid(cleanup_ctxt
->pam_thread
, &sshpam_thread_status
, WNOHANG
)
165 /* PAM thread has not exitted, privsep slave must have */
166 kill(cleanup_ctxt
->pam_thread
, SIGTERM
);
167 while (waitpid(cleanup_ctxt
->pam_thread
,
168 &sshpam_thread_status
, 0) == -1) {
174 if (WIFSIGNALED(sshpam_thread_status
) &&
175 WTERMSIG(sshpam_thread_status
) == SIGTERM
)
176 return; /* terminated by pthread_cancel */
177 if (!WIFEXITED(sshpam_thread_status
))
178 sigdie("PAM: authentication thread exited unexpectedly");
179 if (WEXITSTATUS(sshpam_thread_status
) != 0)
180 sigdie("PAM: authentication thread exited uncleanly");
185 pthread_exit(void *value
)
192 pthread_create(sp_pthread_t
*thread
, const void *attr
,
193 void *(*thread_start
)(void *), void *arg
)
196 struct pam_ctxt
*ctx
= arg
;
198 sshpam_thread_status
= -1;
199 switch ((pid
= fork())) {
201 error("fork(): %s", strerror(errno
));
204 close(ctx
->pam_psock
);
210 close(ctx
->pam_csock
);
212 sshpam_oldsig
= ssh_signal(SIGCHLD
, sshpam_sigchld_handler
);
218 pthread_cancel(sp_pthread_t thread
)
220 ssh_signal(SIGCHLD
, sshpam_oldsig
);
221 return (kill(thread
, SIGTERM
));
226 pthread_join(sp_pthread_t thread
, void **value
)
230 if (sshpam_thread_status
!= -1)
231 return (sshpam_thread_status
);
232 ssh_signal(SIGCHLD
, sshpam_oldsig
);
233 while (waitpid(thread
, &status
, 0) == -1) {
236 fatal("%s: waitpid: %s", __func__
, strerror(errno
));
243 static pam_handle_t
*sshpam_handle
= NULL
;
244 static int sshpam_err
= 0;
245 static int sshpam_authenticated
= 0;
246 static int sshpam_session_open
= 0;
247 static int sshpam_cred_established
= 0;
248 static int sshpam_account_status
= -1;
249 static int sshpam_maxtries_reached
= 0;
250 static char **sshpam_env
= NULL
;
251 static Authctxt
*sshpam_authctxt
= NULL
;
252 static const char *sshpam_password
= NULL
;
253 static char *sshpam_rhost
= NULL
;
254 static char *sshpam_laddr
= NULL
;
255 static char *sshpam_conninfo
= NULL
;
257 /* Some PAM implementations don't implement this */
258 #ifndef HAVE_PAM_GETENVLIST
260 pam_getenvlist(pam_handle_t
*pamh
)
263 * XXX - If necessary, we can still support environment passing
264 * for platforms without pam_getenvlist by searching for known
265 * env vars (e.g. KRB5CCNAME) from the PAM environment.
271 #ifndef HAVE_PAM_PUTENV
273 pam_putenv(pam_handle_t
*pamh
, const char *name_value
)
277 #endif /* HAVE_PAM_PUTENV */
280 * Some platforms, notably Solaris, do not enforce password complexity
281 * rules during pam_chauthtok() if the real uid of the calling process
282 * is 0, on the assumption that it's being called by "passwd" run by root.
283 * This wraps pam_chauthtok and sets/restore the real uid so PAM will do
286 #ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
288 sshpam_chauthtok_ruid(pam_handle_t
*pamh
, int flags
)
292 if (sshpam_authctxt
== NULL
)
293 fatal("PAM: sshpam_authctxt not initialized");
294 if (setreuid(sshpam_authctxt
->pw
->pw_uid
, -1) == -1)
295 fatal("%s: setreuid failed: %s", __func__
, strerror(errno
));
296 result
= pam_chauthtok(pamh
, flags
);
297 if (setreuid(0, -1) == -1)
298 fatal("%s: setreuid failed: %s", __func__
, strerror(errno
));
301 # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b)))
305 sshpam_password_change_required(int reqd
)
307 extern struct sshauthopt
*auth_opts
;
308 static int saved_port
, saved_agent
, saved_x11
;
310 debug3("%s %d", __func__
, reqd
);
311 if (sshpam_authctxt
== NULL
)
312 fatal("%s: PAM authctxt not initialized", __func__
);
313 sshpam_authctxt
->force_pwchange
= reqd
;
315 saved_port
= auth_opts
->permit_port_forwarding_flag
;
316 saved_agent
= auth_opts
->permit_agent_forwarding_flag
;
317 saved_x11
= auth_opts
->permit_x11_forwarding_flag
;
318 auth_opts
->permit_port_forwarding_flag
= 0;
319 auth_opts
->permit_agent_forwarding_flag
= 0;
320 auth_opts
->permit_x11_forwarding_flag
= 0;
323 auth_opts
->permit_port_forwarding_flag
= saved_port
;
325 auth_opts
->permit_agent_forwarding_flag
= saved_agent
;
327 auth_opts
->permit_x11_forwarding_flag
= saved_x11
;
331 /* Import regular and PAM environment from subprocess */
333 import_environments(struct sshbuf
*b
)
339 debug3("PAM: %s entering", __func__
);
341 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
342 /* Import variables set by do_pam_account */
343 if ((r
= sshbuf_get_u32(b
, &n
)) != 0)
344 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
346 fatal("%s: invalid PAM account status %u", __func__
, n
);
347 sshpam_account_status
= (int)n
;
348 if ((r
= sshbuf_get_u32(b
, &n
)) != 0)
349 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
350 sshpam_password_change_required(n
!= 0);
352 /* Import environment from subprocess */
353 if ((r
= sshbuf_get_u32(b
, &num_env
)) != 0)
354 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
356 fatal("%s: received %u environment variables, expected <= 1024",
358 sshpam_env
= xcalloc(num_env
+ 1, sizeof(*sshpam_env
));
359 debug3("PAM: num env strings %d", num_env
);
360 for(i
= 0; i
< num_env
; i
++) {
361 if ((r
= sshbuf_get_cstring(b
, &(sshpam_env
[i
]), NULL
)) != 0)
362 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
364 sshpam_env
[num_env
] = NULL
;
366 /* Import PAM environment from subprocess */
367 if ((r
= sshbuf_get_u32(b
, &num_env
)) != 0)
368 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
369 debug("PAM: num PAM env strings %d", num_env
);
370 for (i
= 0; i
< num_env
; i
++) {
371 if ((r
= sshbuf_get_cstring(b
, &env
, NULL
)) != 0)
372 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
373 /* Errors are not fatal here */
374 if ((r
= pam_putenv(sshpam_handle
, env
)) != PAM_SUCCESS
) {
375 error("PAM: pam_putenv: %s",
376 pam_strerror(sshpam_handle
, r
));
379 * XXX this possibly leaks env because it is not documented
380 * what pam_putenv() does with it. Does it copy it? Does it
381 * take ownweship? We don't know, so it's safest just to leak.
388 * Conversation function for authentication thread.
391 sshpam_thread_conv(int n
, sshpam_const
struct pam_message
**msg
,
392 struct pam_response
**resp
, void *data
)
394 struct sshbuf
*buffer
;
395 struct pam_ctxt
*ctxt
;
396 struct pam_response
*reply
;
400 debug3("PAM: %s entering, %d messages", __func__
, n
);
404 error("PAM: conversation function passed a null context");
405 return (PAM_CONV_ERR
);
408 if (n
<= 0 || n
> PAM_MAX_NUM_MSG
)
409 return (PAM_CONV_ERR
);
411 if ((reply
= calloc(n
, sizeof(*reply
))) == NULL
)
413 if ((buffer
= sshbuf_new()) == NULL
) {
418 for (i
= 0; i
< n
; ++i
) {
419 switch (PAM_MSG_MEMBER(msg
, i
, msg_style
)) {
420 case PAM_PROMPT_ECHO_OFF
:
421 case PAM_PROMPT_ECHO_ON
:
422 if ((r
= sshbuf_put_cstring(buffer
,
423 PAM_MSG_MEMBER(msg
, i
, msg
))) != 0)
424 fatal("%s: buffer error: %s",
425 __func__
, ssh_err(r
));
426 if (ssh_msg_send(ctxt
->pam_csock
,
427 PAM_MSG_MEMBER(msg
, i
, msg_style
), buffer
) == -1)
430 if (ssh_msg_recv(ctxt
->pam_csock
, buffer
) == -1)
432 if ((r
= sshbuf_get_u8(buffer
, &status
)) != 0)
433 fatal("%s: buffer error: %s",
434 __func__
, ssh_err(r
));
435 if (status
!= PAM_AUTHTOK
)
437 if ((r
= sshbuf_get_cstring(buffer
,
438 &reply
[i
].resp
, NULL
)) != 0)
439 fatal("%s: buffer error: %s",
440 __func__
, ssh_err(r
));
444 if ((r
= sshbuf_put_cstring(buffer
,
445 PAM_MSG_MEMBER(msg
, i
, msg
))) != 0)
446 fatal("%s: buffer error: %s",
447 __func__
, ssh_err(r
));
448 if (ssh_msg_send(ctxt
->pam_csock
,
449 PAM_MSG_MEMBER(msg
, i
, msg_style
), buffer
) == -1)
455 sshbuf_reset(buffer
);
459 return (PAM_SUCCESS
);
462 for(i
= 0; i
< n
; i
++) {
467 return (PAM_CONV_ERR
);
471 * Authentication thread.
474 sshpam_thread(void *ctxtp
)
476 struct pam_ctxt
*ctxt
= ctxtp
;
477 struct sshbuf
*buffer
= NULL
;
478 struct pam_conv sshpam_conv
;
479 int r
, flags
= (options
.permit_empty_passwd
== 0 ?
480 PAM_DISALLOW_NULL_AUTHTOK
: 0);
481 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
482 extern char **environ
;
485 const char *pam_user
;
486 const char **ptr_pam_user
= &pam_user
;
487 char *tz
= getenv("TZ");
489 sshpam_err
= pam_get_item(sshpam_handle
, PAM_USER
,
490 (sshpam_const
void **)ptr_pam_user
);
491 if (sshpam_err
!= PAM_SUCCESS
)
496 if (setenv("TZ", tz
, 1) == -1)
497 error("PAM: could not set TZ environment: %s",
500 if (sshpam_authctxt
!= NULL
) {
501 setproctitle("%s [pam]",
502 sshpam_authctxt
->valid
? pam_user
: "unknown");
506 sshpam_conv
.conv
= sshpam_thread_conv
;
507 sshpam_conv
.appdata_ptr
= ctxt
;
509 if (sshpam_authctxt
== NULL
)
510 fatal("%s: PAM authctxt not initialized", __func__
);
512 if ((buffer
= sshbuf_new()) == NULL
)
513 fatal("%s: sshbuf_new failed", __func__
);
515 sshpam_err
= pam_set_item(sshpam_handle
, PAM_CONV
,
516 (const void *)&sshpam_conv
);
517 if (sshpam_err
!= PAM_SUCCESS
)
519 sshpam_err
= pam_authenticate(sshpam_handle
, flags
);
520 if (sshpam_err
== PAM_MAXTRIES
)
521 sshpam_set_maxtries_reached(1);
522 if (sshpam_err
!= PAM_SUCCESS
)
525 if (!do_pam_account()) {
526 sshpam_err
= PAM_ACCT_EXPIRED
;
529 if (sshpam_authctxt
->force_pwchange
) {
530 sshpam_err
= pam_chauthtok(sshpam_handle
,
531 PAM_CHANGE_EXPIRED_AUTHTOK
);
532 if (sshpam_err
!= PAM_SUCCESS
)
534 sshpam_password_change_required(0);
537 if ((r
= sshbuf_put_cstring(buffer
, "OK")) != 0)
538 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
540 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
541 /* Export variables set by do_pam_account */
542 if ((r
= sshbuf_put_u32(buffer
, sshpam_account_status
)) != 0 ||
543 (r
= sshbuf_put_u32(buffer
, sshpam_authctxt
->force_pwchange
)) != 0)
544 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
546 /* Export any environment strings set in child */
547 for (i
= 0; environ
[i
] != NULL
; i
++) {
550 fatal("%s: too many environment strings", __func__
);
552 if ((r
= sshbuf_put_u32(buffer
, i
)) != 0)
553 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
554 for (i
= 0; environ
[i
] != NULL
; i
++) {
555 if ((r
= sshbuf_put_cstring(buffer
, environ
[i
])) != 0)
556 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
558 /* Export any environment strings set by PAM in child */
559 env_from_pam
= pam_getenvlist(sshpam_handle
);
560 for (i
= 0; env_from_pam
!= NULL
&& env_from_pam
[i
] != NULL
; i
++) {
563 fatal("%s: too many PAM environment strings", __func__
);
565 if ((r
= sshbuf_put_u32(buffer
, i
)) != 0)
566 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
567 for (i
= 0; env_from_pam
!= NULL
&& env_from_pam
[i
] != NULL
; i
++) {
568 if ((r
= sshbuf_put_cstring(buffer
, env_from_pam
[i
])) != 0)
569 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
571 #endif /* UNSUPPORTED_POSIX_THREADS_HACK */
573 /* XXX - can't do much about an error here */
574 ssh_msg_send(ctxt
->pam_csock
, sshpam_err
, buffer
);
579 if ((r
= sshbuf_put_cstring(buffer
,
580 pam_strerror(sshpam_handle
, sshpam_err
))) != 0)
581 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
582 /* XXX - can't do much about an error here */
583 if (sshpam_err
== PAM_ACCT_EXPIRED
)
584 ssh_msg_send(ctxt
->pam_csock
, PAM_ACCT_EXPIRED
, buffer
);
585 else if (sshpam_maxtries_reached
)
586 ssh_msg_send(ctxt
->pam_csock
, PAM_MAXTRIES
, buffer
);
588 ssh_msg_send(ctxt
->pam_csock
, PAM_AUTH_ERR
, buffer
);
592 return (NULL
); /* Avoid warning for non-pthread case */
596 sshpam_thread_cleanup(void)
598 struct pam_ctxt
*ctxt
= cleanup_ctxt
;
600 debug3("PAM: %s entering", __func__
);
601 if (ctxt
!= NULL
&& ctxt
->pam_thread
!= 0) {
602 pthread_cancel(ctxt
->pam_thread
);
603 pthread_join(ctxt
->pam_thread
, NULL
);
604 close(ctxt
->pam_psock
);
605 close(ctxt
->pam_csock
);
606 memset(ctxt
, 0, sizeof(*ctxt
));
612 sshpam_null_conv(int n
, sshpam_const
struct pam_message
**msg
,
613 struct pam_response
**resp
, void *data
)
615 debug3("PAM: %s entering, %d messages", __func__
, n
);
616 return (PAM_CONV_ERR
);
619 static struct pam_conv null_conv
= { sshpam_null_conv
, NULL
};
622 sshpam_store_conv(int n
, sshpam_const
struct pam_message
**msg
,
623 struct pam_response
**resp
, void *data
)
625 struct pam_response
*reply
;
628 debug3("PAM: %s called with %d messages", __func__
, n
);
631 if (n
<= 0 || n
> PAM_MAX_NUM_MSG
)
632 return (PAM_CONV_ERR
);
634 if ((reply
= calloc(n
, sizeof(*reply
))) == NULL
)
635 return (PAM_CONV_ERR
);
637 for (i
= 0; i
< n
; ++i
) {
638 switch (PAM_MSG_MEMBER(msg
, i
, msg_style
)) {
641 if ((r
= sshbuf_putf(loginmsg
, "%s\n",
642 PAM_MSG_MEMBER(msg
, i
, msg
))) != 0)
643 fatal("%s: buffer error: %s",
644 __func__
, ssh_err(r
));
645 reply
[i
].resp_retcode
= PAM_SUCCESS
;
652 return (PAM_SUCCESS
);
655 for(i
= 0; i
< n
; i
++) {
659 return (PAM_CONV_ERR
);
662 static struct pam_conv store_conv
= { sshpam_store_conv
, NULL
};
667 if (sshpam_handle
== NULL
|| (use_privsep
&& !mm_is_monitor()))
669 debug("PAM: cleanup");
670 pam_set_item(sshpam_handle
, PAM_CONV
, (const void *)&null_conv
);
671 if (sshpam_session_open
) {
672 debug("PAM: closing session");
673 pam_close_session(sshpam_handle
, PAM_SILENT
);
674 sshpam_session_open
= 0;
676 if (sshpam_cred_established
) {
677 debug("PAM: deleting credentials");
678 pam_setcred(sshpam_handle
, PAM_DELETE_CRED
);
679 sshpam_cred_established
= 0;
681 sshpam_authenticated
= 0;
682 pam_end(sshpam_handle
, sshpam_err
);
683 sshpam_handle
= NULL
;
687 sshpam_init(struct ssh
*ssh
, Authctxt
*authctxt
)
689 const char *pam_user
, *user
= authctxt
->user
;
690 const char **ptr_pam_user
= &pam_user
;
692 #if defined(PAM_SUN_CODEBASE) && defined(PAM_MAX_RESP_SIZE)
693 /* Protect buggy PAM implementations from excessively long usernames */
694 if (strlen(user
) >= PAM_MAX_RESP_SIZE
)
695 fatal("Username too long from %s port %d",
696 ssh_remote_ipaddr(ssh
), ssh_remote_port(ssh
));
698 if (sshpam_handle
== NULL
) {
700 fatal("%s: called initially with no "
701 "packet context", __func__
);
703 } if (sshpam_handle
!= NULL
) {
704 /* We already have a PAM context; check if the user matches */
705 sshpam_err
= pam_get_item(sshpam_handle
,
706 PAM_USER
, (sshpam_const
void **)ptr_pam_user
);
707 if (sshpam_err
== PAM_SUCCESS
&& strcmp(user
, pam_user
) == 0)
709 pam_end(sshpam_handle
, sshpam_err
);
710 sshpam_handle
= NULL
;
712 debug("PAM: initializing for \"%s\"", user
);
714 pam_start(SSHD_PAM_SERVICE
, user
, &store_conv
, &sshpam_handle
);
715 sshpam_authctxt
= authctxt
;
717 if (sshpam_err
!= PAM_SUCCESS
) {
718 pam_end(sshpam_handle
, sshpam_err
);
719 sshpam_handle
= NULL
;
723 if (ssh
!= NULL
&& sshpam_rhost
== NULL
) {
725 * We need to cache these as we don't have packet context
726 * during the kbdint flow.
728 sshpam_rhost
= xstrdup(auth_get_canonical_hostname(ssh
,
730 sshpam_laddr
= get_local_ipaddr(
731 ssh_packet_get_connection_in(ssh
));
732 xasprintf(&sshpam_conninfo
, "SSH_CONNECTION=%.50s %d %.50s %d",
733 ssh_remote_ipaddr(ssh
), ssh_remote_port(ssh
),
734 sshpam_laddr
, ssh_local_port(ssh
));
736 if (sshpam_rhost
!= NULL
) {
737 debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost
);
738 sshpam_err
= pam_set_item(sshpam_handle
, PAM_RHOST
,
740 if (sshpam_err
!= PAM_SUCCESS
) {
741 pam_end(sshpam_handle
, sshpam_err
);
742 sshpam_handle
= NULL
;
745 /* Put SSH_CONNECTION in the PAM environment too */
746 pam_putenv(sshpam_handle
, sshpam_conninfo
);
749 #ifdef PAM_TTY_KLUDGE
751 * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
752 * sshd doesn't set the tty until too late in the auth process and
753 * may not even set one (for tty-less connections)
755 debug("PAM: setting PAM_TTY to \"ssh\"");
756 sshpam_err
= pam_set_item(sshpam_handle
, PAM_TTY
, "ssh");
757 if (sshpam_err
!= PAM_SUCCESS
) {
758 pam_end(sshpam_handle
, sshpam_err
);
759 sshpam_handle
= NULL
;
767 expose_authinfo(const char *caller
)
772 * Expose authentication information to PAM.
773 * The environment variable is versioned. Please increment the
774 * version suffix if the format of session_info changes.
776 if (sshpam_authctxt
->session_info
== NULL
)
777 auth_info
= xstrdup("");
778 else if ((auth_info
= sshbuf_dup_string(
779 sshpam_authctxt
->session_info
)) == NULL
)
780 fatal("%s: sshbuf_dup_string failed", __func__
);
782 debug2("%s: auth information in SSH_AUTH_INFO_0", caller
);
783 do_pam_putenv("SSH_AUTH_INFO_0", auth_info
);
788 sshpam_init_ctx(Authctxt
*authctxt
)
790 struct pam_ctxt
*ctxt
;
791 int result
, socks
[2];
793 debug3("PAM: %s entering", __func__
);
795 * Refuse to start if we don't have PAM enabled or do_pam_account
796 * has previously failed.
798 if (!options
.use_pam
|| sshpam_account_status
== 0)
802 if (sshpam_init(NULL
, authctxt
) == -1) {
803 error("PAM: initialization failed");
807 expose_authinfo(__func__
);
808 ctxt
= xcalloc(1, sizeof *ctxt
);
810 /* Start the authentication thread */
811 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, socks
) == -1) {
812 error("PAM: failed create sockets: %s", strerror(errno
));
816 ctxt
->pam_psock
= socks
[0];
817 ctxt
->pam_csock
= socks
[1];
818 result
= pthread_create(&ctxt
->pam_thread
, NULL
, sshpam_thread
, ctxt
);
820 error("PAM: failed to start authentication thread: %s",
832 sshpam_query(void *ctx
, char **name
, char **info
,
833 u_int
*num
, char ***prompts
, u_int
**echo_on
)
835 struct sshbuf
*buffer
;
836 struct pam_ctxt
*ctxt
= ctx
;
843 debug3("PAM: %s entering", __func__
);
844 if ((buffer
= sshbuf_new()) == NULL
)
845 fatal("%s: sshbuf_new failed", __func__
);
848 *prompts
= xmalloc(sizeof(char *));
851 *echo_on
= xmalloc(sizeof(u_int
));
852 while (ssh_msg_recv(ctxt
->pam_psock
, buffer
) == 0) {
853 if ((r
= sshbuf_get_u8(buffer
, &type
)) != 0 ||
854 (r
= sshbuf_get_cstring(buffer
, &msg
, &mlen
)) != 0)
855 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
857 case PAM_PROMPT_ECHO_ON
:
858 case PAM_PROMPT_ECHO_OFF
:
860 len
= plen
+ mlen
+ 1;
861 **prompts
= xreallocarray(**prompts
, 1, len
);
862 strlcpy(**prompts
+ plen
, msg
, len
- plen
);
864 **echo_on
= (type
== PAM_PROMPT_ECHO_ON
);
870 /* accumulate messages */
871 len
= plen
+ mlen
+ 2;
872 **prompts
= xreallocarray(**prompts
, 1, len
);
873 strlcpy(**prompts
+ plen
, msg
, len
- plen
);
875 strlcat(**prompts
+ plen
, "\n", len
- plen
);
879 case PAM_ACCT_EXPIRED
:
881 if (type
== PAM_ACCT_EXPIRED
)
882 sshpam_account_status
= 0;
883 if (type
== PAM_MAXTRIES
)
884 sshpam_set_maxtries_reached(1);
887 debug3("PAM: %s", pam_strerror(sshpam_handle
, type
));
888 if (**prompts
!= NULL
&& strlen(**prompts
) != 0) {
901 if (**prompts
!= NULL
) {
902 /* drain any accumulated messages */
903 debug("PAM: %s", **prompts
);
904 if ((r
= sshbuf_put(loginmsg
, **prompts
,
905 strlen(**prompts
))) != 0)
906 fatal("%s: buffer error: %s",
907 __func__
, ssh_err(r
));
911 if (type
== PAM_SUCCESS
) {
912 if (!sshpam_authctxt
->valid
||
913 (sshpam_authctxt
->pw
->pw_uid
== 0 &&
914 options
.permit_root_login
!= PERMIT_YES
))
915 fatal("Internal error: PAM auth "
916 "succeeded when it should have "
918 import_environments(buffer
);
926 error("PAM: %s for %s%.100s from %.100s", msg
,
927 sshpam_authctxt
->valid
? "" : "illegal user ",
928 sshpam_authctxt
->user
, sshpam_rhost
);
944 * Returns a junk password of identical length to that the user supplied.
945 * Used to mitigate timing attacks against crypt(3)/PAM stacks that
946 * vary processing time in proportion to password length.
949 fake_password(const char *wire_password
)
951 const char junk
[] = "\b\n\r\177INCORRECT";
953 size_t i
, l
= wire_password
!= NULL
? strlen(wire_password
) : 0;
956 fatal("%s: password length too long: %zu", __func__
, l
);
961 for (i
= 0; i
< l
; i
++)
962 ret
[i
] = junk
[i
% (sizeof(junk
) - 1)];
967 /* XXX - see also comment in auth-chall.c:verify_response */
969 sshpam_respond(void *ctx
, u_int num
, char **resp
)
971 struct sshbuf
*buffer
;
972 struct pam_ctxt
*ctxt
= ctx
;
976 debug2("PAM: %s entering, %u responses", __func__
, num
);
977 switch (ctxt
->pam_done
) {
979 sshpam_authenticated
= 1;
987 error("PAM: expected one response, got %u", num
);
990 if ((buffer
= sshbuf_new()) == NULL
)
991 fatal("%s: sshbuf_new failed", __func__
);
992 if (sshpam_authctxt
->valid
&&
993 (sshpam_authctxt
->pw
->pw_uid
!= 0 ||
994 options
.permit_root_login
== PERMIT_YES
)) {
995 if ((r
= sshbuf_put_cstring(buffer
, *resp
)) != 0)
996 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
998 fake
= fake_password(*resp
);
999 if ((r
= sshbuf_put_cstring(buffer
, fake
)) != 0)
1000 fatal("%s: buffer error: %s", __func__
, ssh_err(r
));
1003 if (ssh_msg_send(ctxt
->pam_psock
, PAM_AUTHTOK
, buffer
) == -1) {
1004 sshbuf_free(buffer
);
1007 sshbuf_free(buffer
);
1012 sshpam_free_ctx(void *ctxtp
)
1014 struct pam_ctxt
*ctxt
= ctxtp
;
1016 debug3("PAM: %s entering", __func__
);
1017 sshpam_thread_cleanup();
1020 * We don't call sshpam_cleanup() here because we may need the PAM
1021 * handle at a later stage, e.g. when setting up a session. It's
1022 * still on the cleanup list, so pam_end() *will* be called before
1023 * the server process terminates.
1027 KbdintDevice sshpam_device
= {
1035 KbdintDevice mm_sshpam_device
= {
1044 * This replaces auth-pam.c
1047 start_pam(struct ssh
*ssh
)
1049 Authctxt
*authctxt
= (Authctxt
*)ssh
->authctxt
;
1051 if (!options
.use_pam
)
1052 fatal("PAM: initialisation requested when UsePAM=no");
1054 if (sshpam_init(ssh
, authctxt
) == -1)
1055 fatal("PAM: initialisation failed");
1066 do_pam_account(void)
1068 debug("%s: called", __func__
);
1069 if (sshpam_account_status
!= -1)
1070 return (sshpam_account_status
);
1072 expose_authinfo(__func__
);
1074 sshpam_err
= pam_acct_mgmt(sshpam_handle
, 0);
1075 debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__
, sshpam_err
,
1076 pam_strerror(sshpam_handle
, sshpam_err
));
1078 if (sshpam_err
!= PAM_SUCCESS
&& sshpam_err
!= PAM_NEW_AUTHTOK_REQD
) {
1079 sshpam_account_status
= 0;
1080 return (sshpam_account_status
);
1083 if (sshpam_err
== PAM_NEW_AUTHTOK_REQD
)
1084 sshpam_password_change_required(1);
1086 sshpam_account_status
= 1;
1087 return (sshpam_account_status
);
1091 do_pam_setcred(int init
)
1093 sshpam_err
= pam_set_item(sshpam_handle
, PAM_CONV
,
1094 (const void *)&store_conv
);
1095 if (sshpam_err
!= PAM_SUCCESS
)
1096 fatal("PAM: failed to set PAM_CONV: %s",
1097 pam_strerror(sshpam_handle
, sshpam_err
));
1099 debug("PAM: establishing credentials");
1100 sshpam_err
= pam_setcred(sshpam_handle
, PAM_ESTABLISH_CRED
);
1102 debug("PAM: reinitializing credentials");
1103 sshpam_err
= pam_setcred(sshpam_handle
, PAM_REINITIALIZE_CRED
);
1105 if (sshpam_err
== PAM_SUCCESS
) {
1106 sshpam_cred_established
= 1;
1109 if (sshpam_authenticated
)
1110 fatal("PAM: pam_setcred(): %s",
1111 pam_strerror(sshpam_handle
, sshpam_err
));
1113 debug("PAM: pam_setcred(): %s",
1114 pam_strerror(sshpam_handle
, sshpam_err
));
1118 sshpam_tty_conv(int n
, sshpam_const
struct pam_message
**msg
,
1119 struct pam_response
**resp
, void *data
)
1121 char input
[PAM_MAX_MSG_SIZE
];
1122 struct pam_response
*reply
;
1125 debug3("PAM: %s called with %d messages", __func__
, n
);
1129 if (n
<= 0 || n
> PAM_MAX_NUM_MSG
|| !isatty(STDIN_FILENO
))
1130 return (PAM_CONV_ERR
);
1132 if ((reply
= calloc(n
, sizeof(*reply
))) == NULL
)
1133 return (PAM_CONV_ERR
);
1135 for (i
= 0; i
< n
; ++i
) {
1136 switch (PAM_MSG_MEMBER(msg
, i
, msg_style
)) {
1137 case PAM_PROMPT_ECHO_OFF
:
1139 read_passphrase(PAM_MSG_MEMBER(msg
, i
, msg
),
1141 reply
[i
].resp_retcode
= PAM_SUCCESS
;
1143 case PAM_PROMPT_ECHO_ON
:
1144 fprintf(stderr
, "%s\n", PAM_MSG_MEMBER(msg
, i
, msg
));
1145 if (fgets(input
, sizeof input
, stdin
) == NULL
)
1147 if ((reply
[i
].resp
= strdup(input
)) == NULL
)
1149 reply
[i
].resp_retcode
= PAM_SUCCESS
;
1153 fprintf(stderr
, "%s\n", PAM_MSG_MEMBER(msg
, i
, msg
));
1154 reply
[i
].resp_retcode
= PAM_SUCCESS
;
1161 return (PAM_SUCCESS
);
1164 for(i
= 0; i
< n
; i
++) {
1165 free(reply
[i
].resp
);
1168 return (PAM_CONV_ERR
);
1171 static struct pam_conv tty_conv
= { sshpam_tty_conv
, NULL
};
1174 * XXX this should be done in the authentication phase, but ssh1 doesn't
1178 do_pam_chauthtok(void)
1181 fatal("Password expired (unable to change with privsep)");
1182 sshpam_err
= pam_set_item(sshpam_handle
, PAM_CONV
,
1183 (const void *)&tty_conv
);
1184 if (sshpam_err
!= PAM_SUCCESS
)
1185 fatal("PAM: failed to set PAM_CONV: %s",
1186 pam_strerror(sshpam_handle
, sshpam_err
));
1187 debug("PAM: changing password");
1188 sshpam_err
= pam_chauthtok(sshpam_handle
, PAM_CHANGE_EXPIRED_AUTHTOK
);
1189 if (sshpam_err
!= PAM_SUCCESS
)
1190 fatal("PAM: pam_chauthtok(): %s",
1191 pam_strerror(sshpam_handle
, sshpam_err
));
1195 do_pam_session(struct ssh
*ssh
)
1197 debug3("PAM: opening session");
1199 expose_authinfo(__func__
);
1201 sshpam_err
= pam_set_item(sshpam_handle
, PAM_CONV
,
1202 (const void *)&store_conv
);
1203 if (sshpam_err
!= PAM_SUCCESS
)
1204 fatal("PAM: failed to set PAM_CONV: %s",
1205 pam_strerror(sshpam_handle
, sshpam_err
));
1206 sshpam_err
= pam_open_session(sshpam_handle
, 0);
1207 if (sshpam_err
== PAM_SUCCESS
)
1208 sshpam_session_open
= 1;
1210 sshpam_session_open
= 0;
1211 auth_restrict_session(ssh
);
1212 error("PAM: pam_open_session(): %s",
1213 pam_strerror(sshpam_handle
, sshpam_err
));
1219 is_pam_session_open(void)
1221 return sshpam_session_open
;
1225 * Set a PAM environment string. We need to do this so that the session
1226 * modules can handle things like Kerberos/GSI credentials that appear
1227 * during the ssh authentication process.
1230 do_pam_putenv(char *name
, char *value
)
1236 len
= strlen(name
) + strlen(value
) + 2;
1237 compound
= xmalloc(len
);
1239 snprintf(compound
, len
, "%s=%s", name
, value
);
1240 ret
= pam_putenv(sshpam_handle
, compound
);
1247 fetch_pam_child_environment(void)
1253 fetch_pam_environment(void)
1255 return (pam_getenvlist(sshpam_handle
));
1259 free_pam_environment(char **env
)
1266 for (envp
= env
; *envp
; envp
++)
1272 * "Blind" conversation function for password authentication. Assumes that
1273 * echo-off prompts are for the password and stores messages for later
1277 sshpam_passwd_conv(int n
, sshpam_const
struct pam_message
**msg
,
1278 struct pam_response
**resp
, void *data
)
1280 struct pam_response
*reply
;
1284 debug3("PAM: %s called with %d messages", __func__
, n
);
1288 if (n
<= 0 || n
> PAM_MAX_NUM_MSG
)
1289 return (PAM_CONV_ERR
);
1291 if ((reply
= calloc(n
, sizeof(*reply
))) == NULL
)
1292 return (PAM_CONV_ERR
);
1294 for (i
= 0; i
< n
; ++i
) {
1295 switch (PAM_MSG_MEMBER(msg
, i
, msg_style
)) {
1296 case PAM_PROMPT_ECHO_OFF
:
1297 if (sshpam_password
== NULL
)
1299 if ((reply
[i
].resp
= strdup(sshpam_password
)) == NULL
)
1301 reply
[i
].resp_retcode
= PAM_SUCCESS
;
1305 len
= strlen(PAM_MSG_MEMBER(msg
, i
, msg
));
1307 if ((r
= sshbuf_putf(loginmsg
, "%s\n",
1308 PAM_MSG_MEMBER(msg
, i
, msg
))) != 0)
1309 fatal("%s: buffer error: %s",
1310 __func__
, ssh_err(r
));
1312 if ((reply
[i
].resp
= strdup("")) == NULL
)
1314 reply
[i
].resp_retcode
= PAM_SUCCESS
;
1321 return (PAM_SUCCESS
);
1324 for(i
= 0; i
< n
; i
++) {
1325 free(reply
[i
].resp
);
1328 return (PAM_CONV_ERR
);
1331 static struct pam_conv passwd_conv
= { sshpam_passwd_conv
, NULL
};
1334 * Attempt password authentication via PAM
1337 sshpam_auth_passwd(Authctxt
*authctxt
, const char *password
)
1339 int flags
= (options
.permit_empty_passwd
== 0 ?
1340 PAM_DISALLOW_NULL_AUTHTOK
: 0);
1343 if (!options
.use_pam
|| sshpam_handle
== NULL
)
1344 fatal("PAM: %s called when PAM disabled or failed to "
1345 "initialise.", __func__
);
1347 sshpam_password
= password
;
1348 sshpam_authctxt
= authctxt
;
1351 * If the user logging in is invalid, or is root but is not permitted
1352 * by PermitRootLogin, use an invalid password to prevent leaking
1353 * information via timing (eg if the PAM config has a delay on fail).
1355 if (!authctxt
->valid
|| (authctxt
->pw
->pw_uid
== 0 &&
1356 options
.permit_root_login
!= PERMIT_YES
))
1357 sshpam_password
= fake
= fake_password(password
);
1359 sshpam_err
= pam_set_item(sshpam_handle
, PAM_CONV
,
1360 (const void *)&passwd_conv
);
1361 if (sshpam_err
!= PAM_SUCCESS
)
1362 fatal("PAM: %s: failed to set PAM_CONV: %s", __func__
,
1363 pam_strerror(sshpam_handle
, sshpam_err
));
1365 sshpam_err
= pam_authenticate(sshpam_handle
, flags
);
1366 sshpam_password
= NULL
;
1368 if (sshpam_err
== PAM_MAXTRIES
)
1369 sshpam_set_maxtries_reached(1);
1370 if (sshpam_err
== PAM_SUCCESS
&& authctxt
->valid
) {
1371 debug("PAM: password authentication accepted for %.100s",
1375 debug("PAM: password authentication failed for %.100s: %s",
1376 authctxt
->valid
? authctxt
->user
: "an illegal user",
1377 pam_strerror(sshpam_handle
, sshpam_err
));
1383 sshpam_get_maxtries_reached(void)
1385 return sshpam_maxtries_reached
;
1389 sshpam_set_maxtries_reached(int reached
)
1391 if (reached
== 0 || sshpam_maxtries_reached
)
1393 sshpam_maxtries_reached
= 1;
1394 options
.password_authentication
= 0;
1395 options
.kbd_interactive_authentication
= 0;
1397 #endif /* USE_PAM */