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