svn rev #21566: branches/mskrb-integ/src/ include/krb5/ kdc/

lhoward@MIT.EDU lhoward at MIT.EDU
Mon Dec 22 21:55:04 EST 2008


http://src.mit.edu/fisheye/changelog/krb5/?cs=21566
Commit By: lhoward
Log Message:
Consolidate authorization data handling interface. Both AS-REQ and
TGS-REQ paths call handle_authdata(). There is a new V1 callback that
provides some additional arguments.

Copying TGT authorization data to new tickets as well as the existing
Novell DB sign_auth_data method are both implemented as static authdata
systems.

Both V0 and V1 plugins are supported.



Changed Files:
U   branches/mskrb-integ/src/include/krb5/authdata_plugin.h
U   branches/mskrb-integ/src/kdc/do_as_req.c
U   branches/mskrb-integ/src/kdc/do_tgs_req.c
U   branches/mskrb-integ/src/kdc/kdc_authdata.c
U   branches/mskrb-integ/src/kdc/kdc_util.c
U   branches/mskrb-integ/src/kdc/kdc_util.h
Modified: branches/mskrb-integ/src/include/krb5/authdata_plugin.h
===================================================================
--- branches/mskrb-integ/src/include/krb5/authdata_plugin.h	2008-12-23 02:39:51 UTC (rev 21565)
+++ branches/mskrb-integ/src/include/krb5/authdata_plugin.h	2008-12-23 02:55:02 UTC (rev 21566)
@@ -108,4 +108,53 @@
 				     krb5_kdc_req *request,
 				     krb5_enc_tkt_part *enc_tkt_reply);
 } krb5plugin_authdata_ftable_v0;
+
+typedef struct krb5plugin_authdata_ftable_v1 {
+    /* Not-usually-visible name. */
+    char *name;
+
+    /*
+     * Per-plugin initialization/cleanup.  The init function is called
+     * by the KDC when the plugin is loaded, and the fini function is
+     * called before the plugin is unloaded.  Both are optional.
+     */
+    krb5_error_code (*init_proc)(krb5_context, void **);
+    void (*fini_proc)(krb5_context, void *);
+    /*
+     * Actual authorization data handling function.  If this field
+     * holds a null pointer, this mechanism will be skipped, and the
+     * init/fini functions will not be run.
+     *
+     * This function should only modify the field
+     * enc_tkt_reply->authorization_data.  All other values should be
+     * considered inputs only.  And, it should *modify* the field, not
+     * overwrite it and assume that there are no other authdata
+     * plugins in use.
+     *
+     * Memory management: authorization_data is a malloc-allocated,
+     * null-terminated sequence of malloc-allocated pointers to
+     * authorization data structures.  This plugin code currently
+     * assumes the libraries, KDC, and plugin all use the same malloc
+     * pool, which may be a problem if/when we get the KDC code
+     * running on Windows.
+     *
+     * If this function returns a non-zero error code, a message
+     * is logged, but no other action is taken.  Other authdata
+     * plugins will be called, and a response will be sent to the
+     * client (barring other problems).
+     */
+    krb5_error_code (*authdata_proc)(krb5_context,
+				     unsigned int flags,
+				     krb5_const_principal reply_client,
+				     struct _krb5_db_entry_new *client,
+				     struct _krb5_db_entry_new *server,
+				     struct _krb5_db_entry_new *tgs,
+				     krb5_keyblock *client_key,
+				     krb5_keyblock *server_key,
+				     krb5_data *req_pkt,
+				     krb5_kdc_req *request,
+				     krb5_enc_tkt_part *enc_tkt_request,
+				     krb5_enc_tkt_part *enc_tkt_reply);
+} krb5plugin_authdata_ftable_v1;
+
 #endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */

Modified: branches/mskrb-integ/src/kdc/do_as_req.c
===================================================================
--- branches/mskrb-integ/src/kdc/do_as_req.c	2008-12-23 02:39:51 UTC (rev 21565)
+++ branches/mskrb-integ/src/kdc/do_as_req.c	2008-12-23 02:55:02 UTC (rev 21566)
@@ -296,6 +296,8 @@
     ticket_reply.server = &server_princ;
 
     enc_tkt_reply.flags = 0;
+    enc_tkt_reply.times.authtime = authtime;
+
     setflag(enc_tkt_reply.flags, TKT_FLG_INITIAL);
 
     	/* It should be noted that local policy may affect the  */
@@ -323,8 +325,6 @@
     enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
     enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
 
-    enc_tkt_reply.times.authtime = kdc_time;
-
     if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
 	setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
 	setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
@@ -498,30 +498,21 @@
     reply_encpart.times.authtime = authtime = kdc_time;
 
     reply_encpart.caddrs = enc_tkt_reply.caddrs;
