Added debugging hooks to stdcc.c
authorTheodore Tso <tytso@mit.edu>
Thu, 18 Feb 1999 04:28:12 +0000 (04:28 +0000)
committerTheodore Tso <tytso@mit.edu>
Thu, 18 Feb 1999 04:28:12 +0000 (04:28 +0000)
Added broadcast event notification of the krb5 cache changing, for backwards
compatibility with krb5.exe.

Added support for the V2 Ccache API.

In stdcc_util.c, replace the old matching algorithm with one that's closer
to the original stdcc and file algorithm, and so is provably correct.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@11181 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/ccache/ccapi/stdcc.c
src/lib/krb5/ccache/ccapi/stdcc_util.c

index 4912ba159fde1d094cd1dd105c533a4982ae6384..b81e82a7d090fcb547cac431e42340df181e5669 100644 (file)
@@ -25,6 +25,7 @@
  * 
  */
 
+#define NEED_WINDOWS
 #include "stdcc.h"
 #include "stdcc_util.h"
 #include "string.h"
 
 #if defined(_MSDOS) || defined(_WIN32)
 apiCB *gCntrlBlock = NULL;
+#else
+#define CC_API_VER2
+#endif
+
+#ifdef DEBUG
+#if defined(_MSDOS) || defined(_WIN32)
+#include <io.h>
+#define SHOW_DEBUG(buf)   MessageBox((HWND)NULL, (buf), "ccapi debug", MB_OK)
+#endif
+       /* XXX need macintosh debugging statement if we want to debug */
+       /* on the mac */
+#else
+#define SHOW_DEBUG(buf)
 #endif
 
 /*
@@ -58,6 +72,31 @@ krb5_cc_ops krb5_cc_stdcc_ops = {
       krb5_stdcc_set_flags,
 };
 
+#if defined(_MSDOS) || defined(_WIN32)
+/*
+ * cache_changed be called after the cache changes.
+ * A notification message is is posted out to all top level
+ * windows so that they may recheck the cache based on the
+ * changes made.  We register a unique message type with which
+ * we'll communicate to all other processes. 
+ */
+void cache_changed()
+{
+       static unsigned int message = 0;
+       
+       if (message == 0)
+               message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
+
+       SendMessage(HWND_BROADCAST, message, 0, 0);
+}
+#else /* _MSDOS || _WIN32 */
+
+void cache_changed()
+{
+       return;
+}
+#endif /* _MSDOS || _WIN32 */
+
 struct err_xlate
 {
        int     cc_err;
@@ -90,6 +129,9 @@ static krb5_error_code cc_err_xlate(int err)
 {
        const struct err_xlate *p;
 
+       if (err == CC_NOERROR)
+               return 0;
+
        for (p = err_xlate_table; p->cc_err; p++) {
                if (err == p->cc_err)
                        return p->krb5_err;
@@ -104,7 +146,11 @@ static krb5_error_code stdcc_setup(krb5_context context,
 
        /* make sure the API has been intialized */
        if (gCntrlBlock == NULL) {
+#ifdef CC_API_VER2
+               err = cc_initialize(&gCntrlBlock, CC_API_VER_2, NULL, NULL);
+#else
                err = cc_initialize(&gCntrlBlock, CC_API_VER_1, NULL, NULL);
+#endif
                if (err != CC_NOERROR)
                        return cc_err_xlate(err);
        }
@@ -286,11 +332,9 @@ krb5_error_code KRB5_CALLCONV  krb5_stdcc_initialize
        err = cc_create(gCntrlBlock, ccapi_data->cache_name, cName,
                        CC_CRED_V5, 0L, &ccapi_data->NamedCache);
        krb5_free_unparsed_name(context, cName);
+       cache_changed();
        
-       if (err)
-               return cc_err_xlate(err);
-       
-       return 0;
+       return cc_err_xlate(err);
 }
 
 /*
@@ -299,7 +343,7 @@ krb5_error_code KRB5_CALLCONV  krb5_stdcc_initialize
  * store some credentials in our cache
  */
 krb5_error_code KRB5_CALLCONV krb5_stdcc_store 
-        (krb5_context context, krb5_ccache id , krb5_creds *creds )
+        (krb5_context context, krb5_ccache id, krb5_creds *creds )
 {
        krb5_error_code retval;
        stdccCacheDataPtr       ccapi_data = id->data;
@@ -324,6 +368,7 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_store
        /* free the cred union */
        err = cc_free_creds(gCntrlBlock, &cu);
                 
+       cache_changed();
        return err;
 }
 
@@ -337,12 +382,22 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_start_seq_get
 {
        stdccCacheDataPtr       ccapi_data = id->data;
        krb5_error_code retval;
+       int     err;
+       ccache_cit      *iterator;
 
        if ((retval = stdcc_setup(context, ccapi_data)))
                return retval;
-       
+
+#ifdef CC_API_VER2
+       err = cc_seq_fetch_creds_begin(gCntrlBlock, ccapi_data->NamedCache,
+                                      &iterator);
+       if (err != CC_NOERROR)
+               return cc_err_xlate(err);
+       *cursor = iterator;
+#else
        /* all we have to do is initialize the cursor */
        *cursor = NULL;
+#endif
        return 0;
 }
 
@@ -360,15 +415,29 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_next_cred
        stdccCacheDataPtr       ccapi_data = id->data;
        int err;
        cred_union *credU = NULL;
+       ccache_cit      *iterator;
        
        if ((retval = stdcc_setup(context, ccapi_data)))
                return retval;
        
+#ifdef CC_API_VER2
+       iterator = *cursor;
+       if (iterator == 0)
+               return KRB5_CC_END;
+       err = cc_seq_fetch_creds_next(gCntrlBlock, &credU, iterator);
+
+       if (err = CC_END) {
+               cc_seq_fetch_creds_end(gCntrlBlock, &iterator);
+               *cursor = 0;
+       }
+#else
        err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
-                                &credU, (ccache_cit **)cursor);
+                                &credU, (ccache_cit **)cursor); 
+#endif
+
        if (err != CC_NOERROR)
                return cc_err_xlate(err);
-
+       
        /* copy data    (with translation) */
        dupCCtoK5(context, credU->cred.pV5Cred, creds);
        
@@ -451,6 +520,11 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_end_seq_get
        if (*cursor == NULL)
                return 0;
 
+#ifdef CC_API_VER2
+       err = cc_seq_fetch_creds_end(gCntrlBlock, (ccache_cit **)cursor);
+       if (err != CC_NOERROR)
+               return cc_err_xlate(err);
+#else  
        /*
         * Finish calling cc_seq_fetch_creds to clear out the cursor
         */
@@ -462,6 +536,7 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_end_seq_get
                
                cc_free_creds(gCntrlBlock, &credU);
        }
