diff options
-rw-r--r-- | source4/utils/ntlm_auth.c | 197 |
1 files changed, 135 insertions, 62 deletions
diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c index b038ad9879..feaae17abb 100644 --- a/source4/utils/ntlm_auth.c +++ b/source4/utils/ntlm_auth.c @@ -50,19 +50,23 @@ enum stdio_helper_mode { typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private); + char *buf, int length, void **private, + unsigned int mux_id); static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private); + char *buf, int length, void **private, + unsigned int mux_id); static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private); + char *buf, int length, void **private, + unsigned int mux_id); static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private); + char *buf, int length, void **private, + unsigned int mux_id); static void manage_squid_request(enum stdio_helper_mode helper_mode, - stdio_helper_function fn, void *private); + stdio_helper_function fn); static const struct { enum stdio_helper_mode mode; @@ -85,13 +89,31 @@ const char *opt_username; const char *opt_domain; const char *opt_workstation; const char *opt_password; +int opt_multiplex; + + +static void mux_printf(unsigned int mux_id, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); + +static void mux_printf(unsigned int mux_id, const char *format, ...) +{ + va_list ap; + + if (opt_multiplex) { + x_fprintf(x_stdout, "%d ", mux_id); + } + + va_start(ap, format); + x_vfprintf(x_stdout, format, ap); + va_end(ap); +} + /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the form DOMAIN/user into a domain and a user */ static BOOL parse_ntlm_auth_domain_user(const char *domuser, fstring domain, - fstring user) + fstring user) { char *p = strchr(domuser,*lp_winbind_separator()); @@ -179,7 +201,8 @@ static NTSTATUS local_pw_check_specified(const char *username, } static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private) + char *buf, int length, void **private, + unsigned int mux_id) { char *user, *pass; user=buf; @@ -187,7 +210,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_stdout, "ERR\n"); + mux_printf(mux_id, "ERR\n"); return; } *pass='\0'; @@ -199,9 +222,9 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, } if (check_plaintext_auth(user, pass, False)) { - x_fprintf(x_stdout, "OK\n"); + mux_printf(mux_id, "OK\n"); } else { - x_fprintf(x_stdout, "ERR\n"); + mux_printf(mux_id, "ERR\n"); } } @@ -209,13 +232,14 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, to the calling application. The callback comes from within gensec */ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private) + char *buf, int length, void **private, + unsigned int mux_id) { DATA_BLOB in; struct gensec_security **gensec_state = (struct gensec_security **)private; if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); return; } @@ -232,17 +256,17 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod if ((*gensec_state)->password_callback_private == NULL) { DEBUG(1, ("Out of memory\n")); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); data_blob_free(&in); return; } - x_fprintf(x_stdout, "OK\n"); + mux_printf(mux_id, "OK\n"); data_blob_free(&in); return; } DEBUG(1, ("Asked for (and expected) a password\n")); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); data_blob_free(&in); } @@ -251,16 +275,17 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod * for the stdio part of this. */ -static NTSTATUS get_password(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, +static NTSTATUS get_password(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, char **password) { *password = NULL; /* Ask for a password */ - x_fprintf(x_stdout, "PW\n"); + mux_printf((unsigned int)gensec_security->password_callback_private, "PW\n"); gensec_security->password_callback_private = NULL; - manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, &gensec_security); + manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request); *password = (char *)gensec_security->password_callback_private; if (*password) { return NT_STATUS_OK; @@ -270,7 +295,8 @@ static NTSTATUS get_password(struct gensec_security *gensec_security, TALLOC_CTX } static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private) + char *buf, int length, void **private, + unsigned int mux_id) { DATA_BLOB in; DATA_BLOB out = data_blob(NULL, 0); @@ -283,7 +309,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); return; } @@ -308,7 +334,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, (strncmp(buf, "NA ", 3) != 0) && (strncmp(buf, "PW ", 3) != 0)) { DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); data_blob_free(&in); return; } @@ -328,12 +354,12 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (opt_password) { if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state, opt_password))) { DEBUG(1, ("Out of memory\n")); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); data_blob_free(&in); return; } } else { - gensec_set_password_callback(*gensec_state, get_password, NULL); + gensec_set_password_callback(*gensec_state, get_password, (void*)mux_id); } break; @@ -351,8 +377,14 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, case GSS_SPNEGO_CLIENT: case GSS_SPNEGO_SERVER: nt_status = gensec_start_mech_by_oid(*gensec_state, OID_SPNEGO); + if (!in.length) { + first = True; + } break; case NTLMSSP_CLIENT_1: + if (!in.length) { + first = True; + } case SQUID_2_5_NTLMSSP: nt_status = gensec_start_mech_by_oid(*gensec_state, OID_NTLMSSP); break; @@ -362,12 +394,9 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("SPENGO login failed to initialise: %s\n", nt_errstr(nt_status))); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); return; } - if (!in.length) { - first = True; - } } if (strncmp(buf, "PW ", 3) == 0) { @@ -377,12 +406,12 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, (const char *)in.data, in.length)))) { DEBUG(1, ("Out of memory\n")); - x_fprintf(x_stdout, "BH\n"); + mux_printf(mux_id, "BH\n"); data_blob_free(&in); return; } - x_fprintf(x_stdout, "OK\n"); + mux_printf(mux_id, "OK\n"); data_blob_free(&in); return; } @@ -449,17 +478,17 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, switch (stdio_helper_mode) { case GSS_SPNEGO_SERVER: - x_fprintf(x_stdout, "%s %s %s\n", reply_code, + mux_printf(mux_id, "%s %s %s\n", reply_code, out_base64 ? out_base64 : "*", reply_arg ? reply_arg : "*"); break; default: if (out_base64) { - x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64); + mux_printf(mux_id, "%s %s\n", reply_code, out_base64); } else if (reply_arg) { - x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg); + mux_printf(mux_id, "%s %s\n", reply_code, reply_arg); } else { - x_fprintf(x_stdout, "%s\n", reply_code); + mux_printf(mux_id, "%s\n", reply_code); } } @@ -468,7 +497,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, } static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private) + char *buf, int length, void **private, + unsigned int mux_id) { char *request, *parameter; static DATA_BLOB challenge; @@ -483,24 +513,24 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod if (strequal(buf, ".")) { if (!full_username && !username) { - x_fprintf(x_stdout, "Error: No username supplied!\n"); + mux_printf(mux_id, "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, *lp_winbind_separator(), username) == -1) { - x_fprintf(x_stdout, "Error: Out of memory in asprintf!\n.\n"); + mux_printf(mux_id, "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"); + mux_printf(mux_id, "Authenticated: Yes\n"); } else { - x_fprintf(x_stdout, "Authenticated: No\n"); + mux_printf(mux_id, "Authenticated: No\n"); } } else if (!lm_response.data && !nt_response.data) { - x_fprintf(x_stdout, "Error: No password supplied!\n"); + mux_printf(mux_id, "Error: No password supplied!\n"); } else if (!challenge.data) { - x_fprintf(x_stdout, "Error: No lanman-challenge supplied!\n"); + mux_printf(mux_id, "Error: No lanman-challenge supplied!\n"); } else { char *error_string = NULL; DATA_BLOB lm_key; @@ -513,7 +543,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod 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"); + mux_printf(mux_id, "Error: Could not parse into domain and username\n"); } SAFE_FREE(username); SAFE_FREE(domain); @@ -544,15 +574,15 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod &error_string, NULL))) { - x_fprintf(x_stdout, "Authenticated: No\n"); - x_fprintf(x_stdout, "Authentication-Error: %s\n.\n", error_string); + mux_printf(mux_id, "Authenticated: No\n"); + mux_printf(mux_id, "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"); + mux_printf(mux_id, "Authenticated: Yes\n"); if (ntlm_server_1_lm_session_key && lm_key.length @@ -561,7 +591,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod hex_encode(lm_key.data, lm_key.length, &hex_lm_key); - x_fprintf(x_stdout, "LANMAN-Session-Key: %s\n", hex_lm_key); + mux_printf(mux_id, "LANMAN-Session-Key: %s\n", hex_lm_key); SAFE_FREE(hex_lm_key); } @@ -572,7 +602,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod hex_encode(user_session_key.data, user_session_key.length, &hex_user_session_key); - x_fprintf(x_stdout, "User-Session-Key: %s\n", hex_user_session_key); + mux_printf(mux_id, "User-Session-Key: %s\n", hex_user_session_key); SAFE_FREE(hex_user_session_key); } } @@ -587,7 +617,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod SAFE_FREE(plaintext_password); ntlm_server_1_user_session_key = False; ntlm_server_1_lm_session_key = False; - x_fprintf(x_stdout, ".\n"); + mux_printf(mux_id, ".\n"); return; } @@ -601,7 +631,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod if (!parameter) { DEBUG(0, ("Parameter not found!\n")); - x_fprintf(x_stdout, "Error: Parameter not found!\n.\n"); + mux_printf(mux_id, "Error: Parameter not found!\n.\n"); return; } @@ -624,7 +654,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod 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", + mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n", parameter, (int)challenge.length); challenge = data_blob(NULL, 0); @@ -632,7 +662,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod } 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", + mux_printf(mux_id, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n", parameter, (int)nt_response.length); nt_response = data_blob(NULL, 0); @@ -640,7 +670,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod } 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", + mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n", parameter, (int)lm_response.length); lm_response = data_blob(NULL, 0); @@ -658,16 +688,26 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod } 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.\n", request); + mux_printf(mux_id, "Error: Unknown request %s\n.\n", request); } } -static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn, void *private) +static void manage_squid_request(enum stdio_helper_mode helper_mode, + stdio_helper_function fn) { char buf[SQUID_BUFFER_SIZE+1]; + unsigned int mux_id; int length; char *c; static BOOL err; + struct mux_private { + unsigned int max_mux; + void **private_pointers; + }; + + static struct mux_private *mux_private; + static void *normal_private; + void **private; /* this is not a typo - x_fgets doesn't work too well under squid */ if (fgets(buf, sizeof(buf)-1, stdin) == NULL) { @@ -689,8 +729,8 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helpe return; } if (err) { - DEBUG(2, ("Oversized message\n")); - x_fprintf(x_stderr, "ERR\n"); + DEBUG(0, ("Oversized message\n")); + x_fprintf(x_stdout, "ERR\n"); err = 0; return; } @@ -698,21 +738,52 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helpe DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length)); if (buf[0] == '\0') { - DEBUG(2, ("Invalid Request\n")); - x_fprintf(x_stderr, "ERR\n"); + DEBUG(0, ("Invalid Request (empty)\n")); + x_fprintf(x_stdout, "ERR\n"); return; } + + if (opt_multiplex) { + if (sscanf(buf, "%u ", &mux_id) != 1) { + DEBUG(0, ("Invalid Request - no multiplex id\n")); + x_fprintf(x_stdout, "ERR\n"); + return; + } + if (!mux_private) { + mux_private = talloc_p(NULL, struct mux_private); + mux_private->max_mux = 0; + mux_private->private_pointers = NULL; + } + + c=memchr(buf,' ',sizeof(buf)-1); + c++; + if (mux_id >= mux_private->max_mux) { + unsigned int prev_max = mux_private->max_mux; + mux_private->max_mux = mux_id + 1; + mux_private->private_pointers + = talloc_realloc_p(mux_private, + mux_private->private_pointers, + void *, mux_private->max_mux); + memset(&mux_private->private_pointers[prev_max], '\0', + (sizeof(*mux_private->private_pointers) * (mux_private->max_mux - prev_max))); + }; + + private = &mux_private->private_pointers[mux_id]; + } else { + c = buf; + private = &normal_private; + } - fn(helper_mode, buf, length, private); + fn(helper_mode, c, length, private, mux_id); } -static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) { - void *private = NULL; +static void squid_stream(enum stdio_helper_mode stdio_mode, + stdio_helper_function fn) { /* initialize FDescs */ x_setbuf(x_stdout, NULL); x_setbuf(x_stderr, NULL); while(1) { - manage_squid_request(stdio_mode, fn, &private); + manage_squid_request(stdio_mode, fn); } } @@ -731,7 +802,8 @@ enum { OPT_LM_KEY, OPT_USER_SESSION_KEY, OPT_DIAGNOSTICS, - OPT_REQUIRE_MEMBERSHIP + OPT_REQUIRE_MEMBERSHIP, + OPT_MULTIPLEX, }; int main(int argc, const char **argv) @@ -756,6 +828,7 @@ enum { { "workstation", 0, POPT_ARG_STRING, &opt_workstation, OPT_WORKSTATION, "workstation"}, { "username", 0, POPT_ARG_STRING, &opt_username, OPT_PASSWORD, "Username"}, { "password", 0, POPT_ARG_STRING, &opt_password, OPT_PASSWORD, "User's plaintext password"}, + { "multiplex", 0, POPT_ARG_NONE, &opt_multiplex, OPT_MULTIPLEX, "Multiplex Mode"}, POPT_COMMON_SAMBA POPT_TABLEEND }; |