summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/gensec/gensec_gssapi.c9
-rw-r--r--source4/auth/gensec/gensec_krb5.c54
-rw-r--r--source4/auth/kerberos/clikrb5.c112
-rw-r--r--source4/auth/kerberos/kerberos-notes.txt14
-rw-r--r--source4/heimdal/lib/krb5/ticket.c158
-rw-r--r--source4/heimdal_build/config.mk1
6 files changed, 199 insertions, 149 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 86ecb604ae..37c8333da3 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -873,18 +873,13 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
if (maj_stat == 0) {
maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
gensec_gssapi_state->gssapi_context,
- KRB5_AUTHDATA_IF_RELEVANT,
+ KRB5_AUTHDATA_WIN2K_PAC,
&pac);
}
if (maj_stat == 0) {
pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
gss_release_buffer(&min_stat, &pac);
-
- if (!unwrap_pac(mem_ctx, &pac_blob, &unwrapped_pac)) {
- /* No pac actually present */
- maj_stat = 1;
- }
}
/* IF we have the PAC - otherwise we need to get this
@@ -902,7 +897,7 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi
}
/* decode and verify the pac */
- nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, unwrapped_pac,
+ nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
gensec_gssapi_state->smb_krb5_context->krb5_context,
NULL, keyblock, principal, authtime);
krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index 3ed38a435c..36cfc49196 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -473,30 +473,44 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
{
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
+ krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
struct auth_serversupplied_info *server_info = NULL;
struct auth_session_info *session_info = NULL;
struct PAC_LOGON_INFO *logon_info;
- krb5_const_principal client_principal;
+ krb5_principal client_principal;
DATA_BLOB pac;
+ krb5_data pac_data;
- BOOL got_auth_data;
+ krb5_error_code ret;
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
- got_auth_data = get_auth_data_from_tkt(mem_ctx, &pac, gensec_krb5_state->ticket);
-
- /* IF we have the PAC - otherwise we need to get this
- * data from elsewere - local ldb, or (TODO) lookup of some
- * kind...
- */
- if (got_auth_data) {
+ ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &pac_data);
+
+ if (ret) {
+ DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n",
+ smb_get_krb5_error_message(context,
+ ret, mem_ctx)));
+ } else {
+ pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
+ if (!pac.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
- client_principal = get_principal_from_tkt(gensec_krb5_state->ticket);
+ ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
+ if (ret) {
+ DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n",
+ smb_get_krb5_error_message(context,
+ ret, mem_ctx)));
+ return NT_STATUS_NO_MEMORY;
+ }
/* decode and verify the pac */
nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, pac,
@@ -504,6 +518,8 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
NULL, gensec_krb5_state->keyblock,
client_principal,
gensec_krb5_state->ticket->ticket.authtime);
+ krb5_free_principal(context, client_principal);
+
if (NT_STATUS_IS_OK(nt_status)) {
union netr_Validation validation;
validation.sam3 = &logon_info->info3;
@@ -515,12 +531,26 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security
talloc_free(mem_ctx);
}
+
+
+ /* IF we have the PAC - otherwise we need to get this
+ * data from elsewere - local ldb, or (TODO) lookup of some
+ * kind...
+ */
if (!NT_STATUS_IS_OK(nt_status)) {
/* NO pac, or can't parse or verify it */
- krb5_error_code ret;
char *principal_string;
+ ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
+ if (ret) {
+ DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n",
+ smb_get_krb5_error_message(context,
+ ret, mem_ctx)));
+ return NT_STATUS_NO_MEMORY;
+ }
+
ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context,
- get_principal_from_tkt(gensec_krb5_state->ticket), &principal_string);
+ client_principal, &principal_string);
+ krb5_free_principal(context, client_principal);
if (ret) {
return NT_STATUS_NO_MEMORY;
}
diff --git a/source4/auth/kerberos/clikrb5.c b/source4/auth/kerberos/clikrb5.c
index 17a1e5f3d4..3cac97cdc6 100644
--- a/source4/auth/kerberos/clikrb5.c
+++ b/source4/auth/kerberos/clikrb5.c
@@ -159,118 +159,6 @@
}
#endif
-BOOL unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data)
-{
- DATA_BLOB pac_contents;
- struct asn1_data data;
- int data_type;
-
- if (!auth_data->length) {
- return False;
- }
-
- asn1_load(&data, *auth_data);
- asn1_start_tag(&data, ASN1_SEQUENCE(0));
- asn1_start_tag(&data, ASN1_SEQUENCE(0));
- asn1_start_tag(&data, ASN1_CONTEXT(0));
- asn1_read_Integer(&data, &data_type);
-
- if (data_type != KRB5_AUTHDATA_WIN2K_PAC ) {
- DEBUG(10,("authorization data is not a Windows PAC (type: %d)\n", data_type));
- asn1_free(&data);
- return False;
- }
-
- asn1_end_tag(&data);
- asn1_start_tag(&data, ASN1_CONTEXT(1));
- asn1_read_OctetString(&data, &pac_contents);
- asn1_end_tag(&data);
- asn1_end_tag(&data);
- asn1_end_tag(&data);
- asn1_free(&data);
-
- *unwrapped_pac_data = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length);
-
- data_blob_free(&pac_contents);
-
- return True;
-}
-
- BOOL get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt)
-{
- DATA_BLOB auth_data_wrapped;
- BOOL got_auth_data_pac = False;
- int i;
-
-#if defined(HAVE_KRB5_TKT_ENC_PART2)
- if (tkt->enc_part2 && tkt->enc_part2->authorization_data &&
- tkt->enc_part2->authorization_data[0] &&
- tkt->enc_part2->authorization_data[0]->length)
- {
- for (i = 0; tkt->enc_part2->authorization_data[i] != NULL; i++) {
-
- if (tkt->enc_part2->authorization_data[i]->ad_type !=
- KRB5_AUTHDATA_IF_RELEVANT) {
- DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
- tkt->enc_part2->authorization_data[i]->ad_type));
- continue;
- }
-
- auth_data_wrapped = data_blob(tkt->enc_part2->authorization_data[i]->contents,
- tkt->enc_part2->authorization_data[i]->length);
-
- /* check if it is a PAC */
- got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
- data_blob_free(&auth_data_wrapped);
-
- if (!got_auth_data_pac) {
- continue;
- }
- }
-
- return got_auth_data_pac;
- }
-
-#else
- if (tkt->ticket.authorization_data &&
- tkt->ticket.authorization_data->len)
- {
- for (i = 0; i < tkt->ticket.authorization_data->len; i++) {
-
- if (tkt->ticket.authorization_data->val[i].ad_type !=
- KRB5_AUTHDATA_IF_RELEVANT) {
- DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
- tkt->ticket.authorization_data->val[i].ad_type));
- continue;
- }
-
- auth_data_wrapped = data_blob(tkt->ticket.authorization_data->val[i].ad_data.data,
- tkt->ticket.authorization_data->val[i].ad_data.length);
-
- /* check if it is a PAC */
- got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
- data_blob_free(&auth_data_wrapped);
-
- if (!got_auth_data_pac) {
- continue;
- }
- }
-
- return got_auth_data_pac;
- }
-#endif
- return False;
-}
-
- krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
-{
-#if defined(HAVE_KRB5_TKT_ENC_PART2)
- return tkt->enc_part2->client;
-#else
- return tkt->client;
-#endif
-}
-
#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
void krb5_free_unparsed_name(krb5_context context, char *val)
{
diff --git a/source4/auth/kerberos/kerberos-notes.txt b/source4/auth/kerberos/kerberos-notes.txt
index a36bf556aa..83fb886c45 100644
--- a/source4/auth/kerberos/kerberos-notes.txt
+++ b/source4/auth/kerberos/kerberos-notes.txt
@@ -309,6 +309,12 @@ Samba makes extensive use of the principal manipulation functions in
Heimdal, including the known structure behind krb_principal and
krb5_realm (a char *).
+Authz data extraction
+---------------------
+
+We use krb5_ticket_get_authorization_data_type(), and expect it to
+return the correct authz data, even if wrapped in an AD-IFRELEVENT container.
+
KDC Extensions
--------------
@@ -392,14 +398,6 @@ PAC Correctness
We need to put the PAC into the TGT, not just the service ticket.
-Authz data extraction
----------------------
-
-We need to parse the authz data field correctly, and have a generic
-rouitine to get at particular types of data, no matter their inclusion
-in 'if relevent' or other stuctures. This should be a utlity function
-we can use in both the client libs and KDC.
-
Forwarded tickets
-----------------
diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c
index 734cd4d4ca..8f4f8fb152 100644
--- a/source4/heimdal/lib/krb5/ticket.c
+++ b/source4/heimdal/lib/krb5/ticket.c
@@ -97,6 +97,141 @@ krb5_ticket_get_server(krb5_context context,
return krb5_copy_principal(context, ticket->server, server);
}
+static int
+find_type_in_ad(krb5_context context,
+ int type,
+ krb5_data *data,
+ int *found,
+ int failp,
+ krb5_keyblock *sessionkey,
+ const AuthorizationData *ad,
+ int level)
+{
+ krb5_error_code ret = ENOENT;
+ int i;
+
+ if (level > 9) {
+ krb5_set_error_string(context, "Authorization data nested deeper "
+ "then %d levels, stop searching", level);
+ ret = ENOENT; /* XXX */
+ goto out;
+ }
+
+ /*
+ * Only copy out the element the first time we get to it, we need
+ * to run over the whole authorization data fields to check if
+ * there are any container clases we need to care about.
+ */
+ for (i = 0; i < ad->len; i++) {
+ if (!*found && ad->val[i].ad_type == type) {
+ ret = copy_octet_string(&ad->val[i].ad_data, data);
+ if (ret) {
+ krb5_set_error_string(context, "malloc - out of memory");
+ goto out;
+ }
+ *found = 1;
+ continue;
+ }
+ switch (ad->val[i].ad_type) {
+ case KRB5_AUTHDATA_IF_RELEVANT: {
+ AuthorizationData child;
+ ret = decode_AuthorizationData(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to decode "
+ "IF_RELEVANT with %d", ret);
+ goto out;
+ }
+ ret = find_type_in_ad(context, type, data, found, 0, sessionkey,
+ &child, level + 1);
+ free_AuthorizationData(&child);
+ if (ret)
+ goto out;
+ break;
+ }
+ case KRB5_AUTHDATA_KDC_ISSUED: {
+ AD_KDCIssued child;
+
+ ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to decode "
+ "AD_KDCIssued with %d", ret);
+ goto out;
+ }
+ if (failp) {
+ krb5_boolean valid;
+ krb5_data buf;
+ size_t len;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
+ &child.elements, &len, ret);
+ if (ret) {
+ free_AD_KDCIssued(&child);
+ krb5_clear_error_string(context);
+ goto out;
+ }
+ if(buf.length != len)
+ krb5_abortx(context, "internal error in ASN.1 encoder");
+
+ ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
+ &child.ad_checksum, &valid);
+ krb5_data_free(&buf);
+ if (ret) {
+ free_AD_KDCIssued(&child);
+ goto out;
+ }
+ if (!valid) {
+ krb5_clear_error_string(context);
+ ret = ENOENT;
+ free_AD_KDCIssued(&child);
+ goto out;
+ }
+ }
+ ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
+ &child.elements, level + 1);
+ free_AD_KDCIssued(&child);
+ if (ret)
+ goto out;
+ break;
+ }
+ case KRB5_AUTHDATA_AND_OR:
+ if (!failp)
+ break;
+ krb5_set_error_string(context, "Authorization data contains "
+ "AND-OR element that is unknown to the "
+ "application");
+ ret = ENOENT; /* XXX */
+ goto out;
+ default:
+ if (!failp)
+ break;
+ krb5_set_error_string(context, "Authorization data contains "
+ "unknown type (%d) ", ad->val[i].ad_type);
+ ret = ENOENT; /* XXX */
+ goto out;
+ }
+ }
+out:
+ if (ret) {
+ if (*found) {
+ krb5_data_free(data);
+ *found = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Extract the authorization data type of `type' from the
+ * 'ticket'. Store the field in `data'. This function is to use for
+ * kerberos applications
+ */
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_ticket_get_authorization_data_type(krb5_context context,
krb5_ticket *ticket,
@@ -104,22 +239,25 @@ krb5_ticket_get_authorization_data_type(krb5_context context,
krb5_data *data)
{
AuthorizationData *ad;
- int i;
+ krb5_error_code ret;
+ int found = 0;
- data->length = 0;
- data->data = NULL;
+ krb5_data_zero(data);
ad = ticket->ticket.authorization_data;
- if (ad == NULL) {
+ if (ticket->ticket.authorization_data == NULL) {
krb5_set_error_string(context, "Ticket have not authorization data");
return ENOENT; /* XXX */
}
- for (i = 0; i < ad->len; i++) {
- if (ad->val[i].ad_type == type)
- return copy_octet_string(&ad->val[i].ad_data, data);
- }
- krb5_set_error_string(context, "Ticket have not authorization "
+ ret = find_type_in_ad(context, type, data, &found, 1, &ticket->ticket.key,
+ ticket->ticket.authorization_data, 0);
+ if (ret)
+ return ret;
+ if (!found) {
+ krb5_set_error_string(context, "Ticket have not authorization "
"data of type %d", type);
- return ENOENT; /* XXX */
+ return ENOENT; /* XXX */
+ }
+ return 0;
}
diff --git a/source4/heimdal_build/config.mk b/source4/heimdal_build/config.mk
index f90cb4ce52..2786a010bb 100644
--- a/source4/heimdal_build/config.mk
+++ b/source4/heimdal_build/config.mk
@@ -191,6 +191,7 @@ ADD_OBJ_FILES = \
../heimdal/lib/asn1/der_copy.o \
../heimdal/lib/asn1/der_cmp.o \
../heimdal/lib/asn1/asn1_AD_IF_RELEVANT.o \
+ ../heimdal/lib/asn1/asn1_AD_KDCIssued.o \
../heimdal/lib/asn1/asn1_APOptions.o \
../heimdal/lib/asn1/asn1_AP_REP.o \
../heimdal/lib/asn1/asn1_AP_REQ.o \