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