static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_security, bool gssapi) { const char *hostname; struct gensec_krb5_state *gensec_krb5_state; NTSTATUS nt_status; hostname = gensec_get_target_hostname(gensec_security); if (!hostname) { DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); return NT_STATUS_INVALID_PARAMETER; } if (is_ipaddress(hostname)) { DEBUG(2, ("Cannot do krb5 to an IP address")); return NT_STATUS_INVALID_PARAMETER; } if (strcmp(hostname, "localhost") == 0) { DEBUG(2, ("krb5 to 'localhost' does not make sense")); return NT_STATUS_INVALID_PARAMETER; } nt_status = gensec_krb5_start(gensec_security, gssapi); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START; gensec_krb5_state->ap_req_options = AP_OPTS_USE_SUBKEY; if (gensec_krb5_state->gssapi) { /* The Fake GSSAPI modal emulates Samba3, which does not do mutual authentication */ if (gensec_setting_bool(gensec_security->settings, "gensec_fake_gssapi_krb5", "mutual", false)) { gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; } } else { /* The wrapping for KPASSWD (a user of the raw KRB5 API) should be mutually authenticated */ if (gensec_setting_bool(gensec_security->settings, "gensec_krb5", "mutual", true)) { gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; } } return NT_STATUS_OK; }
NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx, struct gensec_security *gensec_security, struct smb_krb5_context *smb_krb5_context, DATA_BLOB *pac_blob, const char *principal_string, const struct tsocket_address *remote_address, struct auth_session_info **session_info) { uint32_t session_info_flags = 0; if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) { session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN; } session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; if (!pac_blob) { if (!gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", principal_string)); return NT_STATUS_ACCESS_DENIED; } DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup\n", principal_string)); } if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info_pac) { return gensec_security->auth_context->generate_session_info_pac(gensec_security->auth_context, mem_ctx, smb_krb5_context, pac_blob, principal_string, remote_address, session_info_flags, session_info); } else { DEBUG(0, ("Cannot generate a session_info without the auth_context\n")); return NT_STATUS_INTERNAL_ERROR; } }
/** * Start NTLMSSP on the server side * */ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; struct ntlmssp_state *ntlmssp_state; struct gensec_ntlmssp_context *gensec_ntlmssp; const char *netbios_name; const char *netbios_domain; const char *dns_name; const char *dns_domain; enum server_role role; role = lpcfg_server_role(gensec_security->settings->lp_ctx); 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); ntlmssp_state = talloc_zero(gensec_ntlmssp, struct ntlmssp_state); if (!ntlmssp_state) { return NT_STATUS_NO_MEMORY; } gensec_ntlmssp->ntlmssp_state = ntlmssp_state; ntlmssp_state->role = NTLMSSP_SERVER; ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; ntlmssp_state->allow_lm_response = lpcfg_lanman_auth(gensec_security->settings->lp_ctx); if (ntlmssp_state->allow_lm_response && gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "allow_lm_key", false)) { ntlmssp_state->allow_lm_key = true; } ntlmssp_state->force_old_spnego = false; if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "force_old_spnego", false)) { /* * For testing Windows 2000 mode */ ntlmssp_state->force_old_spnego = true; } ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION; if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "56bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "keyexchange", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "alwayssign", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "ntlm2", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } if (ntlmssp_state->allow_lm_key) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; } /* * We always allow NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL. * * These will be removed if the client doesn't want them. */ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) { /* * We need to handle NTLMSSP_NEGOTIATE_SIGN as * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE * is requested. */ ntlmssp_state->force_wrap_seal = true; } } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } if (role == ROLE_STANDALONE) { ntlmssp_state->server.is_standalone = true; } else { ntlmssp_state->server.is_standalone = false; } if (gensec_security->settings->server_netbios_name) { netbios_name = gensec_security->settings->server_netbios_name; } else { netbios_name = lpcfg_netbios_name(gensec_security->settings->lp_ctx); } if (gensec_security->settings->server_netbios_domain) { netbios_domain = gensec_security->settings->server_netbios_domain; } else { netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx); } if (gensec_security->settings->server_dns_name) { dns_name = gensec_security->settings->server_dns_name; } else { const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); char *lower_netbiosname; lower_netbiosname = strlower_talloc(ntlmssp_state, netbios_name); NT_STATUS_HAVE_NO_MEMORY(lower_netbiosname); /* Find out the DNS host name */ if (dnsdomain && dnsdomain[0] != '\0') { dns_name = talloc_asprintf(ntlmssp_state, "%s.%s", lower_netbiosname, dnsdomain); talloc_free(lower_netbiosname); NT_STATUS_HAVE_NO_MEMORY(dns_name); } else { dns_name = lower_netbiosname; } } if (gensec_security->settings->server_dns_domain) { dns_domain = gensec_security->settings->server_dns_domain; } else { dns_domain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); } ntlmssp_state->server.netbios_name = talloc_strdup(ntlmssp_state, netbios_name); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.netbios_name); ntlmssp_state->server.netbios_domain = talloc_strdup(ntlmssp_state, netbios_domain); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.netbios_domain); ntlmssp_state->server.dns_name = talloc_strdup(ntlmssp_state, dns_name); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_name); ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, dns_domain); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain); ntlmssp_state->neg_flags |= ntlmssp_state->required_flags; ntlmssp_state->conf_flags = ntlmssp_state->neg_flags; return NT_STATUS_OK; }
static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) { struct gensec_gssapi_state *gensec_gssapi_state; krb5_error_code ret; #ifdef SAMBA4_USES_HEIMDAL const char *realm; #endif gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state); if (!gensec_gssapi_state) { return NT_STATUS_NO_MEMORY; } gensec_security->private_data = gensec_gssapi_state; gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT; /* TODO: Fill in channel bindings */ gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; gensec_gssapi_state->server_name = GSS_C_NO_NAME; gensec_gssapi_state->client_name = GSS_C_NO_NAME; gensec_gssapi_state->gss_want_flags = 0; gensec_gssapi_state->expire_time = GENSEC_EXPIRE_TIME_INFINITY; if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_POLICY_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "mutual", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_MUTUAL_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "replay", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_REPLAY_FLAG; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "sequence", true)) { gensec_gssapi_state->gss_want_flags |= GSS_C_SEQUENCE_FLAG; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG; } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG; gensec_gssapi_state->gss_want_flags |= GSS_C_CONF_FLAG; } if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) { gensec_gssapi_state->gss_want_flags |= GSS_C_DCE_STYLE; } gensec_gssapi_state->gss_got_flags = 0; switch (gensec_security->ops->auth_type) { case DCERPC_AUTH_TYPE_SPNEGO: gensec_gssapi_state->gss_oid = gss_mech_spnego; break; case DCERPC_AUTH_TYPE_KRB5: default: gensec_gssapi_state->gss_oid = discard_const_p(void, gss_mech_krb5); break; } ret = smb_krb5_init_context(gensec_gssapi_state, gensec_security->settings->lp_ctx, &gensec_gssapi_state->smb_krb5_context); if (ret) { DEBUG(1,("gensec_gssapi_start: smb_krb5_init_context failed (%s)\n", error_message(ret))); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } gensec_gssapi_state->client_cred = NULL; gensec_gssapi_state->server_cred = NULL; gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; gensec_gssapi_state->sasl = false; gensec_gssapi_state->sasl_state = STAGE_GSS_NEG; gensec_gssapi_state->sasl_protection = 0; gensec_gssapi_state->max_wrap_buf_size = gensec_setting_int(gensec_security->settings, "gensec_gssapi", "max wrap buf size", 65536); gensec_gssapi_state->gss_exchange_count = 0; gensec_gssapi_state->sig_size = 0; talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor); #ifdef SAMBA4_USES_HEIMDAL realm = lpcfg_realm(gensec_security->settings->lp_ctx); if (realm != NULL) { ret = gsskrb5_set_default_realm(realm); if (ret) { DEBUG(1,("gensec_gssapi_start: gsskrb5_set_default_realm failed\n")); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } } /* don't do DNS lookups of any kind, it might/will fail for a netbios name */ ret = gsskrb5_set_dns_canonicalize(gensec_setting_bool(gensec_security->settings, "krb5", "set_dns_canonicalize", false)); if (ret) { DEBUG(1,("gensec_gssapi_start: gsskrb5_set_dns_canonicalize failed\n")); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } #endif return NT_STATUS_OK; }
/* Try to figure out what features we actually got on the connection */ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, uint32_t feature) { struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); if (feature & GENSEC_FEATURE_SIGN) { /* If we are going GSSAPI SASL, then we honour the second negotiation */ if (gensec_gssapi_state->sasl && gensec_gssapi_state->sasl_state == STAGE_DONE) { return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) && (gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)); } return gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG; } if (feature & GENSEC_FEATURE_SEAL) { /* If we are going GSSAPI SASL, then we honour the second negotiation */ if (gensec_gssapi_state->sasl && gensec_gssapi_state->sasl_state == STAGE_DONE) { return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) && (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG)); } return gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG; } if (feature & GENSEC_FEATURE_SESSION_KEY) { /* Only for GSSAPI/Krb5 */ if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) { return true; } } if (feature & GENSEC_FEATURE_DCE_STYLE) { return gensec_gssapi_state->gss_got_flags & GSS_C_DCE_STYLE; } if (feature & GENSEC_FEATURE_NEW_SPNEGO) { NTSTATUS status; uint32_t keytype; if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) { return false; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "force_new_spnego", false)) { return true; } if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "disable_new_spnego", false)) { return false; } status = gssapi_get_session_key(gensec_gssapi_state, gensec_gssapi_state->gssapi_context, NULL, &keytype); /* * We should do a proper sig on the mechListMic unless * we know we have to be backwards compatible with * earlier windows versions. * * Negotiating a non-krb5 * mech for example should be regarded as having * NEW_SPNEGO */ if (NT_STATUS_IS_OK(status)) { switch (keytype) { case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD5: case ENCTYPE_ARCFOUR_HMAC: case ENCTYPE_DES3_CBC_SHA1: return false; } } return true; } /* We can always do async (rather than strict request/reply) packets. */ if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { return true; } if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { return true; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { return true; } return false; } return false; }
static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx_out, struct auth_session_info **_session_info) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context; struct auth_user_info_dc *user_info_dc = NULL; struct auth_session_info *session_info = NULL; struct PAC_LOGON_INFO *logon_info; krb5_principal client_principal; char *principal_string; DATA_BLOB pac; krb5_data pac_data; krb5_error_code ret; TALLOC_CTX *mem_ctx = talloc_new(mem_ctx_out); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal); if (ret) { DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context, client_principal, &principal_string); if (ret) { DEBUG(1, ("Unable to parse client principal: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket, KRB5_AUTHDATA_WIN2K_PAC, &pac_data); if (ret && gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s \n", principal_string, smb_get_krb5_error_message(context, ret, mem_ctx))); free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } else if (ret) { /* NO pac */ DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); if (gensec_security->auth_context && !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s", principal_string, smb_get_krb5_error_message(context, ret, mem_ctx))); nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx, gensec_security->auth_context, principal_string, NULL, &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } } else { DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", principal_string)); free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } } else { /* Found pac */ union netr_Validation validation; pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length); if (!pac.data) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } /* decode and verify the pac */ nt_status = kerberos_pac_logon_info(gensec_krb5_state, pac, gensec_krb5_state->smb_krb5_context->krb5_context, NULL, gensec_krb5_state->keyblock, client_principal, gensec_krb5_state->ticket->ticket.authtime, &logon_info); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } validation.sam3 = &logon_info->info3; nt_status = make_user_info_dc_netlogon_validation(mem_ctx, NULL, 3, &validation, true, /* This user was authenticated */ &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } } free(principal_string); krb5_free_principal(context, client_principal); /* references the user_info_dc into the session_info */ nt_status = gensec_generate_session_info(mem_ctx, gensec_security, user_info_dc, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } nt_status = gensec_krb5_session_key(gensec_security, session_info, &session_info->session_key); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } *_session_info = talloc_steal(mem_ctx_out, session_info); talloc_free(mem_ctx); return NT_STATUS_OK; }
static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_security, bool gssapi) { struct gensec_krb5_state *gensec_krb5_state; krb5_error_code ret; NTSTATUS nt_status; struct ccache_container *ccache_container; const char *hostname; const char *principal; krb5_data in_data; hostname = gensec_get_target_hostname(gensec_security); if (!hostname) { DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); return NT_STATUS_INVALID_PARAMETER; } if (is_ipaddress(hostname)) { DEBUG(2, ("Cannot do krb5 to an IP address")); return NT_STATUS_INVALID_PARAMETER; } if (strcmp(hostname, "localhost") == 0) { DEBUG(2, ("krb5 to 'localhost' does not make sense")); return NT_STATUS_INVALID_PARAMETER; } nt_status = gensec_krb5_start(gensec_security, gssapi); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START; gensec_krb5_state->ap_req_options = AP_OPTS_USE_SUBKEY; if (gensec_krb5_state->gssapi) { /* The Fake GSSAPI modal emulates Samba3, which does not do mutual authentication */ if (gensec_setting_bool(gensec_security->settings, "gensec_fake_gssapi_krb5", "mutual", false)) { gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; } } else { /* The wrapping for KPASSWD (a user of the raw KRB5 API) should be mutually authenticated */ if (gensec_setting_bool(gensec_security->settings, "gensec_krb5", "mutual", true)) { gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; } } principal = gensec_get_target_principal(gensec_security); ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), gensec_security->event_ctx, gensec_security->settings->lp_ctx, &ccache_container); switch (ret) { case 0: break; case KRB5KDC_ERR_PREAUTH_FAILED: return NT_STATUS_LOGON_FAILURE; case KRB5_KDC_UNREACH: DEBUG(3, ("Cannot reach a KDC we require to contact %s\n", principal)); return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ default: DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_message(ret))); return NT_STATUS_UNSUCCESSFUL; } in_data.length = 0; if (principal && lp_client_use_spnego_principal(gensec_security->settings->lp_ctx)) { krb5_principal target_principal; ret = krb5_parse_name(gensec_krb5_state->smb_krb5_context->krb5_context, principal, &target_principal); if (ret == 0) { ret = krb5_mk_req_exact(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context, gensec_krb5_state->ap_req_options, target_principal, &in_data, ccache_container->ccache, &gensec_krb5_state->enc_ticket); krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context, target_principal); } } else { ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context, gensec_krb5_state->ap_req_options, gensec_get_target_service(gensec_security), hostname, &in_data, ccache_container->ccache, &gensec_krb5_state->enc_ticket); } switch (ret) { case 0: return NT_STATUS_OK; case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ case KRB5_KDC_UNREACH: DEBUG(3, ("Cannot reach a KDC we require to contact host [%s]: %s\n", hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5KRB_AP_ERR_TKT_EXPIRED: case KRB5_CC_END: /* Too much clock skew - we will need to kinit to re-skew the clock */ case KRB5KRB_AP_ERR_SKEW: case KRB5_KDCREP_SKEW: { DEBUG(3, ("kerberos (mk_req) failed: %s\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); /*fall through*/ } /* just don't print a message for these really ordinary messages */ case KRB5_FCC_NOFILE: case KRB5_CC_NOTFOUND: case ENOENT: return NT_STATUS_UNSUCCESSFUL; break; default: DEBUG(0, ("kerberos: %s\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); return NT_STATUS_UNSUCCESSFUL; } }
/** * Start NTLMSSP on the server side * */ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; struct ntlmssp_state *ntlmssp_state; struct gensec_ntlmssp_context *gensec_ntlmssp; 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); ntlmssp_state = gensec_ntlmssp->ntlmssp_state; ntlmssp_state->role = NTLMSSP_SERVER; ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; ntlmssp_state->allow_lm_key = (lpcfg_lanman_auth(gensec_security->settings->lp_ctx) && gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "allow_lm_key", false)); ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION; ntlmssp_state->lm_resp = data_blob(NULL, 0); ntlmssp_state->nt_resp = data_blob(NULL, 0); if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "56bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "keyexchange", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "alwayssign", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "ntlm2", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; ntlmssp_state->check_password = auth_ntlmssp_check_password; if (lpcfg_server_role(gensec_security->settings->lp_ctx) == ROLE_STANDALONE) { ntlmssp_state->server.is_standalone = true; } else { ntlmssp_state->server.is_standalone = false; } ntlmssp_state->server.netbios_name = lpcfg_netbios_name(gensec_security->settings->lp_ctx); ntlmssp_state->server.netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx); { const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); char *dnsname, *lower_netbiosname; lower_netbiosname = strlower_talloc(ntlmssp_state, ntlmssp_state->server.netbios_name); /* Find out the DNS host name */ if (dnsdomain && dnsdomain[0] != '\0') { dnsname = talloc_asprintf(ntlmssp_state, "%s.%s", lower_netbiosname, dnsdomain); talloc_free(lower_netbiosname); ntlmssp_state->server.dns_name = dnsname; } else { ntlmssp_state->server.dns_name = lower_netbiosname; } NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_name); ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain); } return NT_STATUS_OK; }
NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) { struct gensec_ntlmssp_context *gensec_ntlmssp; struct ntlmssp_state *ntlmssp_state; NTSTATUS nt_status; 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); ntlmssp_state = talloc_zero(gensec_ntlmssp, struct ntlmssp_state); if (!ntlmssp_state) { return NT_STATUS_NO_MEMORY; } gensec_ntlmssp->ntlmssp_state = ntlmssp_state; ntlmssp_state = gensec_ntlmssp->ntlmssp_state; ntlmssp_state->role = NTLMSSP_CLIENT; ntlmssp_state->client.netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx); ntlmssp_state->client.netbios_name = cli_credentials_get_workstation(gensec_security->credentials); ntlmssp_state->unicode = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "unicode", true); ntlmssp_state->use_nt_response = gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "send_nt_reponse", true); ntlmssp_state->allow_lm_key = (lpcfg_client_lanman_auth(gensec_security->settings->lp_ctx) && (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "allow_lm_key", false) || gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false))); ntlmssp_state->use_ntlmv2 = lpcfg_client_ntlmv2_auth(gensec_security->settings->lp_ctx); ntlmssp_state->expected_state = NTLMSSP_INITIAL; ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET; if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "56bit", false)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "lm_key", false)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "keyexchange", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "alwayssign", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_client", "ntlm2", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } else { /* apparently we can't do ntlmv2 if we don't do ntlm2 */ ntlmssp_state->use_ntlmv2 = false; } if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { /* * We need to set this to allow a later SetPassword * via the SAMR pipe to succeed. Strange.... We could * also add NTLMSSP_NEGOTIATE_SEAL here. JRA. * * Without this, Windows will not create the master key * that it thinks is only used for NTLMSSP signing and * sealing. (It is actually pulled out and used directly) */ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } return NT_STATUS_OK; }