static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB request, DATA_BLOB *reply) { DATA_BLOB struct_blob; const char *dnsname; char *dnsdomname = NULL; uint32 neg_flags = 0; uint32 ntlmssp_command, chal_flags; const uint8 *cryptkey; const char *target_name; /* parse the NTLMSSP packet */ #if 0 file_save("ntlmssp_negotiate.dat", request.data, request.length); #endif if (request.length) { if ((request.length < 16) || !msrpc_parse(&request, "Cdd", "NTLMSSP", &ntlmssp_command, &neg_flags)) { DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n", (unsigned int)request.length)); dump_data(2, request.data, request.length); return NT_STATUS_INVALID_PARAMETER; } debug_ntlmssp_flags(neg_flags); } ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth()); /* Ask our caller what challenge they would like in the packet */ cryptkey = ntlmssp_state->get_challenge(ntlmssp_state); /* Check if we may set the challenge */ if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; } /* The flags we send back are not just the negotiated flags, * they are also 'what is in this packet'. Therfore, we * operate on 'chal_flags' from here on */ chal_flags = ntlmssp_state->neg_flags; /* get the right name to fill in as 'target' */ target_name = ntlmssp_target_name(ntlmssp_state, neg_flags, &chal_flags); if (target_name == NULL) { return NT_STATUS_INVALID_PARAMETER; } ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8); ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8); /* This should be a 'netbios domain -> DNS domain' mapping */ dnsdomname = get_mydnsdomname(ntlmssp_state->mem_ctx); if (!dnsdomname) { dnsdomname = talloc_strdup(ntlmssp_state->mem_ctx, ""); } if (!dnsdomname) { return NT_STATUS_NO_MEMORY; } strlower_m(dnsdomname); dnsname = get_mydnsfullname(); if (!dnsname) { dnsname = ""; } /* This creates the 'blob' of names that appears at the end of the packet */ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { msrpc_gen(&struct_blob, "aaaaa", NTLMSSP_NAME_TYPE_DOMAIN, target_name, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(), NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname, 0, ""); } else { struct_blob = data_blob_null; } { /* Marshel the packet in the right format, be it unicode or ASCII */ const char *gen_string; if (ntlmssp_state->unicode) { gen_string = "CdUdbddB"; } else { gen_string = "CdAdbddB"; } msrpc_gen(reply, gen_string, "NTLMSSP", NTLMSSP_CHALLENGE, target_name, chal_flags, cryptkey, 8, 0, 0, struct_blob.data, struct_blob.length); } data_blob_free(&struct_blob); ntlmssp_state->expected_state = NTLMSSP_AUTH; return NT_STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB request, DATA_BLOB *reply) { struct gensec_ntlmssp_context *gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; struct auth4_context *auth_context = gensec_security->auth_context; DATA_BLOB struct_blob; uint32_t neg_flags = 0; uint32_t ntlmssp_command, chal_flags; uint8_t cryptkey[8]; const char *target_name; NTSTATUS status; /* parse the NTLMSSP packet */ #if 0 file_save("ntlmssp_negotiate.dat", request.data, request.length); #endif if (request.length) { if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd", "NTLMSSP", &ntlmssp_command, &neg_flags)) { DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n", (unsigned int)request.length)); dump_data(2, request.data, request.length); return NT_STATUS_INVALID_PARAMETER; } debug_ntlmssp_flags(neg_flags); if (DEBUGLEVEL >= 10) { struct NEGOTIATE_MESSAGE *negotiate = talloc( ntlmssp_state, struct NEGOTIATE_MESSAGE); if (negotiate != NULL) { status = ntlmssp_pull_NEGOTIATE_MESSAGE( &request, negotiate, negotiate); if (NT_STATUS_IS_OK(status)) { NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE, negotiate); } TALLOC_FREE(negotiate); } } } ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key); /* Ask our caller what challenge they would like in the packet */ if (auth_context->get_ntlm_challenge) { status = auth_context->get_ntlm_challenge(auth_context, cryptkey); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n", nt_errstr(status))); return status; } } else { DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't give a challenge\n")); return NT_STATUS_NOT_IMPLEMENTED; } /* The flags we send back are not just the negotiated flags, * they are also 'what is in this packet'. Therfore, we * operate on 'chal_flags' from here on */ chal_flags = ntlmssp_state->neg_flags; /* get the right name to fill in as 'target' */ target_name = ntlmssp_target_name(ntlmssp_state, neg_flags, &chal_flags); if (target_name == NULL) return NT_STATUS_INVALID_PARAMETER; ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); /* This creates the 'blob' of names that appears at the end of the packet */ if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { status = msrpc_gen(ntlmssp_state, &struct_blob, "aaaaa", MsvAvNbDomainName, target_name, MsvAvNbComputerName, ntlmssp_state->server.netbios_name, MsvAvDnsDomainName, ntlmssp_state->server.dns_domain, MsvAvDnsComputerName, ntlmssp_state->server.dns_name, MsvAvEOL, ""); if (!NT_STATUS_IS_OK(status)) { return status; } } else { struct_blob = data_blob_null; } { /* Marshal the packet in the right format, be it unicode or ASCII */ const char *gen_string; DATA_BLOB version_blob = data_blob_null; if (chal_flags & NTLMSSP_NEGOTIATE_VERSION) { enum ndr_err_code err; struct ntlmssp_VERSION vers; /* "What Windows returns" as a version number. */ ZERO_STRUCT(vers); vers.ProductMajorVersion = NTLMSSP_WINDOWS_MAJOR_VERSION_6; vers.ProductMinorVersion = NTLMSSP_WINDOWS_MINOR_VERSION_1; vers.ProductBuild = 0; vers.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; err = ndr_push_struct_blob(&version_blob, ntlmssp_state, &vers, (ndr_push_flags_fn_t)ndr_push_ntlmssp_VERSION); if (!NDR_ERR_CODE_IS_SUCCESS(err)) { data_blob_free(&struct_blob); return NT_STATUS_NO_MEMORY; } } if (ntlmssp_state->unicode) { gen_string = "CdUdbddBb"; } else { gen_string = "CdAdbddBb"; } status = msrpc_gen(out_mem_ctx, reply, gen_string, "NTLMSSP", NTLMSSP_CHALLENGE, target_name, chal_flags, cryptkey, 8, 0, 0, struct_blob.data, struct_blob.length, version_blob.data, version_blob.length); if (!NT_STATUS_IS_OK(status)) { data_blob_free(&version_blob); data_blob_free(&struct_blob); return status; } data_blob_free(&version_blob); if (DEBUGLEVEL >= 10) { struct CHALLENGE_MESSAGE *challenge = talloc( ntlmssp_state, struct CHALLENGE_MESSAGE); if (challenge != NULL) { challenge->NegotiateFlags = chal_flags; status = ntlmssp_pull_CHALLENGE_MESSAGE( reply, challenge, challenge); if (NT_STATUS_IS_OK(status)) { NDR_PRINT_DEBUG(CHALLENGE_MESSAGE, challenge); } TALLOC_FREE(challenge); } } } data_blob_free(&struct_blob); ntlmssp_state->expected_state = NTLMSSP_AUTH; return NT_STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB request, DATA_BLOB *reply) { struct gensec_ntlmssp_context *gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; struct auth4_context *auth_context = gensec_security->auth_context; DATA_BLOB struct_blob; uint32_t neg_flags = 0; uint32_t ntlmssp_command, chal_flags; uint8_t cryptkey[8]; const char *target_name; NTSTATUS status; struct timeval tv_now = timeval_current(); /* * See [MS-NLMP] * * Windows NT 4.0, windows_2000: use 30 minutes, * Windows XP, Windows Server 2003, Windows Vista, * Windows Server 2008, Windows 7, and Windows Server 2008 R2 * use 36 hours. * * Newer systems doesn't check this, likely because the * connectionless NTLMSSP is no longer supported. * * As we expect the AUTHENTICATION_MESSAGE to arrive * directly after the NEGOTIATE_MESSAGE (typically less than * as 1 second later). We use a hard timeout of 30 Minutes. * * We don't look at AUTHENTICATE_MESSAGE.NtChallengeResponse.TimeStamp * instead we just remember our own time. */ uint32_t max_lifetime = 30 * 60; struct timeval tv_end = timeval_add(&tv_now, max_lifetime, 0); /* parse the NTLMSSP packet */ #if 0 file_save("ntlmssp_negotiate.dat", request.data, request.length); #endif if (request.length) { if (request.length > UINT16_MAX) { DEBUG(1, ("ntlmssp_server_negotiate: reject large request of length %u\n", (unsigned int)request.length)); return NT_STATUS_INVALID_PARAMETER; } if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd", "NTLMSSP", &ntlmssp_command, &neg_flags)) { DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n", (unsigned int)request.length)); dump_data(2, request.data, request.length); return NT_STATUS_INVALID_PARAMETER; } debug_ntlmssp_flags(neg_flags); if (DEBUGLEVEL >= 10) { struct NEGOTIATE_MESSAGE *negotiate = talloc( ntlmssp_state, struct NEGOTIATE_MESSAGE); if (negotiate != NULL) { status = ntlmssp_pull_NEGOTIATE_MESSAGE( &request, negotiate, negotiate); if (NT_STATUS_IS_OK(status)) { NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE, negotiate); } TALLOC_FREE(negotiate); } } } status = ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, "negotiate"); if (!NT_STATUS_IS_OK(status)){ return status; } /* Ask our caller what challenge they would like in the packet */ if (auth_context->get_ntlm_challenge) { status = auth_context->get_ntlm_challenge(auth_context, cryptkey); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n", nt_errstr(status))); return status; } } else { DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't give a challenge\n")); return NT_STATUS_NOT_IMPLEMENTED; } /* The flags we send back are not just the negotiated flags, * they are also 'what is in this packet'. Therfore, we * operate on 'chal_flags' from here on */ chal_flags = ntlmssp_state->neg_flags; ntlmssp_state->server.challenge_endtime = timeval_to_nttime(&tv_end); /* get the right name to fill in as 'target' */ target_name = ntlmssp_target_name(ntlmssp_state, neg_flags, &chal_flags); if (target_name == NULL) return NT_STATUS_INVALID_PARAMETER; ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); /* This creates the 'blob' of names that appears at the end of the packet */ if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { enum ndr_err_code err; struct AV_PAIR *pairs = NULL; uint32_t count = 5; pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR, count + 1); if (pairs == NULL) { return NT_STATUS_NO_MEMORY; } pairs[0].AvId = MsvAvNbDomainName; pairs[0].Value.AvNbDomainName = target_name; pairs[1].AvId = MsvAvNbComputerName; pairs[1].Value.AvNbComputerName = ntlmssp_state->server.netbios_name; pairs[2].AvId = MsvAvDnsDomainName; pairs[2].Value.AvDnsDomainName = ntlmssp_state->server.dns_domain; pairs[3].AvId = MsvAvDnsComputerName; pairs[3].Value.AvDnsComputerName= ntlmssp_state->server.dns_name; if (!ntlmssp_state->force_old_spnego) { pairs[4].AvId = MsvAvTimestamp; pairs[4].Value.AvTimestamp = timeval_to_nttime(&tv_now); count += 1; pairs[5].AvId = MsvAvEOL; } else { pairs[4].AvId = MsvAvEOL; } ntlmssp_state->server.av_pair_list.count = count; ntlmssp_state->server.av_pair_list.pair = pairs; err = ndr_push_struct_blob(&struct_blob, ntlmssp_state, &ntlmssp_state->server.av_pair_list, (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST); if (!NDR_ERR_CODE_IS_SUCCESS(err)) { return NT_STATUS_NO_MEMORY; } } else {
NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB request, DATA_BLOB *reply) { struct gensec_ntlmssp_context *gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; struct auth4_context *auth_context = gensec_security->auth_context; DATA_BLOB struct_blob; uint32_t neg_flags = 0; uint32_t ntlmssp_command, chal_flags; uint8_t cryptkey[8]; const char *target_name; NTSTATUS status; /* parse the NTLMSSP packet */ #if 0 file_save("ntlmssp_negotiate.dat", request.data, request.length); #endif if (request.length) { if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd", "NTLMSSP", &ntlmssp_command, &neg_flags)) { DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n", (unsigned int)request.length)); dump_data(2, request.data, request.length); return NT_STATUS_INVALID_PARAMETER; } debug_ntlmssp_flags(neg_flags); if (DEBUGLEVEL >= 10) { struct NEGOTIATE_MESSAGE *negotiate = talloc( ntlmssp_state, struct NEGOTIATE_MESSAGE); if (negotiate != NULL) { status = ntlmssp_pull_NEGOTIATE_MESSAGE( &request, negotiate, negotiate); if (NT_STATUS_IS_OK(status)) { NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE, negotiate); } TALLOC_FREE(negotiate); } } } ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, ntlmssp_state->allow_lm_key); /* Ask our caller what challenge they would like in the packet */ if (auth_context->get_ntlm_challenge) { status = auth_context->get_ntlm_challenge(auth_context, cryptkey); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n", nt_errstr(status))); return status; } } else { DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't give a challenge\n")); return NT_STATUS_NOT_IMPLEMENTED; } /* The flags we send back are not just the negotiated flags, * they are also 'what is in this packet'. Therfore, we * operate on 'chal_flags' from here on */ chal_flags = ntlmssp_state->neg_flags; /* get the right name to fill in as 'target' */ target_name = ntlmssp_target_name(ntlmssp_state, neg_flags, &chal_flags); if (target_name == NULL) return NT_STATUS_INVALID_PARAMETER; ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); /* This creates the 'blob' of names that appears at the end of the packet */ if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { enum ndr_err_code err; struct AV_PAIR *pairs = NULL; uint32_t count = 5; pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR, count); if (pairs == NULL) { return NT_STATUS_NO_MEMORY; } pairs[0].AvId = MsvAvNbDomainName; pairs[0].Value.AvNbDomainName = target_name; pairs[1].AvId = MsvAvNbComputerName; pairs[1].Value.AvNbComputerName = ntlmssp_state->server.netbios_name; pairs[2].AvId = MsvAvDnsDomainName; pairs[2].Value.AvDnsDomainName = ntlmssp_state->server.dns_domain; pairs[3].AvId = MsvAvDnsComputerName; pairs[3].Value.AvDnsComputerName= ntlmssp_state->server.dns_name; pairs[4].AvId = MsvAvEOL; ntlmssp_state->server.av_pair_list.count = count; ntlmssp_state->server.av_pair_list.pair = pairs; err = ndr_push_struct_blob(&struct_blob, ntlmssp_state, &ntlmssp_state->server.av_pair_list, (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST); if (!NDR_ERR_CODE_IS_SUCCESS(err)) { return NT_STATUS_NO_MEMORY; } } else {