krb5_authdata **elements;
} krb5_ad_kdcissued;
+typedef struct _krb5_ad_signedpath_data {
+ krb5_principal client;
+ krb5_timestamp authtime;
+ krb5_principal *delegated;
+ krb5_pa_data **method_data;
+ krb5_authdata **authorization_data;
+} krb5_ad_signedpath_data;
+
+typedef struct _krb5_ad_signedpath {
+ krb5_enctype enctype;
+ krb5_checksum checksum;
+ krb5_principal *delegated;
+ krb5_pa_data **method_data;
+} krb5_ad_signedpath;
+
typedef krb5_error_code (*krb5_preauth_obtain_proc)
(krb5_context,
krb5_pa_data *,
(krb5_context, krb5_fast_response *);
void KRB5_CALLCONV krb5_free_ad_kdcissued
(krb5_context, krb5_ad_kdcissued *);
+void KRB5_CALLCONV krb5_free_ad_signedpath
+(krb5_context, krb5_ad_signedpath *);
/* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
#include "com_err.h"
krb5_error_code encode_krb5_ad_kdcissued
(const krb5_ad_kdcissued *, krb5_data **);
+krb5_error_code encode_krb5_ad_signedpath
+(const krb5_ad_signedpath *, krb5_data **);
+krb5_error_code encode_krb5_ad_signedpath_data
+(const krb5_ad_signedpath_data *, krb5_data **);
/*************************************************************************
* End of prototypes for krb5_encode.c
krb5_error_code decode_krb5_ad_kdcissued
(const krb5_data *, krb5_ad_kdcissued **);
+krb5_error_code decode_krb5_ad_signedpath
+(const krb5_data *, krb5_ad_signedpath **);
+
struct _krb5_key_data; /* kdb.h */
struct ldap_seqof_key_data {
krb5_ticket *evidence_tkt,
krb5_creds **out_creds);
+krb5_error_code KRB5_CALLCONV
+krb5int_get_authdata_containee_types(krb5_context context,
+ const krb5_authdata *container,
+ unsigned int *nad_types,
+ krb5_authdatatype **ad_types);
+
krb5_error_code krb5int_parse_enctype_list(krb5_context context, char *profstr,
krb5_enctype *default_list,
krb5_enctype **result);
#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REQUEST 26 /* XXX note conflict with above */
#define KRB5_KEYUSAGE_PA_S4U_X509_USER_REPLY 27 /* XXX note conflict with above */
+#define KRB5_KEYUSAGE_AD_SIGNEDPATH -21
+
/* define in draft-ietf-krb-wg-preauth-framework*/
#define KRB5_KEYUSAGE_FAST_REQ_CHKSUM 50
#define KRB5_KEYUSAGE_FAST_ENC 51
#define KRB5_AUTHDATA_SESAME 65
#define KRB5_AUTHDATA_WIN2K_PAC 128
#define KRB5_AUTHDATA_ETYPE_NEGOTIATION 129 /* RFC 4537 */
+#define KRB5_AUTHDATA_SIGNTICKET 142
#define KRB5_AUTHDATA_FX_ARMOR 71
/* password change constants */
krb5_keyblock encrypting_key;
int nprincs = 0;
krb5_boolean more;
- krb5_timestamp kdc_time, authtime=0;
+ krb5_timestamp kdc_time, authtime = 0;
krb5_keyblock session_key;
krb5_timestamp rtime;
krb5_keyblock *reply_key = NULL;
register int i;
int firstpass = 1;
const char *status = 0;
- krb5_enc_tkt_part *header_enc_tkt = NULL; /* TG or evidence ticket */
+ krb5_enc_tkt_part *header_enc_tkt = NULL; /* TGT */
+ krb5_enc_tkt_part *subject_tkt = NULL; /* TGT or evidence ticket */
krb5_db_entry client, krbtgt;
int c_nprincs = 0, k_nprincs = 0;
krb5_pa_s4u_x509_user *s4u_x509_user = NULL; /* protocol transition request */
reply.padata = 0; /* For cleanup handler */
reply_encpart.enc_padata = 0;
+ e_data.data = NULL;
session_key.contents = NULL;
assert(krb5_is_tgs_principal(header_ticket->server));
- /* From now on, use evidence ticket as header ticket */
- header_enc_tkt = request->second_ticket[st_idx]->enc_part2;
-
assert(c_nprincs == 0); /* assured by kdc_process_s4u2self_req() */
client = st_client;
goto cleanup;
}
- authtime = header_enc_tkt->times.authtime;
+ /*
+ * subject_tkt will refer to the evidence ticket (for constrained
+ * delegation) or the TGT. The distinction from header_enc_tkt is
+ * necessary because the TGS signature only protects some fields:
+ * the others could be forged by a malicious server.
+ */
+
+ if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))
+ subject_tkt = request->second_ticket[st_idx]->enc_part2;
+ else
+ subject_tkt = header_enc_tkt;
+ authtime = subject_tkt->times.authtime;
if (is_referral)
ticket_reply.server = server.princ;
* authtime's value.
*/
if (!(header_enc_tkt->times.starttime))
- header_enc_tkt->times.starttime = header_enc_tkt->times.authtime;
+ header_enc_tkt->times.starttime = authtime;
/* don't use new addresses unless forwarded, see below */
}
/*
- * Set authtime to be the same as header_ticket's
+ * Set authtime to be the same as header or evidence ticket's
*/
- enc_tkt_reply.times.authtime = header_enc_tkt->times.authtime;
+ enc_tkt_reply.times.authtime = authtime;
/*
* Propagate the preauthentication flags through to the returned ticket.
errcode = krb5_unparse_name(kdc_context, s4u_x509_user->user_id.user,
&s4u_name);
} else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
- errcode = krb5_unparse_name(kdc_context, header_enc_tkt->client,
+ errcode = krb5_unparse_name(kdc_context, subject_tkt->client,
&s4u_name);
} else {
errcode = 0;
if (isflagset(server.attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED) == 0) {
/*
* If we are not doing protocol transition/constrained delegation
- * and there was no authorization data included, try to lookup
- * the client principal as it may be mapped to a local account.
+ * try to lookup the client principal so plugins can add additional
+ * authorization information.
*
* Always validate authorization data for constrained delegation
* because we must validate the KDC signatures.
*/
- if (!isflagset(c_flags, KRB5_KDB_FLAGS_S4U) &&
- header_enc_tkt->authorization_data == NULL) {
-
+ if (!isflagset(c_flags, KRB5_KDB_FLAGS_S4U)) {
/* Generate authorization data so we can include it in ticket */
setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
/* Map principals from foreign (possibly non-AD) realms */
c_nprincs = 1;
errcode = krb5_db_get_principal_ext(kdc_context,
- header_enc_tkt->client,
+ subject_tkt->client,
c_flags,
&client,
&c_nprincs,
!isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM))
enc_tkt_reply.client = s4u_x509_user->user_id.user;
else
- enc_tkt_reply.client = header_enc_tkt->client;
+ enc_tkt_reply.client = subject_tkt->client;
enc_tkt_reply.session = &session_key;
enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
request,
s4u_x509_user ?
s4u_x509_user->user_id.user : NULL,
- header_enc_tkt,
+ subject_tkt,
&enc_tkt_reply);
if (errcode) {
krb5_klog_syslog(LOG_INFO, "TGS_REQ : handle_authdata (%d)", errcode);
reply_encpart.session = &session_key;
reply_encpart.nonce = request->nonce;
- /* copy the time fields EXCEPT for authtime; its location
- is used for ktime */
+ /* copy the time fields */
reply_encpart.times = enc_tkt_reply.times;
- reply_encpart.times.authtime = header_enc_tkt->times.authtime;
/* starttime is optional, and treated as authtime if not present.
so we can nuke it if it matches */
* kdc/kdc_authdata.c
*
* Copyright (C) 2007 Apple Inc. All Rights Reserved.
- * Copyright (C) 2008 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2008, 2009 by the Massachusetts Institute of Technology.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
#include <syslog.h>
#include <assert.h>
-#include "../include/krb5/authdata_plugin.h"
+#include <krb5/authdata_plugin.h>
#if TARGET_OS_MAC
static const char *objdirs[] = { KRB5_AUTHDATA_PLUGIN_BUNDLE_DIR,
typedef void (*fini_proc)
(krb5_context, void *);
-/* Internal authdata system for copying TGS-REQ authdata to ticket */
static krb5_error_code handle_request_authdata
(krb5_context context,
unsigned int flags,
krb5_enc_tkt_part *enc_tkt_request,
krb5_enc_tkt_part *enc_tkt_reply);
-/* Internal authdata system for handling KDC-issued authdata */
static krb5_error_code handle_tgt_authdata
(krb5_context context,
unsigned int flags,
krb5_enc_tkt_part *enc_tkt_request,
krb5_enc_tkt_part *enc_tkt_reply);
+static krb5_error_code
+handle_kdb_authdata(krb5_context context, unsigned int flags,
+ krb5_db_entry *client, krb5_db_entry *server,
+ krb5_db_entry *krbtgt, krb5_keyblock *client_key,
+ krb5_keyblock *server_key, krb5_keyblock *krbtgt_key,
+ krb5_data *req_pkt, krb5_kdc_req *request,
+ krb5_const_principal for_user_princ,
+ krb5_enc_tkt_part *enc_tkt_request,
+ krb5_enc_tkt_part *enc_tkt_reply);
+
+static krb5_error_code
+handle_signedpath_authdata(krb5_context context, unsigned int flags,
+ krb5_db_entry *client, krb5_db_entry *server,
+ krb5_db_entry *krbtgt, krb5_keyblock *client_key,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_data *req_pkt, krb5_kdc_req *request,
+ krb5_const_principal for_user_princ,
+ krb5_enc_tkt_part *enc_tkt_request,
+ krb5_enc_tkt_part *enc_tkt_reply);
+
typedef struct _krb5_authdata_systems {
const char *name;
#define AUTHDATA_SYSTEM_UNKNOWN -1
#define AUTHDATA_SYSTEM_V2 2
int type;
#define AUTHDATA_FLAG_CRITICAL 0x1
+#define AUTHDATA_FLAG_PRE_PLUGIN 0x2
int flags;
void *plugin_context;
init_proc init;
} krb5_authdata_systems;
static krb5_authdata_systems static_authdata_systems[] = {
- { "tgs_req", AUTHDATA_SYSTEM_V2, AUTHDATA_FLAG_CRITICAL,
- NULL, NULL, NULL, { handle_request_authdata } },
- { "tgt", AUTHDATA_SYSTEM_V2, AUTHDATA_FLAG_CRITICAL,
- NULL, NULL, NULL, { handle_tgt_authdata } },
+ {
+ /* Propagate client-submitted authdata */
+ "tgs_req",
+ AUTHDATA_SYSTEM_V2,
+ AUTHDATA_FLAG_CRITICAL | AUTHDATA_FLAG_PRE_PLUGIN,
+ NULL,
+ NULL,
+ NULL,
+ { handle_request_authdata }
+ },
+ {
+ /* Propagate TGT authdata */
+ "tgt",
+ AUTHDATA_SYSTEM_V2,
+ AUTHDATA_FLAG_CRITICAL,
+ NULL,
+ NULL,
+ NULL,
+ { handle_tgt_authdata }
+ },
+ {
+ /* Verify and issue KDB issued authdata */
+ "kdb",
+ AUTHDATA_SYSTEM_V2,
+ AUTHDATA_FLAG_CRITICAL,
+ NULL,
+ NULL,
+ NULL,
+ { handle_kdb_authdata }
+ },
+ {
+ /* Verify and issue signed delegation path */
+ "signedpath",
+ AUTHDATA_SYSTEM_V2,
+ AUTHDATA_FLAG_CRITICAL,
+ NULL,
+ NULL,
+ NULL,
+ { handle_signedpath_authdata }
+ }
};
static krb5_authdata_systems *authdata_systems;
k = 0;
+ /*
+ * Special case to ensure that handle_request_authdata is
+ * first in the list, to make unenc_authdata available to
+ * plugins.
+ */
+ for (i = 0; i < (sizeof(static_authdata_systems) /
+ sizeof(static_authdata_systems[0])); i++) {
+ if ((static_authdata_systems[i].flags & AUTHDATA_FLAG_PRE_PLUGIN) == 0)
+ continue;
+ assert(static_authdata_systems[i].init == NULL);
+ authdata_systems[k++] = static_authdata_systems[i];
+ }
+
/* Add dynamically loaded V2 plugins */
if (authdata_plugins_ftables_v2 != NULL) {
struct krb5plugin_authdata_server_ftable_v2 *ftable;
}
}
- /* Add the locally-supplied mechanisms to the dynamic list first. */
for (i = 0;
i < sizeof(static_authdata_systems) / sizeof(static_authdata_systems[0]);
i++) {
- authdata_systems[k] = static_authdata_systems[i];
- /* Try to initialize the authdata system. If it fails, we'll remove it
- * from the list of systems we'll be using. */
- server_init_proc = static_authdata_systems[i].init;
- if ((server_init_proc != NULL) &&
- ((*server_init_proc)(context, &authdata_systems[k].plugin_context) != 0)) {
- memset(&authdata_systems[k], 0, sizeof(authdata_systems[k]));
+ if (static_authdata_systems[i].flags & AUTHDATA_FLAG_PRE_PLUGIN)
continue;
- }
- k++;
+ assert(static_authdata_systems[i].init == NULL);
+ authdata_systems[k++] = static_authdata_systems[i];
}
n_authdata_systems = k;
return 0;
}
-/* Merge authdata. If copy == 0, in_authdata is invalid on return */
+/*
+ * Returns TRUE if authdata should be filtered when copying from
+ * untrusted authdata.
+ */
+static krb5_boolean
+is_kdc_issued_authdatum (krb5_context context,
+ krb5_authdata *authdata,
+ krb5_authdatatype desired_type)
+{
+ krb5_boolean ret = FALSE;
+ krb5_authdatatype ad_type;
+ unsigned int i, count = 0;
+ krb5_authdatatype *ad_types = NULL;
+
+ if (authdata->ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
+ if (krb5int_get_authdata_containee_types(context,
+ authdata,
+ &count,
+ &ad_types) != 0)
+ goto cleanup;
+ } else {
+ ad_type = authdata->ad_type;
+ count = 1;
+ ad_types = &ad_type;
+ }
+
+ for (i = 0; i < count; i++) {
+ switch (ad_types[i]) {
+ case KRB5_AUTHDATA_SIGNTICKET:
+ case KRB5_AUTHDATA_KDC_ISSUED:
+ case KRB5_AUTHDATA_WIN2K_PAC:
+ ret = desired_type ? (desired_type == ad_types[i]) : TRUE;
+ break;
+ default:
+ ret = FALSE;
+ break;
+ }
+ if (ret)
+ break;
+ }
+
+cleanup:
+ if (authdata->ad_type == KRB5_AUTHDATA_IF_RELEVANT &&
+ ad_types != NULL)
+ free(ad_types);
+
+ return ret;
+}
+
+static krb5_boolean
+has_kdc_issued_authdata (krb5_context context,
+ krb5_authdata **authdata,
+ krb5_authdatatype desired_type)
+{
+ int i;
+ krb5_boolean ret = FALSE;
+
+ if (authdata != NULL) {
+ for (i = 0; authdata[i] != NULL; i++) {
+ if (is_kdc_issued_authdatum(context, authdata[i], desired_type)) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static krb5_boolean
+has_mandatory_for_kdc_authdata (krb5_context context,
+ krb5_authdata **authdata)
+{
+ int i;
+ krb5_boolean ret = FALSE;
+
+ if (authdata != NULL) {
+ for (i = 0; authdata[i] != NULL; i++) {
+ if (authdata[0]->ad_type == KRB5_AUTHDATA_MANDATORY_FOR_KDC) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Merge authdata.
+ *
+ * If copy is FALSE, in_authdata is invalid on successful return.
+ * If ignore_kdc_issued is TRUE, KDC-issued authdata is not copied.
+ */
static krb5_error_code
merge_authdata (krb5_context context,
krb5_authdata **in_authdata,
krb5_authdata ***out_authdata,
- krb5_boolean copy)
+ krb5_boolean copy,
+ krb5_boolean ignore_kdc_issued)
{
size_t i, nadata = 0;
krb5_authdata **authdata = *out_authdata;
authdata = (krb5_authdata **)calloc(i + 1, sizeof(krb5_authdata *));
} else {
authdata = (krb5_authdata **)realloc(authdata,
- ((nadata + i + 1) * sizeof(krb5_authdata *)));
+ ((nadata + i + 1) * sizeof(krb5_authdata *)));
}
if (authdata == NULL)
return ENOMEM;
in_authdata = tmp;
}
- for (i = 0; in_authdata[i] != NULL; i++)
- authdata[nadata + i] = in_authdata[i];
+ for (i = 0; in_authdata[i] != NULL; i++) {
+ if (ignore_kdc_issued &&
+ is_kdc_issued_authdatum(context, in_authdata[i], 0)) {
+ free(in_authdata[i]->contents);
+ free(in_authdata[i]);
+ } else
+ authdata[nadata + i] = in_authdata[i];
+ }
authdata[nadata + i] = NULL;
free(in_authdata);
+ if (authdata[0] == NULL) {
+ free(authdata);
+ authdata = NULL;
+ }
+
*out_authdata = authdata;
return 0;
free(scratch.data);
- code = merge_authdata(context, request->unenc_authdata,
- &enc_tkt_reply->authorization_data, TRUE /* copy */);
+ if (has_mandatory_for_kdc_authdata(context, request->unenc_authdata))
+ return KRB5KDC_ERR_POLICY;
+
+ code = merge_authdata(context,
+ request->unenc_authdata,
+ &enc_tkt_reply->authorization_data,
+ TRUE, /* copy */
+ TRUE); /* ignore_kdc_issued */
return code;
}
-/* Handle backend-managed authorization data */
+/* Handle copying TGT authorization data into reply */
static krb5_error_code
handle_tgt_authdata (krb5_context context,
unsigned int flags,
krb5_const_principal for_user_princ,
krb5_enc_tkt_part *enc_tkt_request,
krb5_enc_tkt_part *enc_tkt_reply)
+{
+ if (request->msg_type != KRB5_TGS_REQ)
+ return 0;
+
+ if (has_mandatory_for_kdc_authdata(context,
+ enc_tkt_request->authorization_data))
+ return KRB5KDC_ERR_POLICY;
+
+ return merge_authdata(context,
+ enc_tkt_request->authorization_data,
+ &enc_tkt_reply->authorization_data,
+ TRUE, /* copy */
+ TRUE); /* ignore_kdc_issued */
+}
+
+/* Handle backend-managed authorization data */
+static krb5_error_code
+handle_kdb_authdata (krb5_context context,
+ unsigned int flags,
+ krb5_db_entry *client,
+ krb5_db_entry *server,
+ krb5_db_entry *krbtgt,
+ krb5_keyblock *client_key,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_const_principal for_user_princ,
+ krb5_enc_tkt_part *enc_tkt_request,
+ krb5_enc_tkt_part *enc_tkt_reply)
{
krb5_error_code code;
krb5_authdata **db_authdata = NULL;
* or protocol transition/constrained delegation was used, or, in
* the AS-REQ case, if the pre-auth data indicated the PAC should
* be present.
- *
- * We permit sign_authorization_data() to return a krb5_db_entry
- * representing the principal associated with the authorization
- * data, in case that principal is not local to our realm and we
- * need to perform additional checks (such as disabling delegation
- * for cross-realm protocol transition below).
*/
if (tgs_req) {
assert(enc_tkt_request != NULL);
else
actual_client = enc_tkt_reply->client;
- /*
- * If the backend does not implement the sign authdata method, then
- * just copy the TGT authorization data into the reply, except for
- * the constrained delegation case (which requires special handling
- * because it will promote untrusted auth data to KDC issued auth
- * data; this requires backend-specific code)
- *
- * Presently this interface does not support using request auth data
- * to influence (eg. possibly restrict) the reply auth data.
- */
code = sign_db_authdata(context,
flags,
actual_client,
tgs_req ? enc_tkt_request->authorization_data : NULL,
enc_tkt_reply->session,
&db_authdata);
- if (code == KRB5_KDB_DBTYPE_NOSUP) {
- assert(db_authdata == NULL);
-
- if (isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))
- return KRB5KDC_ERR_POLICY;
-
- if (tgs_req)
- return merge_authdata(context, enc_tkt_request->authorization_data,
- &enc_tkt_reply->authorization_data, TRUE);
- else
- return 0;
- }
-
- if (db_authdata != NULL) {
- code = merge_authdata(context, db_authdata,
+ if (code == 0) {
+ code = merge_authdata(context,
+ db_authdata,
&enc_tkt_reply->authorization_data,
- FALSE);
+ FALSE, /* !copy */
+ FALSE); /* !ignore_kdc_issued */
if (code != 0)
krb5_free_authdata(context, db_authdata);
- }
+ } else if (code == KRB5_KDB_DBTYPE_NOSUP)
+ code = 0;
return code;
}
return code;
}
+
+static krb5_error_code
+make_ad_signedpath_data(krb5_context context,
+ krb5_const_principal client,
+ krb5_timestamp authtime,
+ krb5_principal *deleg_path,
+ krb5_pa_data **method_data,
+ krb5_authdata **authdata,
+ krb5_data **data)
+{
+ krb5_ad_signedpath_data sp_data;
+ krb5_authdata **sign_authdata = NULL;
+ int i, j;
+ krb5_error_code code;
+
+ memset(&sp_data, 0, sizeof(sp_data));
+
+ if (authdata != NULL) {
+ for (i = 0; authdata[i] != NULL; i++)
+ ;
+ } else
+ i = 0;
+
+ if (i != 0) {
+ sign_authdata = k5alloc((i + 1) * sizeof(krb5_authdata *), &code);
+ if (code != 0)
+ return code;
+
+ for (i = 0, j = 0; authdata[i] != NULL; i++) {
+ if (is_kdc_issued_authdatum(context, authdata[i],
+ KRB5_AUTHDATA_SIGNTICKET))
+ continue;
+
+ sign_authdata[j++] = authdata[i];
+ }
+
+ sign_authdata[j] = NULL;
+ }
+
+ sp_data.client = (krb5_principal)client;
+ sp_data.authtime = authtime;
+ sp_data.delegated = deleg_path;
+ sp_data.method_data = method_data;
+ sp_data.authorization_data = sign_authdata;
+
+ code = encode_krb5_ad_signedpath_data(&sp_data, data);
+
+ if (sign_authdata != NULL)
+ free(sign_authdata);
+
+ return code;
+}
+
+static krb5_error_code
+verify_ad_signedpath_checksum(krb5_context context,
+ const krb5_db_entry *krbtgt,
+ krb5_keyblock *krbtgt_key,
+ krb5_enc_tkt_part *enc_tkt_part,
+ krb5_principal *deleg_path,
+ krb5_pa_data **method_data,
+ krb5_checksum *cksum,
+ krb5_boolean *valid)
+{
+ krb5_error_code code;
+ krb5_data *data;
+
+ *valid = FALSE;
+
+ if (!krb5_c_is_keyed_cksum(cksum->checksum_type))
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+
+ code = make_ad_signedpath_data(context,
+ enc_tkt_part->client,
+ enc_tkt_part->times.authtime,
+ deleg_path,
+ method_data,
+ enc_tkt_part->authorization_data,
+ &data);
+ if (code != 0)
+ return code;
+
+ code = krb5_c_verify_checksum(context,
+ krbtgt_key,
+ KRB5_KEYUSAGE_AD_SIGNEDPATH,
+ data,
+ cksum,
+ valid);
+
+ krb5_free_data(context, data);
+
+ if (code == 0 && *valid == FALSE)
+ code = KRB5KRB_AP_ERR_MODIFIED;
+
+ return code;
+}
+
+
+static krb5_error_code
+verify_ad_signedpath(krb5_context context,
+ krb5_db_entry *krbtgt,
+ krb5_keyblock *krbtgt_key,
+ krb5_enc_tkt_part *enc_tkt_part,
+ krb5_principal **pdelegated,
+ krb5_boolean *path_is_signed)
+{
+ krb5_error_code code;
+ krb5_ad_signedpath *sp = NULL;
+ krb5_authdata **sp_authdata = NULL;
+ krb5_data enc_sp;
+
+ *pdelegated = NULL;
+ *path_is_signed = FALSE;
+
+ code = krb5int_find_authdata(context,
+ enc_tkt_part->authorization_data,
+ NULL,
+ KRB5_AUTHDATA_SIGNTICKET,
+ &sp_authdata);
+ if (code != 0)
+ goto cleanup;
+
+ if (sp_authdata == NULL ||
+ sp_authdata[0]->ad_type != KRB5_AUTHDATA_SIGNTICKET ||
+ sp_authdata[1] != NULL)
+ goto cleanup;
+
+ enc_sp.data = (char *)sp_authdata[0]->contents;
+ enc_sp.length = sp_authdata[0]->length;
+
+ code = decode_krb5_ad_signedpath(&enc_sp, &sp);
+ if (code != 0)
+ goto cleanup;
+
+ code = verify_ad_signedpath_checksum(context,
+ krbtgt,
+ krbtgt_key,
+ enc_tkt_part,
+ sp->delegated,
+ sp->method_data,
+ &sp->checksum,
+ path_is_signed);
+ if (code != 0)
+ goto cleanup;
+
+ *pdelegated = sp->delegated;
+ sp->delegated = NULL;
+
+cleanup:
+ krb5_free_ad_signedpath(context, sp);
+ krb5_free_authdata(context, sp_authdata);
+
+ return code;
+}
+
+static krb5_error_code
+make_ad_signedpath_checksum(krb5_context context,
+ krb5_const_principal for_user_princ,
+ const krb5_db_entry *krbtgt,
+ krb5_keyblock *krbtgt_key,
+ krb5_enc_tkt_part *enc_tkt_part,
+ krb5_principal *deleg_path,
+ krb5_pa_data **method_data,
+ krb5_checksum *cksum)
+{
+ krb5_error_code code;
+ krb5_data *data;
+ krb5_cksumtype cksumtype;
+ krb5_const_principal client;
+
+ if (for_user_princ != NULL)
+ client = for_user_princ;
+ else
+ client = enc_tkt_part->client;
+
+ code = make_ad_signedpath_data(context,
+ client,
+ enc_tkt_part->times.authtime,
+ deleg_path,
+ method_data,
+ enc_tkt_part->authorization_data,
+ &data);
+ if (code != 0)
+ return code;
+
+ code = krb5int_c_mandatory_cksumtype(context,
+ krbtgt_key->enctype,
+ &cksumtype);
+ if (code != 0) {
+ krb5_free_data(context, data);
+ return code;
+ }
+
+ if (!krb5_c_is_keyed_cksum(cksumtype)) {
+ krb5_free_data(context, data);
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+ }
+
+ code = krb5_c_make_checksum(context, cksumtype, krbtgt_key,
+ KRB5_KEYUSAGE_AD_SIGNEDPATH, data,
+ cksum);
+
+ krb5_free_data(context, data);
+
+ return code;
+}
+
+static krb5_error_code
+make_ad_signedpath(krb5_context context,
+ krb5_const_principal for_user_princ,
+ krb5_principal server,
+ const krb5_db_entry *krbtgt,
+ krb5_keyblock *krbtgt_key,
+ krb5_principal *deleg_path,
+ krb5_enc_tkt_part *enc_tkt_reply)
+{
+ krb5_error_code code;
+ krb5_ad_signedpath sp;
+ int i;
+ krb5_data *data = NULL;
+ krb5_authdata ad_datum, *ad_data[2];
+ krb5_authdata **if_relevant = NULL;
+
+ memset(&sp, 0, sizeof(sp));
+
+ sp.enctype = krbtgt_key->enctype;
+
+ if (deleg_path != NULL) {
+ for (i = 0; deleg_path[i] != NULL; i++)
+ ;
+ } else
+ i = 0;
+
+ sp.delegated = k5alloc((i + (server ? 1 : 0) + 1) *
+ sizeof(krb5_principal), &code);
+ if (code != 0)
+ goto cleanup;
+
+ /* Combine existing and new transited services, if any */
+ if (deleg_path != NULL)
+ memcpy(sp.delegated, deleg_path, i * sizeof(krb5_principal));
+ if (server != NULL)
+ sp.delegated[i++] = server;
+ sp.delegated[i] = NULL;
+ sp.method_data = NULL;
+
+ code = make_ad_signedpath_checksum(context,
+ for_user_princ,
+ krbtgt,
+ krbtgt_key,
+ enc_tkt_reply,
+ sp.delegated,
+ sp.method_data,
+ &sp.checksum);
+ if (code != 0) {
+ if (code == KRB5KRB_AP_ERR_INAPP_CKSUM) {
+ /*
+ * In the hopefully unlikely case the TGS key enctype
+ * has an unkeyed mandatory checksum type, do not fail
+ * so we do not prevent the KDC from servicing requests.
+ */
+ code = 0;
+ }
+ goto cleanup;
+ }
+
+ code = encode_krb5_ad_signedpath(&sp, &data);
+ if (code != 0)
+ goto cleanup;
+
+ ad_datum.ad_type = KRB5_AUTHDATA_SIGNTICKET;
+ ad_datum.contents = (krb5_octet *)data->data;
+ ad_datum.length = data->length;
+
+ ad_data[0] = &ad_datum;
+ ad_data[1] = NULL;
+
+ code = krb5_encode_authdata_container(context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ ad_data,
+ &if_relevant);
+ if (code != 0)
+ goto cleanup;
+
+ code = merge_authdata(context,
+ if_relevant,
+ &enc_tkt_reply->authorization_data,
+ FALSE, /* !copy */
+ FALSE); /* !ignore_kdc_issued */
+ if (code != 0)
+ goto cleanup;
+
+ if_relevant = NULL; /* merge_authdata() freed */
+
+cleanup:
+ if (sp.delegated != NULL)
+ free(sp.delegated);
+ krb5_free_authdata(context, if_relevant);
+ krb5_free_data(context, data);
+ krb5_free_checksum_contents(context, &sp.checksum);
+ krb5_free_pa_data(context, sp.method_data);
+
+ return code;
+}
+
+static void
+free_deleg_path(krb5_context context, krb5_principal *deleg_path)
+{
+ if (deleg_path != NULL) {
+ int i;
+
+ for (i = 0; deleg_path[i] != NULL; i++)
+ krb5_free_principal(context, deleg_path[i]);
+ free(deleg_path);
+ }
+}
+
+/*
+ * Returns TRUE if the Windows 2000 PAC is the only element in the
+ * supplied authorization data.
+ */
+static krb5_boolean
+only_pac_p(krb5_context context, krb5_authdata **authdata)
+{
+ return has_kdc_issued_authdata(context,
+ authdata, KRB5_AUTHDATA_WIN2K_PAC) &&
+ (authdata[1] == NULL);
+}
+
+static krb5_error_code
+handle_signedpath_authdata (krb5_context context,
+ unsigned int flags,
+ krb5_db_entry *client,
+ krb5_db_entry *server,
+ krb5_db_entry *krbtgt,
+ krb5_keyblock *client_key,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_const_principal for_user_princ,
+ krb5_enc_tkt_part *enc_tkt_request,
+ krb5_enc_tkt_part *enc_tkt_reply)
+{
+ krb5_error_code code = 0;
+ krb5_principal *deleg_path = NULL;
+ krb5_boolean signed_path = FALSE;
+ krb5_boolean s4u2proxy;
+
+ s4u2proxy = isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
+
+ /*
+ * The Windows PAC fulfils the same role as the signed path
+ * if it is the only authorization data element.
+ */
+ if (request->msg_type == KRB5_TGS_REQ &&
+ !only_pac_p(context, enc_tkt_request->authorization_data)) {
+ code = verify_ad_signedpath(context,
+ krbtgt,
+ krbtgt_key,
+ enc_tkt_request,
+ &deleg_path,
+ &signed_path);
+ if (code != 0)
+ goto cleanup;
+
+ if (s4u2proxy && signed_path == FALSE) {
+ code = KRB5KDC_ERR_BADOPTION;
+ goto cleanup;
+ }
+ }
+
+ if (!isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM) &&
+ !only_pac_p(context, enc_tkt_reply->authorization_data)) {
+ code = make_ad_signedpath(context,
+ for_user_princ,
+ s4u2proxy ? client->princ : NULL,
+ krbtgt,
+ krbtgt_key,
+ deleg_path,
+ enc_tkt_reply);
+ if (code != 0)
+ goto cleanup;
+ }
+
+cleanup:
+ free_deleg_path(context, deleg_path);
+
+ return code;
+}
return retval;
}
+static asn1_error_code asn1_peek_authdata_elt(asn1buf *buf, krb5_authdatatype *val)
+{
+ setup();
+ *val = 0;
+ { begin_structure();
+ get_field(*val, 0, asn1_decode_authdatatype);
+ end_structure();
+ }
+ return 0;
+error_out:
+ return retval;
+}
+
+asn1_error_code asn1_peek_authorization_data
+(asn1buf *buf, unsigned int *num, krb5_authdatatype **val)
+{
+ int size = 0;
+ krb5_authdatatype *array = NULL, *new_array;
+
+ asn1_error_code retval;
+ { sequence_of(buf);
+ while (asn1buf_remains(&seqbuf,seqofindef) > 0) {
+ size++;
+ new_array = realloc(array,size*sizeof(krb5_authdatatype));
+ if (new_array == NULL) clean_return(ENOMEM);
+ array = new_array;
+ retval = asn1_peek_authdata_elt(&seqbuf,&array[size-1]);
+ if (retval) clean_return(retval);
+ }
+ end_sequence_of(buf);
+ }
+ *num = size;
+ *val = array;
+ return 0;
+error_out:
+ free(array);
+ return retval;
+}
+
asn1_error_code
asn1_decode_authdata_elt_ptr(asn1buf *buf, krb5_authdata **valptr)
{
return retval;
}
+static asn1_error_code asn1_decode_princ_plus_realm
+(asn1buf *buf, krb5_principal *valptr)
+{
+ setup();
+ alloc_principal((*valptr));
+ { begin_structure();
+ get_field((*valptr), 0, asn1_decode_principal_name);
+ get_field((*valptr), 1, asn1_decode_realm);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_principal(NULL, *valptr);
+ *valptr = NULL;
+ return retval;
+}
+
+static asn1_error_code asn1_decode_sequence_of_princ_plus_realm
+(asn1buf *buf, krb5_principal **val)
+{
+ decode_array_body(krb5_principal_data,asn1_decode_princ_plus_realm,krb5_free_principal);
+}
+
+asn1_error_code asn1_decode_ad_signedpath
+(asn1buf *buf, krb5_ad_signedpath *val)
+{
+ setup();
+ val->enctype = ENCTYPE_NULL;
+ val->checksum.contents = NULL;
+ val->delegated = NULL;
+ {
+ begin_structure();
+ get_field(val->enctype, 0, asn1_decode_enctype);
+ get_field(val->checksum, 1, asn1_decode_checksum);
+ opt_field(val->delegated, 2, asn1_decode_sequence_of_princ_plus_realm,
+ NULL);
+ opt_field(val->method_data, 3, asn1_decode_sequence_of_pa_data, NULL);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_checksum_contents(NULL, &val->checksum);
+ return retval;
+}
+
#ifndef DISABLE_PKINIT
/* PKINIT */
asn1_error_code asn1_decode_authdata_elt(asn1buf *buf, krb5_authdata *val);
asn1_error_code asn1_decode_authdata_elt_ptr(asn1buf *buf,
krb5_authdata **valptr);
+asn1_error_code asn1_peek_authorization_data(asn1buf *buf,
+ unsigned int *num,
+ krb5_authdatatype **val);
asn1_error_code asn1_decode_krb_cred_info(asn1buf *buf, krb5_cred_info *val);
asn1_error_code asn1_decode_krb_cred_info_ptr(asn1buf *buf,
krb5_cred_info **valptr);
asn1_error_code asn1_decode_ad_kdcissued_ptr(asn1buf *buf,
krb5_ad_kdcissued **val);
+asn1_error_code asn1_decode_ad_signedpath(asn1buf *buf,
+ krb5_ad_signedpath *val);
+
#endif
FIELDOF_NORM(krb5_principal_data, gstring_data, realm, -1));
DEFPTRTYPE(realm_of_principal, realm_of_principal_data);
-
static const struct field_info princname_fields[] = {
FIELDOF_NORM(krb5_principal_data, int32, type, 0),
FIELDOF_SEQOF_INT32(krb5_principal_data, gstring_data_ptr, data, length, 1),
DEFSEQTYPE(ad_kdc_issued, krb5_ad_kdcissued, ad_kdcissued_fields, ad_kdcissued_optional);
+static const struct field_info princ_plus_realm_fields[] = {
+ FIELDOF_ENCODEAS(krb5_principal_data, principal_data, 0),
+ FIELDOF_ENCODEAS(krb5_principal_data, realm_of_principal_data, 1),
+};
+
+DEFSEQTYPE(princ_plus_realm_data, krb5_principal_data, princ_plus_realm_fields, 0);
+DEFPTRTYPE(princ_plus_realm, princ_plus_realm_data);
+
+DEFNULLTERMSEQOFTYPE(seq_of_princ_plus_realm, princ_plus_realm);
+DEFPTRTYPE(ptr_seq_of_princ_plus_realm, seq_of_princ_plus_realm);
+
+static const struct field_info ad_signedpath_data_fields[] = {
+ FIELDOF_NORM(krb5_ad_signedpath_data, princ_plus_realm, client, 0),
+ FIELDOF_NORM(krb5_ad_signedpath_data, kerberos_time, authtime, 1),
+ FIELDOF_OPT(krb5_ad_signedpath_data, ptr_seq_of_princ_plus_realm, delegated, 2, 2),
+ FIELDOF_OPT(krb5_ad_signedpath_data, ptr_seqof_pa_data, method_data, 3, 3),
+ FIELDOF_OPT(krb5_ad_signedpath_data, auth_data_ptr, authorization_data, 4, 4),
+};
+
+static unsigned int ad_signedpath_data_optional(const void *p)
+{
+ unsigned int optional = 0;
+ const krb5_ad_signedpath_data *val = p;
+ if (val->delegated && val->delegated[0])
+ optional |= (1u << 2);
+ if (val->method_data && val->method_data[0])
+ optional |= (1u << 3);
+ if (val->authorization_data && val->authorization_data[0])
+ optional |= (1u << 4);
+ return optional;
+}
+
+DEFSEQTYPE(ad_signedpath_data, krb5_ad_signedpath_data, ad_signedpath_data_fields, ad_signedpath_data_optional);
+
+static const struct field_info ad_signedpath_fields[] = {
+ FIELDOF_NORM(krb5_ad_signedpath, int32, enctype, 0),
+ FIELDOF_NORM(krb5_ad_signedpath, checksum, checksum, 1),
+ FIELDOF_OPT(krb5_ad_signedpath, ptr_seq_of_princ_plus_realm, delegated, 2, 2),
+ FIELDOF_OPT(krb5_ad_signedpath, ptr_seqof_pa_data, method_data, 3, 3),
+};
+
+static unsigned int ad_signedpath_optional(const void *p)
+{
+ unsigned int optional = 0;
+ const krb5_ad_signedpath *val = p;
+ if (val->delegated && val->delegated[0])
+ optional |= (1u << 2);
+ if (val->method_data && val->method_data[0])
+ optional |= (1u << 3);
+ return optional;
+}
+DEFSEQTYPE(ad_signedpath, krb5_ad_signedpath, ad_signedpath_fields, ad_signedpath_optional);
/* Exported complete encoders -- these produce a krb5_data with
the encoding in the correct byte order. */
MAKE_FULL_ENCODER(encode_krb5_fast_response, fast_response);
MAKE_FULL_ENCODER(encode_krb5_ad_kdcissued, ad_kdc_issued);
+MAKE_FULL_ENCODER(encode_krb5_ad_signedpath_data, ad_signedpath_data);
+MAKE_FULL_ENCODER(encode_krb5_ad_signedpath, ad_signedpath);
cleanup(free);
}
+krb5_error_code decode_krb5_ad_signedpath
+(const krb5_data *code, krb5_ad_signedpath **repptr)
+{
+ setup_buf_only(krb5_ad_signedpath *);
+ alloc_field(rep);
+
+ retval = asn1_decode_ad_signedpath(&buf, rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
+krb5_error_code
+krb5int_get_authdata_containee_types(krb5_context context,
+ const krb5_authdata *authdata,
+ unsigned int *num,
+ krb5_authdatatype **repptr)
+{
+ krb5_data data, *code = &data;
+
+ data.data = (char *)authdata->contents;
+ data.length = authdata->length;
+
+ *num = 0;
+
+ {
+ setup_buf_only(krb5_authdatatype *);
+
+ retval = asn1_peek_authorization_data(&buf, num, &rep);
+ if (retval) clean_return(retval);
+
+ cleanup_none();
+ }
+ assert(0); /* NOTREACHED */
+}
+
#ifndef DISABLE_PKINIT
krb5_error_code
decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr)
static krb5_error_code
find_authdata_1(krb5_context context, krb5_authdata *const *in_authdat,
- krb5_authdatatype ad_type, struct find_authdata_context *fctx)
+ krb5_authdatatype ad_type, struct find_authdata_context *fctx,
+ int from_ap_req)
{
int i = 0;
- krb5_error_code retval=0;
+ krb5_error_code retval = 0;
for (i = 0; in_authdat[i]; i++) {
krb5_authdata *ad = in_authdat[i];
- if (ad->ad_type == ad_type && retval ==0)
- retval = grow_find_authdata(context, fctx, ad);
- else switch (ad->ad_type) {
- krb5_authdata **decoded_container;
- case KRB5_AUTHDATA_IF_RELEVANT:
- if (retval == 0)
- retval = krb5_decode_authdata_container( context, ad->ad_type, ad, &decoded_container);
- if (retval == 0) {
- retval = find_authdata_1(context,
- decoded_container, ad_type, fctx);
- krb5_free_authdata(context, decoded_container);
- }
- break;
- default:
- break;
+ krb5_authdata **decoded_container;
+
+ switch (ad->ad_type) {
+ case KRB5_AUTHDATA_IF_RELEVANT:
+ if (retval == 0)
+ retval = krb5_decode_authdata_container(context,
+ ad->ad_type,
+ ad,
+ &decoded_container);
+ if (retval == 0) {
+ retval = find_authdata_1(context,
+ decoded_container,
+ ad_type,
+ fctx,
+ from_ap_req);
+ krb5_free_authdata(context, decoded_container);
}
+ break;
+ case KRB5_AUTHDATA_SIGNTICKET:
+ case KRB5_AUTHDATA_KDC_ISSUED:
+ case KRB5_AUTHDATA_WIN2K_PAC:
+ if (from_ap_req)
+ continue;
+ default:
+ if (ad->ad_type == ad_type && retval == 0)
+ retval = grow_find_authdata(context, fctx, ad);
+ break;
+ }
}
+
return retval;
}
-
krb5_error_code
krb5int_find_authdata(krb5_context context,
krb5_authdata *const *ticket_authdata,
if (fctx.out == NULL)
return ENOMEM;
if (ticket_authdata)
- retval = find_authdata_1( context, ticket_authdata, ad_type, &fctx);
+ retval = find_authdata_1( context, ticket_authdata, ad_type, &fctx, 0);
if ((retval==0) && ap_req_authdata)
- retval = find_authdata_1( context, ap_req_authdata, ad_type, &fctx);
+ retval = find_authdata_1( context, ap_req_authdata, ad_type, &fctx, 1);
if ((retval== 0) && fctx.length)
*results = fctx.out;
else krb5_free_authdata(context, fctx.out);
if (code != 0)
return code;
+ if (!krb5_c_is_keyed_cksum(cksumtype))
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+
code = encode_krb5_authdata(ad_kdci.elements, &data);
if (code != 0)
return code;
if (code != 0)
return code;
+ if (!krb5_c_is_keyed_cksum(ad_kdci->ad_checksum.checksum_type)) {
+ krb5_free_ad_kdcissued(context, ad_kdci);
+ return KRB5KRB_AP_ERR_INAPP_CKSUM;
+ }
+
code = encode_krb5_authdata(ad_kdci->elements, &data2);
if (code != 0) {
krb5_free_ad_kdcissued(context, ad_kdci);
krb5_free_authdata(context, val->elements);
free(val);
}
+
+void KRB5_CALLCONV
+krb5_free_ad_signedpath(krb5_context context, krb5_ad_signedpath *val)
+{
+ int i;
+
+ if (val == NULL)
+ return;
+
+ krb5_free_checksum_contents(context, &val->checksum);
+ if (val->delegated != NULL) {
+ for (i = 0; val->delegated[i] != NULL; i++)
+ krb5_free_principal(context, val->delegated[i]);
+ free(val->delegated);
+ }
+ krb5_free_pa_data(context, val->method_data);
+}
_krb5_conf_boolean
decode_krb5_ad_kdcissued
+decode_krb5_ad_signedpath
decode_krb5_alt_method
decode_krb5_ap_rep
decode_krb5_ap_rep_enc_part
decode_krb5_ticket
decode_krb5_typed_data
encode_krb5_ad_kdcissued
+encode_krb5_ad_signedpath_data
+encode_krb5_ad_signedpath
encode_krb5_alt_method
encode_krb5_ap_rep
encode_krb5_ap_rep_enc_part
krb5_fcc_ops
krb5_find_serializer
krb5_free_ad_kdcissued
+krb5_free_ad_signedpath
krb5_free_address
krb5_free_addresses
krb5_free_alt_method
krb5int_foreach_localaddr
krb5int_free_addrlist
krb5int_free_data_list
+krb5int_get_authdata_containee_types
krb5int_get_domain_realm_mapping
krb5int_init_context_kdc
krb5int_initialize_library
NULL,
KRB5_AUTHDATA_KDC_ISSUED,
&tgt_authdata);
- if (code != 0)
+ if (code != 0 || tgt_authdata == NULL)
return 0;
code = krb5_verify_authdata_kdc_issued(context,
krb5_error_code code;
krb5_authdata ad_datum, *ad_data[2], **kdc_issued = NULL;
krb5_authdata **if_relevant = NULL;
+ krb5_authdata **tkt_authdata;
ad_datum.ad_type = -42;
ad_datum.contents = (krb5_octet *)greeting->data;
return code;
}
- /* this isn't very friendly to other plugins... */
- krb5_free_authdata(context, enc_tkt_reply->authorization_data);
- enc_tkt_reply->authorization_data = if_relevant;
+ code = krb5_merge_authdata(context,
+ if_relevant,
+ enc_tkt_reply->authorization_data,
+ &tkt_authdata);
+ if (code == 0) {
+ krb5_free_authdata(context, enc_tkt_reply->authorization_data);
+ enc_tkt_reply->authorization_data = tkt_authdata;
+ } else {
+ krb5_free_authdata(context, if_relevant);
+ }
krb5_free_authdata(context, kdc_issued);
- return 0;
+ return code;
}
static krb5_error_code
krb5_error_code code;
krb5_data *greeting = NULL;
- if (request->msg_type == KRB5_TGS_REQ) {
- code = greet_kdc_verify(context, enc_tkt_request, &greeting);
- if (code != 0)
- return code;
- }
+ if (request->msg_type != KRB5_TGS_REQ)
+ return 0;
- if (greeting == NULL) {
- code = greet_hello(context, &greeting);
- if (code != 0)
- return code;
- }
+ code = greet_hello(context, &greeting);
+ if (code != 0)
+ return code;
code = greet_kdc_sign(context, enc_tkt_reply, tgs->princ, greeting);
return code;
}
+static krb5_error_code
+krb5_ldap_check_allowed_to_delegate(krb5_context context,
+ unsigned int method,
+ const krb5_data *request,
+ krb5_data *response)
+{
+ const kdb_check_allowed_to_delegate_req *req;
+ krb5_error_code code;
+ krb5_tl_data *tlp;
+
+ req = (const kdb_check_allowed_to_delegate_req *)request->data;
+
+ code = KRB5KDC_ERR_POLICY;
+
+ for (tlp = req->server->tl_data; tlp != NULL; tlp = tlp->tl_data_next) {
+ krb5_principal acl;
+
+ if (tlp->tl_data_type != KRB5_TL_CONSTRAINED_DELEGATION_ACL)
+ continue;
+
+ if (krb5_parse_name(context, (char *)tlp->tl_data_contents, &acl) != 0)
+ continue;
+
+ if (krb5_principal_compare(context, req->proxy, acl)) {
+ code = 0;
+ krb5_free_principal(context, acl);
+ break;
+ }
+ krb5_free_principal(context, acl);
+ }
+
+ return code;
+}
+
krb5_error_code
krb5_ldap_invoke(krb5_context context,
unsigned int method,
case KRB5_KDB_METHOD_AUDIT_AS:
code = krb5_ldap_audit_as(context, method, req, rep);
break;
+ case KRB5_KDB_METHOD_CHECK_ALLOWED_TO_DELEGATE:
+ code = krb5_ldap_check_allowed_to_delegate(context, method, req, rep);
+ break;
default:
break;
}
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12)
+##### A list of services to which a service principal can delegate.
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributetype: ( 1.3.6.1.4.1.5322.21.2.4
+ NAME 'krbAllowedToDelegateTo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
########################################################################
########################################################################
objectClasses: ( 2.16.840.1.113719.1.301.6.8.1
NAME 'krbPrincipalAux'
AUXILIARY
- MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData ) )
+ MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo ) )
###### This class is used to create additional principals and stand alone principals.
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12)
+##### A list of services to which a service principal can delegate.
+attributetype ( 1.3.6.1.4.1.5322.21.2.4
+ NAME 'krbAllowedToDelegateTo'
+ EQUALITY caseExactIA5Match
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
+
########################################################################
########################################################################
# Object Class Definitions #
NAME 'krbPrincipalAux'
SUP top
AUXILIARY
- MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData ) )
+ MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo ) )
###### This class is used to create additional principals and stand alone principals.
}
}
+ /* ALLOWED TO DELEGATE TO */
+ {
+ char **a2d2 = NULL;
+ int i;
+ krb5_tl_data **tlp;
+
+ st = krb5_ldap_get_strings(ld, ent, "krbAllowedToDelegateTo",
+ &a2d2, &attr_present);
+ if (st != 0)
+ goto cleanup;
+
+ if (attr_present == TRUE) {
+ for (tlp = &entry->tl_data; *tlp; tlp = &(*tlp)->tl_data_next)
+ ;
+ for (i = 0; a2d2[i] != NULL; i++) {
+ krb5_tl_data *tl = k5alloc(sizeof(*tl), &st);
+ if (st != 0) {
+ ldap_value_free(a2d2);
+ goto cleanup;
+ }
+ tl->tl_data_type = KRB5_TL_CONSTRAINED_DELEGATION_ACL;
+ tl->tl_data_length = strlen(a2d2[i]);
+ tl->tl_data_contents = (krb5_octet *)strdup(a2d2[i]);
+ if (tl->tl_data_contents == NULL) {
+ st = ENOMEM;
+ ldap_value_free(a2d2);
+ free(tl);
+ goto cleanup;
+ }
+ tl->tl_data_next = NULL;
+ *tlp = tl;
+ tlp = &tl->tl_data_next;
+ }
+ ldap_value_free(a2d2);
+ }
+ }
+
/* KRBOBJECTREFERENCES */
{
int i=0;
"krbLastPwdChange",
"krbExtraData",
"krbObjectReferences",
+ "krbAllowedToDelegateTo",
NULL };
/* Must match KDB_*_ATTR macros in ldap_principal.h. */
|| ptr->tl_data_type == KRB5_TL_DB_ARGS
#endif
|| ptr->tl_data_type == KRB5_TL_KADM_DATA
- || ptr->tl_data_type == KDB_TL_USER_INFO)
+ || ptr->tl_data_type == KDB_TL_USER_INFO
+ || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL)
continue;
count++;
}
|| ptr->tl_data_type == KRB5_TL_DB_ARGS
#endif
|| ptr->tl_data_type == KRB5_TL_KADM_DATA
- || ptr->tl_data_type == KDB_TL_USER_INFO)
+ || ptr->tl_data_type == KDB_TL_USER_INFO
+ || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL)
continue;
if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
break;
krb5_free_ad_kdcissued);
ktest_empty_ad_kdcissued(&kdci);
}
+#if 0
+ /****************************************************************/
+ /* encode_krb5_ad_signedpath_data */
+ {
+ krb5_ad_signedpath_data spd, *tmp;
+ setup(spd, "ad_signedpath_data",
+ ktest_make_sample_ad_signedpath_data);
+ leak_test(spd, encode_krb5_ad_signedpath_data,
+ decode_krb5_ad_signedpath_data,
+ NULL);
+ ktest_empty_ad_signedpath_data(&spd);
+ }
+#endif
+ /****************************************************************/
+ /* encode_krb5_ad_signedpath */
+ {
+ krb5_ad_signedpath sp, *tmp;
+ setup(sp, "ad_signedpath",
+ ktest_make_sample_ad_signedpath);
+ leak_test(sp, encode_krb5_ad_signedpath,
+ decode_krb5_ad_signedpath,
+ krb5_free_ad_signedpath);
+ ktest_empty_ad_signedpath(&sp);
+ }
krb5_free_context(test_context);
return 0;
}
ktest_empty_ad_kdcissued(&ref);
}
+ /****************************************************************/
+ /* decode_ad_signedpath */
+ {
+ setup(krb5_ad_signedpath,"krb5_ad_signedpath",ktest_make_sample_ad_signedpath);
+ decode_run("ad_signedpath","","30 3E A0 03 02 01 01 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61",decode_krb5_ad_signedpath,ktest_equal_ad_signedpath,krb5_free_ad_signedpath);
+ ktest_empty_ad_signedpath(&ref);
+ }
+
#ifdef ENABLE_LDAP
/* ldap sequence_of_keys */
{
encode_krb5_ad_kdcissued);
ktest_empty_ad_kdcissued(&kdci);
}
+ /****************************************************************/
+ /* encode_krb5_ad_signedpath_data */
+ {
+ krb5_ad_signedpath_data spd;
+ setup(spd,krb5_ad_signedpath_data,"ad_signedpath_data",
+ ktest_make_sample_ad_signedpath_data);
+ encode_run(spd,krb5_ad_signedpath_data,
+ "ad_signedpath_data","",
+ encode_krb5_ad_signedpath_data);
+ ktest_empty_ad_signedpath_data(&spd);
+ }
+ /****************************************************************/
+ /* encode_krb5_ad_signedpath */
+ {
+ krb5_ad_signedpath sp;
+ setup(sp,krb5_ad_signedpath,"ad_signedpath",
+ ktest_make_sample_ad_signedpath);
+ encode_run(sp,krb5_ad_signedpath,
+ "ad_signedpath","",
+ encode_krb5_ad_signedpath);
+ ktest_empty_ad_signedpath(&sp);
+ }
#ifdef ENABLE_LDAP
{
ldap_seqof_key_data skd;
return retval;
}
+krb5_error_code ktest_make_sample_ad_signedpath_data(p)
+ krb5_ad_signedpath_data *p;
+{
+ krb5_error_code retval;
+ retval = ktest_make_sample_principal(&p->client);
+ if (retval) return retval;
+ p->authtime = SAMPLE_TIME;
+ p->delegated = k5alloc((2 * sizeof(krb5_principal)), &retval);
+ if (retval) return retval;
+ retval = ktest_make_sample_principal(&p->delegated[0]);
+ if (retval) return retval;
+ p->delegated[1] = NULL;
+ retval = ktest_make_sample_principal(&p->client);
+ if (retval) return retval;
+ retval = ktest_make_sample_authorization_data(&p->authorization_data);
+ if (retval) return retval;
+ retval = ktest_make_sample_pa_data_array(&p->method_data);
+ if (retval) return retval;
+ return retval;
+}
+
+krb5_error_code ktest_make_sample_ad_signedpath(p)
+ krb5_ad_signedpath*p;
+{
+ krb5_error_code retval;
+ p->enctype = 1;
+ retval = ktest_make_sample_checksum(&p->checksum);
+ if (retval) return retval;
+ p->delegated = k5alloc((2 * sizeof(krb5_principal)), &retval);
+ if (retval) return retval;
+ p->delegated[1] = NULL;
+ retval = ktest_make_sample_pa_data_array(&p->method_data);
+ if (retval) return retval;
+ return retval;
+}
+
#ifdef ENABLE_LDAP
static krb5_error_code ktest_make_sample_key_data(krb5_key_data *p, int i)
{
ktest_destroy_authorization_data(&p->elements);
}
+void ktest_empty_ad_signedpath_data(p)
+ krb5_ad_signedpath_data *p;
+{
+ int i;
+ ktest_destroy_principal(&p->client);
+ if (p->delegated != NULL) {
+ for (i = 0; p->delegated[i] != NULL; i++) {
+ krb5_principal princ = p->delegated[i];
+ ktest_destroy_principal(&princ);
+ }
+ free(p->delegated);
+ }
+ ktest_destroy_pa_data_array(&p->method_data);
+ ktest_destroy_authorization_data(&p->authorization_data);
+}
+
+void ktest_empty_ad_signedpath(p)
+ krb5_ad_signedpath *p;
+{
+ int i;
+ if (p->checksum.contents) free(p->checksum.contents);
+ if (p->delegated != NULL) {
+ for (i = 0; p->delegated[i] != NULL; i++) {
+ krb5_principal princ = p->delegated[i];
+ ktest_destroy_principal(&princ);
+ }
+ free(p->delegated);
+ }
+ ktest_destroy_pa_data_array(&p->method_data);
+}
+
#ifdef ENABLE_LDAP
void ktest_empty_ldap_seqof_key_data(ctx, p)
krb5_context ctx;
krb5_error_code ktest_make_sample_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
krb5_error_code ktest_make_sample_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
krb5_error_code ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p);
+krb5_error_code ktest_make_sample_ad_signedpath_data(krb5_ad_signedpath_data *p);
+krb5_error_code ktest_make_sample_ad_signedpath(krb5_ad_signedpath *p);
#ifdef ENABLE_LDAP
krb5_error_code ktest_make_sample_ldap_seqof_key_data(ldap_seqof_key_data * p);
void ktest_empty_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
void ktest_empty_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
void ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p);
+void ktest_empty_ad_signedpath_data(krb5_ad_signedpath_data *p);
+void ktest_empty_ad_signedpath(krb5_ad_signedpath *p);
#ifdef ENABLE_LDAP
void ktest_empty_ldap_seqof_key_data(krb5_context, ldap_seqof_key_data *p);
return p;
}
+int ktest_equal_ad_signedpath_data(ref, var)
+ krb5_ad_signedpath_data *ref;
+ krb5_ad_signedpath_data *var;
+{
+ int p = TRUE;
+ if (ref == var) return TRUE;
+ else if (ref == NULL || var == NULL) return FALSE;
+ p=p&&ptr_equal(client,ktest_equal_principal_data);
+ p=p&&scalar_equal(authtime);
+ p=p&&ptr_equal(delegated,ktest_equal_sequence_of_principal);
+ p=p&&ptr_equal(method_data,ktest_equal_sequence_of_pa_data);
+ p=p&&ptr_equal(authorization_data,ktest_equal_authorization_data);
+ return p;
+}
+
+int ktest_equal_ad_signedpath(ref, var)
+ krb5_ad_signedpath* ref;
+ krb5_ad_signedpath* var;
+{
+ int p = TRUE;
+ if (ref == var) return TRUE;
+ else if (ref == NULL || var == NULL) return FALSE;
+ p=p&&scalar_equal(enctype);
+ p=p&&struct_equal(checksum,ktest_equal_checksum);
+ p=p&&ptr_equal(delegated,ktest_equal_sequence_of_principal);
+ p=p&&ptr_equal(method_data,ktest_equal_sequence_of_pa_data);
+ return p;
+}
+
#ifdef ENABLE_LDAP
static int equal_key_data(ref, var)
krb5_key_data *ref;
array_compare(ktest_equal_cred_info);
}
+int ktest_equal_sequence_of_principal(ref, var)
+ krb5_principal * ref;
+ krb5_principal * var;
+{
+ array_compare(ktest_equal_principal_data);
+}
+
int ktest_equal_array_of_passwd_phrase_element(ref, var)
passwd_phrase_element ** ref;
passwd_phrase_element ** var;
(krb5_pa_data **ref, krb5_pa_data **var);
int ktest_equal_sequence_of_cred_info
(krb5_cred_info **ref, krb5_cred_info **var);
+int ktest_equal_sequence_of_principal
+ (krb5_principal *ref, krb5_principal *var);
len_array(ktest_equal_array_of_enctype,krb5_enctype);
len_array(ktest_equal_array_of_data,krb5_data);
int ktest_equal_ad_kdcissued
(krb5_ad_kdcissued *ref,
krb5_ad_kdcissued *var);
+int ktest_equal_ad_signedpath_data
+ (krb5_ad_signedpath_data *ref,
+ krb5_ad_signedpath_data *var);
+int ktest_equal_ad_signedpath
+ (krb5_ad_signedpath *ref,
+ krb5_ad_signedpath *var);
int ktest_equal_ldap_sequence_of_keys(ldap_seqof_key_data *ref,
ldap_seqof_key_data *var);
encode_krb5_enc_sam_response_enc_2: 30 1F A0 03 02 01 58 A1 18 04 16 65 6E 63 5F 73 61 6D 5F 72 65 73 70 6F 6E 73 65 5F 65 6E 63 5F 32
encode_krb5_pa_s4u_x509_user: 30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
encode_krb5_ad_kdcissued: 30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
+encode_krb5_ad_signedpath_data: 30 81 C7 A0 30 30 2E A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 32 30 30 30 2E A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
+encode_krb5_ad_signedpath: 30 3E A0 03 02 01 01 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61
. . . [0] [Integer] 1
. . . [1] [Octet String] "foobar"
+encode_krb5_ad_signedpath_data:
+
+[Sequence/Sequence Of]
+. [0] [Sequence/Sequence Of]
+. . [0] [Sequence/Sequence Of]
+. . . [0] [Integer] 1
+. . . [1] [Sequence/Sequence Of]
+. . . . [General string] "hftsai"
+. . . . [General string] "extra"
+. . [1] [General string] "ATHENA.MIT.EDU"
+. [1] [Generalized Time] "19940610060317Z"
+. [2] [Sequence/Sequence Of]
+. . [Sequence/Sequence Of]
+. . . [0] [Sequence/Sequence Of]
+. . . . [0] [Integer] 1
+. . . . [1] [Sequence/Sequence Of]
+. . . . . [General string] "hftsai"
+. . . . . [General string] "extra"
+. . . [1] [General string] "ATHENA.MIT.EDU"
+. [3] [Sequence/Sequence Of]
+. . [Sequence/Sequence Of]
+. . . [1] [Integer] 13
+. . . [2] [Octet String] "pa-data"
+. . [Sequence/Sequence Of]
+. . . [1] [Integer] 13
+. . . [2] [Octet String] "pa-data"
+. [4] [Sequence/Sequence Of]
+. . [Sequence/Sequence Of]
+. . . [0] [Integer] 1
+. . . [1] [Octet String] "foobar"
+. . [Sequence/Sequence Of]
+. . . [0] [Integer] 1
+. . . [1] [Octet String] "foobar"
+
+encode_krb5_ad_signedpath:
+
+[Sequence/Sequence Of]
+. [0] [Integer] 1
+. [1] [Sequence/Sequence Of]
+. . [0] [Integer] 1
+. . [1] [Octet String] "1234"
+. [3] [Sequence/Sequence Of]
+. . [Sequence/Sequence Of]
+. . . [1] [Integer] 13
+. . . [2] [Octet String] "pa-data"
+. . [Sequence/Sequence Of]
+. . . [1] [Integer] 13
+. . . [2] [Octet String] "pa-data"
+