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