From 8efdd957ba8310515242ba2979ff07130a0b1a3a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 12 Apr 2004 20:46:13 +0000 Subject: [PATCH] r188: Add a new 'helper protocol' to ntlm_auth. This protocol looks rather like SMTP headers/LDAP: NT-Domain: TESTWG Username: abartlet ... Password: foo Challenge-response passwords are in hexideciaml, while any 'plain' string can be base64 encoded when like this: Password:: Zm9vCg== (the :: indicates it, just like LDAP - I hope) The protocol is not final, so it is #ifdef DEVELOPER for now (so nobody starts to rely on it until I'm happy), but we may as well get this into subversion. My intention is to use this to power the next version of my PPP/ntlm_auth plugin, and hopefully entice a FreeRadius plugin out of the woods. Andrew Bartlett --- source/utils/ntlm_auth.c | 204 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 2 deletions(-) diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c index 45e37dc37ff..9e65040107a 100644 --- a/source/utils/ntlm_auth.c +++ b/source/utils/ntlm_auth.c @@ -37,6 +37,7 @@ enum stdio_helper_mode { NTLMSSP_CLIENT_1, GSS_SPNEGO, GSS_SPNEGO_CLIENT, + NTLM_SERVER_1, NUM_HELPER_MODES }; @@ -58,6 +59,9 @@ static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode, static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode, char *buf, int length); +static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, + char *buf, int length); + static const struct { enum stdio_helper_mode mode; const char *name; @@ -69,6 +73,9 @@ static const struct { { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_client_ntlmssp_request}, { GSS_SPNEGO, "gss-spnego", manage_gss_spnego_request}, { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gss_spnego_client_request}, +#ifdef DEVELOPER + { NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request}, +#endif { NUM_HELPER_MODES, NULL, NULL} }; @@ -719,7 +726,7 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, pass=memchr(buf,' ',length); if (!pass) { DEBUG(2, ("Password not found. Denying access\n")); - x_fprintf(x_stderr, "ERR\n"); + x_fprintf(x_stdout, "ERR\n"); return; } *pass='\0'; @@ -1268,7 +1275,7 @@ static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper /* We asked for a password and obviously got it :-) */ opt_password = strndup((const char *)request.data, request.length); - + if (opt_password == NULL) { DEBUG(1, ("Out of memory\n")); x_fprintf(x_stdout, "BH\n"); @@ -1381,6 +1388,199 @@ static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper return; } +static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode, + char *buf, int length) +{ + char *request, *parameter; + static DATA_BLOB challenge; + static DATA_BLOB lm_response; + static DATA_BLOB nt_response; + static char *full_username; + static char *username; + static char *domain; + static char *plaintext_password; + static BOOL ntlm_server_1_user_session_key; + static BOOL ntlm_server_1_lm_session_key; + + if (strequal(buf, ".")) { + if (!full_username && !username) { + x_fprintf(x_stdout, "Error: No username supplied!\n"); + } else if (plaintext_password) { + /* handle this request as plaintext */ + if (!full_username) { + if (asprintf(&full_username, "%s%c%s", domain, winbind_separator(), username) == -1) { + x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n"); + return; + } + } + if (check_plaintext_auth(full_username, plaintext_password, False)) { + x_fprintf(x_stdout, "Authenticated: Yes\n"); + } else { + x_fprintf(x_stdout, "Authenticated: No\n"); + } + } else if (!lm_response.data || !nt_response.data) { + x_fprintf(x_stdout, "Error: No password supplied!\n"); + } else if (!challenge.data) { + x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n"); + } else { + char *error_string = NULL; + uchar lm_key[8]; + uchar user_session_key[16]; + uint32 flags = 0; + + if (full_username && !username) { + fstring fstr_user; + fstring fstr_domain; + + if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) { + /* username might be 'tainted', don't print into our new-line deleimianted stream */ + x_fprintf(x_stdout, "Error: Could not parse into domain and username\n"); + } + SAFE_FREE(username); + SAFE_FREE(domain); + username = smb_xstrdup(fstr_user); + domain = smb_xstrdup(fstr_domain); + } + + if (!domain) { + domain = smb_xstrdup(get_winbind_domain()); + } + + if (ntlm_server_1_lm_session_key) + flags |= WBFLAG_PAM_LMKEY; + + if (ntlm_server_1_user_session_key) + flags |= WBFLAG_PAM_USER_SESSION_KEY; + + if (!NT_STATUS_IS_OK( + contact_winbind_auth_crap(username, + domain, + global_myname(), + &challenge, + &lm_response, + &nt_response, + flags, + lm_key, + user_session_key, + &error_string, + NULL))) { + + x_fprintf(x_stdout, "Authenticated: No\n"); + x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string); + SAFE_FREE(error_string); + } else { + static char zeros[16]; + char *hex_lm_key; + char *hex_user_session_key; + + x_fprintf(x_stdout, "Authenticated: Yes\n"); + + if (ntlm_server_1_lm_session_key + && (memcmp(zeros, lm_key, + sizeof(lm_key)) != 0)) { + hex_encode((const unsigned char *)lm_key, + sizeof(lm_key), + &hex_lm_key); + x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key); + SAFE_FREE(hex_lm_key); + } + + if (ntlm_server_1_user_session_key + && (memcmp(zeros, user_session_key, + sizeof(user_session_key)) != 0)) { + hex_encode((const unsigned char *)user_session_key, + sizeof(user_session_key), + &hex_user_session_key); + x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key); + SAFE_FREE(hex_user_session_key); + } + } + } + /* clear out the state */ + challenge = data_blob(NULL, 0); + nt_response = data_blob(NULL, 0); + lm_response = data_blob(NULL, 0); + SAFE_FREE(full_username); + SAFE_FREE(username); + SAFE_FREE(domain); + SAFE_FREE(plaintext_password); + ntlm_server_1_user_session_key = False; + ntlm_server_1_lm_session_key = False; + x_fprintf(x_stdout, ".\n"); + + return; + } + + request = buf; + + parameter = strstr_m(request, ": "); + if (!parameter) { + /* Indicates a base64 encoded structure */ + parameter = strstr_m(request, ":: "); + + if (!parameter) { + DEBUG(0, ("Parameter not found!\n")); + x_fprintf(x_stdout, "Error: Parameter not found!\n.\n"); + return; + } + parameter[0] ='\0'; + parameter++; + parameter[0] ='\0'; + parameter++; + parameter[0] ='\0'; + parameter++; + + base64_decode_inplace(parameter); + } else { + + parameter[0] ='\0'; + parameter++; + parameter[0] ='\0'; + parameter++; + } + + if (strequal(request, "LANMAN-Challenge")) { + challenge = strhex_to_data_blob(parameter); + if (challenge.length != 8) { + x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n", + parameter, + (int)challenge.length); + challenge = data_blob(NULL, 0); + } + } else if (strequal(request, "NT-Response")) { + nt_response = strhex_to_data_blob(parameter); + if (nt_response.length < 24) { + x_fprintf(x_stdout, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n", + parameter, + (int)opt_nt_response.length); + nt_response = data_blob(NULL, 0); + } + } else if (strequal(request, "LANMAN-Response")) { + lm_response = strhex_to_data_blob(parameter); + if (lm_response.length != 24) { + x_fprintf(x_stdout, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n", + parameter, + (int)lm_response.length); + lm_response = data_blob(NULL, 0); + } + } else if (strequal(request, "Password")) { + plaintext_password = smb_xstrdup(parameter); + } else if (strequal(request, "NT-Domain")) { + domain = smb_xstrdup(parameter); + } else if (strequal(request, "Username")) { + username = smb_xstrdup(parameter); + } else if (strequal(request, "Full-Username")) { + full_username = smb_xstrdup(parameter); + } else if (strequal(request, "Request-User-Session-Key")) { + ntlm_server_1_user_session_key = strequal(parameter, "Yes"); + } else if (strequal(request, "Request-LanMan-Session-Key")) { + ntlm_server_1_lm_session_key = strequal(parameter, "Yes"); + } else { + x_fprintf(x_stdout, "Error: Unknown request %s\n", request); + } + x_fprintf(x_stdout, ".\n"); +} + static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn) { char buf[SQUID_BUFFER_SIZE+1];