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