xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_file.c (revision 3f2304d3d03b914a6bc6784aac74829493a6ec31)
17c478bd9Sstevel@tonic-gate /*
2*16d62afbSNicolas Williams  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights
3*16d62afbSNicolas Williams  * reserved.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * lib/krb5/rcache/rc_file.c
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * This file of the Kerberos V5 software is derived from public-domain code
117c478bd9Sstevel@tonic-gate  * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
15159d09a2SMark Phalan 
167c478bd9Sstevel@tonic-gate /*
177c478bd9Sstevel@tonic-gate  * An implementation for the default replay cache type.
187c478bd9Sstevel@tonic-gate  */
19159d09a2SMark Phalan /* Solaris Kerberos */
20159d09a2SMark Phalan #define FREE_RC(x) ((void) free((char *) (x)))
217c478bd9Sstevel@tonic-gate #include "rc_common.h"
227c478bd9Sstevel@tonic-gate #include "rc_file.h"
237c478bd9Sstevel@tonic-gate 
24*16d62afbSNicolas Williams /* Solaris Kerberos */
25*16d62afbSNicolas Williams #include <kstat.h>
26*16d62afbSNicolas Williams #include <atomic.h>
27*16d62afbSNicolas Williams #include <assert.h>
28*16d62afbSNicolas Williams #include <syslog.h>
29*16d62afbSNicolas Williams 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Solaris: The NOIOSTUFF macro has been taken out for the Solaris version
327c478bd9Sstevel@tonic-gate  * of this module, because this has been split into a separate mem rcache.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /* of course, list is backwards from file */
367c478bd9Sstevel@tonic-gate /* hash could be forwards since we have to search on match, but naaaah */
377c478bd9Sstevel@tonic-gate 
38159d09a2SMark Phalan static int
rc_store(krb5_context context,krb5_rcache id,krb5_donot_replay * rep)39159d09a2SMark Phalan rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep)
407c478bd9Sstevel@tonic-gate {
417c478bd9Sstevel@tonic-gate     struct file_data *t = (struct file_data *)id->data;
427c478bd9Sstevel@tonic-gate     int rephash;
437c478bd9Sstevel@tonic-gate     struct authlist *ta;
447c478bd9Sstevel@tonic-gate     krb5_int32 time;
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate     rephash = hash(rep, t->hsize);
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate     /* Solaris: calling krb_timeofday() here, once for better perf. */
497c478bd9Sstevel@tonic-gate     krb5_timeofday(context, &time);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate     /* Solaris: calling alive() on rep since it doesn't make sense to store an
527c478bd9Sstevel@tonic-gate      * expired replay.
537c478bd9Sstevel@tonic-gate      */
547c478bd9Sstevel@tonic-gate     if (alive(context, rep, t->lifespan, time) == CMP_EXPIRED){
557c478bd9Sstevel@tonic-gate 	return CMP_EXPIRED;
567c478bd9Sstevel@tonic-gate     }
577c478bd9Sstevel@tonic-gate 
58159d09a2SMark Phalan     for (ta = t->h[rephash]; ta; ta = ta->nh) {
597c478bd9Sstevel@tonic-gate 	switch(cmp(&ta->rep, rep))
607c478bd9Sstevel@tonic-gate 	{
61159d09a2SMark Phalan 	case CMP_REPLAY:
62159d09a2SMark Phalan 	    return CMP_REPLAY;
63159d09a2SMark Phalan 	case CMP_HOHUM:
64159d09a2SMark Phalan 	    if (alive(context, &ta->rep, t->lifespan, time) == CMP_EXPIRED)
657c478bd9Sstevel@tonic-gate 		t->nummisses++;
667c478bd9Sstevel@tonic-gate 	    else
677c478bd9Sstevel@tonic-gate 		t->numhits++;
687c478bd9Sstevel@tonic-gate 	    break;
69159d09a2SMark Phalan 	default:
70159d09a2SMark Phalan 	    ; /* wtf? */
71159d09a2SMark Phalan 	}
727c478bd9Sstevel@tonic-gate     }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate     if (!(ta = (struct authlist *) malloc(sizeof(struct authlist))))
757c478bd9Sstevel@tonic-gate 	return CMP_MALLOC;
767c478bd9Sstevel@tonic-gate     ta->rep = *rep;
777c478bd9Sstevel@tonic-gate     if (!(ta->rep.client = strdup(rep->client))) {
78159d09a2SMark Phalan 	FREE_RC(ta);
797c478bd9Sstevel@tonic-gate 	return CMP_MALLOC;
807c478bd9Sstevel@tonic-gate     }
817c478bd9Sstevel@tonic-gate     if (!(ta->rep.server = strdup(rep->server))) {
82159d09a2SMark Phalan 	FREE_RC(ta->rep.client);
83159d09a2SMark Phalan 	FREE_RC(ta);
847c478bd9Sstevel@tonic-gate 	return CMP_MALLOC;
857c478bd9Sstevel@tonic-gate     }
867c478bd9Sstevel@tonic-gate     ta->na = t->a; t->a = ta;
877c478bd9Sstevel@tonic-gate     ta->nh = t->h[rephash]; t->h[rephash] = ta;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate     return CMP_HOHUM;
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
937c478bd9Sstevel@tonic-gate char * KRB5_CALLCONV
krb5_rc_file_get_name(krb5_context context,krb5_rcache id)94159d09a2SMark Phalan krb5_rc_file_get_name(krb5_context context, krb5_rcache id)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate  return ((struct file_data *) (id->data))->name;
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1007c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_rc_file_get_span(krb5_context context,krb5_rcache id,krb5_deltat * lifespan)101159d09a2SMark Phalan krb5_rc_file_get_span(krb5_context context, krb5_rcache id,
102159d09a2SMark Phalan 		     krb5_deltat *lifespan)
1037c478bd9Sstevel@tonic-gate {
104505d05c7Sgtb     krb5_error_code err;
105505d05c7Sgtb     struct file_data *t;
106505d05c7Sgtb 
107505d05c7Sgtb     err = k5_mutex_lock(&id->lock);
108505d05c7Sgtb     if (err)
109505d05c7Sgtb 	return err;
110505d05c7Sgtb     t = (struct file_data *) id->data;
111505d05c7Sgtb     *lifespan = t->lifespan;
112505d05c7Sgtb     k5_mutex_unlock(&id->lock);
1137c478bd9Sstevel@tonic-gate     return 0;
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
116159d09a2SMark Phalan static krb5_error_code KRB5_CALLCONV
krb5_rc_file_init_locked(krb5_context context,krb5_rcache id,krb5_deltat lifespan)117159d09a2SMark Phalan krb5_rc_file_init_locked(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate     struct file_data *t = (struct file_data *)id->data;
1207c478bd9Sstevel@tonic-gate     krb5_error_code retval;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate     t->lifespan = lifespan ? lifespan : context->clockskew;
1237c478bd9Sstevel@tonic-gate     /* default to clockskew from the context */
124159d09a2SMark Phalan     if ((retval = krb5_rc_io_creat(context, &t->d, &t->name))) {
1257c478bd9Sstevel@tonic-gate 	return retval;
126159d09a2SMark Phalan     }
1277c478bd9Sstevel@tonic-gate     if ((krb5_rc_io_write(context, &t->d,
1287c478bd9Sstevel@tonic-gate 			  (krb5_pointer) &t->lifespan, sizeof(t->lifespan))
129159d09a2SMark Phalan 	 || krb5_rc_io_sync(context, &t->d))) {
1307c478bd9Sstevel@tonic-gate 	return KRB5_RC_IO;
131159d09a2SMark Phalan     }
1327c478bd9Sstevel@tonic-gate     return 0;
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
135505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_rc_file_init(krb5_context context,krb5_rcache id,krb5_deltat lifespan)136505d05c7Sgtb krb5_rc_file_init(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
137505d05c7Sgtb {
138505d05c7Sgtb     krb5_error_code retval;
139505d05c7Sgtb 
140505d05c7Sgtb     retval = k5_mutex_lock(&id->lock);
141505d05c7Sgtb     if (retval)
142505d05c7Sgtb 	return retval;
143505d05c7Sgtb     retval = krb5_rc_file_init_locked(context, id, lifespan);
144505d05c7Sgtb     k5_mutex_unlock(&id->lock);
145505d05c7Sgtb     return retval;
146505d05c7Sgtb }
147505d05c7Sgtb 
148159d09a2SMark Phalan /* Called with the mutex already locked.  */
149159d09a2SMark Phalan krb5_error_code
krb5_rc_file_close_no_free(krb5_context context,krb5_rcache id)150159d09a2SMark Phalan krb5_rc_file_close_no_free(krb5_context context, krb5_rcache id)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate     struct file_data *t = (struct file_data *)id->data;
1537c478bd9Sstevel@tonic-gate     struct authlist *q;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate     if (t->h)
156159d09a2SMark Phalan 	FREE_RC(t->h);
1577c478bd9Sstevel@tonic-gate     if (t->name)
158159d09a2SMark Phalan 	FREE_RC(t->name);
159159d09a2SMark Phalan     while ((q = t->a))
1607c478bd9Sstevel@tonic-gate     {
1617c478bd9Sstevel@tonic-gate 	t->a = q->na;
162159d09a2SMark Phalan 	FREE_RC(q->rep.client);
163159d09a2SMark Phalan 	FREE_RC(q->rep.server);
164159d09a2SMark Phalan 	FREE_RC(q);
1657c478bd9Sstevel@tonic-gate     }
1667c478bd9Sstevel@tonic-gate     if (t->d.fd >= 0)
1677c478bd9Sstevel@tonic-gate         (void) krb5_rc_io_close(context, &t->d);
168159d09a2SMark Phalan     FREE_RC(t);
1697c478bd9Sstevel@tonic-gate     id->data = NULL;
1707c478bd9Sstevel@tonic-gate     return 0;
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_rc_file_close(krb5_context context,krb5_rcache id)174159d09a2SMark Phalan krb5_rc_file_close(krb5_context context, krb5_rcache id)
1757c478bd9Sstevel@tonic-gate {
176505d05c7Sgtb     krb5_error_code retval;
177505d05c7Sgtb     retval = k5_mutex_lock(&id->lock);
178505d05c7Sgtb     if (retval)
179505d05c7Sgtb 	return retval;
1807c478bd9Sstevel@tonic-gate     krb5_rc_file_close_no_free(context, id);
181505d05c7Sgtb     k5_mutex_unlock(&id->lock);
182505d05c7Sgtb     k5_mutex_destroy(&id->lock);
1837c478bd9Sstevel@tonic-gate     free(id);
1847c478bd9Sstevel@tonic-gate     return 0;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_rc_file_destroy(krb5_context context,krb5_rcache id)188159d09a2SMark Phalan krb5_rc_file_destroy(krb5_context context, krb5_rcache id)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate  if (krb5_rc_io_destroy(context, &((struct file_data *) (id->data))->d))
1917c478bd9Sstevel@tonic-gate    return KRB5_RC_IO;
1927c478bd9Sstevel@tonic-gate  return krb5_rc_file_close(context, id);
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1967c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_rc_file_resolve(krb5_context context,krb5_rcache id,char * name)197159d09a2SMark Phalan krb5_rc_file_resolve(krb5_context context, krb5_rcache id, char *name)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate     struct file_data *t = 0;
2007c478bd9Sstevel@tonic-gate     krb5_error_code retval;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate     /* allocate id? no */
2037c478bd9Sstevel@tonic-gate     if (!(t = (struct file_data *) malloc(sizeof(struct file_data))))
2047c478bd9Sstevel@tonic-gate 	return KRB5_RC_MALLOC;
2057c478bd9Sstevel@tonic-gate     id->data = (krb5_pointer) t;
2067c478bd9Sstevel@tonic-gate     memset(t, 0, sizeof(struct file_data));
2077c478bd9Sstevel@tonic-gate     if (name) {
2087c478bd9Sstevel@tonic-gate 	t->name = malloc(strlen(name)+1);
2097c478bd9Sstevel@tonic-gate 	if (!t->name) {
2107c478bd9Sstevel@tonic-gate 	    retval = KRB5_RC_MALLOC;
2117c478bd9Sstevel@tonic-gate 	    goto cleanup;
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 	strcpy(t->name, name);
2147c478bd9Sstevel@tonic-gate     } else
2157c478bd9Sstevel@tonic-gate 	t->name = 0;
2167c478bd9Sstevel@tonic-gate     t->numhits = t->nummisses = 0;
2177c478bd9Sstevel@tonic-gate     t->hsize = HASHSIZE; /* no need to store---it's memory-only */
2187c478bd9Sstevel@tonic-gate     t->h = (struct authlist **) malloc(t->hsize*sizeof(struct authlist *));
2197c478bd9Sstevel@tonic-gate     if (!t->h) {
2207c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_MALLOC;
2217c478bd9Sstevel@tonic-gate 	goto cleanup;
2227c478bd9Sstevel@tonic-gate     }
2237c478bd9Sstevel@tonic-gate     memset(t->h, 0, t->hsize*sizeof(struct authlist *));
2247c478bd9Sstevel@tonic-gate     t->a = (struct authlist *) 0;
2257c478bd9Sstevel@tonic-gate     t->d.fd = -1;
2267c478bd9Sstevel@tonic-gate     t->recovering = 0;
2277c478bd9Sstevel@tonic-gate     return 0;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate cleanup:
2307c478bd9Sstevel@tonic-gate     if (t) {
2317c478bd9Sstevel@tonic-gate 	if (t->name)
2327c478bd9Sstevel@tonic-gate 	    krb5_xfree(t->name);
2337c478bd9Sstevel@tonic-gate 	if (t->h)
2347c478bd9Sstevel@tonic-gate 	    krb5_xfree(t->h);
2357c478bd9Sstevel@tonic-gate 	krb5_xfree(t);
2367c478bd9Sstevel@tonic-gate 	id->data = NULL;
2377c478bd9Sstevel@tonic-gate     }
2387c478bd9Sstevel@tonic-gate     return retval;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*ARGSUSED*/
242159d09a2SMark Phalan void
krb5_rc_free_entry(krb5_context context,krb5_donot_replay ** rep)243159d09a2SMark Phalan krb5_rc_free_entry(krb5_context context, krb5_donot_replay **rep)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate     krb5_donot_replay *rp = *rep;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate     *rep = NULL;
2487c478bd9Sstevel@tonic-gate     if (rp)
2497c478bd9Sstevel@tonic-gate     {
2507c478bd9Sstevel@tonic-gate 	if (rp->client)
2517c478bd9Sstevel@tonic-gate 	    free(rp->client);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	if (rp->server)
2547c478bd9Sstevel@tonic-gate 	    free(rp->server);
2557c478bd9Sstevel@tonic-gate 	rp->client = NULL;
2567c478bd9Sstevel@tonic-gate 	rp->server = NULL;
2577c478bd9Sstevel@tonic-gate 	free(rp);
2587c478bd9Sstevel@tonic-gate     }
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
261159d09a2SMark Phalan static krb5_error_code
krb5_rc_io_fetch(krb5_context context,struct file_data * t,krb5_donot_replay * rep,int maxlen)262159d09a2SMark Phalan krb5_rc_io_fetch(krb5_context context, struct file_data *t,
263159d09a2SMark Phalan 		 krb5_donot_replay *rep, int maxlen)
2647c478bd9Sstevel@tonic-gate {
265159d09a2SMark Phalan     unsigned int len;
2667c478bd9Sstevel@tonic-gate     krb5_error_code retval;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate     rep->client = rep->server = 0;
2697c478bd9Sstevel@tonic-gate 
270159d09a2SMark Phalan     retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len,
271159d09a2SMark Phalan 			     sizeof(len));
2727c478bd9Sstevel@tonic-gate     if (retval)
2737c478bd9Sstevel@tonic-gate 	return retval;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate     if ((len <= 0) || (len >= maxlen))
2767c478bd9Sstevel@tonic-gate 	return KRB5_RC_IO_EOF;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate     rep->client = malloc (len);
2797c478bd9Sstevel@tonic-gate     if (!rep->client)
2807c478bd9Sstevel@tonic-gate 	return KRB5_RC_MALLOC;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate     retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) rep->client, len);
2837c478bd9Sstevel@tonic-gate     if (retval)
2847c478bd9Sstevel@tonic-gate 	goto errout;
2857c478bd9Sstevel@tonic-gate 
286159d09a2SMark Phalan     retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len,
287159d09a2SMark Phalan 			     sizeof(len));
2887c478bd9Sstevel@tonic-gate     if (retval)
2897c478bd9Sstevel@tonic-gate 	goto errout;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate     if ((len <= 0) || (len >= maxlen)) {
2927c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_IO_EOF;
2937c478bd9Sstevel@tonic-gate 	goto errout;
2947c478bd9Sstevel@tonic-gate     }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate     rep->server = malloc (len);
2977c478bd9Sstevel@tonic-gate     if (!rep->server) {
2987c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_MALLOC;
2997c478bd9Sstevel@tonic-gate 	goto errout;
3007c478bd9Sstevel@tonic-gate     }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate     retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) rep->server, len);
3037c478bd9Sstevel@tonic-gate     if (retval)
3047c478bd9Sstevel@tonic-gate 	goto errout;
3057c478bd9Sstevel@tonic-gate 
306159d09a2SMark Phalan     retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &rep->cusec,
307159d09a2SMark Phalan 			     sizeof(rep->cusec));
3087c478bd9Sstevel@tonic-gate     if (retval)
3097c478bd9Sstevel@tonic-gate 	goto errout;
3107c478bd9Sstevel@tonic-gate 
311159d09a2SMark Phalan     retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &rep->ctime,
312159d09a2SMark Phalan 			     sizeof(rep->ctime));
3137c478bd9Sstevel@tonic-gate     if (retval)
3147c478bd9Sstevel@tonic-gate 	goto errout;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate     return 0;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate errout:
3197c478bd9Sstevel@tonic-gate     if (rep->client)
3207c478bd9Sstevel@tonic-gate 	krb5_xfree(rep->client);
3217c478bd9Sstevel@tonic-gate     if (rep->server)
3227c478bd9Sstevel@tonic-gate 	krb5_xfree(rep->server);
3237c478bd9Sstevel@tonic-gate     rep->client = rep->server = 0;
3247c478bd9Sstevel@tonic-gate     return retval;
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
327159d09a2SMark Phalan 
328505d05c7Sgtb static krb5_error_code
329505d05c7Sgtb krb5_rc_file_expunge_locked(krb5_context context, krb5_rcache id);
330505d05c7Sgtb 
331505d05c7Sgtb static krb5_error_code
krb5_rc_file_recover_locked(krb5_context context,krb5_rcache id)332159d09a2SMark Phalan krb5_rc_file_recover_locked(krb5_context context, krb5_rcache id)
3337c478bd9Sstevel@tonic-gate {
3347c478bd9Sstevel@tonic-gate     struct file_data *t = (struct file_data *)id->data;
3357c478bd9Sstevel@tonic-gate     krb5_donot_replay *rep = 0;
3367c478bd9Sstevel@tonic-gate     krb5_error_code retval;
3377c478bd9Sstevel@tonic-gate     long max_size;
3387c478bd9Sstevel@tonic-gate     int expired_entries = 0;
3397c478bd9Sstevel@tonic-gate 
340159d09a2SMark Phalan     if ((retval = krb5_rc_io_open(context, &t->d, t->name))) {
3417c478bd9Sstevel@tonic-gate 	return retval;
342159d09a2SMark Phalan     }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate     t->recovering = 1;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate     max_size = krb5_rc_io_size(context, &t->d);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate     rep = NULL;
349159d09a2SMark Phalan     if (krb5_rc_io_read(context, &t->d, (krb5_pointer) &t->lifespan,
350159d09a2SMark Phalan 			sizeof(t->lifespan))) {
3517c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_IO;
3527c478bd9Sstevel@tonic-gate 	goto io_fail;
3537c478bd9Sstevel@tonic-gate     }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate     if (!(rep = (krb5_donot_replay *) malloc(sizeof(krb5_donot_replay)))) {
3567c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_MALLOC;
3577c478bd9Sstevel@tonic-gate 	goto io_fail;
3587c478bd9Sstevel@tonic-gate     }
3597c478bd9Sstevel@tonic-gate     rep->client = NULL;
3607c478bd9Sstevel@tonic-gate     rep->server = NULL;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate     /* now read in each auth_replay and insert into table */
3637c478bd9Sstevel@tonic-gate     for (;;) {
3647c478bd9Sstevel@tonic-gate 	if (krb5_rc_io_mark(context, &t->d)) {
3657c478bd9Sstevel@tonic-gate 	    retval = KRB5_RC_IO;
3667c478bd9Sstevel@tonic-gate 	    goto io_fail;
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	retval = krb5_rc_io_fetch (context, t, rep, (int) max_size);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if (retval == KRB5_RC_IO_EOF)
3727c478bd9Sstevel@tonic-gate 	    break;
3737c478bd9Sstevel@tonic-gate 	else if (retval != 0)
3747c478bd9Sstevel@tonic-gate 	    goto io_fail;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/* Solaris: made the change below for better perf. */
3777c478bd9Sstevel@tonic-gate 	switch (rc_store(context, id, rep)) {
3787c478bd9Sstevel@tonic-gate 	    case CMP_EXPIRED:
3797c478bd9Sstevel@tonic-gate 		expired_entries++;
3807c478bd9Sstevel@tonic-gate 		break;
3817c478bd9Sstevel@tonic-gate 	    case CMP_MALLOC:
3827c478bd9Sstevel@tonic-gate 		retval = KRB5_RC_MALLOC;
3837c478bd9Sstevel@tonic-gate 		goto io_fail;
3847c478bd9Sstevel@tonic-gate 		break;
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 *  free fields allocated by rc_io_fetch
3887c478bd9Sstevel@tonic-gate 	 */
389159d09a2SMark Phalan 	FREE_RC(rep->server);
390159d09a2SMark Phalan 	FREE_RC(rep->client);
3917c478bd9Sstevel@tonic-gate 	rep->server = 0;
3927c478bd9Sstevel@tonic-gate 	rep->client = 0;
3937c478bd9Sstevel@tonic-gate     }
3947c478bd9Sstevel@tonic-gate     retval = 0;
3957c478bd9Sstevel@tonic-gate     krb5_rc_io_unmark(context, &t->d);
3967c478bd9Sstevel@tonic-gate     /*
3977c478bd9Sstevel@tonic-gate      *  An automatic expunge here could remove the need for
3987c478bd9Sstevel@tonic-gate      *  mark/unmark but that would be inefficient.
3997c478bd9Sstevel@tonic-gate      */
4007c478bd9Sstevel@tonic-gate io_fail:
4017c478bd9Sstevel@tonic-gate     krb5_rc_free_entry(context, &rep);
4027c478bd9Sstevel@tonic-gate     if (retval)
4037c478bd9Sstevel@tonic-gate 	krb5_rc_io_close(context, &t->d);
4047c478bd9Sstevel@tonic-gate     else if (expired_entries > EXCESSREPS)
405505d05c7Sgtb 	retval = krb5_rc_file_expunge_locked(context, id);
4067c478bd9Sstevel@tonic-gate     t->recovering = 0;
4077c478bd9Sstevel@tonic-gate     return retval;
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate 
410505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_rc_file_recover(krb5_context context,krb5_rcache id)411505d05c7Sgtb krb5_rc_file_recover(krb5_context context, krb5_rcache id)
412505d05c7Sgtb {
413505d05c7Sgtb     krb5_error_code ret;
414505d05c7Sgtb     ret = k5_mutex_lock(&id->lock);
415505d05c7Sgtb     if (ret)
416505d05c7Sgtb 	return ret;
417505d05c7Sgtb     ret = krb5_rc_file_recover_locked(context, id);
418505d05c7Sgtb     k5_mutex_unlock(&id->lock);
419505d05c7Sgtb     return ret;
420505d05c7Sgtb }
421505d05c7Sgtb 
422505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_rc_file_recover_or_init(krb5_context context,krb5_rcache id,krb5_deltat lifespan)423505d05c7Sgtb krb5_rc_file_recover_or_init(krb5_context context, krb5_rcache id,
424505d05c7Sgtb 			    krb5_deltat lifespan)
425505d05c7Sgtb {
426505d05c7Sgtb     krb5_error_code retval;
427505d05c7Sgtb 
428505d05c7Sgtb     retval = k5_mutex_lock(&id->lock);
429505d05c7Sgtb     if (retval)
430505d05c7Sgtb 	return retval;
431505d05c7Sgtb     retval = krb5_rc_file_recover_locked(context, id);
432505d05c7Sgtb     if (retval)
433505d05c7Sgtb 	retval = krb5_rc_file_init_locked(context, id, lifespan);
434505d05c7Sgtb     k5_mutex_unlock(&id->lock);
435505d05c7Sgtb     return retval;
436505d05c7Sgtb }
437505d05c7Sgtb 
4387c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_rc_io_store(krb5_context context,struct file_data * t,krb5_donot_replay * rep)439159d09a2SMark Phalan krb5_rc_io_store(krb5_context context, struct file_data *t,
440159d09a2SMark Phalan 		 krb5_donot_replay *rep)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate     int clientlen, serverlen, len;
4437c478bd9Sstevel@tonic-gate     char *buf, *ptr;
4447c478bd9Sstevel@tonic-gate     krb5_error_code ret;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate     clientlen = strlen(rep->client) + 1;
4477c478bd9Sstevel@tonic-gate     serverlen = strlen(rep->server) + 1;
4487c478bd9Sstevel@tonic-gate     len = sizeof(clientlen) + clientlen + sizeof(serverlen) + serverlen +
4497c478bd9Sstevel@tonic-gate 	sizeof(rep->cusec) + sizeof(rep->ctime);
4507c478bd9Sstevel@tonic-gate     buf = malloc(len);
4517c478bd9Sstevel@tonic-gate     if (buf == 0)
4527c478bd9Sstevel@tonic-gate 	return KRB5_RC_MALLOC;
4537c478bd9Sstevel@tonic-gate     ptr = buf;
4547c478bd9Sstevel@tonic-gate     memcpy(ptr, &clientlen, sizeof(clientlen)); ptr += sizeof(clientlen);
4557c478bd9Sstevel@tonic-gate     memcpy(ptr, rep->client, clientlen); ptr += clientlen;
4567c478bd9Sstevel@tonic-gate     memcpy(ptr, &serverlen, sizeof(serverlen)); ptr += sizeof(serverlen);
4577c478bd9Sstevel@tonic-gate     memcpy(ptr, rep->server, serverlen); ptr += serverlen;
4587c478bd9Sstevel@tonic-gate     memcpy(ptr, &rep->cusec, sizeof(rep->cusec)); ptr += sizeof(rep->cusec);
4597c478bd9Sstevel@tonic-gate     memcpy(ptr, &rep->ctime, sizeof(rep->ctime)); ptr += sizeof(rep->ctime);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate     ret = krb5_rc_io_write(context, &t->d, buf, len);
4627c478bd9Sstevel@tonic-gate     free(buf);
4637c478bd9Sstevel@tonic-gate     return ret;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
466505d05c7Sgtb static krb5_error_code krb5_rc_file_expunge_locked(krb5_context, krb5_rcache);
467505d05c7Sgtb 
468*16d62afbSNicolas Williams /*
469*16d62afbSNicolas Williams  * Solaris Kerberos
470*16d62afbSNicolas Williams  *
471*16d62afbSNicolas Williams  * Get time of boot.  This is needed for fsync()-less operation.  See below.
472*16d62afbSNicolas Williams  *
473*16d62afbSNicolas Williams  * Cstyle note: MIT style used here.
474*16d62afbSNicolas Williams  */
475*16d62afbSNicolas Williams static
476*16d62afbSNicolas Williams krb5_timestamp
get_boot_time(krb5_timestamp now)477*16d62afbSNicolas Williams get_boot_time(krb5_timestamp now)
478*16d62afbSNicolas Williams {
479*16d62afbSNicolas Williams     krb5_timestamp bt;
480*16d62afbSNicolas Williams     kstat_ctl_t *kc;
481*16d62afbSNicolas Williams     kstat_t *k;
482*16d62afbSNicolas Williams     kstat_named_t *kn;
483*16d62afbSNicolas Williams     kid_t rc;
484*16d62afbSNicolas Williams 
485*16d62afbSNicolas Williams     /*
486*16d62afbSNicolas Williams      * We use the boot_time kstat from the "unix" module.
487*16d62afbSNicolas Williams      *
488*16d62afbSNicolas Williams      * It's hard to determine the interface stability of kstats.  To be safe
489*16d62afbSNicolas Williams      * we treat boot_time with extra care: if it disappears or is renamed,
490*16d62afbSNicolas Williams      * or if its type changes, or if its value appears to be in the future,
491*16d62afbSNicolas Williams      * then we fail to get boot time and the rcache falls back on slow
492*16d62afbSNicolas Williams      * behavior (fsync()ing at every write).  If this kstat should produce a
493*16d62afbSNicolas Williams      * time less than the actual boot time then this increases the chance of
494*16d62afbSNicolas Williams      * post-crash replays of Authenticators whose rcache entries were not
495*16d62afbSNicolas Williams      * fsync()ed and were lost.
496*16d62afbSNicolas Williams      *
497*16d62afbSNicolas Williams      * We consider it extremely unlikely that this kstat will ever change at
498*16d62afbSNicolas Williams      * all however, much less to change in such a way that it will return
499*16d62afbSNicolas Williams      * the wrong boot time as an unsigned 32-bit integer.  If we fail to
500*16d62afbSNicolas Williams      * find the kstat we expect we log loudly even though the rcache remains
501*16d62afbSNicolas Williams      * functional.
502*16d62afbSNicolas Williams      */
503*16d62afbSNicolas Williams     if ((kc = kstat_open()) == NULL ||
504*16d62afbSNicolas Williams 	(k = kstat_lookup(kc, "unix", 0, "system_misc")) == NULL ||
505*16d62afbSNicolas Williams 	(rc = kstat_read(kc, k, NULL)) == -1 ||
506*16d62afbSNicolas Williams 	(kn = kstat_data_lookup(k, "boot_time")) == NULL ||
507*16d62afbSNicolas Williams 	/* check that the kstat's type hasn't changed */
508*16d62afbSNicolas Williams 	kn->data_type != KSTAT_DATA_UINT32 ||
509*16d62afbSNicolas Williams 	/* boot_time value sanity check */
510*16d62afbSNicolas Williams 	kn->value.i32 > now ||
511*16d62afbSNicolas Williams 	/* krb5_timestamp is int32_t, this kstat is uint32_t; 2038 problem! */
512*16d62afbSNicolas Williams 	kn->value.i32 < 0) {
513*16d62afbSNicolas Williams 
514*16d62afbSNicolas Williams 	/* Return boot time to 1 to indicate failure to get actual boot time */
515*16d62afbSNicolas Williams 	bt = 1;
516*16d62afbSNicolas Williams 	syslog(LOG_ALERT, "Alert: Unable to determine boot_time (boot_time "
517*16d62afbSNicolas Williams 	    "kstat removed or changed?); rcache will be functional, but slow");
518*16d62afbSNicolas Williams     } else {
519*16d62afbSNicolas Williams 	bt = kn->value.i32;
520*16d62afbSNicolas Williams     }
521*16d62afbSNicolas Williams 
522*16d62afbSNicolas Williams     if (kc != NULL)
523*16d62afbSNicolas Williams 	    (void) kstat_close(kc);
524*16d62afbSNicolas Williams 
525*16d62afbSNicolas Williams     return (bt);
526*16d62afbSNicolas Williams }
527*16d62afbSNicolas Williams 
528*16d62afbSNicolas Williams /*
529*16d62afbSNicolas Williams  * Solaris Kerberos
530*16d62afbSNicolas Williams  *
531*16d62afbSNicolas Williams  * We optimize the rcache by foregoing fsync() in the most common cases.
532*16d62afbSNicolas Williams  * Foregoing fsync() requires an early boot procedure to ensure that we
533*16d62afbSNicolas Williams  * never accept an authenticator that could be a replay of one whose
534*16d62afbSNicolas Williams  * rcache entry we've lost.
535*16d62afbSNicolas Williams  *
536*16d62afbSNicolas Williams  * We do this by picking an arbitrary, small time delta such that
537*16d62afbSNicolas Williams  * storing any krb5_donot_replays whose ctime is further into the future
538*16d62afbSNicolas Williams  * than now + that small delta causes an fsync() of the rcache.  Early
539*16d62afbSNicolas Williams  * after booting we must reject all krb5_donot_replays whose ctime falls
540*16d62afbSNicolas Williams  * before time of boot + that delta.
541*16d62afbSNicolas Williams  *
542*16d62afbSNicolas Williams  * This works well as long as client clocks are reasonably synchronized
543*16d62afbSNicolas Williams  * or as long as they use kdc_timesync.  Clients with clocks faster than
544*16d62afbSNicolas Williams  * this delta will find their AP exchanges are slower than clients with
545*16d62afbSNicolas Williams  * good or slow clocks.  Clients with very slow clocks will find that
546*16d62afbSNicolas Williams  * their AP-REQs are rejected by servers that have just booted.  In all
547*16d62afbSNicolas Williams  * other cases clients will notice only that AP exchanges are much
548*16d62afbSNicolas Williams  * faster as a result of the missing fsync()s.
549*16d62afbSNicolas Williams  *
550*16d62afbSNicolas Williams  * KRB5_RC_FSYNCLESS_FAST_SKEW is that time delta, in seconds.  Five
551*16d62afbSNicolas Williams  * seconds seems like a reasonable delta.  If it takes more than five
552*16d62afbSNicolas Williams  * seconds from the time the kernel initializes itself to the time when
553*16d62afbSNicolas Williams  * a kerberized system starts, and clients have good clocks or use
554*16d62afbSNicolas Williams  * kdc_timesync, then no authenticators will be rejected.
555*16d62afbSNicolas Williams  */
556*16d62afbSNicolas Williams #define	KRB5_RC_FSYNCLESS_FAST_SKEW		5
557*16d62afbSNicolas Williams 
5587c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_rc_file_store(krb5_context context,krb5_rcache id,krb5_donot_replay * rep)559159d09a2SMark Phalan krb5_rc_file_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep)
5607c478bd9Sstevel@tonic-gate {
5617c478bd9Sstevel@tonic-gate     krb5_error_code ret;
562505d05c7Sgtb     struct file_data *t;
563*16d62afbSNicolas Williams     static krb5_timestamp boot_time = 0;
564*16d62afbSNicolas Williams     krb5_timestamp now;
565*16d62afbSNicolas Williams 
566*16d62afbSNicolas Williams     if (krb5_timeofday(context, &now) != 0)
567*16d62afbSNicolas Williams 	/* No time of day -> broken rcache */
568*16d62afbSNicolas Williams 	return KRB5KRB_AP_ERR_REPEAT;
569*16d62afbSNicolas Williams 
570*16d62afbSNicolas Williams     /*
571*16d62afbSNicolas Williams      * Solaris Kerberos
572*16d62afbSNicolas Williams      *
573*16d62afbSNicolas Williams      * if boot_time <= 1 -> we always fsync() (see below)
574*16d62afbSNicolas Williams      * if boot_time == 1 -> don't bother trying to get it again (as it could be
575*16d62afbSNicolas Williams      * a slow operation)
576*16d62afbSNicolas Williams      */
577*16d62afbSNicolas Williams     if (boot_time == 0) {
578*16d62afbSNicolas Williams 	krb5_timestamp btime = get_boot_time(now);
579*16d62afbSNicolas Williams 
580*16d62afbSNicolas Williams 	assert(sizeof (boot_time) == sizeof (krb5_int32) && sizeof (krb5_int32) == sizeof (uint32_t));
581*16d62afbSNicolas Williams 	(void) atomic_cas_32((uint32_t *)&boot_time, 0, btime);
582*16d62afbSNicolas Williams     }
583*16d62afbSNicolas Williams 
584*16d62afbSNicolas Williams     /*
585*16d62afbSNicolas Williams      * Solaris Kerberos
586*16d62afbSNicolas Williams      *
587*16d62afbSNicolas Williams      * fsync()-less-ness requires safety.  If we just booted then we want to
588*16d62afbSNicolas Williams      * reject all Authenticators whose timestamps are old enough that we might
589*16d62afbSNicolas Williams      * not have fsync()ed rcache entries for them prior to booting.  See
590*16d62afbSNicolas Williams      * comment above where KRB5_RC_FSYNCLESS_FAST_SKEW is defined.  See
591*16d62afbSNicolas Williams      * also below, where krb5_rc_io_sync() is called.
592*16d62afbSNicolas Williams      *
593*16d62afbSNicolas Williams      * If we could tell here the time of the last system crash then we
594*16d62afbSNicolas Williams      * could do better because we could know that the rcache has been
595*16d62afbSNicolas Williams      * synced to disk.  But there's no reliable way to detect past
596*16d62afbSNicolas Williams      * crashes in this code; getting the time of boot is hard enough.
597*16d62afbSNicolas Williams      */
598*16d62afbSNicolas Williams     if (boot_time > 1 &&
599*16d62afbSNicolas Williams 	rep->ctime < (boot_time + KRB5_RC_FSYNCLESS_FAST_SKEW))
600*16d62afbSNicolas Williams 	/*
601*16d62afbSNicolas Williams 	 * A better error code would be nice; clients might then know
602*16d62afbSNicolas Williams 	 * that nothing's necessarily wrong with their (or our) clocks
603*16d62afbSNicolas Williams 	 * and that they should just wait a while (or even set their
604*16d62afbSNicolas Williams 	 * clock offset slow so that their timestamps then appear into
605*16d62afbSNicolas Williams 	 * the future, where we'd accept them.
606*16d62afbSNicolas Williams 	 *
607*16d62afbSNicolas Williams 	 * KRB5KRB_AP_ERR_SKEW will just have to do.
608*16d62afbSNicolas Williams 	 */
609*16d62afbSNicolas Williams 	return KRB5KRB_AP_ERR_SKEW;
610505d05c7Sgtb 
611505d05c7Sgtb     ret = k5_mutex_lock(&id->lock);
612505d05c7Sgtb     if (ret)
613505d05c7Sgtb 	return ret;
614505d05c7Sgtb 
615505d05c7Sgtb     t = (struct file_data *)id->data;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate     switch(rc_store(context, id,rep)) {
6187c478bd9Sstevel@tonic-gate     case CMP_MALLOC:
619505d05c7Sgtb 	k5_mutex_unlock(&id->lock);
6207c478bd9Sstevel@tonic-gate 	return KRB5_RC_MALLOC;
6217c478bd9Sstevel@tonic-gate     case CMP_REPLAY:
622505d05c7Sgtb 	k5_mutex_unlock(&id->lock);
6237c478bd9Sstevel@tonic-gate 	return KRB5KRB_AP_ERR_REPEAT;
6247c478bd9Sstevel@tonic-gate     case CMP_EXPIRED:
625505d05c7Sgtb 	k5_mutex_unlock(&id->lock);
6267c478bd9Sstevel@tonic-gate 	return KRB5KRB_AP_ERR_SKEW;
6277c478bd9Sstevel@tonic-gate     case CMP_HOHUM: break;
6287c478bd9Sstevel@tonic-gate     default: /* wtf? */ ;
6297c478bd9Sstevel@tonic-gate     }
6307c478bd9Sstevel@tonic-gate     ret = krb5_rc_io_store (context, t, rep);
631505d05c7Sgtb     if (ret) {
632505d05c7Sgtb 	k5_mutex_unlock(&id->lock);
6337c478bd9Sstevel@tonic-gate 	return ret;
634505d05c7Sgtb     }
6357c478bd9Sstevel@tonic-gate     /* Shall we automatically expunge? */
6367c478bd9Sstevel@tonic-gate     if (t->nummisses > t->numhits + EXCESSREPS)
6377c478bd9Sstevel@tonic-gate     {
638*16d62afbSNicolas Williams 	/* Expunge calls krb5_rc_io_sync() */
639505d05c7Sgtb 	ret = krb5_rc_file_expunge_locked(context, id);
640505d05c7Sgtb 	k5_mutex_unlock(&id->lock);
641505d05c7Sgtb 	return ret;
6427c478bd9Sstevel@tonic-gate     }
643*16d62afbSNicolas Williams     /* Solaris Kerberos */
644*16d62afbSNicolas Williams     else if (boot_time <= 1 || rep->ctime > (now + KRB5_RC_FSYNCLESS_FAST_SKEW))
6457c478bd9Sstevel@tonic-gate     {
646*16d62afbSNicolas Williams 	/*
647*16d62afbSNicolas Williams 	 * fsync() only when necessary:
648*16d62afbSNicolas Williams 	 *
649*16d62afbSNicolas Williams 	 *  - on expunge (see above)
650*16d62afbSNicolas Williams 	 *  - if we don't know when we booted
651*16d62afbSNicolas Williams 	 *  - if rep->ctime is too far into the future
652*16d62afbSNicolas Williams 	 */
653505d05c7Sgtb 	if (krb5_rc_io_sync(context, &t->d)) {
654505d05c7Sgtb 	    k5_mutex_unlock(&id->lock);
6557c478bd9Sstevel@tonic-gate 	    return KRB5_RC_IO;
6567c478bd9Sstevel@tonic-gate 	}
657505d05c7Sgtb     }
658505d05c7Sgtb     k5_mutex_unlock(&id->lock);
6597c478bd9Sstevel@tonic-gate     return 0;
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
662505d05c7Sgtb static krb5_error_code
krb5_rc_file_expunge_locked(krb5_context context,krb5_rcache id)663159d09a2SMark Phalan krb5_rc_file_expunge_locked(krb5_context context, krb5_rcache id)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate     struct file_data *t = (struct file_data *)id->data;
6667c478bd9Sstevel@tonic-gate     struct authlist *q;
6677c478bd9Sstevel@tonic-gate     char *name;
6687c478bd9Sstevel@tonic-gate     krb5_error_code retval = 0;
6697c478bd9Sstevel@tonic-gate     krb5_rcache tmp;
6707c478bd9Sstevel@tonic-gate     krb5_deltat lifespan = t->lifespan;  /* save original lifespan */
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate     if (! t->recovering) {
6737c478bd9Sstevel@tonic-gate 	name = t->name;
6747c478bd9Sstevel@tonic-gate 	t->name = 0;		/* Clear name so it isn't freed */
6757c478bd9Sstevel@tonic-gate 	(void) krb5_rc_file_close_no_free(context, id);
6767c478bd9Sstevel@tonic-gate 	retval = krb5_rc_file_resolve(context, id, name);
6777c478bd9Sstevel@tonic-gate 	free(name);
6787c478bd9Sstevel@tonic-gate 	if (retval)
6797c478bd9Sstevel@tonic-gate 	    return retval;
680505d05c7Sgtb 	retval = krb5_rc_file_recover_locked(context, id);
6817c478bd9Sstevel@tonic-gate 	if (retval)
6827c478bd9Sstevel@tonic-gate 	    return retval;
6837c478bd9Sstevel@tonic-gate 	t = (struct file_data *)id->data; /* point to recovered cache */
6847c478bd9Sstevel@tonic-gate     }
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate     tmp = (krb5_rcache) malloc(sizeof(*tmp));
6877c478bd9Sstevel@tonic-gate     if (!tmp)
6887c478bd9Sstevel@tonic-gate 	return ENOMEM;
689505d05c7Sgtb 
690505d05c7Sgtb     retval = k5_mutex_init(&tmp->lock);
691505d05c7Sgtb     if (retval) {
692505d05c7Sgtb         free(tmp);
693505d05c7Sgtb         return retval;
694505d05c7Sgtb     }
695505d05c7Sgtb 
6967c478bd9Sstevel@tonic-gate     tmp->ops = &krb5_rc_file_ops;
6977c478bd9Sstevel@tonic-gate     if ((retval = krb5_rc_file_resolve(context, tmp, 0)) != 0)
6987c478bd9Sstevel@tonic-gate 	goto out;
6997c478bd9Sstevel@tonic-gate     if ((retval = krb5_rc_initialize(context, tmp, lifespan)) != 0)
7007c478bd9Sstevel@tonic-gate 	goto out;
7017c478bd9Sstevel@tonic-gate     for (q = t->a;q;q = q->na) {
7027c478bd9Sstevel@tonic-gate 	if (krb5_rc_io_store (context, (struct file_data *)tmp->data, &q->rep)) {
7037c478bd9Sstevel@tonic-gate 		retval = KRB5_RC_IO;
7047c478bd9Sstevel@tonic-gate 		goto out;
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate     }
7077c478bd9Sstevel@tonic-gate     if (krb5_rc_io_sync(context, &t->d)) {
7087c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_IO;
7097c478bd9Sstevel@tonic-gate 	goto out;
7107c478bd9Sstevel@tonic-gate     }
7117c478bd9Sstevel@tonic-gate     if (krb5_rc_io_move(context, &t->d, &((struct file_data *)tmp->data)->d))
7127c478bd9Sstevel@tonic-gate 	retval = KRB5_RC_IO;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate out:
7157c478bd9Sstevel@tonic-gate     /*
7167c478bd9Sstevel@tonic-gate      * krb5_rc_file_close() will free the tmp struct and it's members that the
7177c478bd9Sstevel@tonic-gate      * previous functions had allocated.
7187c478bd9Sstevel@tonic-gate      */
7197c478bd9Sstevel@tonic-gate      (void) krb5_rc_file_close(context, tmp);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate     return (retval);
7227c478bd9Sstevel@tonic-gate }
723505d05c7Sgtb 
724505d05c7Sgtb krb5_error_code KRB5_CALLCONV
krb5_rc_file_expunge(krb5_context context,krb5_rcache id)725505d05c7Sgtb krb5_rc_file_expunge(krb5_context context, krb5_rcache id)
726505d05c7Sgtb {
727505d05c7Sgtb     krb5_error_code ret;
728505d05c7Sgtb     ret = k5_mutex_lock(&id->lock);
729505d05c7Sgtb     if (ret)
730505d05c7Sgtb 	return ret;
731505d05c7Sgtb     ret = krb5_rc_file_expunge_locked(context, id);
732505d05c7Sgtb     k5_mutex_unlock(&id->lock);
733505d05c7Sgtb     return ret;
734505d05c7Sgtb }
735