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 auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address, struct gensec_security **gensec_security_out) { struct gensec_security *gensec_security; struct auth_context *auth_context; NTSTATUS nt_status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); nt_status = make_auth_context_subsystem(tmp_ctx, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } if (auth_context->prepare_gensec) { nt_status = auth_context->prepare_gensec(auth_context, tmp_ctx, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } } else { const struct gensec_security_ops **backends = NULL; struct gensec_settings *gensec_settings; struct loadparm_context *lp_ctx; size_t idx = 0; struct cli_credentials *server_credentials; const char *dns_name; const char *dns_domain; struct auth4_context *auth4_context = make_auth4_context_s3(tmp_ctx, auth_context); if (auth4_context == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_INVALID_SERVER_STATE; } gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx); if (lp_ctx == NULL) { DEBUG(10, ("lpcfg_gensec_settings failed\n")); TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* * This should be a 'netbios domain -> DNS domain' * mapping, and can currently validly return NULL on * poorly configured systems. * * This is used for the NTLMSSP server * */ dns_name = get_mydnsfullname(); if (dns_name == NULL) { dns_name = ""; } dns_domain = get_mydnsdomname(tmp_ctx); if (dns_domain == NULL) { dns_domain = ""; } gensec_settings->server_dns_name = strlower_talloc(gensec_settings, dns_name); if (gensec_settings->server_dns_name == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->server_dns_domain = strlower_talloc(gensec_settings, dns_domain); if (gensec_settings->server_dns_domain == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } backends = talloc_zero_array(gensec_settings, const struct gensec_security_ops *, 6); if (backends == NULL) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } gensec_settings->backends = backends; gensec_init(); /* These need to be in priority order, krb5 before NTLMSSP */ #if defined(HAVE_KRB5) backends[idx++] = &gensec_gse_krb5_security_ops; #endif backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP); backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL); backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM); /* * This is anonymous for now, because we just use it * to set the kerberos state at the moment */ server_credentials = cli_credentials_init_anon(tmp_ctx); if (!server_credentials) { DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n")); return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(server_credentials, lp_ctx); if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) { cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS); } else { cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS); } nt_status = gensec_server_start(tmp_ctx, gensec_settings, auth4_context, &gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } gensec_set_credentials(gensec_security, server_credentials); talloc_unlink(tmp_ctx, lp_ctx); talloc_unlink(tmp_ctx, server_credentials); talloc_unlink(tmp_ctx, gensec_settings); talloc_unlink(tmp_ctx, auth4_context); } nt_status = gensec_set_remote_address(gensec_security, remote_address); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } *gensec_security_out = talloc_steal(mem_ctx, gensec_security); TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; }
static NTSTATUS gensec_ntlmssp3_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; bool is_standalone; const char *netbios_name; const char *netbios_domain; const char *dns_name; char *dns_domain; struct gensec_ntlmssp_context *gensec_ntlmssp; if ((enum server_role)lp_server_role() == ROLE_STANDALONE) { is_standalone = true; } else { is_standalone = false; } netbios_name = lp_netbios_name(); netbios_domain = lp_workgroup(); /* This should be a 'netbios domain -> DNS domain' mapping */ dns_domain = get_mydnsdomname(talloc_tos()); if (dns_domain) { strlower_m(dns_domain); } dns_name = get_mydnsfullname(); nt_status = gensec_ntlmssp_start(gensec_security); NT_STATUS_NOT_OK_RETURN(nt_status); gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); nt_status = make_auth_context_subsystem(gensec_ntlmssp, &gensec_ntlmssp->auth_context); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } nt_status = ntlmssp_server_start(gensec_ntlmssp, is_standalone, netbios_name, netbios_domain, dns_name, dns_domain, &gensec_ntlmssp->ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } gensec_ntlmssp->ntlmssp_state->callback_private = gensec_ntlmssp; gensec_ntlmssp->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; gensec_ntlmssp->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; gensec_ntlmssp->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; gensec_ntlmssp->ntlmssp_state->check_password = auth_ntlmssp_check_password; if (gensec_ntlmssp->gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_ntlmssp->gensec_security->want_features & GENSEC_FEATURE_SIGN) { gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_ntlmssp->gensec_security->want_features & GENSEC_FEATURE_SEAL) { gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; gensec_ntlmssp->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } return NT_STATUS_OK; }
static NTSTATUS fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, DSROLE_PRIMARY_DOMAIN_INFO_BASIC **info) { DSROLE_PRIMARY_DOMAIN_INFO_BASIC *basic; const char *netbios_domain; fstring dnsdomain; DEBUG(10,("fill_dsrole_dominfo_basic: enter\n")); if ( !(basic = talloc_zero(ctx, sizeof(DSROLE_PRIMARY_DOMAIN_INFO_BASIC))) ) { DEBUG(0,("fill_dsrole_dominfo_basic: FATAL error! talloc_xero() failed\n")); return NT_STATUS_NO_MEMORY; } switch ( lp_server_role() ) { case ROLE_STANDALONE: basic->machine_role = DSROLE_STANDALONE_SRV; break; case ROLE_DOMAIN_MEMBER: basic->machine_role = DSROLE_DOMAIN_MEMBER_SRV; break; case ROLE_DOMAIN_BDC: basic->machine_role = DSROLE_BDC; basic->flags = DSROLE_PRIMARY_DS_RUNNING|DSROLE_PRIMARY_DS_MIXED_MODE; if ( secrets_fetch_domain_guid( lp_workgroup(), &basic->domain_guid ) ) basic->flags |= DSROLE_PRIMARY_DOMAIN_GUID_PRESENT; get_mydnsdomname(dnsdomain); strlower_m(dnsdomain); break; case ROLE_DOMAIN_PDC: basic->machine_role = DSROLE_PDC; basic->flags = DSROLE_PRIMARY_DS_RUNNING|DSROLE_PRIMARY_DS_MIXED_MODE; if ( secrets_fetch_domain_guid( lp_workgroup(), &basic->domain_guid ) ) basic->flags |= DSROLE_PRIMARY_DOMAIN_GUID_PRESENT; get_mydnsdomname(dnsdomain); strlower_m(dnsdomain); break; } basic->unknown = 0x6173; /* seen on the wire; maybe padding */ /* always set netbios name */ basic->netbios_ptr = 1; netbios_domain = get_global_sam_name(); init_unistr2( &basic->netbios_domain, netbios_domain, UNI_FLAGS_NONE); basic->dnsname_ptr = 1; init_unistr2( &basic->dns_domain, dnsdomain, UNI_FLAGS_NONE); basic->forestname_ptr = 1; init_unistr2( &basic->forest_domain, dnsdomain, UNI_FLAGS_NONE); /* fill in some additional fields if we are a member of an AD domain */ if ( lp_security() == SEC_ADS ) { /* TODO */ ;; } *info = basic; return NT_STATUS_OK; }
NTSTATUS auth_ntlmssp_start(const struct tsocket_address *remote_address, struct auth_ntlmssp_state **auth_ntlmssp_state) { NTSTATUS nt_status; bool is_standalone; const char *netbios_name; const char *netbios_domain; const char *dns_name; char *dns_domain; struct auth_ntlmssp_state *ans; struct auth_context *auth_context; if ((enum server_role)lp_server_role() == ROLE_STANDALONE) { is_standalone = true; } else { is_standalone = false; } netbios_name = lp_netbios_name(); netbios_domain = lp_workgroup(); /* This should be a 'netbios domain -> DNS domain' mapping */ dns_domain = get_mydnsdomname(talloc_tos()); if (dns_domain) { strlower_m(dns_domain); } dns_name = get_mydnsfullname(); ans = talloc_zero(NULL, struct auth_ntlmssp_state); if (!ans) { DEBUG(0,("auth_ntlmssp_start: talloc failed!\n")); return NT_STATUS_NO_MEMORY; } ans->remote_address = tsocket_address_copy(remote_address, ans); if (ans->remote_address == NULL) { DEBUG(0,("auth_ntlmssp_start: talloc failed!\n")); return NT_STATUS_NO_MEMORY; } nt_status = ntlmssp_server_start(ans, is_standalone, netbios_name, netbios_domain, dns_name, dns_domain, &ans->ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } nt_status = make_auth_context_subsystem(talloc_tos(), &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } ans->auth_context = talloc_steal(ans, auth_context); ans->ntlmssp_state->callback_private = ans; ans->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; ans->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; ans->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; ans->ntlmssp_state->check_password = auth_ntlmssp_check_password; talloc_set_destructor((TALLOC_CTX *)ans, auth_ntlmssp_state_destructor); *auth_ntlmssp_state = ans; return NT_STATUS_OK; }