-    errcode = sign_authorization_data(kdc_context,
-				      0,
-				      reply.client,
-				      &client,
-				      &server,
-				      &server,
-				      &client_keyblock,
-				      &server_keyblock,
-				      authtime,
-				      NULL,
-				      &enc_tkt_reply.authorization_data,
-				      NULL,
-				      NULL);
+    reply_encpart.enc_padata = NULL;
+
+    /* Fetch the padata info to be returned (do this before
+       authdata to handle possible replacement of reply key */
+    errcode = return_padata(kdc_context, &client, req_pkt, request,
+			    &reply, client_key, &client_keyblock, &pa_context);
     if (errcode) {
-	status = "SIGN_AUTH_DATA";
+	status = "KDC_RETURN_PADATA";
 	goto errout;
     }
-    /* Add any additional auth data - XXX need to consolidate plugin interfaces */
-    errcode = handle_authdata(kdc_context, &client, req_pkt, request, &enc_tkt_reply);
-    if (errcode) {
-	krb5_klog_syslog(LOG_INFO,  "AS_REQ : handle_authdata (%d)", errcode);
-    }
 
-    reply_encpart.enc_padata = NULL;
+#if APPLE_PKINIT
+    asReqDebug("process_as_req reply realm %s name %s\n", 
+	reply.client->realm.data, reply.client->data->data);
+#endif /* APPLE_PKINIT */
 
     errcode = return_svr_referral_data(kdc_context,
 				       &server, &reply_encpart);
@@ -530,27 +521,31 @@
 	goto errout;
     }
 
-    /* moved here because we need authorization data in ticket_reply */
-    errcode = krb5_encrypt_tkt_part(kdc_context, &server_keyblock, &ticket_reply);
+    errcode = handle_authdata(kdc_context,
+			      c_flags,
+			      reply.client,
+			      &client,
+			      &server,
+			      &server,
+			      &client_keyblock,
+			      &server_keyblock,
+			      req_pkt,
+			      request,
+			      NULL, /* enc_tkt_request */
+			      &enc_tkt_reply);
     if (errcode) {
-	status = "ENCRYPTING_TICKET";
+	krb5_klog_syslog(LOG_INFO, "AS_REQ : handle_authdata (%d)", errcode);
+	status = "HANDLE_AUTHDATA";
 	goto errout;
     }
-    ticket_reply.enc_part.kvno = server_key->key_data_kvno;
 
-    /* Fetch the padata info to be returned */
-    errcode = return_padata(kdc_context, &client, req_pkt, request,
-			    &reply, client_key, &client_keyblock, &pa_context);
+    errcode = krb5_encrypt_tkt_part(kdc_context, &server_keyblock, &ticket_reply);
     if (errcode) {
-	status = "KDC_RETURN_PADATA";
+	status = "ENCRYPTING_TICKET";
 	goto errout;
     }
+    ticket_reply.enc_part.kvno = server_key->key_data_kvno;
 
-#if APPLE_PKINIT
-    asReqDebug("process_as_req reply realm %s name %s\n", 
-	reply.client->realm.data, reply.client->data->data);
-#endif /* APPLE_PKINIT */
-
     /* now encode/encrypt the response */
 
     reply.enc_part.enctype = client_keyblock.enctype;

Modified: branches/mskrb-integ/src/kdc/do_tgs_req.c
===================================================================
--- branches/mskrb-integ/src/kdc/do_tgs_req.c	2008-12-23 02:39:51 UTC (rev 21565)
+++ branches/mskrb-integ/src/kdc/do_tgs_req.c	2008-12-23 02:55:02 UTC (rev 21566)
@@ -614,58 +614,27 @@
 		c_nprincs = 0;
 	    }
 	}
+    }
 
