From 5c6dd5e800b879efdce3bbc3a16f32c5e78b4917 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 15 May 2005 23:42:11 +0000 Subject: r6800: A big GENSEC update: Finally remove the distinction between 'krb5' and 'ms_krb5'. We now don't do kerberos stuff twice on failure. The solution to this is slightly more general than perhaps was really required (as this is a special case), but it works, and I'm happy with the cleanup I achived in the process. All modules have been updated to supply a NULL-terminated list of OIDs. In that process, SPNEGO code has been generalised, as I realised that two of the functions should have been identical in behaviour. Over in the actual modules, I have worked to remove the 'kinit' code from gensec_krb5, and placed it in kerberos/kerberos_util.c. The GSSAPI module has been extended to use this, so no longer requires a manual kinit at the command line. It will soon loose the requirement for a on-disk keytab too. The general kerberos code has also been updated to move from error_message() to our routine which gets the Heimdal error string (which may be much more useful) when available. Andrew Bartlett (This used to be commit 0101728d8e2ed9419eb31fe95047944a718ba135) --- source4/auth/gensec/gensec_krb5.c | 131 ++++++++++++-------------------------- 1 file changed, 42 insertions(+), 89 deletions(-) (limited to 'source4/auth/gensec/gensec_krb5.c') diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index c850d93fce..9e2d113cb8 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -53,9 +53,9 @@ struct gensec_krb5_state { #ifdef KRB5_DO_VERIFY_PAC static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - struct gensec_krb5_state *gensec_krb5_state, - uint32 keyusage) + struct PAC_SIGNATURE_DATA *sig, + struct gensec_krb5_state *gensec_krb5_state, + uint32 keyusage) { krb5_error_code ret; krb5_crypto crypto; @@ -222,7 +222,9 @@ static NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx, return status; } #endif - DEBUG(0,("account_name: %s [%s]\n",logon_info->info3.base.account_name.string, logon_info->info3.base.full_name.string)); + DEBUG(0,("account_name: %s [%s]\n", + logon_info->info3.base.account_name.string, + logon_info->info3.base.full_name.string)); *logon_info_out = logon_info; return status; @@ -233,12 +235,10 @@ static int gensec_krb5_destory(void *ptr) struct gensec_krb5_state *gensec_krb5_state = ptr; if (gensec_krb5_state->ticket.length) { - kerberos_free_data_contents(gensec_krb5_state->context, &gensec_krb5_state->ticket); - } - if (gensec_krb5_state->ccache) { - /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */ - krb5_cc_close(gensec_krb5_state->context, gensec_krb5_state->ccache); + kerberos_free_data_contents(gensec_krb5_state->context, + &gensec_krb5_state->ticket); } + /* ccache freed in a child destructor */ krb5_free_keyblock_contents(gensec_krb5_state->context, &gensec_krb5_state->keyblock); @@ -279,7 +279,9 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) ret = krb5_init_context(&gensec_krb5_state->context); if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", error_message(ret))); + DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", + smb_get_krb5_error_message(gensec_krb5_state->context, + ret, gensec_krb5_state))); return NT_STATUS_INTERNAL_ERROR; } @@ -291,14 +293,18 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) } ret = krb5_set_default_realm(gensec_krb5_state->context, upper_realm); if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_set_default_realm failed (%s)\n", error_message(ret))); + DEBUG(1,("gensec_krb5_start: krb5_set_default_realm failed (%s)\n", + smb_get_krb5_error_message(gensec_krb5_state->context, + ret, gensec_krb5_state))); return NT_STATUS_INTERNAL_ERROR; } } ret = krb5_auth_con_init(gensec_krb5_state->context, &gensec_krb5_state->auth_context); if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", error_message(ret))); + DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", + smb_get_krb5_error_message(gensec_krb5_state->context, + ret, gensec_krb5_state))); return NT_STATUS_INTERNAL_ERROR; } @@ -326,6 +332,8 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security struct gensec_krb5_state *gensec_krb5_state; krb5_error_code ret; NTSTATUS nt_status; + const char *ccache_name; + const char *hostname = gensec_get_target_hostname(gensec_security); if (!hostname) { DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); @@ -347,7 +355,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security ret = krb5_cc_default(gensec_krb5_state->context, &gensec_krb5_state->ccache); if (ret) { DEBUG(1,("krb5_cc_default failed (%s)\n", - error_message(ret))); + smb_get_krb5_error_message(gensec_krb5_state->context, ret, gensec_krb5_state))); return NT_STATUS_INTERNAL_ERROR; } @@ -370,7 +378,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security return NT_STATUS_OK; case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", - hostname, error_message(ret))); + hostname, smb_get_krb5_error_message(gensec_krb5_state->context, ret, gensec_krb5_state))); return NT_STATUS_ACCESS_DENIED; case KRB5KDC_ERR_PREAUTH_FAILED: case KRB5KRB_AP_ERR_TKT_EXPIRED: @@ -380,7 +388,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security case KRB5_KDCREP_SKEW: { DEBUG(3, ("kerberos (mk_req) failed: %s\n", - error_message(ret))); + smb_get_krb5_error_message(gensec_krb5_state->context, ret, gensec_krb5_state))); /* fall down to remaining code */ } @@ -390,59 +398,20 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security case KRB5_CC_NOTFOUND: case ENOENT: - { - const char *password; - char *ccache_string; - time_t kdc_time = 0; - password = cli_credentials_get_password(gensec_security->credentials); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - /* this string should be unique */ - ccache_string = talloc_asprintf(gensec_krb5_state, "MEMORY:%s:%s:%s", - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - gensec_get_target_hostname(gensec_security), - generate_random_str(gensec_krb5_state, 16)); - - ret = krb5_cc_resolve(gensec_krb5_state->context, ccache_string, &gensec_krb5_state->ccache); - if (ret) { - DEBUG(1,("failed to generate a new krb5 keytab (%s): %s\n", - ccache_string, - error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - - ret = kerberos_kinit_password_cc(gensec_krb5_state->context, gensec_krb5_state->ccache, - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - password, NULL, &kdc_time); - - /* cope with ticket being in the future due to clock skew */ - if ((unsigned)kdc_time > time(NULL)) { - time_t t = time(NULL); - int time_offset =(unsigned)kdc_time-t; - DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); - krb5_set_real_time(gensec_krb5_state->context, t + time_offset + 1, 0); - break; - } - - if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { - DEBUG(1,("kinit for %s failed (%s)\n", - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - error_message(ret))); - return NT_STATUS_TIME_DIFFERENCE_AT_DC; - } - if (ret) { - DEBUG(1,("kinit for %s failed (%s)\n", - cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state), - error_message(ret))); - return NT_STATUS_WRONG_PASSWORD; - } - break; + nt_status = kinit_to_ccache(gensec_krb5_state, + gensec_security->credentials, + gensec_krb5_state->context, + &gensec_krb5_state->ccache, + &ccache_name); + + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; } + break; + default: DEBUG(0, ("kerberos: %s\n", - error_message(ret))); + smb_get_krb5_error_message(gensec_krb5_state->context, ret, gensec_krb5_state))); return NT_STATUS_UNSUCCESSFUL; } } @@ -474,7 +443,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, { if (ret) { DEBUG(1,("ads_krb5_mk_req (request ticket) failed (%s)\n", - error_message(ret))); + smb_get_krb5_error_message(gensec_krb5_state->context, ret, out_mem_ctx))); nt_status = NT_STATUS_LOGON_FAILURE; } else { DATA_BLOB unwrapped_out; @@ -515,7 +484,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, &inbuf, &repl); if (ret) { DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n", - error_message(ret))); + smb_get_krb5_error_message(gensec_krb5_state->context, ret, out_mem_ctx))); dump_data_pw("Mutual authentication message:\n", inbuf.data, inbuf.length); nt_status = NT_STATUS_ACCESS_DENIED; } else { @@ -707,24 +676,16 @@ static BOOL gensec_krb5_have_feature(struct gensec_security *gensec_security, return False; } +static const char *gensec_krb5_oids[] = { + GENSEC_OID_KERBEROS5, + GENSEC_OID_KERBEROS5_OLD, + NULL +}; static const struct gensec_security_ops gensec_krb5_security_ops = { .name = "krb5", .auth_type = DCERPC_AUTH_TYPE_KRB5, - .oid = GENSEC_OID_KERBEROS5, - .client_start = gensec_krb5_client_start, - .server_start = gensec_krb5_server_start, - .update = gensec_krb5_update, - .session_key = gensec_krb5_session_key, - .session_info = gensec_krb5_session_info, - .have_feature = gensec_krb5_have_feature, - .enabled = False -}; - -static const struct gensec_security_ops gensec_ms_krb5_security_ops = { - .name = "ms_krb5", - .auth_type = DCERPC_AUTH_TYPE_KRB5, - .oid = GENSEC_OID_KERBEROS5_OLD, + .oid = gensec_krb5_oids, .client_start = gensec_krb5_client_start, .server_start = gensec_krb5_server_start, .update = gensec_krb5_update, @@ -734,7 +695,6 @@ static const struct gensec_security_ops gensec_ms_krb5_security_ops = { .enabled = False }; - NTSTATUS gensec_krb5_init(void) { NTSTATUS ret; @@ -746,12 +706,5 @@ NTSTATUS gensec_krb5_init(void) return ret; } - ret = gensec_register(&gensec_ms_krb5_security_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register '%s' gensec backend!\n", - gensec_krb5_security_ops.name)); - return ret; - } - return ret; } -- cgit