]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/lib/krb5/replay.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / 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 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 }