-	/*
-	 * Check whether KDC issued authorization data should be included.
-	 * A server can explicitly disable the inclusion of authorization
-	 * data by setting the KRB5_KDB_NO_AUTH_DATA_REQUIRED flag on its
-	 * principal entry. Otherwise authorization data will be included
-	 * if it was present in the TGT, the client is from another realm
-	 * or protocol transition/constrained delegation was used.
-	 *
-	 * 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 (header_enc_tkt->authorization_data != NULL ||
-	    isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM) ||
-	    isflagset(c_flags, KRB5_KDB_FLAGS_S4U)) {
-	    krb5_db_entry	ad_entry;
-	    int			ad_nprincs = 0;
+    enc_tkt_reply.authorization_data = NULL;
 
-	    errcode = sign_authorization_data(kdc_context,
-					      c_flags,
-					      isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
-						    for_user->user : header_enc_tkt->client,
-					      (c_nprincs != 0) ? &client : NULL,
-					      &server,
-					      &krbtgt,
-					      NULL, /* ticket reply key not relevant */
-					      &encrypting_key, /* U2U or server key */
-					      header_enc_tkt->times.authtime,
-					      header_enc_tkt->authorization_data,
-					      &kdc_issued_auth_data,
-					      &ad_entry,
-					      &ad_nprincs);
-	    if (errcode) {
-		status = "SIGN_AUTH_DATA";
-		goto cleanup;
-	    }
-	    if (ad_nprincs != 0) {
-		if (isflagset(ad_entry.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
-		    clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
-
-		krb5_db_free_principal(kdc_context, &ad_entry, ad_nprincs);
-
-		if (ad_nprincs != 1) {
-		    status = "NON_UNIQUE_AUTH_DATA_PRINCIPAL";
-		    errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
-		    goto cleanup;
-		}
-	    }
-	}
+    errcode = handle_authdata(kdc_context,
+			      c_flags,
+			      isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
+					for_user->user : header_enc_tkt->client,
+			      (c_nprincs != 0) ? &client : NULL,
+			      &server,
+			      &krbtgt,
+			      NULL, /* ticket reply key not relevant here */
+			      &encrypting_key, /* U2U or server key */
+			      pkt,
+			      request,
+			      header_enc_tkt,
+			      &enc_tkt_reply);
+    if (errcode) {
+	krb5_klog_syslog(LOG_INFO, "TGS_REQ : handle_authdata (%d)", errcode);
+	status = "HANDLE_AUTHDATA";
+	goto cleanup;
     }
 
     errcode = return_svr_referral_data(kdc_context,
@@ -675,46 +644,6 @@
 	goto cleanup;
     }
 
-    /* assemble any authorization data */
-    if (request->authorization_data.ciphertext.data != NULL) {
-	krb5_data scratch;
-
-	scratch.length = request->authorization_data.ciphertext.length;
-	if (!(scratch.data =
-	      malloc(request->authorization_data.ciphertext.length))) {
-	    status = "AUTH_NOMEM";
-	    errcode = ENOMEM;
-	    goto cleanup;
-	}
-
-	if ((errcode = krb5_c_decrypt(kdc_context,
-				      header_ticket->enc_part2->session,
-				      KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
-				      0, &request->authorization_data,
-				      &scratch))) {
-	    status = "AUTH_ENCRYPT_FAIL";
-	    free(scratch.data);
-	    goto cleanup;
-	}
-
-	/* scratch now has the authorization data, so we decode it */
-	errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
-	free(scratch.data);
-	if (errcode) {
-	    status = "AUTH_DECODE";
-	    goto cleanup;
-	}
-
-	if ((errcode =
-	     concat_authorization_data(kdc_issued_auth_data,
-				       request->unenc_authdata,
-				       &enc_tkt_reply.authorization_data))) {
-	    status = "CONCAT_AUTH";
-	    goto cleanup;
-	}
-    } else
-	enc_tkt_reply.authorization_data = kdc_issued_auth_data;
-
     enc_tkt_reply.session = &session_key;
     if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
 	is_local_principal(header_enc_tkt->client))

Modified: branches/mskrb-integ/src/kdc/kdc_authdata.c
===================================================================
--- branches/mskrb-integ/src/kdc/kdc_authdata.c	2008-12-23 02:39:51 UTC (rev 21565)
+++ branches/mskrb-integ/src/kdc/kdc_authdata.c	2008-12-23 02:55:02 UTC (rev 21566)
@@ -2,6 +2,7 @@
  * kdc/kdc_authdata.c
  *
  * Copyright (C) 2007 Apple Inc.  All Rights Reserved.
+ * Copyright (C) 2008 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.
@@ -42,109 +43,95 @@
 static const char *objdirs[] = { LIBDIR "/krb5/plugins/authdata", NULL };
 #endif
 
-typedef krb5_error_code (*authdata_proc)
+/* MIT Kerberos 1.6 (V0) authdata plugin callback */
+typedef krb5_error_code (*authdata_proc_0)
     (krb5_context, krb5_db_entry *client,
      krb5_data *req_pkt,
      krb5_kdc_req *request,
      krb5_enc_tkt_part * enc_tkt_reply);
-
+/* MIT Kerberos 1.7 (V1) authdata plugin callback */
+typedef krb5_error_code (*authdata_proc_1)
+    (krb5_context, unsigned int flags,
+     krb5_const_principal reply_client,
+     krb5_db_entry *client, krb5_db_entry *server,
+     krb5_db_entry *krbtgt,
+     krb5_keyblock *client_key,
+     krb5_keyblock *server_key,
+     krb5_data *req_pkt,
+     krb5_kdc_req *request,
+     krb5_enc_tkt_part *enc_tkt_request,
+     krb5_enc_tkt_part *enc_tkt_reply);
 typedef krb5_error_code (*init_proc)
     (krb5_context, void **);
 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_const_principal reply_client,
+     krb5_db_entry *client,
+     krb5_db_entry *server,
+     krb5_db_entry *krbtgt,
+     krb5_keyblock *client_key,
+     krb5_keyblock *server_key,
+     krb5_data *req_pkt,
+     krb5_kdc_req *request,
+     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_const_principal reply_client,
+     krb5_db_entry *client,
+     krb5_db_entry *server,
+     krb5_db_entry *krbtgt,
+     krb5_keyblock *client_key,
+     krb5_keyblock *server_key,
+     krb5_data *req_pkt,
+     krb5_kdc_req *request,
+     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_V0	0
+#define AUTHDATA_SYSTEM_V1	1
     int         type;
