summaryrefslogtreecommitdiff
path: root/source4/auth
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth')
-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
6 files changed, 302 insertions, 317 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 */