X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source4%2Fauth%2Fgensec%2Fgensec_gssapi.c;h=f0da54d711360b4195772b5b0dcb7c31df3ee0db;hb=5f655e99a1c17ac9d28acb4740585d2100746d69;hp=73c12a20ff660735a260e201247c319b4bbf5f85;hpb=f9ca9e46ad24036bf00cb361a6cef4b2e7e98d7d;p=samba.git diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 73c12a20ff6..f0da54d7113 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -147,32 +147,25 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) { struct gensec_gssapi_state *gensec_gssapi_state; krb5_error_code ret; - struct gsskrb5_send_to_kdc send_to_kdc; const char *realm; - gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state); + gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state); if (!gensec_gssapi_state) { return NT_STATUS_NO_MEMORY; } - - gensec_gssapi_state->gss_exchange_count = 0; - gensec_gssapi_state->max_wrap_buf_size - = gensec_setting_int(gensec_security->settings, "gensec_gssapi", "max wrap buf size", 65536); - - gensec_gssapi_state->sasl = false; - gensec_gssapi_state->sasl_state = STAGE_GSS_NEG; gensec_security->private_data = gensec_gssapi_state; gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT; - gensec_gssapi_state->server_name = GSS_C_NO_NAME; - gensec_gssapi_state->client_name = GSS_C_NO_NAME; - gensec_gssapi_state->lucid = NULL; /* 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->want_flags = 0; + if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) { gensec_gssapi_state->want_flags |= GSS_C_DELEG_POLICY_FLAG; } @@ -189,16 +182,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG; } - gensec_gssapi_state->got_flags = 0; - - gensec_gssapi_state->session_key = data_blob(NULL, 0); - gensec_gssapi_state->pac = data_blob(NULL, 0); - - gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; - gensec_gssapi_state->sig_size = 0; - - talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor); - if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG; } @@ -209,6 +192,8 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE; } + gensec_gssapi_state->got_flags = 0; + switch (gensec_security->ops->auth_type) { case DCERPC_AUTH_TYPE_SPNEGO: gensec_gssapi_state->gss_oid = gss_mech_spnego; @@ -219,17 +204,39 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) break; } - send_to_kdc.func = smb_krb5_send_and_recv_func; - send_to_kdc.ptr = gensec_security->event_ctx; + gensec_gssapi_state->session_key = data_blob(NULL, 0); + gensec_gssapi_state->pac = data_blob(NULL, 0); - ret = gsskrb5_set_send_to_kdc(&send_to_kdc); + ret = smb_krb5_init_context(gensec_gssapi_state, + NULL, + gensec_security->settings->lp_ctx, + &gensec_gssapi_state->smb_krb5_context); if (ret) { - DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n")); + DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", + error_message(ret))); talloc_free(gensec_gssapi_state); return NT_STATUS_INTERNAL_ERROR; } - realm = lp_realm(gensec_security->settings->lp_ctx); + gensec_gssapi_state->client_cred = NULL; + gensec_gssapi_state->server_cred = NULL; + + gensec_gssapi_state->lucid = 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); + + realm = lpcfg_realm(gensec_security->settings->lp_ctx); if (realm != NULL) { ret = gsskrb5_set_default_realm(realm); if (ret) { @@ -247,16 +254,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) return NT_STATUS_INTERNAL_ERROR; } - ret = smb_krb5_init_context(gensec_gssapi_state, - gensec_security->event_ctx, - gensec_security->settings->lp_ctx, - &gensec_gssapi_state->smb_krb5_context); - if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", - error_message(ret))); - talloc_free(gensec_gssapi_state); - return NT_STATUS_INTERNAL_ERROR; - } return NT_STATUS_OK; } @@ -282,7 +279,6 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } else { ret = cli_credentials_get_server_gss_creds(machine_account, - gensec_security->event_ctx, gensec_security->settings->lp_ctx, &gcc); if (ret) { DEBUG(1, ("Aquiring acceptor credentials failed: %s\n", @@ -319,7 +315,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi gss_OID name_type; OM_uint32 maj_stat, min_stat; const char *hostname = gensec_get_target_hostname(gensec_security); - const char *principal; struct gssapi_creds_container *gcc; const char *error_string; @@ -343,18 +338,18 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); - principal = gensec_get_target_principal(gensec_security); - if (principal && lp_client_use_spnego_principal(gensec_security->settings->lp_ctx)) { + gensec_gssapi_state->target_principal = gensec_get_target_principal(gensec_security); + if (gensec_gssapi_state->target_principal) { name_type = GSS_C_NULL_OID; } else { - principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s", + gensec_gssapi_state->target_principal = talloc_asprintf(gensec_gssapi_state, "%s/%s@%s", gensec_get_target_service(gensec_security), - hostname, lp_realm(gensec_security->settings->lp_ctx)); + hostname, lpcfg_realm(gensec_security->settings->lp_ctx)); name_type = GSS_C_NT_USER_NAME; - } - name_token.value = discard_const_p(uint8_t, principal); - name_token.length = strlen(principal); + } + name_token.value = discard_const_p(uint8_t, gensec_gssapi_state->target_principal); + name_token.length = strlen(gensec_gssapi_state->target_principal); maj_stat = gss_import_name (&min_stat, @@ -375,14 +370,16 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi case 0: break; case KRB5KDC_ERR_PREAUTH_FAILED: + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + DEBUG(1, ("Wrong username or password: %s\n", error_string)); return NT_STATUS_LOGON_FAILURE; case KRB5_KDC_UNREACH: - DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", principal, error_string)); - return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ + DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string)); + return NT_STATUS_NO_LOGON_SERVERS; case KRB5_CC_NOTFOUND: case KRB5_CC_END: - DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string)); - return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ + DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string)); + return NT_STATUS_TIME_DIFFERENCE_AT_DC; default: DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string)); return NT_STATUS_UNSUCCESSFUL; @@ -461,6 +458,17 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, switch (gensec_security->gensec_role) { case GENSEC_CLIENT: { + struct gsskrb5_send_to_kdc send_to_kdc; + krb5_error_code ret; + send_to_kdc.func = smb_krb5_send_and_recv_func; + send_to_kdc.ptr = gensec_security->event_ctx; + + min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc); + if (min_stat) { + DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n")); + return NT_STATUS_INTERNAL_ERROR; + } + maj_stat = gss_init_sec_context(&min_stat, gensec_gssapi_state->client_cred->creds, &gensec_gssapi_state->gssapi_context, @@ -477,6 +485,16 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, if (gss_oid_p) { gensec_gssapi_state->gss_oid = gss_oid_p; } + + send_to_kdc.func = smb_krb5_send_and_recv_func; + send_to_kdc.ptr = NULL; + + ret = gsskrb5_set_send_to_kdc(&send_to_kdc); + if (ret) { + DEBUG(1,("gensec_krb5_start: gsskrb5_set_send_to_kdc failed\n")); + return NT_STATUS_INTERNAL_ERROR; + } + break; } case GENSEC_SERVER: @@ -536,9 +554,9 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, gensec_gssapi_state->sasl_state = STAGE_DONE; if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - DEBUG(5, ("GSSAPI Connection will be cryptographicly sealed\n")); + DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n")); } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(5, ("GSSAPI Connection will be cryptographicly signed\n")); + DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n")); } else { DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n")); } @@ -552,25 +570,39 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, return NT_STATUS_MORE_PROCESSING_REQUIRED; } else if (gss_oid_equal(gensec_gssapi_state->gss_oid, gss_mech_krb5)) { switch (min_stat) { + case KRB5KRB_AP_ERR_TKT_NYV: + DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n", + gensec_gssapi_state->target_principal, + gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); + return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */ + case KRB5KRB_AP_ERR_TKT_EXPIRED: + DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n", + gensec_gssapi_state->target_principal, + gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); + 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: %s\n", + DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticetk to %s: %s\n", + gensec_gssapi_state->target_principal, gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); - return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ + return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */ case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: - DEBUG(3, ("Server is not registered with our KDC: %s\n", + DEBUG(3, ("Server %s is not registered with our KDC: %s\n", + gensec_gssapi_state->target_principal, gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ case KRB5KRB_AP_ERR_MSG_TYPE: /* garbage input, possibly from the auto-mech detection */ return NT_STATUS_INVALID_PARAMETER; default: - DEBUG(1, ("GSS Update(krb5)(%d) Update failed: %s\n", + DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n", + gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server", gensec_gssapi_state->gss_exchange_count, gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); return nt_status; } } else { - DEBUG(1, ("GSS Update(%d) failed: %s\n", + DEBUG(1, ("GSS %s Update(%d) failed: %s\n", + gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server", gensec_gssapi_state->gss_exchange_count, gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid))); return nt_status; @@ -624,18 +656,21 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), gensec_gssapi_state->max_wrap_buf_size); gensec_gssapi_state->sasl_protection = 0; - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - if (security_supported & NEG_SEAL) { + if (security_supported & NEG_SEAL) { + if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { gensec_gssapi_state->sasl_protection |= NEG_SEAL; } - } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - if (security_supported & NEG_SIGN) { + } + if (security_supported & NEG_SIGN) { + if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { gensec_gssapi_state->sasl_protection |= NEG_SIGN; } - } else if (security_supported & NEG_NONE) { + } + if (security_supported & NEG_NONE) { gensec_gssapi_state->sasl_protection |= NEG_NONE; - } else { - DEBUG(1, ("Remote server does not support unprotected connections")); + } + if (gensec_gssapi_state->sasl_protection == 0) { + DEBUG(1, ("Remote server does not support unprotected connections\n")); return NT_STATUS_ACCESS_DENIED; } @@ -668,11 +703,11 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, gensec_gssapi_state->sasl_state = STAGE_DONE; if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly sealed\n")); + DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n")); } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly signed\n")); + DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n")); } else { - DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographicly protection\n")); + DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n")); } return NT_STATUS_OK; @@ -769,33 +804,36 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, /* first byte is the proposed security */ security_accepted = maxlength_accepted[0]; maxlength_accepted[0] = '\0'; - + /* Rest is the proposed max wrap length */ gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), gensec_gssapi_state->max_wrap_buf_size); gensec_gssapi_state->sasl_protection = 0; - if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - if (security_accepted & NEG_SEAL) { - gensec_gssapi_state->sasl_protection |= NEG_SEAL; + if (security_accepted & NEG_SEAL) { + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { + DEBUG(1, ("Remote client wanted seal, but gensec refused\n")); + return NT_STATUS_ACCESS_DENIED; } - } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - if (security_accepted & NEG_SIGN) { - gensec_gssapi_state->sasl_protection |= NEG_SIGN; + gensec_gssapi_state->sasl_protection |= NEG_SEAL; + } + if (security_accepted & NEG_SIGN) { + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(1, ("Remote client wanted sign, but gensec refused\n")); + return NT_STATUS_ACCESS_DENIED; } - } else if (security_accepted & NEG_NONE) { + gensec_gssapi_state->sasl_protection |= NEG_SIGN; + } + if (security_accepted & NEG_NONE) { gensec_gssapi_state->sasl_protection |= NEG_NONE; - } else { - DEBUG(1, ("Remote client does not support unprotected connections, but we failed to negotiate anything better")); - return NT_STATUS_ACCESS_DENIED; } /* quirk: This changes the value that gensec_have_feature returns, to be that after SASL negotiation */ gensec_gssapi_state->sasl_state = STAGE_DONE; if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { - DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly sealed\n")); + DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n")); } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { - DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly signed\n")); + DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n")); } else { DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n")); } @@ -1308,6 +1346,7 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi nt_status = gensec_security->auth_context->get_server_info_principal(mem_ctx, gensec_security->auth_context, principal_string, + NULL, &server_info); if (!NT_STATUS_IS_OK(nt_status)) { @@ -1354,8 +1393,7 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi cli_credentials_set_anonymous(session_info->credentials); ret = cli_credentials_set_client_gss_creds(session_info->credentials, - gensec_security->event_ctx, - gensec_security->settings->lp_ctx, + gensec_security->settings->lp_ctx, gensec_gssapi_state->delegated_cred_handle, CRED_SPECIFIED, &error_string); if (ret) {