17c478bd9Sstevel@tonic-gate /*
2159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * lib/krb5/ccache/cc_retr.c
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Copyright 1990,1991,1999 by the Massachusetts Institute of Technology.
117c478bd9Sstevel@tonic-gate  * All Rights Reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
147c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
157c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
167c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
17*55fea89dSDan Cross  *
187c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
197c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
207c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
217c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
227c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
237c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
247c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
257c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
267c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
277c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
287c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
297c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
307c478bd9Sstevel@tonic-gate  * or implied warranty.
31*55fea89dSDan Cross  *
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
35159d09a2SMark Phalan #include "k5-int.h"
36505d05c7Sgtb #include "cc-int.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #define KRB5_OK 0
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #define set(bits) (whichfields & bits)
417c478bd9Sstevel@tonic-gate #define flags_match(a,b) (((a) & (b)) == (a))
427c478bd9Sstevel@tonic-gate #define times_match_exact(t1,t2) (memcmp((char *)(t1), (char *)(t2), sizeof(*(t1))) == 0)
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static krb5_boolean
times_match(const krb5_ticket_times * t1,const krb5_ticket_times * t2)45505d05c7Sgtb times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
467c478bd9Sstevel@tonic-gate {
477c478bd9Sstevel@tonic-gate     if (t1->renew_till) {
487c478bd9Sstevel@tonic-gate 	if (t1->renew_till > t2->renew_till)
497c478bd9Sstevel@tonic-gate 	    return FALSE;		/* this one expires too late */
507c478bd9Sstevel@tonic-gate     }
517c478bd9Sstevel@tonic-gate     if (t1->endtime) {
527c478bd9Sstevel@tonic-gate 	if (t1->endtime > t2->endtime)
537c478bd9Sstevel@tonic-gate 	    return FALSE;		/* this one expires too late */
547c478bd9Sstevel@tonic-gate     }
557c478bd9Sstevel@tonic-gate     /* only care about expiration on a times_match */
567c478bd9Sstevel@tonic-gate     return TRUE;
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static krb5_boolean
standard_fields_match(krb5_context context,const krb5_creds * mcreds,const krb5_creds * creds)60505d05c7Sgtb standard_fields_match(krb5_context context, const krb5_creds *mcreds, const krb5_creds *creds)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate   return (krb5_principal_compare(context, mcreds->client,creds->client)
637c478bd9Sstevel@tonic-gate 	  && krb5_principal_compare(context, mcreds->server,creds->server));
647c478bd9Sstevel@tonic-gate }
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /* only match the server name portion, not the server realm portion */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static krb5_boolean
srvname_match(krb5_context context,const krb5_creds * mcreds,const krb5_creds * creds)69505d05c7Sgtb srvname_match(krb5_context context, const krb5_creds *mcreds, const krb5_creds *creds)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate     krb5_boolean retval;
727c478bd9Sstevel@tonic-gate     krb5_principal_data p1, p2;
73*55fea89dSDan Cross 
747c478bd9Sstevel@tonic-gate     retval = krb5_principal_compare(context, mcreds->client,creds->client);
757c478bd9Sstevel@tonic-gate     if (retval != TRUE)
767c478bd9Sstevel@tonic-gate 	return retval;
777c478bd9Sstevel@tonic-gate     /*
787c478bd9Sstevel@tonic-gate      * Hack to ignore the server realm for the purposes of the compare.
797c478bd9Sstevel@tonic-gate      */
807c478bd9Sstevel@tonic-gate     p1 = *mcreds->server;
817c478bd9Sstevel@tonic-gate     p2 = *creds->server;
827c478bd9Sstevel@tonic-gate     p1.realm = p2.realm;
837c478bd9Sstevel@tonic-gate     return krb5_principal_compare(context, &p1, &p2);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static krb5_boolean
authdata_match(krb5_authdata * const * mdata,krb5_authdata * const * data)87159d09a2SMark Phalan authdata_match(krb5_authdata *const *mdata, krb5_authdata *const *data)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate     const krb5_authdata *mdatap, *datap;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate     if (mdata == data)
927c478bd9Sstevel@tonic-gate       return TRUE;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate     if (mdata == NULL)
957c478bd9Sstevel@tonic-gate 	return *data == NULL;
96*55fea89dSDan Cross 
977c478bd9Sstevel@tonic-gate     if (data == NULL)
987c478bd9Sstevel@tonic-gate 	return *mdata == NULL;
99*55fea89dSDan Cross 
1007c478bd9Sstevel@tonic-gate     /*LINTED*/
1017c478bd9Sstevel@tonic-gate     while ((mdatap = *mdata) && (datap = *data)) {
1027c478bd9Sstevel@tonic-gate       if ((mdatap->ad_type != datap->ad_type) ||
1037c478bd9Sstevel@tonic-gate           (mdatap->length != datap->length) ||
1047c478bd9Sstevel@tonic-gate           (memcmp ((char *)mdatap->contents,
105159d09a2SMark Phalan 		 (char *)datap->contents, (unsigned) mdatap->length) != 0))
1067c478bd9Sstevel@tonic-gate           return FALSE;
1077c478bd9Sstevel@tonic-gate       mdata++;
1087c478bd9Sstevel@tonic-gate       data++;
1097c478bd9Sstevel@tonic-gate     }
1107c478bd9Sstevel@tonic-gate     return (*mdata == NULL) && (*data == NULL);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static krb5_boolean
data_match(const krb5_data * data1,const krb5_data * data2)114505d05c7Sgtb data_match(const krb5_data *data1, const krb5_data *data2)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate     if (!data1) {
1177c478bd9Sstevel@tonic-gate 	if (!data2)
1187c478bd9Sstevel@tonic-gate 	    return TRUE;
1197c478bd9Sstevel@tonic-gate 	else
1207c478bd9Sstevel@tonic-gate 	    return FALSE;
1217c478bd9Sstevel@tonic-gate     }
1227c478bd9Sstevel@tonic-gate     if (!data2) return FALSE;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate     if (data1->length != data2->length)
1257c478bd9Sstevel@tonic-gate 	return FALSE;
1267c478bd9Sstevel@tonic-gate     else
127*55fea89dSDan Cross 	return memcmp(data1->data, data2->data, (unsigned) data1->length)
128159d09a2SMark Phalan 	  ? FALSE : TRUE;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static int
pref(krb5_enctype my_ktype,int nktypes,krb5_enctype * ktypes)1327c478bd9Sstevel@tonic-gate pref (krb5_enctype my_ktype, int nktypes, krb5_enctype *ktypes)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate   int i;
1357c478bd9Sstevel@tonic-gate   for (i = 0; i < nktypes; i++)
1367c478bd9Sstevel@tonic-gate     if (my_ktype == ktypes[i])
1377c478bd9Sstevel@tonic-gate       return i;
1387c478bd9Sstevel@tonic-gate   return -1;
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * Effects:
1437c478bd9Sstevel@tonic-gate  * Searches the credentials cache for a credential matching mcreds,
1447c478bd9Sstevel@tonic-gate  * with the fields specified by whichfields.  If one if found, it is
1457c478bd9Sstevel@tonic-gate  * returned in creds, which should be freed by the caller with
1467c478bd9Sstevel@tonic-gate  * krb5_free_credentials().
147*55fea89dSDan Cross  *
1487c478bd9Sstevel@tonic-gate  * The fields are interpreted in the following way (all constants are
1497c478bd9Sstevel@tonic-gate  * preceded by KRB5_TC_).  MATCH_IS_SKEY requires the is_skey field to
1507c478bd9Sstevel@tonic-gate  * match exactly.  MATCH_TIMES requires the requested lifetime to be
1517c478bd9Sstevel@tonic-gate  * at least as great as that specified; MATCH_TIMES_EXACT requires the
1527c478bd9Sstevel@tonic-gate  * requested lifetime to be exactly that specified.  MATCH_FLAGS
1537c478bd9Sstevel@tonic-gate  * requires only the set bits in mcreds be set in creds;
1547c478bd9Sstevel@tonic-gate  * MATCH_FLAGS_EXACT requires all bits to match.
1557c478bd9Sstevel@tonic-gate  *
1567c478bd9Sstevel@tonic-gate  * Flag SUPPORTED_KTYPES means check all matching entries that have
1577c478bd9Sstevel@tonic-gate  * any supported enctype (according to tgs_enctypes) and return the one
1587c478bd9Sstevel@tonic-gate  * with the enctype listed earliest.  Return CC_NOT_KTYPE if a match
1597c478bd9Sstevel@tonic-gate  * is found *except* for having a supported enctype.
1607c478bd9Sstevel@tonic-gate  *
1617c478bd9Sstevel@tonic-gate  * Errors:
1627c478bd9Sstevel@tonic-gate  * system errors
1637c478bd9Sstevel@tonic-gate  * permission errors
1647c478bd9Sstevel@tonic-gate  * KRB5_CC_NOMEM
1657c478bd9Sstevel@tonic-gate  * KRB5_CC_NOT_KTYPE
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate 
168505d05c7Sgtb krb5_boolean
krb5int_cc_creds_match_request(krb5_context context,krb5_flags whichfields,krb5_creds * mcreds,krb5_creds * creds)169505d05c7Sgtb krb5int_cc_creds_match_request(krb5_context context, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds)
170505d05c7Sgtb {
171505d05c7Sgtb     if (((set(KRB5_TC_MATCH_SRV_NAMEONLY) &&
172505d05c7Sgtb 		   srvname_match(context, mcreds, creds)) ||
173505d05c7Sgtb 	       standard_fields_match(context, mcreds, creds))
174505d05c7Sgtb 	      &&
175505d05c7Sgtb 	      (! set(KRB5_TC_MATCH_IS_SKEY) ||
176505d05c7Sgtb 	       mcreds->is_skey == creds->is_skey)
177505d05c7Sgtb 	      &&
178505d05c7Sgtb 	      (! set(KRB5_TC_MATCH_FLAGS_EXACT) ||
179505d05c7Sgtb 	       mcreds->ticket_flags == creds->ticket_flags)
180505d05c7Sgtb 	      &&
181505d05c7Sgtb 	      (! set(KRB5_TC_MATCH_FLAGS) ||
182505d05c7Sgtb 	       flags_match(mcreds->ticket_flags, creds->ticket_flags))
183505d05c7Sgtb 	      &&
184505d05c7Sgtb 	      (! set(KRB5_TC_MATCH_TIMES_EXACT) ||
185505d05c7Sgtb 	       times_match_exact(&mcreds->times, &creds->times))
186505d05c7Sgtb 	      &&
187505d05c7Sgtb 	      (! set(KRB5_TC_MATCH_TIMES) ||
188505d05c7Sgtb 	       times_match(&mcreds->times, &creds->times))
189505d05c7Sgtb 	      &&
190505d05c7Sgtb 	      ( ! set(KRB5_TC_MATCH_AUTHDATA) ||
191505d05c7Sgtb 	       authdata_match(mcreds->authdata, creds->authdata))
192505d05c7Sgtb 	      &&
193505d05c7Sgtb 	      (! set(KRB5_TC_MATCH_2ND_TKT) ||
194505d05c7Sgtb 	       data_match (&mcreds->second_ticket, &creds->second_ticket))
195505d05c7Sgtb 	      &&
196505d05c7Sgtb 	     ((! set(KRB5_TC_MATCH_KTYPE))||
197505d05c7Sgtb 		(mcreds->keyblock.enctype == creds->keyblock.enctype)))
198505d05c7Sgtb         return TRUE;
199505d05c7Sgtb     return FALSE;
200505d05c7Sgtb }
201505d05c7Sgtb 
2027c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_cc_retrieve_cred_seq(krb5_context context,krb5_ccache id,krb5_flags whichfields,krb5_creds * mcreds,krb5_creds * creds,int nktypes,krb5_enctype * ktypes)203159d09a2SMark Phalan krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id,
204159d09a2SMark Phalan 			   krb5_flags whichfields, krb5_creds *mcreds,
205159d09a2SMark Phalan 			   krb5_creds *creds, int nktypes, krb5_enctype *ktypes)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate      /* This function could be considerably faster if it kept indexing */
2087c478bd9Sstevel@tonic-gate      /* information.. sounds like a "next version" idea to me. :-) */
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate      krb5_cc_cursor cursor;
2117c478bd9Sstevel@tonic-gate      krb5_error_code kret;
2127c478bd9Sstevel@tonic-gate      krb5_error_code nomatch_err = KRB5_CC_NOTFOUND;
2137c478bd9Sstevel@tonic-gate      struct {
2147c478bd9Sstevel@tonic-gate        krb5_creds creds;
2157c478bd9Sstevel@tonic-gate        int pref;
2167c478bd9Sstevel@tonic-gate      } fetched, best;
2177c478bd9Sstevel@tonic-gate      int have_creds = 0;
218159d09a2SMark Phalan      krb5_flags oflags = 0;
2197c478bd9Sstevel@tonic-gate #define fetchcreds (fetched.creds)
2207c478bd9Sstevel@tonic-gate 
221159d09a2SMark Phalan      /* Solaris Kerberos */
2227c478bd9Sstevel@tonic-gate      memset(&best, 0, sizeof (best));
2237c478bd9Sstevel@tonic-gate      memset(&fetched, 0, sizeof (fetched));
2247c478bd9Sstevel@tonic-gate 
225159d09a2SMark Phalan      kret = krb5_cc_get_flags(context, id, &oflags);
2267c478bd9Sstevel@tonic-gate      if (kret != KRB5_OK)
2277c478bd9Sstevel@tonic-gate 	  return kret;
228159d09a2SMark Phalan      if (oflags & KRB5_TC_OPENCLOSE)
229159d09a2SMark Phalan 	 (void) krb5_cc_set_flags(context, id, oflags & ~KRB5_TC_OPENCLOSE);
230159d09a2SMark Phalan      kret = krb5_cc_start_seq_get(context, id, &cursor);
231159d09a2SMark Phalan      if (kret != KRB5_OK) {
232159d09a2SMark Phalan 	  if (oflags & KRB5_TC_OPENCLOSE)
233159d09a2SMark Phalan 	       krb5_cc_set_flags(context, id, oflags);
234159d09a2SMark Phalan 	  return kret;
235159d09a2SMark Phalan      }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate      while ((kret = krb5_cc_next_cred(context, id, &cursor, &fetchcreds)) == KRB5_OK) {
238159d09a2SMark Phalan       if (krb5int_cc_creds_match_request(context, whichfields, mcreds, &fetchcreds))
239159d09a2SMark Phalan       {
2407c478bd9Sstevel@tonic-gate 	      if (ktypes) {
2417c478bd9Sstevel@tonic-gate 		  fetched.pref = pref (fetchcreds.keyblock.enctype,
2427c478bd9Sstevel@tonic-gate 				       nktypes, ktypes);
2437c478bd9Sstevel@tonic-gate 		  if (fetched.pref < 0)
2447c478bd9Sstevel@tonic-gate 		      nomatch_err = KRB5_CC_NOT_KTYPE;
2457c478bd9Sstevel@tonic-gate 		  else if (!have_creds || fetched.pref < best.pref) {
2467c478bd9Sstevel@tonic-gate 		      if (have_creds)
2477c478bd9Sstevel@tonic-gate 			  krb5_free_cred_contents (context, &best.creds);
2487c478bd9Sstevel@tonic-gate 		      else
2497c478bd9Sstevel@tonic-gate 			  have_creds = 1;
2507c478bd9Sstevel@tonic-gate 		      best = fetched;
2517c478bd9Sstevel@tonic-gate 		      continue;
2527c478bd9Sstevel@tonic-gate 		  }
2537c478bd9Sstevel@tonic-gate 	      } else {
254159d09a2SMark Phalan 		  krb5_cc_end_seq_get(context, id, &cursor);
2557c478bd9Sstevel@tonic-gate 		  *creds = fetchcreds;
256159d09a2SMark Phalan 		  /* Solaris Kerberos */
2577c478bd9Sstevel@tonic-gate 		  creds->keyblock.hKey = CK_INVALID_HANDLE;
258159d09a2SMark Phalan 		  if (oflags & KRB5_TC_OPENCLOSE)
259159d09a2SMark Phalan 		      krb5_cc_set_flags(context, id, oflags);
2607c478bd9Sstevel@tonic-gate 		  return KRB5_OK;
2617c478bd9Sstevel@tonic-gate 	      }
2627c478bd9Sstevel@tonic-gate 	  }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	  /* This one doesn't match */
2657c478bd9Sstevel@tonic-gate 	  krb5_free_cred_contents(context, &fetchcreds);
2667c478bd9Sstevel@tonic-gate      }
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate      /* If we get here, a match wasn't found */
269159d09a2SMark Phalan      krb5_cc_end_seq_get(context, id, &cursor);
270159d09a2SMark Phalan      if (oflags & KRB5_TC_OPENCLOSE)
271159d09a2SMark Phalan 	 krb5_cc_set_flags(context, id, oflags);
2727c478bd9Sstevel@tonic-gate      if (have_creds) {
2737c478bd9Sstevel@tonic-gate 	 *creds = best.creds;
274159d09a2SMark Phalan 	 /* Solaris Kerberos */
2757c478bd9Sstevel@tonic-gate 	 creds->keyblock.hKey = CK_INVALID_HANDLE;
2767c478bd9Sstevel@tonic-gate 	 return KRB5_OK;
2777c478bd9Sstevel@tonic-gate      } else
2787c478bd9Sstevel@tonic-gate 	 return nomatch_err;
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_cc_retrieve_cred_default(krb5_context context,krb5_ccache id,krb5_flags flags,krb5_creds * mcreds,krb5_creds * creds)282505d05c7Sgtb krb5_cc_retrieve_cred_default (krb5_context context, krb5_ccache id, krb5_flags flags, krb5_creds *mcreds, krb5_creds *creds)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate     krb5_enctype *ktypes;
2857c478bd9Sstevel@tonic-gate     int nktypes;
2867c478bd9Sstevel@tonic-gate     krb5_error_code ret;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate     if (flags & KRB5_TC_SUPPORTED_KTYPES) {
2897c478bd9Sstevel@tonic-gate 	ret = krb5_get_tgs_ktypes (context, mcreds->server, &ktypes);
2907c478bd9Sstevel@tonic-gate 	if (ret)
2917c478bd9Sstevel@tonic-gate 	    return ret;
2927c478bd9Sstevel@tonic-gate 	nktypes = 0;
2937c478bd9Sstevel@tonic-gate 	while (ktypes[nktypes])
2947c478bd9Sstevel@tonic-gate 	    nktypes++;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	ret = krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
2977c478bd9Sstevel@tonic-gate 					 nktypes, ktypes);
2987c478bd9Sstevel@tonic-gate 	free (ktypes);
2997c478bd9Sstevel@tonic-gate 	return ret;
3007c478bd9Sstevel@tonic-gate     } else {
301159d09a2SMark Phalan 	/* Solaris Kerberos */
3027c478bd9Sstevel@tonic-gate 	return krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
3037c478bd9Sstevel@tonic-gate 					  0, (krb5_enctype *)NULL);
3047c478bd9Sstevel@tonic-gate     }
3057c478bd9Sstevel@tonic-gate }
306159d09a2SMark Phalan 
307159d09a2SMark Phalan /* The following function duplicates some of the functionality above and */
308159d09a2SMark Phalan /* should probably be merged with it at some point.  It is used by the   */
309159d09a2SMark Phalan /* CCAPI krb5_cc_remove to figure out if the opaque credentials object   */
310159d09a2SMark Phalan /* returned by the CCAPI is the same creds as the caller passed in.      */
311159d09a2SMark Phalan /* Unlike the code above it requires that all structures be identical.   */
312159d09a2SMark Phalan 
313*55fea89dSDan Cross krb5_boolean KRB5_CALLCONV
krb5_creds_compare(krb5_context in_context,krb5_creds * in_creds,krb5_creds * in_compare_creds)314159d09a2SMark Phalan krb5_creds_compare (krb5_context in_context,
315159d09a2SMark Phalan                     krb5_creds *in_creds,
316159d09a2SMark Phalan                     krb5_creds *in_compare_creds)
317159d09a2SMark Phalan {
318159d09a2SMark Phalan     /* Set to 0 when we hit the first mismatch and then fall through */
319159d09a2SMark Phalan     int equal = 1;
320*55fea89dSDan Cross 
321159d09a2SMark Phalan     if (equal) {
322*55fea89dSDan Cross         equal = krb5_principal_compare (in_context, in_creds->client,
323159d09a2SMark Phalan                                         in_compare_creds->client);
324159d09a2SMark Phalan     }
325*55fea89dSDan Cross 
326159d09a2SMark Phalan     if (equal) {
327*55fea89dSDan Cross         equal = krb5_principal_compare (in_context, in_creds->server,
328159d09a2SMark Phalan                                         in_compare_creds->server);
329159d09a2SMark Phalan     }
330*55fea89dSDan Cross 
331159d09a2SMark Phalan     if (equal) {
332159d09a2SMark Phalan         equal = (in_creds->keyblock.enctype == in_compare_creds->keyblock.enctype &&
333159d09a2SMark Phalan                  in_creds->keyblock.length  == in_compare_creds->keyblock.length &&
334159d09a2SMark Phalan                  (!in_creds->keyblock.length ||
335159d09a2SMark Phalan                   !memcmp (in_creds->keyblock.contents, in_compare_creds->keyblock.contents,
336159d09a2SMark Phalan                            in_creds->keyblock.length)));
337159d09a2SMark Phalan     }
338*55fea89dSDan Cross 
339*55fea89dSDan Cross     if (equal) {
340159d09a2SMark Phalan         equal = (in_creds->times.authtime   == in_compare_creds->times.authtime &&
341159d09a2SMark Phalan                  in_creds->times.starttime  == in_compare_creds->times.starttime &&
342159d09a2SMark Phalan                  in_creds->times.endtime    == in_compare_creds->times.endtime &&
343159d09a2SMark Phalan                  in_creds->times.renew_till == in_compare_creds->times.renew_till);
344159d09a2SMark Phalan     }
345*55fea89dSDan Cross 
346159d09a2SMark Phalan     if (equal) {
347159d09a2SMark Phalan         equal = (in_creds->is_skey == in_compare_creds->is_skey);
348*55fea89dSDan Cross     }
349*55fea89dSDan Cross 
350159d09a2SMark Phalan     if (equal) {
351159d09a2SMark Phalan         equal = (in_creds->ticket_flags == in_compare_creds->ticket_flags);
352159d09a2SMark Phalan     }
353*55fea89dSDan Cross 
354159d09a2SMark Phalan     if (equal) {
355159d09a2SMark Phalan         krb5_address **addresses = in_creds->addresses;
356159d09a2SMark Phalan         krb5_address **compare_addresses = in_compare_creds->addresses;
357159d09a2SMark Phalan         unsigned int i;
358*55fea89dSDan Cross 
359159d09a2SMark Phalan         if (addresses && compare_addresses) {
360159d09a2SMark Phalan             for (i = 0; (equal && addresses[i] && compare_addresses[i]); i++) {
361159d09a2SMark Phalan                 equal = krb5_address_compare (in_context, addresses[i],
362159d09a2SMark Phalan                                               compare_addresses[i]);
363159d09a2SMark Phalan             }
364159d09a2SMark Phalan             if (equal) { equal = (!addresses[i] && !compare_addresses[i]); }
365159d09a2SMark Phalan         } else {
366159d09a2SMark Phalan             if (equal) { equal = (!addresses && !compare_addresses); }
367159d09a2SMark Phalan         }
368159d09a2SMark Phalan     }
369*55fea89dSDan Cross 
370159d09a2SMark Phalan     if (equal) {
371159d09a2SMark Phalan         equal = (in_creds->ticket.length  == in_compare_creds->ticket.length &&
372159d09a2SMark Phalan                  (!in_creds->ticket.length ||
373159d09a2SMark Phalan                   !memcmp (in_creds->ticket.data, in_compare_creds->ticket.data,
374159d09a2SMark Phalan                            in_creds->ticket.length)));
375159d09a2SMark Phalan     }
376*55fea89dSDan Cross 
377159d09a2SMark Phalan     if (equal) {
378159d09a2SMark Phalan         equal = (in_creds->second_ticket.length  == in_compare_creds->second_ticket.length &&
379159d09a2SMark Phalan                  (!in_creds->second_ticket.length ||
380159d09a2SMark Phalan                   !memcmp (in_creds->second_ticket.data, in_compare_creds->second_ticket.data,
381159d09a2SMark Phalan                            in_creds->second_ticket.length)));
382159d09a2SMark Phalan     }
383*55fea89dSDan Cross 
384159d09a2SMark Phalan     if (equal) {
385159d09a2SMark Phalan         krb5_authdata **authdata = in_creds->authdata;
386159d09a2SMark Phalan         krb5_authdata **compare_authdata = in_compare_creds->authdata;
387159d09a2SMark Phalan         unsigned int i;
388*55fea89dSDan Cross 
389*55fea89dSDan Cross         if (authdata && compare_authdata) {
390159d09a2SMark Phalan             for (i = 0; (equal && authdata[i] && compare_authdata[i]); i++) {
391159d09a2SMark Phalan                 equal = (authdata[i]->ad_type == compare_authdata[i]->ad_type &&
392159d09a2SMark Phalan                          authdata[i]->length  == compare_authdata[i]->length &&
393*55fea89dSDan Cross                          (!authdata[i]->length ||
394159d09a2SMark Phalan                           !memcmp (authdata[i]->contents, compare_authdata[i]->contents,
395159d09a2SMark Phalan                                    authdata[i]->length)));
396159d09a2SMark Phalan             }
397159d09a2SMark Phalan             if (equal) { equal = (!authdata[i] && !compare_authdata[i]); }
398159d09a2SMark Phalan         } else {
399159d09a2SMark Phalan             if (equal) { equal = (!authdata && !compare_authdata); }
400159d09a2SMark Phalan         }
401159d09a2SMark Phalan     }
402*55fea89dSDan Cross 
403159d09a2SMark Phalan     return equal;
404159d09a2SMark Phalan }
405