From 6af7079089f3ff2291f2ae77173f5f008e8dfc44 Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Thu, 18 Feb 1999 04:28:12 +0000 Subject: [PATCH] Added debugging hooks to stdcc.c 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 | 93 ++++++++++- src/lib/krb5/ccache/ccapi/stdcc_util.c | 206 ++++++++++++++++--------- 2 files changed, 222 insertions(+), 77 deletions(-) diff --git a/src/lib/krb5/ccache/ccapi/stdcc.c b/src/lib/krb5/ccache/ccapi/stdcc.c index 4912ba159..b81e82a7d 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc.c +++ b/src/lib/krb5/ccache/ccapi/stdcc.c @@ -25,6 +25,7 @@ * */ +#define NEED_WINDOWS #include "stdcc.h" #include "stdcc_util.h" #include "string.h" @@ -32,6 +33,19 @@ #if defined(_MSDOS) || defined(_WIN32) apiCB *gCntrlBlock = NULL; +#else +#define CC_API_VER2 +#endif + +#ifdef DEBUG +#if defined(_MSDOS) || defined(_WIN32) +#include +#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); diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c index dd44109ad..3c6917ad9 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc_util.c +++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c @@ -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; } -- 2.26.2