xref: /freebsd/crypto/openssh/auth-pam.c (revision 87569f75a91f298c52a71823c04d41cf53c88889)
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.126 2005/07/17 07:18:50 djm 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_SUCCESS:
721 		case PAM_AUTH_ERR:
722 			if (**prompts != NULL) {
723 				/* drain any accumulated messages */
724 				debug("PAM: %s", **prompts);
725 				buffer_append(&loginmsg, **prompts,
726 				    strlen(**prompts));
727 				xfree(**prompts);
728 				**prompts = NULL;
729 			}
730 			if (type == PAM_SUCCESS) {
731 				if (!sshpam_authctxt->valid ||
732 				    (sshpam_authctxt->pw->pw_uid == 0 &&
733 				    options.permit_root_login != PERMIT_YES))
734 					fatal("Internal error: PAM auth "
735 					    "succeeded when it should have "
736 					    "failed");
737 				import_environments(&buffer);
738 				*num = 0;
739 				**echo_on = 0;
740 				ctxt->pam_done = 1;
741 				xfree(msg);
742 				return (0);
743 			}
744 			error("PAM: %s for %s%.100s from %.100s", msg,
745 			    sshpam_authctxt->valid ? "" : "illegal user ",
746 			    sshpam_authctxt->user,
747 			    get_remote_name_or_ip(utmp_len, options.use_dns));
748 			/* FALLTHROUGH */
749 		default:
750 			*num = 0;
751 			**echo_on = 0;
752 			xfree(msg);
753 			ctxt->pam_done = -1;
754 			return (-1);
755 		}
756 	}
757 	return (-1);
758 }
759 
760 /* XXX - see also comment in auth-chall.c:verify_response */
761 static int
762 sshpam_respond(void *ctx, u_int num, char **resp)
763 {
764 	Buffer buffer;
765 	struct pam_ctxt *ctxt = ctx;
766 
767 	debug2("PAM: %s entering, %d responses", __func__, num);
768 	switch (ctxt->pam_done) {
769 	case 1:
770 		sshpam_authenticated = 1;
771 		return (0);
772 	case 0:
773 		break;
774 	default:
775 		return (-1);
776 	}
777 	if (num != 1) {
778 		error("PAM: expected one response, got %u", num);
779 		return (-1);
780 	}
781 	buffer_init(&buffer);
782 	if (sshpam_authctxt->valid &&
783 	    (sshpam_authctxt->pw->pw_uid != 0 ||
784 	    options.permit_root_login == PERMIT_YES))
785 		buffer_put_cstring(&buffer, *resp);
786 	else
787 		buffer_put_cstring(&buffer, badpw);
788 	if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
789 		buffer_free(&buffer);
790 		return (-1);
791 	}
792 	buffer_free(&buffer);
793 	return (1);
794 }
795 
796 static void
797 sshpam_free_ctx(void *ctxtp)
798 {
799 	struct pam_ctxt *ctxt = ctxtp;
800 
801 	debug3("PAM: %s entering", __func__);
802 	sshpam_thread_cleanup();
803 	xfree(ctxt);
804 	/*
805 	 * We don't call sshpam_cleanup() here because we may need the PAM
806 	 * handle at a later stage, e.g. when setting up a session.  It's
807 	 * still on the cleanup list, so pam_end() *will* be called before
808 	 * the server process terminates.
809 	 */
810 }
811 
812 KbdintDevice sshpam_device = {
813 	"pam",
814 	sshpam_init_ctx,
815 	sshpam_query,
816 	sshpam_respond,
817 	sshpam_free_ctx
818 };
819 
820 KbdintDevice mm_sshpam_device = {
821 	"pam",
822 	mm_sshpam_init_ctx,
823 	mm_sshpam_query,
824 	mm_sshpam_respond,
825 	mm_sshpam_free_ctx
826 };
827 
828 /*
829  * This replaces auth-pam.c
830  */
831 void
832 start_pam(Authctxt *authctxt)
833 {
834 	if (!options.use_pam)
835 		fatal("PAM: initialisation requested when UsePAM=no");
836 
837 	if (sshpam_init(authctxt) == -1)
838 		fatal("PAM: initialisation failed");
839 }
840 
841 void
842 finish_pam(void)
843 {
844 	sshpam_cleanup();
845 }
846 
847 u_int
848 do_pam_account(void)
849 {
850 	debug("%s: called", __func__);
851 	if (sshpam_account_status != -1)
852 		return (sshpam_account_status);
853 
854 	sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
855 	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
856 	    pam_strerror(sshpam_handle, sshpam_err));
857 
858 	if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
859 		sshpam_account_status = 0;
860 		return (sshpam_account_status);
861 	}
862 
863 	if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
864 		sshpam_password_change_required(1);
865 
866 	sshpam_account_status = 1;
867 	return (sshpam_account_status);
868 }
869 
870 void
871 do_pam_set_tty(const char *tty)
872 {
873 	if (tty != NULL) {
874 		debug("PAM: setting PAM_TTY to \"%s\"", tty);
875 		sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
876 		if (sshpam_err != PAM_SUCCESS)
877 			fatal("PAM: failed to set PAM_TTY: %s",
878 			    pam_strerror(sshpam_handle, sshpam_err));
879 	}
880 }
881 
882 void
883 do_pam_setcred(int init)
884 {
885 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
886 	    (const void *)&store_conv);
887 	if (sshpam_err != PAM_SUCCESS)
888 		fatal("PAM: failed to set PAM_CONV: %s",
889 		    pam_strerror(sshpam_handle, sshpam_err));
890 	if (init) {
891 		debug("PAM: establishing credentials");
892 		sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
893 	} else {
894 		debug("PAM: reinitializing credentials");
895 		sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
896 	}
897 	if (sshpam_err == PAM_SUCCESS) {
898 		sshpam_cred_established = 1;
899 		return;
900 	}
901 	if (sshpam_authenticated)
902 		fatal("PAM: pam_setcred(): %s",
903 		    pam_strerror(sshpam_handle, sshpam_err));
904 	else
905 		debug("PAM: pam_setcred(): %s",
906 		    pam_strerror(sshpam_handle, sshpam_err));
907 }
908 
909 static int
910 sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
911     struct pam_response **resp, void *data)
912 {
913 	char input[PAM_MAX_MSG_SIZE];
914 	struct pam_response *reply;
915 	int i;
916 
917 	debug3("PAM: %s called with %d messages", __func__, n);
918 
919 	*resp = NULL;
920 
921 	if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
922 		return (PAM_CONV_ERR);
923 
924 	if ((reply = malloc(n * sizeof(*reply))) == NULL)
925 		return (PAM_CONV_ERR);
926 	memset(reply, 0, n * sizeof(*reply));
927 
928 	for (i = 0; i < n; ++i) {
929 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
930 		case PAM_PROMPT_ECHO_OFF:
931 			reply[i].resp =
932 			    read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
933 			    RP_ALLOW_STDIN);
934 			reply[i].resp_retcode = PAM_SUCCESS;
935 			break;
936 		case PAM_PROMPT_ECHO_ON:
937 			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
938 			fgets(input, sizeof input, stdin);
939 			if ((reply[i].resp = strdup(input)) == NULL)
940 				goto fail;
941 			reply[i].resp_retcode = PAM_SUCCESS;
942 			break;
943 		case PAM_ERROR_MSG:
944 		case PAM_TEXT_INFO:
945 			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
946 			reply[i].resp_retcode = PAM_SUCCESS;
947 			break;
948 		default:
949 			goto fail;
950 		}
951 	}
952 	*resp = reply;
953 	return (PAM_SUCCESS);
954 
955  fail:
956 	for(i = 0; i < n; i++) {
957 		if (reply[i].resp != NULL)
958 			xfree(reply[i].resp);
959 	}
960 	xfree(reply);
961 	return (PAM_CONV_ERR);
962 }
963 
964 static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
965 
966 /*
967  * XXX this should be done in the authentication phase, but ssh1 doesn't
968  * support that
969  */
970 void
971 do_pam_chauthtok(void)
972 {
973 	if (use_privsep)
974 		fatal("Password expired (unable to change with privsep)");
975 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
976 	    (const void *)&tty_conv);
977 	if (sshpam_err != PAM_SUCCESS)
978 		fatal("PAM: failed to set PAM_CONV: %s",
979 		    pam_strerror(sshpam_handle, sshpam_err));
980 	debug("PAM: changing password");
981 	sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
982 	if (sshpam_err != PAM_SUCCESS)
983 		fatal("PAM: pam_chauthtok(): %s",
984 		    pam_strerror(sshpam_handle, sshpam_err));
985 }
986 
987 void
988 do_pam_session(void)
989 {
990 	debug3("PAM: opening session");
991 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
992 	    (const void *)&store_conv);
993 	if (sshpam_err != PAM_SUCCESS)
994 		fatal("PAM: failed to set PAM_CONV: %s",
995 		    pam_strerror(sshpam_handle, sshpam_err));
996 	sshpam_err = pam_open_session(sshpam_handle, 0);
997 	if (sshpam_err == PAM_SUCCESS)
998 		sshpam_session_open = 1;
999 	else {
1000 		sshpam_session_open = 0;
1001 		disable_forwarding();
1002 		error("PAM: pam_open_session(): %s",
1003 		    pam_strerror(sshpam_handle, sshpam_err));
1004 	}
1005 
1006 }
1007 
1008 int
1009 is_pam_session_open(void)
1010 {
1011 	return sshpam_session_open;
1012 }
1013 
1014 /*
1015  * Set a PAM environment string. We need to do this so that the session
1016  * modules can handle things like Kerberos/GSI credentials that appear
1017  * during the ssh authentication process.
1018  */
1019 int
1020 do_pam_putenv(char *name, char *value)
1021 {
1022 	int ret = 1;
1023 #ifdef HAVE_PAM_PUTENV
1024 	char *compound;
1025 	size_t len;
1026 
1027 	len = strlen(name) + strlen(value) + 2;
1028 	compound = xmalloc(len);
1029 
1030 	snprintf(compound, len, "%s=%s", name, value);
1031 	ret = pam_putenv(sshpam_handle, compound);
1032 	xfree(compound);
1033 #endif
1034 
1035 	return (ret);
1036 }
1037 
1038 char **
1039 fetch_pam_child_environment(void)
1040 {
1041 	return sshpam_env;
1042 }
1043 
1044 char **
1045 fetch_pam_environment(void)
1046 {
1047 	return (pam_getenvlist(sshpam_handle));
1048 }
1049 
1050 void
1051 free_pam_environment(char **env)
1052 {
1053 	char **envp;
1054 
1055 	if (env == NULL)
1056 		return;
1057 
1058 	for (envp = env; *envp; envp++)
1059 		xfree(*envp);
1060 	xfree(env);
1061 }
1062 
1063 /*
1064  * "Blind" conversation function for password authentication.  Assumes that
1065  * echo-off prompts are for the password and stores messages for later
1066  * display.
1067  */
1068 static int
1069 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
1070     struct pam_response **resp, void *data)
1071 {
1072 	struct pam_response *reply;
1073 	int i;
1074 	size_t len;
1075 
1076 	debug3("PAM: %s called with %d messages", __func__, n);
1077 
1078 	*resp = NULL;
1079 
1080 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
1081 		return (PAM_CONV_ERR);
1082 
1083 	if ((reply = malloc(n * sizeof(*reply))) == NULL)
1084 		return (PAM_CONV_ERR);
1085 	memset(reply, 0, n * sizeof(*reply));
1086 
1087 	for (i = 0; i < n; ++i) {
1088 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1089 		case PAM_PROMPT_ECHO_OFF:
1090 			if (sshpam_password == NULL)
1091 				goto fail;
1092 			if ((reply[i].resp = strdup(sshpam_password)) == NULL)
1093 				goto fail;
1094 			reply[i].resp_retcode = PAM_SUCCESS;
1095 			break;
1096 		case PAM_ERROR_MSG:
1097 		case PAM_TEXT_INFO:
1098 			len = strlen(PAM_MSG_MEMBER(msg, i, msg));
1099 			if (len > 0) {
1100 				buffer_append(&loginmsg,
1101 				    PAM_MSG_MEMBER(msg, i, msg), len);
1102 				buffer_append(&loginmsg, "\n", 1);
1103 			}
1104 			if ((reply[i].resp = strdup("")) == NULL)
1105 				goto fail;
1106 			reply[i].resp_retcode = PAM_SUCCESS;
1107 			break;
1108 		default:
1109 			goto fail;
1110 		}
1111 	}
1112 	*resp = reply;
1113 	return (PAM_SUCCESS);
1114 
1115  fail:
1116 	for(i = 0; i < n; i++) {
1117 		if (reply[i].resp != NULL)
1118 			xfree(reply[i].resp);
1119 	}
1120 	xfree(reply);
1121 	return (PAM_CONV_ERR);
1122 }
1123 
1124 static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
1125 
1126 /*
1127  * Attempt password authentication via PAM
1128  */
1129 int
1130 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
1131 {
1132 	int flags = (options.permit_empty_passwd == 0 ?
1133 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
1134 
1135 	if (!options.use_pam || sshpam_handle == NULL)
1136 		fatal("PAM: %s called when PAM disabled or failed to "
1137 		    "initialise.", __func__);
1138 
1139 	sshpam_password = password;
1140 	sshpam_authctxt = authctxt;
1141 
1142 	/*
1143 	 * If the user logging in is invalid, or is root but is not permitted
1144 	 * by PermitRootLogin, use an invalid password to prevent leaking
1145 	 * information via timing (eg if the PAM config has a delay on fail).
1146 	 */
1147 	if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
1148 	    options.permit_root_login != PERMIT_YES))
1149 		sshpam_password = badpw;
1150 
1151 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1152 	    (const void *)&passwd_conv);
1153 	if (sshpam_err != PAM_SUCCESS)
1154 		fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
1155 		    pam_strerror(sshpam_handle, sshpam_err));
1156 
1157 	sshpam_err = pam_authenticate(sshpam_handle, flags);
1158 	sshpam_password = NULL;
1159 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
1160 		debug("PAM: password authentication accepted for %.100s",
1161 		    authctxt->user);
1162 		return 1;
1163 	} else {
1164 		debug("PAM: password authentication failed for %.100s: %s",
1165 		    authctxt->valid ? authctxt->user : "an illegal user",
1166 		    pam_strerror(sshpam_handle, sshpam_err));
1167 		return 0;
1168 	}
1169 }
1170 #endif /* USE_PAM */
1171