xref: /freebsd/crypto/heimdal/lib/krb5/keytab_keyfile.c (revision 5f1c68f7489c12bce03cdbe6af4faa34f7031683)
1 /*
2  * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 
36 RCSID("$Id: keytab_keyfile.c,v 1.7 2000/01/02 04:00:22 assar Exp $");
37 
38 /* afs keyfile operations --------------------------------------- */
39 
40 /*
41  * Minimum tools to handle the AFS KeyFile.
42  *
43  * Format of the KeyFile is:
44  * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys}
45  *
46  * It just adds to the end of the keyfile, deleting isn't implemented.
47  * Use your favorite text/hex editor to delete keys.
48  *
49  */
50 
51 #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell"
52 #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf"
53 
54 struct akf_data {
55     int num_entries;
56     char *filename;
57     char *cell;
58     char *realm;
59 };
60 
61 /*
62  * set `d->cell' and `d->realm'
63  */
64 
65 static int
66 get_cell_and_realm (struct akf_data *d)
67 {
68     FILE *f;
69     char buf[BUFSIZ], *cp;
70 
71     f = fopen (AFS_SERVERTHISCELL, "r");
72     if (f == NULL)
73 	return errno;
74     if (fgets (buf, sizeof(buf), f) == NULL) {
75 	fclose (f);
76 	return EINVAL;
77     }
78     if (buf[strlen(buf) - 1] == '\n')
79 	buf[strlen(buf) - 1] = '\0';
80     fclose(f);
81 
82     d->cell = strdup (buf);
83     if (d->cell == NULL)
84 	return errno;
85 
86     f = fopen (AFS_SERVERMAGICKRBCONF, "r");
87     if (f != NULL) {
88 	if (fgets (buf, sizeof(buf), f) == NULL) {
89 	    fclose (f);
90 	    return EINVAL;
91 	}
92 	if (buf[strlen(buf)-1] == '\n')
93 	    buf[strlen(buf)-1] = '\0';
94 	fclose(f);
95     }
96     /* uppercase */
97     for (cp = buf; *cp != '\0'; cp++)
98 	*cp = toupper(*cp);
99 
100     d->realm = strdup (buf);
101     if (d->realm == NULL) {
102 	free (d->cell);
103 	return errno;
104     }
105     return 0;
106 }
107 
108 /*
109  * init and get filename
110  */
111 
112 static krb5_error_code
113 akf_resolve(krb5_context context, const char *name, krb5_keytab id)
114 {
115     int ret;
116     struct akf_data *d = malloc(sizeof (struct akf_data));
117 
118     if (d == NULL)
119 	return errno;
120 
121     d->num_entries = 0;
122     ret = get_cell_and_realm (d);
123     if (ret) {
124 	free (d);
125 	return ret;
126     }
127     d->filename = strdup (name);
128     if (d->filename == NULL) {
129 	free (d->cell);
130 	free (d->realm);
131 	free (d);
132 	return ENOMEM;
133     }
134     id->data = d;
135 
136     return 0;
137 }
138 
139 /*
140  * cleanup
141  */
142 
143 static krb5_error_code
144 akf_close(krb5_context context, krb5_keytab id)
145 {
146     struct akf_data *d = id->data;
147 
148     free (d->filename);
149     free (d->cell);
150     free (d);
151     return 0;
152 }
153 
154 /*
155  * Return filename
156  */
157 
158 static krb5_error_code
159 akf_get_name(krb5_context context,
160 	     krb5_keytab id,
161 	     char *name,
162 	     size_t name_sz)
163 {
164     struct akf_data *d = id->data;
165 
166     strlcpy (name, d->filename, name_sz);
167     return 0;
168 }
169 
170 /*
171  * Init
172  */
173 
174 static krb5_error_code
175 akf_start_seq_get(krb5_context context,
176 		  krb5_keytab id,
177 		  krb5_kt_cursor *c)
178 {
179     int32_t ret;
180     struct akf_data *d = id->data;
181 
182     c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600);
183     if (c->fd < 0)
184 	return errno;
185 
186     c->sp = krb5_storage_from_fd(c->fd);
187     ret = krb5_ret_int32(c->sp, &d->num_entries);
188     if(ret) {
189 	krb5_storage_free(c->sp);
190 	close(c->fd);
191 	return ret;
192     }
193 
194     return 0;
195 }
196 
197 static krb5_error_code
198 akf_next_entry(krb5_context context,
199 	       krb5_keytab id,
200 	       krb5_keytab_entry *entry,
201 	       krb5_kt_cursor *cursor)
202 {
203     struct akf_data *d = id->data;
204     int32_t kvno;
205     off_t pos;
206     int ret;
207 
208     pos = cursor->sp->seek(cursor->sp, 0, SEEK_CUR);
209 
210     if ((pos - 4) / (4 + 8) >= d->num_entries)
211 	return KRB5_KT_END;
212 
213     ret = krb5_make_principal (context, &entry->principal,
214 			       d->realm, "afs", d->cell, NULL);
215     if (ret)
216 	goto out;
217 
218     ret = krb5_ret_int32(cursor->sp, &kvno);
219     if (ret) {
220 	krb5_free_principal (context, entry->principal);
221 	goto out;
222     }
223 
224     entry->vno = (int8_t) kvno;
225 
226     entry->keyblock.keytype         = ETYPE_DES_CBC_MD5;
227     entry->keyblock.keyvalue.length = 8;
228     entry->keyblock.keyvalue.data   = malloc (8);
229     if (entry->keyblock.keyvalue.data == NULL) {
230 	krb5_free_principal (context, entry->principal);
231 	ret = ENOMEM;
232 	goto out;
233     }
234 
235     ret = cursor->sp->fetch(cursor->sp, entry->keyblock.keyvalue.data, 8);
236     if(ret != 8)
237 	ret = (ret < 0) ? errno : KRB5_KT_END;
238 
239     entry->timestamp = time(NULL);
240 
241  out:
242     cursor->sp->seek(cursor->sp, pos + 4 + 8, SEEK_SET);
243     return ret;
244 }
245 
246 static krb5_error_code
247 akf_end_seq_get(krb5_context context,
248 		krb5_keytab id,
249 		krb5_kt_cursor *cursor)
250 {
251     krb5_storage_free(cursor->sp);
252     close(cursor->fd);
253     return 0;
254 }
255 
256 static krb5_error_code
257 akf_add_entry(krb5_context context,
258 	      krb5_keytab id,
259 	      krb5_keytab_entry *entry)
260 {
261     struct akf_data *d = id->data;
262     int fd, created = 0;
263     int32_t kvno;
264 
265     fd = open (d->filename, O_RDWR | O_BINARY);
266     if (fd < 0) {
267 	fd = open (d->filename,
268 		   O_RDWR | O_BINARY | O_CREAT, 0600);
269 	if (fd < 0)
270 	    return errno;
271 	created = 1;
272     }
273 
274     if (entry->keyblock.keyvalue.length == 8
275 	&& entry->keyblock.keytype == ETYPE_DES_CBC_MD5) {
276 
277 	int32_t len = 0;
278 
279 	if (!created) {
280 	    if (lseek (fd, 0, SEEK_SET))
281 		return errno;
282 
283 	    if (read (fd, &len, sizeof(len)) != sizeof(len))
284 		return errno;
285 	}
286 	len += 1;
287 
288 	if (lseek (fd, 0, SEEK_SET))
289 	    return errno;
290 
291 	if (write (fd, &len, sizeof(len)) != sizeof(len))
292 	    return errno;
293 
294 	if (lseek (fd, 4 + (len-1) * (8+4), SEEK_SET))
295 	    return errno;
296 
297 	kvno = entry->vno;
298 	write(fd, &kvno, sizeof(kvno));
299 	write(fd, entry->keyblock.keyvalue.data, 8);
300     }
301     close (fd);
302     return 0;
303 }
304 
305 const krb5_kt_ops krb5_akf_ops = {
306     "AFSKEYFILE",
307     akf_resolve,
308     akf_get_name,
309     akf_close,
310     NULL, /* get */
311     akf_start_seq_get,
312     akf_next_entry,
313     akf_end_seq_get,
314     akf_add_entry,
315     NULL /* remove */
316 };
317