+#define AUTHDATA_FLAG_CRITICAL	0x1
     int         flags;
     void       *plugin_context;
     init_proc   init;
     fini_proc   fini;
-    authdata_proc handle_authdata;
+    union {
+	authdata_proc_1 v1;
+	authdata_proc_0 v0;
+    } handle_authdata;
 } krb5_authdata_systems;
 
-#undef GREET_PREAUTH
-
-#ifdef GREET_PREAUTH
-static krb5_error_code
-greet_init(krb5_context ctx, void **blob)
-{
-    *blob = "hello";
-    return 0;
-}
-
-static void
-greet_fini(krb5_context ctx, void *blob)
-{
-}
-
-static krb5_error_code
-greet_authdata(krb5_context ctx, krb5_db_entry *client,
-	       krb5_data *req_pkt,
-	       krb5_kdc_req *request,
-	       krb5_enc_tkt_part * enc_tkt_reply)
-{
-#define GREET_SIZE (20)
-
-    char *p;
-    krb5_authdata *a;
-    size_t count;
-    krb5_authdata **new_ad;
-
-    krb5_klog_syslog (LOG_DEBUG, "in greet_authdata");
-
-    p = calloc(1, GREET_SIZE);
-    a = calloc(1, sizeof(*a));
-
-    if (p == NULL || a == NULL) {
-	free(p);
-	free(a);
-	return ENOMEM;
-    }
-    strlcpy(p, "hello", GREET_SIZE);
-    a->magic = KV5M_AUTHDATA;
-    a->ad_type = -42;
-    a->length = GREET_SIZE;
-    a->contents = p;
-    if (enc_tkt_reply->authorization_data == 0) {
-	count = 0;
-    } else {
-	for (count = 0; enc_tkt_reply->authorization_data[count] != 0; count++)
-	    ;
-    }
-    new_ad = realloc(enc_tkt_reply->authorization_data,
-		     (count+2) * sizeof(krb5_authdata *));
-    if (new_ad == NULL) {
-	free(p);
-	free(a);
-	return ENOMEM;
-    }
-    enc_tkt_reply->authorization_data = new_ad;
-    new_ad[count] = a;
-    new_ad[count+1] = NULL;
-    return 0;
-}
-#endif
-
 static krb5_authdata_systems static_authdata_systems[] = {
-#ifdef GREET_PREAUTH
-    { "greeting", 0, 0, 0, greet_init, greet_fini, greet_authdata },
-#endif
-    { "[end]", -1,}
+    { "tgs_req", AUTHDATA_SYSTEM_V1, AUTHDATA_FLAG_CRITICAL, NULL, NULL, NULL, { handle_request_authdata } },
+    { "tgt", AUTHDATA_SYSTEM_V1, AUTHDATA_FLAG_CRITICAL, NULL, NULL, NULL, { handle_tgt_authdata } },
 };
 
 static krb5_authdata_systems *authdata_systems;
 static int n_authdata_systems;
 static struct plugin_dir_handle authdata_plugins;
 
+/* Load both v0 and v1 authdata plugins */
 krb5_error_code
 load_authdata_plugins(krb5_context context)
 {
-    void **authdata_plugins_ftables = NULL;
-    struct krb5plugin_authdata_ftable_v0 *ftable = NULL;
+    void **authdata_plugins_ftables_v0 = NULL;
+    void **authdata_plugins_ftables_v1 = NULL;
     size_t module_count;
-    int i, k;
+    size_t i, k;
     init_proc server_init_proc = NULL;
+    krb5_error_code code;
 
     /* Attempt to load all of the authdata plugins we can find. */
     PLUGIN_DIR_INIT(&authdata_plugins);
@@ -156,40 +143,56 @@
     }
 
     /* Get the method tables provided by the loaded plugins. */
-    authdata_plugins_ftables = NULL;
+    authdata_plugins_ftables_v0 = NULL;
+    authdata_plugins_ftables_v1 = NULL;
     n_authdata_systems = 0;
+
     if (krb5int_get_plugin_dir_data(&authdata_plugins,
+				    "authdata_server_1",
+				    &authdata_plugins_ftables_v1, &context->err) != 0 ||
+	krb5int_get_plugin_dir_data(&authdata_plugins,
 				    "authdata_server_0",
-				    &authdata_plugins_ftables, &context->err) != 0) {
-	return KRB5_PLUGIN_NO_HANDLE;
+				    &authdata_plugins_ftables_v0, &context->err) != 0) {
+	code = KRB5_PLUGIN_NO_HANDLE;
+	goto cleanup;
     }
 
     /* Count the valid modules. */ 
     module_count = sizeof(static_authdata_systems)
 	/ sizeof(static_authdata_systems[0]);
