auth-pam.c (147005) | auth-pam.c (149753) |
---|---|
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. --- 33 unchanged lines hidden (view full) --- 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" | 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. --- 33 unchanged lines hidden (view full) --- 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" |
50RCSID("$Id: auth-pam.c,v 1.122 2005/05/25 06:18:10 dtucker Exp $"); 51RCSID("$FreeBSD: head/crypto/openssh/auth-pam.c 147005 2005-06-05 15:46:09Z des $"); | 50RCSID("$Id: auth-pam.c,v 1.126 2005/07/17 07:18:50 djm Exp $"); 51RCSID("$FreeBSD: head/crypto/openssh/auth-pam.c 149753 2005-09-03 07:04:25Z des $"); |
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 | 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/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */ 61#ifdef PAM_SUN_CODEBASE 62# define sshpam_const /* Solaris, HP-UX, AIX */ 63#else 64# define sshpam_const const /* LinuxPAM, OpenPAM */ 65#endif 66 |
|
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" --- 44 unchanged lines hidden (view full) --- 112#ifndef UNSUPPORTED_POSIX_THREADS_HACK 113/* 114 * Simulate threads with processes. 115 */ 116 117static int sshpam_thread_status = -1; 118static mysig_t sshpam_oldsig; 119 | 67#include "auth.h" 68#include "auth-pam.h" 69#include "buffer.h" 70#include "bufaux.h" 71#include "canohost.h" 72#include "log.h" 73#include "monitor_wrap.h" 74#include "msg.h" --- 44 unchanged lines hidden (view full) --- 119#ifndef UNSUPPORTED_POSIX_THREADS_HACK 120/* 121 * Simulate threads with processes. 122 */ 123 124static int sshpam_thread_status = -1; 125static mysig_t sshpam_oldsig; 126 |
120static void | 127static void |
121sshpam_sigchld_handler(int sig) 122{ 123 signal(SIGCHLD, SIG_DFL); 124 if (cleanup_ctxt == NULL) 125 return; /* handler called after PAM cleanup, shouldn't happen */ 126 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG) | 128sshpam_sigchld_handler(int sig) 129{ 130 signal(SIGCHLD, SIG_DFL); 131 if (cleanup_ctxt == NULL) 132 return; /* handler called after PAM cleanup, shouldn't happen */ 133 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG) |
127 <= 0) { | 134 <= 0) { |
128 /* PAM thread has not exitted, privsep slave must have */ 129 kill(cleanup_ctxt->pam_thread, SIGTERM); 130 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) 131 <= 0) 132 return; /* could not wait */ 133 } 134 if (WIFSIGNALED(sshpam_thread_status) && 135 WTERMSIG(sshpam_thread_status) == SIGTERM) --- 10 unchanged lines hidden (view full) --- 146 _exit(0); 147} 148 149static int 150pthread_create(sp_pthread_t *thread, const void *attr __unused, 151 void *(*thread_start)(void *), void *arg) 152{ 153 pid_t pid; | 135 /* PAM thread has not exitted, privsep slave must have */ 136 kill(cleanup_ctxt->pam_thread, SIGTERM); 137 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) 138 <= 0) 139 return; /* could not wait */ 140 } 141 if (WIFSIGNALED(sshpam_thread_status) && 142 WTERMSIG(sshpam_thread_status) == SIGTERM) --- 10 unchanged lines hidden (view full) --- 153 _exit(0); 154} 155 156static int 157pthread_create(sp_pthread_t *thread, const void *attr __unused, 158 void *(*thread_start)(void *), void *arg) 159{ 160 pid_t pid; |
161 struct pam_ctxt *ctx = arg; |
|
154 155 sshpam_thread_status = -1; 156 switch ((pid = fork())) { 157 case -1: 158 error("fork(): %s", strerror(errno)); 159 return (-1); 160 case 0: | 162 163 sshpam_thread_status = -1; 164 switch ((pid = fork())) { 165 case -1: 166 error("fork(): %s", strerror(errno)); 167 return (-1); 168 case 0: |
169 close(ctx->pam_psock); 170 ctx->pam_psock = -1; |
|
161 thread_start(arg); 162 _exit(1); 163 default: 164 *thread = pid; | 171 thread_start(arg); 172 _exit(1); 173 default: 174 *thread = pid; |
175 close(ctx->pam_csock); 176 ctx->pam_csock = -1; |
|
165 sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler); 166 return (0); 167 } 168} 169 170static int 171pthread_cancel(sp_pthread_t thread) 172{ --- 123 unchanged lines hidden (view full) --- 296 } 297#endif 298} 299 300/* 301 * Conversation function for authentication thread. 302 */ 303static int | 177 sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler); 178 return (0); 179 } 180} 181 182static int 183pthread_cancel(sp_pthread_t thread) 184{ --- 123 unchanged lines hidden (view full) --- 308 } 309#endif 310} 311 312/* 313 * Conversation function for authentication thread. 314 */ 315static int |
304sshpam_thread_conv(int n, struct pam_message **msg, | 316sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, |
305 struct pam_response **resp, void *data) 306{ 307 Buffer buffer; 308 struct pam_ctxt *ctxt; 309 struct pam_response *reply; 310 int i; 311 312 debug3("PAM: %s entering, %d messages", __func__, n); --- 82 unchanged lines hidden (view full) --- 395 struct pam_conv sshpam_conv; 396 int flags = (options.permit_empty_passwd == 0 ? 397 PAM_DISALLOW_NULL_AUTHTOK : 0); 398#ifndef UNSUPPORTED_POSIX_THREADS_HACK 399 extern char **environ; 400 char **env_from_pam; 401 u_int i; 402 const char *pam_user; | 317 struct pam_response **resp, void *data) 318{ 319 Buffer buffer; 320 struct pam_ctxt *ctxt; 321 struct pam_response *reply; 322 int i; 323 324 debug3("PAM: %s entering, %d messages", __func__, n); --- 82 unchanged lines hidden (view full) --- 407 struct pam_conv sshpam_conv; 408 int flags = (options.permit_empty_passwd == 0 ? 409 PAM_DISALLOW_NULL_AUTHTOK : 0); 410#ifndef UNSUPPORTED_POSIX_THREADS_HACK 411 extern char **environ; 412 char **env_from_pam; 413 u_int i; 414 const char *pam_user; |
415 const char **ptr_pam_user = &pam_user; |
|
403 | 416 |
404 pam_get_item(sshpam_handle, PAM_USER, (void **)&pam_user); | 417 pam_get_item(sshpam_handle, PAM_USER, 418 (sshpam_const void **)ptr_pam_user); |
405 environ[0] = NULL; 406 407 if (sshpam_authctxt != NULL) { 408 setproctitle("%s [pam]", 409 sshpam_authctxt->valid ? pam_user : "unknown"); 410 } 411#endif 412 --- 75 unchanged lines hidden (view full) --- 488 close(ctxt->pam_psock); 489 close(ctxt->pam_csock); 490 memset(ctxt, 0, sizeof(*ctxt)); 491 cleanup_ctxt = NULL; 492 } 493} 494 495static int | 419 environ[0] = NULL; 420 421 if (sshpam_authctxt != NULL) { 422 setproctitle("%s [pam]", 423 sshpam_authctxt->valid ? pam_user : "unknown"); 424 } 425#endif 426 --- 75 unchanged lines hidden (view full) --- 502 close(ctxt->pam_psock); 503 close(ctxt->pam_csock); 504 memset(ctxt, 0, sizeof(*ctxt)); 505 cleanup_ctxt = NULL; 506 } 507} 508 509static int |
496sshpam_null_conv(int n, struct pam_message **msg, | 510sshpam_null_conv(int n, sshpam_const struct pam_message **msg, |
497 struct pam_response **resp, void *data) 498{ 499 debug3("PAM: %s entering, %d messages", __func__, n); 500 return (PAM_CONV_ERR); 501} 502 503static struct pam_conv null_conv = { sshpam_null_conv, NULL }; 504 505static int | 511 struct pam_response **resp, void *data) 512{ 513 debug3("PAM: %s entering, %d messages", __func__, n); 514 return (PAM_CONV_ERR); 515} 516 517static struct pam_conv null_conv = { sshpam_null_conv, NULL }; 518 519static int |
506sshpam_store_conv(int n, struct pam_message **msg, | 520sshpam_store_conv(int n, sshpam_const struct pam_message **msg, |
507 struct pam_response **resp, void *data) 508{ 509 struct pam_response *reply; 510 int i; 511 size_t len; 512 513 debug3("PAM: %s called with %d messages", __func__, n); 514 *resp = NULL; --- 52 unchanged lines hidden (view full) --- 567 sshpam_handle = NULL; 568} 569 570static int 571sshpam_init(Authctxt *authctxt) 572{ 573 extern char *__progname; 574 const char *pam_rhost, *pam_user, *user = authctxt->user; | 521 struct pam_response **resp, void *data) 522{ 523 struct pam_response *reply; 524 int i; 525 size_t len; 526 527 debug3("PAM: %s called with %d messages", __func__, n); 528 *resp = NULL; --- 52 unchanged lines hidden (view full) --- 581 sshpam_handle = NULL; 582} 583 584static int 585sshpam_init(Authctxt *authctxt) 586{ 587 extern char *__progname; 588 const char *pam_rhost, *pam_user, *user = authctxt->user; |
589 const char **ptr_pam_user = &pam_user; |
|
575 576 if (sshpam_handle != NULL) { 577 /* We already have a PAM context; check if the user matches */ 578 sshpam_err = pam_get_item(sshpam_handle, | 590 591 if (sshpam_handle != NULL) { 592 /* We already have a PAM context; check if the user matches */ 593 sshpam_err = pam_get_item(sshpam_handle, |
579 PAM_USER, (void **)&pam_user); | 594 PAM_USER, (sshpam_const void **)ptr_pam_user); |
580 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) 581 return (0); 582 pam_end(sshpam_handle, sshpam_err); 583 sshpam_handle = NULL; 584 } 585 debug("PAM: initializing for \"%s\"", user); 586 sshpam_err = 587 pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); --- 173 unchanged lines hidden (view full) --- 761 } 762 if (num != 1) { 763 error("PAM: expected one response, got %u", num); 764 return (-1); 765 } 766 buffer_init(&buffer); 767 if (sshpam_authctxt->valid && 768 (sshpam_authctxt->pw->pw_uid != 0 || | 595 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) 596 return (0); 597 pam_end(sshpam_handle, sshpam_err); 598 sshpam_handle = NULL; 599 } 600 debug("PAM: initializing for \"%s\"", user); 601 sshpam_err = 602 pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); --- 173 unchanged lines hidden (view full) --- 776 } 777 if (num != 1) { 778 error("PAM: expected one response, got %u", num); 779 return (-1); 780 } 781 buffer_init(&buffer); 782 if (sshpam_authctxt->valid && 783 (sshpam_authctxt->pw->pw_uid != 0 || |
769 options.permit_root_login == PERMIT_YES)) | 784 options.permit_root_login == PERMIT_YES)) |
770 buffer_put_cstring(&buffer, *resp); 771 else 772 buffer_put_cstring(&buffer, badpw); 773 if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { 774 buffer_free(&buffer); 775 return (-1); 776 } 777 buffer_free(&buffer); --- 56 unchanged lines hidden (view full) --- 834{ 835 debug("%s: called", __func__); 836 if (sshpam_account_status != -1) 837 return (sshpam_account_status); 838 839 sshpam_err = pam_acct_mgmt(sshpam_handle, 0); 840 debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, 841 pam_strerror(sshpam_handle, sshpam_err)); | 785 buffer_put_cstring(&buffer, *resp); 786 else 787 buffer_put_cstring(&buffer, badpw); 788 if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { 789 buffer_free(&buffer); 790 return (-1); 791 } 792 buffer_free(&buffer); --- 56 unchanged lines hidden (view full) --- 849{ 850 debug("%s: called", __func__); 851 if (sshpam_account_status != -1) 852 return (sshpam_account_status); 853 854 sshpam_err = pam_acct_mgmt(sshpam_handle, 0); 855 debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, 856 pam_strerror(sshpam_handle, sshpam_err)); |
842 | 857 |
843 if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { 844 sshpam_account_status = 0; 845 return (sshpam_account_status); 846 } 847 848 if (sshpam_err == PAM_NEW_AUTHTOK_REQD) 849 sshpam_password_change_required(1); 850 --- 36 unchanged lines hidden (view full) --- 887 fatal("PAM: pam_setcred(): %s", 888 pam_strerror(sshpam_handle, sshpam_err)); 889 else 890 debug("PAM: pam_setcred(): %s", 891 pam_strerror(sshpam_handle, sshpam_err)); 892} 893 894static int | 858 if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { 859 sshpam_account_status = 0; 860 return (sshpam_account_status); 861 } 862 863 if (sshpam_err == PAM_NEW_AUTHTOK_REQD) 864 sshpam_password_change_required(1); 865 --- 36 unchanged lines hidden (view full) --- 902 fatal("PAM: pam_setcred(): %s", 903 pam_strerror(sshpam_handle, sshpam_err)); 904 else 905 debug("PAM: pam_setcred(): %s", 906 pam_strerror(sshpam_handle, sshpam_err)); 907} 908 909static int |
895sshpam_tty_conv(int n, struct pam_message **msg, | 910sshpam_tty_conv(int n, sshpam_const struct pam_message **msg, |
896 struct pam_response **resp, void *data) 897{ 898 char input[PAM_MAX_MSG_SIZE]; 899 struct pam_response *reply; 900 int i; 901 902 debug3("PAM: %s called with %d messages", __func__, n); 903 --- 142 unchanged lines hidden (view full) --- 1046} 1047 1048/* 1049 * "Blind" conversation function for password authentication. Assumes that 1050 * echo-off prompts are for the password and stores messages for later 1051 * display. 1052 */ 1053static int | 911 struct pam_response **resp, void *data) 912{ 913 char input[PAM_MAX_MSG_SIZE]; 914 struct pam_response *reply; 915 int i; 916 917 debug3("PAM: %s called with %d messages", __func__, n); 918 --- 142 unchanged lines hidden (view full) --- 1061} 1062 1063/* 1064 * "Blind" conversation function for password authentication. Assumes that 1065 * echo-off prompts are for the password and stores messages for later 1066 * display. 1067 */ 1068static int |
1054sshpam_passwd_conv(int n, struct pam_message **msg, | 1069sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg, |
1055 struct pam_response **resp, void *data) 1056{ 1057 struct pam_response *reply; 1058 int i; 1059 size_t len; 1060 1061 debug3("PAM: %s called with %d messages", __func__, n); 1062 --- 29 unchanged lines hidden (view full) --- 1092 break; 1093 default: 1094 goto fail; 1095 } 1096 } 1097 *resp = reply; 1098 return (PAM_SUCCESS); 1099 | 1070 struct pam_response **resp, void *data) 1071{ 1072 struct pam_response *reply; 1073 int i; 1074 size_t len; 1075 1076 debug3("PAM: %s called with %d messages", __func__, n); 1077 --- 29 unchanged lines hidden (view full) --- 1107 break; 1108 default: 1109 goto fail; 1110 } 1111 } 1112 *resp = reply; 1113 return (PAM_SUCCESS); 1114 |
1100 fail: | 1115 fail: |
1101 for(i = 0; i < n; i++) { 1102 if (reply[i].resp != NULL) 1103 xfree(reply[i].resp); 1104 } 1105 xfree(reply); 1106 return (PAM_CONV_ERR); 1107} 1108 --- 16 unchanged lines hidden (view full) --- 1125 sshpam_authctxt = authctxt; 1126 1127 /* 1128 * If the user logging in is invalid, or is root but is not permitted 1129 * by PermitRootLogin, use an invalid password to prevent leaking 1130 * information via timing (eg if the PAM config has a delay on fail). 1131 */ 1132 if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && | 1116 for(i = 0; i < n; i++) { 1117 if (reply[i].resp != NULL) 1118 xfree(reply[i].resp); 1119 } 1120 xfree(reply); 1121 return (PAM_CONV_ERR); 1122} 1123 --- 16 unchanged lines hidden (view full) --- 1140 sshpam_authctxt = authctxt; 1141 1142 /* 1143 * If the user logging in is invalid, or is root but is not permitted 1144 * by PermitRootLogin, use an invalid password to prevent leaking 1145 * information via timing (eg if the PAM config has a delay on fail). 1146 */ 1147 if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && |
1133 options.permit_root_login != PERMIT_YES)) | 1148 options.permit_root_login != PERMIT_YES)) |
1134 sshpam_password = badpw; 1135 1136 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 1137 (const void *)&passwd_conv); 1138 if (sshpam_err != PAM_SUCCESS) 1139 fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, 1140 pam_strerror(sshpam_handle, sshpam_err)); 1141 1142 sshpam_err = pam_authenticate(sshpam_handle, flags); 1143 sshpam_password = NULL; 1144 if (sshpam_err == PAM_SUCCESS && authctxt->valid) { 1145 debug("PAM: password authentication accepted for %.100s", 1146 authctxt->user); | 1149 sshpam_password = badpw; 1150 1151 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 1152 (const void *)&passwd_conv); 1153 if (sshpam_err != PAM_SUCCESS) 1154 fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, 1155 pam_strerror(sshpam_handle, sshpam_err)); 1156 1157 sshpam_err = pam_authenticate(sshpam_handle, flags); 1158 sshpam_password = NULL; 1159 if (sshpam_err == PAM_SUCCESS && authctxt->valid) { 1160 debug("PAM: password authentication accepted for %.100s", 1161 authctxt->user); |
1147 return 1; | 1162 return 1; |
1148 } else { 1149 debug("PAM: password authentication failed for %.100s: %s", 1150 authctxt->valid ? authctxt->user : "an illegal user", 1151 pam_strerror(sshpam_handle, sshpam_err)); 1152 return 0; 1153 } 1154} 1155#endif /* USE_PAM */ | 1163 } else { 1164 debug("PAM: password authentication failed for %.100s: %s", 1165 authctxt->valid ? authctxt->user : "an illegal user", 1166 pam_strerror(sshpam_handle, sshpam_err)); 1167 return 0; 1168 } 1169} 1170#endif /* USE_PAM */ |