+#endif
        
        return(0);
 }
@@ -515,6 +590,7 @@ krb5_stdcc_destroy (krb5_context context, krb5_ccache id)
        
        /* destroy the named cache */
        err = cc_destroy(gCntrlBlock, &ccapi_data->NamedCache);
+       cache_changed();
        
        return cc_err_xlate(err);
 }
@@ -614,6 +690,7 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_remove
        
        /* free the temp cred union */
        err = cc_free_creds(gCntrlBlock, &cu);
+       cache_changed();
        if (err != CC_NOERROR)
                return cc_err_xlate(err);
 
index dd44109ad8b4bcdefdc5459ca0608eb26c618432..3c6917ad924b42fe4caf0f9dc8c69eb38ab83a8e 100644 (file)
@@ -310,13 +310,115 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu)
 }
 
 /*
- *  bitTst
- *  - utility function for below function
+ * Utility functions...
  */
-int bitTst(int var, int mask) {
+static krb5_boolean
+times_match(t1, t2)
+register const krb5_ticket_times *t1;
+register const krb5_ticket_times *t2;
+{
+    if (t1->renew_till) {
+       if (t1->renew_till > t2->renew_till)
+           return FALSE;               /* this one expires too late */
+    }
+    if (t1->endtime) {
+       if (t1->endtime > t2->endtime)
+           return FALSE;               /* this one expires too late */
+    }
+    /* only care about expiration on a times_match */
+    return TRUE;
+}
+
+static krb5_boolean
+times_match_exact (t1, t2)
+    register const krb5_ticket_times *t1, *t2;
+{
+    return (t1->authtime == t2->authtime
+           && t1->starttime == t2->starttime
+           && t1->endtime == t2->endtime
+           && t1->renew_till == t2->renew_till);
+}
 
-       return var & mask;
-} 
+static krb5_boolean
+standard_fields_match(context, mcreds, creds)
+   krb5_context context;
+register const krb5_creds *mcreds, *creds;
+{
+    return (krb5_principal_compare(context, mcreds->client,creds->client) &&
+           krb5_principal_compare(context, mcreds->server,creds->server));
+}
+
+/* only match the server name portion, not the server realm portion */
+
+static krb5_boolean
+srvname_match(context, mcreds, creds)
+   krb5_context context;
+register const krb5_creds *mcreds, *creds;
+{
+    krb5_boolean retval;
+    krb5_principal_data p1, p2;
+    
+    retval = krb5_principal_compare(context, mcreds->client,creds->client);
+    if (retval != TRUE)
+       return retval;
+    /*
+     * Hack to ignore the server realm for the purposes of the compare.
+     */
+    p1 = *mcreds->server;
+    p2 = *creds->server;
+    p1.realm = p2.realm;
+    return krb5_principal_compare(context, &p1, &p2);
+}
+
+
+static krb5_boolean
+authdata_match(mdata, data)
+    krb5_authdata *const *mdata, *const *data;
+{
+    const krb5_authdata *mdatap, *datap;
+
+    if (mdata == data)
+       return TRUE;
+
+    if (mdata == NULL)
+       return *data == NULL;
+
+    if (data == NULL)
+       return *mdata == NULL;
+
+    while ((mdatap = *mdata)
+          && (datap = *data)
+          && mdatap->ad_type == datap->ad_type
+          && mdatap->length == datap->length
+          && !memcmp ((char *) mdatap->contents, (char *) datap->contents,
+                      datap->length)) {
+       mdata++;
+       data++;
+    }
+
+    return !*mdata && !*data;
+}
+
+static krb5_boolean
+data_match(data1, data2)
+register const krb5_data *data1, *data2;
+{
+    if (!data1) {
+       if (!data2)
+           return TRUE;
+       else
+           return FALSE;
+    }
+    if (!data2) return FALSE;
+
+    if (data1->length != data2->length)
+       return FALSE;
+    else
+       return memcmp(data1->data, data2->data, data1->length) ? FALSE : TRUE;
+}
+
+#define MATCH_SET(bits) (whichfields & bits)
+#define flags_match(a,b) (((a) & (b)) == (a))
 
 /*  stdccCredsMatch
  *  - check to see if the creds match based on the whichFields variable
@@ -330,70 +432,36 @@ int stdccCredsMatch(krb5_context context, krb5_creds *base,
        krb5_ticket_times b, m;
        krb5_authdata **bp, **mp;
        krb5_boolean retval;
-       
 
-       /* always check the standard fields */
-       if ((krb5_principal_compare(context, base->client, match->client) &&
-           krb5_principal_compare(context, base->server, match->server)) == FALSE)
-           return FALSE;
-
-       if (bitTst(whichfields, KRB5_TC_MATCH_TIMES)) {
-               /*
-                * test for matching times
-                * according to the file cache implementation we do:
-                */
-               if (match->times.renew_till) {
-                       if (match->times.renew_till > base->times.renew_till)
-                               return FALSE;           /* this one expires too late */
-               }
-               if (match->times.endtime) {
-                       if (match->times.endtime > base->times.endtime)
-                               return FALSE;           /* this one expires too late */
-               }
-       } 
-       
-       if (bitTst(whichfields, KRB5_TC_MATCH_IS_SKEY)) 
-               if (base->is_skey != match->is_skey) return FALSE;
-       
-       if (bitTst(whichfields, KRB5_TC_MATCH_FLAGS)) 
-               if (base->ticket_flags != match->ticket_flags) return FALSE;
-               
-       if (bitTst(whichfields, KRB5_TC_MATCH_TIMES_EXACT)) {
-               b = base->times; m = match->times;
-               if ((b.authtime != m.authtime) ||
-                       (b.starttime != m.starttime) ||
-                       (b.endtime != m.endtime) ||
-                       (b.renew_till != m.renew_till)) return FALSE;
-               }
-               
-       if (bitTst(whichfields, KRB5_TC_MATCH_AUTHDATA)) {
-               bp = base->authdata;
-               mp = match->authdata;
-               if ((bp != NULL) && (mp != NULL)) {
-               while ( (bp) && (*bp != NULL) ){
-                       if (( (*bp)->ad_type != (*mp)->ad_type) ||
-                               ( (*bp)->length != (*mp)->length) ||
-                               ( memcmp( (*bp)->contents, (*mp)->contents, (*bp)->length) != 0)) return FALSE;
-                       mp++; bp++;
-               }
-         }
-       }
+       if (((MATCH_SET(KRB5_TC_MATCH_SRV_NAMEONLY) &&
+             srvname_match(context, match, base)) ||
+            standard_fields_match(context, match, base))
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_IS_SKEY) ||
+            match->is_skey == base->is_skey)
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_FLAGS_EXACT) ||
+            match->ticket_flags == base->ticket_flags)
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_FLAGS) ||
+            flags_match(match->ticket_flags, base->ticket_flags))
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_TIMES_EXACT) ||
+            times_match_exact(&match->times, &base->times))
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_TIMES) ||
+            times_match(&match->times, &base->times))
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_AUTHDATA) ||
+            authdata_match (match->authdata, base->authdata))
+           &&
+           (! MATCH_SET(KRB5_TC_MATCH_2ND_TKT) ||
+            data_match (&match->second_ticket, &base->second_ticket))
+           &&
+           ((! MATCH_SET(KRB5_TC_MATCH_KTYPE))||
+            (match->keyblock.enctype == base->keyblock.enctype))
+           )
+               return TRUE;
+       return FALSE;
        
-       if (bitTst(whichfields, KRB5_TC_MATCH_SRV_NAMEONLY)) {
-               //taken from cc_retrv.c
-               retval = krb5_principal_compare(context, base->client,match->client);
-               if (!retval) return FALSE;
-         
-         }
-        
-       if (bitTst(whichfields, KRB5_TC_MATCH_2ND_TKT)) 
-               if ( (base->second_ticket.length != match->second_ticket.length) ||
-                       (memcmp(base->second_ticket.data, match->second_ticket.data, base->second_ticket.length) != 0))
-                       return FALSE;
-                       
-       if (bitTst(whichfields, KRB5_TC_MATCH_KTYPE))
-               if (base->keyblock.enctype != match->keyblock.enctype) return FALSE;
-                       
-       //if we fall through to here, they must match
-       return TRUE;
 }