xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/keytab_keyfile.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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