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