diff options
Diffstat (limited to 'auth-pam.c')
-rw-r--r-- | auth-pam.c | 147 |
1 files changed, 88 insertions, 59 deletions
diff --git a/auth-pam.c b/auth-pam.c index b93241f48..6ce8c429b 100644 --- a/auth-pam.c +++ b/auth-pam.c | |||
@@ -47,7 +47,7 @@ | |||
47 | 47 | ||
48 | /* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */ | 48 | /* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */ |
49 | #include "includes.h" | 49 | #include "includes.h" |
50 | RCSID("$Id: auth-pam.c,v 1.114 2004/08/16 13:12:06 dtucker Exp $"); | 50 | RCSID("$Id: auth-pam.c,v 1.121 2005/01/20 02:29:51 dtucker Exp $"); |
51 | 51 | ||
52 | #ifdef USE_PAM | 52 | #ifdef USE_PAM |
53 | #if defined(HAVE_SECURITY_PAM_APPL_H) | 53 | #if defined(HAVE_SECURITY_PAM_APPL_H) |
@@ -186,6 +186,7 @@ static int sshpam_account_status = -1; | |||
186 | static char **sshpam_env = NULL; | 186 | static char **sshpam_env = NULL; |
187 | static Authctxt *sshpam_authctxt = NULL; | 187 | static Authctxt *sshpam_authctxt = NULL; |
188 | static const char *sshpam_password = NULL; | 188 | static const char *sshpam_password = NULL; |
189 | static char badpw[] = "\b\n\r\177INCORRECT"; | ||
189 | 190 | ||
190 | /* Some PAM implementations don't implement this */ | 191 | /* Some PAM implementations don't implement this */ |
191 | #ifndef HAVE_PAM_GETENVLIST | 192 | #ifndef HAVE_PAM_GETENVLIST |
@@ -490,6 +491,51 @@ sshpam_null_conv(int n, struct pam_message **msg, | |||
490 | 491 | ||
491 | static struct pam_conv null_conv = { sshpam_null_conv, NULL }; | 492 | static struct pam_conv null_conv = { sshpam_null_conv, NULL }; |
492 | 493 | ||
494 | static int | ||
495 | sshpam_store_conv(int n, struct pam_message **msg, | ||
496 | struct pam_response **resp, void *data) | ||
497 | { | ||
498 | struct pam_response *reply; | ||
499 | int i; | ||
500 | size_t len; | ||
501 | |||
502 | debug3("PAM: %s called with %d messages", __func__, n); | ||
503 | *resp = NULL; | ||
504 | |||
505 | if (n <= 0 || n > PAM_MAX_NUM_MSG) | ||
506 | return (PAM_CONV_ERR); | ||
507 | |||
508 | if ((reply = malloc(n * sizeof(*reply))) == NULL) | ||
509 | return (PAM_CONV_ERR); | ||
510 | memset(reply, 0, n * sizeof(*reply)); | ||
511 | |||
512 | for (i = 0; i < n; ++i) { | ||
513 | switch (PAM_MSG_MEMBER(msg, i, msg_style)) { | ||
514 | case PAM_ERROR_MSG: | ||
515 | case PAM_TEXT_INFO: | ||
516 | len = strlen(PAM_MSG_MEMBER(msg, i, msg)); | ||
517 | buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); | ||
518 | buffer_append(&loginmsg, "\n", 1 ); | ||
519 | reply[i].resp_retcode = PAM_SUCCESS; | ||
520 | break; | ||
521 | default: | ||
522 | goto fail; | ||
523 | } | ||
524 | } | ||
525 | *resp = reply; | ||
526 | return (PAM_SUCCESS); | ||
527 | |||
528 | fail: | ||
529 | for(i = 0; i < n; i++) { | ||
530 | if (reply[i].resp != NULL) | ||
531 | xfree(reply[i].resp); | ||
532 | } | ||
533 | xfree(reply); | ||
534 | return (PAM_CONV_ERR); | ||
535 | } | ||
536 | |||
537 | static struct pam_conv store_conv = { sshpam_store_conv, NULL }; | ||
538 | |||
493 | void | 539 | void |
494 | sshpam_cleanup(void) | 540 | sshpam_cleanup(void) |
495 | { | 541 | { |
@@ -527,7 +573,7 @@ sshpam_init(Authctxt *authctxt) | |||
527 | } | 573 | } |
528 | debug("PAM: initializing for \"%s\"", user); | 574 | debug("PAM: initializing for \"%s\"", user); |
529 | sshpam_err = | 575 | sshpam_err = |
530 | pam_start(SSHD_PAM_SERVICE, user, &null_conv, &sshpam_handle); | 576 | pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); |
531 | sshpam_authctxt = authctxt; | 577 | sshpam_authctxt = authctxt; |
532 | 578 | ||
533 | if (sshpam_err != PAM_SUCCESS) { | 579 | if (sshpam_err != PAM_SUCCESS) { |
@@ -609,7 +655,7 @@ sshpam_query(void *ctx, char **name, char **info, | |||
609 | size_t plen; | 655 | size_t plen; |
610 | u_char type; | 656 | u_char type; |
611 | char *msg; | 657 | char *msg; |
612 | size_t len; | 658 | size_t len, mlen; |
613 | 659 | ||
614 | debug3("PAM: %s entering", __func__); | 660 | debug3("PAM: %s entering", __func__); |
615 | buffer_init(&buffer); | 661 | buffer_init(&buffer); |
@@ -622,22 +668,27 @@ sshpam_query(void *ctx, char **name, char **info, | |||
622 | while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) { | 668 | while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) { |
623 | type = buffer_get_char(&buffer); | 669 | type = buffer_get_char(&buffer); |
624 | msg = buffer_get_string(&buffer, NULL); | 670 | msg = buffer_get_string(&buffer, NULL); |
671 | mlen = strlen(msg); | ||
625 | switch (type) { | 672 | switch (type) { |
626 | case PAM_PROMPT_ECHO_ON: | 673 | case PAM_PROMPT_ECHO_ON: |
627 | case PAM_PROMPT_ECHO_OFF: | 674 | case PAM_PROMPT_ECHO_OFF: |
628 | *num = 1; | 675 | *num = 1; |
629 | len = plen + strlen(msg) + 1; | 676 | len = plen + mlen + 1; |
630 | **prompts = xrealloc(**prompts, len); | 677 | **prompts = xrealloc(**prompts, len); |
631 | plen += snprintf(**prompts + plen, len, "%s", msg); | 678 | strlcpy(**prompts + plen, msg, len - plen); |
679 | plen += mlen; | ||
632 | **echo_on = (type == PAM_PROMPT_ECHO_ON); | 680 | **echo_on = (type == PAM_PROMPT_ECHO_ON); |
633 | xfree(msg); | 681 | xfree(msg); |
634 | return (0); | 682 | return (0); |
635 | case PAM_ERROR_MSG: | 683 | case PAM_ERROR_MSG: |
636 | case PAM_TEXT_INFO: | 684 | case PAM_TEXT_INFO: |
637 | /* accumulate messages */ | 685 | /* accumulate messages */ |
638 | len = plen + strlen(msg) + 2; | 686 | len = plen + mlen + 2; |
639 | **prompts = xrealloc(**prompts, len); | 687 | **prompts = xrealloc(**prompts, len); |
640 | plen += snprintf(**prompts + plen, len, "%s\n", msg); | 688 | strlcpy(**prompts + plen, msg, len - plen); |
689 | plen += mlen; | ||
690 | strlcat(**prompts + plen, "\n", len - plen); | ||
691 | plen++; | ||
641 | xfree(msg); | 692 | xfree(msg); |
642 | break; | 693 | break; |
643 | case PAM_SUCCESS: | 694 | case PAM_SUCCESS: |
@@ -651,6 +702,12 @@ sshpam_query(void *ctx, char **name, char **info, | |||
651 | **prompts = NULL; | 702 | **prompts = NULL; |
652 | } | 703 | } |
653 | if (type == PAM_SUCCESS) { | 704 | if (type == PAM_SUCCESS) { |
705 | if (!sshpam_authctxt->valid || | ||
706 | (sshpam_authctxt->pw->pw_uid == 0 && | ||
707 | options.permit_root_login != PERMIT_YES)) | ||
708 | fatal("Internal error: PAM auth " | ||
709 | "succeeded when it should have " | ||
710 | "failed"); | ||
654 | import_environments(&buffer); | 711 | import_environments(&buffer); |
655 | *num = 0; | 712 | *num = 0; |
656 | **echo_on = 0; | 713 | **echo_on = 0; |
@@ -696,7 +753,12 @@ sshpam_respond(void *ctx, u_int num, char **resp) | |||
696 | return (-1); | 753 | return (-1); |
697 | } | 754 | } |
698 | buffer_init(&buffer); | 755 | buffer_init(&buffer); |
699 | buffer_put_cstring(&buffer, *resp); | 756 | if (sshpam_authctxt->valid && |
757 | (sshpam_authctxt->pw->pw_uid != 0 || | ||
758 | options.permit_root_login == PERMIT_YES)) | ||
759 | buffer_put_cstring(&buffer, *resp); | ||
760 | else | ||
761 | buffer_put_cstring(&buffer, badpw); | ||
700 | if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { | 762 | if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { |
701 | buffer_free(&buffer); | 763 | buffer_free(&buffer); |
702 | return (-1); | 764 | return (-1); |
@@ -759,11 +821,13 @@ finish_pam(void) | |||
759 | u_int | 821 | u_int |
760 | do_pam_account(void) | 822 | do_pam_account(void) |
761 | { | 823 | { |
824 | debug("%s: called", __func__); | ||
762 | if (sshpam_account_status != -1) | 825 | if (sshpam_account_status != -1) |
763 | return (sshpam_account_status); | 826 | return (sshpam_account_status); |
764 | 827 | ||
765 | sshpam_err = pam_acct_mgmt(sshpam_handle, 0); | 828 | sshpam_err = pam_acct_mgmt(sshpam_handle, 0); |
766 | debug3("PAM: %s pam_acct_mgmt = %d", __func__, sshpam_err); | 829 | debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, |
830 | pam_strerror(sshpam_handle, sshpam_err)); | ||
767 | 831 | ||
768 | if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { | 832 | if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { |
769 | sshpam_account_status = 0; | 833 | sshpam_account_status = 0; |
@@ -793,7 +857,7 @@ void | |||
793 | do_pam_setcred(int init) | 857 | do_pam_setcred(int init) |
794 | { | 858 | { |
795 | sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, | 859 | sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, |
796 | (const void *)&null_conv); | 860 | (const void *)&store_conv); |
797 | if (sshpam_err != PAM_SUCCESS) | 861 | if (sshpam_err != PAM_SUCCESS) |
798 | fatal("PAM: failed to set PAM_CONV: %s", | 862 | fatal("PAM: failed to set PAM_CONV: %s", |
799 | pam_strerror(sshpam_handle, sshpam_err)); | 863 | pam_strerror(sshpam_handle, sshpam_err)); |
@@ -894,51 +958,6 @@ do_pam_chauthtok(void) | |||
894 | pam_strerror(sshpam_handle, sshpam_err)); | 958 | pam_strerror(sshpam_handle, sshpam_err)); |
895 | } | 959 | } |
896 | 960 | ||
897 | static int | ||
898 | sshpam_store_conv(int n, struct pam_message **msg, | ||
899 | struct pam_response **resp, void *data) | ||
900 | { | ||
901 | struct pam_response *reply; | ||
902 | int i; | ||
903 | size_t len; | ||
904 | |||
905 | debug3("PAM: %s called with %d messages", __func__, n); | ||
906 | *resp = NULL; | ||
907 | |||
908 | if (n <= 0 || n > PAM_MAX_NUM_MSG) | ||
909 | return (PAM_CONV_ERR); | ||
910 | |||
911 | if ((reply = malloc(n * sizeof(*reply))) == NULL) | ||
912 | return (PAM_CONV_ERR); | ||
913 | memset(reply, 0, n * sizeof(*reply)); | ||
914 | |||
915 | for (i = 0; i < n; ++i) { | ||
916 | switch (PAM_MSG_MEMBER(msg, i, msg_style)) { | ||
917 | case PAM_ERROR_MSG: | ||
918 | case PAM_TEXT_INFO: | ||
919 | len = strlen(PAM_MSG_MEMBER(msg, i, msg)); | ||
920 | buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); | ||
921 | buffer_append(&loginmsg, "\n", 1 ); | ||
922 | reply[i].resp_retcode = PAM_SUCCESS; | ||
923 | break; | ||
924 | default: | ||
925 | goto fail; | ||
926 | } | ||
927 | } | ||
928 | *resp = reply; | ||
929 | return (PAM_SUCCESS); | ||
930 | |||
931 | fail: | ||
932 | for(i = 0; i < n; i++) { | ||
933 | if (reply[i].resp != NULL) | ||
934 | xfree(reply[i].resp); | ||
935 | } | ||
936 | xfree(reply); | ||
937 | return (PAM_CONV_ERR); | ||
938 | } | ||
939 | |||
940 | static struct pam_conv store_conv = { sshpam_store_conv, NULL }; | ||
941 | |||
942 | void | 961 | void |
943 | do_pam_session(void) | 962 | do_pam_session(void) |
944 | { | 963 | { |
@@ -949,10 +968,21 @@ do_pam_session(void) | |||
949 | fatal("PAM: failed to set PAM_CONV: %s", | 968 | fatal("PAM: failed to set PAM_CONV: %s", |
950 | pam_strerror(sshpam_handle, sshpam_err)); | 969 | pam_strerror(sshpam_handle, sshpam_err)); |
951 | sshpam_err = pam_open_session(sshpam_handle, 0); | 970 | sshpam_err = pam_open_session(sshpam_handle, 0); |
952 | if (sshpam_err != PAM_SUCCESS) | 971 | if (sshpam_err == PAM_SUCCESS) |
953 | fatal("PAM: pam_open_session(): %s", | 972 | sshpam_session_open = 1; |
973 | else { | ||
974 | sshpam_session_open = 0; | ||
975 | disable_forwarding(); | ||
976 | error("PAM: pam_open_session(): %s", | ||
954 | pam_strerror(sshpam_handle, sshpam_err)); | 977 | pam_strerror(sshpam_handle, sshpam_err)); |
955 | sshpam_session_open = 1; | 978 | } |
979 | |||
980 | } | ||
981 | |||
982 | int | ||
983 | is_pam_session_open(void) | ||
984 | { | ||
985 | return sshpam_session_open; | ||
956 | } | 986 | } |
957 | 987 | ||
958 | /* | 988 | /* |
@@ -1075,7 +1105,6 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) | |||
1075 | { | 1105 | { |
1076 | int flags = (options.permit_empty_passwd == 0 ? | 1106 | int flags = (options.permit_empty_passwd == 0 ? |
1077 | PAM_DISALLOW_NULL_AUTHTOK : 0); | 1107 | PAM_DISALLOW_NULL_AUTHTOK : 0); |
1078 | static char badpw[] = "\b\n\r\177INCORRECT"; | ||
1079 | 1108 | ||
1080 | if (!options.use_pam || sshpam_handle == NULL) | 1109 | if (!options.use_pam || sshpam_handle == NULL) |
1081 | fatal("PAM: %s called when PAM disabled or failed to " | 1110 | fatal("PAM: %s called when PAM disabled or failed to " |