diff options
Diffstat (limited to 'auth-pam.c')
-rw-r--r-- | auth-pam.c | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/auth-pam.c b/auth-pam.c index abd6a5e1b..348fe370a 100644 --- a/auth-pam.c +++ b/auth-pam.c | |||
@@ -68,9 +68,9 @@ | |||
68 | 68 | ||
69 | /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */ | 69 | /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */ |
70 | #ifdef PAM_SUN_CODEBASE | 70 | #ifdef PAM_SUN_CODEBASE |
71 | # define sshpam_const /* Solaris, HP-UX, AIX */ | 71 | # define sshpam_const /* Solaris, HP-UX, SunOS */ |
72 | #else | 72 | #else |
73 | # define sshpam_const const /* LinuxPAM, OpenPAM */ | 73 | # define sshpam_const const /* LinuxPAM, OpenPAM, AIX */ |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | /* Ambiguity in spec: is it an array of pointers or a pointer to an array? */ | 76 | /* Ambiguity in spec: is it an array of pointers or a pointer to an array? */ |
@@ -154,9 +154,12 @@ sshpam_sigchld_handler(int sig) | |||
154 | <= 0) { | 154 | <= 0) { |
155 | /* PAM thread has not exitted, privsep slave must have */ | 155 | /* PAM thread has not exitted, privsep slave must have */ |
156 | kill(cleanup_ctxt->pam_thread, SIGTERM); | 156 | kill(cleanup_ctxt->pam_thread, SIGTERM); |
157 | if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) | 157 | while (waitpid(cleanup_ctxt->pam_thread, |
158 | <= 0) | 158 | &sshpam_thread_status, 0) == -1) { |
159 | return; /* could not wait */ | 159 | if (errno == EINTR) |
160 | continue; | ||
161 | return; | ||
162 | } | ||
160 | } | 163 | } |
161 | if (WIFSIGNALED(sshpam_thread_status) && | 164 | if (WIFSIGNALED(sshpam_thread_status) && |
162 | WTERMSIG(sshpam_thread_status) == SIGTERM) | 165 | WTERMSIG(sshpam_thread_status) == SIGTERM) |
@@ -217,7 +220,11 @@ pthread_join(sp_pthread_t thread, void **value) | |||
217 | if (sshpam_thread_status != -1) | 220 | if (sshpam_thread_status != -1) |
218 | return (sshpam_thread_status); | 221 | return (sshpam_thread_status); |
219 | signal(SIGCHLD, sshpam_oldsig); | 222 | signal(SIGCHLD, sshpam_oldsig); |
220 | waitpid(thread, &status, 0); | 223 | while (waitpid(thread, &status, 0) == -1) { |
224 | if (errno == EINTR) | ||
225 | continue; | ||
226 | fatal("%s: waitpid: %s", __func__, strerror(errno)); | ||
227 | } | ||
221 | return (status); | 228 | return (status); |
222 | } | 229 | } |
223 | #endif | 230 | #endif |
@@ -229,6 +236,7 @@ static int sshpam_authenticated = 0; | |||
229 | static int sshpam_session_open = 0; | 236 | static int sshpam_session_open = 0; |
230 | static int sshpam_cred_established = 0; | 237 | static int sshpam_cred_established = 0; |
231 | static int sshpam_account_status = -1; | 238 | static int sshpam_account_status = -1; |
239 | static int sshpam_maxtries_reached = 0; | ||
232 | static char **sshpam_env = NULL; | 240 | static char **sshpam_env = NULL; |
233 | static Authctxt *sshpam_authctxt = NULL; | 241 | static Authctxt *sshpam_authctxt = NULL; |
234 | static const char *sshpam_password = NULL; | 242 | static const char *sshpam_password = NULL; |
@@ -364,17 +372,6 @@ sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, | |||
364 | for (i = 0; i < n; ++i) { | 372 | for (i = 0; i < n; ++i) { |
365 | switch (PAM_MSG_MEMBER(msg, i, msg_style)) { | 373 | switch (PAM_MSG_MEMBER(msg, i, msg_style)) { |
366 | case PAM_PROMPT_ECHO_OFF: | 374 | case PAM_PROMPT_ECHO_OFF: |
367 | buffer_put_cstring(&buffer, | ||
368 | PAM_MSG_MEMBER(msg, i, msg)); | ||
369 | if (ssh_msg_send(ctxt->pam_csock, | ||
370 | PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) | ||
371 | goto fail; | ||
372 | if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) | ||
373 | goto fail; | ||
374 | if (buffer_get_char(&buffer) != PAM_AUTHTOK) | ||
375 | goto fail; | ||
376 | reply[i].resp = buffer_get_string(&buffer, NULL); | ||
377 | break; | ||
378 | case PAM_PROMPT_ECHO_ON: | 375 | case PAM_PROMPT_ECHO_ON: |
379 | buffer_put_cstring(&buffer, | 376 | buffer_put_cstring(&buffer, |
380 | PAM_MSG_MEMBER(msg, i, msg)); | 377 | PAM_MSG_MEMBER(msg, i, msg)); |
@@ -388,12 +385,6 @@ sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, | |||
388 | reply[i].resp = buffer_get_string(&buffer, NULL); | 385 | reply[i].resp = buffer_get_string(&buffer, NULL); |
389 | break; | 386 | break; |
390 | case PAM_ERROR_MSG: | 387 | case PAM_ERROR_MSG: |
391 | buffer_put_cstring(&buffer, | ||
392 | PAM_MSG_MEMBER(msg, i, msg)); | ||
393 | if (ssh_msg_send(ctxt->pam_csock, | ||
394 | PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) | ||
395 | goto fail; | ||
396 | break; | ||
397 | case PAM_TEXT_INFO: | 388 | case PAM_TEXT_INFO: |
398 | buffer_put_cstring(&buffer, | 389 | buffer_put_cstring(&buffer, |
399 | PAM_MSG_MEMBER(msg, i, msg)); | 390 | PAM_MSG_MEMBER(msg, i, msg)); |
@@ -467,6 +458,8 @@ sshpam_thread(void *ctxtp) | |||
467 | if (sshpam_err != PAM_SUCCESS) | 458 | if (sshpam_err != PAM_SUCCESS) |
468 | goto auth_fail; | 459 | goto auth_fail; |
469 | sshpam_err = pam_authenticate(sshpam_handle, flags); | 460 | sshpam_err = pam_authenticate(sshpam_handle, flags); |
461 | if (sshpam_err == PAM_MAXTRIES) | ||
462 | sshpam_set_maxtries_reached(1); | ||
470 | if (sshpam_err != PAM_SUCCESS) | 463 | if (sshpam_err != PAM_SUCCESS) |
471 | goto auth_fail; | 464 | goto auth_fail; |
472 | 465 | ||
@@ -518,6 +511,8 @@ sshpam_thread(void *ctxtp) | |||
518 | /* XXX - can't do much about an error here */ | 511 | /* XXX - can't do much about an error here */ |
519 | if (sshpam_err == PAM_ACCT_EXPIRED) | 512 | if (sshpam_err == PAM_ACCT_EXPIRED) |
520 | ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer); | 513 | ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer); |
514 | else if (sshpam_maxtries_reached) | ||
515 | ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, &buffer); | ||
521 | else | 516 | else |
522 | ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); | 517 | ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); |
523 | buffer_free(&buffer); | 518 | buffer_free(&buffer); |
@@ -623,6 +618,7 @@ sshpam_init(Authctxt *authctxt) | |||
623 | extern char *__progname; | 618 | extern char *__progname; |
624 | const char *pam_rhost, *pam_user, *user = authctxt->user; | 619 | const char *pam_rhost, *pam_user, *user = authctxt->user; |
625 | const char **ptr_pam_user = &pam_user; | 620 | const char **ptr_pam_user = &pam_user; |
621 | struct ssh *ssh = active_state; /* XXX */ | ||
626 | 622 | ||
627 | if (sshpam_handle != NULL) { | 623 | if (sshpam_handle != NULL) { |
628 | /* We already have a PAM context; check if the user matches */ | 624 | /* We already have a PAM context; check if the user matches */ |
@@ -643,7 +639,7 @@ sshpam_init(Authctxt *authctxt) | |||
643 | sshpam_handle = NULL; | 639 | sshpam_handle = NULL; |
644 | return (-1); | 640 | return (-1); |
645 | } | 641 | } |
646 | pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns); | 642 | pam_rhost = auth_get_canonical_hostname(ssh, options.use_dns); |
647 | debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost); | 643 | debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost); |
648 | sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost); | 644 | sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost); |
649 | if (sshpam_err != PAM_SUCCESS) { | 645 | if (sshpam_err != PAM_SUCCESS) { |
@@ -714,6 +710,7 @@ static int | |||
714 | sshpam_query(void *ctx, char **name, char **info, | 710 | sshpam_query(void *ctx, char **name, char **info, |
715 | u_int *num, char ***prompts, u_int **echo_on) | 711 | u_int *num, char ***prompts, u_int **echo_on) |
716 | { | 712 | { |
713 | struct ssh *ssh = active_state; /* XXX */ | ||
717 | Buffer buffer; | 714 | Buffer buffer; |
718 | struct pam_ctxt *ctxt = ctx; | 715 | struct pam_ctxt *ctxt = ctx; |
719 | size_t plen; | 716 | size_t plen; |
@@ -756,7 +753,11 @@ sshpam_query(void *ctx, char **name, char **info, | |||
756 | free(msg); | 753 | free(msg); |
757 | break; | 754 | break; |
758 | case PAM_ACCT_EXPIRED: | 755 | case PAM_ACCT_EXPIRED: |
759 | sshpam_account_status = 0; | 756 | case PAM_MAXTRIES: |
757 | if (type == PAM_ACCT_EXPIRED) | ||
758 | sshpam_account_status = 0; | ||
759 | if (type == PAM_MAXTRIES) | ||
760 | sshpam_set_maxtries_reached(1); | ||
760 | /* FALLTHROUGH */ | 761 | /* FALLTHROUGH */ |
761 | case PAM_AUTH_ERR: | 762 | case PAM_AUTH_ERR: |
762 | debug3("PAM: %s", pam_strerror(sshpam_handle, type)); | 763 | debug3("PAM: %s", pam_strerror(sshpam_handle, type)); |
@@ -796,7 +797,7 @@ sshpam_query(void *ctx, char **name, char **info, | |||
796 | error("PAM: %s for %s%.100s from %.100s", msg, | 797 | error("PAM: %s for %s%.100s from %.100s", msg, |
797 | sshpam_authctxt->valid ? "" : "illegal user ", | 798 | sshpam_authctxt->valid ? "" : "illegal user ", |
798 | sshpam_authctxt->user, | 799 | sshpam_authctxt->user, |
799 | get_remote_name_or_ip(utmp_len, options.use_dns)); | 800 | auth_get_canonical_hostname(ssh, options.use_dns)); |
800 | /* FALLTHROUGH */ | 801 | /* FALLTHROUGH */ |
801 | default: | 802 | default: |
802 | *num = 0; | 803 | *num = 0; |
@@ -1233,6 +1234,8 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) | |||
1233 | sshpam_err = pam_authenticate(sshpam_handle, flags); | 1234 | sshpam_err = pam_authenticate(sshpam_handle, flags); |
1234 | sshpam_password = NULL; | 1235 | sshpam_password = NULL; |
1235 | free(fake); | 1236 | free(fake); |
1237 | if (sshpam_err == PAM_MAXTRIES) | ||
1238 | sshpam_set_maxtries_reached(1); | ||
1236 | if (sshpam_err == PAM_SUCCESS && authctxt->valid) { | 1239 | if (sshpam_err == PAM_SUCCESS && authctxt->valid) { |
1237 | debug("PAM: password authentication accepted for %.100s", | 1240 | debug("PAM: password authentication accepted for %.100s", |
1238 | authctxt->user); | 1241 | authctxt->user); |
@@ -1244,4 +1247,21 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) | |||
1244 | return 0; | 1247 | return 0; |
1245 | } | 1248 | } |
1246 | } | 1249 | } |
1250 | |||
1251 | int | ||
1252 | sshpam_get_maxtries_reached(void) | ||
1253 | { | ||
1254 | return sshpam_maxtries_reached; | ||
1255 | } | ||
1256 | |||
1257 | void | ||
1258 | sshpam_set_maxtries_reached(int reached) | ||
1259 | { | ||
1260 | if (reached == 0 || sshpam_maxtries_reached) | ||
1261 | return; | ||
1262 | sshpam_maxtries_reached = 1; | ||
1263 | options.password_authentication = 0; | ||
1264 | options.kbd_interactive_authentication = 0; | ||
1265 | options.challenge_response_authentication = 0; | ||
1266 | } | ||
1247 | #endif /* USE_PAM */ | 1267 | #endif /* USE_PAM */ |