xref: /freebsd/crypto/heimdal/lib/krb5/keytab_keyfile.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "krb5_locl.h"
35b528cefcSMark Murray 
36*ae771770SStanislav Sedov #ifndef HEIMDAL_SMALLER
37b528cefcSMark Murray 
38b528cefcSMark Murray /* afs keyfile operations --------------------------------------- */
39b528cefcSMark Murray 
40b528cefcSMark Murray /*
41b528cefcSMark Murray  * Minimum tools to handle the AFS KeyFile.
42b528cefcSMark Murray  *
43b528cefcSMark Murray  * Format of the KeyFile is:
44b528cefcSMark Murray  * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys}
45b528cefcSMark Murray  *
46b528cefcSMark Murray  * It just adds to the end of the keyfile, deleting isn't implemented.
47b528cefcSMark Murray  * Use your favorite text/hex editor to delete keys.
48b528cefcSMark Murray  *
49b528cefcSMark Murray  */
50b528cefcSMark Murray 
51b528cefcSMark Murray #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell"
52b528cefcSMark Murray #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf"
53b528cefcSMark Murray 
54b528cefcSMark Murray struct akf_data {
55*ae771770SStanislav Sedov     uint32_t num_entries;
56b528cefcSMark Murray     char *filename;
57b528cefcSMark Murray     char *cell;
58b528cefcSMark Murray     char *realm;
59b528cefcSMark Murray };
60b528cefcSMark Murray 
61b528cefcSMark Murray /*
62b528cefcSMark Murray  * set `d->cell' and `d->realm'
63b528cefcSMark Murray  */
64b528cefcSMark Murray 
65b528cefcSMark Murray static int
get_cell_and_realm(krb5_context context,struct akf_data * d)66c19800e8SDoug Rabson get_cell_and_realm (krb5_context context, struct akf_data *d)
67b528cefcSMark Murray {
68b528cefcSMark Murray     FILE *f;
69b528cefcSMark Murray     char buf[BUFSIZ], *cp;
70adb0ddaeSAssar Westerlund     int ret;
71b528cefcSMark Murray 
72b528cefcSMark Murray     f = fopen (AFS_SERVERTHISCELL, "r");
73adb0ddaeSAssar Westerlund     if (f == NULL) {
74adb0ddaeSAssar Westerlund 	ret = errno;
75*ae771770SStanislav Sedov 	krb5_set_error_message (context, ret,
76*ae771770SStanislav Sedov 				N_("Open ThisCell %s: %s", ""),
77*ae771770SStanislav Sedov 				AFS_SERVERTHISCELL,
78adb0ddaeSAssar Westerlund 				strerror(ret));
79adb0ddaeSAssar Westerlund 	return ret;
80adb0ddaeSAssar Westerlund     }
81b528cefcSMark Murray     if (fgets (buf, sizeof(buf), f) == NULL) {
82b528cefcSMark Murray 	fclose (f);
83*ae771770SStanislav Sedov 	krb5_set_error_message (context, EINVAL,
84*ae771770SStanislav Sedov 				N_("No cell in ThisCell file %s", ""),
85*ae771770SStanislav Sedov 				AFS_SERVERTHISCELL);
86b528cefcSMark Murray 	return EINVAL;
87b528cefcSMark Murray     }
885bda878eSJacques Vidrine     buf[strcspn(buf, "\n")] = '\0';
89b528cefcSMark Murray     fclose(f);
90b528cefcSMark Murray 
91b528cefcSMark Murray     d->cell = strdup (buf);
92adb0ddaeSAssar Westerlund     if (d->cell == NULL) {
93*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
94*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
95adb0ddaeSAssar Westerlund 	return ENOMEM;
96adb0ddaeSAssar Westerlund     }
97b528cefcSMark Murray 
98b528cefcSMark Murray     f = fopen (AFS_SERVERMAGICKRBCONF, "r");
99b528cefcSMark Murray     if (f != NULL) {
100b528cefcSMark Murray 	if (fgets (buf, sizeof(buf), f) == NULL) {
101c19800e8SDoug Rabson 	    free (d->cell);
102c19800e8SDoug Rabson 	    d->cell = NULL;
103b528cefcSMark Murray 	    fclose (f);
104*ae771770SStanislav Sedov 	    krb5_set_error_message (context, EINVAL,
105*ae771770SStanislav Sedov 				    N_("No realm in ThisCell file %s", ""),
106adb0ddaeSAssar Westerlund 				    AFS_SERVERMAGICKRBCONF);
107b528cefcSMark Murray 	    return EINVAL;
108b528cefcSMark Murray 	}
1095bda878eSJacques Vidrine 	buf[strcspn(buf, "\n")] = '\0';
110b528cefcSMark Murray 	fclose(f);
111b528cefcSMark Murray     }
112b528cefcSMark Murray     /* uppercase */
113b528cefcSMark Murray     for (cp = buf; *cp != '\0'; cp++)
114c19800e8SDoug Rabson 	*cp = toupper((unsigned char)*cp);
115b528cefcSMark Murray 
116b528cefcSMark Murray     d->realm = strdup (buf);
117b528cefcSMark Murray     if (d->realm == NULL) {
118b528cefcSMark Murray 	free (d->cell);
119c19800e8SDoug Rabson 	d->cell = NULL;
120*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
121*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
122adb0ddaeSAssar Westerlund 	return ENOMEM;
123b528cefcSMark Murray     }
124b528cefcSMark Murray     return 0;
125b528cefcSMark Murray }
126b528cefcSMark Murray 
127b528cefcSMark Murray /*
128b528cefcSMark Murray  * init and get filename
129b528cefcSMark Murray  */
130b528cefcSMark Murray 
131*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_resolve(krb5_context context,const char * name,krb5_keytab id)132b528cefcSMark Murray akf_resolve(krb5_context context, const char *name, krb5_keytab id)
133b528cefcSMark Murray {
134b528cefcSMark Murray     int ret;
135b528cefcSMark Murray     struct akf_data *d = malloc(sizeof (struct akf_data));
136b528cefcSMark Murray 
137adb0ddaeSAssar Westerlund     if (d == NULL) {
138*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
139*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
140adb0ddaeSAssar Westerlund 	return ENOMEM;
141adb0ddaeSAssar Westerlund     }
142b528cefcSMark Murray 
143b528cefcSMark Murray     d->num_entries = 0;
144adb0ddaeSAssar Westerlund     ret = get_cell_and_realm (context, d);
145b528cefcSMark Murray     if (ret) {
146b528cefcSMark Murray 	free (d);
147b528cefcSMark Murray 	return ret;
148b528cefcSMark Murray     }
149b528cefcSMark Murray     d->filename = strdup (name);
150b528cefcSMark Murray     if (d->filename == NULL) {
151b528cefcSMark Murray 	free (d->cell);
152b528cefcSMark Murray 	free (d->realm);
153b528cefcSMark Murray 	free (d);
154*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
155*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
156b528cefcSMark Murray 	return ENOMEM;
157b528cefcSMark Murray     }
158b528cefcSMark Murray     id->data = d;
159b528cefcSMark Murray 
160b528cefcSMark Murray     return 0;
161b528cefcSMark Murray }
162b528cefcSMark Murray 
163b528cefcSMark Murray /*
164b528cefcSMark Murray  * cleanup
165b528cefcSMark Murray  */
166b528cefcSMark Murray 
167*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_close(krb5_context context,krb5_keytab id)168b528cefcSMark Murray akf_close(krb5_context context, krb5_keytab id)
169b528cefcSMark Murray {
170b528cefcSMark Murray     struct akf_data *d = id->data;
171b528cefcSMark Murray 
172b528cefcSMark Murray     free (d->filename);
173b528cefcSMark Murray     free (d->cell);
174b528cefcSMark Murray     free (d);
175b528cefcSMark Murray     return 0;
176b528cefcSMark Murray }
177b528cefcSMark Murray 
178b528cefcSMark Murray /*
179b528cefcSMark Murray  * Return filename
180b528cefcSMark Murray  */
181b528cefcSMark Murray 
182*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_get_name(krb5_context context,krb5_keytab id,char * name,size_t name_sz)183b528cefcSMark Murray akf_get_name(krb5_context context,
184b528cefcSMark Murray 	     krb5_keytab id,
185b528cefcSMark Murray 	     char *name,
186b528cefcSMark Murray 	     size_t name_sz)
187b528cefcSMark Murray {
188b528cefcSMark Murray     struct akf_data *d = id->data;
189b528cefcSMark Murray 
190b528cefcSMark Murray     strlcpy (name, d->filename, name_sz);
191b528cefcSMark Murray     return 0;
192b528cefcSMark Murray }
193b528cefcSMark Murray 
194b528cefcSMark Murray /*
195b528cefcSMark Murray  * Init
196b528cefcSMark Murray  */
197b528cefcSMark Murray 
198*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)199b528cefcSMark Murray akf_start_seq_get(krb5_context context,
200b528cefcSMark Murray 		  krb5_keytab id,
201b528cefcSMark Murray 		  krb5_kt_cursor *c)
202b528cefcSMark Murray {
203b528cefcSMark Murray     int32_t ret;
204b528cefcSMark Murray     struct akf_data *d = id->data;
205b528cefcSMark Murray 
206*ae771770SStanislav Sedov     c->fd = open (d->filename, O_RDONLY | O_BINARY | O_CLOEXEC, 0600);
207adb0ddaeSAssar Westerlund     if (c->fd < 0) {
208adb0ddaeSAssar Westerlund 	ret = errno;
209*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
210*ae771770SStanislav Sedov 			       N_("keytab afs keyfile open %s failed: %s", ""),
211*ae771770SStanislav Sedov 			       d->filename, strerror(ret));
212adb0ddaeSAssar Westerlund 	return ret;
213adb0ddaeSAssar Westerlund     }
214b528cefcSMark Murray 
215*ae771770SStanislav Sedov     c->data = NULL;
216b528cefcSMark Murray     c->sp = krb5_storage_from_fd(c->fd);
217*ae771770SStanislav Sedov     if (c->sp == NULL) {
218*ae771770SStanislav Sedov 	close(c->fd);
219*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
220*ae771770SStanislav Sedov 	return KRB5_KT_NOTFOUND;
221*ae771770SStanislav Sedov     }
222*ae771770SStanislav Sedov     krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
223*ae771770SStanislav Sedov 
224*ae771770SStanislav Sedov     ret = krb5_ret_uint32(c->sp, &d->num_entries);
225*ae771770SStanislav Sedov     if(ret || d->num_entries > INT_MAX / 8) {
226b528cefcSMark Murray 	krb5_storage_free(c->sp);
227b528cefcSMark Murray 	close(c->fd);
228*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
2298373020dSJacques Vidrine 	if(ret == KRB5_KT_END)
230adb0ddaeSAssar Westerlund 	    return KRB5_KT_NOTFOUND;
231b528cefcSMark Murray 	return ret;
232b528cefcSMark Murray     }
233b528cefcSMark Murray 
234b528cefcSMark Murray     return 0;
235b528cefcSMark Murray }
236b528cefcSMark Murray 
237*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)238b528cefcSMark Murray akf_next_entry(krb5_context context,
239b528cefcSMark Murray 	       krb5_keytab id,
240b528cefcSMark Murray 	       krb5_keytab_entry *entry,
241b528cefcSMark Murray 	       krb5_kt_cursor *cursor)
242b528cefcSMark Murray {
243b528cefcSMark Murray     struct akf_data *d = id->data;
244b528cefcSMark Murray     int32_t kvno;
245b528cefcSMark Murray     off_t pos;
246b528cefcSMark Murray     int ret;
247b528cefcSMark Murray 
2488373020dSJacques Vidrine     pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
249b528cefcSMark Murray 
250b528cefcSMark Murray     if ((pos - 4) / (4 + 8) >= d->num_entries)
251b528cefcSMark Murray 	return KRB5_KT_END;
252b528cefcSMark Murray 
253b528cefcSMark Murray     ret = krb5_make_principal (context, &entry->principal,
254b528cefcSMark Murray 			       d->realm, "afs", d->cell, NULL);
255b528cefcSMark Murray     if (ret)
256b528cefcSMark Murray 	goto out;
257b528cefcSMark Murray 
258b528cefcSMark Murray     ret = krb5_ret_int32(cursor->sp, &kvno);
259b528cefcSMark Murray     if (ret) {
260b528cefcSMark Murray 	krb5_free_principal (context, entry->principal);
261b528cefcSMark Murray 	goto out;
262b528cefcSMark Murray     }
263b528cefcSMark Murray 
2645e9cd1aeSAssar Westerlund     entry->vno = kvno;
265b528cefcSMark Murray 
266*ae771770SStanislav Sedov     if (cursor->data)
267b528cefcSMark Murray 	entry->keyblock.keytype         = ETYPE_DES_CBC_MD5;
268*ae771770SStanislav Sedov     else
269*ae771770SStanislav Sedov 	entry->keyblock.keytype         = ETYPE_DES_CBC_CRC;
270b528cefcSMark Murray     entry->keyblock.keyvalue.length = 8;
271b528cefcSMark Murray     entry->keyblock.keyvalue.data   = malloc (8);
272b528cefcSMark Murray     if (entry->keyblock.keyvalue.data == NULL) {
273b528cefcSMark Murray 	krb5_free_principal (context, entry->principal);
274*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
275*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
276b528cefcSMark Murray 	ret = ENOMEM;
277b528cefcSMark Murray 	goto out;
278b528cefcSMark Murray     }
279b528cefcSMark Murray 
2808373020dSJacques Vidrine     ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8);
281b528cefcSMark Murray     if(ret != 8)
282b528cefcSMark Murray 	ret = (ret < 0) ? errno : KRB5_KT_END;
2835e9cd1aeSAssar Westerlund     else
2845e9cd1aeSAssar Westerlund 	ret = 0;
285b528cefcSMark Murray 
286b528cefcSMark Murray     entry->timestamp = time(NULL);
287*ae771770SStanislav Sedov     entry->flags = 0;
288*ae771770SStanislav Sedov     entry->aliases = NULL;
289b528cefcSMark Murray 
290b528cefcSMark Murray  out:
291*ae771770SStanislav Sedov     if (cursor->data) {
2928373020dSJacques Vidrine 	krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET);
293*ae771770SStanislav Sedov 	cursor->data = NULL;
294*ae771770SStanislav Sedov     } else
295*ae771770SStanislav Sedov 	cursor->data = cursor;
296b528cefcSMark Murray     return ret;
297b528cefcSMark Murray }
298b528cefcSMark Murray 
299*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)300b528cefcSMark Murray akf_end_seq_get(krb5_context context,
301b528cefcSMark Murray 		krb5_keytab id,
302b528cefcSMark Murray 		krb5_kt_cursor *cursor)
303b528cefcSMark Murray {
304b528cefcSMark Murray     krb5_storage_free(cursor->sp);
305b528cefcSMark Murray     close(cursor->fd);
306*ae771770SStanislav Sedov     cursor->data = NULL;
307b528cefcSMark Murray     return 0;
308b528cefcSMark Murray }
309b528cefcSMark Murray 
310*ae771770SStanislav Sedov static krb5_error_code KRB5_CALLCONV
akf_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)311b528cefcSMark Murray akf_add_entry(krb5_context context,
312b528cefcSMark Murray 	      krb5_keytab id,
313b528cefcSMark Murray 	      krb5_keytab_entry *entry)
314b528cefcSMark Murray {
315b528cefcSMark Murray     struct akf_data *d = id->data;
316b528cefcSMark Murray     int fd, created = 0;
3175e9cd1aeSAssar Westerlund     krb5_error_code ret;
3184137ff4cSJacques Vidrine     int32_t len;
3194137ff4cSJacques Vidrine     krb5_storage *sp;
3204137ff4cSJacques Vidrine 
3214137ff4cSJacques Vidrine 
322c19800e8SDoug Rabson     if (entry->keyblock.keyvalue.length != 8)
3234137ff4cSJacques Vidrine 	return 0;
324c19800e8SDoug Rabson     switch(entry->keyblock.keytype) {
325c19800e8SDoug Rabson     case ETYPE_DES_CBC_CRC:
326c19800e8SDoug Rabson     case ETYPE_DES_CBC_MD4:
327c19800e8SDoug Rabson     case ETYPE_DES_CBC_MD5:
328c19800e8SDoug Rabson 	break;
329c19800e8SDoug Rabson     default:
330c19800e8SDoug Rabson 	return 0;
331c19800e8SDoug Rabson     }
332b528cefcSMark Murray 
333*ae771770SStanislav Sedov     fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
334b528cefcSMark Murray     if (fd < 0) {
335b528cefcSMark Murray 	fd = open (d->filename,
336*ae771770SStanislav Sedov 		   O_RDWR | O_BINARY | O_CREAT | O_EXCL | O_CLOEXEC, 0600);
337adb0ddaeSAssar Westerlund 	if (fd < 0) {
338adb0ddaeSAssar Westerlund 	    ret = errno;
339*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
340*ae771770SStanislav Sedov 				   N_("open keyfile(%s): %s", ""),
341*ae771770SStanislav Sedov 				   d->filename,
342adb0ddaeSAssar Westerlund 				   strerror(ret));
343adb0ddaeSAssar Westerlund 	    return ret;
344adb0ddaeSAssar Westerlund 	}
345b528cefcSMark Murray 	created = 1;
346b528cefcSMark Murray     }
347b528cefcSMark Murray 
3485e9cd1aeSAssar Westerlund     sp = krb5_storage_from_fd(fd);
3495e9cd1aeSAssar Westerlund     if(sp == NULL) {
3505e9cd1aeSAssar Westerlund 	close(fd);
351*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
352*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
3535e9cd1aeSAssar Westerlund 	return ENOMEM;
3545e9cd1aeSAssar Westerlund     }
3555e9cd1aeSAssar Westerlund     if (created)
3565e9cd1aeSAssar Westerlund 	len = 0;
3575e9cd1aeSAssar Westerlund     else {
3588373020dSJacques Vidrine 	if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
359adb0ddaeSAssar Westerlund 	    ret = errno;
3605e9cd1aeSAssar Westerlund 	    krb5_storage_free(sp);
3615e9cd1aeSAssar Westerlund 	    close(fd);
362*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
363*ae771770SStanislav Sedov 				   N_("seeking in keyfile: %s", ""),
364*ae771770SStanislav Sedov 				   strerror(ret));
365adb0ddaeSAssar Westerlund 	    return ret;
366b528cefcSMark Murray 	}
367b528cefcSMark Murray 
3685e9cd1aeSAssar Westerlund 	ret = krb5_ret_int32(sp, &len);
3695e9cd1aeSAssar Westerlund 	if(ret) {
3705e9cd1aeSAssar Westerlund 	    krb5_storage_free(sp);
3715e9cd1aeSAssar Westerlund 	    close(fd);
3725e9cd1aeSAssar Westerlund 	    return ret;
3735e9cd1aeSAssar Westerlund 	}
3745e9cd1aeSAssar Westerlund     }
375c19800e8SDoug Rabson 
376c19800e8SDoug Rabson     /*
377c19800e8SDoug Rabson      * Make sure we don't add the entry twice, assumes the DES
378c19800e8SDoug Rabson      * encryption types are all the same key.
379c19800e8SDoug Rabson      */
380c19800e8SDoug Rabson     if (len > 0) {
381c19800e8SDoug Rabson 	int32_t kvno;
382c19800e8SDoug Rabson 	int i;
383c19800e8SDoug Rabson 
384c19800e8SDoug Rabson 	for (i = 0; i < len; i++) {
385c19800e8SDoug Rabson 	    ret = krb5_ret_int32(sp, &kvno);
386c19800e8SDoug Rabson 	    if (ret) {
387*ae771770SStanislav Sedov 		krb5_set_error_message (context, ret,
388*ae771770SStanislav Sedov 					N_("Failed getting kvno from keyfile", ""));
389c19800e8SDoug Rabson 		goto out;
390c19800e8SDoug Rabson 	    }
391c19800e8SDoug Rabson 	    if(krb5_storage_seek(sp, 8, SEEK_CUR) < 0) {
392*ae771770SStanislav Sedov 		ret = errno;
393*ae771770SStanislav Sedov 		krb5_set_error_message (context, ret,
394*ae771770SStanislav Sedov 					N_("Failed seeing in keyfile: %s", ""),
395*ae771770SStanislav Sedov 					strerror(ret));
396c19800e8SDoug Rabson 		goto out;
397c19800e8SDoug Rabson 	    }
398c19800e8SDoug Rabson 	    if (kvno == entry->vno) {
399c19800e8SDoug Rabson 		ret = 0;
400c19800e8SDoug Rabson 		goto out;
401c19800e8SDoug Rabson 	    }
402c19800e8SDoug Rabson 	}
403c19800e8SDoug Rabson     }
404c19800e8SDoug Rabson 
4055e9cd1aeSAssar Westerlund     len++;
4065e9cd1aeSAssar Westerlund 
4078373020dSJacques Vidrine     if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
408adb0ddaeSAssar Westerlund 	ret = errno;
409*ae771770SStanislav Sedov 	krb5_set_error_message (context, ret,
410*ae771770SStanislav Sedov 				N_("Failed seeing in keyfile: %s", ""),
411*ae771770SStanislav Sedov 				strerror(ret));
412c19800e8SDoug Rabson 	goto out;
4135e9cd1aeSAssar Westerlund     }
414b528cefcSMark Murray 
4155e9cd1aeSAssar Westerlund     ret = krb5_store_int32(sp, len);
4165e9cd1aeSAssar Westerlund     if(ret) {
417*ae771770SStanislav Sedov 	ret = errno;
418*ae771770SStanislav Sedov 	krb5_set_error_message (context, ret,
419*ae771770SStanislav Sedov 				N_("keytab keyfile failed new length", ""));
4205e9cd1aeSAssar Westerlund 	return ret;
4215e9cd1aeSAssar Westerlund     }
4225e9cd1aeSAssar Westerlund 
4238373020dSJacques Vidrine     if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) {
424adb0ddaeSAssar Westerlund 	ret = errno;
425*ae771770SStanislav Sedov 	krb5_set_error_message (context, ret,
426*ae771770SStanislav Sedov 				N_("seek to end: %s", ""), strerror(ret));
427c19800e8SDoug Rabson 	goto out;
4285e9cd1aeSAssar Westerlund     }
429b528cefcSMark Murray 
4305e9cd1aeSAssar Westerlund     ret = krb5_store_int32(sp, entry->vno);
4315e9cd1aeSAssar Westerlund     if(ret) {
432*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
433*ae771770SStanislav Sedov 			       N_("keytab keyfile failed store kvno", ""));
434c19800e8SDoug Rabson 	goto out;
4355e9cd1aeSAssar Westerlund     }
4368373020dSJacques Vidrine     ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data,
4375e9cd1aeSAssar Westerlund 			     entry->keyblock.keyvalue.length);
4385e9cd1aeSAssar Westerlund     if(ret != entry->keyblock.keyvalue.length) {
4395e9cd1aeSAssar Westerlund 	if (ret < 0)
440c19800e8SDoug Rabson 	    ret = errno;
441c19800e8SDoug Rabson 	else
442c19800e8SDoug Rabson 	    ret = ENOTTY;
443*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret,
444*ae771770SStanislav Sedov 			       N_("keytab keyfile failed to add key", ""));
445c19800e8SDoug Rabson 	goto out;
4465e9cd1aeSAssar Westerlund     }
447c19800e8SDoug Rabson     ret = 0;
448c19800e8SDoug Rabson out:
4495e9cd1aeSAssar Westerlund     krb5_storage_free(sp);
450b528cefcSMark Murray     close (fd);
451c19800e8SDoug Rabson     return ret;
452b528cefcSMark Murray }
453b528cefcSMark Murray 
454b528cefcSMark Murray const krb5_kt_ops krb5_akf_ops = {
455b528cefcSMark Murray     "AFSKEYFILE",
456b528cefcSMark Murray     akf_resolve,
457b528cefcSMark Murray     akf_get_name,
458b528cefcSMark Murray     akf_close,
459*ae771770SStanislav Sedov     NULL, /* destroy */
460b528cefcSMark Murray     NULL, /* get */
461b528cefcSMark Murray     akf_start_seq_get,
462b528cefcSMark Murray     akf_next_entry,
463b528cefcSMark Murray     akf_end_seq_get,
464b528cefcSMark Murray     akf_add_entry,
465b528cefcSMark Murray     NULL /* remove */
466b528cefcSMark Murray };
467*ae771770SStanislav Sedov 
468*ae771770SStanislav Sedov #endif /* HEIMDAL_SMALLER */
469