xref: /freebsd/crypto/heimdal/lib/krb5/replay.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
1 /*
2  * Copyright (c) 1997-2001 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 #include <vis.h>
36 
37 RCSID("$Id: replay.c 17047 2006-04-10 17:13:49Z lha $");
38 
39 struct krb5_rcache_data {
40     char *name;
41 };
42 
43 krb5_error_code KRB5_LIB_FUNCTION
44 krb5_rc_resolve(krb5_context context,
45 		krb5_rcache id,
46 		const char *name)
47 {
48     id->name = strdup(name);
49     if(id->name == NULL) {
50 	krb5_set_error_string (context, "malloc: out of memory");
51 	return KRB5_RC_MALLOC;
52     }
53     return 0;
54 }
55 
56 krb5_error_code KRB5_LIB_FUNCTION
57 krb5_rc_resolve_type(krb5_context context,
58 		     krb5_rcache *id,
59 		     const char *type)
60 {
61     *id = NULL;
62     if(strcmp(type, "FILE")) {
63 	krb5_set_error_string (context, "replay cache type %s not supported",
64 			       type);
65 	return KRB5_RC_TYPE_NOTFOUND;
66     }
67     *id = calloc(1, sizeof(**id));
68     if(*id == NULL) {
69 	krb5_set_error_string (context, "malloc: out of memory");
70 	return KRB5_RC_MALLOC;
71     }
72     return 0;
73 }
74 
75 krb5_error_code KRB5_LIB_FUNCTION
76 krb5_rc_resolve_full(krb5_context context,
77 		     krb5_rcache *id,
78 		     const char *string_name)
79 {
80     krb5_error_code ret;
81 
82     *id = NULL;
83 
84     if(strncmp(string_name, "FILE:", 5)) {
85 	krb5_set_error_string (context, "replay cache type %s not supported",
86 			       string_name);
87 	return KRB5_RC_TYPE_NOTFOUND;
88     }
89     ret = krb5_rc_resolve_type(context, id, "FILE");
90     if(ret)
91 	return ret;
92     ret = krb5_rc_resolve(context, *id, string_name + 5);
93     if (ret) {
94 	krb5_rc_close(context, *id);
95 	*id = NULL;
96     }
97     return ret;
98 }
99 
100 const char* KRB5_LIB_FUNCTION
101 krb5_rc_default_name(krb5_context context)
102 {
103     return "FILE:/var/run/default_rcache";
104 }
105 
106 const char* KRB5_LIB_FUNCTION
107 krb5_rc_default_type(krb5_context context)
108 {
109     return "FILE";
110 }
111 
112 krb5_error_code KRB5_LIB_FUNCTION
113 krb5_rc_default(krb5_context context,
114 		krb5_rcache *id)
115 {
116     return krb5_rc_resolve_full(context, id, krb5_rc_default_name(context));
117 }
118 
119 struct rc_entry{
120     time_t stamp;
121     unsigned char data[16];
122 };
123 
124 krb5_error_code KRB5_LIB_FUNCTION
125 krb5_rc_initialize(krb5_context context,
126 		   krb5_rcache id,
127 		   krb5_deltat auth_lifespan)
128 {
129     FILE *f = fopen(id->name, "w");
130     struct rc_entry tmp;
131     int ret;
132 
133     if(f == NULL) {
134 	ret = errno;
135 	krb5_set_error_string (context, "open(%s): %s", id->name,
136 			       strerror(ret));
137 	return ret;
138     }
139     tmp.stamp = auth_lifespan;
140     fwrite(&tmp, 1, sizeof(tmp), f);
141     fclose(f);
142     return 0;
143 }
144 
145 krb5_error_code KRB5_LIB_FUNCTION
146 krb5_rc_recover(krb5_context context,
147 		krb5_rcache id)
148 {
149     return 0;
150 }
151 
152 krb5_error_code KRB5_LIB_FUNCTION
153 krb5_rc_destroy(krb5_context context,
154 		krb5_rcache id)
155 {
156     int ret;
157 
158     if(remove(id->name) < 0) {
159 	ret = errno;
160 	krb5_set_error_string (context, "remove(%s): %s", id->name,
161 			       strerror(ret));
162 	return ret;
163     }
164     return krb5_rc_close(context, id);
165 }
166 
167 krb5_error_code KRB5_LIB_FUNCTION
168 krb5_rc_close(krb5_context context,
169 	      krb5_rcache id)
170 {
171     free(id->name);
172     free(id);
173     return 0;
174 }
175 
176 static void
177 checksum_authenticator(Authenticator *auth, void *data)
178 {
179     MD5_CTX md5;
180     int i;
181 
182     MD5_Init (&md5);
183     MD5_Update (&md5, auth->crealm, strlen(auth->crealm));
184     for(i = 0; i < auth->cname.name_string.len; i++)
185 	MD5_Update(&md5, auth->cname.name_string.val[i],
186 		   strlen(auth->cname.name_string.val[i]));
187     MD5_Update (&md5, &auth->ctime, sizeof(auth->ctime));
188     MD5_Update (&md5, &auth->cusec, sizeof(auth->cusec));
189     MD5_Final (data, &md5);
190 }
191 
192 krb5_error_code KRB5_LIB_FUNCTION
193 krb5_rc_store(krb5_context context,
194 	      krb5_rcache id,
195 	      krb5_donot_replay *rep)
196 {
197     struct rc_entry ent, tmp;
198     time_t t;
199     FILE *f;
200     int ret;
201 
202     ent.stamp = time(NULL);
203     checksum_authenticator(rep, ent.data);
204     f = fopen(id->name, "r");
205     if(f == NULL) {
206 	ret = errno;
207 	krb5_set_error_string (context, "open(%s): %s", id->name,
208 			       strerror(ret));
209 	return ret;
210     }
211     fread(&tmp, sizeof(ent), 1, f);
212     t = ent.stamp - tmp.stamp;
213     while(fread(&tmp, sizeof(ent), 1, f)){
214 	if(tmp.stamp < t)
215 	    continue;
216 	if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){
217 	    fclose(f);
218 	    krb5_clear_error_string (context);
219 	    return KRB5_RC_REPLAY;
220 	}
221     }
222     if(ferror(f)){
223 	ret = errno;
224 	fclose(f);
225 	krb5_set_error_string (context, "%s: %s", id->name, strerror(ret));
226 	return ret;
227     }
228     fclose(f);
229     f = fopen(id->name, "a");
230     if(f == NULL) {
231 	krb5_set_error_string (context, "open(%s): %s", id->name,
232 			       strerror(errno));
233 	return KRB5_RC_IO_UNKNOWN;
234     }
235     fwrite(&ent, 1, sizeof(ent), f);
236     fclose(f);
237     return 0;
238 }
239 
240 krb5_error_code KRB5_LIB_FUNCTION
241 krb5_rc_expunge(krb5_context context,
242 		krb5_rcache id)
243 {
244     return 0;
245 }
246 
247 krb5_error_code KRB5_LIB_FUNCTION
248 krb5_rc_get_lifespan(krb5_context context,
249 		     krb5_rcache id,
250 		     krb5_deltat *auth_lifespan)
251 {
252     FILE *f = fopen(id->name, "r");
253     int r;
254     struct rc_entry ent;
255     r = fread(&ent, sizeof(ent), 1, f);
256     fclose(f);
257     if(r){
258 	*auth_lifespan = ent.stamp;
259 	return 0;
260     }
261     krb5_clear_error_string (context);
262     return KRB5_RC_IO_UNKNOWN;
263 }
264 
265 const char* KRB5_LIB_FUNCTION
266 krb5_rc_get_name(krb5_context context,
267 		 krb5_rcache id)
268 {
269     return id->name;
270 }
271 
272 const char* KRB5_LIB_FUNCTION
273 krb5_rc_get_type(krb5_context context,
274 		 krb5_rcache id)
275 {
276     return "FILE";
277 }
278 
279 krb5_error_code KRB5_LIB_FUNCTION
280 krb5_get_server_rcache(krb5_context context,
281 		       const krb5_data *piece,
282 		       krb5_rcache *id)
283 {
284     krb5_rcache rcache;
285     krb5_error_code ret;
286 
287     char *tmp = malloc(4 * piece->length + 1);
288     char *name;
289 
290     if(tmp == NULL) {
291 	krb5_set_error_string (context, "malloc: out of memory");
292 	return ENOMEM;
293     }
294     strvisx(tmp, piece->data, piece->length, VIS_WHITE | VIS_OCTAL);
295 #ifdef HAVE_GETEUID
296     asprintf(&name, "FILE:rc_%s_%u", tmp, (unsigned)geteuid());
297 #else
298     asprintf(&name, "FILE:rc_%s", tmp);
299 #endif
300     free(tmp);
301     if(name == NULL) {
302 	krb5_set_error_string (context, "malloc: out of memory");
303 	return ENOMEM;
304     }
305 
306     ret = krb5_rc_resolve_full(context, &rcache, name);
307     free(name);
308     if(ret)
309 	return ret;
310     *id = rcache;
311     return ret;
312 }
313