-    if (authdata_plugins_ftables != NULL) {
-	for (i = 0; authdata_plugins_ftables[i] != NULL; i++) {
-	    ftable = authdata_plugins_ftables[i];
-	    if ((ftable->authdata_proc != NULL)) {
+
+    if (authdata_plugins_ftables_v1 != NULL) {
+	struct krb5plugin_authdata_ftable_v1 *ftable;
+
+	for (i = 0; authdata_plugins_ftables_v1[i] != NULL; i++) {
+	    ftable = authdata_plugins_ftables_v1[i];
+	    if (ftable->authdata_proc != NULL)
 		module_count++;
-	    }
 	}
     }
+ 
+    if (authdata_plugins_ftables_v0 != NULL) {
+	struct krb5plugin_authdata_ftable_v0 *ftable;
 
+	for (i = 0; authdata_plugins_ftables_v0[i] != NULL; i++) {
+	    ftable = authdata_plugins_ftables_v0[i];
+	    if (ftable->authdata_proc != NULL)
+		module_count++;
+	}
+    }
+
     /* Build the complete list of supported authdata options, and
      * leave room for a terminator entry. */
     authdata_systems = calloc(module_count + 1, sizeof(krb5_authdata_systems));
     if (authdata_systems == NULL) {
-	krb5int_free_plugin_dir_data(authdata_plugins_ftables);
-	return ENOMEM;
+	code = ENOMEM;
+	goto cleanup;
     }
 
     /* Add the locally-supplied mechanisms to the dynamic list first. */
     for (i = 0, k = 0;
 	 i < sizeof(static_authdata_systems) / sizeof(static_authdata_systems[0]);
 	 i++) {
-	if (static_authdata_systems[i].type == -1)
-	    break;
 	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. */
@@ -202,13 +205,15 @@
 	k++;
     }
 
-    /* Now add the dynamically-loaded mechanisms to the list. */
-    if (authdata_plugins_ftables != NULL) {
-	for (i = 0; authdata_plugins_ftables[i] != NULL; i++) {
+    /* Add dynamically loaded V1 plugins */
+    if (authdata_plugins_ftables_v1 != NULL) {
+	struct krb5plugin_authdata_ftable_v1 *ftable;
+
+	for (i = 0; authdata_plugins_ftables_v1[i] != NULL; i++) {
 	    krb5_error_code initerr;
 	    void *pctx = NULL;
 
-	    ftable = authdata_plugins_ftables[i];
+	    ftable = authdata_plugins_ftables_v1[i];
 	    if ((ftable->authdata_proc == NULL)) {
 		continue;
 	    }
@@ -229,19 +234,66 @@
 	    }
     
 	    authdata_systems[k].name = ftable->name;
+	    authdata_systems[k].type = AUTHDATA_SYSTEM_V1;
 	    authdata_systems[k].init = server_init_proc;
 	    authdata_systems[k].fini = ftable->fini_proc;
-	    authdata_systems[k].handle_authdata = ftable->authdata_proc;
+	    authdata_systems[k].handle_authdata.v1 = ftable->authdata_proc;
 	    authdata_systems[k].plugin_context = pctx;
 	    k++;
 	}
-	krb5int_free_plugin_dir_data(authdata_plugins_ftables);
     }
+
+    /* Add dynamically loaded V0 plugins */
+    if (authdata_plugins_ftables_v0 != NULL) {
+	struct krb5plugin_authdata_ftable_v0 *ftable;
+
+	for (i = 0; authdata_plugins_ftables_v0[i] != NULL; i++) {
+	    krb5_error_code initerr;
+	    void *pctx = NULL;
+
+	    ftable = authdata_plugins_ftables_v0[i];
+	    if ((ftable->authdata_proc == NULL)) {
+		continue;
+	    }
+	    server_init_proc = ftable->init_proc;
+	    if ((server_init_proc != NULL) &&
+		((initerr = (*server_init_proc)(context, &pctx)) != 0)) {
+		const char *emsg;
+		emsg = krb5_get_error_message(context, initerr);
+		if (emsg) {
+		    krb5_klog_syslog(LOG_ERR,
+				     "authdata %s failed to initialize: %s",
+				     ftable->name, emsg);
+		    krb5_free_error_message(context, emsg);
+		}
+		memset(&authdata_systems[k], 0, sizeof(authdata_systems[k]));
+	
+		continue;
+	    }
+    
+	    authdata_systems[k].name = ftable->name;
+	    authdata_systems[k].type = AUTHDATA_SYSTEM_V0;
+	    authdata_systems[k].init = server_init_proc;
+	    authdata_systems[k].fini = ftable->fini_proc;
+	    authdata_systems[k].handle_authdata.v0 = ftable->authdata_proc;
+	    authdata_systems[k].plugin_context = pctx;
+	    k++;
+	}
+    }
+
     n_authdata_systems = k;
     /* Add the end-of-list marker. */
     authdata_systems[k].name = "[end]";
-    authdata_systems[k].type = -1;
-    return 0;
+    authdata_systems[k].type = AUTHDATA_SYSTEM_UNKNOWN;
+    code = 0;
+
+cleanup:
+    if (authdata_plugins_ftables_v1 != NULL)
+	krb5int_free_plugin_dir_data(authdata_plugins_ftables_v1);
+    if (authdata_plugins_ftables_v0 != NULL)
+	krb5int_free_plugin_dir_data(authdata_plugins_ftables_v0);
+
+    return code;
 }
 
 krb5_error_code
@@ -264,35 +316,277 @@
     return 0;
 }
 
+/* Merge authdata. If copy == 0, in_authdata is invalid on return */
+static krb5_error_code
+merge_authdata (krb5_context context,
+		krb5_authdata **in_authdata,
+		krb5_authdata ***out_authdata,
+		int copy)
+{
+    size_t i, nadata = 0;
+    krb5_authdata **authdata = *out_authdata;
+
+    if (in_authdata == NULL || in_authdata[0] == NULL)
+	return 0;
+
+    if (authdata != NULL) {
+	for (nadata = 0; authdata[nadata] != NULL; nadata++)
+	    ;
+    }
+
+    for (i = 0; in_authdata[i] != NULL; i++)
+	;
+
+    authdata = (krb5_authdata **)realloc(*out_authdata,
+	((nadata + i + 1) * sizeof(krb5_authdata *)));
+    if (authdata == NULL)
+	return ENOMEM;
+
+    if (copy) {
+	krb5_error_code code;
+	krb5_authdata **tmp;
+
+	code = krb5_copy_authdata(context, in_authdata, &tmp);
+	if (code != 0)
+	    return code;
+
+	in_authdata = tmp;
+    }
+
+    for (i = 0; in_authdata[i] != NULL; i++)
+	authdata[nadata + i] = in_authdata[i];
+
+    authdata[nadata + i] = NULL;
+
+    free(in_authdata);
+
+    *out_authdata = authdata;
+
+    return 0;
+}
+
+/* Handle copying TGS-REQ authorization data into reply */
+static krb5_error_code
+handle_request_authdata (krb5_context context,
+			 unsigned int flags,
+			 krb5_const_principal reply_client,
+			 krb5_db_entry *client,
+			 krb5_db_entry *server,
+			 krb5_db_entry *krbtgt,
+			 krb5_keyblock *client_key,
+			 krb5_keyblock *server_key,
+			 krb5_data *req_pkt,
+			 krb5_kdc_req *request,
+			 krb5_enc_tkt_part *enc_tkt_request,
+			 krb5_enc_tkt_part *enc_tkt_reply)
+{
+    krb5_error_code code;
+    krb5_data scratch;
+
+    if (request->msg_type != KRB5_TGS_REQ ||
+	request->authorization_data.ciphertext.data == NULL)
+	return 0;
+
+    assert(enc_tkt_request != NULL);
+
+    scratch.length = request->authorization_data.ciphertext.length;
+    scratch.data = malloc(scratch.length);
+    if (scratch.data == NULL)
+	return ENOMEM;
+
+    code = krb5_c_decrypt(context,
+			  enc_tkt_request->session,
+			  KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
+			  0, &request->authorization_data,
+			  &scratch);
+    if (code != 0) {
+	free(scratch.data);
+	return code;
+    }
+
+    /* scratch now has the authorization data, so we decode it, and make
+     * it available to subsequent authdata plugins */
+    code = decode_krb5_authdata(&scratch, &request->unenc_authdata);
+    if (code != 0) {
+	free(scratch.data);
+	return code;
+    }
+
+    free(scratch.data);
+
+    code = merge_authdata(context, request->unenc_authdata,
+			  &enc_tkt_reply->authorization_data, TRUE /* copy */);
+
+    return code;
+}
+
+/* Handle backend-managed authorization data */
+static krb5_error_code
+handle_tgt_authdata (krb5_context context,
+		     unsigned int flags,
+		     krb5_const_principal reply_client,
+		     krb5_db_entry *client,
+		     krb5_db_entry *server,
+		     krb5_db_entry *krbtgt,
+		     krb5_keyblock *client_key,
+		     krb5_keyblock *server_key,
+		     krb5_data *req_pkt,
+		     krb5_kdc_req *request,
+		     krb5_enc_tkt_part *enc_tkt_request,
+		     krb5_enc_tkt_part *enc_tkt_reply)
+{
+    krb5_error_code code;
+    krb5_authdata **db_authdata = NULL;
+    krb5_db_entry ad_entry;
+    int ad_nprincs = 0;
+    krb5_boolean tgs_req = (request->msg_type == KRB5_TGS_REQ);
+
+    /*
+     * Check whether KDC issued authorization data should be included.
+     * A server can explicitly disable the inclusion of authorization
+     * data by setting the KRB5_KDB_NO_AUTH_DATA_REQUIRED flag on its
+     * principal entry. Otherwise authorization data will be included
+     * if it was present in the TGT, the client is from another realm
+     * or protocol transition/constrained delegation was used, or, in
+     * the AS-REQ case, if the pre-auth data indicated the PAC should
+     * be absent.
+     *
+     * 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);
+
+	if (isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED))
+	    return 0;
+
+	if (enc_tkt_request->authorization_data == NULL &&
+	    !isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM | KRB5_KDB_FLAGS_S4U))
+	    return 0;
+
+	assert(enc_tkt_reply->times.authtime == enc_tkt_request->times.authtime);
+    } else {
+	if (!isflagset(flags, KRB5_KDB_FLAG_INCLUDE_PAC))
+	    return 0;
+    }
+
+    /*
+     * 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,
+			    reply_client,
+			    client,
+			    server,
+			    krbtgt,
+			    client_key,
+			    server_key, /* U2U or server key */
+			    enc_tkt_reply->times.authtime,
+			    tgs_req ? enc_tkt_request->authorization_data : NULL,
+			    &db_authdata,
+			    &ad_entry,
+			    &ad_nprincs);
+    if (code == KRB5_KDB_DBTYPE_NOSUP) {
+	assert(ad_nprincs == 0);
+	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);
+    }
+
+    if (ad_nprincs != 0) {
+	if (tgs_req &&
+	    isflagset(ad_entry.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))
+	    clear(enc_tkt_reply->flags, TKT_FLG_FORWARDABLE);
+
+	krb5_db_free_principal(context, &ad_entry, ad_nprincs);
+
+	if (ad_nprincs != 1) {
+	    if (db_authdata != NULL)
+		krb5_free_authdata(context, db_authdata);
+	    return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
+	}
+    }
+
+    if (db_authdata != NULL) {
+	code = merge_authdata(context, db_authdata,
+			      &enc_tkt_reply->authorization_data,
+			      FALSE);
+	if (code != 0)
+	    krb5_free_authdata(context, db_authdata);
+    }
+
+    return code;
+}
+
 krb5_error_code
