Add heimdal-0.6.3
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / krb5 / replay.c
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 }