[krbdev.mit.edu #5596] patch for providing a way to set the ok-as-delegate flag

Sam Hartman via RT rt-comment at krbdev.mit.edu
Wed Jul 18 10:50:44 EDT 2007


Here's the current Sandia patch.  I'm sorry for sitting on this so
long.

My recommendation is that if possible you use the same flag and kadmin
option that they do.  I'm a bit confused by the client support.  As
far as I can tell the new function they add is static so I'm not sure
how you'd ever use it.

In terms of a way forward, I think it is reasonable to commit your
server side patches if we end up using the same flag names and kadmin
options or you explain why that would be a bad idea.

I think it would be good to have a client side API that works similar
to the Sandia proposal, but I think it needs another round of work and
I don't think your patches should be blocked on it.


diff -Naur krb5-1.4.3/src/include/krb5/kdb.h krb5-1.4.3.ok_as_del/src/include/krb5/kdb.h
--- krb5-1.4.3/src/include/krb5/kdb.h	2004-06-22 12:14:15.000000000 -0600
+++ krb5-1.4.3.ok_as_del/src/include/krb5/kdb.h	2006-04-12 11:19:10.000000000 -0600
@@ -79,6 +79,7 @@
 #define KRB5_KDB_PWCHANGE_SERVICE	0x00002000
 #define KRB5_KDB_SUPPORT_DESMD5         0x00004000
 #define	KRB5_KDB_NEW_PRINC		0x00008000
+#define KRB5_KDB_ALLOW_OK_AS_DELEGATE   0x00010000
 
 /* Creation flags */
 #define KRB5_KDB_CREATE_BTREE		0x00000001
diff -Naur krb5-1.4.3/src/include/krb5.hin krb5-1.4.3.ok_as_del/src/include/krb5.hin
--- krb5-1.4.3/src/include/krb5.hin	2005-10-26 16:00:27.000000000 -0600
+++ krb5-1.4.3.ok_as_del/src/include/krb5.hin	2006-04-12 15:06:33.000000000 -0600
@@ -900,6 +900,11 @@
 #define KRB5_KPASSWD_BAD_VERSION	6
 #define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7	/* unused */
 
+/* flags for forwarding tickets */
+#define KRB5_FWD_TKT_MUST   0
+#define KRB5_FWD_TKT_MAY    1
+#define KRB5_FWD_TKT_NO     2
+
 /*
  * end "proto.h"
  */
diff -Naur krb5-1.4.3/src/kadmin/cli/kadmin.c krb5-1.4.3.ok_as_del/src/kadmin/cli/kadmin.c
--- krb5-1.4.3/src/kadmin/cli/kadmin.c	2005-03-22 16:53:59.000000000 -0700
+++ krb5-1.4.3.ok_as_del/src/kadmin/cli/kadmin.c	2006-04-12 11:22:14.000000000 -0600
@@ -59,6 +59,7 @@
 {"requires_hwauth",	15,	KRB5_KDB_REQUIRES_HW_AUTH,	0},
 {"needchange",		10,	KRB5_KDB_REQUIRES_PWCHANGE,	0},
 {"allow_svr",		9,	KRB5_KDB_DISALLOW_SVR,		1},
+{"allow_ok_to_delegate",    20, KRB5_KDB_ALLOW_OK_AS_DELEGATE, 0 },
 {"password_changing_service",	25,	KRB5_KDB_PWCHANGE_SERVICE,	0 },
 {"support_desmd5",	14,	KRB5_KDB_SUPPORT_DESMD5,	0 }
 };
@@ -80,6 +81,8 @@
     "PWCHANGE_SERVICE",		/* 0x00002000 */
     "SUPPORT_DESMD5",		/* 0x00004000 */
     "NEW_PRINC",		/* 0x00008000 */
+    "ALLOW_OK_AS_DELEGATE", /* 0x00010000 */
+
 };
 
 char *getenv();
diff -Naur krb5-1.4.3/src/kdc/do_as_req.c krb5-1.4.3.ok_as_del/src/kdc/do_as_req.c
--- krb5-1.4.3/src/kdc/do_as_req.c	2005-07-12 14:59:52.000000000 -0600
+++ krb5-1.4.3.ok_as_del/src/kdc/do_as_req.c	2006-04-12 13:53:39.000000000 -0600
@@ -192,6 +192,8 @@
     	/* It should be noted that local policy may affect the  */
         /* processing of any of these flags.  For example, some */
         /* realms may refuse to issue renewable tickets         */
+    if (isflagset(server.attributes, KRB5_KDB_ALLOW_OK_AS_DELEGATE ))
+    setflag(enc_tkt_reply.flags, TKT_FLG_OK_AS_DELEGATE);
 
     if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
 	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
diff -Naur krb5-1.4.3/src/lib/kadm5/str_conv.c krb5-1.4.3.ok_as_del/src/lib/kadm5/str_conv.c
--- krb5-1.4.3/src/lib/kadm5/str_conv.c	2001-06-26 13:59:45.000000000 -0600
+++ krb5-1.4.3.ok_as_del/src/lib/kadm5/str_conv.c	2006-04-12 11:31:55.000000000 -0600
@@ -76,6 +76,7 @@
 static const char flags_pwchange_in[]	= "pwchange";
 static const char flags_service_in[]	= "service";
 static const char flags_pwsvc_in[]	= "pwservice";
