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