xref: /netbsd-src/crypto/external/bsd/openssh/dist/auth-pam.c (revision 3f351f34c6d827cf017cdcff3543f6ec0c88b420)
1 /*	$NetBSD: auth-pam.c,v 1.21 2023/10/25 20:19:57 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 Networks Associates Technology, Inc.
5  * All rights reserved.
6  *
7  * This software was developed for the FreeBSD Project by ThinkSec AS and
8  * NAI Labs, the Security Research Division of Network Associates, Inc.
9  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
10  * DARPA CHATS research program.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 /*
34  * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
35  * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
36  *
37  * Permission to use, copy, modify, and distribute this software for any
38  * purpose with or without fee is hereby granted, provided that the above
39  * copyright notice and this permission notice appear in all copies.
40  *
41  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
42  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
43  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
44  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
45  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
46  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
47  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48  */
49 
50 /* Based on FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des */
51 
52 #include "includes.h"
53 /*
54  * NetBSD local changes
55  */
56 __RCSID("$NetBSD: auth-pam.c,v 1.21 2023/10/25 20:19:57 christos Exp $");
57 #define _LIB_PTHREAD_H
58 #undef USE_POSIX_THREADS /* Not yet */
59 #define HAVE_SECURITY_PAM_APPL_H
60 #define HAVE_PAM_GETENVLIST
61 #define HAVE_PAM_PUTENV
62 #define sshpam_const	const	/* LinuxPAM, OpenPAM */
63 #define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
64 #define SSHD_PAM_SERVICE               getprogname()
65 /* end NetBSD local changes */
66 
67 #include <sys/types.h>
68 #include <sys/socket.h>
69 #include <sys/stat.h>
70 #include <sys/wait.h>
71 
72 #include <errno.h>
73 #include <signal.h>
74 #include <stdarg.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78 #include <pwd.h>
79 
80 #ifdef USE_PAM
81 #if defined(HAVE_SECURITY_PAM_APPL_H)
82 #include <security/pam_appl.h>
83 #elif defined (HAVE_PAM_PAM_APPL_H)
84 #include <pam/pam_appl.h>
85 #endif
86 
87 #if !defined(SSHD_PAM_SERVICE)
88 extern char *__progname;
89 # define SSHD_PAM_SERVICE		__progname
90 #endif
91 
92 #ifndef __NetBSD__
93 /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
94 #ifdef PAM_SUN_CODEBASE
95 # define sshpam_const		/* Solaris, HP-UX, SunOS */
96 #else
97 # define sshpam_const	const	/* LinuxPAM, OpenPAM, AIX */
98 #endif
99 
100 /* Ambiguity in spec: is it an array of pointers or a pointer to an array? */
101 #ifdef PAM_SUN_CODEBASE
102 # define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
103 #else
104 # define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
105 #endif
106 #endif
107 
108 #include "xmalloc.h"
109 #include "sshbuf.h"
110 #include "ssherr.h"
111 #include "hostfile.h"
112 #include "auth.h"
113 #include "auth-pam.h"
114 #include "canohost.h"
115 #include "log.h"
116 #include "msg.h"
117 #include "packet.h"
118 #include "misc.h"
119 #include "servconf.h"
120 #include "ssh2.h"
121 #include "auth-options.h"
122 #ifdef GSSAPI
123 #include "ssh-gss.h"
124 #endif
125 #include "monitor_wrap.h"
126 
127 extern ServerOptions options;
128 extern struct sshbuf *loginmsg;
129 extern u_int utmp_len;
130 
131 /* so we don't silently change behaviour */
132 #ifdef USE_POSIX_THREADS
133 # error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
134 #endif
135 
136 /*
137  * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
138  * and generally a bad idea.  Use at own risk and do not expect support if
139  * this breaks.
140  */
141 #ifdef UNSUPPORTED_POSIX_THREADS_HACK
142 #error "foo"
143 #include <pthread.h>
144 /*
145  * Avoid namespace clash when *not* using pthreads for systems *with*
146  * pthreads, which unconditionally define pthread_t via sys/types.h
147  * (e.g. Linux)
148  */
149 typedef pthread_t sp_pthread_t;
150 #else
151 typedef pid_t sp_pthread_t;
152 #define pthread_exit	fake_pthread_exit
153 #define pthread_create	fake_pthread_create
154 #define pthread_cancel	fake_pthread_cancel
155 #define pthread_join	fake_pthread_join
156 #endif
157 
158 struct pam_ctxt {
159 	sp_pthread_t	 pam_thread;
160 	int		 pam_psock;
161 	int		 pam_csock;
162 	int		 pam_done;
163 };
164 
165 static void sshpam_free_ctx(void *);
166 static struct pam_ctxt *cleanup_ctxt;
167 
168 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
169 /*
170  * Simulate threads with processes.
171  */
172 
173 static int sshpam_thread_status = -1;
174 static sshsig_t sshpam_oldsig;
175 
176 static void
177 sshpam_sigchld_handler(int sig)
178 {
179 	ssh_signal(SIGCHLD, SIG_DFL);
180 	if (cleanup_ctxt == NULL)
181 		return;	/* handler called after PAM cleanup, shouldn't happen */
182 	if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
183 	    <= 0) {
184 		/* PAM thread has not exitted, privsep slave must have */
185 		kill(cleanup_ctxt->pam_thread, SIGTERM);
186 		while (waitpid(cleanup_ctxt->pam_thread,
187 		    &sshpam_thread_status, 0) == -1) {
188 			if (errno == EINTR)
189 				continue;
190 			return;
191 		}
192 	}
193 	if (WIFSIGNALED(sshpam_thread_status) &&
194 	    WTERMSIG(sshpam_thread_status) == SIGTERM)
195 		return;	/* terminated by pthread_cancel */
196 	if (!WIFEXITED(sshpam_thread_status))
197 		sigdie("PAM: authentication thread exited unexpectedly");
198 	if (WEXITSTATUS(sshpam_thread_status) != 0)
199 		sigdie("PAM: authentication thread exited uncleanly");
200 }
201 
202 /* ARGSUSED */
203 __dead static void
204 pthread_exit(void *value)
205 {
206 	_exit(0);
207 }
208 
209 /* ARGSUSED */
210 static int
211 pthread_create(sp_pthread_t *thread, const void *attr,
212     void *(*thread_start)(void *), void *arg)
213 {
214 	pid_t pid;
215 	struct pam_ctxt *ctx = arg;
216 
217 	sshpam_thread_status = -1;
218 	switch ((pid = fork())) {
219 	case -1:
220 		error("fork(): %s", strerror(errno));
221 		return errno;
222 	case 0:
223 		close(ctx->pam_psock);
224 		ctx->pam_psock = -1;
225 		thread_start(arg);
226 		_exit(1);
227 	default:
228 		*thread = pid;
229 		close(ctx->pam_csock);
230 		ctx->pam_csock = -1;
231 		sshpam_oldsig = ssh_signal(SIGCHLD, sshpam_sigchld_handler);
232 		return (0);
233 	}
234 }
235 
236 static int
237 pthread_cancel(sp_pthread_t thread)
238 {
239 	ssh_signal(SIGCHLD, sshpam_oldsig);
240 	return (kill(thread, SIGTERM));
241 }
242 
243 /* ARGSUSED */
244 static int
245 pthread_join(sp_pthread_t thread, void **value)
246 {
247 	int status;
248 
249 	if (sshpam_thread_status != -1)
250 		return (sshpam_thread_status);
251 	ssh_signal(SIGCHLD, sshpam_oldsig);
252 	while (waitpid(thread, &status, 0) == -1) {
253 		if (errno == EINTR)
254 			continue;
255 		fatal("%s: waitpid: %s", __func__, strerror(errno));
256 	}
257 	return (status);
258 }
259 #endif
260 
261 
262 static pam_handle_t *sshpam_handle = NULL;
263 static int sshpam_err = 0;
264 static int sshpam_authenticated = 0;
265 static int sshpam_session_open = 0;
266 static int sshpam_cred_established = 0;
267 static int sshpam_account_status = -1;
268 static int sshpam_maxtries_reached = 0;
269 static char **sshpam_env = NULL;
270 static Authctxt *sshpam_authctxt = NULL;
271 static const char *sshpam_password = NULL;
272 static char *sshpam_rhost = NULL;
273 static char *sshpam_laddr = NULL;
274 
275 /* Some PAM implementations don't implement this */
276 #ifndef HAVE_PAM_GETENVLIST
277 static char **
278 pam_getenvlist(pam_handle_t *pamh)
279 {
280 	/*
281 	 * XXX - If necessary, we can still support environment passing
282 	 * for platforms without pam_getenvlist by searching for known
283 	 * env vars (e.g. KRB5CCNAME) from the PAM environment.
284 	 */
285 	 return NULL;
286 }
287 #endif
288 
289 #ifndef HAVE_PAM_PUTENV
290 static int
291 pam_putenv(pam_handle_t *pamh, const char *name_value)
292 {
293 	return PAM_SUCCESS;
294 }
295 #endif /* HAVE_PAM_PUTENV */
296 
297 /*
298  * Some platforms, notably Solaris, do not enforce password complexity
299  * rules during pam_chauthtok() if the real uid of the calling process
300  * is 0, on the assumption that it's being called by "passwd" run by root.
301  * This wraps pam_chauthtok and sets/restore the real uid so PAM will do
302  * the right thing.
303  */
304 #ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
305 static int
306 sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
307 {
308 	int result;
309 
310 	if (sshpam_authctxt == NULL)
311 		fatal("PAM: sshpam_authctxt not initialized");
312 	if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
313 		fatal("%s: setreuid failed: %s", __func__, strerror(errno));
314 	result = pam_chauthtok(pamh, flags);
315 	if (setreuid(0, -1) == -1)
316 		fatal("%s: setreuid failed: %s", __func__, strerror(errno));
317 	return result;
318 }
319 # define pam_chauthtok(a,b)	(sshpam_chauthtok_ruid((a), (b)))
320 #endif
321 
322 static void
323 sshpam_password_change_required(int reqd)
324 {
325 	extern struct sshauthopt *auth_opts;
326 	static int saved_port, saved_agent, saved_x11;
327 
328 	debug3("%s %d", __func__, reqd);
329 	if (sshpam_authctxt == NULL)
330 		fatal("%s: PAM authctxt not initialized", __func__);
331 	sshpam_authctxt->force_pwchange = reqd;
332 	if (reqd) {
333 		saved_port = auth_opts->permit_port_forwarding_flag;
334 		saved_agent = auth_opts->permit_agent_forwarding_flag;
335 		saved_x11 = auth_opts->permit_x11_forwarding_flag;
336 		auth_opts->permit_port_forwarding_flag = 0;
337 		auth_opts->permit_agent_forwarding_flag = 0;
338 		auth_opts->permit_x11_forwarding_flag = 0;
339 	} else {
340 		if (saved_port)
341 			auth_opts->permit_port_forwarding_flag = saved_port;
342 		if (saved_agent)
343 			auth_opts->permit_agent_forwarding_flag = saved_agent;
344 		if (saved_x11)
345 			auth_opts->permit_x11_forwarding_flag = saved_x11;
346 	}
347 }
348 
349 /* Import regular and PAM environment from subprocess */
350 static void
351 import_environments(struct sshbuf *b)
352 {
353 	char *env;
354 	u_int n, i, num_env;
355 	int r;
356 
357 	debug3("PAM: %s entering", __func__);
358 
359 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
360 	/* Import variables set by do_pam_account */
361 	if ((r = sshbuf_get_u32(b, &n)) != 0)
362 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
363 	if (n > INT_MAX)
364 		fatal("%s: invalid PAM account status %u", __func__, n);
365 	sshpam_account_status = (int)n;
366 	if ((r = sshbuf_get_u32(b, &n)) != 0)
367 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
368 	sshpam_password_change_required(n != 0);
369 
370 	/* Import environment from subprocess */
371 	if ((r = sshbuf_get_u32(b, &num_env)) != 0)
372 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
373 	if (num_env > 1024) {
374 		fatal_f("received %u environment variables, expected <= 1024",
375 		    num_env);
376 	}
377 	sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
378 	debug3("PAM: num env strings %u", num_env);
379 	for(i = 0; i < num_env; i++) {
380 		if ((r = sshbuf_get_cstring(b, &(sshpam_env[i]), NULL)) != 0)
381 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
382 	}
383 	sshpam_env[num_env] = NULL;
384 
385 	/* Import PAM environment from subprocess */
386 	if ((r = sshbuf_get_u32(b, &num_env)) != 0)
387 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
388 	if (num_env > 1024) {
389 		fatal_f("received %u PAM env variables, expected <= 1024",
390 		    num_env);
391 	}
392 	debug("PAM: num PAM env strings %u", num_env);
393 	for (i = 0; i < num_env; i++) {
394 		if ((r = sshbuf_get_cstring(b, &env, NULL)) != 0)
395 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
396 #ifdef HAVE_PAM_PUTENV
397 		/* Errors are not fatal here */
398 		if ((r = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
399 			error("PAM: pam_putenv: %s",
400 			    pam_strerror(sshpam_handle, r));
401 		}
402 #endif
403 		/*
404 		 * XXX this possibly leaks env because it is not documented
405 		 * what pam_putenv() does with it. Does it copy it? Does it
406 		 * take ownweship? We don't know, so it's safest just to leak.
407 		 */
408 	}
409 #endif
410 }
411 
412 /*
413  * Conversation function for authentication thread.
414  */
415 static int
416 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
417     struct pam_response **resp, void *data)
418 {
419 	struct sshbuf *buffer;
420 	struct pam_ctxt *ctxt;
421 	struct pam_response *reply;
422 	int r, i;
423 	u_char status;
424 
425 	debug3("PAM: %s entering, %d messages", __func__, n);
426 	*resp = NULL;
427 
428 	if (data == NULL) {
429 		error("PAM: conversation function passed a null context");
430 		return (PAM_CONV_ERR);
431 	}
432 	ctxt = data;
433 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
434 		return (PAM_CONV_ERR);
435 
436 	if ((reply = calloc(n, sizeof(*reply))) == NULL)
437 		return PAM_CONV_ERR;
438 	if ((buffer = sshbuf_new()) == NULL) {
439 		free(reply);
440 		return PAM_CONV_ERR;
441 	}
442 
443 	for (i = 0; i < n; ++i) {
444 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
445 		case PAM_PROMPT_ECHO_OFF:
446 		case PAM_PROMPT_ECHO_ON:
447 			if ((r = sshbuf_put_cstring(buffer,
448 			    PAM_MSG_MEMBER(msg, i, msg))) != 0)
449 				fatal("%s: buffer error: %s",
450 				    __func__, ssh_err(r));
451 			if (ssh_msg_send(ctxt->pam_csock,
452 			    PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
453 				goto fail;
454 
455 			if (ssh_msg_recv(ctxt->pam_csock, buffer) == -1)
456 				goto fail;
457 			if ((r = sshbuf_get_u8(buffer, &status)) != 0)
458 				fatal("%s: buffer error: %s",
459 				    __func__, ssh_err(r));
460 			if (status != PAM_AUTHTOK)
461 				goto fail;
462 			if ((r = sshbuf_get_cstring(buffer,
463 			    &reply[i].resp, NULL)) != 0)
464 				fatal("%s: buffer error: %s",
465 				    __func__, ssh_err(r));
466 			break;
467 		case PAM_ERROR_MSG:
468 		case PAM_TEXT_INFO:
469 			if ((r = sshbuf_put_cstring(buffer,
470 			    PAM_MSG_MEMBER(msg, i, msg))) != 0)
471 				fatal("%s: buffer error: %s",
472 				    __func__, ssh_err(r));
473 			if (ssh_msg_send(ctxt->pam_csock,
474 			    PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
475 				goto fail;
476 			break;
477 		default:
478 			goto fail;
479 		}
480 		sshbuf_reset(buffer);
481 	}
482 	sshbuf_free(buffer);
483 	*resp = reply;
484 	return (PAM_SUCCESS);
485 
486  fail:
487 	for(i = 0; i < n; i++) {
488 		free(reply[i].resp);
489 	}
490 	free(reply);
491 	sshbuf_free(buffer);
492 	return (PAM_CONV_ERR);
493 }
494 
495 /*
496  * Authentication thread.
497  */
498 static void *
499 sshpam_thread(void *ctxtp)
500 {
501 	struct pam_ctxt *ctxt = ctxtp;
502 	struct sshbuf *buffer = NULL;
503 	struct pam_conv sshpam_conv;
504 	int r, flags = (options.permit_empty_passwd == 0 ?
505 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
506 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
507 	extern char **environ;
508 	char **env_from_pam;
509 	u_int i;
510 	const char *pam_user;
511 	const char **ptr_pam_user = &pam_user;
512 	char *tz = getenv("TZ");
513 
514 	sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
515 	    (sshpam_const void **)ptr_pam_user);
516 	if (sshpam_err != PAM_SUCCESS)
517 		goto auth_fail;
518 
519 	environ[0] = NULL;
520 	if (tz != NULL)
521 		if (setenv("TZ", tz, 1) == -1)
522 			error("PAM: could not set TZ environment: %s",
523 			    strerror(errno));
524 
525 	if (sshpam_authctxt != NULL) {
526 		setproctitle("%s [pam]",
527 		    sshpam_authctxt->valid ? pam_user : "unknown");
528 	}
529 #endif
530 
531 	sshpam_conv.conv = sshpam_thread_conv;
532 	sshpam_conv.appdata_ptr = ctxt;
533 
534 	if (sshpam_authctxt == NULL)
535 		fatal("%s: PAM authctxt not initialized", __func__);
536 
537 	if ((buffer = sshbuf_new()) == NULL)
538 		fatal("%s: sshbuf_new failed", __func__);
539 
540 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
541 	    (const void *)&sshpam_conv);
542 	if (sshpam_err != PAM_SUCCESS)
543 		goto auth_fail;
544 	sshpam_err = pam_authenticate(sshpam_handle, flags);
545 	if (sshpam_err == PAM_MAXTRIES)
546 		sshpam_set_maxtries_reached(1);
547 	if (sshpam_err != PAM_SUCCESS)
548 		goto auth_fail;
549 
550 	if (!do_pam_account()) {
551 		sshpam_err = PAM_ACCT_EXPIRED;
552 		goto auth_fail;
553 	}
554 	if (sshpam_authctxt->force_pwchange) {
555 		sshpam_err = pam_chauthtok(sshpam_handle,
556 		    PAM_CHANGE_EXPIRED_AUTHTOK);
557 		if (sshpam_err != PAM_SUCCESS)
558 			goto auth_fail;
559 		sshpam_password_change_required(0);
560 	}
561 
562 	if ((r = sshbuf_put_cstring(buffer, "OK")) != 0)
563 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
564 
565 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
566 	/* Export variables set by do_pam_account */
567 	if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 ||
568 	    (r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0)
569 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
570 
571 	/* Export any environment strings set in child */
572 	for (i = 0; environ[i] != NULL; i++) {
573 		/* Count */
574 		if (i > INT_MAX)
575 			fatal("%s: too many environment strings", __func__);
576 	}
577 	if ((r = sshbuf_put_u32(buffer, i)) != 0)
578 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
579 	for (i = 0; environ[i] != NULL; i++) {
580 		if ((r = sshbuf_put_cstring(buffer, environ[i])) != 0)
581 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
582 	}
583 	/* Export any environment strings set by PAM in child */
584 	env_from_pam = pam_getenvlist(sshpam_handle);
585 	for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
586 		/* Count */
587 		if (i > INT_MAX)
588 			fatal("%s: too many PAM environment strings", __func__);
589 	}
590 	if ((r = sshbuf_put_u32(buffer, i)) != 0)
591 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
592 	for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
593 		if ((r = sshbuf_put_cstring(buffer, env_from_pam[i])) != 0)
594 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
595 	}
596 #endif /* UNSUPPORTED_POSIX_THREADS_HACK */
597 
598 	/* XXX - can't do much about an error here */
599 	ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer);
600 	sshbuf_free(buffer);
601 	pthread_exit(NULL);
602 
603  auth_fail:
604 	if ((r = sshbuf_put_cstring(buffer,
605 	    pam_strerror(sshpam_handle, sshpam_err))) != 0)
606 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
607 	/* XXX - can't do much about an error here */
608 	if (sshpam_err == PAM_ACCT_EXPIRED)
609 		ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer);
610 	else if (sshpam_maxtries_reached)
611 		ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer);
612 	else
613 		ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, buffer);
614 	sshbuf_free(buffer);
615 	pthread_exit(NULL);
616 
617 	return (NULL); /* Avoid warning for non-pthread case */
618 }
619 
620 void
621 sshpam_thread_cleanup(void)
622 {
623 	struct pam_ctxt *ctxt = cleanup_ctxt;
624 
625 	debug3("PAM: %s entering", __func__);
626 	if (ctxt != NULL && ctxt->pam_thread != 0) {
627 		pthread_cancel(ctxt->pam_thread);
628 		pthread_join(ctxt->pam_thread, NULL);
629 		close(ctxt->pam_psock);
630 		close(ctxt->pam_csock);
631 		memset(ctxt, 0, sizeof(*ctxt));
632 		cleanup_ctxt = NULL;
633 	}
634 }
635 
636 static int
637 sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
638     struct pam_response **resp, void *data)
639 {
640 	debug3("PAM: %s entering, %d messages", __func__, n);
641 	return (PAM_CONV_ERR);
642 }
643 
644 static struct pam_conv null_conv = { sshpam_null_conv, NULL };
645 
646 static int
647 sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
648     struct pam_response **resp, void *data)
649 {
650 	struct pam_response *reply;
651 	int r, i;
652 
653 	debug3("PAM: %s called with %d messages", __func__, n);
654 	*resp = NULL;
655 
656 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
657 		return (PAM_CONV_ERR);
658 
659 	if ((reply = calloc(n, sizeof(*reply))) == NULL)
660 		return (PAM_CONV_ERR);
661 
662 	for (i = 0; i < n; ++i) {
663 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
664 		case PAM_ERROR_MSG:
665 		case PAM_TEXT_INFO:
666 			if ((r = sshbuf_putf(loginmsg, "%s\n",
667 			    PAM_MSG_MEMBER(msg, i, msg))) != 0)
668 				fatal("%s: buffer error: %s",
669 				    __func__, ssh_err(r));
670 			reply[i].resp_retcode = PAM_SUCCESS;
671 			break;
672 		default:
673 			goto fail;
674 		}
675 	}
676 	*resp = reply;
677 	return (PAM_SUCCESS);
678 
679  fail:
680 	for(i = 0; i < n; i++) {
681 		free(reply[i].resp);
682 	}
683 	free(reply);
684 	return (PAM_CONV_ERR);
685 }
686 
687 static struct pam_conv store_conv = { sshpam_store_conv, NULL };
688 
689 void
690 sshpam_cleanup(void)
691 {
692 	if (sshpam_handle == NULL || (use_privsep && !mm_is_monitor()))
693 		return;
694 	debug("PAM: cleanup");
695 	pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
696 	if (sshpam_session_open) {
697 		debug("PAM: closing session");
698 		pam_close_session(sshpam_handle, PAM_SILENT);
699 		sshpam_session_open = 0;
700 	}
701 	if (sshpam_cred_established) {
702 		debug("PAM: deleting credentials");
703 		pam_setcred(sshpam_handle, PAM_DELETE_CRED);
704 		sshpam_cred_established = 0;
705 	}
706 	sshpam_authenticated = 0;
707 	pam_end(sshpam_handle, sshpam_err);
708 	sshpam_handle = NULL;
709 }
710 
711 static int
712 sshpam_init(struct ssh *ssh, Authctxt *authctxt)
713 {
714 	const char *pam_user, *user = authctxt->user;
715 	const char **ptr_pam_user = &pam_user;
716 	int r;
717 
718 #if defined(PAM_SUN_CODEBASE) && defined(PAM_MAX_RESP_SIZE)
719 	/* Protect buggy PAM implementations from excessively long usernames */
720 	if (strlen(user) >= PAM_MAX_RESP_SIZE)
721 		fatal("Username too long from %s port %d",
722 		    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
723 #endif
724 
725 	if (sshpam_handle == NULL) {
726 		if (ssh == NULL) {
727 			fatal("%s: called initially with no "
728 			    "packet context", __func__);
729 		}
730 	} if (sshpam_handle != NULL) {
731 		/* We already have a PAM context; check if the user matches */
732 		sshpam_err = pam_get_item(sshpam_handle,
733 		    PAM_USER, (sshpam_const void **)ptr_pam_user);
734 		if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
735 			return (0);
736 		pam_end(sshpam_handle, sshpam_err);
737 		sshpam_handle = NULL;
738 	}
739 	debug("PAM: initializing for \"%s\"", user);
740 	sshpam_err =
741 	    pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
742 	sshpam_authctxt = authctxt;
743 
744 	if (sshpam_err != PAM_SUCCESS) {
745 		pam_end(sshpam_handle, sshpam_err);
746 		sshpam_handle = NULL;
747 		return (-1);
748 	}
749 
750 	if (ssh != NULL && sshpam_rhost == NULL) {
751 		/*
752 		 * We need to cache these as we don't have packet context
753 		 * during the kbdint flow.
754 		 */
755 		sshpam_rhost = xstrdup(auth_get_canonical_hostname(ssh,
756 		    options.use_dns));
757 		sshpam_laddr = get_local_ipaddr(
758 		    ssh_packet_get_connection_in(ssh));
759 	}
760 	if (sshpam_rhost != NULL) {
761 		debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost);
762 		sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST,
763 		    sshpam_rhost);
764 		if (sshpam_err != PAM_SUCCESS) {
765 			pam_end(sshpam_handle, sshpam_err);
766 			sshpam_handle = NULL;
767 			return (-1);
768 		}
769 	}
770 	if (ssh != NULL && sshpam_laddr != NULL) {
771 		char *conninfo;
772 
773  		/* Put SSH_CONNECTION in the PAM environment too */
774 		xasprintf(&conninfo, "SSH_CONNECTION=%.50s %d %.50s %d",
775 		    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
776 		    sshpam_laddr, ssh_local_port(ssh));
777 		if ((r = pam_putenv(sshpam_handle, conninfo)) != PAM_SUCCESS)
778 			logit("pam_putenv: %s", pam_strerror(sshpam_handle, r));
779 		free(conninfo);
780 	}
781 
782 #ifdef PAM_TTY_KLUDGE
783 	/*
784 	 * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
785 	 * sshd doesn't set the tty until too late in the auth process and
786 	 * may not even set one (for tty-less connections)
787 	 */
788 	debug("PAM: setting PAM_TTY to \"ssh\"");
789 	sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
790 	if (sshpam_err != PAM_SUCCESS) {
791 		pam_end(sshpam_handle, sshpam_err);
792 		sshpam_handle = NULL;
793 		return (-1);
794 	}
795 #endif
796 	return (0);
797 }
798 
799 static void
800 expose_authinfo(const char *caller)
801 {
802 	char *auth_info;
803 
804 	/*
805 	 * Expose authentication information to PAM.
806 	 * The environment variable is versioned. Please increment the
807 	 * version suffix if the format of session_info changes.
808 	 */
809 	if (sshpam_authctxt->session_info == NULL)
810 		auth_info = xstrdup("");
811 	else if ((auth_info = sshbuf_dup_string(
812 	    sshpam_authctxt->session_info)) == NULL)
813 		fatal("%s: sshbuf_dup_string failed", __func__);
814 
815 	debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
816 	do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
817 	free(auth_info);
818 }
819 
820 static void *
821 sshpam_init_ctx(Authctxt *authctxt)
822 {
823 	struct pam_ctxt *ctxt;
824 	int result, socks[2];
825 
826 	debug3("PAM: %s entering", __func__);
827 	/*
828 	 * Refuse to start if we don't have PAM enabled or do_pam_account
829 	 * has previously failed.
830 	 */
831 	if (!options.use_pam || sshpam_account_status == 0)
832 		return NULL;
833 
834 	/* Initialize PAM */
835 	if (sshpam_init(NULL, authctxt) == -1) {
836 		error("PAM: initialization failed");
837 		return (NULL);
838 	}
839 
840 	expose_authinfo(__func__);
841 	ctxt = xcalloc(1, sizeof *ctxt);
842 
843 	/* Start the authentication thread */
844 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
845 		error("PAM: failed create sockets: %s", strerror(errno));
846 		free(ctxt);
847 		return (NULL);
848 	}
849 	ctxt->pam_psock = socks[0];
850 	ctxt->pam_csock = socks[1];
851 	result = pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt);
852 	if (result != 0) {
853 		error("PAM: failed to start authentication thread: %s",
854 		    strerror(result));
855 		close(socks[0]);
856 		close(socks[1]);
857 		free(ctxt);
858 		return (NULL);
859 	}
860 	cleanup_ctxt = ctxt;
861 	return (ctxt);
862 }
863 
864 static int
865 sshpam_query(void *ctx, char **name, char **info,
866     u_int *num, char ***prompts, u_int **echo_on)
867 {
868 	struct sshbuf *buffer;
869 	struct pam_ctxt *ctxt = ctx;
870 	size_t plen;
871 	u_char type;
872 	char *msg;
873 	size_t len, mlen, nmesg = 0;
874 	int r;
875 
876 	debug3("PAM: %s entering", __func__);
877 	if ((buffer = sshbuf_new()) == NULL)
878 		fatal("%s: sshbuf_new failed", __func__);
879 	*name = xstrdup("");
880 	*info = xstrdup("");
881 	*prompts = xmalloc(sizeof(char *));
882 	**prompts = NULL;
883 	plen = 0;
884 	*echo_on = xmalloc(sizeof(u_int));
885 	while (ssh_msg_recv(ctxt->pam_psock, buffer) == 0) {
886 		if (++nmesg > PAM_MAX_NUM_MSG)
887 			fatal_f("too many query messages");
888 		if ((r = sshbuf_get_u8(buffer, &type)) != 0 ||
889 		    (r = sshbuf_get_cstring(buffer, &msg, &mlen)) != 0)
890 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
891 		switch (type) {
892 		case PAM_PROMPT_ECHO_ON:
893 		case PAM_PROMPT_ECHO_OFF:
894 			*num = 1;
895 			len = plen + mlen + 1;
896 			**prompts = xreallocarray(**prompts, 1, len);
897 			strlcpy(**prompts + plen, msg, len - plen);
898 			plen += mlen;
899 			**echo_on = (type == PAM_PROMPT_ECHO_ON);
900 			free(msg);
901 			sshbuf_free(buffer);
902 			return (0);
903 		case PAM_ERROR_MSG:
904 		case PAM_TEXT_INFO:
905 			/* accumulate messages */
906 			len = plen + mlen + 2;
907 			**prompts = xreallocarray(**prompts, 1, len);
908 			strlcpy(**prompts + plen, msg, len - plen);
909 			plen += mlen;
910 			strlcat(**prompts + plen, "\n", len - plen);
911 			plen++;
912 			free(msg);
913 			break;
914 		case PAM_ACCT_EXPIRED:
915 		case PAM_MAXTRIES:
916 			if (type == PAM_ACCT_EXPIRED)
917 				sshpam_account_status = 0;
918 			if (type == PAM_MAXTRIES)
919 				sshpam_set_maxtries_reached(1);
920 			/* FALLTHROUGH */
921 		case PAM_AUTH_ERR:
922 			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
923 			if (**prompts != NULL && strlen(**prompts) != 0) {
924 				free(*info);
925 				*info = **prompts;
926 				**prompts = NULL;
927 				*num = 0;
928 				**echo_on = 0;
929 				ctxt->pam_done = -1;
930 				free(msg);
931 				sshbuf_free(buffer);
932 				return 0;
933 			}
934 			/* FALLTHROUGH */
935 		case PAM_SUCCESS:
936 			if (**prompts != NULL) {
937 				/* drain any accumulated messages */
938 				debug("PAM: %s", **prompts);
939 				if ((r = sshbuf_put(loginmsg, **prompts,
940 				    strlen(**prompts))) != 0)
941 					fatal("%s: buffer error: %s",
942 					    __func__, ssh_err(r));
943 				free(**prompts);
944 				**prompts = NULL;
945 			}
946 			if (type == PAM_SUCCESS) {
947 				if (!sshpam_authctxt->valid ||
948 				    (sshpam_authctxt->pw->pw_uid == 0 &&
949 				    options.permit_root_login != PERMIT_YES))
950 					fatal("Internal error: PAM auth "
951 					    "succeeded when it should have "
952 					    "failed");
953 				import_environments(buffer);
954 				*num = 0;
955 				**echo_on = 0;
956 				ctxt->pam_done = 1;
957 				free(msg);
958 				sshbuf_free(buffer);
959 				return (0);
960 			}
961 			error("PAM: %s for %s%.100s from %.100s", msg,
962 			    sshpam_authctxt->valid ? "" : "illegal user ",
963 			    sshpam_authctxt->user, sshpam_rhost);
964 			/* FALLTHROUGH */
965 		default:
966 			*num = 0;
967 			**echo_on = 0;
968 			free(msg);
969 			ctxt->pam_done = -1;
970 			sshbuf_free(buffer);
971 			return (-1);
972 		}
973 	}
974 	sshbuf_free(buffer);
975 	return (-1);
976 }
977 
978 /*
979  * Returns a junk password of identical length to that the user supplied.
980  * Used to mitigate timing attacks against crypt(3)/PAM stacks that
981  * vary processing time in proportion to password length.
982  */
983 static char *
984 fake_password(const char *wire_password)
985 {
986 	const char junk[] = "\b\n\r\177INCORRECT";
987 	char *ret = NULL;
988 	size_t i, l = wire_password != NULL ? strlen(wire_password) : 0;
989 
990 	if (l >= INT_MAX)
991 		fatal("%s: password length too long: %zu", __func__, l);
992 
993 	ret = malloc(l + 1);
994 	if (ret == NULL)
995 		return NULL;
996 	for (i = 0; i < l; i++)
997 		ret[i] = junk[i % (sizeof(junk) - 1)];
998 	ret[i] = '\0';
999 	return ret;
1000 }
1001 
1002 /* XXX - see also comment in auth-chall.c:verify_response */
1003 static int
1004 sshpam_respond(void *ctx, u_int num, char **resp)
1005 {
1006 	struct sshbuf *buffer;
1007 	struct pam_ctxt *ctxt = ctx;
1008 	char *fake;
1009 	int r;
1010 
1011 	debug2("PAM: %s entering, %u responses", __func__, num);
1012 	switch (ctxt->pam_done) {
1013 	case 1:
1014 		sshpam_authenticated = 1;
1015 		return (0);
1016 	case 0:
1017 		break;
1018 	default:
1019 		return (-1);
1020 	}
1021 	if (num != 1) {
1022 		error("PAM: expected one response, got %u", num);
1023 		return (-1);
1024 	}
1025 	if ((buffer = sshbuf_new()) == NULL)
1026 		fatal("%s: sshbuf_new failed", __func__);
1027 	if (sshpam_authctxt->valid &&
1028 	    (sshpam_authctxt->pw->pw_uid != 0 ||
1029 	    options.permit_root_login == PERMIT_YES)) {
1030 		if ((r = sshbuf_put_cstring(buffer, *resp)) != 0)
1031 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1032 	} else {
1033 		fake = fake_password(*resp);
1034 		if ((r = sshbuf_put_cstring(buffer, fake)) != 0)
1035 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1036 		free(fake);
1037 	}
1038 	if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, buffer) == -1) {
1039 		sshbuf_free(buffer);
1040 		return (-1);
1041 	}
1042 	sshbuf_free(buffer);
1043 	return (1);
1044 }
1045 
1046 static void
1047 sshpam_free_ctx(void *ctxtp)
1048 {
1049 	struct pam_ctxt *ctxt = ctxtp;
1050 
1051 	debug3("PAM: %s entering", __func__);
1052 	sshpam_thread_cleanup();
1053 	free(ctxt);
1054 	/*
1055 	 * We don't call sshpam_cleanup() here because we may need the PAM
1056 	 * handle at a later stage, e.g. when setting up a session.  It's
1057 	 * still on the cleanup list, so pam_end() *will* be called before
1058 	 * the server process terminates.
1059 	 */
1060 }
1061 
1062 KbdintDevice sshpam_device = {
1063 	"pam",
1064 	sshpam_init_ctx,
1065 	sshpam_query,
1066 	sshpam_respond,
1067 	sshpam_free_ctx
1068 };
1069 
1070 KbdintDevice mm_sshpam_device = {
1071 	"pam",
1072 	mm_sshpam_init_ctx,
1073 	mm_sshpam_query,
1074 	mm_sshpam_respond,
1075 	mm_sshpam_free_ctx
1076 };
1077 
1078 /*
1079  * This replaces auth-pam.c
1080  */
1081 void
1082 start_pam(struct ssh *ssh)
1083 {
1084 	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
1085 
1086 	if (!options.use_pam)
1087 		fatal("PAM: initialisation requested when UsePAM=no");
1088 
1089 	if (sshpam_init(ssh, authctxt) == -1)
1090 		fatal("PAM: initialisation failed");
1091 }
1092 
1093 void
1094 finish_pam(void)
1095 {
1096 	sshpam_cleanup();
1097 }
1098 
1099 
1100 u_int
1101 do_pam_account(void)
1102 {
1103 	debug("%s: called", __func__);
1104 	if (sshpam_account_status != -1)
1105 		return (sshpam_account_status);
1106 
1107 	expose_authinfo(__func__);
1108 
1109 	sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
1110 	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
1111 	    pam_strerror(sshpam_handle, sshpam_err));
1112 
1113 	if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
1114 		sshpam_account_status = 0;
1115 		return (sshpam_account_status);
1116 	}
1117 
1118 	if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
1119 		sshpam_password_change_required(1);
1120 
1121 	sshpam_account_status = 1;
1122 	return (sshpam_account_status);
1123 }
1124 
1125 void
1126 do_pam_setcred(int init)
1127 {
1128 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1129 	    (const void *)&store_conv);
1130 	if (sshpam_err != PAM_SUCCESS)
1131 		fatal("PAM: failed to set PAM_CONV: %s",
1132 		    pam_strerror(sshpam_handle, sshpam_err));
1133 	if (init) {
1134 		debug("PAM: establishing credentials");
1135 		sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
1136 	} else {
1137 		debug("PAM: reinitializing credentials");
1138 		sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
1139 	}
1140 	if (sshpam_err == PAM_SUCCESS) {
1141 		sshpam_cred_established = 1;
1142 		return;
1143 	}
1144 	if (sshpam_authenticated)
1145 		fatal("PAM: pam_setcred(): %s",
1146 		    pam_strerror(sshpam_handle, sshpam_err));
1147 	else
1148 		debug("PAM: pam_setcred(): %s",
1149 		    pam_strerror(sshpam_handle, sshpam_err));
1150 }
1151 
1152 static int
1153 sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
1154     struct pam_response **resp, void *data)
1155 {
1156 	char input[PAM_MAX_MSG_SIZE];
1157 	struct pam_response *reply;
1158 	int i;
1159 
1160 	debug3("PAM: %s called with %d messages", __func__, n);
1161 
1162 	*resp = NULL;
1163 
1164 	if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
1165 		return (PAM_CONV_ERR);
1166 
1167 	if ((reply = calloc(n, sizeof(*reply))) == NULL)
1168 		return (PAM_CONV_ERR);
1169 
1170 	for (i = 0; i < n; ++i) {
1171 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1172 		case PAM_PROMPT_ECHO_OFF:
1173 			reply[i].resp =
1174 			    read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
1175 			    RP_ALLOW_STDIN);
1176 			reply[i].resp_retcode = PAM_SUCCESS;
1177 			break;
1178 		case PAM_PROMPT_ECHO_ON:
1179 			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
1180 			if (fgets(input, sizeof input, stdin) == NULL)
1181 				input[0] = '\0';
1182 			if ((reply[i].resp = strdup(input)) == NULL)
1183 				goto fail;
1184 			reply[i].resp_retcode = PAM_SUCCESS;
1185 			break;
1186 		case PAM_ERROR_MSG:
1187 		case PAM_TEXT_INFO:
1188 			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
1189 			reply[i].resp_retcode = PAM_SUCCESS;
1190 			break;
1191 		default:
1192 			goto fail;
1193 		}
1194 	}
1195 	*resp = reply;
1196 	return (PAM_SUCCESS);
1197 
1198  fail:
1199 	for(i = 0; i < n; i++) {
1200 		free(reply[i].resp);
1201 	}
1202 	free(reply);
1203 	return (PAM_CONV_ERR);
1204 }
1205 
1206 static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
1207 
1208 /*
1209  * XXX this should be done in the authentication phase, but ssh1 doesn't
1210  * support that
1211  */
1212 void
1213 do_pam_chauthtok(void)
1214 {
1215 	if (use_privsep)
1216 		fatal("Password expired (unable to change with privsep)");
1217 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1218 	    (const void *)&tty_conv);
1219 	if (sshpam_err != PAM_SUCCESS)
1220 		fatal("PAM: failed to set PAM_CONV: %s",
1221 		    pam_strerror(sshpam_handle, sshpam_err));
1222 	debug("PAM: changing password");
1223 	sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
1224 	if (sshpam_err != PAM_SUCCESS)
1225 		fatal("PAM: pam_chauthtok(): %s",
1226 		    pam_strerror(sshpam_handle, sshpam_err));
1227 }
1228 
1229 void
1230 do_pam_session(struct ssh *ssh)
1231 {
1232 	debug3("PAM: opening session");
1233 
1234 	expose_authinfo(__func__);
1235 
1236 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1237 	    (const void *)&store_conv);
1238 	if (sshpam_err != PAM_SUCCESS)
1239 		fatal("PAM: failed to set PAM_CONV: %s",
1240 		    pam_strerror(sshpam_handle, sshpam_err));
1241 	sshpam_err = pam_open_session(sshpam_handle, 0);
1242 	if (sshpam_err == PAM_SUCCESS)
1243 		sshpam_session_open = 1;
1244 	else {
1245 		sshpam_session_open = 0;
1246 		auth_restrict_session(ssh);
1247 		error("PAM: pam_open_session(): %s",
1248 		    pam_strerror(sshpam_handle, sshpam_err));
1249 	}
1250 
1251 }
1252 
1253 int
1254 is_pam_session_open(void)
1255 {
1256 	return sshpam_session_open;
1257 }
1258 
1259 /*
1260  * Set a PAM environment string. We need to do this so that the session
1261  * modules can handle things like Kerberos/GSI credentials that appear
1262  * during the ssh authentication process.
1263  */
1264 int
1265 do_pam_putenv(const char *name, char *value)
1266 {
1267 	int ret = 1;
1268 #ifdef HAVE_PAM_PUTENV
1269 	char *compound;
1270 	size_t len;
1271 
1272 	len = strlen(name) + strlen(value) + 2;
1273 	compound = xmalloc(len);
1274 
1275 	snprintf(compound, len, "%s=%s", name, value);
1276 	ret = pam_putenv(sshpam_handle, compound);
1277 	free(compound);
1278 #endif
1279 
1280 	return (ret);
1281 }
1282 
1283 char **
1284 fetch_pam_child_environment(void)
1285 {
1286 	return sshpam_env;
1287 }
1288 
1289 char **
1290 fetch_pam_environment(void)
1291 {
1292 	return (pam_getenvlist(sshpam_handle));
1293 }
1294 
1295 void
1296 free_pam_environment(char **env)
1297 {
1298 	char **envp;
1299 
1300 	if (env == NULL)
1301 		return;
1302 
1303 	for (envp = env; *envp; envp++)
1304 		free(*envp);
1305 	free(env);
1306 }
1307 
1308 /*
1309  * "Blind" conversation function for password authentication.  Assumes that
1310  * echo-off prompts are for the password and stores messages for later
1311  * display.
1312  */
1313 static int
1314 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
1315     struct pam_response **resp, void *data)
1316 {
1317 	struct pam_response *reply;
1318 	int r, i;
1319 	size_t len;
1320 
1321 	debug3("PAM: %s called with %d messages", __func__, n);
1322 
1323 	*resp = NULL;
1324 
1325 	if (n <= 0 || n > PAM_MAX_NUM_MSG)
1326 		return (PAM_CONV_ERR);
1327 
1328 	if ((reply = calloc(n, sizeof(*reply))) == NULL)
1329 		return (PAM_CONV_ERR);
1330 
1331 	for (i = 0; i < n; ++i) {
1332 		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1333 		case PAM_PROMPT_ECHO_OFF:
1334 			if (sshpam_password == NULL)
1335 				goto fail;
1336 			if ((reply[i].resp = strdup(sshpam_password)) == NULL)
1337 				goto fail;
1338 			reply[i].resp_retcode = PAM_SUCCESS;
1339 			break;
1340 		case PAM_ERROR_MSG:
1341 		case PAM_TEXT_INFO:
1342 			len = strlen(PAM_MSG_MEMBER(msg, i, msg));
1343 			if (len > 0) {
1344 				if ((r = sshbuf_putf(loginmsg, "%s\n",
1345 				    PAM_MSG_MEMBER(msg, i, msg))) != 0)
1346 					fatal("%s: buffer error: %s",
1347 					    __func__, ssh_err(r));
1348 			}
1349 			if ((reply[i].resp = strdup("")) == NULL)
1350 				goto fail;
1351 			reply[i].resp_retcode = PAM_SUCCESS;
1352 			break;
1353 		default:
1354 			goto fail;
1355 		}
1356 	}
1357 	*resp = reply;
1358 	return (PAM_SUCCESS);
1359 
1360  fail:
1361 	for(i = 0; i < n; i++) {
1362 		free(reply[i].resp);
1363 	}
1364 	free(reply);
1365 	return (PAM_CONV_ERR);
1366 }
1367 
1368 static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
1369 
1370 /*
1371  * Attempt password authentication via PAM
1372  */
1373 int
1374 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
1375 {
1376 	int flags = (options.permit_empty_passwd == 0 ?
1377 	    PAM_DISALLOW_NULL_AUTHTOK : 0);
1378 	char *fake = NULL;
1379 
1380 	if (!options.use_pam || sshpam_handle == NULL)
1381 		fatal("PAM: %s called when PAM disabled or failed to "
1382 		    "initialise.", __func__);
1383 
1384 	sshpam_password = password;
1385 	sshpam_authctxt = authctxt;
1386 
1387 	/*
1388 	 * If the user logging in is invalid, or is root but is not permitted
1389 	 * by PermitRootLogin, use an invalid password to prevent leaking
1390 	 * information via timing (eg if the PAM config has a delay on fail).
1391 	 */
1392 	if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
1393 	    options.permit_root_login != PERMIT_YES))
1394 		sshpam_password = fake = fake_password(password);
1395 
1396 	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1397 	    (const void *)&passwd_conv);
1398 	if (sshpam_err != PAM_SUCCESS)
1399 		fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
1400 		    pam_strerror(sshpam_handle, sshpam_err));
1401 
1402 	sshpam_err = pam_authenticate(sshpam_handle, flags);
1403 	sshpam_password = NULL;
1404 	free(fake);
1405 	if (sshpam_err == PAM_MAXTRIES)
1406 		sshpam_set_maxtries_reached(1);
1407 	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
1408 		debug("PAM: password authentication accepted for %.100s",
1409 		    authctxt->user);
1410 		return 1;
1411 	} else {
1412 		debug("PAM: password authentication failed for %.100s: %s",
1413 		    authctxt->valid ? authctxt->user : "an illegal user",
1414 		    pam_strerror(sshpam_handle, sshpam_err));
1415 		return 0;
1416 	}
1417 }
1418 
1419 int
1420 sshpam_get_maxtries_reached(void)
1421 {
1422 	return sshpam_maxtries_reached;
1423 }
1424 
1425 void
1426 sshpam_set_maxtries_reached(int reached)
1427 {
1428 	if (reached == 0 || sshpam_maxtries_reached)
1429 		return;
1430 	sshpam_maxtries_reached = 1;
1431 	options.password_authentication = 0;
1432 	options.kbd_interactive_authentication = 0;
1433 }
1434 #endif /* USE_PAM */
1435