1*0a6a1f1dSLionel Sambuc /* $NetBSD: keytab_keyfile.c,v 1.1.1.2 2014/04/24 12:45:50 pettai Exp $ */
2ebfedea0SLionel Sambuc
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc * Copyright (c) 1997 - 2007 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
38ebfedea0SLionel Sambuc #ifndef HEIMDAL_SMALLER
39ebfedea0SLionel Sambuc
40ebfedea0SLionel Sambuc /* afs keyfile operations --------------------------------------- */
41ebfedea0SLionel Sambuc
42ebfedea0SLionel Sambuc /*
43ebfedea0SLionel Sambuc * Minimum tools to handle the AFS KeyFile.
44ebfedea0SLionel Sambuc *
45ebfedea0SLionel Sambuc * Format of the KeyFile is:
46ebfedea0SLionel Sambuc * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys}
47ebfedea0SLionel Sambuc *
48ebfedea0SLionel Sambuc * It just adds to the end of the keyfile, deleting isn't implemented.
49ebfedea0SLionel Sambuc * Use your favorite text/hex editor to delete keys.
50ebfedea0SLionel Sambuc *
51ebfedea0SLionel Sambuc */
52ebfedea0SLionel Sambuc
53ebfedea0SLionel Sambuc #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell"
54ebfedea0SLionel Sambuc #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf"
55ebfedea0SLionel Sambuc
56ebfedea0SLionel Sambuc struct akf_data {
57ebfedea0SLionel Sambuc uint32_t num_entries;
58ebfedea0SLionel Sambuc char *filename;
59ebfedea0SLionel Sambuc char *cell;
60ebfedea0SLionel Sambuc char *realm;
61ebfedea0SLionel Sambuc };
62ebfedea0SLionel Sambuc
63ebfedea0SLionel Sambuc /*
64ebfedea0SLionel Sambuc * set `d->cell' and `d->realm'
65ebfedea0SLionel Sambuc */
66ebfedea0SLionel Sambuc
67ebfedea0SLionel Sambuc static int
get_cell_and_realm(krb5_context context,struct akf_data * d)68ebfedea0SLionel Sambuc get_cell_and_realm (krb5_context context, struct akf_data *d)
69ebfedea0SLionel Sambuc {
70ebfedea0SLionel Sambuc FILE *f;
71ebfedea0SLionel Sambuc char buf[BUFSIZ], *cp;
72ebfedea0SLionel Sambuc int ret;
73ebfedea0SLionel Sambuc
74ebfedea0SLionel Sambuc f = fopen (AFS_SERVERTHISCELL, "r");
75ebfedea0SLionel Sambuc if (f == NULL) {
76ebfedea0SLionel Sambuc ret = errno;
77ebfedea0SLionel Sambuc krb5_set_error_message (context, ret,
78ebfedea0SLionel Sambuc N_("Open ThisCell %s: %s", ""),
79ebfedea0SLionel Sambuc AFS_SERVERTHISCELL,
80ebfedea0SLionel Sambuc strerror(ret));
81ebfedea0SLionel Sambuc return ret;
82ebfedea0SLionel Sambuc }
83ebfedea0SLionel Sambuc if (fgets (buf, sizeof(buf), f) == NULL) {
84ebfedea0SLionel Sambuc fclose (f);
85ebfedea0SLionel Sambuc krb5_set_error_message (context, EINVAL,
86ebfedea0SLionel Sambuc N_("No cell in ThisCell file %s", ""),
87ebfedea0SLionel Sambuc AFS_SERVERTHISCELL);
88ebfedea0SLionel Sambuc return EINVAL;
89ebfedea0SLionel Sambuc }
90ebfedea0SLionel Sambuc buf[strcspn(buf, "\n")] = '\0';
91ebfedea0SLionel Sambuc fclose(f);
92ebfedea0SLionel Sambuc
93ebfedea0SLionel Sambuc d->cell = strdup (buf);
94ebfedea0SLionel Sambuc if (d->cell == NULL) {
95ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM,
96ebfedea0SLionel Sambuc N_("malloc: out of memory", ""));
97ebfedea0SLionel Sambuc return ENOMEM;
98ebfedea0SLionel Sambuc }
99ebfedea0SLionel Sambuc
100ebfedea0SLionel Sambuc f = fopen (AFS_SERVERMAGICKRBCONF, "r");
101ebfedea0SLionel Sambuc if (f != NULL) {
102ebfedea0SLionel Sambuc if (fgets (buf, sizeof(buf), f) == NULL) {
103ebfedea0SLionel Sambuc free (d->cell);
104ebfedea0SLionel Sambuc d->cell = NULL;
105ebfedea0SLionel Sambuc fclose (f);
106ebfedea0SLionel Sambuc krb5_set_error_message (context, EINVAL,
107ebfedea0SLionel Sambuc N_("No realm in ThisCell file %s", ""),
108ebfedea0SLionel Sambuc AFS_SERVERMAGICKRBCONF);
109ebfedea0SLionel Sambuc return EINVAL;
110ebfedea0SLionel Sambuc }
111ebfedea0SLionel Sambuc buf[strcspn(buf, "\n")] = '\0';
112ebfedea0SLionel Sambuc fclose(f);
113ebfedea0SLionel Sambuc }
114ebfedea0SLionel Sambuc /* uppercase */
115ebfedea0SLionel Sambuc for (cp = buf; *cp != '\0'; cp++)
116ebfedea0SLionel Sambuc *cp = toupper((unsigned char)*cp);
117ebfedea0SLionel Sambuc
118ebfedea0SLionel Sambuc d->realm = strdup (buf);
119ebfedea0SLionel Sambuc if (d->realm == NULL) {
120ebfedea0SLionel Sambuc free (d->cell);
121ebfedea0SLionel Sambuc d->cell = NULL;
122ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM,
123ebfedea0SLionel Sambuc N_("malloc: out of memory", ""));
124ebfedea0SLionel Sambuc return ENOMEM;
125ebfedea0SLionel Sambuc }
126ebfedea0SLionel Sambuc return 0;
127ebfedea0SLionel Sambuc }
128ebfedea0SLionel Sambuc
129ebfedea0SLionel Sambuc /*
130ebfedea0SLionel Sambuc * init and get filename
131ebfedea0SLionel Sambuc */
132ebfedea0SLionel Sambuc
133ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_resolve(krb5_context context,const char * name,krb5_keytab id)134ebfedea0SLionel Sambuc akf_resolve(krb5_context context, const char *name, krb5_keytab id)
135ebfedea0SLionel Sambuc {
136ebfedea0SLionel Sambuc int ret;
137ebfedea0SLionel Sambuc struct akf_data *d = malloc(sizeof (struct akf_data));
138ebfedea0SLionel Sambuc
139ebfedea0SLionel Sambuc if (d == NULL) {
140ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM,
141ebfedea0SLionel Sambuc N_("malloc: out of memory", ""));
142ebfedea0SLionel Sambuc return ENOMEM;
143ebfedea0SLionel Sambuc }
144ebfedea0SLionel Sambuc
145ebfedea0SLionel Sambuc d->num_entries = 0;
146ebfedea0SLionel Sambuc ret = get_cell_and_realm (context, d);
147ebfedea0SLionel Sambuc if (ret) {
148ebfedea0SLionel Sambuc free (d);
149ebfedea0SLionel Sambuc return ret;
150ebfedea0SLionel Sambuc }
151ebfedea0SLionel Sambuc d->filename = strdup (name);
152ebfedea0SLionel Sambuc if (d->filename == NULL) {
153ebfedea0SLionel Sambuc free (d->cell);
154ebfedea0SLionel Sambuc free (d->realm);
155ebfedea0SLionel Sambuc free (d);
156ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM,
157ebfedea0SLionel Sambuc N_("malloc: out of memory", ""));
158ebfedea0SLionel Sambuc return ENOMEM;
159ebfedea0SLionel Sambuc }
160ebfedea0SLionel Sambuc id->data = d;
161ebfedea0SLionel Sambuc
162ebfedea0SLionel Sambuc return 0;
163ebfedea0SLionel Sambuc }
164ebfedea0SLionel Sambuc
165ebfedea0SLionel Sambuc /*
166ebfedea0SLionel Sambuc * cleanup
167ebfedea0SLionel Sambuc */
168ebfedea0SLionel Sambuc
169ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_close(krb5_context context,krb5_keytab id)170ebfedea0SLionel Sambuc akf_close(krb5_context context, krb5_keytab id)
171ebfedea0SLionel Sambuc {
172ebfedea0SLionel Sambuc struct akf_data *d = id->data;
173ebfedea0SLionel Sambuc
174ebfedea0SLionel Sambuc free (d->filename);
175ebfedea0SLionel Sambuc free (d->cell);
176ebfedea0SLionel Sambuc free (d);
177ebfedea0SLionel Sambuc return 0;
178ebfedea0SLionel Sambuc }
179ebfedea0SLionel Sambuc
180ebfedea0SLionel Sambuc /*
181ebfedea0SLionel Sambuc * Return filename
182ebfedea0SLionel Sambuc */
183ebfedea0SLionel Sambuc
184ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_get_name(krb5_context context,krb5_keytab id,char * name,size_t name_sz)185ebfedea0SLionel Sambuc akf_get_name(krb5_context context,
186ebfedea0SLionel Sambuc krb5_keytab id,
187ebfedea0SLionel Sambuc char *name,
188ebfedea0SLionel Sambuc size_t name_sz)
189ebfedea0SLionel Sambuc {
190ebfedea0SLionel Sambuc struct akf_data *d = id->data;
191ebfedea0SLionel Sambuc
192ebfedea0SLionel Sambuc strlcpy (name, d->filename, name_sz);
193ebfedea0SLionel Sambuc return 0;
194ebfedea0SLionel Sambuc }
195ebfedea0SLionel Sambuc
196ebfedea0SLionel Sambuc /*
197ebfedea0SLionel Sambuc * Init
198ebfedea0SLionel Sambuc */
199ebfedea0SLionel Sambuc
200ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)201ebfedea0SLionel Sambuc akf_start_seq_get(krb5_context context,
202ebfedea0SLionel Sambuc krb5_keytab id,
203ebfedea0SLionel Sambuc krb5_kt_cursor *c)
204ebfedea0SLionel Sambuc {
205ebfedea0SLionel Sambuc int32_t ret;
206ebfedea0SLionel Sambuc struct akf_data *d = id->data;
207ebfedea0SLionel Sambuc
208ebfedea0SLionel Sambuc c->fd = open (d->filename, O_RDONLY | O_BINARY | O_CLOEXEC, 0600);
209ebfedea0SLionel Sambuc if (c->fd < 0) {
210ebfedea0SLionel Sambuc ret = errno;
211ebfedea0SLionel Sambuc krb5_set_error_message(context, ret,
212ebfedea0SLionel Sambuc N_("keytab afs keyfile open %s failed: %s", ""),
213ebfedea0SLionel Sambuc d->filename, strerror(ret));
214ebfedea0SLionel Sambuc return ret;
215ebfedea0SLionel Sambuc }
216ebfedea0SLionel Sambuc
217*0a6a1f1dSLionel Sambuc c->data = NULL;
218ebfedea0SLionel Sambuc c->sp = krb5_storage_from_fd(c->fd);
219*0a6a1f1dSLionel Sambuc if (c->sp == NULL) {
220*0a6a1f1dSLionel Sambuc close(c->fd);
221*0a6a1f1dSLionel Sambuc krb5_clear_error_message (context);
222*0a6a1f1dSLionel Sambuc return KRB5_KT_NOTFOUND;
223*0a6a1f1dSLionel Sambuc }
224*0a6a1f1dSLionel Sambuc krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
225*0a6a1f1dSLionel Sambuc
226ebfedea0SLionel Sambuc ret = krb5_ret_uint32(c->sp, &d->num_entries);
227*0a6a1f1dSLionel Sambuc if(ret || d->num_entries > INT_MAX / 8) {
228ebfedea0SLionel Sambuc krb5_storage_free(c->sp);
229ebfedea0SLionel Sambuc close(c->fd);
230ebfedea0SLionel Sambuc krb5_clear_error_message (context);
231ebfedea0SLionel Sambuc if(ret == KRB5_KT_END)
232ebfedea0SLionel Sambuc return KRB5_KT_NOTFOUND;
233ebfedea0SLionel Sambuc return ret;
234ebfedea0SLionel Sambuc }
235ebfedea0SLionel Sambuc
236ebfedea0SLionel Sambuc return 0;
237ebfedea0SLionel Sambuc }
238ebfedea0SLionel Sambuc
239ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)240ebfedea0SLionel Sambuc akf_next_entry(krb5_context context,
241ebfedea0SLionel Sambuc krb5_keytab id,
242ebfedea0SLionel Sambuc krb5_keytab_entry *entry,
243ebfedea0SLionel Sambuc krb5_kt_cursor *cursor)
244ebfedea0SLionel Sambuc {
245ebfedea0SLionel Sambuc struct akf_data *d = id->data;
246ebfedea0SLionel Sambuc int32_t kvno;
247ebfedea0SLionel Sambuc off_t pos;
248ebfedea0SLionel Sambuc int ret;
249ebfedea0SLionel Sambuc
250ebfedea0SLionel Sambuc pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
251ebfedea0SLionel Sambuc
252ebfedea0SLionel Sambuc if ((pos - 4) / (4 + 8) >= d->num_entries)
253ebfedea0SLionel Sambuc return KRB5_KT_END;
254ebfedea0SLionel Sambuc
255ebfedea0SLionel Sambuc ret = krb5_make_principal (context, &entry->principal,
256ebfedea0SLionel Sambuc d->realm, "afs", d->cell, NULL);
257ebfedea0SLionel Sambuc if (ret)
258ebfedea0SLionel Sambuc goto out;
259ebfedea0SLionel Sambuc
260ebfedea0SLionel Sambuc ret = krb5_ret_int32(cursor->sp, &kvno);
261ebfedea0SLionel Sambuc if (ret) {
262ebfedea0SLionel Sambuc krb5_free_principal (context, entry->principal);
263ebfedea0SLionel Sambuc goto out;
264ebfedea0SLionel Sambuc }
265ebfedea0SLionel Sambuc
266ebfedea0SLionel Sambuc entry->vno = kvno;
267ebfedea0SLionel Sambuc
268*0a6a1f1dSLionel Sambuc if (cursor->data)
269ebfedea0SLionel Sambuc entry->keyblock.keytype = ETYPE_DES_CBC_MD5;
270*0a6a1f1dSLionel Sambuc else
271*0a6a1f1dSLionel Sambuc entry->keyblock.keytype = ETYPE_DES_CBC_CRC;
272ebfedea0SLionel Sambuc entry->keyblock.keyvalue.length = 8;
273ebfedea0SLionel Sambuc entry->keyblock.keyvalue.data = malloc (8);
274ebfedea0SLionel Sambuc if (entry->keyblock.keyvalue.data == NULL) {
275ebfedea0SLionel Sambuc krb5_free_principal (context, entry->principal);
276ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM,
277ebfedea0SLionel Sambuc N_("malloc: out of memory", ""));
278ebfedea0SLionel Sambuc ret = ENOMEM;
279ebfedea0SLionel Sambuc goto out;
280ebfedea0SLionel Sambuc }
281ebfedea0SLionel Sambuc
282ebfedea0SLionel Sambuc ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8);
283ebfedea0SLionel Sambuc if(ret != 8)
284ebfedea0SLionel Sambuc ret = (ret < 0) ? errno : KRB5_KT_END;
285ebfedea0SLionel Sambuc else
286ebfedea0SLionel Sambuc ret = 0;
287ebfedea0SLionel Sambuc
288ebfedea0SLionel Sambuc entry->timestamp = time(NULL);
289ebfedea0SLionel Sambuc entry->flags = 0;
290ebfedea0SLionel Sambuc entry->aliases = NULL;
291ebfedea0SLionel Sambuc
292ebfedea0SLionel Sambuc out:
293*0a6a1f1dSLionel Sambuc if (cursor->data) {
294ebfedea0SLionel Sambuc krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET);
295*0a6a1f1dSLionel Sambuc cursor->data = NULL;
296*0a6a1f1dSLionel Sambuc } else
297*0a6a1f1dSLionel Sambuc cursor->data = cursor;
298ebfedea0SLionel Sambuc return ret;
299ebfedea0SLionel Sambuc }
300ebfedea0SLionel Sambuc
301ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)302ebfedea0SLionel Sambuc akf_end_seq_get(krb5_context context,
303ebfedea0SLionel Sambuc krb5_keytab id,
304ebfedea0SLionel Sambuc krb5_kt_cursor *cursor)
305ebfedea0SLionel Sambuc {
306ebfedea0SLionel Sambuc krb5_storage_free(cursor->sp);
307ebfedea0SLionel Sambuc close(cursor->fd);
308*0a6a1f1dSLionel Sambuc cursor->data = NULL;
309ebfedea0SLionel Sambuc return 0;
310ebfedea0SLionel Sambuc }
311ebfedea0SLionel Sambuc
312ebfedea0SLionel Sambuc static krb5_error_code KRB5_CALLCONV
akf_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)313ebfedea0SLionel Sambuc akf_add_entry(krb5_context context,
314ebfedea0SLionel Sambuc krb5_keytab id,
315ebfedea0SLionel Sambuc krb5_keytab_entry *entry)
316ebfedea0SLionel Sambuc {
317ebfedea0SLionel Sambuc struct akf_data *d = id->data;
318ebfedea0SLionel Sambuc int fd, created = 0;
319ebfedea0SLionel Sambuc krb5_error_code ret;
320ebfedea0SLionel Sambuc int32_t len;
321ebfedea0SLionel Sambuc krb5_storage *sp;
322ebfedea0SLionel Sambuc
323ebfedea0SLionel Sambuc
324ebfedea0SLionel Sambuc if (entry->keyblock.keyvalue.length != 8)
325ebfedea0SLionel Sambuc return 0;
326ebfedea0SLionel Sambuc switch(entry->keyblock.keytype) {
327ebfedea0SLionel Sambuc case ETYPE_DES_CBC_CRC:
328ebfedea0SLionel Sambuc case ETYPE_DES_CBC_MD4:
329ebfedea0SLionel Sambuc case ETYPE_DES_CBC_MD5:
330ebfedea0SLionel Sambuc break;
331ebfedea0SLionel Sambuc default:
332ebfedea0SLionel Sambuc return 0;
333ebfedea0SLionel Sambuc }
334ebfedea0SLionel Sambuc
335ebfedea0SLionel Sambuc fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
336ebfedea0SLionel Sambuc if (fd < 0) {
337ebfedea0SLionel Sambuc fd = open (d->filename,
338ebfedea0SLionel Sambuc O_RDWR | O_BINARY | O_CREAT | O_EXCL | O_CLOEXEC, 0600);
339ebfedea0SLionel Sambuc if (fd < 0) {
340ebfedea0SLionel Sambuc ret = errno;
341ebfedea0SLionel Sambuc krb5_set_error_message(context, ret,
342ebfedea0SLionel Sambuc N_("open keyfile(%s): %s", ""),
343ebfedea0SLionel Sambuc d->filename,
344ebfedea0SLionel Sambuc strerror(ret));
345ebfedea0SLionel Sambuc return ret;
346ebfedea0SLionel Sambuc }
347ebfedea0SLionel Sambuc created = 1;
348ebfedea0SLionel Sambuc }
349ebfedea0SLionel Sambuc
350ebfedea0SLionel Sambuc sp = krb5_storage_from_fd(fd);
351ebfedea0SLionel Sambuc if(sp == NULL) {
352ebfedea0SLionel Sambuc close(fd);
353ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM,
354ebfedea0SLionel Sambuc N_("malloc: out of memory", ""));
355ebfedea0SLionel Sambuc return ENOMEM;
356ebfedea0SLionel Sambuc }
357ebfedea0SLionel Sambuc if (created)
358ebfedea0SLionel Sambuc len = 0;
359ebfedea0SLionel Sambuc else {
360ebfedea0SLionel Sambuc if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
361ebfedea0SLionel Sambuc ret = errno;
362ebfedea0SLionel Sambuc krb5_storage_free(sp);
363ebfedea0SLionel Sambuc close(fd);
364ebfedea0SLionel Sambuc krb5_set_error_message(context, ret,
365ebfedea0SLionel Sambuc N_("seeking in keyfile: %s", ""),
366ebfedea0SLionel Sambuc strerror(ret));
367ebfedea0SLionel Sambuc return ret;
368ebfedea0SLionel Sambuc }
369ebfedea0SLionel Sambuc
370ebfedea0SLionel Sambuc ret = krb5_ret_int32(sp, &len);
371ebfedea0SLionel Sambuc if(ret) {
372ebfedea0SLionel Sambuc krb5_storage_free(sp);
373ebfedea0SLionel Sambuc close(fd);
374ebfedea0SLionel Sambuc return ret;
375ebfedea0SLionel Sambuc }
376ebfedea0SLionel Sambuc }
377ebfedea0SLionel Sambuc
378ebfedea0SLionel Sambuc /*
379ebfedea0SLionel Sambuc * Make sure we don't add the entry twice, assumes the DES
380ebfedea0SLionel Sambuc * encryption types are all the same key.
381ebfedea0SLionel Sambuc */
382ebfedea0SLionel Sambuc if (len > 0) {
383ebfedea0SLionel Sambuc int32_t kvno;
384ebfedea0SLionel Sambuc int i;
385ebfedea0SLionel Sambuc
386ebfedea0SLionel Sambuc for (i = 0; i < len; i++) {
387ebfedea0SLionel Sambuc ret = krb5_ret_int32(sp, &kvno);
388ebfedea0SLionel Sambuc if (ret) {
389ebfedea0SLionel Sambuc krb5_set_error_message (context, ret,
390ebfedea0SLionel Sambuc N_("Failed getting kvno from keyfile", ""));
391ebfedea0SLionel Sambuc goto out;
392ebfedea0SLionel Sambuc }
393ebfedea0SLionel Sambuc if(krb5_storage_seek(sp, 8, SEEK_CUR) < 0) {
394ebfedea0SLionel Sambuc ret = errno;
395ebfedea0SLionel Sambuc krb5_set_error_message (context, ret,
396ebfedea0SLionel Sambuc N_("Failed seeing in keyfile: %s", ""),
397ebfedea0SLionel Sambuc strerror(ret));
398ebfedea0SLionel Sambuc goto out;
399ebfedea0SLionel Sambuc }
400ebfedea0SLionel Sambuc if (kvno == entry->vno) {
401ebfedea0SLionel Sambuc ret = 0;
402ebfedea0SLionel Sambuc goto out;
403ebfedea0SLionel Sambuc }
404ebfedea0SLionel Sambuc }
405ebfedea0SLionel Sambuc }
406ebfedea0SLionel Sambuc
407ebfedea0SLionel Sambuc len++;
408ebfedea0SLionel Sambuc
409ebfedea0SLionel Sambuc if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
410ebfedea0SLionel Sambuc ret = errno;
411ebfedea0SLionel Sambuc krb5_set_error_message (context, ret,
412ebfedea0SLionel Sambuc N_("Failed seeing in keyfile: %s", ""),
413ebfedea0SLionel Sambuc strerror(ret));
414ebfedea0SLionel Sambuc goto out;
415ebfedea0SLionel Sambuc }
416ebfedea0SLionel Sambuc
417ebfedea0SLionel Sambuc ret = krb5_store_int32(sp, len);
418ebfedea0SLionel Sambuc if(ret) {
419ebfedea0SLionel Sambuc ret = errno;
420ebfedea0SLionel Sambuc krb5_set_error_message (context, ret,
421ebfedea0SLionel Sambuc N_("keytab keyfile failed new length", ""));
422ebfedea0SLionel Sambuc return ret;
423ebfedea0SLionel Sambuc }
424ebfedea0SLionel Sambuc
425ebfedea0SLionel Sambuc if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) {
426ebfedea0SLionel Sambuc ret = errno;
427ebfedea0SLionel Sambuc krb5_set_error_message (context, ret,
428ebfedea0SLionel Sambuc N_("seek to end: %s", ""), strerror(ret));
429ebfedea0SLionel Sambuc goto out;
430ebfedea0SLionel Sambuc }
431ebfedea0SLionel Sambuc
432ebfedea0SLionel Sambuc ret = krb5_store_int32(sp, entry->vno);
433ebfedea0SLionel Sambuc if(ret) {
434ebfedea0SLionel Sambuc krb5_set_error_message(context, ret,
435ebfedea0SLionel Sambuc N_("keytab keyfile failed store kvno", ""));
436ebfedea0SLionel Sambuc goto out;
437ebfedea0SLionel Sambuc }
438ebfedea0SLionel Sambuc ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data,
439ebfedea0SLionel Sambuc entry->keyblock.keyvalue.length);
440ebfedea0SLionel Sambuc if(ret != entry->keyblock.keyvalue.length) {
441ebfedea0SLionel Sambuc if (ret < 0)
442ebfedea0SLionel Sambuc ret = errno;
443ebfedea0SLionel Sambuc else
444ebfedea0SLionel Sambuc ret = ENOTTY;
445ebfedea0SLionel Sambuc krb5_set_error_message(context, ret,
446ebfedea0SLionel Sambuc N_("keytab keyfile failed to add key", ""));
447ebfedea0SLionel Sambuc goto out;
448ebfedea0SLionel Sambuc }
449ebfedea0SLionel Sambuc ret = 0;
450ebfedea0SLionel Sambuc out:
451ebfedea0SLionel Sambuc krb5_storage_free(sp);
452ebfedea0SLionel Sambuc close (fd);
453ebfedea0SLionel Sambuc return ret;
454ebfedea0SLionel Sambuc }
455ebfedea0SLionel Sambuc
456ebfedea0SLionel Sambuc const krb5_kt_ops krb5_akf_ops = {
457ebfedea0SLionel Sambuc "AFSKEYFILE",
458ebfedea0SLionel Sambuc akf_resolve,
459ebfedea0SLionel Sambuc akf_get_name,
460ebfedea0SLionel Sambuc akf_close,
461ebfedea0SLionel Sambuc NULL, /* destroy */
462ebfedea0SLionel Sambuc NULL, /* get */
463ebfedea0SLionel Sambuc akf_start_seq_get,
464ebfedea0SLionel Sambuc akf_next_entry,
465ebfedea0SLionel Sambuc akf_end_seq_get,
466ebfedea0SLionel Sambuc akf_add_entry,
467ebfedea0SLionel Sambuc NULL /* remove */
468ebfedea0SLionel Sambuc };
469ebfedea0SLionel Sambuc
470ebfedea0SLionel Sambuc #endif /* HEIMDAL_SMALLER */
471