diff options
Diffstat (limited to 'source3/utils/ntlm_auth.c')
-rw-r--r-- | source3/utils/ntlm_auth.c | 547 |
1 files changed, 121 insertions, 426 deletions
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 88913c8051..ac456769f2 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -4,7 +4,7 @@ Winbind status program. Copyright (C) Tim Potter 2000-2002 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 + Copyright (C) Andrew Bartlett 2003 Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000 This program is free software; you can redistribute it and/or modify @@ -39,17 +39,22 @@ enum squid_mode { extern int winbindd_fd; static const char *helper_protocol; -static const char *opt_username; -static const char *opt_domain; -static const char *opt_workstation; -static const char *opt_password; -static DATA_BLOB opt_challenge; -static DATA_BLOB opt_lm_response; -static DATA_BLOB opt_nt_response; +static const char *username; +static const char *domain; +static const char *workstation; +static const char *hex_challenge; +static const char *hex_lm_response; +static const char *hex_nt_response; +static unsigned char *challenge; +static size_t challenge_len; +static unsigned char *lm_response; +static size_t lm_response_len; +static unsigned char *nt_response; +static size_t nt_response_len; static int request_lm_key; static int request_nt_key; -static int diagnostics; +static char *password; static char winbind_separator(void) { @@ -157,110 +162,58 @@ static BOOL check_plaintext_auth(const char *user, const char *pass, BOOL stdout d_printf("Reading winbind reply failed! (0x01)\n"); } - d_printf("%s: %s (0x%x)\n", + d_printf("%s (0x%x)\n", response.data.auth.nt_status_string, - response.data.auth.error_string, response.data.auth.nt_status); } else { if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) { DEBUG(1, ("Reading winbind reply failed! (0x01)\n")); } - DEBUG(3, ("%s: %s (0x%x)\n", - response.data.auth.nt_status_string, - response.data.auth.error_string, - response.data.auth.nt_status)); + DEBUG(3, ("%s (0x%x)\n", + response.data.auth.nt_status_string, + response.data.auth.nt_status)); } return (result == NSS_STATUS_SUCCESS); } -/* authenticate a user with an encrypted username/password */ - -static NTSTATUS contact_winbind_auth_crap(const char *username, - const char *domain, - const char *workstation, - const DATA_BLOB *challenge, - const DATA_BLOB *lm_response, - const DATA_BLOB *nt_response, - uint32 flags, - uint8 lm_key[16], - uint8 nt_key[16], - char **error_string) +static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state) { - NTSTATUS nt_status; - NSS_STATUS result; struct winbindd_request request; struct winbindd_response response; - - static uint8 zeros[16]; + NSS_STATUS result; + /* Send off request */ ZERO_STRUCT(request); ZERO_STRUCT(response); - request.data.auth_crap.flags = flags; - - fstrcpy(request.data.auth_crap.user, username); - - fstrcpy(request.data.auth_crap.domain, domain); - fstrcpy(request.data.auth_crap.workstation, workstation); - - memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8)); + fstrcpy(request.data.auth_crap.user, ntlmssp_state->user); - if (lm_response && lm_response->length) { - memcpy(request.data.auth_crap.lm_resp, lm_response->data, MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp))); - request.data.auth_crap.lm_resp_len = lm_response->length; - } - - if (nt_response && nt_response->length) { - memcpy(request.data.auth_crap.nt_resp, nt_response->data, MIN(nt_response->length, sizeof(request.data.auth_crap.nt_resp))); - request.data.auth_crap.nt_resp_len = nt_response->length; - } + fstrcpy(request.data.auth_crap.domain, ntlmssp_state->domain); + fstrcpy(request.data.auth_crap.workstation, ntlmssp_state->workstation); + memcpy(request.data.auth_crap.chal, ntlmssp_state->chal.data, + MIN(ntlmssp_state->chal.length, 8)); + + memcpy(request.data.auth_crap.lm_resp, ntlmssp_state->lm_resp.data, + MIN(ntlmssp_state->lm_resp.length, sizeof(request.data.auth_crap.lm_resp))); + + memcpy(request.data.auth_crap.nt_resp, ntlmssp_state->nt_resp.data, + MIN(ntlmssp_state->nt_resp.length, sizeof(request.data.auth_crap.nt_resp))); + + request.data.auth_crap.lm_resp_len = ntlmssp_state->lm_resp.length; + request.data.auth_crap.nt_resp_len = ntlmssp_state->nt_resp.length; + result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response); /* Display response */ if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) { - nt_status = NT_STATUS_UNSUCCESSFUL; - if (error_string) - *error_string = smb_xstrdup("Reading winbind reply failed!"); - return nt_status; - } - - nt_status = (NT_STATUS(response.data.auth.nt_status)); - if (!NT_STATUS_IS_OK(nt_status)) { - if (error_string) - *error_string = smb_xstrdup(response.data.auth.error_string); - return nt_status; + return NT_STATUS_UNSUCCESSFUL; } - if ((flags & WINBIND_PAM_LMKEY) && lm_key - && (memcmp(zeros, response.data.auth.first_8_lm_hash, - sizeof(response.data.auth.first_8_lm_hash)) != 0)) { - memcpy(lm_key, response.data.auth.first_8_lm_hash, - sizeof(response.data.auth.first_8_lm_hash)); - } - if ((flags & WINBIND_PAM_NTKEY) && nt_key - && (memcmp(zeros, response.data.auth.nt_session_key, - sizeof(response.data.auth.nt_session_key)) != 0)) { - memcpy(nt_key, response.data.auth.nt_session_key, - sizeof(response.data.auth.nt_session_key)); - } - return nt_status; -} - -static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state) -{ - return contact_winbind_auth_crap(ntlmssp_state->user, ntlmssp_state->domain, - ntlmssp_state->workstation, - &ntlmssp_state->chal, - &ntlmssp_state->lm_resp, - &ntlmssp_state->nt_resp, - 0, - NULL, - NULL, - NULL); + return NT_STATUS(response.data.auth.nt_status); } static void manage_squid_ntlmssp_request(enum squid_mode squid_mode, @@ -403,283 +356,72 @@ static void squid_stream(enum squid_mode squid_mode) { static BOOL check_auth_crap(void) { - NTSTATUS nt_status; - uint32 flags = 0; - char lm_key[8]; - char nt_key[16]; - char *hex_lm_key; - char *hex_nt_key; - char *error_string; - + struct winbindd_request request; + struct winbindd_response response; + char *lm_key; + char *nt_key; static uint8 zeros[16]; - if (request_lm_key) - flags |= WINBIND_PAM_LMKEY; - - if (request_nt_key) - flags |= WINBIND_PAM_NTKEY; - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &opt_challenge, - &opt_lm_response, - &opt_nt_response, - flags, - lm_key, - nt_key, - &error_string); - - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } - - if (request_lm_key - && (memcmp(zeros, lm_key, - sizeof(lm_key)) != 0)) { - hex_encode(lm_key, - sizeof(lm_key), - &hex_lm_key); - d_printf("LM_KEY: %s\n", hex_lm_key); - SAFE_FREE(hex_lm_key); - } - if (request_nt_key - && (memcmp(zeros, nt_key, - sizeof(nt_key)) != 0)) { - hex_encode(nt_key, - sizeof(nt_key), - &hex_nt_key); - d_printf("NT_KEY: %s\n", hex_nt_key); - SAFE_FREE(hex_nt_key); - } - - return True; -} - -/* - Authenticate a user with a challenge/response, checking session key - and valid authentication types -*/ - -static const DATA_BLOB get_challenge(void) -{ - static DATA_BLOB chal; - if (opt_challenge.length) - return opt_challenge; - - chal = data_blob(NULL, 8); - - generate_random_buffer(chal.data, chal.length, False); - return chal; -} - -static BOOL test_lm(void) -{ - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB lm_response = data_blob(NULL, 24); - - uchar lm_key[8]; - uchar lm_hash[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - flags |= WINBIND_PAM_LMKEY; - - SMBencrypt(opt_password,chall.data,lm_response.data); - E_deshash(opt_password, lm_hash); - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, - &chall, - &lm_response, - NULL, - flags, - lm_key, - NULL, - &error_string); - - data_blob_free(&lm_response); - - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - return False; - } + NSS_STATUS result; + /* Send off request */ - if (memcmp(lm_hash, lm_key, - sizeof(lm_key)) != 0) { - DEBUG(1, ("LM Key does not match expectations!\n")); - DEBUG(1, ("lm_key:\n")); - dump_data(1, lm_key, 8); - DEBUG(1, ("expected:\n")); - dump_data(1, lm_hash, 8); - } - return True; -} + ZERO_STRUCT(request); + ZERO_STRUCT(response); -static BOOL test_lm_ntlm(void) -{ - BOOL pass = True; - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB lm_response = data_blob(NULL, 24); - DATA_BLOB nt_response = data_blob(NULL, 24); - DATA_BLOB session_key = data_blob(NULL, 16); - - uchar lm_key[8]; - uchar nt_key[16]; - uchar lm_hash[16]; - uchar nt_hash[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; - - SMBencrypt(opt_password,chall.data,lm_response.data); - E_deshash(opt_password, lm_hash); - - SMBNTencrypt(opt_password,chall.data,nt_response.data); - - E_md4hash(opt_password, nt_hash); - SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &chall, - &lm_response, - &nt_response, - flags, - lm_key, - nt_key, - &error_string); - - data_blob_free(&lm_response); + if (request_lm_key) + request.data.auth_crap.flags |= WINBIND_PAM_LMKEY; - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } + if (request_nt_key) + request.data.auth_crap.flags |= WINBIND_PAM_NTKEY; - if (memcmp(lm_hash, lm_key, - sizeof(lm_key)) != 0) { - DEBUG(1, ("LM Key does not match expectations!\n")); - DEBUG(1, ("lm_key:\n")); - dump_data(1, lm_key, 8); - DEBUG(1, ("expected:\n")); - dump_data(1, lm_hash, 8); - pass = False; - } - if (memcmp(session_key.data, nt_key, - sizeof(nt_key)) != 0) { - DEBUG(1, ("NT Session Key does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, nt_key, 16); - DEBUG(1, ("expected:\n")); - dump_data(1, session_key.data, session_key.length); - pass = False; - } - return pass; -} + fstrcpy(request.data.auth_crap.user, username); -static BOOL test_ntlm(void) -{ - BOOL pass = True; - NTSTATUS nt_status; - uint32 flags = 0; - DATA_BLOB nt_response = data_blob(NULL, 24); - DATA_BLOB session_key = data_blob(NULL, 16); - - char nt_key[16]; - char nt_hash[16]; - DATA_BLOB chall = get_challenge(); - char *error_string; - - flags |= WINBIND_PAM_NTKEY; - - SMBNTencrypt(opt_password,chall.data,nt_response.data); - E_md4hash(opt_password, nt_hash); - SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); - - nt_status = contact_winbind_auth_crap(opt_username, opt_domain, - opt_workstation, - &chall, - NULL, - &nt_response, - flags, - NULL, - nt_key, - &error_string); + fstrcpy(request.data.auth_crap.domain, domain); + fstrcpy(request.data.auth_crap.workstation, workstation); - data_blob_free(&nt_response); + memcpy(request.data.auth_crap.chal, challenge, MIN(challenge_len, 8)); - if (!NT_STATUS_IS_OK(nt_status)) { - d_printf("%s (0x%x)\n", - error_string, - NT_STATUS_V(nt_status)); - SAFE_FREE(error_string); - return False; - } - - if (memcmp(session_key.data, nt_key, - sizeof(nt_key)) != 0) { - DEBUG(1, ("NT Session Key does not match expectations!\n")); - DEBUG(1, ("nt_key:\n")); - dump_data(1, nt_key, 16); - DEBUG(1, ("expected:\n")); - dump_data(1, session_key.data, session_key.length); - pass = False; - } - return pass; -} + memcpy(request.data.auth_crap.lm_resp, lm_response, MIN(lm_response_len, sizeof(request.data.auth_crap.lm_resp))); + + memcpy(request.data.auth_crap.nt_resp, nt_response, MIN(nt_response_len, sizeof(request.data.auth_crap.nt_resp))); + + request.data.auth_crap.lm_resp_len = lm_response_len; + request.data.auth_crap.nt_resp_len = nt_response_len; -/* - Tests: - - - LM only - - NT and LM - - NT - - NTLMv2 - - NTLMv2 and LMv2 - - LMv2 - - check we get the correct session key in each case - check what values we get for the LM session key - -*/ - -struct ntlm_tests { - BOOL (*fn)(); - const char *name; -} test_table[] = { - {test_lm, "test LM"}, - {test_lm_ntlm, "test LM and NTLM"}, - {test_ntlm, "test NTLM"} -/* {test_lm_ntlmv2, "test NTLMv2"}, */ -/* {test_lm_ntlmv2, "test NTLMv2 and LMv2"}, */ -/* {test_lm_ntlmv2, "test LMv2"} */ -}; + result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response); -static BOOL diagnose_ntlm_auth(void) -{ - unsigned int i; - BOOL pass = True; + /* Display response */ - for (i=0; test_table[i].fn; i++) { - if (!test_table[i].fn()) { - DEBUG(1, ("Test %s failed!\n", test_table[i].name)); - pass = False; + if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) { + d_printf("Reading winbind reply failed! (0x01)\n"); + } + + d_printf("%s (0x%x)\n", + response.data.auth.nt_status_string, + response.data.auth.nt_status); + + if (response.data.auth.nt_status == 0) { + if (request_lm_key + && (memcmp(zeros, response.data.auth.first_8_lm_hash, + sizeof(response.data.auth.first_8_lm_hash)) != 0)) { + hex_encode(response.data.auth.first_8_lm_hash, + sizeof(response.data.auth.first_8_lm_hash), + &lm_key); + d_printf("LM_KEY: %s\n", lm_key); + SAFE_FREE(lm_key); + } + if (request_nt_key + && (memcmp(zeros, response.data.auth.nt_session_key, + sizeof(response.data.auth.nt_session_key)) != 0)) { + hex_encode(response.data.auth.nt_session_key, + sizeof(response.data.auth.nt_session_key), + &nt_key); + d_printf("NT_KEY: %s\n", nt_key); + SAFE_FREE(nt_key); } } - return pass; + return result == NSS_STATUS_SUCCESS; } /* Main program */ @@ -694,49 +436,31 @@ enum { OPT_NT, OPT_PASSWORD, OPT_LM_KEY, - OPT_NT_KEY, - OPT_DIAGNOSTICS + OPT_NT_KEY }; - int main(int argc, const char **argv) +int main(int argc, const char **argv) { int opt; - static const char *hex_challenge; - static const char *hex_lm_response; - static const char *hex_nt_response; - char *challenge; - char *lm_response; - char *nt_response; - size_t challenge_len; - size_t lm_response_len; - size_t nt_response_len; - poptContext pc; - - /* NOTE: DO NOT change this interface without considering the implications! - This is an external interface, which other programs will use to interact - with this helper. - */ - - /* We do not use single-letter command abbreviations, because they harm future - interface stability. */ - struct poptOption long_options[] = { POPT_AUTOHELP + { "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"}, - { "username", 0, POPT_ARG_STRING, &opt_username, OPT_USERNAME, "username"}, - { "domain", 0, POPT_ARG_STRING, &opt_domain, OPT_DOMAIN, "domain name"}, - { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"}, + { "username", 0, POPT_ARG_STRING, &username, OPT_USERNAME, "username"}, + { "domain", 0, POPT_ARG_STRING, &domain, OPT_DOMAIN, "domain name"}, + { "workstation", 0, POPT_ARG_STRING, &domain, OPT_WORKSTATION, "workstation"}, { "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"}, { "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"}, { "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"}, - { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"}, + { "password", 0, POPT_ARG_STRING, &password, OPT_PASSWORD, "User's plaintext password"}, { "request-lm-key", 0, POPT_ARG_NONE, &request_lm_key, OPT_LM_KEY, "Retreive LM session key"}, { "request-nt-key", 0, POPT_ARG_NONE, &request_nt_key, OPT_NT_KEY, "Retreive NT session key"}, - { "diagnostics", 0, POPT_ARG_NONE, &diagnostics, OPT_DIAGNOSTICS, "Perform diagnostics on the authentictaion chain"}, - POPT_COMMON_SAMBA - POPT_TABLEEND + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug }, + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile }, + { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version}, + { 0, 0, 0, 0 } }; /* Samba client initialisation */ @@ -760,40 +484,29 @@ enum { while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_CHALLENGE: - challenge = smb_xmalloc((strlen(hex_challenge)+1)/2); - if ((challenge_len = strhex_to_str(challenge, - strlen(hex_challenge), - hex_challenge)) != 8) { - x_fprintf(x_stderr, "hex decode of %s failed (only got %u bytes)!\n", + challenge_len = strlen(hex_challenge); + challenge = smb_xmalloc((challenge_len+1)/2); + if ((challenge_len = strhex_to_str(challenge, challenge_len, hex_challenge)) != 8) { + fprintf(stderr, "hex decode of %s failed (only got %u bytes)!\n", hex_challenge, challenge_len); exit(1); } - opt_challenge = data_blob(challenge, challenge_len); - SAFE_FREE(challenge); break; case OPT_LM: - lm_response = smb_xmalloc((strlen(hex_lm_response)+1)/2); - lm_response_len = strhex_to_str(lm_response, - strlen(hex_lm_response), - hex_lm_response); - if (lm_response_len != 24) { - x_fprintf(x_stderr, "hex decode of %s failed!\n", hex_lm_response); + lm_response_len = strlen(hex_lm_response); + lm_response = smb_xmalloc((lm_response_len+1)/2); + if ((lm_response_len = strhex_to_str(lm_response, lm_response_len, hex_lm_response)) != 24) { + fprintf(stderr, "hex decode of %s failed!\n", hex_lm_response); exit(1); } - opt_lm_response = data_blob(lm_response, lm_response_len); - SAFE_FREE(lm_response); break; case OPT_NT: - nt_response = smb_xmalloc((strlen(hex_nt_response)+1)/2); - nt_response_len = strhex_to_str(nt_response, - strlen(hex_nt_response), - hex_nt_response); - if (nt_response_len < 24) { - x_fprintf(x_stderr, "hex decode of %s failed!\n", hex_nt_response); + nt_response_len = strlen(hex_nt_response); + nt_response = smb_xmalloc((nt_response_len+1)/2); + if ((nt_response_len = strhex_to_str(nt_response, nt_response_len, hex_nt_response)) < 24) { + fprintf(stderr, "hex decode of %s failed!\n", hex_nt_response); exit(1); } - opt_nt_response = data_blob(nt_response, nt_response_len); - SAFE_FREE(nt_response); break; } } @@ -806,45 +519,27 @@ enum { } else if (strcmp(helper_protocol, "squid-2.4-basic")== 0) { squid_stream(SQUID_2_4_BASIC); } else { - x_fprintf(x_stderr, "unknown helper protocol [%s]\n", helper_protocol); + fprintf(stderr, "unknown helper protocol [%s]\n", helper_protocol); exit(1); } } - if (!opt_username) { - x_fprintf(x_stderr, "username must be specified!\n\n"); - poptPrintHelp(pc, stderr, 0); - exit(1); - } - - if (opt_domain == NULL) { - opt_domain = get_winbind_domain(); + if (domain == NULL) { + domain = get_winbind_domain(); } - if (opt_workstation == NULL) { - opt_workstation = ""; + if (workstation == NULL) { + workstation = ""; } - if (opt_challenge.length) { + if (challenge) { if (!check_auth_crap()) { exit(1); } - exit(0); - } - - if (!opt_password) { - opt_password = getpass("password: "); - } - - if (diagnostics) { - if (!diagnose_ntlm_auth()) { - exit(1); - } - } else { + } else if (password) { fstring user; - - snprintf(user, sizeof(user)-1, "%s%c%s", opt_domain, winbind_separator(), opt_username); - if (!check_plaintext_auth(user, opt_password, True)) { + snprintf(user, sizeof(user)-1, "%s%c%s", domain, winbind_separator(), username); + if (!check_plaintext_auth(user, password, True)) { exit(1); } } |