xref: /freebsd/crypto/heimdal/lib/krb5/keytab_keyfile.c (revision b528cefc6b8f9670b31a865051741d946cb37085)
1b528cefcSMark Murray /*
2b528cefcSMark Murray  * Copyright (c) 1997 - 2000 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 
36b528cefcSMark Murray RCSID("$Id: keytab_keyfile.c,v 1.7 2000/01/02 04:00:22 assar Exp $");
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 {
55b528cefcSMark Murray     int 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
66b528cefcSMark Murray get_cell_and_realm (struct akf_data *d)
67b528cefcSMark Murray {
68b528cefcSMark Murray     FILE *f;
69b528cefcSMark Murray     char buf[BUFSIZ], *cp;
70b528cefcSMark Murray 
71b528cefcSMark Murray     f = fopen (AFS_SERVERTHISCELL, "r");
72b528cefcSMark Murray     if (f == NULL)
73b528cefcSMark Murray 	return errno;
74b528cefcSMark Murray     if (fgets (buf, sizeof(buf), f) == NULL) {
75b528cefcSMark Murray 	fclose (f);
76b528cefcSMark Murray 	return EINVAL;
77b528cefcSMark Murray     }
78b528cefcSMark Murray     if (buf[strlen(buf) - 1] == '\n')
79b528cefcSMark Murray 	buf[strlen(buf) - 1] = '\0';
80b528cefcSMark Murray     fclose(f);
81b528cefcSMark Murray 
82b528cefcSMark Murray     d->cell = strdup (buf);
83b528cefcSMark Murray     if (d->cell == NULL)
84b528cefcSMark Murray 	return errno;
85b528cefcSMark Murray 
86b528cefcSMark Murray     f = fopen (AFS_SERVERMAGICKRBCONF, "r");
87b528cefcSMark Murray     if (f != NULL) {
88b528cefcSMark Murray 	if (fgets (buf, sizeof(buf), f) == NULL) {
89b528cefcSMark Murray 	    fclose (f);
90b528cefcSMark Murray 	    return EINVAL;
91b528cefcSMark Murray 	}
92b528cefcSMark Murray 	if (buf[strlen(buf)-1] == '\n')
93b528cefcSMark Murray 	    buf[strlen(buf)-1] = '\0';
94b528cefcSMark Murray 	fclose(f);
95b528cefcSMark Murray     }
96b528cefcSMark Murray     /* uppercase */
97b528cefcSMark Murray     for (cp = buf; *cp != '\0'; cp++)
98b528cefcSMark Murray 	*cp = toupper(*cp);
99b528cefcSMark Murray 
100b528cefcSMark Murray     d->realm = strdup (buf);
101b528cefcSMark Murray     if (d->realm == NULL) {
102b528cefcSMark Murray 	free (d->cell);
103b528cefcSMark Murray 	return errno;
104b528cefcSMark Murray     }
105b528cefcSMark Murray     return 0;
106b528cefcSMark Murray }
107b528cefcSMark Murray 
108b528cefcSMark Murray /*
109b528cefcSMark Murray  * init and get filename
110b528cefcSMark Murray  */
111b528cefcSMark Murray 
112b528cefcSMark Murray static krb5_error_code
113b528cefcSMark Murray akf_resolve(krb5_context context, const char *name, krb5_keytab id)
114b528cefcSMark Murray {
115b528cefcSMark Murray     int ret;
116b528cefcSMark Murray     struct akf_data *d = malloc(sizeof (struct akf_data));
117b528cefcSMark Murray 
118b528cefcSMark Murray     if (d == NULL)
119b528cefcSMark Murray 	return errno;
120b528cefcSMark Murray 
121b528cefcSMark Murray     d->num_entries = 0;
122b528cefcSMark Murray     ret = get_cell_and_realm (d);
123b528cefcSMark Murray     if (ret) {
124b528cefcSMark Murray 	free (d);
125b528cefcSMark Murray 	return ret;
126b528cefcSMark Murray     }
127b528cefcSMark Murray     d->filename = strdup (name);
128b528cefcSMark Murray     if (d->filename == NULL) {
129b528cefcSMark Murray 	free (d->cell);
130b528cefcSMark Murray 	free (d->realm);
131b528cefcSMark Murray 	free (d);
132b528cefcSMark Murray 	return ENOMEM;
133b528cefcSMark Murray     }
134b528cefcSMark Murray     id->data = d;
135b528cefcSMark Murray 
136b528cefcSMark Murray     return 0;
137b528cefcSMark Murray }
138b528cefcSMark Murray 
139b528cefcSMark Murray /*
140b528cefcSMark Murray  * cleanup
141b528cefcSMark Murray  */
142b528cefcSMark Murray 
143b528cefcSMark Murray static krb5_error_code
144b528cefcSMark Murray akf_close(krb5_context context, krb5_keytab id)
145b528cefcSMark Murray {
146b528cefcSMark Murray     struct akf_data *d = id->data;
147b528cefcSMark Murray 
148b528cefcSMark Murray     free (d->filename);
149b528cefcSMark Murray     free (d->cell);
150b528cefcSMark Murray     free (d);
151b528cefcSMark Murray     return 0;
152b528cefcSMark Murray }
153b528cefcSMark Murray 
154b528cefcSMark Murray /*
155b528cefcSMark Murray  * Return filename
156b528cefcSMark Murray  */
157b528cefcSMark Murray 
158b528cefcSMark Murray static krb5_error_code
159b528cefcSMark Murray akf_get_name(krb5_context context,
160b528cefcSMark Murray 	     krb5_keytab id,
161b528cefcSMark Murray 	     char *name,
162b528cefcSMark Murray 	     size_t name_sz)
163b528cefcSMark Murray {
164b528cefcSMark Murray     struct akf_data *d = id->data;
165b528cefcSMark Murray 
166b528cefcSMark Murray     strlcpy (name, d->filename, name_sz);
167b528cefcSMark Murray     return 0;
168b528cefcSMark Murray }
169b528cefcSMark Murray 
170b528cefcSMark Murray /*
171b528cefcSMark Murray  * Init
172b528cefcSMark Murray  */
173b528cefcSMark Murray 
174b528cefcSMark Murray static krb5_error_code
175b528cefcSMark Murray akf_start_seq_get(krb5_context context,
176b528cefcSMark Murray 		  krb5_keytab id,
177b528cefcSMark Murray 		  krb5_kt_cursor *c)
178b528cefcSMark Murray {
179b528cefcSMark Murray     int32_t ret;
180b528cefcSMark Murray     struct akf_data *d = id->data;
181b528cefcSMark Murray 
182b528cefcSMark Murray     c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600);
183b528cefcSMark Murray     if (c->fd < 0)
184b528cefcSMark Murray 	return errno;
185b528cefcSMark Murray 
186b528cefcSMark Murray     c->sp = krb5_storage_from_fd(c->fd);
187b528cefcSMark Murray     ret = krb5_ret_int32(c->sp, &d->num_entries);
188b528cefcSMark Murray     if(ret) {
189b528cefcSMark Murray 	krb5_storage_free(c->sp);
190b528cefcSMark Murray 	close(c->fd);
191b528cefcSMark Murray 	return ret;
192b528cefcSMark Murray     }
193b528cefcSMark Murray 
194b528cefcSMark Murray     return 0;
195b528cefcSMark Murray }
196b528cefcSMark Murray 
197b528cefcSMark Murray static krb5_error_code
198b528cefcSMark Murray akf_next_entry(krb5_context context,
199b528cefcSMark Murray 	       krb5_keytab id,
200b528cefcSMark Murray 	       krb5_keytab_entry *entry,
201b528cefcSMark Murray 	       krb5_kt_cursor *cursor)
202b528cefcSMark Murray {
203b528cefcSMark Murray     struct akf_data *d = id->data;
204b528cefcSMark Murray     int32_t kvno;
205b528cefcSMark Murray     off_t pos;
206b528cefcSMark Murray     int ret;
207b528cefcSMark Murray 
208b528cefcSMark Murray     pos = cursor->sp->seek(cursor->sp, 0, SEEK_CUR);
209b528cefcSMark Murray 
210b528cefcSMark Murray     if ((pos - 4) / (4 + 8) >= d->num_entries)
211b528cefcSMark Murray 	return KRB5_KT_END;
212b528cefcSMark Murray 
213b528cefcSMark Murray     ret = krb5_make_principal (context, &entry->principal,
214b528cefcSMark Murray 			       d->realm, "afs", d->cell, NULL);
215b528cefcSMark Murray     if (ret)
216b528cefcSMark Murray 	goto out;
217b528cefcSMark Murray 
218b528cefcSMark Murray     ret = krb5_ret_int32(cursor->sp, &kvno);
219b528cefcSMark Murray     if (ret) {
220b528cefcSMark Murray 	krb5_free_principal (context, entry->principal);
221b528cefcSMark Murray 	goto out;
222b528cefcSMark Murray     }
223b528cefcSMark Murray 
224b528cefcSMark Murray     entry->vno = (int8_t) kvno;
225b528cefcSMark Murray 
226b528cefcSMark Murray     entry->keyblock.keytype         = ETYPE_DES_CBC_MD5;
227b528cefcSMark Murray     entry->keyblock.keyvalue.length = 8;
228b528cefcSMark Murray     entry->keyblock.keyvalue.data   = malloc (8);
229b528cefcSMark Murray     if (entry->keyblock.keyvalue.data == NULL) {
230b528cefcSMark Murray 	krb5_free_principal (context, entry->principal);
231b528cefcSMark Murray 	ret = ENOMEM;
232b528cefcSMark Murray 	goto out;
233b528cefcSMark Murray     }
234b528cefcSMark Murray 
235b528cefcSMark Murray     ret = cursor->sp->fetch(cursor->sp, entry->keyblock.keyvalue.data, 8);
236b528cefcSMark Murray     if(ret != 8)
237b528cefcSMark Murray 	ret = (ret < 0) ? errno : KRB5_KT_END;
238b528cefcSMark Murray 
239b528cefcSMark Murray     entry->timestamp = time(NULL);
240b528cefcSMark Murray 
241b528cefcSMark Murray  out:
242b528cefcSMark Murray     cursor->sp->seek(cursor->sp, pos + 4 + 8, SEEK_SET);
243b528cefcSMark Murray     return ret;
244b528cefcSMark Murray }
245b528cefcSMark Murray 
246b528cefcSMark Murray static krb5_error_code
247b528cefcSMark Murray akf_end_seq_get(krb5_context context,
248b528cefcSMark Murray 		krb5_keytab id,
249b528cefcSMark Murray 		krb5_kt_cursor *cursor)
250b528cefcSMark Murray {
251b528cefcSMark Murray     krb5_storage_free(cursor->sp);
252b528cefcSMark Murray     close(cursor->fd);
253b528cefcSMark Murray     return 0;
254b528cefcSMark Murray }
255b528cefcSMark Murray 
256b528cefcSMark Murray static krb5_error_code
257b528cefcSMark Murray akf_add_entry(krb5_context context,
258b528cefcSMark Murray 	      krb5_keytab id,
259b528cefcSMark Murray 	      krb5_keytab_entry *entry)
260b528cefcSMark Murray {
261b528cefcSMark Murray     struct akf_data *d = id->data;
262b528cefcSMark Murray     int fd, created = 0;
263b528cefcSMark Murray     int32_t kvno;
264b528cefcSMark Murray 
265b528cefcSMark Murray     fd = open (d->filename, O_RDWR | O_BINARY);
266b528cefcSMark Murray     if (fd < 0) {
267b528cefcSMark Murray 	fd = open (d->filename,
268b528cefcSMark Murray 		   O_RDWR | O_BINARY | O_CREAT, 0600);
269b528cefcSMark Murray 	if (fd < 0)
270b528cefcSMark Murray 	    return errno;
271b528cefcSMark Murray 	created = 1;
272b528cefcSMark Murray     }
273b528cefcSMark Murray 
274b528cefcSMark Murray     if (entry->keyblock.keyvalue.length == 8
275b528cefcSMark Murray 	&& entry->keyblock.keytype == ETYPE_DES_CBC_MD5) {
276b528cefcSMark Murray 
277b528cefcSMark Murray 	int32_t len = 0;
278b528cefcSMark Murray 
279b528cefcSMark Murray 	if (!created) {
280b528cefcSMark Murray 	    if (lseek (fd, 0, SEEK_SET))
281b528cefcSMark Murray 		return errno;
282b528cefcSMark Murray 
283b528cefcSMark Murray 	    if (read (fd, &len, sizeof(len)) != sizeof(len))
284b528cefcSMark Murray 		return errno;
285b528cefcSMark Murray 	}
286b528cefcSMark Murray 	len += 1;
287b528cefcSMark Murray 
288b528cefcSMark Murray 	if (lseek (fd, 0, SEEK_SET))
289b528cefcSMark Murray 	    return errno;
290b528cefcSMark Murray 
291b528cefcSMark Murray 	if (write (fd, &len, sizeof(len)) != sizeof(len))
292b528cefcSMark Murray 	    return errno;
293b528cefcSMark Murray 
294b528cefcSMark Murray 	if (lseek (fd, 4 + (len-1) * (8+4), SEEK_SET))
295b528cefcSMark Murray 	    return errno;
296b528cefcSMark Murray 
297b528cefcSMark Murray 	kvno = entry->vno;
298b528cefcSMark Murray 	write(fd, &kvno, sizeof(kvno));
299b528cefcSMark Murray 	write(fd, entry->keyblock.keyvalue.data, 8);
300b528cefcSMark Murray     }
301b528cefcSMark Murray     close (fd);
302b528cefcSMark Murray     return 0;
303b528cefcSMark Murray }
304b528cefcSMark Murray 
305b528cefcSMark Murray const krb5_kt_ops krb5_akf_ops = {
306b528cefcSMark Murray     "AFSKEYFILE",
307b528cefcSMark Murray     akf_resolve,
308b528cefcSMark Murray     akf_get_name,
309b528cefcSMark Murray     akf_close,
310b528cefcSMark Murray     NULL, /* get */
311b528cefcSMark Murray     akf_start_seq_get,
312b528cefcSMark Murray     akf_next_entry,
313b528cefcSMark Murray     akf_end_seq_get,
314b528cefcSMark Murray     akf_add_entry,
315b528cefcSMark Murray     NULL /* remove */
316b528cefcSMark Murray };
317