xref: /freebsd/crypto/openssh/auth-pam.c (revision d056fa046c6a91b90cd98165face0e42a33a5173)
1 /*-
2  * Copyright (c) 2002 Networks Associates Technology, Inc.
3  * All rights reserved.
4  *
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.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  *
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
29  * SUCH DAMAGE.
30  */
31 /*
32  * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
33  * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
34  *
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.
38  *
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.
46  */
47 
48 /* Based on $xFreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */
49 #include "includes.h"
50 RCSID("$Id: auth-pam.c,v 1.128 2006/01/29 05:46:13 dtucker Exp $");
51 RCSID("$FreeBSD$");
52 
53 #ifdef USE_PAM
54 #if defined(HAVE_SECURITY_PAM_APPL_H)
55 #include <security/pam_appl.h>
56 #elif defined (HAVE_PAM_PAM_APPL_H)
57 #include <pam/pam_appl.h>
58 #endif
59 
60 /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
61 #ifdef PAM_SUN_CODEBASE
62 # define sshpam_const		/* Solaris, HP-UX, AIX */
63 #else
64 # define sshpam_const	const	/* LinuxPAM, OpenPAM */
65 #endif
66 
67 #include "auth.h"
68 #include "auth-pam.h"
69 #include "buffer.h"
70 #include "bufaux.h"
71 #include "canohost.h"
72 #include "log.h"
73 #include "monitor_wrap.h"
74 #include "msg.h"
75 #include "packet.h"
76 #include "misc.h"
77 #include "servconf.h"
78 #include "ssh2.h"
79 #include "xmalloc.h"
80 #include "auth-options.h"
81 
82 extern ServerOptions options;
83 extern Buffer loginmsg;
84 extern int compat20;
85 extern u_int utmp_len;
86 
87 /* so we don't silently change behaviour */
88 #ifdef USE_POSIX_THREADS
89 # error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
90 #endif
91 
92 /*
93  * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
94  * and generally a bad idea.  Use at own risk and do not expect support if
95  * this breaks.
96  */
97 #ifdef UNSUPPORTED_POSIX_THREADS_HACK
98 #include <pthread.h>
99 /*
100  * Avoid namespace clash when *not* using pthreads for systems *with*
101  * pthreads, which unconditionally define pthread_t via sys/types.h
102  * (e.g. Linux)
103  */
104 typedef pthread_t sp_pthread_t;
105 #else
106 typedef pid_t sp_pthread_t;
107 #endif
108 
109 struct pam_ctxt {
110 	sp_pthread_t	 pam_thread;
111 	int		 pam_psock;
112 	int		 pam_csock;
113 	int		 pam_done;
114 };
115 
116 static void sshpam_free_ctx(void *);
117 static struct pam_ctxt *cleanup_ctxt;
118 
119 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
120 /*
121  * Simulate threads with processes.
122  */
123 
124 static int sshpam_thread_status = -1;
125 static mysig_t sshpam_oldsig;
126 
127 static void
128 sshpam_sigchld_handler(int sig)
129 {
130 	signal(SIGCHLD, SIG_DFL);
131 	if (cleanup_ctxt == NULL)
132 		return;	/* handler called after PAM cleanup, shouldn't happen */
133 	if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
134 	    <= 0) {
135 		/* PAM thread has not exitted, privsep slave must have */
136 		kill(cleanup_ctxt->pam_thread, SIGTERM);
137 		if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0)
138 		    <= 0)
139 			return; /* could not wait */
140 	}
141 	if (WIFSIGNALED(sshpam_thread_status) &&
142 	    WTERMSIG(sshpam_thread_status) == SIGTERM)
143 		return;	/* terminated by pthread_cancel */
144 	if (!WIFEXITED(sshpam_thread_status))
145 		fatal("PAM: authentication thread exited unexpectedly");
146 	if (WEXITSTATUS(sshpam_thread_status) != 0)
147 		fatal("PAM: authentication thread exited uncleanly");
148 }
149 
150 static void
151 pthread_exit(void *value __unused)
152 {
153 	_exit(0);
154 }
155 
156 static int
157 pthread_create(sp_pthread_t *thread, const void *attr __unused,
158     void *(*thread_start)(void *), void *arg)
159 {
160 	pid_t pid;
161 	struct pam_ctxt *ctx = arg;
162 
163 	sshpam_thread_status = -1;
164 	switch ((pid = fork())) {
165 	case -1:
166 		error("fork(): %s", strerror(errno));
167 		return (-1);
168 	case 0:
169 		close(ctx->pam_psock);
170 		ctx->pam_psock = -1;
171 		thread_start(arg);
172 		_exit(1);
173 	default:
174 		*thread = pid;
175 		close(ctx->pam_csock);
176 		ctx->pam_csock = -1;
177 		sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
178 		return (0);
179 	}
180 }
181 
182 static int
183 pthread_cancel(sp_pthread_t thread)
184 {
185 	signal(SIGCHLD, sshpam_oldsig);
186 	return (kill(thread, SIGTERM));
187 }
188 
189 static int
190 pthread_join(sp_pthread_t thread, void **value __unused)
191 {
192 	int status;
193 
194 	if (sshpam_thread_status != -1)
195 		return (sshpam_thread_status);
196 	signal(SIGCHLD, sshpam_oldsig);
197 	waitpid(thread, &status, 0);
198 	return (status);
199 }
200 #endif
201 
202 
203 static pam_handle_t *sshpam_handle = NULL;
204 static int sshpam_err = 0;
205 static int sshpam_authenticated = 0;
206 static int sshpam_session_open = 0;
207 static int sshpam_cred_established = 0;
208 static int sshpam_account_status = -1;
209 static char **sshpam_env = NULL;
210 static Authctxt *sshpam_authctxt = NULL;
211 static const char *sshpam_password = NULL;
212 static char badpw[] = "\b\n\r\177INCORRECT";
213 
214 /* Some PAM implementations don't implement this */
215 #ifndef HAVE_PAM_GETENVLIST
216 static char **
217 pam_getenvlist(pam_handle_t *pamh)
218 {
219 	/*
220 	 * XXX - If necessary, we can still support envrionment passing
221 	 * for platforms without pam_getenvlist by searching for known
222 	 * env vars (e.g. KRB5CCNAME) from the PAM environment.
223 	 */
224 	 return NULL;
225 }
226 #endif
227 
228 /*
229  * Some platforms, notably Solaris, do not enforce password complexity
230  * rules during pam_chauthtok() if the real uid of the calling process
231  * is 0, on the assumption that it's being called by "passwd" run by root.
232  * This wraps pam_chauthtok and sets/restore the real uid so PAM will do
233  * the right thing.
234  */
235 #ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
236 static int
237 sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
238 {
239 	int result;
240 
241 	if (sshpam_authctxt == NULL)
242 		fatal("PAM: sshpam_authctxt not initialized");
243 	if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
244 		fatal("%s: setreuid failed: %s", __func__, strerror(errno));
245 	result = pam_chauthtok(pamh, flags);
246 	if (setreuid(0, -1) == -1)
247 		fatal("%s: setreuid failed: %s", __func__, strerror(errno));
248 	return result;
249 }
250 # define pam_chauthtok(a,b)	(sshpam_chauthtok_ruid((a), (b)))
251 #endif
252 
253 void
254 sshpam_password_change_required(int reqd)
255 {
256 	debug3("%s %d", __func__, reqd);
257 	if (sshpam_authctxt == NULL)
258 		fatal("%s: PAM authctxt not initialized", __func__);
259 	sshpam_authctxt->force_pwchange = reqd;
260 	if (reqd) {
261 		no_port_forwarding_flag |= 2;
262 		no_agent_forwarding_flag |= 2;
263 		no_x11_forwarding_flag |= 2;
264 	} else {
265 		no_port_forwarding_flag &= ~2;
266 		no_agent_forwarding_flag &= ~2;
267 		no_x11_forwarding_flag &= ~2;
268 	}
269 }
270 
271 /* Import regular and PAM environment from subprocess */
272 static void
273 import_environments(Buffer *b)
274 {
275 	char *env;
276 	u_int i, num_env;
277 	int err;
278 
279 	debug3("PAM: %s entering", __func__);
280 
281 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
282 	/* Import variables set by do_pam_account */
283 	sshpam_account_status = buffer_get_int(b);
284 	sshpam_password_change_required(buffer_get_int(b));
285 
286 	/* Import environment from subprocess */
287 	num_env = buffer_get_int(b);
288 	sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env));
289 	debug3("PAM: num env strings %d", num_env);
290 	for(i = 0; i < num_env; i++)
291 		sshpam_env[i] = buffer_get_string(b, NULL);
292 
293 	sshpam_env[num_env] = NULL;
294 
295 	/* Import PAM environment from subprocess */
296 	num_env = buffer_get_int(b);
297 	debug("PAM: num PAM env strings %d", num_env);
298 	for(i = 0; i < num_env; i++) {
299 		env = buffer_get_string(b, NULL);
300 
301 #ifdef HAVE_PAM_PUTENV
302 		/* Errors are not fatal here */
303 		if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
304 			error("PAM: pam_putenv: %s",
305 			    pam_strerror(sshpam_handle, sshpam_err));
306 		}
307 #endif
308 	}
309 #endif
310 }
311 
312 /*
313  * Conversation function for authentication thread.
314  */
315 static int
316 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
317     struct pam_response **resp, void *data)
318 {
319 	Buffer buffer;
320 	struct pam_ctxt *ctxt;
321 	struct pam_response *reply;
322 	int i;
323 
324 	debug3("PAM: %s entering, %d messages", __func__, n);
325 	*resp = NULL;
326 
327 	if (data == NULL) {
328 		error("PAM: conversation function passed a null context");
329 		return (PAM_CONV_ERR);
330 	}
331 	ctxt = data;
332 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
333 		return (PAM_CONV_ERR);
334 
335 	if ((reply = malloc(n * sizeof(*reply))) == NULL)
336 		return (PAM_CONV_ERR);
337 	memset(reply, 0, n * sizeof(*reply));
338 
339 	buffer_init(&buffer);
340 	for (i = 0; i < n; ++i) {
341 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
342 		case PAM_PROMPT_ECHO_OFF:
343 			buffer_put_cstring(&buffer,
344 			    PAM_MSG_MEMBER(msg, i, msg));
345 			if (ssh_msg_send(ctxt->pam_csock,
346 			    PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
347 				goto fail;
348 			if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
349 				goto fail;
350 			if (buffer_get_char(&buffer) != PAM_AUTHTOK)
351 				goto fail;
352 			reply[i].resp = buffer_get_string(&buffer, NULL);
353 			break;
354 		case PAM_PROMPT_ECHO_ON:
355 			buffer_put_cstring(&buffer,
356 			    PAM_MSG_MEMBER(msg, i, msg));
357 			if (ssh_msg_send(ctxt->pam_csock,
358 			    PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
359 				goto fail;
360 			if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
361 				goto fail;
362 			if (buffer_get_char(&buffer) != PAM_AUTHTOK)
363 				goto fail;
364 			reply[i].resp = buffer_get_string(&buffer, NULL);
365 			break;
366 		case PAM_ERROR_MSG:
367 			buffer_put_cstring(&buffer,
368 			    PAM_MSG_MEMBER(msg, i, msg));
369 			if (ssh_msg_send(ctxt->pam_csock,
370 			    PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
371 				goto fail;
372 			break;
373 		case PAM_TEXT_INFO:
374 			buffer_put_cstring(&buffer,
375 			    PAM_MSG_MEMBER(msg, i, msg));
376 			if (ssh_msg_send(ctxt->pam_csock,
377 			    PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
378 				goto fail;
379 			break;
380 		default:
381 			goto fail;
382 		}
383 		buffer_clear(&buffer);
384 	}
385 	buffer_free(&buffer);
386 	*resp = reply;
387 	return (PAM_SUCCESS);
388 
389  fail:
390 	for(i = 0; i < n; i++) {
391 		if (reply[i].resp != NULL)
392 			xfree(reply[i].resp);
393 	}
394 	xfree(reply);
395 	buffer_free(&buffer);
396 	return (PAM_CONV_ERR);
397 }
398 
399 /*
400  * Authentication thread.
401  */
402 static void *
403 sshpam_thread(void *ctxtp)
404 {
405 	struct pam_ctxt *ctxt = ctxtp;
406 	Buffer buffer;
407 	struct pam_conv sshpam_conv;
408 	int flags = (options.permit_empty_passwd == 0 ?
409 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
410 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
411 	extern char **environ;
412 	char **env_from_pam;
413 	u_int i;
414 	const char *pam_user;
415 	const char **ptr_pam_user = &pam_user;
416 
417 	pam_get_item(sshpam_handle, PAM_USER,
418 	    (sshpam_const void **)ptr_pam_user);
419 	environ[0] = NULL;
420 
421 	if (sshpam_authctxt != NULL) {
422 		setproctitle("%s [pam]",
423 		    sshpam_authctxt->valid ? pam_user : "unknown");
424 	}
425 #endif
426 
427 	sshpam_conv.conv = sshpam_thread_conv;
428 	sshpam_conv.appdata_ptr = ctxt;
429 
430 	if (sshpam_authctxt == NULL)
431 		fatal("%s: PAM authctxt not initialized", __func__);
432 
433 	buffer_init(&buffer);
434 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
435 	    (const void *)&sshpam_conv);
436 	if (sshpam_err != PAM_SUCCESS)
437 		goto auth_fail;
438 	sshpam_err = pam_authenticate(sshpam_handle, flags);
439 	if (sshpam_err != PAM_SUCCESS)
440 		goto auth_fail;
441 
442 	if (compat20) {
443 		if (!do_pam_account())
444 			goto auth_fail;
445 		if (sshpam_authctxt->force_pwchange) {
446 			sshpam_err = pam_chauthtok(sshpam_handle,
447 			    PAM_CHANGE_EXPIRED_AUTHTOK);
448 			if (sshpam_err != PAM_SUCCESS)
449 				goto auth_fail;
450 			sshpam_password_change_required(0);
451 		}
452 	}
453 
454 	buffer_put_cstring(&buffer, "OK");
455 
456 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
457 	/* Export variables set by do_pam_account */
458 	buffer_put_int(&buffer, sshpam_account_status);
459 	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
460 
461 	/* Export any environment strings set in child */
462 	for(i = 0; environ[i] != NULL; i++)
463 		; /* Count */
464 	buffer_put_int(&buffer, i);
465 	for(i = 0; environ[i] != NULL; i++)
466 		buffer_put_cstring(&buffer, environ[i]);
467 
468 	/* Export any environment strings set by PAM in child */
469 	env_from_pam = pam_getenvlist(sshpam_handle);
470 	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
471 		; /* Count */
472 	buffer_put_int(&buffer, i);
473 	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
474 		buffer_put_cstring(&buffer, env_from_pam[i]);
475 #endif /* UNSUPPORTED_POSIX_THREADS_HACK */
476 
477 	/* XXX - can't do much about an error here */
478 	ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
479 	buffer_free(&buffer);
480 	pthread_exit(NULL);
481 
482  auth_fail:
483 	buffer_put_cstring(&buffer,
484 	    pam_strerror(sshpam_handle, sshpam_err));
485 	/* XXX - can't do much about an error here */
486 	ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
487 	buffer_free(&buffer);
488 	pthread_exit(NULL);
489 
490 	return (NULL); /* Avoid warning for non-pthread case */
491 }
492 
493 void
494 sshpam_thread_cleanup(void)
495 {
496 	struct pam_ctxt *ctxt = cleanup_ctxt;
497 
498 	debug3("PAM: %s entering", __func__);
499 	if (ctxt != NULL && ctxt->pam_thread != 0) {
500 		pthread_cancel(ctxt->pam_thread);
501 		pthread_join(ctxt->pam_thread, NULL);
502 		close(ctxt->pam_psock);
503 		close(ctxt->pam_csock);
504 		memset(ctxt, 0, sizeof(*ctxt));
505 		cleanup_ctxt = NULL;
506 	}
507 }
508 
509 static int
510 sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
511     struct pam_response **resp, void *data)
512 {
513 	debug3("PAM: %s entering, %d messages", __func__, n);
514 	return (PAM_CONV_ERR);
515 }
516 
517 static struct pam_conv null_conv = { sshpam_null_conv, NULL };
518 
519 static int
520 sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
521     struct pam_response **resp, void *data)
522 {
523 	struct pam_response *reply;
524 	int i;
525 	size_t len;
526 
527 	debug3("PAM: %s called with %d messages", __func__, n);
528 	*resp = NULL;
529 
530 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
531 		return (PAM_CONV_ERR);
532 
533 	if ((reply = malloc(n * sizeof(*reply))) == NULL)
534 		return (PAM_CONV_ERR);
535 	memset(reply, 0, n * sizeof(*reply));
536 
537 	for (i = 0; i < n; ++i) {
538 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
539 		case PAM_ERROR_MSG:
540 		case PAM_TEXT_INFO:
541 			len = strlen(PAM_MSG_MEMBER(msg, i, msg));
542 			buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
543 			buffer_append(&loginmsg, "\n", 1 );
544 			reply[i].resp_retcode = PAM_SUCCESS;
545 			break;
546 		default:
547 			goto fail;
548 		}
549 	}
550 	*resp = reply;
551 	return (PAM_SUCCESS);
552 
553  fail:
554 	for(i = 0; i < n; i++) {
555 		if (reply[i].resp != NULL)
556 			xfree(reply[i].resp);
557 	}
558 	xfree(reply);
559 	return (PAM_CONV_ERR);
560 }
561 
562 static struct pam_conv store_conv = { sshpam_store_conv, NULL };
563 
564 void
565 sshpam_cleanup(void)
566 {
567 	debug("PAM: cleanup");
568 	if (sshpam_handle == NULL)
569 		return;
570 	pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
571 	if (sshpam_cred_established) {
572 		pam_setcred(sshpam_handle, PAM_DELETE_CRED);
573 		sshpam_cred_established = 0;
574 	}
575 	if (sshpam_session_open) {
576 		pam_close_session(sshpam_handle, PAM_SILENT);
577 		sshpam_session_open = 0;
578 	}
579 	sshpam_authenticated = 0;
580 	pam_end(sshpam_handle, sshpam_err);
581 	sshpam_handle = NULL;
582 }
583 
584 static int
585 sshpam_init(Authctxt *authctxt)
586 {
587 	extern char *__progname;
588 	const char *pam_rhost, *pam_user, *user = authctxt->user;
589 	const char **ptr_pam_user = &pam_user;
590 
591 	if (sshpam_handle != NULL) {
592 		/* We already have a PAM context; check if the user matches */
593 		sshpam_err = pam_get_item(sshpam_handle,
594 		    PAM_USER, (sshpam_const void **)ptr_pam_user);
595 		if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
596 			return (0);
597 		pam_end(sshpam_handle, sshpam_err);
598 		sshpam_handle = NULL;
599 	}
600 	debug("PAM: initializing for \"%s\"", user);
601 	sshpam_err =
602 	    pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
603 	sshpam_authctxt = authctxt;
604 
605 	if (sshpam_err != PAM_SUCCESS) {
606 		pam_end(sshpam_handle, sshpam_err);
607 		sshpam_handle = NULL;
608 		return (-1);
609 	}
610 	pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns);
611 	debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
612 	sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
613 	if (sshpam_err != PAM_SUCCESS) {
614 		pam_end(sshpam_handle, sshpam_err);
615 		sshpam_handle = NULL;
616 		return (-1);
617 	}
618 #ifdef PAM_TTY_KLUDGE
619 	/*
620 	 * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
621 	 * sshd doesn't set the tty until too late in the auth process and
622 	 * may not even set one (for tty-less connections)
623 	 */
624 	debug("PAM: setting PAM_TTY to \"ssh\"");
625 	sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
626 	if (sshpam_err != PAM_SUCCESS) {
627 		pam_end(sshpam_handle, sshpam_err);
628 		sshpam_handle = NULL;
629 		return (-1);
630 	}
631 #endif
632 	return (0);
633 }
634 
635 static void *
636 sshpam_init_ctx(Authctxt *authctxt)
637 {
638 	struct pam_ctxt *ctxt;
639 	int socks[2];
640 
641 	debug3("PAM: %s entering", __func__);
642 	/* Refuse to start if we don't have PAM enabled */
643 	if (!options.use_pam)
644 		return NULL;
645 
646 	/* Initialize PAM */
647 	if (sshpam_init(authctxt) == -1) {
648 		error("PAM: initialization failed");
649 		return (NULL);
650 	}
651 
652 	ctxt = xmalloc(sizeof *ctxt);
653 	memset(ctxt, 0, sizeof(*ctxt));
654 
655 	/* Start the authentication thread */
656 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
657 		error("PAM: failed create sockets: %s", strerror(errno));
658 		xfree(ctxt);
659 		return (NULL);
660 	}
661 	ctxt->pam_psock = socks[0];
662 	ctxt->pam_csock = socks[1];
663 	if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
664 		error("PAM: failed to start authentication thread: %s",
665 		    strerror(errno));
666 		close(socks[0]);
667 		close(socks[1]);
668 		xfree(ctxt);
669 		return (NULL);
670 	}
671 	cleanup_ctxt = ctxt;
672 	return (ctxt);
673 }
674 
675 static int
676 sshpam_query(void *ctx, char **name, char **info,
677     u_int *num, char ***prompts, u_int **echo_on)
678 {
679 	Buffer buffer;
680 	struct pam_ctxt *ctxt = ctx;
681 	size_t plen;
682 	u_char type;
683 	char *msg;
684 	size_t len, mlen;
685 
686 	debug3("PAM: %s entering", __func__);
687 	buffer_init(&buffer);
688 	*name = xstrdup("");
689 	*info = xstrdup("");
690 	*prompts = xmalloc(sizeof(char *));
691 	**prompts = NULL;
692 	plen = 0;
693 	*echo_on = xmalloc(sizeof(u_int));
694 	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
695 		type = buffer_get_char(&buffer);
696 		msg = buffer_get_string(&buffer, NULL);
697 		mlen = strlen(msg);
698 		switch (type) {
699 		case PAM_PROMPT_ECHO_ON:
700 		case PAM_PROMPT_ECHO_OFF:
701 			*num = 1;
702 			len = plen + mlen + 1;
703 			**prompts = xrealloc(**prompts, len);
704 			strlcpy(**prompts + plen, msg, len - plen);
705 			plen += mlen;
706 			**echo_on = (type == PAM_PROMPT_ECHO_ON);
707 			xfree(msg);
708 			return (0);
709 		case PAM_ERROR_MSG:
710 		case PAM_TEXT_INFO:
711 			/* accumulate messages */
712 			len = plen + mlen + 2;
713 			**prompts = xrealloc(**prompts, len);
714 			strlcpy(**prompts + plen, msg, len - plen);
715 			plen += mlen;
716 			strlcat(**prompts + plen, "\n", len - plen);
717 			plen++;
718 			xfree(msg);
719 			break;
720 		case PAM_AUTH_ERR:
721 			debug3("PAM: PAM_AUTH_ERR");
722 			if (**prompts != NULL && strlen(**prompts) != 0) {
723 				*info = **prompts;
724 				**prompts = NULL;
725 				*num = 0;
726 				**echo_on = 0;
727 				ctxt->pam_done = -1;
728 				return 0;
729 			}
730 			/* FALLTHROUGH */
731 		case PAM_SUCCESS:
732 			if (**prompts != NULL) {
733 				/* drain any accumulated messages */
734 				debug("PAM: %s", **prompts);
735 				buffer_append(&loginmsg, **prompts,
736 				    strlen(**prompts));
737 				xfree(**prompts);
738 				**prompts = NULL;
739 			}
740 			if (type == PAM_SUCCESS) {
741 				if (!sshpam_authctxt->valid ||
742 				    (sshpam_authctxt->pw->pw_uid == 0 &&
743 				    options.permit_root_login != PERMIT_YES))
744 					fatal("Internal error: PAM auth "
745 					    "succeeded when it should have "
746 					    "failed");
747 				import_environments(&buffer);
748 				*num = 0;
749 				**echo_on = 0;
750 				ctxt->pam_done = 1;
751 				xfree(msg);
752 				return (0);
753 			}
754 			error("PAM: %s for %s%.100s from %.100s", msg,
755 			    sshpam_authctxt->valid ? "" : "illegal user ",
756 			    sshpam_authctxt->user,
757 			    get_remote_name_or_ip(utmp_len, options.use_dns));
758 			/* FALLTHROUGH */
759 		default:
760 			*num = 0;
761 			**echo_on = 0;
762 			xfree(msg);
763 			ctxt->pam_done = -1;
764 			return (-1);
765 		}
766 	}
767 	return (-1);
768 }
769 
770 /* XXX - see also comment in auth-chall.c:verify_response */
771 static int
772 sshpam_respond(void *ctx, u_int num, char **resp)
773 {
774 	Buffer buffer;
775 	struct pam_ctxt *ctxt = ctx;
776 
777 	debug2("PAM: %s entering, %u responses", __func__, num);
778 	switch (ctxt->pam_done) {
779 	case 1:
780 		sshpam_authenticated = 1;
781 		return (0);
782 	case 0:
783 		break;
784 	default:
785 		return (-1);
786 	}
787 	if (num != 1) {
788 		error("PAM: expected one response, got %u", num);
789 		return (-1);
790 	}
791 	buffer_init(&buffer);
792 	if (sshpam_authctxt->valid &&
793 	    (sshpam_authctxt->pw->pw_uid != 0 ||
794 	    options.permit_root_login == PERMIT_YES))
795 		buffer_put_cstring(&buffer, *resp);
796 	else
797 		buffer_put_cstring(&buffer, badpw);
798 	if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
799 		buffer_free(&buffer);
800 		return (-1);
801 	}
802 	buffer_free(&buffer);
803 	return (1);
804 }
805 
806 static void
807 sshpam_free_ctx(void *ctxtp)
808 {
809 	struct pam_ctxt *ctxt = ctxtp;
810 
811 	debug3("PAM: %s entering", __func__);
812 	sshpam_thread_cleanup();
813 	xfree(ctxt);
814 	/*
815 	 * We don't call sshpam_cleanup() here because we may need the PAM
816 	 * handle at a later stage, e.g. when setting up a session.  It's
817 	 * still on the cleanup list, so pam_end() *will* be called before
818 	 * the server process terminates.
819 	 */
820 }
821 
822 KbdintDevice sshpam_device = {
823 	"pam",
824 	sshpam_init_ctx,
825 	sshpam_query,
826 	sshpam_respond,
827 	sshpam_free_ctx
828 };
829 
830 KbdintDevice mm_sshpam_device = {
831 	"pam",
832 	mm_sshpam_init_ctx,
833 	mm_sshpam_query,
834 	mm_sshpam_respond,
835 	mm_sshpam_free_ctx
836 };
837 
838 /*
839  * This replaces auth-pam.c
840  */
841 void
842 start_pam(Authctxt *authctxt)
843 {
844 	if (!options.use_pam)
845 		fatal("PAM: initialisation requested when UsePAM=no");
846 
847 	if (sshpam_init(authctxt) == -1)
848 		fatal("PAM: initialisation failed");
849 }
850 
851 void
852 finish_pam(void)
853 {
854 	sshpam_cleanup();
855 }
856 
857 u_int
858 do_pam_account(void)
859 {
860 	debug("%s: called", __func__);
861 	if (sshpam_account_status != -1)
862 		return (sshpam_account_status);
863 
864 	sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
865 	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
866 	    pam_strerror(sshpam_handle, sshpam_err));
867 
868 	if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
869 		sshpam_account_status = 0;
870 		return (sshpam_account_status);
871 	}
872 
873 	if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
874 		sshpam_password_change_required(1);
875 
876 	sshpam_account_status = 1;
877 	return (sshpam_account_status);
878 }
879 
880 void
881 do_pam_set_tty(const char *tty)
882 {
883 	if (tty != NULL) {
884 		debug("PAM: setting PAM_TTY to \"%s\"", tty);
885 		sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
886 		if (sshpam_err != PAM_SUCCESS)
887 			fatal("PAM: failed to set PAM_TTY: %s",
888 			    pam_strerror(sshpam_handle, sshpam_err));
889 	}
890 }
891 
892 void
893 do_pam_setcred(int init)
894 {
895 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
896 	    (const void *)&store_conv);
897 	if (sshpam_err != PAM_SUCCESS)
898 		fatal("PAM: failed to set PAM_CONV: %s",
899 		    pam_strerror(sshpam_handle, sshpam_err));
900 	if (init) {
901 		debug("PAM: establishing credentials");
902 		sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
903 	} else {
904 		debug("PAM: reinitializing credentials");
905 		sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
906 	}
907 	if (sshpam_err == PAM_SUCCESS) {
908 		sshpam_cred_established = 1;
909 		return;
910 	}
911 	if (sshpam_authenticated)
912 		fatal("PAM: pam_setcred(): %s",
913 		    pam_strerror(sshpam_handle, sshpam_err));
914 	else
915 		debug("PAM: pam_setcred(): %s",
916 		    pam_strerror(sshpam_handle, sshpam_err));
917 }
918 
919 static int
920 sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
921     struct pam_response **resp, void *data)
922 {
923 	char input[PAM_MAX_MSG_SIZE];
924 	struct pam_response *reply;
925 	int i;
926 
927 	debug3("PAM: %s called with %d messages", __func__, n);
928 
929 	*resp = NULL;
930 
931 	if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
932 		return (PAM_CONV_ERR);
933 
934 	if ((reply = malloc(n * sizeof(*reply))) == NULL)
935 		return (PAM_CONV_ERR);
936 	memset(reply, 0, n * sizeof(*reply));
937 
938 	for (i = 0; i < n; ++i) {
939 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
940 		case PAM_PROMPT_ECHO_OFF:
941 			reply[i].resp =
942 			    read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
943 			    RP_ALLOW_STDIN);
944 			reply[i].resp_retcode = PAM_SUCCESS;
945 			break;
946 		case PAM_PROMPT_ECHO_ON:
947 			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
948 			fgets(input, sizeof input, stdin);
949 			if ((reply[i].resp = strdup(input)) == NULL)
950 				goto fail;
951 			reply[i].resp_retcode = PAM_SUCCESS;
952 			break;
953 		case PAM_ERROR_MSG:
954 		case PAM_TEXT_INFO:
955 			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
956 			reply[i].resp_retcode = PAM_SUCCESS;
957 			break;
958 		default:
959 			goto fail;
960 		}
961 	}
962 	*resp = reply;
963 	return (PAM_SUCCESS);
964 
965  fail:
966 	for(i = 0; i < n; i++) {
967 		if (reply[i].resp != NULL)
968 			xfree(reply[i].resp);
969 	}
970 	xfree(reply);
971 	return (PAM_CONV_ERR);
972 }
973 
974 static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
975 
976 /*
977  * XXX this should be done in the authentication phase, but ssh1 doesn't
978  * support that
979  */
980 void
981 do_pam_chauthtok(void)
982 {
983 	if (use_privsep)
984 		fatal("Password expired (unable to change with privsep)");
985 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
986 	    (const void *)&tty_conv);
987 	if (sshpam_err != PAM_SUCCESS)
988 		fatal("PAM: failed to set PAM_CONV: %s",
989 		    pam_strerror(sshpam_handle, sshpam_err));
990 	debug("PAM: changing password");
991 	sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
992 	if (sshpam_err != PAM_SUCCESS)
993 		fatal("PAM: pam_chauthtok(): %s",
994 		    pam_strerror(sshpam_handle, sshpam_err));
995 }
996 
997 void
998 do_pam_session(void)
999 {
1000 	debug3("PAM: opening session");
1001 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1002 	    (const void *)&store_conv);
1003 	if (sshpam_err != PAM_SUCCESS)
1004 		fatal("PAM: failed to set PAM_CONV: %s",
1005 		    pam_strerror(sshpam_handle, sshpam_err));
1006 	sshpam_err = pam_open_session(sshpam_handle, 0);
1007 	if (sshpam_err == PAM_SUCCESS)
1008 		sshpam_session_open = 1;
1009 	else {
1010 		sshpam_session_open = 0;
1011 		disable_forwarding();
1012 		error("PAM: pam_open_session(): %s",
1013 		    pam_strerror(sshpam_handle, sshpam_err));
1014 	}
1015 
1016 }
1017 
1018 int
1019 is_pam_session_open(void)
1020 {
1021 	return sshpam_session_open;
1022 }
1023 
1024 /*
1025  * Set a PAM environment string. We need to do this so that the session
1026  * modules can handle things like Kerberos/GSI credentials that appear
1027  * during the ssh authentication process.
1028  */
1029 int
1030 do_pam_putenv(char *name, char *value)
1031 {
1032 	int ret = 1;
1033 #ifdef HAVE_PAM_PUTENV
1034 	char *compound;
1035 	size_t len;
1036 
1037 	len = strlen(name) + strlen(value) + 2;
1038 	compound = xmalloc(len);
1039 
1040 	snprintf(compound, len, "%s=%s", name, value);
1041 	ret = pam_putenv(sshpam_handle, compound);
1042 	xfree(compound);
1043 #endif
1044 
1045 	return (ret);
1046 }
1047 
1048 char **
1049 fetch_pam_child_environment(void)
1050 {
1051 	return sshpam_env;
1052 }
1053 
1054 char **
1055 fetch_pam_environment(void)
1056 {
1057 	return (pam_getenvlist(sshpam_handle));
1058 }
1059 
1060 void
1061 free_pam_environment(char **env)
1062 {
1063 	char **envp;
1064 
1065 	if (env == NULL)
1066 		return;
1067 
1068 	for (envp = env; *envp; envp++)
1069 		xfree(*envp);
1070 	xfree(env);
1071 }
1072 
1073 /*
1074  * "Blind" conversation function for password authentication.  Assumes that
1075  * echo-off prompts are for the password and stores messages for later
1076  * display.
1077  */
1078 static int
1079 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
1080     struct pam_response **resp, void *data)
1081 {
1082 	struct pam_response *reply;
1083 	int i;
1084 	size_t len;
1085 
1086 	debug3("PAM: %s called with %d messages", __func__, n);
1087 
1088 	*resp = NULL;
1089 
1090 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
1091 		return (PAM_CONV_ERR);
1092 
1093 	if ((reply = malloc(n * sizeof(*reply))) == NULL)
1094 		return (PAM_CONV_ERR);
1095 	memset(reply, 0, n * sizeof(*reply));
1096 
1097 	for (i = 0; i < n; ++i) {
1098 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1099 		case PAM_PROMPT_ECHO_OFF:
1100 			if (sshpam_password == NULL)
1101 				goto fail;
1102 			if ((reply[i].resp = strdup(sshpam_password)) == NULL)
1103 				goto fail;
1104 			reply[i].resp_retcode = PAM_SUCCESS;
1105 			break;
1106 		case PAM_ERROR_MSG:
1107 		case PAM_TEXT_INFO:
1108 			len = strlen(PAM_MSG_MEMBER(msg, i, msg));
1109 			if (len > 0) {
1110 				buffer_append(&loginmsg,
1111 				    PAM_MSG_MEMBER(msg, i, msg), len);
1112 				buffer_append(&loginmsg, "\n", 1);
1113 			}
1114 			if ((reply[i].resp = strdup("")) == NULL)
1115 				goto fail;
1116 			reply[i].resp_retcode = PAM_SUCCESS;
1117 			break;
1118 		default:
1119 			goto fail;
1120 		}
1121 	}
1122 	*resp = reply;
1123 	return (PAM_SUCCESS);
1124 
1125  fail:
1126 	for(i = 0; i < n; i++) {
1127 		if (reply[i].resp != NULL)
1128 			xfree(reply[i].resp);
1129 	}
1130 	xfree(reply);
1131 	return (PAM_CONV_ERR);
1132 }
1133 
1134 static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
1135 
1136 /*
1137  * Attempt password authentication via PAM
1138  */
1139 int
1140 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
1141 {
1142 	int flags = (options.permit_empty_passwd == 0 ?
1143 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
1144 
1145 	if (!options.use_pam || sshpam_handle == NULL)
1146 		fatal("PAM: %s called when PAM disabled or failed to "
1147 		    "initialise.", __func__);
1148 
1149 	sshpam_password = password;
1150 	sshpam_authctxt = authctxt;
1151 
1152 	/*
1153 	 * If the user logging in is invalid, or is root but is not permitted
1154 	 * by PermitRootLogin, use an invalid password to prevent leaking
1155 	 * information via timing (eg if the PAM config has a delay on fail).
1156 	 */
1157 	if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
1158 	    options.permit_root_login != PERMIT_YES))
1159 		sshpam_password = badpw;
1160 
1161 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1162 	    (const void *)&passwd_conv);
1163 	if (sshpam_err != PAM_SUCCESS)
1164 		fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
1165 		    pam_strerror(sshpam_handle, sshpam_err));
1166 
1167 	sshpam_err = pam_authenticate(sshpam_handle, flags);
1168 	sshpam_password = NULL;
1169 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
1170 		debug("PAM: password authentication accepted for %.100s",
1171 		    authctxt->user);
1172 		return 1;
1173 	} else {
1174 		debug("PAM: password authentication failed for %.100s: %s",
1175 		    authctxt->valid ? authctxt->user : "an illegal user",
1176 		    pam_strerror(sshpam_handle, sshpam_err));
1177 		return 0;
1178 	}
1179 }
1180 #endif /* USE_PAM */
1181