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