-handle_authdata (krb5_context context, krb5_db_entry *client,
-		 krb5_data *req_pkt, krb5_kdc_req *request,
+handle_authdata (krb5_context context,
+		 unsigned int flags,
+		 krb5_const_principal reply_client,
+		 krb5_db_entry *client,
+		 krb5_db_entry *server,
+		 krb5_db_entry *krbtgt,
+		 krb5_keyblock *client_key,
+		 krb5_keyblock *server_key,
+		 krb5_data *req_pkt,
+		 krb5_kdc_req *request,
+		 krb5_enc_tkt_part *enc_tkt_request,
 		 krb5_enc_tkt_part *enc_tkt_reply)
 {
-    krb5_error_code retval = 0;
+    krb5_error_code code = 0;
     int i;
-    const char *emsg;
 
-#if 0
-    krb5_klog_syslog (LOG_DEBUG, "handling authdata");
-#endif
-
+    assert(enc_tkt_reply->authorization_data == NULL);
     for (i = 0; i < n_authdata_systems; i++) {
 	const krb5_authdata_systems *asys = &authdata_systems[i];
-	if (asys->handle_authdata && asys->type != -1) {
-	    retval = asys->handle_authdata(context, client, req_pkt,
-					   request, enc_tkt_reply);
-	    if (retval) {
-		emsg = krb5_get_error_message (context, retval);
-		krb5_klog_syslog (LOG_INFO,
-				  "authdata (%s) handling failure: %s",
-				  asys->name, emsg);
-		krb5_free_error_message (context, emsg);
-	    } else {
-		krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
-	    }
+
+	switch (asys->type) {
+	case AUTHDATA_SYSTEM_V0:
+	    /* V0 was only in AS-REQ code path */
+	    if (request->msg_type != KRB5_AS_REQ)
+		continue;
+
+	    code = asys->handle_authdata.v0(context, client, req_pkt,
+					    request, enc_tkt_reply);
+	    break;
+	case AUTHDATA_SYSTEM_V1:
+	    code = asys->handle_authdata.v1(context, flags, reply_client,
+					    client, server, krbtgt,
+					    client_key, server_key,
+					    req_pkt, request, enc_tkt_request,
+					    enc_tkt_reply);
+	default:
+	    code = 0;
+	    break;
 	}
+	if (code != 0) {
+	    const char *emsg;
+
+	    emsg = krb5_get_error_message (context, code);
+	    krb5_klog_syslog (LOG_INFO,
+			      "authdata (%s) handling failure: %s",
+			      asys->name, emsg);
+	    krb5_free_error_message (context, emsg);
+
+	    if (asys->flags & AUTHDATA_FLAG_CRITICAL)
+		break;
+	}
     }
 
-    return 0;
+    return code;
 }
+

Modified: branches/mskrb-integ/src/kdc/kdc_util.c
===================================================================
--- branches/mskrb-integ/src/kdc/kdc_util.c	2008-12-23 02:39:51 UTC (rev 21565)
+++ branches/mskrb-integ/src/kdc/kdc_util.c	2008-12-23 02:55:02 UTC (rev 21566)
@@ -1669,27 +1669,27 @@
 }
 
 krb5_error_code
-sign_authorization_data(krb5_context context,
-			unsigned int flags,
-			krb5_const_principal client_princ,
-			krb5_db_entry *client,
-			krb5_db_entry *server,
-			krb5_db_entry *krbtgt,
-			krb5_keyblock *client_key,
-			krb5_keyblock *server_key,
-			krb5_timestamp authtime,
-			krb5_authdata **auth_data,
-			krb5_authdata ***ret_auth_data,
-			krb5_db_entry *ad_entry,
-			int *ad_nprincs)
+sign_db_authdata (krb5_context context,
+		  unsigned int flags,
+		  krb5_const_principal client_princ,
+		  krb5_db_entry *client,
+		  krb5_db_entry *server,
+		  krb5_db_entry *krbtgt,
+		  krb5_keyblock *client_key,
+		  krb5_keyblock *server_key,
+		  krb5_timestamp authtime,
+		  krb5_authdata **tgs_authdata,
+		  krb5_authdata ***ret_authdata,
+		  krb5_db_entry *ad_entry,
+		  int *ad_nprincs)
 {
-    krb5_error_code		code;
-    kdb_sign_auth_data_req	req;
-    kdb_sign_auth_data_rep	rep;
-    krb5_data			req_data;
-    krb5_data			rep_data;
+    krb5_error_code code;
+    kdb_sign_auth_data_req req;
+    kdb_sign_auth_data_rep rep;
+    krb5_data req_data;
+    krb5_data rep_data;
 
-    *ret_auth_data = NULL;
+    *ret_authdata = NULL;
     if (ad_entry != NULL) {
 	assert(ad_nprincs != NULL);
 	memset(ad_entry, 0, sizeof(*ad_entry));
@@ -1707,7 +1707,7 @@
     req.client_key		= client_key;
     req.server_key		= server_key;
     req.authtime		= authtime;
-    req.auth_data		= auth_data;
+    req.auth_data		= tgs_authdata;
 
     rep.entry			= ad_entry;
     rep.nprincs			= 0;
@@ -1722,25 +1722,10 @@
 			  KRB5_KDB_METHOD_SIGN_AUTH_DATA,
 			  &req_data,
 			  &rep_data);
-    if (code == KRB5_KDB_DBTYPE_NOSUP) {
-	/*
-	 * If the backend does not implement the sign auth data
-	 * method, then we just copy the authorization data into
-	 * the response, 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)
-	 */
-	if (isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))
-	    code = KRB5KDC_ERR_POLICY;
-	else
-	    code = krb5_copy_authdata(context, auth_data, ret_auth_data);
-    } else {
-	*ret_auth_data = rep.auth_data;
-	if (ad_nprincs != NULL)
-	    *ad_nprincs = rep.nprincs;
-    }
 
+    *ret_authdata = rep.auth_data;
+    *ad_nprincs = rep.nprincs;
+ 
     return code;
 }
 

