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