From 18a36c17ac59c4d30a8ef891d6e16a0fd00d33c1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 13 Sep 2010 18:09:20 +0200 Subject: [PATCH 1/9] ntlm_auth: Fix a valgrind error (cherry picked from commit 69db4b4ccf051b05517e6eb9039ab48f90608075) Signed-off-by: Stefan Metzmacher --- source3/utils/ntlm_auth.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index afd0b99..ec035a1 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1137,7 +1137,7 @@ static void offer_gss_spnego_mechs(void) { /* Server negTokenInit (mech offerings) */ spnego.type = SPNEGO_NEG_TOKEN_INIT; - spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 2); + spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 3); #ifdef HAVE_KRB5 spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_KERBEROS5_OLD); spnego.negTokenInit.mechTypes[1] = talloc_strdup(ctx, OID_NTLMSSP); -- 1.7.0.4 From 91dee466684898f39d9fe8ef71c2dfddf1c802bc Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 15 Sep 2010 10:29:44 +0200 Subject: [PATCH 2/9] s3: Fix some debug msgs in ntlm_auth (cherry picked from commit 6400f3ee62108e3dd1e6c1013ccea9fb4b08d562) Signed-off-by: Stefan Metzmacher --- source3/utils/ntlm_auth.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index ec035a1..20f58fe 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -785,7 +785,7 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, NTSTATUS nt_status; if (strlen(buf) < 2) { - DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); + DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); return; } @@ -854,7 +854,7 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, data_blob_free(&request); return; } else { - DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); + DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); return; } @@ -921,7 +921,7 @@ static void manage_client_ntlmssp_request(struct ntlm_auth_state *state, } if (strlen(buf) < 2) { - DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); + DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); return; } @@ -1013,7 +1013,7 @@ static void manage_client_ntlmssp_request(struct ntlm_auth_state *state, data_blob_free(&request); return; } else { - DEBUG(1, ("NTLMSSP query [%s] invalid", buf)); + DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); return; } @@ -1187,7 +1187,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, char *reply_argument = NULL; if (strlen(buf) < 2) { - DEBUG(1, ("SPENGO query [%s] invalid", buf)); + DEBUG(1, ("SPENGO query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH SPENGO query invalid\n"); return; } @@ -1198,7 +1198,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, } else if (strncmp(buf, "KK", 2) == 0) { ; } else { - DEBUG(1, ("SPENGO query [%s] invalid", buf)); + DEBUG(1, ("SPENGO query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH SPENGO query invalid\n"); return; } @@ -1225,7 +1225,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, data_blob_free(&token); if (len == -1) { - DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf)); + DEBUG(1, ("GSS-SPNEGO query [%s] invalid\n", buf)); x_fprintf(x_stdout, "BH GSS-SPNEGO query invalid\n"); return; } @@ -1237,7 +1237,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, if ( (request.negTokenInit.mechTypes == NULL) || (request.negTokenInit.mechTypes[0] == NULL) ) { - DEBUG(1, ("Client did not offer any mechanism")); + DEBUG(1, ("Client did not offer any mechanism\n")); x_fprintf(x_stdout, "BH Client did not offer any " "mechanism\n"); return; -- 1.7.0.4 From f53c3fcf2c7e65372de7fa90543278b750695ff8 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 16 Sep 2010 10:36:21 +0200 Subject: [PATCH 3/9] s3: Wrap the ntlm_auth loop with a talloc_stackframe (cherry picked from commit ae483bbe9af526623189cefe7735f3f2813da6d7) Signed-off-by: Stefan Metzmacher --- source3/utils/ntlm_auth.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 20f58fe..9b9b1b8 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -2288,7 +2288,9 @@ static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_functio state->helper_mode = stdio_mode; while(1) { + TALLOC_CTX *frame = talloc_stackframe(); manage_squid_request(state, fn); + TALLOC_FREE(frame); } } -- 1.7.0.4 From 128d97702c9be4badd581bf7f750fc78f6bf2aed Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 30 Nov 2010 10:46:28 +0100 Subject: [PATCH 4/9] s3: Split off output generation from manage_squid_ntlmssp_request (cherry picked from commit de2c143f4d540f695db5c7fe8685614c03977365) Signed-off-by: Stefan Metzmacher --- source3/utils/ntlm_auth.c | 58 +++++++++++++++++++++++++++++++------------- 1 files changed, 41 insertions(+), 17 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 9b9b1b8..0c2546e 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -778,15 +778,17 @@ static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_m return NT_STATUS_MORE_PROCESSING_REQUIRED; } -static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, - char *buf, int length) +static void manage_squid_ntlmssp_request_int(struct ntlm_auth_state *state, + char *buf, int length, + TALLOC_CTX *mem_ctx, + char **response) { DATA_BLOB request, reply; NTSTATUS nt_status; if (strlen(buf) < 2) { DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); - x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); + *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid"); return; } @@ -796,7 +798,7 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, TALLOC_FREE(state->want_feature_list); state->want_feature_list = talloc_strdup(state->mem_ctx, buf+3); - x_fprintf(x_stdout, "OK\n"); + *response = talloc_strdup(mem_ctx, "OK"); return; } request = base64_decode_data_blob(buf + 3); @@ -813,12 +815,12 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, if (opt_password == NULL) { DEBUG(1, ("Out of memory\n")); - x_fprintf(x_stdout, "BH Out of memory\n"); + *response = talloc_strdup(mem_ctx, "BH Out of memory"); data_blob_free(&request); return; } - x_fprintf(x_stdout, "OK\n"); + *response = talloc_strdup(mem_ctx, "OK"); data_blob_free(&request); return; } @@ -833,10 +835,11 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, DEBUG(10, ("Requested negotiated NTLMSSP flags\n")); if (state->svr_state == SERVER_FINISHED) { - x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags); + *response = talloc_asprintf(mem_ctx, "GF 0x%08x", + state->neg_flags); } else { - x_fprintf(x_stdout, "BH\n"); + *response = talloc_strdup(mem_ctx, "BH\n"); } data_blob_free(&request); return; @@ -845,17 +848,18 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, if(state->have_session_key) { char *key64 = base64_encode_data_blob(state->mem_ctx, state->session_key); - x_fprintf(x_stdout, "GK %s\n", key64?key64:""); + *response = talloc_asprintf(mem_ctx, "GK %s", + key64 ? key64 : ""); TALLOC_FREE(key64); } else { - x_fprintf(x_stdout, "BH\n"); + *response = talloc_strdup(mem_ctx, "BH"); } data_blob_free(&request); return; } else { DEBUG(1, ("NTLMSSP query [%s] invalid\n", buf)); - x_fprintf(x_stdout, "BH NTLMSSP query invalid\n"); + *response = talloc_strdup(mem_ctx, "BH NTLMSSP query invalid"); return; } @@ -863,7 +867,8 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, nt_status = ntlm_auth_start_ntlmssp_server( &state->ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { - x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); + *response = talloc_asprintf( + mem_ctx, "BH %s", nt_errstr(nt_status)); return; } ntlmssp_want_feature_list(state->ntlmssp_state, @@ -878,22 +883,25 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { char *reply_base64 = base64_encode_data_blob(state->mem_ctx, reply); - x_fprintf(x_stdout, "TT %s\n", reply_base64); + *response = talloc_asprintf(mem_ctx, "TT %s", reply_base64); TALLOC_FREE(reply_base64); data_blob_free(&reply); state->svr_state = SERVER_CHALLENGE; DEBUG(10, ("NTLMSSP challenge\n")); } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) { - x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status)); + *response = talloc_asprintf(mem_ctx, "BH %s", + nt_errstr(nt_status)); DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status))); ntlmssp_end(&state->ntlmssp_state); } else if (!NT_STATUS_IS_OK(nt_status)) { - x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status)); + *response = talloc_asprintf(mem_ctx, "NA %s", + nt_errstr(nt_status)); DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status))); } else { - x_fprintf(x_stdout, "AF %s\n", - (char *)state->ntlmssp_state->auth_context); + *response = talloc_asprintf( + mem_ctx, "AF %s", + (char *)state->ntlmssp_state->auth_context); DEBUG(10, ("NTLMSSP OK!\n")); if(state->have_session_key) @@ -909,6 +917,22 @@ static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, data_blob_free(&request); } +static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state, + char *buf, int length) +{ + char *response; + + manage_squid_ntlmssp_request_int(state, buf, length, + talloc_tos(), &response); + + if (response == NULL) { + x_fprintf(x_stdout, "BH Out of memory\n"); + return; + } + x_fprintf(x_stdout, "%s\n", response); + TALLOC_FREE(response); +} + static void manage_client_ntlmssp_request(struct ntlm_auth_state *state, char *buf, int length) { -- 1.7.0.4 From 6c3e3daf4803543027180966c255f6331b19b034 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 16 Sep 2010 10:22:00 +0200 Subject: [PATCH 5/9] s3: Fall back to raw NTLMSSP for the gss-spnego protocol This is to handle the mod_auth_ntlm_winbind protocol sending "Negotiate" to IE, which sends raw NTLMSSP instead of a SPNEGO wrapped NTLMSSP blob. (cherry picked from commit 70ab7eb5303a5ff058939541dd5bc1f81113a48e) Signed-off-by: Stefan Metzmacher --- source3/utils/ntlm_auth.c | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 0c2546e..835c227 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1245,6 +1245,31 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, } token = base64_decode_data_blob(buf + 3); + + if ((token.length >= 7) + && (strncmp((char *)token.data, "NTLMSSP", 7) == 0)) { + char *reply; + + DEBUG(10, ("Could not parse GSS-SPNEGO, trying raw " + "ntlmssp\n")); + + manage_squid_ntlmssp_request_int(state, buf, length, + talloc_tos(), &reply); + if (reply == NULL) { + x_fprintf(x_stdout, "BH Out of memory\n"); + return; + } + + if (strncmp(reply, "AF ", 3) == 0) { + x_fprintf(x_stdout, "AF * %s\n", reply+3); + } else { + x_fprintf(x_stdout, "%s *\n", reply); + } + + TALLOC_FREE(reply); + return; + } + len = spnego_read_data(ctx, token, &request); data_blob_free(&token); -- 1.7.0.4 From 95237fc870154543b189718bddedfc9e90a8db08 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 30 Nov 2010 10:52:52 +0100 Subject: [PATCH 6/9] s3: Correctly unwrap the krb ticket in gss-spnego (cherry picked from commit 547b268cfaa2e791bf92e8804bfa504c4e37050b) Signed-off-by: Stefan Metzmacher renamed to _spnego_parse_krb5_wrap() metze --- source3/utils/ntlm_auth.c | 53 ++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 52 insertions(+), 1 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 835c227..4384946 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1193,6 +1193,45 @@ static void offer_gss_spnego_mechs(void) { return; } +static bool _spnego_parse_krb5_wrap(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2]) +{ + bool ret; + ASN1_DATA *data; + int data_remaining; + + data = asn1_init(talloc_tos()); + if (data == NULL) { + return false; + } + + asn1_load(data, blob); + asn1_start_tag(data, ASN1_APPLICATION(0)); + asn1_check_OID(data, OID_KERBEROS5); + + data_remaining = asn1_tag_remaining(data); + + if (data_remaining < 3) { + data->has_error = True; + } else { + asn1_read(data, tok_id, 2); + data_remaining -= 2; + *ticket = data_blob_talloc(ctx, NULL, data_remaining); + asn1_read(data, ticket->data, ticket->length); + } + + asn1_end_tag(data); + + ret = !data->has_error; + + if (data->has_error) { + data_blob_free(ticket); + } + + asn1_free(data); + + return ret; +} + static void manage_gss_spnego_request(struct ntlm_auth_state *state, char *buf, int length) { @@ -1338,6 +1377,8 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, DATA_BLOB ap_rep; DATA_BLOB session_key; struct PAC_DATA *pac_data = NULL; + DATA_BLOB ticket; + uint8_t tok_id[2]; if ( request.negTokenInit.mechToken.data == NULL ) { DEBUG(1, ("Client did not provide Kerberos data\n")); @@ -1346,13 +1387,23 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, return; } + dump_data(10, request.negTokenInit.mechToken.data, + request.negTokenInit.mechToken.length); + + if (!_spnego_parse_krb5_wrap(ctx, request.negTokenInit.mechToken, + &ticket, tok_id)) { + DEBUG(1, ("spnego_parse_krb5_wrap failed\n")); + x_fprintf(x_stdout, "BH spnego_parse_krb5_wrap failed\n"); + return; + } + response.type = SPNEGO_NEG_TOKEN_TARG; response.negTokenTarg.supportedMech = talloc_strdup(ctx, OID_KERBEROS5_OLD); response.negTokenTarg.mechListMIC = data_blob_talloc(ctx, NULL, 0); response.negTokenTarg.responseToken = data_blob_talloc(ctx, NULL, 0); status = ads_verify_ticket(mem_ctx, lp_realm(), 0, - &request.negTokenInit.mechToken, + &ticket, &principal, &pac_data, &ap_rep, &session_key, True); -- 1.7.0.4 From a4b6bc42c9480dc4393f050c501048a9f774810b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 1 Dec 2010 05:50:59 +0100 Subject: [PATCH 7/9] s3:ntlm_auth: fix memory leak in the raw ntlmssp code path metze (cherry picked from commit 9a56ade6b1d627126418c75de4602610b4482503) --- source3/utils/ntlm_auth.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 4384946..c6b3038 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1289,6 +1289,8 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, && (strncmp((char *)token.data, "NTLMSSP", 7) == 0)) { char *reply; + data_blob_free(&token); + DEBUG(10, ("Could not parse GSS-SPNEGO, trying raw " "ntlmssp\n")); -- 1.7.0.4 From 2167ae1e1897f42b332d0842879e9302ebc47fbc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 1 Dec 2010 05:59:16 +0100 Subject: [PATCH 8/9] s3:ntlm_auth: free session key, as we don't use it (at least for now) metze (cherry picked from commit ee4f5ac6182969bcab91955e6d6581e408d222f1) --- source3/utils/ntlm_auth.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index c6b3038..bc1ff2f 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1377,7 +1377,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request"); char *principal; DATA_BLOB ap_rep; - DATA_BLOB session_key; + DATA_BLOB session_key = data_blob_null; struct PAC_DATA *pac_data = NULL; DATA_BLOB ticket; uint8_t tok_id[2]; @@ -1430,6 +1430,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, user = SMB_STRDUP(principal); data_blob_free(&ap_rep); + data_blob_free(&session_key); } TALLOC_FREE(mem_ctx); -- 1.7.0.4 From 13782111d1807a8c6600e99b9dcbb768bcd522ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 2 Dec 2010 00:39:23 +0100 Subject: [PATCH 9/9] s3:ntlm_auth: support clients which offer a spnego mechs we don't support (bug #7855) Before we rejected the authentication if we don't support the first spnego mech the client offered. We now negotiate the first mech we support. This fix works arround problems, when a client sends the NEGOEX (1.3.6.1.4.1.311.2.2.30) oid, which we don't support. metze (cherry picked from commit f802075f08fe0d86f3d176f2302236aeb5834f3d) Modified to work in the v3-5-test branch, e.g. use ntlmssp_end() --- source3/Makefile.in | 2 +- source3/utils/ntlm_auth.c | 284 ++++++++++++++++++++++++++++----------------- 2 files changed, 177 insertions(+), 109 deletions(-) diff --git a/source3/Makefile.in b/source3/Makefile.in index 9e960c9..8cdecef 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1315,7 +1315,7 @@ NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \ $(LIBADS_SERVER_OBJ) \ $(PASSDB_OBJ) $(LIBTSOCKET_OBJ) $(GROUPDB_OBJ) \ $(SMBLDAP_OBJ) $(LIBNMB_OBJ) \ - $(LDB_OBJ) $(WBCOMMON_OBJ) \ + $(LDB_OBJ) $(WBCOMMON_OBJ) $(SLCACHE_OBJ) \ $(LIBNDR_GEN_OBJ0) $(LIBNDR_GEN_OBJ1) @BUILD_INIPARSER@ diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index bc1ff2f..a85f123 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -76,6 +76,8 @@ struct ntlm_auth_state { struct ntlmssp_state *ntlmssp_state; uint32_t neg_flags; char *want_feature_list; + char *spnego_mech; + char *spnego_mech_oid; bool have_session_key; DATA_BLOB session_key; DATA_BLOB initial_message; @@ -1161,11 +1163,12 @@ static void offer_gss_spnego_mechs(void) { /* Server negTokenInit (mech offerings) */ spnego.type = SPNEGO_NEG_TOKEN_INIT; - spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 3); + spnego.negTokenInit.mechTypes = talloc_array(ctx, const char *, 4); #ifdef HAVE_KRB5 spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_KERBEROS5_OLD); - spnego.negTokenInit.mechTypes[1] = talloc_strdup(ctx, OID_NTLMSSP); - spnego.negTokenInit.mechTypes[2] = NULL; + spnego.negTokenInit.mechTypes[1] = talloc_strdup(ctx, OID_KERBEROS5); + spnego.negTokenInit.mechTypes[2] = talloc_strdup(ctx, OID_NTLMSSP); + spnego.negTokenInit.mechTypes[3] = NULL; #else spnego.negTokenInit.mechTypes[0] = talloc_strdup(ctx, OID_NTLMSSP); spnego.negTokenInit.mechTypes[1] = NULL; @@ -1235,9 +1238,10 @@ static bool _spnego_parse_krb5_wrap(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB * static void manage_gss_spnego_request(struct ntlm_auth_state *state, char *buf, int length) { - static NTLMSSP_STATE *ntlmssp_state = NULL; struct spnego_data request, response; DATA_BLOB token; + DATA_BLOB raw_in_token = data_blob_null; + DATA_BLOB raw_out_token = data_blob_null; NTSTATUS status; ssize_t len; TALLOC_CTX *ctx = talloc_tos(); @@ -1248,6 +1252,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, const char *reply_code; char *reply_base64; char *reply_argument = NULL; + char *supportedMech = NULL; if (strlen(buf) < 2) { DEBUG(1, ("SPENGO query [%s] invalid\n", buf)); @@ -1256,8 +1261,10 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, } if (strncmp(buf, "YR", 2) == 0) { - if (ntlmssp_state) - ntlmssp_end(&ntlmssp_state); + if (state->ntlmssp_state) + ntlmssp_end(&state->ntlmssp_state); + TALLOC_FREE(state->spnego_mech); + TALLOC_FREE(state->spnego_mech_oid); } else if (strncmp(buf, "KK", 2) == 0) { ; } else { @@ -1311,6 +1318,7 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, return; } + ZERO_STRUCT(request); len = spnego_read_data(ctx, token, &request); data_blob_free(&token); @@ -1321,6 +1329,20 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, } if (request.type == SPNEGO_NEG_TOKEN_INIT) { +#ifdef HAVE_KRB5 + int krb5_idx = -1; +#endif + int ntlm_idx = -1; + int used_idx = -1; + int i; + + if (state->spnego_mech) { + DEBUG(1, ("Client restarted SPNEGO with NegTokenInit " + "while mech[%s] was already negotiated\n", + state->spnego_mech)); + x_fprintf(x_stdout, "BH Client send NegTokenInit twice\n"); + return; + } /* Second request from Client. This is where the client offers its mechanism to use. */ @@ -1334,156 +1356,204 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, } status = NT_STATUS_UNSUCCESSFUL; - if (strcmp(request.negTokenInit.mechTypes[0], OID_NTLMSSP) == 0) { + for (i = 0; request.negTokenInit.mechTypes[i] != NULL; i++) { + DEBUG(10,("got mech[%d][%s]\n", + i, request.negTokenInit.mechTypes[i])); +#ifdef HAVE_KRB5 + if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5_OLD) == 0) { + krb5_idx = i; + break; + } + if (strcmp(request.negTokenInit.mechTypes[i], OID_KERBEROS5) == 0) { + krb5_idx = i; + break; + } +#endif + if (strcmp(request.negTokenInit.mechTypes[i], OID_NTLMSSP) == 0) { + ntlm_idx = i; + break; + } + } - if ( request.negTokenInit.mechToken.data == NULL ) { - DEBUG(1, ("Client did not provide NTLMSSP data\n")); - x_fprintf(x_stdout, "BH Client did not provide " - "NTLMSSP data\n"); + used_idx = ntlm_idx; +#ifdef HAVE_KRB5 + if (krb5_idx != -1) { + ntlm_idx = -1; + used_idx = krb5_idx; + } +#endif + if (ntlm_idx > -1) { + state->spnego_mech = talloc_strdup(state, "ntlmssp"); + if (state->spnego_mech == NULL) { + x_fprintf(x_stdout, "BH Out of memory\n"); return; } - if ( ntlmssp_state != NULL ) { + if (state->ntlmssp_state) { DEBUG(1, ("Client wants a new NTLMSSP challenge, but " "already got one\n")); x_fprintf(x_stdout, "BH Client wants a new " "NTLMSSP challenge, but " "already got one\n"); - ntlmssp_end(&ntlmssp_state); + ntlmssp_end(&state->ntlmssp_state); return; } - if (!NT_STATUS_IS_OK(status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) { + status = ntlm_auth_start_ntlmssp_server(&state->ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { x_fprintf(x_stdout, "BH %s\n", nt_errstr(status)); return; } - - DEBUG(10, ("got NTLMSSP packet:\n")); - dump_data(10, request.negTokenInit.mechToken.data, - request.negTokenInit.mechToken.length); - - response.type = SPNEGO_NEG_TOKEN_TARG; - response.negTokenTarg.supportedMech = talloc_strdup(ctx, OID_NTLMSSP); - response.negTokenTarg.mechListMIC = data_blob_talloc(ctx, NULL, 0); - - status = ntlmssp_update(ntlmssp_state, - request.negTokenInit.mechToken, - &response.negTokenTarg.responseToken); } #ifdef HAVE_KRB5 - if (strcmp(request.negTokenInit.mechTypes[0], OID_KERBEROS5_OLD) == 0) { - - TALLOC_CTX *mem_ctx = talloc_init("manage_gss_spnego_request"); - char *principal; - DATA_BLOB ap_rep; - DATA_BLOB session_key = data_blob_null; - struct PAC_DATA *pac_data = NULL; - DATA_BLOB ticket; - uint8_t tok_id[2]; - - if ( request.negTokenInit.mechToken.data == NULL ) { - DEBUG(1, ("Client did not provide Kerberos data\n")); - x_fprintf(x_stdout, "BH Client did not provide " - "Kerberos data\n"); + if (krb5_idx > -1) { + state->spnego_mech = talloc_strdup(state, "krb5"); + if (state->spnego_mech == NULL) { + x_fprintf(x_stdout, "BH Out of memory\n"); return; } - - dump_data(10, request.negTokenInit.mechToken.data, - request.negTokenInit.mechToken.length); - - if (!_spnego_parse_krb5_wrap(ctx, request.negTokenInit.mechToken, - &ticket, tok_id)) { - DEBUG(1, ("spnego_parse_krb5_wrap failed\n")); - x_fprintf(x_stdout, "BH spnego_parse_krb5_wrap failed\n"); + } +#endif + if (used_idx > -1) { + state->spnego_mech_oid = talloc_strdup(state, + request.negTokenInit.mechTypes[used_idx]); + if (state->spnego_mech_oid == NULL) { + x_fprintf(x_stdout, "BH Out of memory\n"); return; } - - response.type = SPNEGO_NEG_TOKEN_TARG; - response.negTokenTarg.supportedMech = talloc_strdup(ctx, OID_KERBEROS5_OLD); - response.negTokenTarg.mechListMIC = data_blob_talloc(ctx, NULL, 0); - response.negTokenTarg.responseToken = data_blob_talloc(ctx, NULL, 0); - - status = ads_verify_ticket(mem_ctx, lp_realm(), 0, - &ticket, - &principal, &pac_data, &ap_rep, - &session_key, True); - - /* Now in "principal" we have the name we are - authenticated as. */ - - if (NT_STATUS_IS_OK(status)) { - - domain = strchr_m(principal, '@'); - - if (domain == NULL) { - DEBUG(1, ("Did not get a valid principal " - "from ads_verify_ticket\n")); - x_fprintf(x_stdout, "BH Did not get a " - "valid principal from " - "ads_verify_ticket\n"); - return; - } - - *domain++ = '\0'; - domain = SMB_STRDUP(domain); - user = SMB_STRDUP(principal); - - data_blob_free(&ap_rep); - data_blob_free(&session_key); + supportedMech = talloc_strdup(ctx, state->spnego_mech_oid); + if (supportedMech == NULL) { + x_fprintf(x_stdout, "BH Out of memory\n"); + return; } - TALLOC_FREE(mem_ctx); + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + } else { + status = NT_STATUS_NOT_SUPPORTED; + } + if (used_idx == 0) { + status = NT_STATUS_OK; + raw_in_token = request.negTokenInit.mechToken; } -#endif - } else { + if (state->spnego_mech == NULL) { + DEBUG(1,("Got netTokenTarg without negTokenInit\n")); + x_fprintf(x_stdout, "BH Got a negTokenTarg without " + "negTokenInit\n"); + return; + } - if ( (request.negTokenTarg.supportedMech == NULL) || - ( strcmp(request.negTokenTarg.supportedMech, OID_NTLMSSP) != 0 ) ) { - /* Kerberos should never send a negTokenTarg, OID_NTLMSSP - is the only one we support that sends this stuff */ - DEBUG(1, ("Got a negTokenTarg for something non-NTLMSSP: %s\n", - request.negTokenTarg.supportedMech)); - x_fprintf(x_stdout, "BH Got a negTokenTarg for " - "something non-NTLMSSP\n"); + if ((request.negTokenTarg.supportedMech != NULL) && + (strcmp(request.negTokenTarg.supportedMech, state->spnego_mech_oid) != 0 ) ) { + DEBUG(1, ("Got a negTokenTarg with mech[%s] while [%s] was already negotiated\n", + request.negTokenTarg.supportedMech, + state->spnego_mech_oid)); + x_fprintf(x_stdout, "BH Got a negTokenTarg with speficied mech\n"); return; } - if (request.negTokenTarg.responseToken.data == NULL) { - DEBUG(1, ("Got a negTokenTarg without a responseToken!\n")); - x_fprintf(x_stdout, "BH Got a negTokenTarg without a " - "responseToken!\n"); + status = NT_STATUS_OK; + raw_in_token = request.negTokenTarg.responseToken; + } + + if (!NT_STATUS_IS_OK(status)) { + /* error or more processing */ + } else if (strcmp(state->spnego_mech, "ntlmssp") == 0) { + + DEBUG(10, ("got NTLMSSP packet:\n")); + dump_data(10, raw_in_token.data, raw_in_token.length); + + status = ntlmssp_update(state->ntlmssp_state, + raw_in_token, + &raw_out_token); + if (NT_STATUS_IS_OK(status)) { + user = talloc_strdup(ctx, state->ntlmssp_state->user); + domain = talloc_strdup(ctx, state->ntlmssp_state->domain); + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + ntlmssp_end(&state->ntlmssp_state); + } +#ifdef HAVE_KRB5 + } else if (strcmp(state->spnego_mech, "krb5") == 0) { + char *principal; + DATA_BLOB ap_rep; + DATA_BLOB session_key; + struct PAC_DATA *pac_data = NULL; + DATA_BLOB ticket; + uint8_t tok_id[2]; + + if (!_spnego_parse_krb5_wrap(ctx, raw_in_token, + &ticket, tok_id)) { + DEBUG(1, ("spnego_parse_krb5_wrap failed\n")); + x_fprintf(x_stdout, "BH spnego_parse_krb5_wrap failed\n"); return; } - status = ntlmssp_update(ntlmssp_state, - request.negTokenTarg.responseToken, - &response.negTokenTarg.responseToken); + status = ads_verify_ticket(ctx, lp_realm(), 0, + &ticket, + &principal, &pac_data, &ap_rep, + &session_key, True); - response.type = SPNEGO_NEG_TOKEN_TARG; - response.negTokenTarg.supportedMech = talloc_strdup(ctx, OID_NTLMSSP); - response.negTokenTarg.mechListMIC = data_blob_talloc(ctx, NULL, 0); + /* Now in "principal" we have the name we are authenticated as. */ if (NT_STATUS_IS_OK(status)) { - user = SMB_STRDUP(ntlmssp_state->user); - domain = SMB_STRDUP(ntlmssp_state->domain); - ntlmssp_end(&ntlmssp_state); + + domain = strchr_m(principal, '@'); + + if (domain == NULL) { + DEBUG(1, ("Did not get a valid principal " + "from ads_verify_ticket\n")); + x_fprintf(x_stdout, "BH Did not get a " + "valid principal from " + "ads_verify_ticket\n"); + return; + } + + *domain++ = '\0'; + domain = talloc_strdup(ctx, domain); + user = talloc_strdup(ctx, principal); + + if (pac_data) { + struct PAC_LOGON_INFO *logon_info; + logon_info = get_logon_info_from_pac( + pac_data); + if (logon_info) { + netsamlogon_cache_store( + user, + &logon_info->info3); + } + } + + data_blob_free(&ap_rep); + data_blob_free(&session_key); } + data_blob_free(&ticket); +#endif } spnego_free_data(&request); + ZERO_STRUCT(response); + response.type = SPNEGO_NEG_TOKEN_TARG; if (NT_STATUS_IS_OK(status)) { + TALLOC_FREE(state->spnego_mech); + TALLOC_FREE(state->spnego_mech_oid); response.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; + response.negTokenTarg.responseToken = raw_out_token; reply_code = "AF"; reply_argument = talloc_asprintf(ctx, "%s\\%s", domain, user); } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + response.negTokenTarg.supportedMech = supportedMech; + response.negTokenTarg.responseToken = raw_out_token; response.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; reply_code = "TT"; reply_argument = talloc_strdup(ctx, "*"); } else { + TALLOC_FREE(state->spnego_mech); + TALLOC_FREE(state->spnego_mech_oid); + data_blob_free(&raw_out_token); response.negTokenTarg.negResult = SPNEGO_REJECT; reply_code = "NA"; reply_argument = talloc_strdup(ctx, nt_errstr(status)); @@ -1492,12 +1562,10 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, if (!reply_argument) { DEBUG(1, ("Could not write SPNEGO data blob\n")); x_fprintf(x_stdout, "BH Could not write SPNEGO data blob\n"); + spnego_free_data(&response); return; } - SAFE_FREE(user); - SAFE_FREE(domain); - len = spnego_write_data(ctx, &token, &response); spnego_free_data(&response); -- 1.7.0.4