Modified: branches/mskrb-integ/src/kdc/kdc_util.h
===================================================================
--- branches/mskrb-integ/src/kdc/kdc_util.h	2008-12-23 02:39:51 UTC (rev 21565)
+++ branches/mskrb-integ/src/kdc/kdc_util.h	2008-12-23 02:55:02 UTC (rev 21566)
@@ -176,9 +176,19 @@
 krb5_error_code load_authdata_plugins(krb5_context context);
 krb5_error_code unload_authdata_plugins(krb5_context context);
 
-krb5_error_code handle_authdata (krb5_context context, krb5_db_entry *client,
-				 krb5_data *req_pkt, krb5_kdc_req *request,
-				 krb5_enc_tkt_part *enc_tkt_reply);
+krb5_error_code
+handle_authdata (krb5_context context,
+		 unsigned int flags,
+		 krb5_const_principal reply_client,
+		 krb5_db_entry *client,
+		 krb5_db_entry *server,
+		 krb5_db_entry *krbtgt,
+		 krb5_keyblock *client_key,
+		 krb5_keyblock *server_key,
+		 krb5_data *req_pkt,
+		 krb5_kdc_req *request,
+		 krb5_enc_tkt_part *enc_tkt_request,
+		 krb5_enc_tkt_part *enc_tkt_reply);
 
 /* replay.c */
 krb5_boolean kdc_check_lookaside (krb5_data *, krb5_data **);
@@ -201,11 +211,11 @@
 
 krb5_error_code return_svr_referral_data
    (krb5_context context,
-	       krb5_db_entry *server,
-	       krb5_enc_kdc_rep_part *reply_encpart);
+		krb5_db_entry *server,
+		krb5_enc_kdc_rep_part *reply_encpart);
 
-krb5_error_code sign_authorization_data
-   (krb5_context context,
+krb5_error_code sign_db_authdata
+    (krb5_context context,
 		unsigned int flags,
 		krb5_const_principal client_princ,
 		krb5_db_entry *client,
@@ -214,8 +224,8 @@
 		krb5_keyblock *client_key,
 		krb5_keyblock *server_key,
 		krb5_timestamp authtime,
-		krb5_authdata **tgs_auth_data,
-		krb5_authdata ***ret_auth_data,
+		krb5_authdata **tgs_authdata,
+		krb5_authdata ***ret_authdata,
 		krb5_db_entry *ad_entry,
 		int *ad_nprincs);
 




More information about the cvs-krb5 mailing list