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