Merge from vendor branch OPENSSH:
[dragonfly.git] / crypto / openssh-4 / auth-pam.c
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 Exp $ */
49 #include "includes.h"
50 RCSID("$Id: auth-pam.c,v 1.128 2006/01/29 05:46:13 dtucker Exp $");
51
52 #ifdef USE_PAM
53 #if defined(HAVE_SECURITY_PAM_APPL_H)
54 #include <security/pam_appl.h>
55 #elif defined (HAVE_PAM_PAM_APPL_H)
56 #include <pam/pam_appl.h>
57 #endif
58
59 /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
60 #ifdef PAM_SUN_CODEBASE
61 # define sshpam_const           /* Solaris, HP-UX, AIX */
62 #else
63 # define sshpam_const   const   /* LinuxPAM, OpenPAM */
64 #endif
65
66 #include "auth.h"
67 #include "auth-pam.h"
68 #include "buffer.h"
69 #include "bufaux.h"
70 #include "canohost.h"
71 #include "log.h"
72 #include "monitor_wrap.h"
73 #include "msg.h"
74 #include "packet.h"
75 #include "misc.h"
76 #include "servconf.h"
77 #include "ssh2.h"
78 #include "xmalloc.h"
79 #include "auth-options.h"
80
81 extern ServerOptions options;
82 extern Buffer loginmsg;
83 extern int compat20;
84 extern u_int utmp_len;
85
86 /* so we don't silently change behaviour */
87 #ifdef USE_POSIX_THREADS
88 # error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
89 #endif
90
91 /*
92  * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
93  * and generally a bad idea.  Use at own risk and do not expect support if
94  * this breaks.
95  */
96 #ifdef UNSUPPORTED_POSIX_THREADS_HACK
97 #include <pthread.h>
98 /*
99  * Avoid namespace clash when *not* using pthreads for systems *with*
100  * pthreads, which unconditionally define pthread_t via sys/types.h
101  * (e.g. Linux)
102  */
103 typedef pthread_t sp_pthread_t;
104 #else
105 typedef pid_t sp_pthread_t;
106 #endif
107
108 struct pam_ctxt {
109         sp_pthread_t     pam_thread;
110         int              pam_psock;
111         int              pam_csock;
112         int              pam_done;
113 };
114
115 static void sshpam_free_ctx(void *);
116 static struct pam_ctxt *cleanup_ctxt;
117
118 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
119 /*
120  * Simulate threads with processes.
121  */
122
123 static int sshpam_thread_status = -1;
124 static mysig_t sshpam_oldsig;
125
126 static void
127 sshpam_sigchld_handler(int sig)
128 {
129         signal(SIGCHLD, SIG_DFL);
130         if (cleanup_ctxt == NULL)
131                 return; /* handler called after PAM cleanup, shouldn't happen */
132         if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
133             <= 0) {
134                 /* PAM thread has not exitted, privsep slave must have */
135                 kill(cleanup_ctxt->pam_thread, SIGTERM);
136                 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0)
137                     <= 0)
138                         return; /* could not wait */
139         }
140         if (WIFSIGNALED(sshpam_thread_status) &&
141             WTERMSIG(sshpam_thread_status) == SIGTERM)
142                 return; /* terminated by pthread_cancel */
143         if (!WIFEXITED(sshpam_thread_status))
144                 fatal("PAM: authentication thread exited unexpectedly");
145         if (WEXITSTATUS(sshpam_thread_status) != 0)
146                 fatal("PAM: authentication thread exited uncleanly");
147 }
148
149 static void
150 pthread_exit(void *value __unused)
151 {
152         _exit(0);
153 }
154
155 static int
156 pthread_create(sp_pthread_t *thread, const void *attr __unused,
157     void *(*thread_start)(void *), void *arg)
158 {
159         pid_t pid;
160         struct pam_ctxt *ctx = arg;
161
162         sshpam_thread_status = -1;
163         switch ((pid = fork())) {
164         case -1:
165                 error("fork(): %s", strerror(errno));
166                 return (-1);
167         case 0:
168                 close(ctx->pam_psock);
169                 ctx->pam_psock = -1;
170                 thread_start(arg);
171                 _exit(1);
172         default:
173                 *thread = pid;
174                 close(ctx->pam_csock);
175                 ctx->pam_csock = -1;
176                 sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
177                 return (0);
178         }
179 }
180
181 static int
182 pthread_cancel(sp_pthread_t thread)
183 {
184         signal(SIGCHLD, sshpam_oldsig);
185         return (kill(thread, SIGTERM));
186 }
187
188 static int
189 pthread_join(sp_pthread_t thread, void **value __unused)
190 {
191         int status;
192
193         if (sshpam_thread_status != -1)
194                 return (sshpam_thread_status);
195         signal(SIGCHLD, sshpam_oldsig);
196         waitpid(thread, &status, 0);
197         return (status);
198 }
199 #endif
200
201
202 static pam_handle_t *sshpam_handle = NULL;
203 static int sshpam_err = 0;
204 static int sshpam_authenticated = 0;
205 static int sshpam_session_open = 0;
206 static int sshpam_cred_established = 0;
207 static int sshpam_account_status = -1;
208 static char **sshpam_env = NULL;
209 static Authctxt *sshpam_authctxt = NULL;
210 static const char *sshpam_password = NULL;
211 static char badpw[] = "\b\n\r\177INCORRECT";
212
213 /* Some PAM implementations don't implement this */
214 #ifndef HAVE_PAM_GETENVLIST
215 static char **
216 pam_getenvlist(pam_handle_t *pamh)
217 {
218         /*
219          * XXX - If necessary, we can still support envrionment passing
220          * for platforms without pam_getenvlist by searching for known
221          * env vars (e.g. KRB5CCNAME) from the PAM environment.
222          */
223          return NULL;
224 }
225 #endif
226
227 /*
228  * Some platforms, notably Solaris, do not enforce password complexity
229  * rules during pam_chauthtok() if the real uid of the calling process
230  * is 0, on the assumption that it's being called by "passwd" run by root.
231  * This wraps pam_chauthtok and sets/restore the real uid so PAM will do
232  * the right thing.
233  */
234 #ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
235 static int
236 sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
237 {
238         int result;
239
240         if (sshpam_authctxt == NULL)
241                 fatal("PAM: sshpam_authctxt not initialized");
242         if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
243                 fatal("%s: setreuid failed: %s", __func__, strerror(errno));
244         result = pam_chauthtok(pamh, flags);
245         if (setreuid(0, -1) == -1)
246                 fatal("%s: setreuid failed: %s", __func__, strerror(errno));
247         return result;
248 }
249 # define pam_chauthtok(a,b)     (sshpam_chauthtok_ruid((a), (b)))
250 #endif
251
252 void
253 sshpam_password_change_required(int reqd)
254 {
255         debug3("%s %d", __func__, reqd);
256         if (sshpam_authctxt == NULL)
257                 fatal("%s: PAM authctxt not initialized", __func__);
258         sshpam_authctxt->force_pwchange = reqd;
259         if (reqd) {
260                 no_port_forwarding_flag |= 2;
261                 no_agent_forwarding_flag |= 2;
262                 no_x11_forwarding_flag |= 2;
263         } else {
264                 no_port_forwarding_flag &= ~2;
265                 no_agent_forwarding_flag &= ~2;
266                 no_x11_forwarding_flag &= ~2;
267         }
268 }
269
270 /* Import regular and PAM environment from subprocess */
271 static void
272 import_environments(Buffer *b)
273 {
274         char *env;
275         u_int i, num_env;
276         int err;
277
278         debug3("PAM: %s entering", __func__);
279
280 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
281         /* Import variables set by do_pam_account */
282         sshpam_account_status = buffer_get_int(b);
283         sshpam_password_change_required(buffer_get_int(b));
284
285         /* Import environment from subprocess */
286         num_env = buffer_get_int(b);
287         sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env));
288         debug3("PAM: num env strings %d", num_env);
289         for(i = 0; i < num_env; i++)
290                 sshpam_env[i] = buffer_get_string(b, NULL);
291
292         sshpam_env[num_env] = NULL;
293
294         /* Import PAM environment from subprocess */
295         num_env = buffer_get_int(b);
296         debug("PAM: num PAM env strings %d", num_env);
297         for(i = 0; i < num_env; i++) {
298                 env = buffer_get_string(b, NULL);
299
300 #ifdef HAVE_PAM_PUTENV
301                 /* Errors are not fatal here */
302                 if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
303                         error("PAM: pam_putenv: %s",
304                             pam_strerror(sshpam_handle, sshpam_err));
305                 }
306 #endif
307         }
308 #endif
309 }
310
311 /*
312  * Conversation function for authentication thread.
313  */
314 static int
315 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
316     struct pam_response **resp, void *data)
317 {
318         Buffer buffer;
319         struct pam_ctxt *ctxt;
320         struct pam_response *reply;
321         int i;
322
323         debug3("PAM: %s entering, %d messages", __func__, n);
324         *resp = NULL;
325
326         if (data == NULL) {
327                 error("PAM: conversation function passed a null context");
328                 return (PAM_CONV_ERR);
329         }
330         ctxt = data;
331         if (n <= 0 || n > PAM_MAX_NUM_MSG)
332                 return (PAM_CONV_ERR);
333
334         if ((reply = malloc(n * sizeof(*reply))) == NULL)
335                 return (PAM_CONV_ERR);
336         memset(reply, 0, n * sizeof(*reply));
337
338         buffer_init(&buffer);
339         for (i = 0; i < n; ++i) {
340                 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
341                 case PAM_PROMPT_ECHO_OFF:
342                         buffer_put_cstring(&buffer,
343                             PAM_MSG_MEMBER(msg, i, msg));
344                         if (ssh_msg_send(ctxt->pam_csock,
345                             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
346                                 goto fail;
347                         if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
348                                 goto fail;
349                         if (buffer_get_char(&buffer) != PAM_AUTHTOK)
350                                 goto fail;
351                         reply[i].resp = buffer_get_string(&buffer, NULL);
352                         break;
353                 case PAM_PROMPT_ECHO_ON:
354                         buffer_put_cstring(&buffer,
355                             PAM_MSG_MEMBER(msg, i, msg));
356                         if (ssh_msg_send(ctxt->pam_csock,
357                             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
358                                 goto fail;
359                         if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
360                                 goto fail;
361                         if (buffer_get_char(&buffer) != PAM_AUTHTOK)
362                                 goto fail;
363                         reply[i].resp = buffer_get_string(&buffer, NULL);
364                         break;
365                 case PAM_ERROR_MSG:
366                         buffer_put_cstring(&buffer,
367                             PAM_MSG_MEMBER(msg, i, msg));
368                         if (ssh_msg_send(ctxt->pam_csock,
369                             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
370                                 goto fail;
371                         break;
372                 case PAM_TEXT_INFO:
373                         buffer_put_cstring(&buffer,
374                             PAM_MSG_MEMBER(msg, i, msg));
375                         if (ssh_msg_send(ctxt->pam_csock,
376                             PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
377                                 goto fail;
378                         break;
379                 default:
380                         goto fail;
381                 }
382                 buffer_clear(&buffer);
383         }
384         buffer_free(&buffer);
385         *resp = reply;
386         return (PAM_SUCCESS);
387
388  fail:
389         for(i = 0; i < n; i++) {
390                 if (reply[i].resp != NULL)
391                         xfree(reply[i].resp);
392         }
393         xfree(reply);
394         buffer_free(&buffer);
395         return (PAM_CONV_ERR);
396 }
397
398 /*
399  * Authentication thread.
400  */
401 static void *
402 sshpam_thread(void *ctxtp)
403 {
404         struct pam_ctxt *ctxt = ctxtp;
405         Buffer buffer;
406         struct pam_conv sshpam_conv;
407         int flags = (options.permit_empty_passwd == 0 ?
408             PAM_DISALLOW_NULL_AUTHTOK : 0);
409 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
410         extern char **environ;
411         char **env_from_pam;
412         u_int i;
413         const char *pam_user;
414         const char **ptr_pam_user = &pam_user;
415
416         pam_get_item(sshpam_handle, PAM_USER,
417             (sshpam_const void **)ptr_pam_user);
418         environ[0] = NULL;
419
420         if (sshpam_authctxt != NULL) {
421                 setproctitle("%s [pam]",
422                     sshpam_authctxt->valid ? pam_user : "unknown");
423         }
424 #endif
425
426         sshpam_conv.conv = sshpam_thread_conv;
427         sshpam_conv.appdata_ptr = ctxt;
428
429         if (sshpam_authctxt == NULL)
430                 fatal("%s: PAM authctxt not initialized", __func__);
431
432         buffer_init(&buffer);
433         sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
434             (const void *)&sshpam_conv);
435         if (sshpam_err != PAM_SUCCESS)
436                 goto auth_fail;
437         sshpam_err = pam_authenticate(sshpam_handle, flags);
438         if (sshpam_err != PAM_SUCCESS)
439                 goto auth_fail;
440
441         if (compat20) {
442                 if (!do_pam_account())
443                         goto auth_fail;
444                 if (sshpam_authctxt->force_pwchange) {
445                         sshpam_err = pam_chauthtok(sshpam_handle,
446                             PAM_CHANGE_EXPIRED_AUTHTOK);
447                         if (sshpam_err != PAM_SUCCESS)
448                                 goto auth_fail;
449                         sshpam_password_change_required(0);
450                 }
451         }
452
453         buffer_put_cstring(&buffer, "OK");
454
455 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
456         /* Export variables set by do_pam_account */
457         buffer_put_int(&buffer, sshpam_account_status);
458         buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
459
460         /* Export any environment strings set in child */
461         for(i = 0; environ[i] != NULL; i++)
462                 ; /* Count */
463         buffer_put_int(&buffer, i);
464         for(i = 0; environ[i] != NULL; i++)
465                 buffer_put_cstring(&buffer, environ[i]);
466
467         /* Export any environment strings set by PAM in child */
468         env_from_pam = pam_getenvlist(sshpam_handle);
469         for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
470                 ; /* Count */
471         buffer_put_int(&buffer, i);
472         for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
473                 buffer_put_cstring(&buffer, env_from_pam[i]);
474 #endif /* UNSUPPORTED_POSIX_THREADS_HACK */
475
476         /* XXX - can't do much about an error here */
477         ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
478         buffer_free(&buffer);
479         pthread_exit(NULL);
480
481  auth_fail:
482         buffer_put_cstring(&buffer,
483             pam_strerror(sshpam_handle, sshpam_err));
484         /* XXX - can't do much about an error here */
485         ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
486         buffer_free(&buffer);
487         pthread_exit(NULL);
488
489         return (NULL); /* Avoid warning for non-pthread case */
490 }
491
492 void
493 sshpam_thread_cleanup(void)
494 {
495         struct pam_ctxt *ctxt = cleanup_ctxt;
496
497         debug3("PAM: %s entering", __func__);
498         if (ctxt != NULL && ctxt->pam_thread != 0) {
499                 pthread_cancel(ctxt->pam_thread);
500                 pthread_join(ctxt->pam_thread, NULL);
501                 close(ctxt->pam_psock);
502                 close(ctxt->pam_csock);
503                 memset(ctxt, 0, sizeof(*ctxt));
504                 cleanup_ctxt = NULL;
505         }
506 }
507
508 static int
509 sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
510     struct pam_response **resp, void *data)
511 {
512         debug3("PAM: %s entering, %d messages", __func__, n);
513         return (PAM_CONV_ERR);
514 }
515
516 static struct pam_conv null_conv = { sshpam_null_conv, NULL };
517
518 static int
519 sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
520     struct pam_response **resp, void *data)
521 {
522         struct pam_response *reply;
523         int i;
524         size_t len;
525
526         debug3("PAM: %s called with %d messages", __func__, n);
527         *resp = NULL;
528
529         if (n <= 0 || n > PAM_MAX_NUM_MSG)
530                 return (PAM_CONV_ERR);
531
532         if ((reply = malloc(n * sizeof(*reply))) == NULL)
533                 return (PAM_CONV_ERR);
534         memset(reply, 0, n * sizeof(*reply));
535
536         for (i = 0; i < n; ++i) {
537                 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
538                 case PAM_ERROR_MSG:
539                 case PAM_TEXT_INFO:
540                         len = strlen(PAM_MSG_MEMBER(msg, i, msg));
541                         buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
542                         buffer_append(&loginmsg, "\n", 1 );
543                         reply[i].resp_retcode = PAM_SUCCESS;
544                         break;
545                 default:
546                         goto fail;
547                 }
548         }
549         *resp = reply;
550         return (PAM_SUCCESS);
551
552  fail:
553         for(i = 0; i < n; i++) {
554                 if (reply[i].resp != NULL)
555                         xfree(reply[i].resp);
556         }
557         xfree(reply);
558         return (PAM_CONV_ERR);
559 }
560
561 static struct pam_conv store_conv = { sshpam_store_conv, NULL };
562
563 void
564 sshpam_cleanup(void)
565 {
566         debug("PAM: cleanup");
567         if (sshpam_handle == NULL)
568                 return;
569         pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
570         if (sshpam_cred_established) {
571                 pam_setcred(sshpam_handle, PAM_DELETE_CRED);
572                 sshpam_cred_established = 0;
573         }
574         if (sshpam_session_open) {
575                 pam_close_session(sshpam_handle, PAM_SILENT);
576                 sshpam_session_open = 0;
577         }
578         sshpam_authenticated = 0;
579         pam_end(sshpam_handle, sshpam_err);
580         sshpam_handle = NULL;
581 }
582
583 static int
584 sshpam_init(Authctxt *authctxt)
585 {
586         extern char *__progname;
587         const char *pam_rhost, *pam_user, *user = authctxt->user;
588         const char **ptr_pam_user = &pam_user;
589
590         if (sshpam_handle != NULL) {
591                 /* We already have a PAM context; check if the user matches */
592                 sshpam_err = pam_get_item(sshpam_handle,
593                     PAM_USER, (sshpam_const void **)ptr_pam_user);
594                 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
595                         return (0);
596                 pam_end(sshpam_handle, sshpam_err);
597                 sshpam_handle = NULL;
598         }
599         debug("PAM: initializing for \"%s\"", user);
600         sshpam_err =
601             pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
602         sshpam_authctxt = authctxt;
603
604         if (sshpam_err != PAM_SUCCESS) {
605                 pam_end(sshpam_handle, sshpam_err);
606                 sshpam_handle = NULL;
607                 return (-1);
608         }
609         pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns);
610         debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
611         sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
612         if (sshpam_err != PAM_SUCCESS) {
613                 pam_end(sshpam_handle, sshpam_err);
614                 sshpam_handle = NULL;
615                 return (-1);
616         }
617 #ifdef PAM_TTY_KLUDGE
618         /*
619          * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
620          * sshd doesn't set the tty until too late in the auth process and
621          * may not even set one (for tty-less connections)
622          */
623         debug("PAM: setting PAM_TTY to \"ssh\"");
624         sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
625         if (sshpam_err != PAM_SUCCESS) {
626                 pam_end(sshpam_handle, sshpam_err);
627                 sshpam_handle = NULL;
628                 return (-1);
629         }
630 #endif
631         return (0);
632 }
633
634 static void *
635 sshpam_init_ctx(Authctxt *authctxt)
636 {
637         struct pam_ctxt *ctxt;
638         int socks[2];
639
640         debug3("PAM: %s entering", __func__);
641         /* Refuse to start if we don't have PAM enabled */
642         if (!options.use_pam)
643                 return NULL;
644
645         /* Initialize PAM */
646         if (sshpam_init(authctxt) == -1) {
647                 error("PAM: initialization failed");
648                 return (NULL);
649         }
650
651         ctxt = xmalloc(sizeof *ctxt);
652         memset(ctxt, 0, sizeof(*ctxt));
653
654         /* Start the authentication thread */
655         if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
656                 error("PAM: failed create sockets: %s", strerror(errno));
657                 xfree(ctxt);
658                 return (NULL);
659         }
660         ctxt->pam_psock = socks[0];
661         ctxt->pam_csock = socks[1];
662         if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
663                 error("PAM: failed to start authentication thread: %s",
664                     strerror(errno));
665                 close(socks[0]);
666                 close(socks[1]);
667                 xfree(ctxt);
668                 return (NULL);
669         }
670         cleanup_ctxt = ctxt;
671         return (ctxt);
672 }
673
674 static int
675 sshpam_query(void *ctx, char **name, char **info,
676     u_int *num, char ***prompts, u_int **echo_on)
677 {
678         Buffer buffer;
679         struct pam_ctxt *ctxt = ctx;
680         size_t plen;
681         u_char type;
682         char *msg;
683         size_t len, mlen;
684
685         debug3("PAM: %s entering", __func__);
686         buffer_init(&buffer);
687         *name = xstrdup("");
688         *info = xstrdup("");
689         *prompts = xmalloc(sizeof(char *));
690         **prompts = NULL;
691         plen = 0;
692         *echo_on = xmalloc(sizeof(u_int));
693         while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
694                 type = buffer_get_char(&buffer);
695                 msg = buffer_get_string(&buffer, NULL);
696                 mlen = strlen(msg);
697                 switch (type) {
698                 case PAM_PROMPT_ECHO_ON:
699                 case PAM_PROMPT_ECHO_OFF:
700                         *num = 1;
701                         len = plen + mlen + 1;
702                         **prompts = xrealloc(**prompts, len);
703                         strlcpy(**prompts + plen, msg, len - plen);
704                         plen += mlen;
705                         **echo_on = (type == PAM_PROMPT_ECHO_ON);
706                         xfree(msg);
707                         return (0);
708                 case PAM_ERROR_MSG:
709                 case PAM_TEXT_INFO:
710                         /* accumulate messages */
711                         len = plen + mlen + 2;
712                         **prompts = xrealloc(**prompts, len);
713                         strlcpy(**prompts + plen, msg, len - plen);
714                         plen += mlen;
715                         strlcat(**prompts + plen, "\n", len - plen);
716                         plen++;
717                         xfree(msg);
718                         break;
719                 case PAM_AUTH_ERR:
720                         debug3("PAM: PAM_AUTH_ERR");
721                         if (**prompts != NULL && strlen(**prompts) != 0) {
722                                 *info = **prompts;
723                                 **prompts = NULL;
724                                 *num = 0;
725                                 **echo_on = 0;
726                                 ctxt->pam_done = -1;
727                                 return 0;
728                         }
729                         /* FALLTHROUGH */
730                 case PAM_SUCCESS:
731                         if (**prompts != NULL) {
732                                 /* drain any accumulated messages */
733                                 debug("PAM: %s", **prompts);
734                                 buffer_append(&loginmsg, **prompts,
735                                     strlen(**prompts));
736                                 xfree(**prompts);
737                                 **prompts = NULL;
738                         }
739                         if (type == PAM_SUCCESS) {
740                                 if (!sshpam_authctxt->valid ||
741                                     (sshpam_authctxt->pw->pw_uid == 0 &&
742                                     options.permit_root_login != PERMIT_YES))
743                                         fatal("Internal error: PAM auth "
744                                             "succeeded when it should have "
745                                             "failed");
746                                 import_environments(&buffer);
747                                 *num = 0;
748                                 **echo_on = 0;
749                                 ctxt->pam_done = 1;
750                                 xfree(msg);
751                                 return (0);
752                         }
753                         error("PAM: %s for %s%.100s from %.100s", msg,
754                             sshpam_authctxt->valid ? "" : "illegal user ",
755                             sshpam_authctxt->user,
756                             get_remote_name_or_ip(utmp_len, options.use_dns));
757                         /* FALLTHROUGH */
758                 default:
759                         *num = 0;
760                         **echo_on = 0;
761                         xfree(msg);
762                         ctxt->pam_done = -1;
763                         return (-1);
764                 }
765         }
766         return (-1);
767 }
768
769 /* XXX - see also comment in auth-chall.c:verify_response */
770 static int
771 sshpam_respond(void *ctx, u_int num, char **resp)
772 {
773         Buffer buffer;
774         struct pam_ctxt *ctxt = ctx;
775
776         debug2("PAM: %s entering, %u responses", __func__, num);
777         switch (ctxt->pam_done) {
778         case 1:
779                 sshpam_authenticated = 1;
780                 return (0);
781         case 0:
782                 break;
783         default:
784                 return (-1);
785         }
786         if (num != 1) {
787                 error("PAM: expected one response, got %u", num);
788                 return (-1);
789         }
790         buffer_init(&buffer);
791         if (sshpam_authctxt->valid &&
792             (sshpam_authctxt->pw->pw_uid != 0 ||
793             options.permit_root_login == PERMIT_YES))
794                 buffer_put_cstring(&buffer, *resp);
795         else
796                 buffer_put_cstring(&buffer, badpw);
797         if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
798                 buffer_free(&buffer);
799                 return (-1);
800         }
801         buffer_free(&buffer);
802         return (1);
803 }
804
805 static void
806 sshpam_free_ctx(void *ctxtp)
807 {
808         struct pam_ctxt *ctxt = ctxtp;
809
810         debug3("PAM: %s entering", __func__);
811         sshpam_thread_cleanup();
812         xfree(ctxt);
813         /*
814          * We don't call sshpam_cleanup() here because we may need the PAM
815          * handle at a later stage, e.g. when setting up a session.  It's
816          * still on the cleanup list, so pam_end() *will* be called before
817          * the server process terminates.
818          */
819 }
820
821 KbdintDevice sshpam_device = {
822         "pam",
823         sshpam_init_ctx,
824         sshpam_query,
825         sshpam_respond,
826         sshpam_free_ctx
827 };
828
829 KbdintDevice mm_sshpam_device = {
830         "pam",
831         mm_sshpam_init_ctx,
832         mm_sshpam_query,
833         mm_sshpam_respond,
834         mm_sshpam_free_ctx
835 };
836
837 /*
838  * This replaces auth-pam.c
839  */
840 void
841 start_pam(Authctxt *authctxt)
842 {
843         if (!options.use_pam)
844                 fatal("PAM: initialisation requested when UsePAM=no");
845
846         if (sshpam_init(authctxt) == -1)
847                 fatal("PAM: initialisation failed");
848 }
849
850 void
851 finish_pam(void)
852 {
853         sshpam_cleanup();
854 }
855
856 u_int
857 do_pam_account(void)
858 {
859         debug("%s: called", __func__);
860         if (sshpam_account_status != -1)
861                 return (sshpam_account_status);
862
863         sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
864         debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
865             pam_strerror(sshpam_handle, sshpam_err));
866
867         if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
868                 sshpam_account_status = 0;
869                 return (sshpam_account_status);
870         }
871
872         if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
873                 sshpam_password_change_required(1);
874
875         sshpam_account_status = 1;
876         return (sshpam_account_status);
877 }
878
879 void
880 do_pam_set_tty(const char *tty)
881 {
882         if (tty != NULL) {
883                 debug("PAM: setting PAM_TTY to \"%s\"", tty);
884                 sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
885                 if (sshpam_err != PAM_SUCCESS)
886                         fatal("PAM: failed to set PAM_TTY: %s",
887                             pam_strerror(sshpam_handle, sshpam_err));
888         }
889 }
890
891 void
892 do_pam_setcred(int init)
893 {
894         sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
895             (const void *)&store_conv);
896         if (sshpam_err != PAM_SUCCESS)
897                 fatal("PAM: failed to set PAM_CONV: %s",
898                     pam_strerror(sshpam_handle, sshpam_err));
899         if (init) {
900                 debug("PAM: establishing credentials");
901                 sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
902         } else {
903                 debug("PAM: reinitializing credentials");
904                 sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
905         }
906         if (sshpam_err == PAM_SUCCESS) {
907                 sshpam_cred_established = 1;
908                 return;
909         }
910         if (sshpam_authenticated)
911                 fatal("PAM: pam_setcred(): %s",
912                     pam_strerror(sshpam_handle, sshpam_err));
913         else
914                 debug("PAM: pam_setcred(): %s",
915                     pam_strerror(sshpam_handle, sshpam_err));
916 }
917
918 static int
919 sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
920     struct pam_response **resp, void *data)
921 {
922         char input[PAM_MAX_MSG_SIZE];
923         struct pam_response *reply;
924         int i;
925
926         debug3("PAM: %s called with %d messages", __func__, n);
927
928         *resp = NULL;
929
930         if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
931                 return (PAM_CONV_ERR);
932
933         if ((reply = malloc(n * sizeof(*reply))) == NULL)
934                 return (PAM_CONV_ERR);
935         memset(reply, 0, n * sizeof(*reply));
936
937         for (i = 0; i < n; ++i) {
938                 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
939                 case PAM_PROMPT_ECHO_OFF:
940                         reply[i].resp =
941                             read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
942                             RP_ALLOW_STDIN);
943                         reply[i].resp_retcode = PAM_SUCCESS;
944                         break;
945                 case PAM_PROMPT_ECHO_ON:
946                         fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
947                         fgets(input, sizeof input, stdin);
948                         if ((reply[i].resp = strdup(input)) == NULL)
949                                 goto fail;
950                         reply[i].resp_retcode = PAM_SUCCESS;
951                         break;
952                 case PAM_ERROR_MSG:
953                 case PAM_TEXT_INFO:
954                         fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
955                         reply[i].resp_retcode = PAM_SUCCESS;
956                         break;
957                 default:
958                         goto fail;
959                 }
960         }
961         *resp = reply;
962         return (PAM_SUCCESS);
963
964  fail:
965         for(i = 0; i < n; i++) {
966                 if (reply[i].resp != NULL)
967                         xfree(reply[i].resp);
968         }
969         xfree(reply);
970         return (PAM_CONV_ERR);
971 }
972
973 static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
974
975 /*
976  * XXX this should be done in the authentication phase, but ssh1 doesn't
977  * support that
978  */
979 void
980 do_pam_chauthtok(void)
981 {
982         if (use_privsep)
983                 fatal("Password expired (unable to change with privsep)");
984         sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
985             (const void *)&tty_conv);
986         if (sshpam_err != PAM_SUCCESS)
987                 fatal("PAM: failed to set PAM_CONV: %s",
988                     pam_strerror(sshpam_handle, sshpam_err));
989         debug("PAM: changing password");
990         sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
991         if (sshpam_err != PAM_SUCCESS)
992                 fatal("PAM: pam_chauthtok(): %s",
993                     pam_strerror(sshpam_handle, sshpam_err));
994 }
995
996 void
997 do_pam_session(void)
998 {
999         debug3("PAM: opening session");
1000         sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1001             (const void *)&store_conv);
1002         if (sshpam_err != PAM_SUCCESS)
1003                 fatal("PAM: failed to set PAM_CONV: %s",
1004                     pam_strerror(sshpam_handle, sshpam_err));
1005         sshpam_err = pam_open_session(sshpam_handle, 0);
1006         if (sshpam_err == PAM_SUCCESS)
1007                 sshpam_session_open = 1;
1008         else {
1009                 sshpam_session_open = 0;
1010                 disable_forwarding();
1011                 error("PAM: pam_open_session(): %s",
1012                     pam_strerror(sshpam_handle, sshpam_err));
1013         }
1014
1015 }
1016
1017 int
1018 is_pam_session_open(void)
1019 {
1020         return sshpam_session_open;
1021 }
1022
1023 /*
1024  * Set a PAM environment string. We need to do this so that the session
1025  * modules can handle things like Kerberos/GSI credentials that appear
1026  * during the ssh authentication process.
1027  */
1028 int
1029 do_pam_putenv(char *name, char *value)
1030 {
1031         int ret = 1;
1032 #ifdef HAVE_PAM_PUTENV
1033         char *compound;
1034         size_t len;
1035
1036         len = strlen(name) + strlen(value) + 2;
1037         compound = xmalloc(len);
1038
1039         snprintf(compound, len, "%s=%s", name, value);
1040         ret = pam_putenv(sshpam_handle, compound);
1041         xfree(compound);
1042 #endif
1043
1044         return (ret);
1045 }
1046
1047 char **
1048 fetch_pam_child_environment(void)
1049 {
1050         return sshpam_env;
1051 }
1052
1053 char **
1054 fetch_pam_environment(void)
1055 {
1056         return (pam_getenvlist(sshpam_handle));
1057 }
1058
1059 void
1060 free_pam_environment(char **env)
1061 {
1062         char **envp;
1063
1064         if (env == NULL)
1065                 return;
1066
1067         for (envp = env; *envp; envp++)
1068                 xfree(*envp);
1069         xfree(env);
1070 }
1071
1072 /*
1073  * "Blind" conversation function for password authentication.  Assumes that
1074  * echo-off prompts are for the password and stores messages for later
1075  * display.
1076  */
1077 static int
1078 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
1079     struct pam_response **resp, void *data)
1080 {
1081         struct pam_response *reply;
1082         int i;
1083         size_t len;
1084
1085         debug3("PAM: %s called with %d messages", __func__, n);
1086
1087         *resp = NULL;
1088
1089         if (n <= 0 || n > PAM_MAX_NUM_MSG)
1090                 return (PAM_CONV_ERR);
1091
1092         if ((reply = malloc(n * sizeof(*reply))) == NULL)
1093                 return (PAM_CONV_ERR);
1094         memset(reply, 0, n * sizeof(*reply));
1095
1096         for (i = 0; i < n; ++i) {
1097                 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1098                 case PAM_PROMPT_ECHO_OFF:
1099                         if (sshpam_password == NULL)
1100                                 goto fail;
1101                         if ((reply[i].resp = strdup(sshpam_password)) == NULL)
1102                                 goto fail;
1103                         reply[i].resp_retcode = PAM_SUCCESS;
1104                         break;
1105                 case PAM_ERROR_MSG:
1106                 case PAM_TEXT_INFO:
1107                         len = strlen(PAM_MSG_MEMBER(msg, i, msg));
1108                         if (len > 0) {
1109                                 buffer_append(&loginmsg,
1110                                     PAM_MSG_MEMBER(msg, i, msg), len);
1111                                 buffer_append(&loginmsg, "\n", 1);
1112                         }
1113                         if ((reply[i].resp = strdup("")) == NULL)
1114                                 goto fail;
1115                         reply[i].resp_retcode = PAM_SUCCESS;
1116                         break;
1117                 default:
1118                         goto fail;
1119                 }
1120         }
1121         *resp = reply;
1122         return (PAM_SUCCESS);
1123
1124  fail:
1125         for(i = 0; i < n; i++) {
1126                 if (reply[i].resp != NULL)
1127                         xfree(reply[i].resp);
1128         }
1129         xfree(reply);
1130         return (PAM_CONV_ERR);
1131 }
1132
1133 static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
1134
1135 /*
1136  * Attempt password authentication via PAM
1137  */
1138 int
1139 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
1140 {
1141         int flags = (options.permit_empty_passwd == 0 ?
1142             PAM_DISALLOW_NULL_AUTHTOK : 0);
1143
1144         if (!options.use_pam || sshpam_handle == NULL)
1145                 fatal("PAM: %s called when PAM disabled or failed to "
1146                     "initialise.", __func__);
1147
1148         sshpam_password = password;
1149         sshpam_authctxt = authctxt;
1150
1151         /*
1152          * If the user logging in is invalid, or is root but is not permitted
1153          * by PermitRootLogin, use an invalid password to prevent leaking
1154          * information via timing (eg if the PAM config has a delay on fail).
1155          */
1156         if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
1157             options.permit_root_login != PERMIT_YES))
1158                 sshpam_password = badpw;
1159
1160         sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1161             (const void *)&passwd_conv);
1162         if (sshpam_err != PAM_SUCCESS)
1163                 fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
1164                     pam_strerror(sshpam_handle, sshpam_err));
1165
1166         sshpam_err = pam_authenticate(sshpam_handle, flags);
1167         sshpam_password = NULL;
1168         if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
1169                 debug("PAM: password authentication accepted for %.100s",
1170                     authctxt->user);
1171                 return 1;
1172         } else {
1173                 debug("PAM: password authentication failed for %.100s: %s",
1174                     authctxt->valid ? authctxt->user : "an illegal user",
1175                     pam_strerror(sshpam_handle, sshpam_err));
1176                 return 0;
1177         }
1178 }
1179 #endif /* USE_PAM */