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