+static const char flags_delegate_in[]   = "ok-to-delegate";
 static const char flags_md5_in[]	= "md5";
 static const char flags_pdate_out[]	= "Not Postdateable";
 static const char flags_fwd_out[]	= "Not Forwardable";
@@ -89,6 +90,7 @@
 static const char flags_pwchange_out[]	= "Password Change required";
 static const char flags_service_out[]	= "Service Disabled";
 static const char flags_pwsvc_out[]	= "Password Changing Service";
+static const char flags_delegate_out[]   = "OK To Delegate";
 static const char flags_md5_out[]	= "RSA-MD5 supported";
 static const char flags_default_neg[]	= "-";
 static const char flags_default_sep[]	= " ";
@@ -112,6 +114,7 @@
 { KRB5_KDB_REQUIRES_PWCHANGE,	1,	flags_pwchange_in, flags_pwchange_out},
 { KRB5_KDB_DISALLOW_SVR,	0,	flags_service_in,  flags_service_out },
 { KRB5_KDB_PWCHANGE_SERVICE,	1,	flags_pwsvc_in,	   flags_pwsvc_out   },
+{ KRB5_KDB_ALLOW_OK_AS_DELEGATE,1,      flags_delegate_in, flags_delegate_out},
 { KRB5_KDB_SUPPORT_DESMD5,	1,	flags_md5_in,	   flags_md5_out     }
 };
 static const int flags_table_nents = sizeof(flags_table)/
diff -Naur krb5-1.4.3/src/lib/krb5/krb/fwd_tgt.c krb5-1.4.3.ok_as_del/src/lib/krb5/krb/fwd_tgt.c
--- krb5-1.4.3/src/lib/krb5/krb/fwd_tgt.c	2003-06-16 16:34:50.000000000 -0600
+++ krb5-1.4.3.ok_as_del/src/lib/krb5/krb/fwd_tgt.c	2006-05-02 10:02:07.000000000 -0600
@@ -33,15 +33,23 @@
 /* helper function: convert flags to necessary KDC options */
 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
 
-/* Get a TGT for use at the remote host */
+/* local functions */
+static int str_match(const char *pattern,  const char *str);
+static krb5_error_code profile_check_deleg(krb5_context context, krb5_principal server, int * result);
+
+static krb5_error_code krb5_fwd_tgt_creds_flag(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, int do_fwd_flag, krb5_data *outbuf);
+
+/* We now use this as a wrapper */
 krb5_error_code KRB5_CALLCONV
-krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf)
-                         
-                                   
-                
-                          
-                          
-                   
+krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf){
+
+    return krb5_fwd_tgt_creds_flag(context, auth_context, rhost, client, server, cc, forwardable, KRB5_FWD_TKT_MUST, krb5_data *outbuf);
+}
+
+
+/* this now supports do_fwd_flag */
+static krb5_fwd_tgt_creds_flag(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, int do_fwd_flag, krb5_data *outbuf){
+
                           /* Should forwarded TGT also be forwardable? */
                       
 {
@@ -61,6 +69,12 @@
     memset((char *)&creds, 0, sizeof(creds));
     memset((char *)&tgt, 0, sizeof(creds));
 
+    /* i don't know why you would do this */
+    if (do_fwd_flag == KRB5_FWD_TKT_NO){
+        retval = KRB5_TKT_NOT_FORWARDABLE_HERE;
+        goto errout;
+    }
+
     if (cc == 0) {
       if ((retval = krb5int_cc_default(context, &cc)))
 	goto errout;
@@ -73,27 +87,54 @@
 	enctype = session_key->enctype;
 	krb5_free_keyblock (context, session_key);
 	session_key = NULL;
-    } else if (server) { /* must server be non-NULL when rhost is given? */
-	/* Try getting credentials to see what the remote side supports.
-	   Not bulletproof, just a heuristic.  */
-	krb5_creds in, *out = 0;
-	memset (&in, 0, sizeof(in));
+    }
+
+    if (!server){
+    
+        /* there must be a principal name to check for delegation */
+        retval = KRB5_TKT_NOT_FORWARDABLE_HERE;
+        goto errout;
+    }
+    else {
+
+        int match = 0;
+	    /* Try getting credentials to see what the remote side supports.
+    	   Not bulletproof, just a heuristic.  */
+	    krb5_creds in, *out = 0;
+    	memset (&in, 0, sizeof(in));
+
+    	retval = krb5_copy_principal (context, server, &in.server);
+    	if (retval)
+    	    goto punt;
+    	retval = krb5_copy_principal (context, client, &in.client);
+    	if (retval)
+    	    goto punt;
+    	retval = krb5_get_credentials (context, 0, cc, &in, &out);
+    	if (retval)
+    	    goto punt;
+
+        /* if the do_fwd_flag KRB5_FWD_TKT_MUST or 
+        *  if the do_fwd_flag KRB5_FWD_TKT_MAY && TKT_FLG_OK_AS_DELEGE we delegate */
+        if (((out->ticket_flags & TKT_FLG_OK_AS_DELEGATE) && do_fwd_flag == KRB5_FWD_TKT_MAY)
+            || (do_fwd_flag == KRB5_FWD_TKT_MUST))
+            match = 1;
+
+        /* Got the credentials.  Record the enctype if we didn't get one from the session key*/
+        if (!enctype)
+    	    enctype = out->keyblock.enctype;
+    	krb5_free_creds (context, out);
+        punt:
+    	krb5_free_cred_contents (context, &in);
+
+        if (!match)
+           profile_check_deleg(context, server, &match);
+
+        if (!match)
+        {
+           retval = KRB5_TKT_NOT_FORWARDABLE_HERE;
+           goto errout;
+        }
 
-	retval = krb5_copy_principal (context, server, &in.server);
-	if (retval)
-	    goto punt;
-	retval = krb5_copy_principal (context, client, &in.client);
-	if (retval)
-	    goto punt;
-	retval = krb5_get_credentials (context, 0, cc, &in, &out);
-	if (retval)
-	    goto punt;
-	/* Got the credentials.  Okay, now record the enctype and
-	   throw them away.  */
-	enctype = out->keyblock.enctype;
-	krb5_free_creds (context, out);
-    punt:
-	krb5_free_cred_contents (context, &in);
     }
 
     if ((retval = krb5_copy_principal(context, client, &creds.client)))
@@ -196,3 +237,166 @@
     krb5_free_cred_contents(context, &tgt);
     return retval;
 }
+
+/* str_match
+ * matches a string against a pattern.
+ *
+ * pattern - pattern to match against
+ * str     - string to match
+ *
+ * returns 1 if there is a match
+ * returns 0 if there is not a match
+ *
+ * Pattern can contain any number of
+ * asterisks as wild cards. Use backslash before a
+ * control character (asterisk and backslash) to
+ * use it's actual character value.
+ *
+ * The str value has no control characters.
+ */
+
+static int str_match(pattern, str)
+    const char *pattern;
+    const char *str;
+{
+    int special = 0;
+
+    /* was the function called correctly? */
+
+    if (!pattern || !str)
+        return 0;
+
+    /* a pattern ends with a non-escaped
+     * backslash this makes no sense
+     */
+    if (*pattern == '\\' && !*(pattern + 1))
+        return 0;
+
+    /* allow asterisks and backslash to be
+     * processed normally */
+
+    if (*pattern == '\\')
+    {
+        special = 1;
+        pattern++;
+    }
+
+     /* try every possible way that
+      * the wildcard character can
+      * eat the characters in the str */
+
+    if (*pattern == '*')
+    {
+        while (*str)
+        {
+            if (str_match(pattern+1, str))
+                return 1;
+
+            str++;
+        }
+
+        /* check to see if the wildcard
+         * matches of the end of string character */
+
+        return str_match(pattern+1, str);
+    }
+
+    /* the end of both strings was reached
+     * successfully */
+
+    if (!*pattern && !*str)
+        return 1;
+
+    /* the strings match so far ... */
+
+    if (*pattern == *str)
+        return (str_match(pattern+1, str+1));
+
+    /* the strings don't match */
+
+    return 0;
+}
+
+/* profile_check_deleg
+ *
+ * determines whether a service can
+ * delegate to particular service principal
+ * by checking the ok_to_delegate item
+ * in the configuration file.
+ *
+ * context - kerberos context
+ * server  - server principal
+ * result  - 1 (true) or 0 (false)
+ *
+ * returns error code
+ *
+ * There can be any number of ok_to_delegate
+ * items under a particular realm.
+ *
+ * See the str_match function to determine
+ * what is considered a match.
+ */
+
+static krb5_error_code
+profile_check_deleg(context, server, result)
+    const krb5_context context;
+    const krb5_principal server;
+    int * result;
+{
+
+    int len = 0;
+    void * data = NULL;
+    char * realm = NULL;
+    char * princ_name = NULL;
+    const char * names[4];
+    char ** values = NULL;
+    char ** item = NULL;
+    int retval = 0;
+
+    *result = 0;
+    retval =  krb5_unparse_name(context, server, &princ_name);
+
+    if (retval)
+        return retval;
+
+    len = krb5_princ_realm(context, server)->length;
+    data = krb5_princ_realm(context, server)->data;
+
+    realm = malloc(len + 1);
+    strncpy(realm, data, len);
+
+    realm[len] = '\0';
+
+    names[0] = "realms";
+    names[1] = realm;
+    names[2] = DELEGATION_CONFIG;
+    names[3] =  0;
+
+    retval = profile_get_values(context->profile, names, &values);
+
+    if (retval)
+        goto cleanup;
+
+    item = values;
+
+    while(*item && !*result)
+    {
+       *result = str_match(*item, princ_name);
+
+       item++;
+    }
+
+cleanup:
+
+    if (realm)
+        free(realm);
+
+    if (princ_name)
+        free(princ_name);
+
+    if (values)
+        profile_free_list(values);
+
+    return retval;
+}
+





More information about the krb5-bugs mailing list