X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source4%2Futils%2Fntlm_auth.c;h=a60ce98d48fc1f4af85e52885ef932372e70e94f;hb=7a23b9769be2c3c25cfb8fa280efb0ab34cd24b2;hp=5532a9ad0b975d63d2a3d92dbe66658582112872;hpb=70d10653ad3dcc4c12c83d4ca14752d0a0c89fe8;p=sfrench%2Fsamba-autobuild%2F.git diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c index 5532a9ad0b9..a60ce98d48f 100644 --- a/source4/utils/ntlm_auth.c +++ b/source4/utils/ntlm_auth.c @@ -9,7 +9,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -18,20 +18,28 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" #include "system/filesys.h" #include "lib/cmdline/popt_common.h" +#include "lib/ldb/include/ldb.h" +#include "auth/credentials/credentials.h" +#include "auth/gensec/gensec.h" #include "auth/auth.h" -#include "pstring.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "auth/auth_sam.h" #include "libcli/auth/libcli_auth.h" -#include "librpc/gen_ndr/ndr_security.h" -#include "lib/ldb/include/ldb.h" +#include "libcli/security/security.h" +#include "lib/events/events.h" +#include "lib/messaging/messaging.h" +#include "lib/messaging/irpc.h" +#include "auth/ntlmssp/ntlmssp.h" +#include "param/param.h" -#define SQUID_BUFFER_SIZE 2010 +#define INITIAL_BUFFER_SIZE 300 +#define MAX_BUFFER_SIZE 63000 enum stdio_helper_mode { SQUID_2_4_BASIC, @@ -49,22 +57,27 @@ enum stdio_helper_mode { typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2); static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2); static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2); static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2); -static void manage_squid_request(enum stdio_helper_mode helper_mode, +static void manage_squid_request(struct loadparm_context *lp_ctx, + enum stdio_helper_mode helper_mode, stdio_helper_function fn, void **private2); static const struct { @@ -89,6 +102,7 @@ static const char *opt_domain; static const char *opt_workstation; static const char *opt_password; static int opt_multiplex; +static int use_cached_creds; static void mux_printf(unsigned int mux_id, const char *format, ...) PRINTF_ATTRIBUTE(2, 3); @@ -111,21 +125,21 @@ static void mux_printf(unsigned int mux_id, const char *format, ...) /* 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) +static bool parse_ntlm_auth_domain_user(const char *domuser, char **domain, + char **user, char winbind_separator) { - char *p = strchr(domuser,*lp_winbind_separator()); + char *p = strchr(domuser, winbind_separator); if (!p) { - return False; + return false; } - fstrcpy(user, p+1); - fstrcpy(domain, domuser); - domain[PTR_DIFF(p, domuser)] = 0; + *user = smb_xstrdup(p+1); + *domain = smb_xstrdup(domuser); + (*domain)[PTR_DIFF(p, domuser)] = 0; - return True; + return true; } /** @@ -158,15 +172,16 @@ static void base64_decode_inplace(char *s) /* Authenticate a user with a plaintext password */ -static BOOL check_plaintext_auth(const char *user, const char *pass, - BOOL stdout_diagnostics) +static bool check_plaintext_auth(const char *user, const char *pass, + bool stdout_diagnostics) { return (strcmp(pass, opt_password) == 0); } /* authenticate a user with an encrypted username/password */ -static NTSTATUS local_pw_check_specified(const char *username, +static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx, + const char *username, const char *domain, const char *workstation, const DATA_BLOB *challenge, @@ -196,6 +211,8 @@ static NTSTATUS local_pw_check_specified(const char *username, nt_status = ntlm_password_check(mem_ctx, + lp_lanman_auth(lp_ctx), + lp_ntlm_auth(lp_ctx), MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, challenge, @@ -210,7 +227,7 @@ static NTSTATUS local_pw_check_specified(const char *username, if (unix_name) { asprintf(unix_name, "%s%c%s", domain, - *lp_winbind_separator(), + *lp_winbind_separator(lp_ctx), username); } } else { @@ -229,13 +246,14 @@ 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, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2) { char *user, *pass; user=buf; - pass=memchr(buf,' ',length); + pass = memchr(buf, ' ', length); if (!pass) { DEBUG(2, ("Password not found. Denying access\n")); mux_printf(mux_id, "ERR\n"); @@ -249,7 +267,7 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, rfc1738_unescape(pass); } - if (check_plaintext_auth(user, pass, False)) { + if (check_plaintext_auth(user, pass, false)) { mux_printf(mux_id, "OK\n"); } else { mux_printf(mux_id, "ERR\n"); @@ -260,13 +278,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, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **password) { DATA_BLOB in; if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); - mux_printf(mux_id, "BH\n"); + mux_printf(mux_id, "BH Query invalid\n"); return; } @@ -278,12 +297,12 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod if (strncmp(buf, "PW ", 3) == 0) { - *password = talloc_strndup(*private /* hopefully the right gensec context, useful to use for talloc */, + *password = talloc_strndup(*private1 /* hopefully the right gensec context, useful to use for talloc */, (const char *)in.data, in.length); if (*password == NULL) { DEBUG(1, ("Out of memory\n")); - mux_printf(mux_id, "BH\n"); + mux_printf(mux_id, "BH Out of memory\n"); data_blob_free(&in); return; } @@ -293,13 +312,13 @@ static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mod return; } DEBUG(1, ("Asked for (and expected) a password\n")); - mux_printf(mux_id, "BH\n"); + mux_printf(mux_id, "BH Expected a password\n"); data_blob_free(&in); } /** - * Callback for password credentails. This is not async, and when - * GENSEC and the credentails code is made async, it will look rather + * Callback for password credentials. This is not async, and when + * GENSEC and the credentials code is made async, it will look rather * different. */ @@ -308,15 +327,59 @@ static const char *get_password(struct cli_credentials *credentials) char *password = NULL; /* Ask for a password */ - mux_printf((unsigned int)credentials->priv_data, "PW\n"); + mux_printf((unsigned int)(uintptr_t)credentials->priv_data, "PW\n"); credentials->priv_data = NULL; - manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, (void **)&password); + manage_squid_request(cmdline_lp_ctx, NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, (void **)&password); return password; } +/** + Check if a string is part of a list. +**/ +static bool in_list(const char *s, const char *list, bool casesensitive) +{ + char *tok; + size_t tok_len = 1024; + const char *p=list; + + if (!list) + return false; + + tok = (char *)malloc(tok_len); + if (!tok) { + return false; + } + + while (next_token(&p, tok, LIST_SEP, tok_len)) { + if ((casesensitive?strcmp:strcasecmp_m)(tok,s) == 0) { + free(tok); + return true; + } + } + free(tok); + return false; +} + +static void gensec_want_feature_list(struct gensec_security *state, char* feature_list) +{ + if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_SESSION_KEY\n")); + gensec_want_feature(state, GENSEC_FEATURE_SESSION_KEY); + } + if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_SIGN\n")); + gensec_want_feature(state, GENSEC_FEATURE_SIGN); + } + if (in_list("NTLMSSP_FEATURE_SEAL", feature_list, true)) { + DEBUG(10, ("want GENSEC_FEATURE_SEAL\n")); + gensec_want_feature(state, GENSEC_FEATURE_SEAL); + } +} + static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, - char *buf, int length, void **private, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2) { DATA_BLOB in; @@ -328,23 +391,28 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, const char *set_password; }; struct gensec_ntlm_state *state; + struct tevent_context *ev; + struct messaging_context *msg; NTSTATUS nt_status; - BOOL first = False; + bool first = false; const char *reply_code; struct cli_credentials *creds; + static char *want_feature_list = NULL; + static DATA_BLOB session_key; + TALLOC_CTX *mem_ctx; - if (*private) { - state = *private; + if (*private1) { + state = (struct gensec_ntlm_state *)*private1; } else { state = talloc_zero(NULL, struct gensec_ntlm_state); if (!state) { mux_printf(mux_id, "BH No Memory\n"); exit(1); } - *private = state; + *private1 = state; if (opt_password) { state->set_password = opt_password; } @@ -352,11 +420,18 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); - mux_printf(mux_id, "BH\n"); + mux_printf(mux_id, "BH Query invalid\n"); return; } if (strlen(buf) > 3) { + if(strncmp(buf, "SF ", 3) == 0) { + DEBUG(10, ("Setting flags to negotiate\n")); + talloc_free(want_feature_list); + want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3); + mux_printf(mux_id, "OK\n"); + return; + } in = base64_decode_data_blob(NULL, buf + 3); } else { in = data_blob(NULL, 0); @@ -368,7 +443,8 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, state->gensec_state = NULL; } } else if ( (strncmp(buf, "OK", 2) == 0)) { - /* do nothing */ + /* Just return BH, like ntlm_auth from Samba 3 does. */ + mux_printf(mux_id, "BH Command expected\n"); data_blob_free(&in); return; } else if ( (strncmp(buf, "TT ", 3) != 0) && @@ -376,13 +452,22 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, (strncmp(buf, "AF ", 3) != 0) && (strncmp(buf, "NA ", 3) != 0) && (strncmp(buf, "UG", 2) != 0) && - (strncmp(buf, "PW ", 3) != 0)) { + (strncmp(buf, "PW ", 3) != 0) && + (strncmp(buf, "GK", 2) != 0) && + (strncmp(buf, "GF", 2) != 0)) { DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); - mux_printf(mux_id, "BH\n"); + mux_printf(mux_id, "BH SPNEGO request invalid\n"); data_blob_free(&in); return; } + ev = s4_event_context_init(state); + if (!ev) { + exit(1); + } + + mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx"); + /* setup gensec */ if (!(state->gensec_state)) { switch (stdio_helper_mode) { @@ -390,24 +475,53 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, case NTLMSSP_CLIENT_1: /* setup the client side */ - nt_status = gensec_client_start(NULL, &state->gensec_state, NULL); + nt_status = gensec_client_start(NULL, &state->gensec_state, ev, + lp_gensec_settings(NULL, lp_ctx)); if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(mem_ctx); exit(1); } break; case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: - if (!NT_STATUS_IS_OK(gensec_server_start(NULL, &state->gensec_state, NULL))) { + { + const char *winbind_method[] = { "winbind", NULL }; + struct auth_context *auth_context; + + msg = messaging_client_init(state, lp_messaging_path(state, lp_ctx), + lp_iconv_convenience(lp_ctx), ev); + if (!msg) { + talloc_free(mem_ctx); + exit(1); + } + nt_status = auth_context_create_methods(mem_ctx, + winbind_method, + ev, + msg, + lp_ctx, + &auth_context); + + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(mem_ctx); + exit(1); + } + + if (!NT_STATUS_IS_OK(gensec_server_start(state, ev, + lp_gensec_settings(state, lp_ctx), + auth_context, &state->gensec_state))) { + talloc_free(mem_ctx); exit(1); } break; + } default: + talloc_free(mem_ctx); abort(); } creds = cli_credentials_init(state->gensec_state); - cli_credentials_set_conf(creds); + cli_credentials_set_conf(creds, lp_ctx); if (opt_username) { cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED); } @@ -418,7 +532,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED); } else { cli_credentials_set_password_callback(creds, get_password); - creds->priv_data = (void*)mux_id; + creds->priv_data = (void*)(uintptr_t)mux_id; } if (opt_workstation) { cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED); @@ -427,45 +541,47 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, switch (stdio_helper_mode) { case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: - cli_credentials_set_machine_account(creds); + cli_credentials_set_machine_account(creds, lp_ctx); break; default: break; } gensec_set_credentials(state->gensec_state, creds); + gensec_want_feature_list(state->gensec_state, want_feature_list); switch (stdio_helper_mode) { case GSS_SPNEGO_CLIENT: case GSS_SPNEGO_SERVER: nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO); if (!in.length) { - first = True; + first = true; } break; case NTLMSSP_CLIENT_1: if (!in.length) { - first = True; + first = true; } /* fall through */ case SQUID_2_5_NTLMSSP: nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP); break; default: + talloc_free(mem_ctx); abort(); } if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status))); - mux_printf(mux_id, "BH\n"); + mux_printf(mux_id, "BH GENSEC mech failed to start\n"); + talloc_free(mem_ctx); return; } } /* update */ - mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx"); - + if (strncmp(buf, "PW ", 3) == 0) { state->set_password = talloc_strndup(state, (const char *)in.data, @@ -501,7 +617,7 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, struct security_token *token = session_info->security_token; const char *sidstr = dom_sid_string(session_info, token->sids[i]); - grouplist = talloc_asprintf_append(grouplist, "%s,", sidstr); + grouplist = talloc_asprintf_append_buffer(grouplist, "%s,", sidstr); } mux_printf(mux_id, "GL %s\n", grouplist); @@ -511,6 +627,37 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, return; } + if (strncmp(buf, "GK", 2) == 0) { + char *base64_key; + DEBUG(10, ("Requested session key\n")); + nt_status = gensec_session_key(state->gensec_state, &session_key); + if(!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status))); + mux_printf(mux_id, "BH No session key\n"); + talloc_free(mem_ctx); + return; + } else { + base64_key = base64_encode_data_blob(state, session_key); + mux_printf(mux_id, "GK %s\n", base64_key); + talloc_free(base64_key); + } + talloc_free(mem_ctx); + return; + } + + if (strncmp(buf, "GF", 2) == 0) { + struct gensec_ntlmssp_state *gensec_ntlmssp_state; + uint32_t neg_flags; + + gensec_ntlmssp_state = talloc_get_type(state->gensec_state->private_data, + struct gensec_ntlmssp_state); + neg_flags = gensec_ntlmssp_state->neg_flags; + + DEBUG(10, ("Requested negotiated feature flags\n")); + mux_printf(mux_id, "GF 0x%08x\n", neg_flags); + return; + } + nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out); /* don't leak 'bad password'/'no such user' info to the network client */ @@ -536,11 +683,11 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) { - reply_code = "BH"; + reply_code = "BH NT_STATUS_ACCESS_DENIED"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) { - reply_code = "BH"; + reply_code = "BH NT_STATUS_UNSUCCESSFUL"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if (!NT_STATUS_IS_OK(nt_status)) { @@ -552,15 +699,15 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, nt_status = gensec_session_info(state->gensec_state, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { - reply_code = "BH"; + reply_code = "BH Failed to retrive session info"; reply_arg = nt_errstr(nt_status); - DEBUG(1, ("GENSEC failed to retreive the session info: %s\n", nt_errstr(nt_status))); + DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status))); } else { reply_code = "AF"; reply_arg = talloc_asprintf(state->gensec_state, "%s%s%s", session_info->server_info->domain_name, - lp_winbind_separator(), session_info->server_info->account_name); + lp_winbind_separator(lp_ctx), session_info->server_info->account_name); talloc_free(session_info); } } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { @@ -591,7 +738,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, + struct loadparm_context *lp_ctx, + char *buf, int length, void **private1, unsigned int mux_id, void **private2) { char *request, *parameter; @@ -602,8 +750,8 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod 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; + static bool ntlm_server_1_user_session_key; + static bool ntlm_server_1_lm_session_key; if (strequal(buf, ".")) { if (!full_username && !username) { @@ -611,12 +759,12 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod } 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) { + if (asprintf(&full_username, "%s%c%s", domain, *lp_winbind_separator(lp_ctx), username) == -1) { mux_printf(mux_id, "Error: Out of memory in asprintf!\n.\n"); return; } } - if (check_plaintext_auth(full_username, plaintext_password, False)) { + if (check_plaintext_auth(full_username, plaintext_password, false)) { mux_printf(mux_id, "Authenticated: Yes\n"); } else { mux_printf(mux_id, "Authenticated: No\n"); @@ -632,21 +780,18 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod uint32_t flags = 0; if (full_username && !username) { - fstring fstr_user; - fstring fstr_domain; - - if (!parse_ntlm_auth_domain_user(full_username, fstr_user, fstr_domain)) { + SAFE_FREE(username); + SAFE_FREE(domain); + if (!parse_ntlm_auth_domain_user(full_username, &username, + &domain, + *lp_winbind_separator(lp_ctx))) { /* username might be 'tainted', don't print into our new-line deleimianted stream */ mux_printf(mux_id, "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(lp_workgroup()); + domain = smb_xstrdup(lp_workgroup(lp_ctx)); } if (ntlm_server_1_lm_session_key) @@ -656,9 +801,10 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod flags |= NTLM_AUTH_FLAG_USER_SESSION_KEY; if (!NT_STATUS_IS_OK( - local_pw_check_specified(username, + local_pw_check_specified(lp_ctx, + username, domain, - lp_netbios_name(), + lp_netbios_name(lp_ctx), &challenge, &lm_response, &nt_response, @@ -709,8 +855,8 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod SAFE_FREE(username); SAFE_FREE(domain); SAFE_FREE(plaintext_password); - ntlm_server_1_user_session_key = False; - ntlm_server_1_lm_session_key = False; + ntlm_server_1_user_session_key = false; + ntlm_server_1_lm_session_key = false; mux_printf(mux_id, ".\n"); return; @@ -746,7 +892,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); + challenge = strhex_to_data_blob(NULL, parameter); if (challenge.length != 8) { mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 8)\n.\n", parameter, @@ -754,7 +900,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod challenge = data_blob(NULL, 0); } } else if (strequal(request, "NT-Response")) { - nt_response = strhex_to_data_blob(parameter); + nt_response = strhex_to_data_blob(NULL, parameter); if (nt_response.length < 24) { mux_printf(mux_id, "Error: hex decode of %s failed! (only got %d bytes, needed at least 24)\n.\n", parameter, @@ -762,7 +908,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod nt_response = data_blob(NULL, 0); } } else if (strequal(request, "LANMAN-Response")) { - lm_response = strhex_to_data_blob(parameter); + lm_response = strhex_to_data_blob(NULL, parameter); if (lm_response.length != 24) { mux_printf(mux_id, "Error: hex decode of %s failed! (got %d bytes, expected 24)\n.\n", parameter, @@ -786,54 +932,68 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod } } -static void manage_squid_request(enum stdio_helper_mode helper_mode, +static void manage_squid_request(struct loadparm_context *lp_ctx, enum stdio_helper_mode helper_mode, stdio_helper_function fn, void **private2) { - char buf[SQUID_BUFFER_SIZE+1]; + char *buf; + char tmp[INITIAL_BUFFER_SIZE+1]; unsigned int mux_id = 0; - int length; + int length, buf_size = 0; 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; + void **private1; - /* this is not a typo - x_fgets doesn't work too well under squid */ - if (fgets(buf, sizeof(buf)-1, stdin) == NULL) { - if (ferror(stdin)) { - DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin), - strerror(ferror(stdin)))); - - exit(1); /* BIIG buffer */ - } - exit(0); - } - - c=memchr(buf,'\n',sizeof(buf)-1); - if (c) { - *c = '\0'; - length = c-buf; - } else { - err = 1; - return; - } - if (err) { - DEBUG(0, ("Oversized message\n")); + buf = talloc_strdup(NULL, ""); + + if (buf == NULL) { + DEBUG(0, ("Failed to allocate memory for reading the input " + "buffer.\n")); x_fprintf(x_stdout, "ERR\n"); - err = 0; return; } + do { + /* this is not a typo - x_fgets doesn't work too well under + * squid */ + if (fgets(tmp, INITIAL_BUFFER_SIZE, stdin) == NULL) { + if (ferror(stdin)) { + DEBUG(1, ("fgets() failed! dying..... errno=%d " + "(%s)\n", ferror(stdin), + strerror(ferror(stdin)))); + + exit(1); /* BIIG buffer */ + } + exit(0); + } + + buf = talloc_strdup_append_buffer(buf, tmp); + buf_size += INITIAL_BUFFER_SIZE; + + if (buf_size > MAX_BUFFER_SIZE) { + DEBUG(0, ("Invalid Request (too large)\n")); + x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); + return; + } + + c = strchr(buf, '\n'); + } while (c == NULL); + + *c = '\0'; + length = c-buf; + DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length)); if (buf[0] == '\0') { DEBUG(0, ("Invalid Request (empty)\n")); x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); return; } @@ -841,6 +1001,7 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, if (sscanf(buf, "%u ", &mux_id) != 1) { DEBUG(0, ("Invalid Request - no multiplex id\n")); x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); return; } if (!mux_private) { @@ -853,6 +1014,7 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, if (!c) { DEBUG(0, ("Invalid Request - no data after multiplex id\n")); x_fprintf(x_stdout, "ERR\n"); + talloc_free(buf); return; } c++; @@ -867,22 +1029,24 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, (sizeof(*mux_private->private_pointers) * (mux_private->max_mux - prev_max))); }; - private = &mux_private->private_pointers[mux_id]; + private1 = &mux_private->private_pointers[mux_id]; } else { c = buf; - private = &normal_private; + private1 = &normal_private; } - - fn(helper_mode, c, length, private, mux_id, private2); + + fn(helper_mode, lp_ctx, c, length, private1, mux_id, private2); + talloc_free(buf); } -static void squid_stream(enum stdio_helper_mode stdio_mode, +static void squid_stream(struct loadparm_context *lp_ctx, + 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, NULL); + manage_squid_request(lp_ctx, stdio_mode, fn, NULL); } } @@ -903,6 +1067,7 @@ enum { OPT_DIAGNOSTICS, OPT_REQUIRE_MEMBERSHIP, OPT_MULTIPLEX, + OPT_USE_CACHED_CREDS, }; int main(int argc, const char **argv) @@ -928,9 +1093,10 @@ int main(int argc, const char **argv) { "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"}, + { "use-cached-creds", 0, POPT_ARG_NONE, &use_cached_creds, OPT_USE_CACHED_CREDS, "silently ignored for compatibility reasons"}, POPT_COMMON_SAMBA POPT_COMMON_VERSION - POPT_TABLEEND + { NULL } }; /* Samba client initialisation */ @@ -963,17 +1129,17 @@ int main(int argc, const char **argv) return 1; } - gensec_init(); + gensec_init(cmdline_lp_ctx); if (opt_domain == NULL) { - opt_domain = lp_workgroup(); + opt_domain = lp_workgroup(cmdline_lp_ctx); } if (helper_protocol) { int i; for (i=0; i