summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/auth/gensec/gensec_gssapi.c114
-rw-r--r--source4/auth/gensec/gensec_krb5.c134
-rw-r--r--source4/auth/kerberos/clikrb5.c10
-rw-r--r--source4/auth/kerberos/kerberos.h49
-rw-r--r--source4/auth/kerberos/kerberos_pac.c96
-rw-r--r--source4/auth/kerberos/kerberos_verify.c216
-rw-r--r--source4/heimdal/kdc/kerberos5.c31
-rw-r--r--source4/heimdal/lib/gssapi/accept_sec_context.c667
-rw-r--r--source4/heimdal/lib/gssapi/copy_ccache.c19
-rw-r--r--source4/heimdal/lib/gssapi/gssapi.h4
-rw-r--r--source4/heimdal/lib/gssapi/init_sec_context.c18
-rw-r--r--source4/heimdal/lib/krb5/krb5-protos.h13
-rw-r--r--source4/heimdal/lib/krb5/rd_rep.c146
-rw-r--r--source4/heimdal/lib/krb5/rd_req.c20
-rw-r--r--source4/heimdal/lib/roken/roken-common.h31
-rw-r--r--source4/kdc/pac-glue.c11
-rw-r--r--source4/torture/auth/pac.c143
17 files changed, 961 insertions, 761 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 6316b52bad..c3f7c52085 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -118,7 +118,7 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
/* TODO: Fill in channel bindings */
gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
- gensec_gssapi_state->want_flags = 0;
+ gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG;
gensec_gssapi_state->got_flags = 0;
gensec_gssapi_state->session_key = data_blob(NULL, 0);
@@ -388,12 +388,15 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security,
}
- *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
- gss_release_buffer(&min_stat2, &output_token);
-
if (maj_stat == GSS_S_COMPLETE) {
+ *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
+ gss_release_buffer(&min_stat2, &output_token);
+
return NT_STATUS_OK;
} else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+ *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
+ gss_release_buffer(&min_stat2, &output_token);
+
return NT_STATUS_MORE_PROCESSING_REQUIRED;
} else {
if (maj_stat == GSS_S_FAILURE
@@ -427,12 +430,12 @@ static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security,
&conf_state,
&output_token);
if (GSS_ERROR(maj_stat)) {
- DEBUG(1, ("GSS Wrap failed: %s\n",
+ DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n",
gssapi_error_string(mem_ctx, maj_stat, min_stat)));
return NT_STATUS_ACCESS_DENIED;
}
- *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
+ *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
gss_release_buffer(&min_stat, &output_token);
if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
@@ -462,12 +465,12 @@ static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security,
&conf_state,
&qop_state);
if (GSS_ERROR(maj_stat)) {
- DEBUG(1, ("GSS UnWrap failed: %s\n",
+ DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n",
gssapi_error_string(mem_ctx, maj_stat, min_stat)));
return NT_STATUS_ACCESS_DENIED;
}
- *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
+ *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
gss_release_buffer(&min_stat, &output_token);
if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
@@ -506,7 +509,7 @@ static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_securit
&conf_state,
&output_token);
if (GSS_ERROR(maj_stat)) {
- DEBUG(1, ("GSS Wrap failed: %s\n",
+ DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n",
gssapi_error_string(mem_ctx, maj_stat, min_stat)));
return NT_STATUS_ACCESS_DENIED;
}
@@ -546,7 +549,7 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur
gss_qop_t qop_state;
DATA_BLOB in;
- dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
+ dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
@@ -563,7 +566,7 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur
&conf_state,
&qop_state);
if (GSS_ERROR(maj_stat)) {
- DEBUG(1, ("GSS UnWrap failed: %s\n",
+ DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n",
gssapi_error_string(mem_ctx, maj_stat, min_stat)));
return NT_STATUS_ACCESS_DENIED;
}
@@ -688,7 +691,7 @@ static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security,
}
}
if (feature & GENSEC_FEATURE_DCE_STYLE) {
- return True;
+ return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
}
if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
return True;
@@ -744,15 +747,21 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info = NULL;
struct PAC_LOGON_INFO *logon_info;
- char *p;
- char *principal;
- const char *account_name;
- const char *realm;
OM_uint32 maj_stat, min_stat;
gss_buffer_desc name_token;
gss_buffer_desc pac;
krb5_keyblock *keyblock;
+ time_t authtime;
+ krb5_principal principal;
+ char *principal_string;
+ if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
+ || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements,
+ gensec_gssapi_state->gss_oid->length) != 0)) {
+ DEBUG(1, ("NO session info available for this mech\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context");
NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
@@ -764,49 +773,56 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
return NT_STATUS_FOOBAR;
}
- principal = talloc_strndup(mem_ctx, name_token.value, name_token.length);
+ principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
gss_release_buffer(&min_stat, &name_token);
- if (!principal) {
+ if (!principal_string) {
talloc_free(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
- p = strchr(principal, '@');
- if (p) {
- *p = '\0';
- p++;
- realm = p;
- } else {
- realm = lp_realm();
- }
- account_name = principal;
-
maj_stat = gss_krb5_copy_service_keyblock(&min_stat,
gensec_gssapi_state->gssapi_context,
&keyblock);
- maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
- gensec_gssapi_state->gssapi_context,
- KRB5_AUTHDATA_IF_RELEVANT,
- &pac);
+ if (maj_stat == 0) {
+ maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
+ gensec_gssapi_state->gssapi_context,
+ &authtime);
+ }
+
+ if (maj_stat == 0) {
+ maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
+ gensec_gssapi_state->gssapi_context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ &pac);
+ }
if (maj_stat == 0) {
+ krb5_error_code ret;
DATA_BLOB pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
pac_blob = unwrap_pac(mem_ctx, &pac_blob);
gss_release_buffer(&min_stat, &pac);
+
+ ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
+ principal_string, &principal);
+ if (ret) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
/* decode and verify the pac */
nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
gensec_gssapi_state->smb_krb5_context->krb5_context,
- NULL, keyblock);
+ NULL, keyblock, principal, authtime);
+ krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
if (NT_STATUS_IS_OK(nt_status)) {
union netr_Validation validation;
validation.sam3 = &logon_info->info3;
nt_status = make_server_info_netlogon_validation(gensec_gssapi_state,
- account_name,
+ NULL,
3, &validation,
&server_info);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -819,6 +835,9 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
}
if (maj_stat) {
+ krb5_error_code ret;
+ DATA_BLOB user_sess_key = data_blob(NULL, 0);
+ DATA_BLOB lm_sess_key = data_blob(NULL, 0);
/* IF we have the PAC - otherwise we need to get this
* data from elsewere - local ldb, or (TODO) lookup of some
* kind...
@@ -827,12 +846,32 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
* no PAC present
*/
- DATA_BLOB user_sess_key = data_blob(NULL, 0);
- DATA_BLOB lm_sess_key = data_blob(NULL, 0);
- /* TODO: should we pass the krb5 session key in here? */
+ char *account_name;
+ const char *realm;
+ ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
+ principal_string, &principal);
+ if (ret) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ realm = krb5_principal_get_realm(gensec_gssapi_state->smb_krb5_context->krb5_context,
+ principal);
+ ret = krb5_unparse_name_norealm(gensec_gssapi_state->smb_krb5_context->krb5_context,
+ principal, &account_name);
+ if (ret) {
+ krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
+ talloc_free(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
nt_status = sam_get_server_info(mem_ctx, account_name, realm,
user_sess_key, lm_sess_key,
&server_info);
+ free(account_name);
+ krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
+
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return nt_status;
@@ -841,6 +880,7 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
/* references the server_info into the session_info */
nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
+ talloc_free(mem_ctx);
talloc_free(server_info);
NT_STATUS_NOT_OK_RETURN(nt_status);
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index 09722af10b..d4147496fd 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -45,19 +45,25 @@ struct gensec_krb5_state {
enum GENSEC_KRB5_STATE state_position;
struct smb_krb5_context *smb_krb5_context;
krb5_auth_context auth_context;
- krb5_data ticket;
+ krb5_data enc_ticket;
krb5_keyblock *keyblock;
- char *peer_principal;
+ krb5_ticket *ticket;
};
static int gensec_krb5_destory(void *ptr)
{
struct gensec_krb5_state *gensec_krb5_state = ptr;
- if (gensec_krb5_state->ticket.length) {
+ if (gensec_krb5_state->enc_ticket.length) {
kerberos_free_data_contents(gensec_krb5_state->smb_krb5_context->krb5_context,
- &gensec_krb5_state->ticket);
+ &gensec_krb5_state->enc_ticket);
}
+
+ if (gensec_krb5_state->ticket) {
+ krb5_free_ticket(gensec_krb5_state->smb_krb5_context->krb5_context,
+ gensec_krb5_state->ticket);
+ }
+
/* ccache freed in a child destructor */
krb5_free_keyblock(gensec_krb5_state->smb_krb5_context->krb5_context,
@@ -83,8 +89,9 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
gensec_security->private_data = gensec_krb5_state;
gensec_krb5_state->auth_context = NULL;
- ZERO_STRUCT(gensec_krb5_state->ticket);
- ZERO_STRUCT(gensec_krb5_state->keyblock);
+ gensec_krb5_state->ticket = NULL;
+ ZERO_STRUCT(gensec_krb5_state->enc_ticket);
+ gensec_krb5_state->keyblock = NULL;
gensec_krb5_state->session_key = data_blob(NULL, 0);
gensec_krb5_state->pac = data_blob(NULL, 0);
@@ -114,6 +121,14 @@ static NTSTATUS gensec_krb5_server_start(struct gensec_security *gensec_security
return NT_STATUS_INTERNAL_ERROR;
}
+ ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context);
+ if (ret) {
+ DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n",
+ smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context,
+ ret, gensec_krb5_state)));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
gensec_krb5_state = gensec_security->private_data;
gensec_krb5_state->state_position = GENSEC_KRB5_SERVER_START;
@@ -173,7 +188,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
gensec_get_target_service(gensec_security),
hostname,
&in_data, ccache_container->ccache,
- &gensec_krb5_state->ticket);
+ &gensec_krb5_state->enc_ticket);
}
switch (ret) {
@@ -249,31 +264,23 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
{
struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
krb5_error_code ret = 0;
- DATA_BLOB pac;
NTSTATUS nt_status;
switch (gensec_krb5_state->state_position) {
case GENSEC_KRB5_CLIENT_START:
{
- if (ret) {
- DEBUG(1,("ads_krb5_mk_req (request ticket) failed (%s)\n",
- smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, out_mem_ctx)));
- nt_status = NT_STATUS_LOGON_FAILURE;
- } else {
- DATA_BLOB unwrapped_out;
-
+ DATA_BLOB unwrapped_out;
+
#ifndef GENSEC_SEND_UNWRAPPED_KRB5 /* This should be a switch for the torture code to set */
- unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length);
-
- /* wrap that up in a nice GSS-API wrapping */
- *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ);
+ unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
+
+ /* wrap that up in a nice GSS-API wrapping */
+ *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ);
#else
- *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length);
+ *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length);
#endif
- gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH;
- nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
- }
-
+ gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH;
+ nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
return nt_status;
}
@@ -314,7 +321,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
case GENSEC_KRB5_SERVER_START:
{
- char *principal;
DATA_BLOB unwrapped_in;
DATA_BLOB unwrapped_out = data_blob(NULL, 0);
uint8_t tok_id[2];
@@ -328,20 +334,20 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
nt_status = ads_verify_ticket(out_mem_ctx,
gensec_krb5_state->smb_krb5_context,
- gensec_krb5_state->auth_context,
+ &gensec_krb5_state->auth_context,
lp_realm(),
gensec_get_target_service(gensec_security), &in,
- &principal, &pac, &unwrapped_out,
+ &gensec_krb5_state->ticket, &unwrapped_out,
&gensec_krb5_state->keyblock);
} else {
/* TODO: check the tok_id */
nt_status = ads_verify_ticket(out_mem_ctx,
gensec_krb5_state->smb_krb5_context,
- gensec_krb5_state->auth_context,
+ &gensec_krb5_state->auth_context,
lp_realm(),
gensec_get_target_service(gensec_security),
&unwrapped_in,
- &principal, &pac, &unwrapped_out,
+ &gensec_krb5_state->ticket, &unwrapped_out,
&gensec_krb5_state->keyblock);
}
@@ -349,10 +355,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
return nt_status;
}
- if (pac.data) {
- gensec_krb5_state->pac = data_blob_talloc_reference(gensec_krb5_state, &pac);
- }
-
if (NT_STATUS_IS_OK(nt_status)) {
gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
/* wrap that up in a nice GSS-API wrapping */
@@ -361,7 +363,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
#else
*out = unwrapped_out;
#endif
- gensec_krb5_state->peer_principal = talloc_steal(gensec_krb5_state, principal);
}
return nt_status;
}
@@ -418,28 +419,29 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info = NULL;
struct PAC_LOGON_INFO *logon_info;
- char *p;
- char *principal;
- const char *account_name;
- const char *realm;
-
- principal = talloc_strdup(gensec_krb5_state, gensec_krb5_state->peer_principal);
- NT_STATUS_HAVE_NO_MEMORY(principal);
-
- p = strchr(principal, '@');
- if (p) {
- *p = '\0';
- p++;
- realm = p;
- } else {
- realm = lp_realm();
+
+ krb5_const_principal client_principal;
+
+ DATA_BLOB pac_wrapped;
+ DATA_BLOB pac;
+
+ TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
}
- account_name = principal;
+
+ pac_wrapped = get_auth_data_from_tkt(mem_ctx, gensec_krb5_state->ticket);
+
+ pac = unwrap_pac(mem_ctx, &pac_wrapped);
+
+ client_principal = get_principal_from_tkt(gensec_krb5_state->ticket);
/* decode and verify the pac */
- nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, gensec_krb5_state->pac,
+ nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, pac,
gensec_krb5_state->smb_krb5_context->krb5_context,
- NULL, gensec_krb5_state->keyblock);
+ NULL, gensec_krb5_state->keyblock,
+ client_principal,
+ gensec_krb5_state->ticket->ticket.authtime);
/* IF we have the PAC - otherwise we need to get this
* data from elsewere - local ldb, or (TODO) lookup of some
@@ -453,25 +455,41 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
union netr_Validation validation;
validation.sam3 = &logon_info->info3;
nt_status = make_server_info_netlogon_validation(gensec_krb5_state,
- account_name,
+ NULL,
3, &validation,
&server_info);
- talloc_free(principal);
+ talloc_free(mem_ctx);
NT_STATUS_NOT_OK_RETURN(nt_status);
} else {
+ krb5_error_code ret;
DATA_BLOB user_sess_key = data_blob(NULL, 0);
DATA_BLOB lm_sess_key = data_blob(NULL, 0);
+
+ char *account_name;
+ const char *realm = krb5_principal_get_realm(gensec_krb5_state->smb_krb5_context->krb5_context,
+ get_principal_from_tkt(gensec_krb5_state->ticket));
+ ret = krb5_unparse_name_norealm(gensec_krb5_state->smb_krb5_context->krb5_context,
+ get_principal_from_tkt(gensec_krb5_state->ticket), &account_name);
+ if (ret) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
/* TODO: should we pass the krb5 session key in here? */
- nt_status = sam_get_server_info(gensec_krb5_state, account_name, realm,
+ nt_status = sam_get_server_info(mem_ctx, account_name, realm,
user_sess_key, lm_sess_key,
&server_info);
- talloc_free(principal);
- NT_STATUS_NOT_OK_RETURN(nt_status);
+ free(account_name);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(mem_ctx);
+ return nt_status;
+ }
}
/* references the server_info into the session_info */
nt_status = auth_generate_session_info(gensec_krb5_state, server_info, &session_info);
- talloc_free(server_info);
+ talloc_free(mem_ctx);
+
NT_STATUS_NOT_OK_RETURN(nt_status);
nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key);
diff --git a/source4/auth/kerberos/clikrb5.c b/source4/auth/kerberos/clikrb5.c
index 40c1e254f8..e3f2057b44 100644
--- a/source4/auth/kerberos/clikrb5.c
+++ b/source4/auth/kerberos/clikrb5.c
@@ -375,11 +375,13 @@ cleanup_princ:
#if defined(HAVE_KRB5_GET_ERROR_STRING) && defined(HAVE_KRB5_FREE_ERROR_STRING)
char *context_error = krb5_get_error_string(context);
- ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error);
- krb5_free_error_string(context, context_error);
-#else
- ret = talloc_strdup(mem_ctx, error_message(code));
+ if (context_error) {
+ ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error);
+ krb5_free_error_string(context, context_error);
+ return ret;
+ }
#endif
+ ret = talloc_strdup(mem_ctx, error_message(code));
return ret;
}
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index 39bba5f46f..9535094e2b 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -92,13 +92,12 @@ krb5_error_code ads_krb5_mk_req(krb5_context context,
krb5_data *outbuf);
DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx,
krb5_ticket *tkt);
-
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
struct smb_krb5_context *smb_krb5_context,
- krb5_auth_context auth_context,
+ krb5_auth_context *auth_context,
const char *realm, const char *service,
- const DATA_BLOB *ticket,
- char **principal, DATA_BLOB *auth_data,
+ const DATA_BLOB *enc_ticket,
+ krb5_ticket **tkt,
DATA_BLOB *ap_rep,
krb5_keyblock **keyblock);
int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc,
@@ -125,6 +124,10 @@ krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx,
struct cli_credentials *machine_account,
struct smb_krb5_context *smb_krb5_context,
krb5_principal *salt_princ);
+krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
+ struct cli_credentials *credentials,
+ struct smb_krb5_context *smb_krb5_context,
+ krb5_principal *princ);
NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx,
struct cli_credentials *machine_account,
struct smb_krb5_context *smb_krb5_context,
@@ -134,26 +137,30 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
DATA_BLOB blob,
krb5_context context,
krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *service_keyblock);
-NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx,
- struct PAC_LOGON_INFO **logon_info,
- DATA_BLOB blob,
- krb5_context context,
- krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *service_keyblock);
-krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx,
- struct auth_serversupplied_info *server_info,
- krb5_context context,
- krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *server_keyblock,
- time_t tgs_authtime,
- DATA_BLOB *pac);
-
-krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
+ krb5_keyblock *service_keyblock,
+ krb5_const_principal client_principal,
+ time_t tgs_authtime);
+ NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx,
+ struct PAC_LOGON_INFO **logon_info,
+ DATA_BLOB blob,
+ krb5_context context,
+ krb5_keyblock *krbtgt_keyblock,
+ krb5_keyblock *service_keyblock,
+ krb5_const_principal client_principal,
+ time_t tgs_authtime);
+ krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx,
struct PAC_DATA *pac_data,
krb5_context context,
krb5_keyblock *krbtgt_keyblock,
krb5_keyblock *service_keyblock,
- DATA_BLOB *pac);
+ DATA_BLOB *pac) ;
+ krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx,
+ struct auth_serversupplied_info *server_info,
+ krb5_context context,
+ krb5_keyblock *krbtgt_keyblock,
+ krb5_keyblock *service_keyblock,
+ krb5_principal client_principal,
+ time_t tgs_authtime,
+ DATA_BLOB *pac);
#endif /* HAVE_KRB5 */
diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c
index b26a25eac1..3294699070 100644
--- a/source4/auth/kerberos/kerberos_pac.c
+++ b/source4/auth/kerberos/kerberos_pac.c
@@ -33,11 +33,11 @@
#include "librpc/gen_ndr/ndr_krb5pac.h"
#include "auth/auth.h"
-static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
- DATA_BLOB pac_data,
- struct PAC_SIGNATURE_DATA *sig,
- krb5_context context,
- krb5_keyblock *keyblock)
+static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx,
+ DATA_BLOB pac_data,
+ struct PAC_SIGNATURE_DATA *sig,
+ krb5_context context,
+ krb5_keyblock *keyblock)
{
krb5_error_code ret;
krb5_crypto crypto;
@@ -55,7 +55,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
if (ret) {
DEBUG(0,("krb5_crypto_init() failed: %s\n",
smb_get_krb5_error_message(context, ret, mem_ctx)));
- return NT_STATUS_FOOBAR;
+ return ret;
}
ret = krb5_verify_checksum(context,
crypto,
@@ -63,18 +63,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
pac_data.data,
pac_data.length,
&cksum);
- if (ret) {
- DEBUG(2, ("PAC Verification failed: %s\n",
- smb_get_krb5_error_message(context, ret, mem_ctx)));
- }
-
krb5_crypto_destroy(context, crypto);
- if (ret) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- return NT_STATUS_OK;
+ return ret;
}
NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
@@ -82,17 +73,23 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
DATA_BLOB blob,
krb5_context context,
krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *service_keyblock)
+ krb5_keyblock *service_keyblock,
+ krb5_const_principal client_principal,
+ time_t tgs_authtime)
{
+ krb5_error_code ret;
NTSTATUS status;
struct PAC_SIGNATURE_DATA srv_sig;
struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL;
struct PAC_SIGNATURE_DATA kdc_sig;
struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL;
struct PAC_LOGON_INFO *logon_info = NULL;
+ struct PAC_LOGON_NAME *logon_name = NULL;
struct PAC_DATA *pac_data;
DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length);
+ NTTIME tgs_authtime_nttime;
+ krb5_principal client_principal_pac;
int i;
pac_data = talloc(mem_ctx, struct PAC_DATA);
@@ -136,6 +133,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
kdc_sig = pac_data->buffers[i].info->kdc_cksum;
break;
case PAC_TYPE_LOGON_NAME:
+ logon_name = &pac_data->buffers[i].info->logon_name;
break;
default:
break;
@@ -163,28 +161,54 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
'\0', 16);
/* verify by service_key */
- status = check_pac_checksum(mem_ctx,
+ ret = check_pac_checksum(mem_ctx,
modified_pac_blob, &srv_sig,
context,
service_keyblock);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("PAC Decode: Failed to verify the service signature\n"));
- return status;
+ if (ret) {
+ DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return NT_STATUS_ACCESS_DENIED;
}
if (krbtgt_keyblock) {
DATA_BLOB service_checksum_blob
= data_blob_const(srv_sig_ptr->signature, sizeof(srv_sig_ptr->signature));
- status = check_pac_checksum(mem_ctx,
+ ret = check_pac_checksum(mem_ctx,
service_checksum_blob, &kdc_sig,
context, krbtgt_keyblock);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("PAC Decode: Failed to verify the krbtgt signature\n"));
- return status;
+ if (ret) {
+ DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n",
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return NT_STATUS_ACCESS_DENIED;
}
}
+ /* Convert to NT time, so as not to loose accuracy in comparison */
+ unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime);
+
+ if (tgs_authtime_nttime != logon_name->logon_time) {
+ DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n"));
+ DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time)));
+ DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ ret = krb5_parse_name_norealm(context, logon_name->account_name, &client_principal_pac);
+ if (ret) {
+ DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n",
+ logon_name->account_name,
+ smb_get_krb5_error_message(context, ret, mem_ctx)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) {
+ DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n",
+ logon_name->account_name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
#if 0
if (strcasecmp(logon_info->info3.base.account_name.string,
"Administrator")== 0) {
@@ -205,7 +229,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
DATA_BLOB blob,
krb5_context context,
krb5_keyblock *krbtgt_keyblock,
- krb5_keyblock *service_keyblock)
+ krb5_keyblock *service_keyblock,
+ krb5_const_principal client_principal,
+ time_t tgs_authtime)
{
NTSTATUS nt_status;
struct PAC_DATA *pac_data;
@@ -215,7 +241,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx,
blob,
context,
krbtgt_keyblock,
- service_keyblock);
+ service_keyblock,
+ client_principal,
+ tgs_authtime);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
@@ -275,6 +303,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
if (cksum.checksum.length == sizeof(sig->signature)) {
memcpy(sig->signature, cksum.checksum.data, sizeof(sig->signature));
}
+ free_Checksum(&cksum);
return 0;
}
@@ -385,6 +414,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
krb5_context context,
krb5_keyblock *krbtgt_keyblock,
krb5_keyblock *service_keyblock,
+ krb5_principal client_principal,
time_t tgs_authtime,
DATA_BLOB *pac)
{
@@ -400,6 +430,8 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
union PAC_INFO *u_KDC_CHECKSUM;
union PAC_INFO *u_SRV_CHECKSUM;
+ char *name;
+
enum {
PAC_BUF_LOGON_INFO = 0,
PAC_BUF_LOGON_NAME = 1,
@@ -478,11 +510,15 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx,
LOGON_INFO->info3 = *sam3;
LOGON_INFO->info3.base.last_logon = timeval_to_nttime(&tv);
- LOGON_NAME->account_name = server_info->account_name;
-
+ ret = krb5_unparse_name_norealm(context, client_principal, &name);
+ if (ret) {
+ return ret;
+ }
+ LOGON_NAME->account_name = talloc_strdup(LOGON_NAME, name);
+ free(name);
/*
this logon_time field is absolutely critical. This is what
- caused all our pac troubles :-)
+ caused all our PAC troubles :-)
*/
unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime);
diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c
index b140eb6ae9..dec084299b 100644
--- a/source4/auth/kerberos/kerberos_verify.c
+++ b/source4/auth/kerberos/kerberos_verify.c
@@ -71,9 +71,10 @@ DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data)
***********************************************************************************/
static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_context context,
- krb5_auth_context auth_context,
+ krb5_auth_context *auth_context,
const char *service,
- const DATA_BLOB *ticket, krb5_data *p_packet,
+ const krb5_data *p_packet,
+ krb5_flags *ap_req_options,
krb5_ticket **pp_tkt,
krb5_keyblock **keyblock)
{
@@ -146,12 +147,10 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
}
number_matched_principals++;
- p_packet->length = ticket->length;
- p_packet->data = (krb5_pointer)ticket->data;
*pp_tkt = NULL;
- ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet,
+ ret = krb5_rd_req_return_keyblock(context, auth_context, p_packet,
kt_entry.principal, keytab,
- NULL, pp_tkt, keyblock);
+ ap_req_options, pp_tkt, keyblock);
if (ret) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n",
@@ -216,121 +215,28 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
}
/**********************************************************************************
- Try to verify a ticket using the secrets.tdb.
-***********************************************************************************/
-
-static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
- struct cli_credentials *machine_account,
- krb5_context context,
- krb5_auth_context auth_context,
- krb5_principal salt_princ,
- const DATA_BLOB *ticket, krb5_data *p_packet,
- krb5_ticket **pp_tkt,
- krb5_keyblock **keyblock)
-{
- krb5_error_code ret = 0;
- krb5_error_code our_ret;
- krb5_data password;
- krb5_enctype *enctypes = NULL;
- int i;
- char *password_s = talloc_strdup(mem_ctx, cli_credentials_get_password(machine_account));
- if (!password_s) {
- DEBUG(1, ("ads_secrets_verify_ticket: Could not obtain password for our local machine account!\n"));
- return ENOENT;
- }
-
- ZERO_STRUCTP(keyblock);
-
- password.data = password_s;
- password.length = strlen(password_s);
-
- /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */
-
- if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) {
- DEBUG(1,("ads_secrets_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n",
- error_message(ret)));
-
- krb5_free_principal(context, salt_princ);
- return ret;
- }
-
- p_packet->length = ticket->length;
- p_packet->data = (krb5_pointer)ticket->data;
-
- /* We need to setup a auth context with each possible encoding type in turn. */
-
- ret = KRB5_BAD_ENCTYPE;
- for (i=0;enctypes[i];i++) {
- krb5_keyblock *key = NULL;
-
- if (!(key = malloc_p(krb5_keyblock))) {
- break;
- }
-
- if (create_kerberos_key_from_string(context, salt_princ, &password, key, enctypes[i])) {
- SAFE_FREE(key);
- continue;
- }
-
- krb5_auth_con_setuseruserkey(context, auth_context, key);
-
- krb5_free_keyblock(context, key);
-
- our_ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet,
- NULL,
- NULL, NULL, pp_tkt,
- keyblock);
- if (!our_ret) {
-
- DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
- (unsigned int)enctypes[i] ));
- ret = our_ret;
- break;
- }
-
- DEBUG((our_ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
- ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
- (unsigned int)enctypes[i], smb_get_krb5_error_message(context, our_ret, mem_ctx)));
-
- if (our_ret != KRB5_BAD_ENCTYPE) {
- ret = our_ret;
- }
- }
-
- free_kerberos_etypes(context, enctypes);
-
- return ret;
-}
-
-/**********************************************************************************
Verify an incoming ticket and parse out the principal name and
authorization_data if available.
***********************************************************************************/
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
struct smb_krb5_context *smb_krb5_context,
- krb5_auth_context auth_context,
+ krb5_auth_context *auth_context,
const char *realm, const char *service,
- const DATA_BLOB *ticket,
- char **principal, DATA_BLOB *auth_data,
+ const DATA_BLOB *enc_ticket,
+ krb5_ticket **tkt,
DATA_BLOB *ap_rep,
krb5_keyblock **keyblock)
{
- NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
+ krb5_keyblock *local_keyblock;
krb5_data packet;
- krb5_ticket *tkt = NULL;
krb5_principal salt_princ;
int ret;
+ krb5_flags ap_req_options = 0;
- char *malloc_principal;
-
- NTSTATUS creds_nt_status;
+ NTSTATUS creds_nt_status, status;
struct cli_credentials *machine_account;
- ZERO_STRUCT(packet);
- ZERO_STRUCTP(auth_data);
- ZERO_STRUCTP(ap_rep);
-
machine_account = cli_credentials_init(mem_ctx);
cli_credentials_set_conf(machine_account);
creds_nt_status = cli_credentials_set_machine_account(machine_account);
@@ -360,78 +266,54 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
* directory. This will eventually prevent replay attacks
*/
+ packet.length = enc_ticket->length;
+ packet.data = (krb5_pointer)enc_ticket->data;
+
ret = ads_keytab_verify_ticket(mem_ctx, smb_krb5_context->krb5_context, auth_context,
- service, ticket, &packet, &tkt, keyblock);
+ service, &packet, &ap_req_options, tkt, &local_keyblock);
if (ret && machine_account) {
- ret = ads_secrets_verify_ticket(mem_ctx, machine_account, smb_krb5_context->krb5_context, auth_context,
- salt_princ, ticket,
- &packet, &tkt, keyblock);
- }
-
- if (ret) {
- goto out;
+ krb5_keytab keytab;
+ krb5_principal server;
+ status = create_memory_keytab(mem_ctx, machine_account, smb_krb5_context,
+ &keytab);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context,
+ &server);
+ if (ret == 0) {
+ ret = krb5_rd_req_return_keyblock(smb_krb5_context->krb5_context, auth_context, &packet,
+ server,
+ keytab, &ap_req_options, tkt,
+ &local_keyblock);
+ }
}
- ret = krb5_mk_rep(smb_krb5_context->krb5_context, auth_context, &packet);
if (ret) {
- DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
+ DEBUG(3,("ads_secrets_verify_ticket: failed to decrypt with error %s\n",
smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
- goto out;
- }
-
- *ap_rep = data_blob_talloc(mem_ctx, packet.data, packet.length);
- SAFE_FREE(packet.data);
- packet.length = 0;
-
-#if 0
- file_save("/tmp/ticket.dat", ticket->data, ticket->length);
-#endif
-
- *auth_data = get_auth_data_from_tkt(mem_ctx, tkt);
-
- *auth_data = unwrap_pac(mem_ctx, auth_data);
-
-#if 0
- if (tkt->enc_part2) {
- file_save("/tmp/authdata.dat",
- tkt->enc_part2->authorization_data[0]->contents,
- tkt->enc_part2->authorization_data[0]->length);
+ return NT_STATUS_LOGON_FAILURE;
}
-#endif
+ *keyblock = local_keyblock;
- if ((ret = krb5_unparse_name(smb_krb5_context->krb5_context, get_principal_from_tkt(tkt),
- &malloc_principal))) {
- DEBUG(3,("ads_verify_ticket: krb5_unparse_name failed (%s)\n",
- smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
- sret = NT_STATUS_LOGON_FAILURE;
- goto out;
- }
-
- *principal = talloc_strdup(mem_ctx, malloc_principal);
- SAFE_FREE(malloc_principal);
- if (!principal) {
- DEBUG(3,("ads_verify_ticket: talloc_strdup() failed\n"));
- sret = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- sret = NT_STATUS_OK;
-
- out:
-
- if (!NT_STATUS_IS_OK(sret)) {
- data_blob_free(auth_data);
- }
-
- if (!NT_STATUS_IS_OK(sret)) {
- data_blob_free(ap_rep);
- }
-
- if (tkt != NULL) {
- krb5_free_ticket(smb_krb5_context->krb5_context, tkt);
+ if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
+ krb5_data packet_out;
+ ret = krb5_mk_rep(smb_krb5_context->krb5_context, *auth_context, &packet_out);
+ if (ret) {
+ krb5_free_ticket(smb_krb5_context->krb5_context, *tkt);
+
+ DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ *ap_rep = data_blob_talloc(mem_ctx, packet_out.data, packet_out.length);
+ krb5_free_data_contents(smb_krb5_context->krb5_context, &packet_out);
+ } else {
+ *ap_rep = data_blob(NULL, 0);
}
- return sret;
+ return NT_STATUS_OK;
}
#endif /* HAVE_KRB5 */
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index 453263774b..38444f4a13 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -208,7 +208,7 @@ log_timestamp(krb5_context context,
strlcpy(renewtime_str, "unset", sizeof(renewtime_str));
kdc_log(context, config, 5,
- "%s authtime: %s starttime: %s endtype: %s renew till: %s",
+ "%s authtime: %s starttime: %s endtime: %s renew till: %s",
type, authtime_str, starttime_str, endtime_str, renewtime_str);
}
@@ -329,8 +329,9 @@ make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key)
{
ent->etype = key->key.keytype;
if(key->salt){
- ALLOC(ent->salttype);
#if 0
+ ALLOC(ent->salttype);
+
if(key->salt->type == hdb_pw_salt)
*ent->salttype = 0; /* or 1? or NULL? */
else if(key->salt->type == hdb_afs3_salt)
@@ -345,8 +346,17 @@ make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key)
*know* what cell you are using (e.g by assuming
that the cell is the same as the realm in lower
case) */
-#else
+#elif 0
+ ALLOC(ent->salttype);
*ent->salttype = key->salt->type;
+#else
+ /*
+ * We shouldn't sent salttype since its incompatible with the
+ * specification and its break windows clients. The afs
+ * salting problem is solved by using KRB5-PADATA-AFS3-SALT
+ * implemented in Heimdal 0.7 and later.
+ */
+ ent->salttype = NULL;
#endif
krb5_copy_data(context, &key->salt->salt,
&ent->salt);
@@ -1508,7 +1518,20 @@ fix_transited_encoding(krb5_context context,
int num_realms;
int i;
- if(tr->tr_type != DOMAIN_X500_COMPRESS) {
+ switch (tr->tr_type) {
+ case DOMAIN_X500_COMPRESS:
+ break;
+ case 0:
+ /*
+ * Allow empty content of type 0 because that is was Microsoft
+ * generates in their TGT.
+ */
+ if (tr->contents.length == 0)
+ break;
+ kdc_log(context, config, 0,
+ "Transited type 0 with non empty content");
+ return KRB5KDC_ERR_TRTYPE_NOSUPP;
+ default:
kdc_log(context, config, 0,
"Unknown transited type: %u", tr->tr_type);
return KRB5KDC_ERR_TRTYPE_NOSUPP;
diff --git a/source4/heimdal/lib/gssapi/accept_sec_context.c b/source4/heimdal/lib/gssapi/accept_sec_context.c
index 2ba2415112..7412d84eb0 100644
--- a/source4/heimdal/lib/gssapi/accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/accept_sec_context.c
@@ -274,215 +274,224 @@ gsskrb5_acceptor_ready(
return GSS_S_COMPLETE;
}
-
static OM_uint32
-gsskrb5_acceptor_start(
- OM_uint32 * minor_status,
- gss_ctx_id_t * context_handle,
- const gss_cred_id_t acceptor_cred_handle,
- const gss_buffer_t input_token,
- const gss_channel_bindings_t input_chan_bindings,
- gss_name_t * src_name,
- gss_OID * mech_type,
- gss_buffer_t output_token,
- OM_uint32 * ret_flags,
- OM_uint32 * time_rec,
- gss_cred_id_t * delegated_cred_handle)
+gsskrb5_acceptor_start
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token_buffer,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle
+ )
{
- krb5_error_code kret;
- OM_uint32 ret = GSS_S_COMPLETE;
- krb5_data indata;
- krb5_flags ap_options;
- OM_uint32 flags;
- krb5_ticket *ticket = NULL;
- krb5_keytab keytab = NULL;
- krb5_keyblock *keyblock = NULL;
- int no_wrap = 0;
-
- /*
- * TODO: check the channel_bindings
- */
-
- /*
- * We need a sequence number
- */
- krb5_auth_con_addflags(gssapi_krb5_context,
- (*context_handle)->auth_context,
- KRB5_AUTH_CONTEXT_DO_SEQUENCE,
- NULL);
-
- /*
- * We need remove the decapsulate only when GSS_C_DCE_STYLE isn't in use
- */
- ret = gssapi_krb5_decapsulate(minor_status,
- input_token,&indata,
- "\x01\x00",
- GSS_KRB5_MECHANISM);
- if (ret) {
- /* No OID wrapping apparently available. */
- no_wrap = 1;
- indata.length = input_token->length;
- indata.data = input_token->value;
- }
+ krb5_error_code kret;
+ OM_uint32 ret = GSS_S_COMPLETE;
+ krb5_data indata;
+ krb5_flags ap_options;
+ OM_uint32 flags;
+ krb5_ticket *ticket = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_keyblock *keyblock = NULL;
+ krb5_data fwd_data;
+ int is_cfx = 0;
+
+ krb5_data_zero (&fwd_data);
+
+ /*
+ * We may, or may not, have an escapsulation.
+ */
+ ret = gssapi_krb5_decapsulate (minor_status,
+ input_token_buffer,
+ &indata,
+ "\x01\x00",
+ GSS_KRB5_MECHANISM);
- /*
- * We need to get our keytab
- */
- if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
- if (gssapi_krb5_keytab != NULL) {
- keytab = gssapi_krb5_keytab;
- }
- } else {
- keytab = acceptor_cred_handle->keytab;
- }
+ if (ret) {
+ /* No OID wrapping apparently available. */
+ indata.length = input_token_buffer->length;
+ indata.data = input_token_buffer->value;
+ }
- /*
- * We need to check the ticket and create the AP-REP packet
- */
- kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
- &(*context_handle)->auth_context,
- &indata,
- (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
- keytab,
- &ap_options,
- &ticket,
- &keyblock);
- if (kret) {
- *minor_status = kret;
- gssapi_krb5_set_error_string ();
- return GSS_S_FAILURE;
+ /*
+ * We need to get our keytab
+ */
+ if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
+ if (gssapi_krb5_keytab != NULL) {
+ keytab = gssapi_krb5_keytab;
}
+ } else if (acceptor_cred_handle->keytab != NULL) {
+ keytab = acceptor_cred_handle->keytab;
+ }
+
+ /*
+ * We need to check the ticket and create the AP-REP packet
+ */
+ kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
+ &(*context_handle)->auth_context,
+ &indata,
+ (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
+ keytab,
+ &ap_options,
+ &ticket,
+ &keyblock);
+ if (kret) {
+ ret = GSS_S_FAILURE;
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return ret;
+ }
+
+ /*
+ * We need to remember some data on the context_handle
+ */
+ (*context_handle)->ticket = ticket;
+ (*context_handle)->service_keyblock = keyblock;
+ (*context_handle)->lifetime = ticket->ticket.endtime;
+
+ /*
+ * We need to copy the principal names to the context and the calling layer
+ */
+ kret = krb5_copy_principal(gssapi_krb5_context,
+ ticket->client,
+ &(*context_handle)->source);
+ if (kret) {
+ ret = GSS_S_FAILURE;
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ }
- /*
- * We need to remember some data on the context_handle
- */
- (*context_handle)->ticket = ticket;
- (*context_handle)->service_keyblock = keyblock;
- (*context_handle)->lifetime = ticket->ticket.endtime;
-
- /*
- * We need to copy the principal names to the context and the calling layer
- */
- kret = krb5_copy_principal(gssapi_krb5_context,
- ticket->client,
- &(*context_handle)->source);
- if (kret) {
- *minor_status = kret;
- gssapi_krb5_set_error_string ();
- return GSS_S_FAILURE;
- }
+ kret = krb5_copy_principal (gssapi_krb5_context,
+ ticket->server,
+ &(*context_handle)->target);
+ if (kret) {
+ ret = GSS_S_FAILURE;
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return ret;
+ }
+
+ /*
+ * We need to setup some compat stuff, this assumes that context_handle->target is already set
+ */
+ ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
+ if (ret) {
+ return ret;
+ }
- kret = krb5_copy_principal(gssapi_krb5_context,
- ticket->server,
- &(*context_handle)->target);
+ if (src_name != NULL) {
+ kret = krb5_copy_principal (gssapi_krb5_context,
+ ticket->client,
+ src_name);
if (kret) {
- *minor_status = kret;
- gssapi_krb5_set_error_string ();
- return GSS_S_FAILURE;
+ ret = GSS_S_FAILURE;
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return ret;
}
+ }
- /*
- * We need to setup some compat stuff, this assumes that context_handle->target is already set
- */
- ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
- if (ret) return ret;
-
- /*
- * We need to get the flags out of the 8003 checksum
- */
- {
- krb5_authenticator authenticator;
-
- kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
+ /*
+ * We need to get the flags out of the 8003 checksum
+ */
+ {
+ krb5_authenticator authenticator;
+
+ kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
(*context_handle)->auth_context,
&authenticator);
- if (kret) {
- *minor_status = kret;
- gssapi_krb5_set_error_string ();
- return GSS_S_FAILURE;
- }
-
- ret = gssapi_krb5_verify_8003_checksum(minor_status,
- input_chan_bindings,
- authenticator->cksum,
- &flags,
- &(*context_handle)->fwd_data);
- krb5_free_authenticator(gssapi_krb5_context, &authenticator);
- if (ret) return ret;
- }
-
- /* And remember them for later */
- (*context_handle)->flags = flags;
-
- if(flags & GSS_C_MUTUAL_FLAG) {
- int is_cfx = 0;
- krb5_data outbuf;
-
- gsskrb5_is_cfx(*context_handle, &is_cfx);
-
- if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
- kret = krb5_auth_con_addflags(gssapi_krb5_context,
- (*context_handle)->auth_context,
- KRB5_AUTH_CONTEXT_USE_SUBKEY,
- NULL);
- (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
- }
-
- kret = krb5_mk_rep(gssapi_krb5_context,
- (*context_handle)->auth_context,
- &outbuf);
- if (kret) {
- *minor_status = kret;
- gssapi_krb5_set_error_string ();
- return GSS_S_FAILURE;
- }
-
- if (!(flags & GSS_C_DCE_STYLE)) {
- ret = gssapi_krb5_encapsulate(minor_status,
- &outbuf,
- output_token,
- "\x02\x00",
- GSS_KRB5_MECHANISM);
- krb5_data_free (&outbuf);
- if (ret) return ret;
- } else {
- output_token->length = outbuf.length;
- output_token->value = outbuf.data;
- }
+ if(kret) {
+ ret = GSS_S_FAILURE;
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return ret;
}
- /*
- * We need to set the return value for the calling layer
- */
- if (ret_flags) *ret_flags = flags;
-
- if (time_rec) {
- ret = gssapi_lifetime_left(minor_status,
- (*context_handle)->lifetime,
- time_rec);
- if (ret) return ret;
- }
+ ret = gssapi_krb5_verify_8003_checksum(minor_status,
+ input_chan_bindings,
+ authenticator->cksum,
+ &flags,
+ &fwd_data);
+ krb5_free_authenticator(gssapi_krb5_context, &authenticator);
+ if (ret)
+ if (ret) return ret;
+ }
+
+ if(flags & GSS_C_MUTUAL_FLAG) {
+ krb5_data outbuf;
+
+ gsskrb5_is_cfx(*context_handle, &is_cfx);
+
+ if (is_cfx != 0
+ || (ap_options & AP_OPTS_USE_SUBKEY)) {
+ kret = krb5_auth_con_addflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_USE_SUBKEY,
+ NULL);
+ (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
+ }
+
+ kret = krb5_mk_rep(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &outbuf);
+ if (kret) {
+ *minor_status = kret;
+ gssapi_krb5_set_error_string ();
+ return GSS_S_FAILURE;
+ }
+
+ if (!(flags & GSS_C_DCE_STYLE)) {
+ ret = gssapi_krb5_encapsulate(minor_status,
+ &outbuf,
+ output_token,
+ "\x02\x00",
+ GSS_KRB5_MECHANISM);
+ krb5_data_free (&outbuf);
+ if (ret) return ret;
+ } else {
+ output_token->length = outbuf.length;
+ output_token->value = outbuf.data;
+ }
+ }
+
+ /*
+ * We need to send the flags back to the caller
+ */
+ flags |= GSS_C_TRANS_FLAG;
- if (src_name) {
- kret = krb5_copy_principal(gssapi_krb5_context,
- (*context_handle)->source,
- src_name);
- if (kret) {
- *minor_status = kret;
- gssapi_krb5_set_error_string ();
- return GSS_S_FAILURE;
- }
- }
+ if (ret_flags)
+ *ret_flags = flags;
+
+ /* And remember them for later */
+
+ (*context_handle)->lifetime = ticket->ticket.endtime;
+ (*context_handle)->flags = flags;
+ (*context_handle)->more_flags |= OPEN;
+
+ if (mech_type)
+ *mech_type = GSS_KRB5_MECHANISM;
+
+ if (time_rec) {
+ ret = gssapi_lifetime_left(minor_status,
+ (*context_handle)->lifetime,
+ time_rec);
+ if (ret)
+ if (ret) return ret;
+ }
- /*
- * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
- */
- if (flags & GSS_C_DCE_STYLE) {
- (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
- return GSS_S_CONTINUE_NEEDED;
- }
+ /*
+ * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
+ */
+ if (flags & GSS_C_DCE_STYLE) {
+ (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
+ return GSS_S_CONTINUE_NEEDED;
+ }
- return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
+ return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
}
static OM_uint32
@@ -490,7 +499,7 @@ gsskrb5_acceptor_wait_for_dcestyle(
OM_uint32 * minor_status,
gss_ctx_id_t * context_handle,
const gss_cred_id_t acceptor_cred_handle,
- const gss_buffer_t input_token,
+ const gss_buffer_t input_token_buffer,
const gss_channel_bindings_t input_chan_bindings,
gss_name_t * src_name,
gss_OID * mech_type,
@@ -506,8 +515,8 @@ gsskrb5_acceptor_wait_for_dcestyle(
OM_uint32 l_seq_number;
/* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */
- inbuf.length = input_token->length;
- inbuf.data = input_token->value;
+ inbuf.length = input_token_buffer->length;
+ inbuf.data = input_token_buffer->value;
/*
* We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number,
@@ -547,18 +556,41 @@ gsskrb5_acceptor_wait_for_dcestyle(
*/
{
krb5_ap_rep_enc_part *repl;
+ int32_t auth_flags;
+
+ kret = krb5_auth_con_removeflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags);
+ if (kret) { /* Can't happen */
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
- kret = _krb5_rd_rep_type(gssapi_krb5_context,
- (*context_handle)->auth_context,
- &inbuf,
- &repl,
- TRUE);
+ kret = krb5_rd_rep(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ &inbuf,
+ &repl);
if (kret) {
gssapi_krb5_set_error_string ();
*minor_status = kret;
return GSS_S_FAILURE;
}
+
+ /* Because the inbuf above is a final leg from client
+ * to server, we don't have a use for a 'reply'
+ * here */
krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
+
+ /* Do no harm, put the flags back */
+ kret = krb5_auth_con_setflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ auth_flags);
+ if (kret) { /* Can't happen */
+ gssapi_krb5_set_error_string ();
+ *minor_status = kret;
+ return GSS_S_FAILURE;
+ }
}
/* We need to check the liftime */
@@ -598,7 +630,7 @@ gsskrb5_acceptor_wait_for_dcestyle(
*/
{
OM_uint32 tmp_r_seq_number;
- OM_uint32 l_seq_number;
+ OM_uint32 tmp_l_seq_number;
kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
(*context_handle)->auth_context,
@@ -611,7 +643,7 @@ gsskrb5_acceptor_wait_for_dcestyle(
kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
(*context_handle)->auth_context,
- &l_seq_number);
+ &tmp_l_seq_number);
if (kret) {
gssapi_krb5_set_error_string ();
*minor_status = kret;
@@ -621,7 +653,7 @@ gsskrb5_acceptor_wait_for_dcestyle(
/*
* Here we check if the client has responsed with our local seq_number,
*/
- if (tmp_r_seq_number != l_seq_number) {
+ if (tmp_r_seq_number != tmp_l_seq_number) {
return GSS_S_UNSEQ_TOKEN;
}
}
@@ -645,73 +677,102 @@ gsskrb5_acceptor_wait_for_dcestyle(
}
static OM_uint32
-gsskrb5_accept_sec_context(
- OM_uint32 * minor_status,
- gss_ctx_id_t * context_handle,
- const gss_cred_id_t acceptor_cred_handle,
- const gss_buffer_t input_token,
- const gss_channel_bindings_t input_chan_bindings,
- gss_name_t * src_name,
- gss_OID * actual_mech_type,
- gss_buffer_t output_token,
- OM_uint32 * ret_flags,
- OM_uint32 * time_rec,
- gss_cred_id_t * delegated_cred_handle)
+gsskrb5_accept_sec_context
+ (OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ const gss_cred_id_t acceptor_cred_handle,
+ const gss_buffer_t input_token_buffer,
+ const gss_channel_bindings_t input_chan_bindings,
+ gss_name_t * src_name,
+ gss_OID * mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags,
+ OM_uint32 * time_rec,
+ gss_cred_id_t * delegated_cred_handle
+ )
{
- OM_uint32 ret;
-
- if (*context_handle == GSS_C_NO_CONTEXT) {
- ret = _gsskrb5_create_ctx(minor_status,
- context_handle,
- input_chan_bindings,
- ACCEPTOR_START);
- if (ret) return ret;
- }
+ OM_uint32 ret = GSS_S_COMPLETE;
+ krb5_data fwd_data;
+ gss_ctx_id_t local_context;
- if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM;
+ GSSAPI_KRB5_INIT();
- HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex);
+ krb5_data_zero (&fwd_data);
+ output_token->length = 0;
+ output_token->value = NULL;
+
+ if (src_name != NULL)
+ *src_name = NULL;
+ if (mech_type)
+ *mech_type = GSS_KRB5_MECHANISM;
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ ret = _gsskrb5_create_ctx(minor_status,
+ &local_context,
+ input_chan_bindings,
+ ACCEPTOR_START);
+ if (ret) return ret;
+ } else {
+ local_context = *context_handle;
+ }
+
+ /*
+ * TODO: check the channel_bindings
+ * (above just sets them to krb5 layer)
+ */
- switch ((*context_handle)->state) {
- case ACCEPTOR_START:
- ret = gsskrb5_acceptor_start(minor_status,
- context_handle,
- acceptor_cred_handle,
- input_token,
- input_chan_bindings,
- src_name,
- actual_mech_type,
- output_token,
- ret_flags,
- time_rec,
- delegated_cred_handle);
- break;
- case ACCEPTOR_WAIT_FOR_DCESTYLE:
- ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
- context_handle,
- acceptor_cred_handle,
- input_token,
- input_chan_bindings,
- src_name,
- actual_mech_type,
- output_token,
- ret_flags,
- time_rec,
- delegated_cred_handle);
- break;
- case ACCEPTOR_READY:
- /* this function should not be called after it has returned GSS_S_COMPLETE */
- ret = GSS_S_BAD_STATUS;
- break;
- default:
- /* TODO: is this correct here? --metze */
- ret = GSS_S_BAD_STATUS;
- break;
+ HEIMDAL_MUTEX_lock(&(local_context)->ctx_id_mutex);
+
+ switch ((local_context)->state) {
+ case ACCEPTOR_START:
+ ret = gsskrb5_acceptor_start(minor_status,
+ &local_context,
+ acceptor_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ break;
+ case ACCEPTOR_WAIT_FOR_DCESTYLE:
+ ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
+ &local_context,
+ acceptor_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ break;
+ case ACCEPTOR_READY:
+ /* this function should not be called after it has returned GSS_S_COMPLETE */
+ ret = GSS_S_BAD_STATUS;
+ break;
+ default:
+ /* TODO: is this correct here? --metze */
+ ret = GSS_S_BAD_STATUS;
+ break;
+ }
+
+ HEIMDAL_MUTEX_unlock(&(local_context)->ctx_id_mutex);
+
+ if (*context_handle == GSS_C_NO_CONTEXT) {
+ if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
+ *context_handle = local_context;
+ } else {
+ gss_delete_sec_context(minor_status,
+ &local_context,
+ NULL);
}
+ }
- HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex);
-
- return ret;
+ return ret;
}
static OM_uint32
@@ -1065,53 +1126,45 @@ gss_accept_sec_context
gss_cred_id_t * delegated_cred_handle
)
{
+ OM_uint32 ret;
ssize_t mech_len;
const u_char *p;
*minor_status = 0;
- if (src_name) *src_name = GSS_C_NO_NAME;
- if (mech_type) *mech_type = GSS_C_NO_OID;
-
- output_token->length = 0;
- output_token->value = NULL;
-
- if (ret_flags) *ret_flags = 0;
- if (time_rec) *time_rec = 0;
- if (delegated_cred_handle) *delegated_cred_handle = NULL;
-
- mech_len = gssapi_krb5_get_mech(input_token_buffer->value,
- input_token_buffer->length,
- &p);
-
- /* This could be 'dce style' kerberos, where the OID is missing :-( */
- if ((mech_len < 0) || (mech_len == GSS_KRB5_MECHANISM->length
- && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)) {
- return gsskrb5_accept_sec_context(minor_status,
- context_handle,
- acceptor_cred_handle,
- input_token_buffer,
- input_chan_bindings,
- src_name,
- mech_type,
- output_token,
- ret_flags,
- time_rec,
- delegated_cred_handle);
- } else if (mech_len == GSS_SPNEGO_MECHANISM->length
- && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0) {
- return spnego_accept_sec_context(minor_status,
- context_handle,
- acceptor_cred_handle,
- input_token_buffer,
- input_chan_bindings,
- src_name,
- mech_type,
- output_token,
- ret_flags,
- time_rec,
- delegated_cred_handle);
- }
-
+ mech_len = gssapi_krb5_get_mech (input_token_buffer->value,
+ input_token_buffer->length,
+ &p);
+
+ /* This could be 'dce style' kerberos, where the OID is missing :-( */
+ if ((mech_len < 0) || ((mech_len == GSS_KRB5_MECHANISM->length)
+ && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0))
+ ret = gsskrb5_accept_sec_context(minor_status,
+ context_handle,
+ acceptor_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ else if (mech_len == GSS_SPNEGO_MECHANISM->length
+ && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0)
+ ret = spnego_accept_sec_context(minor_status,
+ context_handle,
+ acceptor_cred_handle,
+ input_token_buffer,
+ input_chan_bindings,
+ src_name,
+ mech_type,
+ output_token,
+ ret_flags,
+ time_rec,
+ delegated_cred_handle);
+ else
return GSS_S_BAD_MECH;
+
+ return ret;
}
diff --git a/source4/heimdal/lib/gssapi/copy_ccache.c b/source4/heimdal/lib/gssapi/copy_ccache.c
index 4f2b3f4895..828ca64156 100644
--- a/source4/heimdal/lib/gssapi/copy_ccache.c
+++ b/source4/heimdal/lib/gssapi/copy_ccache.c
@@ -105,6 +105,25 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
+OM_uint32
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ time_t *authtime)
+{
+ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+ if (context_handle->ticket == NULL) {
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+ *minor_status = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ *authtime = context_handle->ticket->ticket.authtime;
+ HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+ *minor_status = 0;
+ return GSS_S_COMPLETE;
+}
+
OM_uint32 gss_krb5_copy_service_keyblock
(OM_uint32 *minor_status,
gss_ctx_id_t context_handle,
diff --git a/source4/heimdal/lib/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi.h
index 5712581d3f..4ee988b020 100644
--- a/source4/heimdal/lib/gssapi/gssapi.h
+++ b/source4/heimdal/lib/gssapi/gssapi.h
@@ -809,6 +809,10 @@ gsskrb5_extract_authz_data_from_sec_context
int /*ad_type*/,
gss_buffer_t /*ad_data*/);
OM_uint32
+gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
+ gss_ctx_id_t context_handle,
+ time_t *authtime);
+OM_uint32
gsskrb5_get_initiator_subkey
(OM_uint32 * /*minor_status*/,
const gss_ctx_id_t context_handle,
diff --git a/source4/heimdal/lib/gssapi/init_sec_context.c b/source4/heimdal/lib/gssapi/init_sec_context.c
index 6a80934e46..5c6c6a0f8e 100644
--- a/source4/heimdal/lib/gssapi/init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/init_sec_context.c
@@ -147,6 +147,15 @@ _gsskrb5_create_ctx(
return GSS_S_BAD_BINDINGS;
}
+ /*
+ * We need a sequence number
+ */
+
+ krb5_auth_con_addflags(gssapi_krb5_context,
+ (*context_handle)->auth_context,
+ KRB5_AUTH_CONTEXT_DO_SEQUENCE,
+ NULL);
+
return GSS_S_COMPLETE;
}
@@ -388,15 +397,6 @@ gsskrb5_initiator_start
ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
if (ret) return ret;
- /*
- * We need a sequence number
- */
-
- krb5_auth_con_addflags(gssapi_krb5_context,
- (*context_handle)->auth_context,
- KRB5_AUTH_CONTEXT_DO_SEQUENCE,
- NULL);
-
/* We need the key and a random local subkey */
{
kret = krb5_auth_con_setkey(gssapi_krb5_context,
diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h
index cc619314a3..97f286b83e 100644
--- a/source4/heimdal/lib/krb5/krb5-protos.h
+++ b/source4/heimdal/lib/krb5/krb5-protos.h
@@ -2378,6 +2378,12 @@ krb5_parse_name (
krb5_principal */*principal*/);
krb5_error_code KRB5_LIB_FUNCTION
+krb5_parse_name_mustrealm (
+ krb5_context /*context*/,
+ const char */*name*/,
+ krb5_principal */*principal*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
krb5_parse_name_norealm (
krb5_context /*context*/,
const char */*name*/,
@@ -3436,13 +3442,6 @@ krb5_write_safe_message (
krb5_error_code KRB5_LIB_FUNCTION
krb5_xfree (void */*ptr*/);
-krb5_error_code
-parse_name (
- krb5_context /*context*/,
- const char */*name*/,
- krb5_boolean /*short_form*/,
- krb5_principal */*principal*/);
-
#ifdef __cplusplus
}
#endif
diff --git a/source4/heimdal/lib/krb5/rd_rep.c b/source4/heimdal/lib/krb5/rd_rep.c
index a92eea5c04..53138d9f45 100644
--- a/source4/heimdal/lib/krb5/rd_rep.c
+++ b/source4/heimdal/lib/krb5/rd_rep.c
@@ -36,94 +36,80 @@
RCSID("$Id: rd_rep.c,v 1.25 2005/06/17 07:49:33 lha Exp $");
krb5_error_code KRB5_LIB_FUNCTION
-_krb5_rd_rep_type(krb5_context context,
- krb5_auth_context auth_context,
- const krb5_data *inbuf,
- krb5_ap_rep_enc_part **repl,
- krb5_boolean dce_style_response)
+krb5_rd_rep(krb5_context context,
+ krb5_auth_context auth_context,
+ const krb5_data *inbuf,
+ krb5_ap_rep_enc_part **repl)
{
- krb5_error_code ret;
- AP_REP ap_rep;
- size_t len;
- krb5_data data;
- krb5_crypto crypto;
+ krb5_error_code ret;
+ AP_REP ap_rep;
+ size_t len;
+ krb5_data data;
+ krb5_crypto crypto;
- krb5_data_zero (&data);
- ret = 0;
+ krb5_data_zero (&data);
+ ret = 0;
- ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len);
- if (ret)
- return ret;
- if (ap_rep.pvno != 5) {
- ret = KRB5KRB_AP_ERR_BADVERSION;
- krb5_clear_error_string (context);
- goto out;
- }
- if (ap_rep.msg_type != krb_ap_rep) {
- ret = KRB5KRB_AP_ERR_MSG_TYPE;
- krb5_clear_error_string (context);
- goto out;
- }
+ ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len);
+ if (ret)
+ return ret;
+ if (ap_rep.pvno != 5) {
+ ret = KRB5KRB_AP_ERR_BADVERSION;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+ if (ap_rep.msg_type != krb_ap_rep) {
+ ret = KRB5KRB_AP_ERR_MSG_TYPE;
+ krb5_clear_error_string (context);
+ goto out;
+ }
- ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto);
- if (ret)
- goto out;
- ret = krb5_decrypt_EncryptedData (context,
- crypto,
- KRB5_KU_AP_REQ_ENC_PART,
- &ap_rep.enc_part,
- &data);
- krb5_crypto_destroy(context, crypto);
- if (ret)
- goto out;
+ ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto);
+ if (ret)
+ goto out;
+ ret = krb5_decrypt_EncryptedData (context,
+ crypto,
+ KRB5_KU_AP_REQ_ENC_PART,
+ &ap_rep.enc_part,
+ &data);
+ krb5_crypto_destroy(context, crypto);
+ if (ret)
+ goto out;
- *repl = malloc(sizeof(**repl));
- if (*repl == NULL) {
- ret = ENOMEM;
- krb5_set_error_string (context, "malloc: out of memory");
- goto out;
- }
- ret = krb5_decode_EncAPRepPart(context,
- data.data,
- data.length,
- *repl,
- &len);
- if (ret)
- return ret;
-
- if (!dce_style_response) {
- if ((*repl)->ctime != auth_context->authenticator->ctime ||
- (*repl)->cusec != auth_context->authenticator->cusec) {
- ret = KRB5KRB_AP_ERR_MUT_FAIL;
- krb5_set_error_string (context, "Mutual authentication failed: Timestamps mismatch");
- goto out;
- }
- }
- if ((*repl)->seq_number)
- krb5_auth_con_setremoteseqnumber(context, auth_context,
- *((*repl)->seq_number));
- if ((*repl)->subkey)
- krb5_auth_con_setremotesubkey(context, auth_context, (*repl)->subkey);
+ *repl = malloc(sizeof(**repl));
+ if (*repl == NULL) {
+ ret = ENOMEM;
+ krb5_set_error_string (context, "malloc: out of memory");
+ goto out;
+ }
+ ret = krb5_decode_EncAPRepPart(context,
+ data.data,
+ data.length,
+ *repl,
+ &len);
+ if (ret)
+ return ret;
+
+ if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+ if ((*repl)->ctime != auth_context->authenticator->ctime ||
+ (*repl)->cusec != auth_context->authenticator->cusec) {
+ ret = KRB5KRB_AP_ERR_MUT_FAIL;
+ krb5_clear_error_string (context);
+ goto out;
+ }
+ }
+ if ((*repl)->seq_number)
+ krb5_auth_con_setremoteseqnumber(context, auth_context,
+ *((*repl)->seq_number));
+ if ((*repl)->subkey)
+ krb5_auth_con_setremotesubkey(context, auth_context, (*repl)->subkey);
-out:
- krb5_data_free (&data);
- free_AP_REP (&ap_rep);
- return ret;
+ out:
+ krb5_data_free (&data);
+ free_AP_REP (&ap_rep);
+ return ret;
}
-krb5_error_code KRB5_LIB_FUNCTION
-krb5_rd_rep(krb5_context context,
- krb5_auth_context auth_context,
- const krb5_data *inbuf,
- krb5_ap_rep_enc_part **repl)
-{
- return _krb5_rd_rep_type(context,
- auth_context,
- inbuf,
- repl,
- FALSE);
-}
-
void KRB5_LIB_FUNCTION
krb5_free_ap_rep_enc_part (krb5_context context,
krb5_ap_rep_enc_part *val)
diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c
index 30ad08bd82..66172c10fb 100644
--- a/source4/heimdal/lib/krb5/rd_req.c
+++ b/source4/heimdal/lib/krb5/rd_req.c
@@ -33,7 +33,7 @@
#include <krb5_locl.h>
-RCSID("$Id: rd_req.c,v 1.57 2005/01/08 20:41:17 lha Exp $");
+RCSID("$Id: rd_req.c,v 1.58 2005/08/27 05:48:57 lha Exp $");
static krb5_error_code
decrypt_tkt_enc_part (krb5_context context,
@@ -136,6 +136,10 @@ check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc)
int num_realms;
krb5_error_code ret;
+ /* Windows w2k and w2k3 uses this */
+ if(enc->transited.tr_type == 0 && enc->transited.contents.length == 0)
+ return 0;
+
if(enc->transited.tr_type != DOMAIN_X500_COMPRESS)
return KRB5KDC_ERR_TRTYPE_NOSUPP;
@@ -561,6 +565,7 @@ krb5_rd_req_return_keyblock(krb5_context context,
krb5_error_code ret;
krb5_ap_req ap_req;
krb5_principal service = NULL;
+ krb5_keyblock *local_keyblock;
if (*auth_context == NULL) {
ret = krb5_auth_con_init(context, auth_context);
@@ -592,13 +597,13 @@ krb5_rd_req_return_keyblock(krb5_context context,
&ap_req,
server,
keytab,
- keyblock);
+ &local_keyblock);
if(ret)
goto out;
} else {
ret = krb5_copy_keyblock(context,
(*auth_context)->keyblock,
- keyblock);
+ &local_keyblock);
if (ret)
goto out;
}
@@ -607,17 +612,20 @@ krb5_rd_req_return_keyblock(krb5_context context,
auth_context,
&ap_req,
server,
- *keyblock,
+ local_keyblock,
0,
ap_req_options,
ticket);
+ if (ret) {
+ krb5_free_keyblock(context, local_keyblock);
+ } else {
+ *keyblock = local_keyblock;
+ }
out:
free_AP_REQ(&ap_req);
if(service)
krb5_free_principal(context, service);
- if (ret)
- krb5_free_keyblock(context, *keyblock);
return ret;
}
diff --git a/source4/heimdal/lib/roken/roken-common.h b/source4/heimdal/lib/roken/roken-common.h
index d85d55f433..c4ba2edb7c 100644
--- a/source4/heimdal/lib/roken/roken-common.h
+++ b/source4/heimdal/lib/roken/roken-common.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: roken-common.h,v 1.61 2005/07/07 05:03:30 lha Exp $ */
+/* $Id: roken-common.h,v 1.62 2005/09/01 18:47:35 lha Exp $ */
#ifndef __ROKEN_COMMON_H__
#define __ROKEN_COMMON_H__
@@ -312,43 +312,46 @@ ewrite (int fd, const void *buf, size_t nbytes);
struct hostent;
const char * ROKEN_LIB_FUNCTION
-hostent_find_fqdn (const struct hostent *he);
+hostent_find_fqdn (const struct hostent *);
void ROKEN_LIB_FUNCTION
-esetenv(const char *var, const char *val, int rewrite);
+esetenv(const char *, const char *, int);
void ROKEN_LIB_FUNCTION
-socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port);
+socket_set_address_and_port (struct sockaddr *, const void *, int);
size_t ROKEN_LIB_FUNCTION
-socket_addr_size (const struct sockaddr *sa);
+socket_addr_size (const struct sockaddr *);
void ROKEN_LIB_FUNCTION
-socket_set_any (struct sockaddr *sa, int af);
+socket_set_any (struct sockaddr *, int);
size_t ROKEN_LIB_FUNCTION
-socket_sockaddr_size (const struct sockaddr *sa);
+socket_sockaddr_size (const struct sockaddr *);
void * ROKEN_LIB_FUNCTION
-socket_get_address (struct sockaddr *sa);
+socket_get_address (struct sockaddr *);
int ROKEN_LIB_FUNCTION
-socket_get_port (const struct sockaddr *sa);
+socket_get_port (const struct sockaddr *);
void ROKEN_LIB_FUNCTION
-socket_set_port (struct sockaddr *sa, int port);
+socket_set_port (struct sockaddr *, int);
void ROKEN_LIB_FUNCTION
-socket_set_portrange (int sock, int restr, int af);
+socket_set_portrange (int, int, int);
void ROKEN_LIB_FUNCTION
-socket_set_debug (int sock);
+socket_set_debug (int);
void ROKEN_LIB_FUNCTION
-socket_set_tos (int sock, int tos);
+socket_set_tos (int, int);
void ROKEN_LIB_FUNCTION
-socket_set_reuseaddr (int sock, int val);
+socket_set_reuseaddr (int, int);
+
+void ROKEN_LIB_FUNCTION
+socket_set_ipv6only (int, int);
char ** ROKEN_LIB_FUNCTION
vstrcollect(va_list *ap);
diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c
index 45b6776f70..20578a786e 100644
--- a/source4/kdc/pac-glue.c
+++ b/source4/kdc/pac-glue.c
@@ -36,7 +36,7 @@
krb5_error_code ret;
NTSTATUS nt_status;
struct auth_serversupplied_info *server_info;
- char *username, *p;
+ char *username;
const char *realm;
DATA_BLOB tmp_blob;
TALLOC_CTX *mem_ctx = talloc_named(config, 0, "samba_get_pac context");
@@ -44,7 +44,7 @@
return ENOMEM;
}
- ret = krb5_unparse_name(context, client, &username);
+ ret = krb5_unparse_name_norealm(context, client, &username);
if (ret != 0) {
krb5_set_error_string(context, "get pac: could not parse principal");
@@ -55,12 +55,6 @@
/* parse the principal name */
realm = krb5_principal_get_realm(context, client);
- username = talloc_strdup(mem_ctx, username);
- p = strchr(username, '@');
- if (p) {
- p[0] = '\0';
- }
-
nt_status = sam_get_server_info(mem_ctx, username, realm,
data_blob(NULL, 0), data_blob(NULL, 0),
@@ -75,6 +69,7 @@
context,
krbtgt_keyblock,
server_keyblock,
+ client,
tgs_authtime,
&tmp_blob);
diff --git a/source4/torture/auth/pac.c b/source4/torture/auth/pac.c
index 8b0da02bf3..b99fcfe95e 100644
--- a/source4/torture/auth/pac.c
+++ b/source4/torture/auth/pac.c
@@ -50,6 +50,9 @@ static BOOL torture_pac_self_check(void)
struct auth_serversupplied_info *server_info;
struct auth_serversupplied_info *server_info_out;
+ krb5_principal client_principal;
+ time_t logon_time = time(NULL);
+
ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
if (ret) {
@@ -99,13 +102,25 @@ static BOOL torture_pac_self_check(void)
talloc_free(mem_ctx);
return False;
}
-
+
+ ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context,
+ server_info->account_name, &client_principal);
+ if (ret) {
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ talloc_free(mem_ctx);
+ return False;
+ }
+
/* OK, go ahead and make a PAC */
ret = kerberos_create_pac(mem_ctx, server_info,
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
&server_keyblock,
- time(NULL),
+ client_principal,
+ logon_time,
&tmp_blob);
if (ret) {
@@ -117,6 +132,8 @@ static BOOL torture_pac_self_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
talloc_free(mem_ctx);
return False;
}
@@ -128,13 +145,17 @@ static BOOL torture_pac_self_check(void)
tmp_blob,
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
- &server_keyblock);
+ &server_keyblock,
+ client_principal,
+ logon_time);
if (!NT_STATUS_IS_OK(nt_status)) {
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
DEBUG(1, ("PAC decoding failed: %s\n",
nt_errstr(nt_status)));
@@ -147,13 +168,17 @@ static BOOL torture_pac_self_check(void)
tmp_blob,
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
- &server_keyblock);
+ &server_keyblock,
+ client_principal,
+ logon_time);
if (!NT_STATUS_IS_OK(nt_status)) {
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
printf("PAC decoding (for logon info) failed: %s\n",
nt_errstr(nt_status));
@@ -165,6 +190,8 @@ static BOOL torture_pac_self_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context,
+ client_principal);
validation.sam3 = &logon_info->info3;
nt_status = make_server_info_netlogon_validation(mem_ctx,
@@ -249,7 +276,6 @@ static BOOL torture_pac_saved_check(void)
struct PAC_LOGON_INFO *logon_info;
union netr_Validation validation;
const char *pac_file, *pac_kdc_key, *pac_member_key;
-
struct auth_serversupplied_info *server_info_out;
krb5_keyblock server_keyblock;
@@ -257,9 +283,13 @@ static BOOL torture_pac_saved_check(void)
struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
krb5_error_code ret;
-
struct smb_krb5_context *smb_krb5_context;
+ const char *principal_string;
+ krb5_principal client_principal;
+ const char *authtime_string;
+ time_t authtime;
+
ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context);
if (ret) {
@@ -336,12 +366,40 @@ static BOOL torture_pac_saved_check(void)
dump_data(10,tmp_blob.data,tmp_blob.length);
+ principal_string = lp_parm_string(-1,"torture","pac_client_principal");
+ if (!principal_string) {
+ principal_string = "w2003final$@WIN2K3.THINKER.LOCAL";
+ }
+
+ authtime_string = lp_parm_string(-1,"torture","pac_authtime");
+ if (!authtime_string) {
+ authtime = 1120440609;
+ } else {
+ authtime = strtoull(authtime_string, NULL, 0);
+ }
+
+ ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string,
+ &client_principal);
+ if (ret) {
+ DEBUG(1, ("parsing of client principal [%s] failed: %s\n",
+ principal_string,
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ talloc_free(mem_ctx);
+ return False;
+ }
+
/* Decode and verify the signaure on the PAC */
nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
tmp_blob,
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
- &server_keyblock);
+ &server_keyblock,
+ client_principal, authtime);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("PAC decoding failed: %s\n",
nt_errstr(nt_status)));
@@ -350,6 +408,8 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
talloc_free(mem_ctx);
return False;
}
@@ -359,13 +419,16 @@ static BOOL torture_pac_saved_check(void)
tmp_blob,
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
- &server_keyblock);
+ &server_keyblock,
+ client_principal, authtime);
if (!NT_STATUS_IS_OK(nt_status)) {
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
printf("PAC decoding (for logon info) failed: %s\n",
nt_errstr(nt_status));
@@ -383,6 +446,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
printf("PAC decoding (make server info) failed: %s\n",
nt_errstr(nt_status));
@@ -398,6 +462,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
printf("PAC Decode resulted in *different* domain SID: %s != %s\n",
"S-1-5-21-3048156945-3961193616-3706469200-1005",
@@ -418,6 +483,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
DEBUG(0, ("PAC push failed\n"));
talloc_free(mem_ctx);
@@ -435,6 +501,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
DEBUG(0, ("PAC push failed: original buffer length[%u] != created buffer length[%u]\n",
(unsigned)tmp_blob.length, (unsigned)validate_blob.length));
@@ -447,6 +514,7 @@ static BOOL torture_pac_saved_check(void)
&krbtgt_keyblock);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
&server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
DEBUG(0, ("PAC push failed: length[%u] matches, but data does not\n",
(unsigned)tmp_blob.length));
@@ -454,6 +522,61 @@ static BOOL torture_pac_saved_check(void)
return False;
}
+ /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
+ nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ &krbtgt_keyblock,
+ &server_keyblock,
+ client_principal,
+ authtime + 1);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("PAC decoding DID NOT fail on broken auth time (time + 1)\n"));
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+ talloc_free(mem_ctx);
+ return False;
+ }
+
+ /* Break the client principal */
+ krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
+
+ ret = krb5_parse_name(smb_krb5_context->krb5_context,
+ "not the right principal", &client_principal);
+ if (ret) {
+ DEBUG(1, ("parsing of bogus client principal failed: %s\n",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ talloc_free(mem_ctx);
+ return False;
+ }
+
+ nt_status = kerberos_decode_pac(mem_ctx, &pac_data,
+ tmp_blob,
+ smb_krb5_context->krb5_context,
+ &krbtgt_keyblock,
+ &server_keyblock,
+ client_principal,
+ authtime);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(1, ("PAC decoding DID NOT fail on modified principal\n"));
+
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &krbtgt_keyblock);
+ krb5_free_keyblock_contents(smb_krb5_context->krb5_context,
+ &server_keyblock);
+ talloc_free(mem_ctx);
+ return False;
+ }
+
/* Finally... Bugger up the signature, and check we fail the checksum */
tmp_blob.data[tmp_blob.length - 2]++;
@@ -461,7 +584,9 @@ static BOOL torture_pac_saved_check(void)
tmp_blob,
smb_krb5_context->krb5_context,
&krbtgt_keyblock,
- &server_keyblock);
+ &server_keyblock,
+ client_principal,
+ authtime);
if (NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("PAC decoding DID NOT fail on broken checksum\n"));