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