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