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