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