1*d3273b5bSchristos /* $NetBSD: keytab_file.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2ca1c9b0cSelric
3ca1c9b0cSelric /*
4ca1c9b0cSelric * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
5ca1c9b0cSelric * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric * All rights reserved.
7ca1c9b0cSelric *
8ca1c9b0cSelric * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric * modification, are permitted provided that the following conditions
10ca1c9b0cSelric * are met:
11ca1c9b0cSelric *
12ca1c9b0cSelric * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric * notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric *
15ca1c9b0cSelric * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric * notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric * documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric *
19ca1c9b0cSelric * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric * may be used to endorse or promote products derived from this software
21ca1c9b0cSelric * without specific prior written permission.
22ca1c9b0cSelric *
23ca1c9b0cSelric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric * SUCH DAMAGE.
34ca1c9b0cSelric */
35ca1c9b0cSelric
36ca1c9b0cSelric #include "krb5_locl.h"
37ca1c9b0cSelric
38ca1c9b0cSelric #define KRB5_KT_VNO_1 1
39ca1c9b0cSelric #define KRB5_KT_VNO_2 2
40ca1c9b0cSelric #define KRB5_KT_VNO KRB5_KT_VNO_2
41ca1c9b0cSelric
42ca1c9b0cSelric #define KRB5_KT_FL_JAVA 1
43ca1c9b0cSelric
44ca1c9b0cSelric
45ca1c9b0cSelric /* file operations -------------------------------------------- */
46ca1c9b0cSelric
47ca1c9b0cSelric struct fkt_data {
48ca1c9b0cSelric char *filename;
49ca1c9b0cSelric int flags;
50ca1c9b0cSelric };
51ca1c9b0cSelric
52ca1c9b0cSelric static krb5_error_code
krb5_kt_ret_data(krb5_context context,krb5_storage * sp,krb5_data * data)53ca1c9b0cSelric krb5_kt_ret_data(krb5_context context,
54ca1c9b0cSelric krb5_storage *sp,
55ca1c9b0cSelric krb5_data *data)
56ca1c9b0cSelric {
57ca1c9b0cSelric int ret;
58ca1c9b0cSelric int16_t size;
59ca1c9b0cSelric ret = krb5_ret_int16(sp, &size);
60ca1c9b0cSelric if(ret)
61ca1c9b0cSelric return ret;
62ca1c9b0cSelric data->length = size;
63ca1c9b0cSelric data->data = malloc(size);
64b9d004c6Schristos if (data->data == NULL)
65b9d004c6Schristos return krb5_enomem(context);
66ca1c9b0cSelric ret = krb5_storage_read(sp, data->data, size);
67ca1c9b0cSelric if(ret != size)
68ca1c9b0cSelric return (ret < 0)? errno : KRB5_KT_END;
69ca1c9b0cSelric return 0;
70ca1c9b0cSelric }
71ca1c9b0cSelric
72ca1c9b0cSelric static krb5_error_code
krb5_kt_ret_string(krb5_context context,krb5_storage * sp,heim_general_string * data)73ca1c9b0cSelric krb5_kt_ret_string(krb5_context context,
74ca1c9b0cSelric krb5_storage *sp,
75ca1c9b0cSelric heim_general_string *data)
76ca1c9b0cSelric {
77ca1c9b0cSelric int ret;
78ca1c9b0cSelric int16_t size;
79ca1c9b0cSelric ret = krb5_ret_int16(sp, &size);
80ca1c9b0cSelric if(ret)
81ca1c9b0cSelric return ret;
82ca1c9b0cSelric *data = malloc(size + 1);
83b9d004c6Schristos if (*data == NULL)
84b9d004c6Schristos return krb5_enomem(context);
85ca1c9b0cSelric ret = krb5_storage_read(sp, *data, size);
86ca1c9b0cSelric (*data)[size] = '\0';
87ca1c9b0cSelric if(ret != size)
88ca1c9b0cSelric return (ret < 0)? errno : KRB5_KT_END;
89ca1c9b0cSelric return 0;
90ca1c9b0cSelric }
91ca1c9b0cSelric
92ca1c9b0cSelric static krb5_error_code
krb5_kt_store_data(krb5_context context,krb5_storage * sp,krb5_data data)93ca1c9b0cSelric krb5_kt_store_data(krb5_context context,
94ca1c9b0cSelric krb5_storage *sp,
95ca1c9b0cSelric krb5_data data)
96ca1c9b0cSelric {
97ca1c9b0cSelric int ret;
98ca1c9b0cSelric ret = krb5_store_int16(sp, data.length);
99ca1c9b0cSelric if(ret < 0)
100ca1c9b0cSelric return ret;
101ca1c9b0cSelric ret = krb5_storage_write(sp, data.data, data.length);
1024f77a458Spettai if(ret != (int)data.length){
103ca1c9b0cSelric if(ret < 0)
104ca1c9b0cSelric return errno;
105ca1c9b0cSelric return KRB5_KT_END;
106ca1c9b0cSelric }
107ca1c9b0cSelric return 0;
108ca1c9b0cSelric }
109ca1c9b0cSelric
110ca1c9b0cSelric static krb5_error_code
krb5_kt_store_string(krb5_storage * sp,heim_general_string data)111ca1c9b0cSelric krb5_kt_store_string(krb5_storage *sp,
112ca1c9b0cSelric heim_general_string data)
113ca1c9b0cSelric {
114ca1c9b0cSelric int ret;
115ca1c9b0cSelric size_t len = strlen(data);
116ca1c9b0cSelric ret = krb5_store_int16(sp, len);
117ca1c9b0cSelric if(ret < 0)
118ca1c9b0cSelric return ret;
119ca1c9b0cSelric ret = krb5_storage_write(sp, data, len);
1204f77a458Spettai if(ret != (int)len){
121ca1c9b0cSelric if(ret < 0)
122ca1c9b0cSelric return errno;
123ca1c9b0cSelric return KRB5_KT_END;
124ca1c9b0cSelric }
125ca1c9b0cSelric return 0;
126ca1c9b0cSelric }
127ca1c9b0cSelric
128ca1c9b0cSelric static krb5_error_code
krb5_kt_ret_keyblock(krb5_context context,struct fkt_data * fkt,krb5_storage * sp,krb5_keyblock * p)129ca1c9b0cSelric krb5_kt_ret_keyblock(krb5_context context,
130ca1c9b0cSelric struct fkt_data *fkt,
131ca1c9b0cSelric krb5_storage *sp,
132ca1c9b0cSelric krb5_keyblock *p)
133ca1c9b0cSelric {
134ca1c9b0cSelric int ret;
135ca1c9b0cSelric int16_t tmp;
136ca1c9b0cSelric
137ca1c9b0cSelric ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
138ca1c9b0cSelric if(ret) {
139ca1c9b0cSelric krb5_set_error_message(context, ret,
140ca1c9b0cSelric N_("Cant read keyblock from file %s", ""),
141ca1c9b0cSelric fkt->filename);
142ca1c9b0cSelric return ret;
143ca1c9b0cSelric }
144ca1c9b0cSelric p->keytype = tmp;
145ca1c9b0cSelric ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
146ca1c9b0cSelric if (ret)
147ca1c9b0cSelric krb5_set_error_message(context, ret,
148ca1c9b0cSelric N_("Cant read keyblock from file %s", ""),
149ca1c9b0cSelric fkt->filename);
150ca1c9b0cSelric return ret;
151ca1c9b0cSelric }
152ca1c9b0cSelric
153ca1c9b0cSelric static krb5_error_code
krb5_kt_store_keyblock(krb5_context context,struct fkt_data * fkt,krb5_storage * sp,krb5_keyblock * p)154ca1c9b0cSelric krb5_kt_store_keyblock(krb5_context context,
155ca1c9b0cSelric struct fkt_data *fkt,
156ca1c9b0cSelric krb5_storage *sp,
157ca1c9b0cSelric krb5_keyblock *p)
158ca1c9b0cSelric {
159ca1c9b0cSelric int ret;
160ca1c9b0cSelric
161ca1c9b0cSelric ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
162ca1c9b0cSelric if(ret) {
163ca1c9b0cSelric krb5_set_error_message(context, ret,
164ca1c9b0cSelric N_("Cant store keyblock to file %s", ""),
165ca1c9b0cSelric fkt->filename);
166ca1c9b0cSelric return ret;
167ca1c9b0cSelric }
168ca1c9b0cSelric ret = krb5_kt_store_data(context, sp, p->keyvalue);
169ca1c9b0cSelric if (ret)
170ca1c9b0cSelric krb5_set_error_message(context, ret,
171ca1c9b0cSelric N_("Cant store keyblock to file %s", ""),
172ca1c9b0cSelric fkt->filename);
173ca1c9b0cSelric return ret;
174ca1c9b0cSelric }
175ca1c9b0cSelric
176ca1c9b0cSelric
177ca1c9b0cSelric static krb5_error_code
krb5_kt_ret_principal(krb5_context context,struct fkt_data * fkt,krb5_storage * sp,krb5_principal * princ)178ca1c9b0cSelric krb5_kt_ret_principal(krb5_context context,
179ca1c9b0cSelric struct fkt_data *fkt,
180ca1c9b0cSelric krb5_storage *sp,
181ca1c9b0cSelric krb5_principal *princ)
182ca1c9b0cSelric {
1834f77a458Spettai size_t i;
184ca1c9b0cSelric int ret;
185ca1c9b0cSelric krb5_principal p;
186ca1c9b0cSelric int16_t len;
187ca1c9b0cSelric
188ca1c9b0cSelric ALLOC(p, 1);
189b9d004c6Schristos if(p == NULL)
190b9d004c6Schristos return krb5_enomem(context);
191ca1c9b0cSelric
192ca1c9b0cSelric ret = krb5_ret_int16(sp, &len);
193ca1c9b0cSelric if(ret) {
194ca1c9b0cSelric krb5_set_error_message(context, ret,
195ca1c9b0cSelric N_("Failed decoding length of "
196ca1c9b0cSelric "keytab principal in keytab file %s", ""),
197ca1c9b0cSelric fkt->filename);
198ca1c9b0cSelric goto out;
199ca1c9b0cSelric }
200ca1c9b0cSelric if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
201ca1c9b0cSelric len--;
202ca1c9b0cSelric if (len < 0) {
203ca1c9b0cSelric ret = KRB5_KT_END;
204ca1c9b0cSelric krb5_set_error_message(context, ret,
205ca1c9b0cSelric N_("Keytab principal contains "
206ca1c9b0cSelric "invalid length in keytab %s", ""),
207ca1c9b0cSelric fkt->filename);
208ca1c9b0cSelric goto out;
209ca1c9b0cSelric }
210ca1c9b0cSelric ret = krb5_kt_ret_string(context, sp, &p->realm);
211ca1c9b0cSelric if(ret) {
212ca1c9b0cSelric krb5_set_error_message(context, ret,
213ca1c9b0cSelric N_("Can't read realm from keytab: %s", ""),
214ca1c9b0cSelric fkt->filename);
215ca1c9b0cSelric goto out;
216ca1c9b0cSelric }
217ca1c9b0cSelric p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val));
218ca1c9b0cSelric if(p->name.name_string.val == NULL) {
219b9d004c6Schristos ret = krb5_enomem(context);
220ca1c9b0cSelric goto out;
221ca1c9b0cSelric }
222ca1c9b0cSelric p->name.name_string.len = len;
223ca1c9b0cSelric for(i = 0; i < p->name.name_string.len; i++){
224ca1c9b0cSelric ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
225ca1c9b0cSelric if(ret) {
226ca1c9b0cSelric krb5_set_error_message(context, ret,
227ca1c9b0cSelric N_("Can't read principal from "
228ca1c9b0cSelric "keytab: %s", ""),
229ca1c9b0cSelric fkt->filename);
230ca1c9b0cSelric goto out;
231ca1c9b0cSelric }
232ca1c9b0cSelric }
233ca1c9b0cSelric if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
234ca1c9b0cSelric p->name.name_type = KRB5_NT_UNKNOWN;
235ca1c9b0cSelric else {
236ca1c9b0cSelric int32_t tmp32;
237ca1c9b0cSelric ret = krb5_ret_int32(sp, &tmp32);
238ca1c9b0cSelric p->name.name_type = tmp32;
239ca1c9b0cSelric if (ret) {
240ca1c9b0cSelric krb5_set_error_message(context, ret,
241ca1c9b0cSelric N_("Can't read name-type from "
242ca1c9b0cSelric "keytab: %s", ""),
243ca1c9b0cSelric fkt->filename);
244ca1c9b0cSelric goto out;
245ca1c9b0cSelric }
246ca1c9b0cSelric }
247ca1c9b0cSelric *princ = p;
248ca1c9b0cSelric return 0;
249ca1c9b0cSelric out:
250ca1c9b0cSelric krb5_free_principal(context, p);
251ca1c9b0cSelric return ret;
252ca1c9b0cSelric }
253ca1c9b0cSelric
254ca1c9b0cSelric static krb5_error_code
krb5_kt_store_principal(krb5_context context,krb5_storage * sp,krb5_principal p)255ca1c9b0cSelric krb5_kt_store_principal(krb5_context context,
256ca1c9b0cSelric krb5_storage *sp,
257ca1c9b0cSelric krb5_principal p)
258ca1c9b0cSelric {
2594f77a458Spettai size_t i;
260ca1c9b0cSelric int ret;
261ca1c9b0cSelric
262ca1c9b0cSelric if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
263ca1c9b0cSelric ret = krb5_store_int16(sp, p->name.name_string.len + 1);
264ca1c9b0cSelric else
265ca1c9b0cSelric ret = krb5_store_int16(sp, p->name.name_string.len);
266ca1c9b0cSelric if(ret) return ret;
267ca1c9b0cSelric ret = krb5_kt_store_string(sp, p->realm);
268ca1c9b0cSelric if(ret) return ret;
269ca1c9b0cSelric for(i = 0; i < p->name.name_string.len; i++){
270ca1c9b0cSelric ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
271ca1c9b0cSelric if(ret)
272ca1c9b0cSelric return ret;
273ca1c9b0cSelric }
274ca1c9b0cSelric if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
275ca1c9b0cSelric ret = krb5_store_int32(sp, p->name.name_type);
276ca1c9b0cSelric if(ret)
277ca1c9b0cSelric return ret;
278ca1c9b0cSelric }
279ca1c9b0cSelric
280ca1c9b0cSelric return 0;
281ca1c9b0cSelric }
282ca1c9b0cSelric
283ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_resolve(krb5_context context,const char * name,krb5_keytab id)284ca1c9b0cSelric fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
285ca1c9b0cSelric {
286ca1c9b0cSelric struct fkt_data *d;
287ca1c9b0cSelric
288ca1c9b0cSelric d = malloc(sizeof(*d));
289b9d004c6Schristos if(d == NULL)
290b9d004c6Schristos return krb5_enomem(context);
291ca1c9b0cSelric d->filename = strdup(name);
292ca1c9b0cSelric if(d->filename == NULL) {
293ca1c9b0cSelric free(d);
294b9d004c6Schristos return krb5_enomem(context);
295ca1c9b0cSelric }
296ca1c9b0cSelric d->flags = 0;
297ca1c9b0cSelric id->data = d;
298ca1c9b0cSelric return 0;
299ca1c9b0cSelric }
300ca1c9b0cSelric
301ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_resolve_java14(krb5_context context,const char * name,krb5_keytab id)302ca1c9b0cSelric fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id)
303ca1c9b0cSelric {
304ca1c9b0cSelric krb5_error_code ret;
305ca1c9b0cSelric
306ca1c9b0cSelric ret = fkt_resolve(context, name, id);
307ca1c9b0cSelric if (ret == 0) {
308ca1c9b0cSelric struct fkt_data *d = id->data;
309ca1c9b0cSelric d->flags |= KRB5_KT_FL_JAVA;
310ca1c9b0cSelric }
311ca1c9b0cSelric return ret;
312ca1c9b0cSelric }
313ca1c9b0cSelric
314ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_close(krb5_context context,krb5_keytab id)315ca1c9b0cSelric fkt_close(krb5_context context, krb5_keytab id)
316ca1c9b0cSelric {
317ca1c9b0cSelric struct fkt_data *d = id->data;
318ca1c9b0cSelric free(d->filename);
319ca1c9b0cSelric free(d);
320ca1c9b0cSelric return 0;
321ca1c9b0cSelric }
322ca1c9b0cSelric
323ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_destroy(krb5_context context,krb5_keytab id)324ca1c9b0cSelric fkt_destroy(krb5_context context, krb5_keytab id)
325ca1c9b0cSelric {
326ca1c9b0cSelric struct fkt_data *d = id->data;
327ca1c9b0cSelric _krb5_erase_file(context, d->filename);
328ca1c9b0cSelric return 0;
329ca1c9b0cSelric }
330ca1c9b0cSelric
331ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_get_name(krb5_context context,krb5_keytab id,char * name,size_t namesize)332ca1c9b0cSelric fkt_get_name(krb5_context context,
333ca1c9b0cSelric krb5_keytab id,
334ca1c9b0cSelric char *name,
335ca1c9b0cSelric size_t namesize)
336ca1c9b0cSelric {
337ca1c9b0cSelric /* This function is XXX */
338ca1c9b0cSelric struct fkt_data *d = id->data;
339ca1c9b0cSelric strlcpy(name, d->filename, namesize);
340ca1c9b0cSelric return 0;
341ca1c9b0cSelric }
342ca1c9b0cSelric
343ca1c9b0cSelric static void
storage_set_flags(krb5_context context,krb5_storage * sp,int vno)344ca1c9b0cSelric storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
345ca1c9b0cSelric {
346ca1c9b0cSelric int flags = 0;
347ca1c9b0cSelric switch(vno) {
348ca1c9b0cSelric case KRB5_KT_VNO_1:
349ca1c9b0cSelric flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
350ca1c9b0cSelric flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
351ca1c9b0cSelric flags |= KRB5_STORAGE_HOST_BYTEORDER;
352ca1c9b0cSelric break;
353ca1c9b0cSelric case KRB5_KT_VNO_2:
354ca1c9b0cSelric break;
355ca1c9b0cSelric default:
356ca1c9b0cSelric krb5_warnx(context,
357ca1c9b0cSelric "storage_set_flags called with bad vno (%d)", vno);
358ca1c9b0cSelric }
359ca1c9b0cSelric krb5_storage_set_flags(sp, flags);
360ca1c9b0cSelric }
361ca1c9b0cSelric
362ca1c9b0cSelric static krb5_error_code
fkt_start_seq_get_int(krb5_context context,krb5_keytab id,int flags,int exclusive,krb5_kt_cursor * c)363ca1c9b0cSelric fkt_start_seq_get_int(krb5_context context,
364ca1c9b0cSelric krb5_keytab id,
365ca1c9b0cSelric int flags,
366ca1c9b0cSelric int exclusive,
367ca1c9b0cSelric krb5_kt_cursor *c)
368ca1c9b0cSelric {
369ca1c9b0cSelric int8_t pvno, tag;
370ca1c9b0cSelric krb5_error_code ret;
371ca1c9b0cSelric struct fkt_data *d = id->data;
372ca1c9b0cSelric
373ca1c9b0cSelric c->fd = open (d->filename, flags);
374ca1c9b0cSelric if (c->fd < 0) {
375ca1c9b0cSelric ret = errno;
376ca1c9b0cSelric krb5_set_error_message(context, ret,
377ca1c9b0cSelric N_("keytab %s open failed: %s", ""),
378ca1c9b0cSelric d->filename, strerror(ret));
379ca1c9b0cSelric return ret;
380ca1c9b0cSelric }
381ca1c9b0cSelric rk_cloexec(c->fd);
382ca1c9b0cSelric ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
383ca1c9b0cSelric if (ret) {
384ca1c9b0cSelric close(c->fd);
385ca1c9b0cSelric return ret;
386ca1c9b0cSelric }
387ca1c9b0cSelric c->sp = krb5_storage_from_fd(c->fd);
388ca1c9b0cSelric if (c->sp == NULL) {
389ca1c9b0cSelric _krb5_xunlock(context, c->fd);
390ca1c9b0cSelric close(c->fd);
391b9d004c6Schristos return krb5_enomem(context);
392ca1c9b0cSelric }
393ca1c9b0cSelric krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
394ca1c9b0cSelric ret = krb5_ret_int8(c->sp, &pvno);
395ca1c9b0cSelric if(ret) {
396ca1c9b0cSelric krb5_storage_free(c->sp);
397ca1c9b0cSelric _krb5_xunlock(context, c->fd);
398ca1c9b0cSelric close(c->fd);
399ca1c9b0cSelric krb5_clear_error_message(context);
400ca1c9b0cSelric return ret;
401ca1c9b0cSelric }
402ca1c9b0cSelric if(pvno != 5) {
403ca1c9b0cSelric krb5_storage_free(c->sp);
404ca1c9b0cSelric _krb5_xunlock(context, c->fd);
405ca1c9b0cSelric close(c->fd);
406ca1c9b0cSelric krb5_clear_error_message (context);
407ca1c9b0cSelric return KRB5_KEYTAB_BADVNO;
408ca1c9b0cSelric }
409ca1c9b0cSelric ret = krb5_ret_int8(c->sp, &tag);
410ca1c9b0cSelric if (ret) {
411ca1c9b0cSelric krb5_storage_free(c->sp);
412ca1c9b0cSelric _krb5_xunlock(context, c->fd);
413ca1c9b0cSelric close(c->fd);
414ca1c9b0cSelric krb5_clear_error_message(context);
415ca1c9b0cSelric return ret;
416ca1c9b0cSelric }
417ca1c9b0cSelric id->version = tag;
418ca1c9b0cSelric storage_set_flags(context, c->sp, id->version);
419ca1c9b0cSelric return 0;
420ca1c9b0cSelric }
421ca1c9b0cSelric
422ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)423ca1c9b0cSelric fkt_start_seq_get(krb5_context context,
424ca1c9b0cSelric krb5_keytab id,
425ca1c9b0cSelric krb5_kt_cursor *c)
426ca1c9b0cSelric {
427ca1c9b0cSelric return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c);
428ca1c9b0cSelric }
429ca1c9b0cSelric
430ca1c9b0cSelric static krb5_error_code
fkt_next_entry_int(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor,off_t * start,off_t * end)431ca1c9b0cSelric fkt_next_entry_int(krb5_context context,
432ca1c9b0cSelric krb5_keytab id,
433ca1c9b0cSelric krb5_keytab_entry *entry,
434ca1c9b0cSelric krb5_kt_cursor *cursor,
435ca1c9b0cSelric off_t *start,
436ca1c9b0cSelric off_t *end)
437ca1c9b0cSelric {
438ca1c9b0cSelric struct fkt_data *d = id->data;
439ca1c9b0cSelric int32_t len;
440ca1c9b0cSelric int ret;
441ca1c9b0cSelric int8_t tmp8;
442ca1c9b0cSelric int32_t tmp32;
443ca1c9b0cSelric uint32_t utmp32;
444ca1c9b0cSelric off_t pos, curpos;
445ca1c9b0cSelric
446ca1c9b0cSelric pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
447ca1c9b0cSelric loop:
448ca1c9b0cSelric ret = krb5_ret_int32(cursor->sp, &len);
449ca1c9b0cSelric if (ret)
450ca1c9b0cSelric return ret;
451ca1c9b0cSelric if(len < 0) {
452ca1c9b0cSelric pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
453ca1c9b0cSelric goto loop;
454ca1c9b0cSelric }
455ca1c9b0cSelric ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
456ca1c9b0cSelric if (ret)
457ca1c9b0cSelric goto out;
458ca1c9b0cSelric ret = krb5_ret_uint32(cursor->sp, &utmp32);
459ca1c9b0cSelric entry->timestamp = utmp32;
460ca1c9b0cSelric if (ret)
461ca1c9b0cSelric goto out;
462ca1c9b0cSelric ret = krb5_ret_int8(cursor->sp, &tmp8);
463ca1c9b0cSelric if (ret)
464ca1c9b0cSelric goto out;
465ca1c9b0cSelric entry->vno = tmp8;
466ca1c9b0cSelric ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
467ca1c9b0cSelric if (ret)
468ca1c9b0cSelric goto out;
469ca1c9b0cSelric /* there might be a 32 bit kvno here
470ca1c9b0cSelric * if it's zero, assume that the 8bit one was right,
471ca1c9b0cSelric * otherwise trust the new value */
472ca1c9b0cSelric curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
473ca1c9b0cSelric if(len + 4 + pos - curpos >= 4) {
474ca1c9b0cSelric ret = krb5_ret_int32(cursor->sp, &tmp32);
475ca1c9b0cSelric if (ret == 0 && tmp32 != 0)
476ca1c9b0cSelric entry->vno = tmp32;
477ca1c9b0cSelric }
478ca1c9b0cSelric /* there might be a flags field here */
479ca1c9b0cSelric if(len + 4 + pos - curpos >= 8) {
480ca1c9b0cSelric ret = krb5_ret_uint32(cursor->sp, &utmp32);
481ca1c9b0cSelric if (ret == 0)
482ca1c9b0cSelric entry->flags = utmp32;
483ca1c9b0cSelric } else
484ca1c9b0cSelric entry->flags = 0;
485ca1c9b0cSelric
486ca1c9b0cSelric entry->aliases = NULL;
487ca1c9b0cSelric
488ca1c9b0cSelric if(start) *start = pos;
489ca1c9b0cSelric if(end) *end = pos + 4 + len;
490ca1c9b0cSelric out:
491b9d004c6Schristos if (ret)
492b9d004c6Schristos krb5_kt_free_entry(context, entry);
493ca1c9b0cSelric krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
494ca1c9b0cSelric return ret;
495ca1c9b0cSelric }
496ca1c9b0cSelric
497ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)498ca1c9b0cSelric fkt_next_entry(krb5_context context,
499ca1c9b0cSelric krb5_keytab id,
500ca1c9b0cSelric krb5_keytab_entry *entry,
501ca1c9b0cSelric krb5_kt_cursor *cursor)
502ca1c9b0cSelric {
503ca1c9b0cSelric return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
504ca1c9b0cSelric }
505ca1c9b0cSelric
506ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)507ca1c9b0cSelric fkt_end_seq_get(krb5_context context,
508ca1c9b0cSelric krb5_keytab id,
509ca1c9b0cSelric krb5_kt_cursor *cursor)
510ca1c9b0cSelric {
511ca1c9b0cSelric krb5_storage_free(cursor->sp);
512ca1c9b0cSelric _krb5_xunlock(context, cursor->fd);
513ca1c9b0cSelric close(cursor->fd);
514ca1c9b0cSelric return 0;
515ca1c9b0cSelric }
516ca1c9b0cSelric
517ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_setup_keytab(krb5_context context,krb5_keytab id,krb5_storage * sp)518ca1c9b0cSelric fkt_setup_keytab(krb5_context context,
519ca1c9b0cSelric krb5_keytab id,
520ca1c9b0cSelric krb5_storage *sp)
521ca1c9b0cSelric {
522ca1c9b0cSelric krb5_error_code ret;
523ca1c9b0cSelric ret = krb5_store_int8(sp, 5);
524ca1c9b0cSelric if(ret)
525ca1c9b0cSelric return ret;
526ca1c9b0cSelric if(id->version == 0)
527ca1c9b0cSelric id->version = KRB5_KT_VNO;
528ca1c9b0cSelric return krb5_store_int8 (sp, id->version);
529ca1c9b0cSelric }
530ca1c9b0cSelric
531ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)532ca1c9b0cSelric fkt_add_entry(krb5_context context,
533ca1c9b0cSelric krb5_keytab id,
534ca1c9b0cSelric krb5_keytab_entry *entry)
535ca1c9b0cSelric {
536ca1c9b0cSelric int ret;
537ca1c9b0cSelric int fd;
538ca1c9b0cSelric krb5_storage *sp;
539ca1c9b0cSelric struct fkt_data *d = id->data;
540ca1c9b0cSelric krb5_data keytab;
541ca1c9b0cSelric int32_t len;
542ca1c9b0cSelric
543ca1c9b0cSelric fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
544ca1c9b0cSelric if (fd < 0) {
545ca1c9b0cSelric fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
546ca1c9b0cSelric if (fd < 0) {
547ca1c9b0cSelric ret = errno;
548ca1c9b0cSelric krb5_set_error_message(context, ret,
549ca1c9b0cSelric N_("open(%s): %s", ""), d->filename,
550ca1c9b0cSelric strerror(ret));
551ca1c9b0cSelric return ret;
552ca1c9b0cSelric }
553ca1c9b0cSelric rk_cloexec(fd);
554ca1c9b0cSelric
555ca1c9b0cSelric ret = _krb5_xlock(context, fd, 1, d->filename);
556ca1c9b0cSelric if (ret) {
557ca1c9b0cSelric close(fd);
558ca1c9b0cSelric return ret;
559ca1c9b0cSelric }
560ca1c9b0cSelric sp = krb5_storage_from_fd(fd);
561ca1c9b0cSelric krb5_storage_set_eof_code(sp, KRB5_KT_END);
562ca1c9b0cSelric ret = fkt_setup_keytab(context, id, sp);
563ca1c9b0cSelric if(ret) {
564ca1c9b0cSelric goto out;
565ca1c9b0cSelric }
566ca1c9b0cSelric storage_set_flags(context, sp, id->version);
567ca1c9b0cSelric } else {
568ca1c9b0cSelric int8_t pvno, tag;
569ca1c9b0cSelric
570ca1c9b0cSelric rk_cloexec(fd);
571ca1c9b0cSelric
572ca1c9b0cSelric ret = _krb5_xlock(context, fd, 1, d->filename);
573ca1c9b0cSelric if (ret) {
574ca1c9b0cSelric close(fd);
575ca1c9b0cSelric return ret;
576ca1c9b0cSelric }
577ca1c9b0cSelric sp = krb5_storage_from_fd(fd);
578ca1c9b0cSelric krb5_storage_set_eof_code(sp, KRB5_KT_END);
579ca1c9b0cSelric ret = krb5_ret_int8(sp, &pvno);
580ca1c9b0cSelric if(ret) {
581ca1c9b0cSelric /* we probably have a zero byte file, so try to set it up
582ca1c9b0cSelric properly */
583ca1c9b0cSelric ret = fkt_setup_keytab(context, id, sp);
584ca1c9b0cSelric if(ret) {
585ca1c9b0cSelric krb5_set_error_message(context, ret,
586ca1c9b0cSelric N_("%s: keytab is corrupted: %s", ""),
587ca1c9b0cSelric d->filename, strerror(ret));
588ca1c9b0cSelric goto out;
589ca1c9b0cSelric }
590ca1c9b0cSelric storage_set_flags(context, sp, id->version);
591ca1c9b0cSelric } else {
592ca1c9b0cSelric if(pvno != 5) {
593ca1c9b0cSelric ret = KRB5_KEYTAB_BADVNO;
594ca1c9b0cSelric krb5_set_error_message(context, ret,
595ca1c9b0cSelric N_("Bad version in keytab %s", ""),
596ca1c9b0cSelric d->filename);
597ca1c9b0cSelric goto out;
598ca1c9b0cSelric }
599ca1c9b0cSelric ret = krb5_ret_int8 (sp, &tag);
600ca1c9b0cSelric if (ret) {
601ca1c9b0cSelric krb5_set_error_message(context, ret,
602ca1c9b0cSelric N_("failed reading tag from "
603ca1c9b0cSelric "keytab %s", ""),
604ca1c9b0cSelric d->filename);
605ca1c9b0cSelric goto out;
606ca1c9b0cSelric }
607ca1c9b0cSelric id->version = tag;
608ca1c9b0cSelric storage_set_flags(context, sp, id->version);
609ca1c9b0cSelric }
610ca1c9b0cSelric }
611ca1c9b0cSelric
612ca1c9b0cSelric {
613ca1c9b0cSelric krb5_storage *emem;
614ca1c9b0cSelric emem = krb5_storage_emem();
615ca1c9b0cSelric if(emem == NULL) {
616b9d004c6Schristos ret = krb5_enomem(context);
617ca1c9b0cSelric goto out;
618ca1c9b0cSelric }
619ca1c9b0cSelric ret = krb5_kt_store_principal(context, emem, entry->principal);
620ca1c9b0cSelric if(ret) {
621ca1c9b0cSelric krb5_set_error_message(context, ret,
622ca1c9b0cSelric N_("Failed storing principal "
623ca1c9b0cSelric "in keytab %s", ""),
624ca1c9b0cSelric d->filename);
625ca1c9b0cSelric krb5_storage_free(emem);
626ca1c9b0cSelric goto out;
627ca1c9b0cSelric }
628ca1c9b0cSelric ret = krb5_store_int32 (emem, entry->timestamp);
629ca1c9b0cSelric if(ret) {
630ca1c9b0cSelric krb5_set_error_message(context, ret,
631ca1c9b0cSelric N_("Failed storing timpstamp "
632ca1c9b0cSelric "in keytab %s", ""),
633ca1c9b0cSelric d->filename);
634ca1c9b0cSelric krb5_storage_free(emem);
635ca1c9b0cSelric goto out;
636ca1c9b0cSelric }
637ca1c9b0cSelric ret = krb5_store_int8 (emem, entry->vno % 256);
638ca1c9b0cSelric if(ret) {
639ca1c9b0cSelric krb5_set_error_message(context, ret,
640ca1c9b0cSelric N_("Failed storing kvno "
641ca1c9b0cSelric "in keytab %s", ""),
642ca1c9b0cSelric d->filename);
643ca1c9b0cSelric krb5_storage_free(emem);
644ca1c9b0cSelric goto out;
645ca1c9b0cSelric }
646ca1c9b0cSelric ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock);
647ca1c9b0cSelric if(ret) {
648ca1c9b0cSelric krb5_storage_free(emem);
649ca1c9b0cSelric goto out;
650ca1c9b0cSelric }
651ca1c9b0cSelric if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
652ca1c9b0cSelric ret = krb5_store_int32 (emem, entry->vno);
653ca1c9b0cSelric if (ret) {
654ca1c9b0cSelric krb5_set_error_message(context, ret,
655ca1c9b0cSelric N_("Failed storing extended kvno "
656ca1c9b0cSelric "in keytab %s", ""),
657ca1c9b0cSelric d->filename);
658ca1c9b0cSelric krb5_storage_free(emem);
659ca1c9b0cSelric goto out;
660ca1c9b0cSelric }
661ca1c9b0cSelric ret = krb5_store_uint32 (emem, entry->flags);
662ca1c9b0cSelric if (ret) {
663ca1c9b0cSelric krb5_set_error_message(context, ret,
664ca1c9b0cSelric N_("Failed storing extended kvno "
665ca1c9b0cSelric "in keytab %s", ""),
666ca1c9b0cSelric d->filename);
667ca1c9b0cSelric krb5_storage_free(emem);
668ca1c9b0cSelric goto out;
669ca1c9b0cSelric }
670ca1c9b0cSelric }
671ca1c9b0cSelric
672ca1c9b0cSelric ret = krb5_storage_to_data(emem, &keytab);
673ca1c9b0cSelric krb5_storage_free(emem);
674ca1c9b0cSelric if(ret) {
675ca1c9b0cSelric krb5_set_error_message(context, ret,
676ca1c9b0cSelric N_("Failed converting keytab entry "
677ca1c9b0cSelric "to memory block for keytab %s", ""),
678ca1c9b0cSelric d->filename);
679ca1c9b0cSelric goto out;
680ca1c9b0cSelric }
681ca1c9b0cSelric }
682ca1c9b0cSelric
683ca1c9b0cSelric while(1) {
684ca1c9b0cSelric ret = krb5_ret_int32(sp, &len);
685ca1c9b0cSelric if(ret == KRB5_KT_END) {
686ca1c9b0cSelric len = keytab.length;
687ca1c9b0cSelric break;
688ca1c9b0cSelric }
689ca1c9b0cSelric if(len < 0) {
690ca1c9b0cSelric len = -len;
6914f77a458Spettai if(len >= (int)keytab.length) {
692ca1c9b0cSelric krb5_storage_seek(sp, -4, SEEK_CUR);
693ca1c9b0cSelric break;
694ca1c9b0cSelric }
695ca1c9b0cSelric }
696ca1c9b0cSelric krb5_storage_seek(sp, len, SEEK_CUR);
697ca1c9b0cSelric }
698ca1c9b0cSelric ret = krb5_store_int32(sp, len);
699ca1c9b0cSelric if(krb5_storage_write(sp, keytab.data, keytab.length) < 0) {
700ca1c9b0cSelric ret = errno;
701ca1c9b0cSelric krb5_set_error_message(context, ret,
702ca1c9b0cSelric N_("Failed writing keytab block "
703ca1c9b0cSelric "in keytab %s: %s", ""),
704ca1c9b0cSelric d->filename, strerror(ret));
705ca1c9b0cSelric }
706ca1c9b0cSelric memset(keytab.data, 0, keytab.length);
707ca1c9b0cSelric krb5_data_free(&keytab);
708ca1c9b0cSelric out:
709ca1c9b0cSelric krb5_storage_free(sp);
710ca1c9b0cSelric _krb5_xunlock(context, fd);
711ca1c9b0cSelric close(fd);
712ca1c9b0cSelric return ret;
713ca1c9b0cSelric }
714ca1c9b0cSelric
715ca1c9b0cSelric static krb5_error_code KRB5_CALLCONV
fkt_remove_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)716ca1c9b0cSelric fkt_remove_entry(krb5_context context,
717ca1c9b0cSelric krb5_keytab id,
718ca1c9b0cSelric krb5_keytab_entry *entry)
719ca1c9b0cSelric {
720ca1c9b0cSelric krb5_keytab_entry e;
721ca1c9b0cSelric krb5_kt_cursor cursor;
722ca1c9b0cSelric off_t pos_start, pos_end;
723ca1c9b0cSelric int found = 0;
724ca1c9b0cSelric krb5_error_code ret;
725ca1c9b0cSelric
726ca1c9b0cSelric ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor);
727ca1c9b0cSelric if(ret != 0)
728ca1c9b0cSelric goto out; /* return other error here? */
729ca1c9b0cSelric while(fkt_next_entry_int(context, id, &e, &cursor,
730ca1c9b0cSelric &pos_start, &pos_end) == 0) {
731ca1c9b0cSelric if(krb5_kt_compare(context, &e, entry->principal,
732ca1c9b0cSelric entry->vno, entry->keyblock.keytype)) {
733ca1c9b0cSelric int32_t len;
734ca1c9b0cSelric unsigned char buf[128];
735ca1c9b0cSelric found = 1;
736ca1c9b0cSelric krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
737ca1c9b0cSelric len = pos_end - pos_start - 4;
738ca1c9b0cSelric krb5_store_int32(cursor.sp, -len);
739ca1c9b0cSelric memset(buf, 0, sizeof(buf));
740ca1c9b0cSelric while(len > 0) {
7414f77a458Spettai krb5_storage_write(cursor.sp, buf,
7424f77a458Spettai min((size_t)len, sizeof(buf)));
7434f77a458Spettai len -= min((size_t)len, sizeof(buf));
744ca1c9b0cSelric }
745ca1c9b0cSelric }
746ca1c9b0cSelric krb5_kt_free_entry(context, &e);
747ca1c9b0cSelric }
748ca1c9b0cSelric krb5_kt_end_seq_get(context, id, &cursor);
749ca1c9b0cSelric out:
750ca1c9b0cSelric if (!found) {
751ca1c9b0cSelric krb5_clear_error_message (context);
752ca1c9b0cSelric return KRB5_KT_NOTFOUND;
753ca1c9b0cSelric }
754ca1c9b0cSelric return 0;
755ca1c9b0cSelric }
756ca1c9b0cSelric
757ca1c9b0cSelric const krb5_kt_ops krb5_fkt_ops = {
758ca1c9b0cSelric "FILE",
759ca1c9b0cSelric fkt_resolve,
760ca1c9b0cSelric fkt_get_name,
761ca1c9b0cSelric fkt_close,
762ca1c9b0cSelric fkt_destroy,
763ca1c9b0cSelric NULL, /* get */
764ca1c9b0cSelric fkt_start_seq_get,
765ca1c9b0cSelric fkt_next_entry,
766ca1c9b0cSelric fkt_end_seq_get,
767ca1c9b0cSelric fkt_add_entry,
768b9d004c6Schristos fkt_remove_entry,
769b9d004c6Schristos NULL,
770b9d004c6Schristos 0
771ca1c9b0cSelric };
772ca1c9b0cSelric
773ca1c9b0cSelric const krb5_kt_ops krb5_wrfkt_ops = {
774ca1c9b0cSelric "WRFILE",
775ca1c9b0cSelric fkt_resolve,
776ca1c9b0cSelric fkt_get_name,
777ca1c9b0cSelric fkt_close,
778ca1c9b0cSelric fkt_destroy,
779ca1c9b0cSelric NULL, /* get */
780ca1c9b0cSelric fkt_start_seq_get,
781ca1c9b0cSelric fkt_next_entry,
782ca1c9b0cSelric fkt_end_seq_get,
783ca1c9b0cSelric fkt_add_entry,
784b9d004c6Schristos fkt_remove_entry,
785b9d004c6Schristos NULL,
786b9d004c6Schristos 0
787ca1c9b0cSelric };
788ca1c9b0cSelric
789ca1c9b0cSelric const krb5_kt_ops krb5_javakt_ops = {
790ca1c9b0cSelric "JAVA14",
791ca1c9b0cSelric fkt_resolve_java14,
792ca1c9b0cSelric fkt_get_name,
793ca1c9b0cSelric fkt_close,
794ca1c9b0cSelric fkt_destroy,
795ca1c9b0cSelric NULL, /* get */
796ca1c9b0cSelric fkt_start_seq_get,
797ca1c9b0cSelric fkt_next_entry,
798ca1c9b0cSelric fkt_end_seq_get,
799ca1c9b0cSelric fkt_add_entry,
800b9d004c6Schristos fkt_remove_entry,
801b9d004c6Schristos NULL,
802b9d004c6Schristos 0
803ca1c9b0cSelric };
804