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)
88extern 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
127extern ServerOptions options;
128extern struct sshbuf *loginmsg;
129extern 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 */
149typedef pthread_t sp_pthread_t;
150#else
151typedef 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
158struct pam_ctxt {
159	sp_pthread_t	 pam_thread;
160	int		 pam_psock;
161	int		 pam_csock;
162	int		 pam_done;
163};
164
165static void sshpam_free_ctx(void *);
166static struct pam_ctxt *cleanup_ctxt;
167
168#ifndef UNSUPPORTED_POSIX_THREADS_HACK
169/*
170 * Simulate threads with processes.
171 */
172
173static int sshpam_thread_status = -1;
174static sshsig_t sshpam_oldsig;
175
176static void
177sshpam_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
204pthread_exit(void *value)
205{
206	_exit(0);
207}
208
209/* ARGSUSED */
210static int
211pthread_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
236static int
237pthread_cancel(sp_pthread_t thread)
238{
239	ssh_signal(SIGCHLD, sshpam_oldsig);
240	return (kill(thread, SIGTERM));
241}
242
243/* ARGSUSED */
244static int
245pthread_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
262static pam_handle_t *sshpam_handle = NULL;
263static int sshpam_err = 0;
264static int sshpam_authenticated = 0;
265static int sshpam_session_open = 0;
266static int sshpam_cred_established = 0;
267static int sshpam_account_status = -1;
268static int sshpam_maxtries_reached = 0;
269static char **sshpam_env = NULL;
270static Authctxt *sshpam_authctxt = NULL;
271static const char *sshpam_password = NULL;
272static char *sshpam_rhost = NULL;
273static char *sshpam_laddr = NULL;
274
275/* Some PAM implementations don't implement this */
276#ifndef HAVE_PAM_GETENVLIST
277static char **
278pam_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
290static int
291pam_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
305static int
306sshpam_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
322static void
323sshpam_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 */
350static void
351import_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 */
415static int
416sshpam_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 */
498static void *
499sshpam_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
620void
621sshpam_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
636static int
637sshpam_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
644static struct pam_conv null_conv = { sshpam_null_conv, NULL };
645
646static int
647sshpam_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
687static struct pam_conv store_conv = { sshpam_store_conv, NULL };
688
689void
690sshpam_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
711static int
712sshpam_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
799static void
800expose_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
820static void *
821sshpam_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
864static int
865sshpam_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 */
983static char *
984fake_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 */
1003static int
1004sshpam_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
1046static void
1047sshpam_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
1062KbdintDevice sshpam_device = {
1063	"pam",
1064	sshpam_init_ctx,
1065	sshpam_query,
1066	sshpam_respond,
1067	sshpam_free_ctx
1068};
1069
1070KbdintDevice 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 */
1081void
1082start_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
1093void
1094finish_pam(void)
1095{
1096	sshpam_cleanup();
1097}
1098
1099
1100u_int
1101do_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
1125void
1126do_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
1152static int
1153sshpam_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
1206static 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 */
1212void
1213do_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
1229void
1230do_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
1253int
1254is_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 */
1264int
1265do_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
1283char **
1284fetch_pam_child_environment(void)
1285{
1286	return sshpam_env;
1287}
1288
1289char **
1290fetch_pam_environment(void)
1291{
1292	return (pam_getenvlist(sshpam_handle));
1293}
1294
1295void
1296free_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 */
1313static int
1314sshpam_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
1368static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
1369
1370/*
1371 * Attempt password authentication via PAM
1372 */
1373int
1374sshpam_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
1419int
1420sshpam_get_maxtries_reached(void)
1421{
1422	return sshpam_maxtries_reached;
1423}
1424
1425void
1426sshpam_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