xref: /freebsd/crypto/heimdal/lib/krb5/replay.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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,v 1.9 2001/07/03 19:33:13 assar Exp $");
38 
39 struct krb5_rcache_data {
40     char *name;
41 };
42 
43 krb5_error_code
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
57 krb5_rc_resolve_type(krb5_context context,
58 		     krb5_rcache *id,
59 		     const char *type)
60 {
61     if(strcmp(type, "FILE")) {
62 	krb5_set_error_string (context, "replay cache type %s not supported",
63 			       type);
64 	return KRB5_RC_TYPE_NOTFOUND;
65     }
66     *id = calloc(1, sizeof(**id));
67     if(*id == NULL) {
68 	krb5_set_error_string (context, "malloc: out of memory");
69 	return KRB5_RC_MALLOC;
70     }
71     return 0;
72 }
73 
74 krb5_error_code
75 krb5_rc_resolve_full(krb5_context context,
76 		     krb5_rcache *id,
77 		     const char *string_name)
78 {
79     krb5_error_code ret;
80     if(strncmp(string_name, "FILE:", 5)) {
81 	krb5_set_error_string (context, "replay cache type %s not supported",
82 			       string_name);
83 	return KRB5_RC_TYPE_NOTFOUND;
84     }
85     ret = krb5_rc_resolve_type(context, id, "FILE");
86     if(ret)
87 	return ret;
88     ret = krb5_rc_resolve(context, *id, string_name + 5);
89     return ret;
90 }
91 
92 const char *
93 krb5_rc_default_name(krb5_context context)
94 {
95     return "FILE:/var/run/default_rcache";
96 }
97 
98 const char *
99 krb5_rc_default_type(krb5_context context)
100 {
101     return "FILE";
102 }
103 
104 krb5_error_code
105 krb5_rc_default(krb5_context context,
106 		krb5_rcache *id)
107 {
108     return krb5_rc_resolve_full(context, id, krb5_rc_default_name(context));
109 }
110 
111 struct rc_entry{
112     time_t stamp;
113     unsigned char data[16];
114 };
115 
116 krb5_error_code
117 krb5_rc_initialize(krb5_context context,
118 		   krb5_rcache id,
119 		   krb5_deltat auth_lifespan)
120 {
121     FILE *f = fopen(id->name, "w");
122     struct rc_entry tmp;
123     int ret;
124 
125     if(f == NULL) {
126 	ret = errno;
127 	krb5_set_error_string (context, "open(%s): %s", id->name,
128 			       strerror(ret));
129 	return ret;
130     }
131     tmp.stamp = auth_lifespan;
132     fwrite(&tmp, 1, sizeof(tmp), f);
133     fclose(f);
134     return 0;
135 }
136 
137 krb5_error_code
138 krb5_rc_recover(krb5_context context,
139 		krb5_rcache id)
140 {
141     return 0;
142 }
143 
144 krb5_error_code
145 krb5_rc_destroy(krb5_context context,
146 		krb5_rcache id)
147 {
148     int ret;
149 
150     if(remove(id->name) < 0) {
151 	ret = errno;
152 	krb5_set_error_string (context, "remove(%s): %s", id->name,
153 			       strerror(ret));
154 	return ret;
155     }
156     return krb5_rc_close(context, id);
157 }
158 
159 krb5_error_code
160 krb5_rc_close(krb5_context context,
161 	      krb5_rcache id)
162 {
163     free(id->name);
164     free(id);
165     return 0;
166 }
167 
168 static void
169 checksum_authenticator(Authenticator *auth, void *data)
170 {
171     MD5_CTX md5;
172     int i;
173 
174     MD5_Init (&md5);
175     MD5_Update (&md5, auth->crealm, strlen(auth->crealm));
176     for(i = 0; i < auth->cname.name_string.len; i++)
177 	MD5_Update(&md5, auth->cname.name_string.val[i],
178 		   strlen(auth->cname.name_string.val[i]));
179     MD5_Update (&md5, &auth->ctime, sizeof(auth->ctime));
180     MD5_Update (&md5, &auth->cusec, sizeof(auth->cusec));
181     MD5_Final (data, &md5);
182 }
183 
184 krb5_error_code
185 krb5_rc_store(krb5_context context,
186 	      krb5_rcache id,
187 	      krb5_donot_replay *rep)
188 {
189     struct rc_entry ent, tmp;
190     time_t t;
191     FILE *f;
192     int ret;
193 
194     ent.stamp = time(NULL);
195     checksum_authenticator(rep, ent.data);
196     f = fopen(id->name, "r");
197     if(f == NULL) {
198 	ret = errno;
199 	krb5_set_error_string (context, "open(%s): %s", id->name,
200 			       strerror(ret));
201 	return ret;
202     }
203     fread(&tmp, sizeof(ent), 1, f);
204     t = ent.stamp - tmp.stamp;
205     while(fread(&tmp, sizeof(ent), 1, f)){
206 	if(tmp.stamp < t)
207 	    continue;
208 	if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){
209 	    fclose(f);
210 	    krb5_clear_error_string (context);
211 	    return KRB5_RC_REPLAY;
212 	}
213     }
214     if(ferror(f)){
215 	ret = errno;
216 	fclose(f);
217 	krb5_set_error_string (context, "%s: %s", id->name, strerror(ret));
218 	return ret;
219     }
220     fclose(f);
221     f = fopen(id->name, "a");
222     if(f == NULL) {
223 	krb5_set_error_string (context, "open(%s): %s", id->name,
224 			       strerror(errno));
225 	return KRB5_RC_IO_UNKNOWN;
226     }
227     fwrite(&ent, 1, sizeof(ent), f);
228     fclose(f);
229     return 0;
230 }
231 
232 krb5_error_code
233 krb5_rc_expunge(krb5_context context,
234 		krb5_rcache id)
235 {
236     return 0;
237 }
238 
239 krb5_error_code
240 krb5_rc_get_lifespan(krb5_context context,
241 		     krb5_rcache id,
242 		     krb5_deltat *auth_lifespan)
243 {
244     FILE *f = fopen(id->name, "r");
245     int r;
246     struct rc_entry ent;
247     r = fread(&ent, sizeof(ent), 1, f);
248     fclose(f);
249     if(r){
250 	*auth_lifespan = ent.stamp;
251 	return 0;
252     }
253     krb5_clear_error_string (context);
254     return KRB5_RC_IO_UNKNOWN;
255 }
256 
257 const char*
258 krb5_rc_get_name(krb5_context context,
259 		 krb5_rcache id)
260 {
261     return id->name;
262 }
263 
264 const char*
265 krb5_rc_get_type(krb5_context context,
266 		 krb5_rcache id)
267 {
268     return "FILE";
269 }
270 
271 krb5_error_code
272 krb5_get_server_rcache(krb5_context context,
273 		       const krb5_data *piece,
274 		       krb5_rcache *id)
275 {
276     krb5_rcache rcache;
277     krb5_error_code ret;
278 
279     char *tmp = malloc(4 * piece->length + 1);
280     char *name;
281 
282     if(tmp == NULL) {
283 	krb5_set_error_string (context, "malloc: out of memory");
284 	return ENOMEM;
285     }
286     strvisx(tmp, piece->data, piece->length, VIS_WHITE | VIS_OCTAL);
287 #ifdef HAVE_GETEUID
288     asprintf(&name, "FILE:rc_%s_%u", tmp, (unsigned)geteuid());
289 #else
290     asprintf(&name, "FILE:rc_%s", tmp);
291 #endif
292     free(tmp);
293     if(name == NULL) {
294 	krb5_set_error_string (context, "malloc: out of memory");
295 	return ENOMEM;
296     }
297 
298     ret = krb5_rc_resolve_full(context, &rcache, name);
299     free(name);
300     if(ret)
301 	return ret;
302     *id = rcache;
303     return ret;
304 }
305