• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/heimdal/lib/hdb/
1/*
2 * Copyright (c) 1999 - 2002 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 "hdb_locl.h"
35
36/* keytab backend for HDB databases */
37
38struct hdb_data {
39    char *dbname;
40    char *mkey;
41};
42
43struct hdb_cursor {
44    HDB *db;
45    hdb_entry_ex hdb_entry;
46    int first, next;
47    int key_idx;
48};
49
50/*
51 * the format for HDB keytabs is:
52 * HDB:[database:file:mkey]
53 */
54
55static krb5_error_code
56hdb_resolve(krb5_context context, const char *name, krb5_keytab id)
57{
58    struct hdb_data *d;
59    const char *db, *mkey;
60
61    d = malloc(sizeof(*d));
62    if(d == NULL) {
63	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
64	return ENOMEM;
65    }
66    db = name;
67    mkey = strchr(name, ':');
68    if(mkey == NULL || mkey[1] == '\0') {
69	if(*name == '\0')
70	    d->dbname = NULL;
71	else {
72	    d->dbname = strdup(name);
73	    if(d->dbname == NULL) {
74		free(d);
75		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
76		return ENOMEM;
77	    }
78	}
79	d->mkey = NULL;
80    } else {
81	if((mkey - db) == 0) {
82	    d->dbname = NULL;
83	} else {
84	    d->dbname = malloc(mkey - db + 1);
85	    if(d->dbname == NULL) {
86		free(d);
87		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
88		return ENOMEM;
89	    }
90	    memmove(d->dbname, db, mkey - db);
91	    d->dbname[mkey - db] = '\0';
92	}
93	d->mkey = strdup(mkey + 1);
94	if(d->mkey == NULL) {
95	    free(d->dbname);
96	    free(d);
97	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
98	    return ENOMEM;
99	}
100    }
101    id->data = d;
102    return 0;
103}
104
105static krb5_error_code
106hdb_close(krb5_context context, krb5_keytab id)
107{
108    struct hdb_data *d = id->data;
109
110    free(d->dbname);
111    free(d->mkey);
112    free(d);
113    return 0;
114}
115
116static krb5_error_code
117hdb_get_name(krb5_context context,
118	     krb5_keytab id,
119	     char *name,
120	     size_t namesize)
121{
122    struct hdb_data *d = id->data;
123
124    snprintf(name, namesize, "%s%s%s",
125	     d->dbname ? d->dbname : "",
126	     (d->dbname || d->mkey) ? ":" : "",
127	     d->mkey ? d->mkey : "");
128    return 0;
129}
130
131/*
132 * try to figure out the database (`dbname') and master-key (`mkey')
133 * that should be used for `principal'.
134 */
135
136static krb5_error_code
137find_db (krb5_context context,
138	 char **dbname,
139	 char **mkey,
140	 krb5_const_principal principal)
141{
142    krb5_const_realm realm = krb5_principal_get_realm(context, principal);
143    krb5_error_code ret;
144    struct hdb_dbinfo *head, *dbinfo = NULL;
145
146    *dbname = *mkey = NULL;
147
148    ret = hdb_get_dbinfo(context, &head);
149    if (ret)
150	return ret;
151
152    while ((dbinfo = hdb_dbinfo_get_next(head, dbinfo)) != NULL) {
153	const char *p = hdb_dbinfo_get_realm(context, dbinfo);
154	if (p && strcmp (realm, p) == 0) {
155	    p = hdb_dbinfo_get_dbname(context, dbinfo);
156	    if (p)
157		*dbname = strdup(p);
158	    p = hdb_dbinfo_get_mkey_file(context, dbinfo);
159	    if (p)
160		*mkey = strdup(p);
161	    break;
162	}
163    }
164    hdb_free_dbinfo(context, &head);
165    if (*dbname == NULL)
166	*dbname = strdup(HDB_DEFAULT_DB);
167    return 0;
168}
169
170/*
171 * find the keytab entry in `id' for `principal, kvno, enctype' and return
172 * it in `entry'.  return 0 or an error code
173 */
174
175static krb5_error_code
176hdb_get_entry(krb5_context context,
177	      krb5_keytab id,
178	      krb5_const_principal principal,
179	      krb5_kvno kvno,
180	      krb5_enctype enctype,
181	      krb5_keytab_entry *entry)
182{
183    hdb_entry_ex ent;
184    krb5_error_code ret;
185    struct hdb_data *d = id->data;
186    const char *dbname = d->dbname;
187    const char *mkey   = d->mkey;
188    char *fdbname = NULL, *fmkey = NULL;
189    HDB *db;
190    int i;
191
192    memset(&ent, 0, sizeof(ent));
193
194    if (dbname == NULL) {
195	ret = find_db(context, &fdbname, &fmkey, principal);
196	if (ret)
197	    return ret;
198	dbname = fdbname;
199	mkey = fmkey;
200    }
201
202    ret = hdb_create (context, &db, dbname);
203    if (ret)
204	goto out2;
205    ret = hdb_set_master_keyfile (context, db, mkey);
206    if (ret) {
207	(*db->hdb_destroy)(context, db);
208	goto out2;
209    }
210
211    ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
212    if (ret) {
213	(*db->hdb_destroy)(context, db);
214	goto out2;
215    }
216    ret = (*db->hdb_fetch)(context, db, principal,
217			   HDB_F_DECRYPT|
218			   HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
219			   &ent);
220
221    if(ret == HDB_ERR_NOENTRY) {
222	ret = KRB5_KT_NOTFOUND;
223	goto out;
224    }else if(ret)
225	goto out;
226
227    if(kvno && ent.entry.kvno != kvno) {
228	hdb_free_entry(context, &ent);
229 	ret = KRB5_KT_NOTFOUND;
230	goto out;
231    }
232    if(enctype == 0)
233	if(ent.entry.keys.len > 0)
234	    enctype = ent.entry.keys.val[0].key.keytype;
235    ret = KRB5_KT_NOTFOUND;
236    for(i = 0; i < ent.entry.keys.len; i++) {
237	if(ent.entry.keys.val[i].key.keytype == enctype) {
238	    krb5_copy_principal(context, principal, &entry->principal);
239	    entry->vno = ent.entry.kvno;
240	    krb5_copy_keyblock_contents(context,
241					&ent.entry.keys.val[i].key,
242					&entry->keyblock);
243	    ret = 0;
244	    break;
245	}
246    }
247    hdb_free_entry(context, &ent);
248 out:
249    (*db->hdb_close)(context, db);
250    (*db->hdb_destroy)(context, db);
251 out2:
252    free(fdbname);
253    free(fmkey);
254    return ret;
255}
256
257/*
258 * find the keytab entry in `id' for `principal, kvno, enctype' and return
259 * it in `entry'.  return 0 or an error code
260 */
261
262static krb5_error_code
263hdb_start_seq_get(krb5_context context,
264		  krb5_keytab id,
265		  krb5_kt_cursor *cursor)
266{
267    krb5_error_code ret;
268    struct hdb_cursor *c;
269    struct hdb_data *d = id->data;
270    const char *dbname = d->dbname;
271    const char *mkey   = d->mkey;
272    HDB *db;
273
274    if (dbname == NULL) {
275	/*
276	 * We don't support enumerating without being told what
277	 * backend to enumerate on
278	 */
279  	ret = KRB5_KT_NOTFOUND;
280	return ret;
281    }
282
283    ret = hdb_create (context, &db, dbname);
284    if (ret)
285	return ret;
286    ret = hdb_set_master_keyfile (context, db, mkey);
287    if (ret) {
288	(*db->hdb_destroy)(context, db);
289	return ret;
290    }
291
292    ret = (*db->hdb_open)(context, db, O_RDONLY, 0);
293    if (ret) {
294	(*db->hdb_destroy)(context, db);
295	return ret;
296    }
297
298    cursor->data = c = malloc (sizeof(*c));
299    if(c == NULL){
300	(*db->hdb_close)(context, db);
301	(*db->hdb_destroy)(context, db);
302	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
303	return ENOMEM;
304    }
305
306    c->db = db;
307    c->first = TRUE;
308    c->next = TRUE;
309    c->key_idx = 0;
310
311    cursor->data = c;
312    return ret;
313}
314
315static int
316hdb_next_entry(krb5_context context,
317	       krb5_keytab id,
318	       krb5_keytab_entry *entry,
319	       krb5_kt_cursor *cursor)
320{
321    struct hdb_cursor *c = cursor->data;
322    krb5_error_code ret;
323
324    memset(entry, 0, sizeof(*entry));
325
326    if (c->first) {
327	c->first = FALSE;
328	ret = (c->db->hdb_firstkey)(context, c->db,
329				    HDB_F_DECRYPT|
330				    HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
331				    &c->hdb_entry);
332	if (ret == HDB_ERR_NOENTRY)
333	    return KRB5_KT_END;
334	else if (ret)
335	    return ret;
336
337	if (c->hdb_entry.entry.keys.len == 0)
338	    hdb_free_entry(context, &c->hdb_entry);
339	else
340	    c->next = FALSE;
341    }
342
343    while (c->next) {
344	ret = (c->db->hdb_nextkey)(context, c->db,
345				   HDB_F_DECRYPT|
346				   HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
347				   &c->hdb_entry);
348	if (ret == HDB_ERR_NOENTRY)
349	    return KRB5_KT_END;
350	else if (ret)
351	    return ret;
352
353	/* If no keys on this entry, try again */
354	if (c->hdb_entry.entry.keys.len == 0)
355	    hdb_free_entry(context, &c->hdb_entry);
356	else
357	    c->next = FALSE;
358    }
359
360    /*
361     * Return next enc type (keytabs are one slot per key, while
362     * hdb is one record per principal.
363     */
364
365    ret = krb5_copy_principal(context,
366			      c->hdb_entry.entry.principal,
367			      &entry->principal);
368    if (ret)
369	return ret;
370
371    entry->vno = c->hdb_entry.entry.kvno;
372    ret = krb5_copy_keyblock_contents(context,
373				      &c->hdb_entry.entry.keys.val[c->key_idx].key,
374				      &entry->keyblock);
375    if (ret) {
376	krb5_free_principal(context, entry->principal);
377	memset(entry, 0, sizeof(*entry));
378	return ret;
379    }
380    c->key_idx++;
381
382    /*
383     * Once we get to the end of the list, signal that we want the
384     * next entry
385     */
386
387    if (c->key_idx == c->hdb_entry.entry.keys.len) {
388	hdb_free_entry(context, &c->hdb_entry);
389	c->next = TRUE;
390	c->key_idx = 0;
391    }
392
393    return 0;
394}
395
396
397static int
398hdb_end_seq_get(krb5_context context,
399		krb5_keytab id,
400		krb5_kt_cursor *cursor)
401{
402    struct hdb_cursor *c = cursor->data;
403
404    (c->db->hdb_close)(context, c->db);
405    (c->db->hdb_destroy)(context, c->db);
406
407    if (!c->next)
408	hdb_free_entry(context, &c->hdb_entry);
409
410    free(c);
411    return 0;
412}
413
414krb5_kt_ops hdb_kt_ops = {
415    "HDB",
416    hdb_resolve,
417    hdb_get_name,
418    hdb_close,
419    NULL,		/* destroy */
420    hdb_get_entry,
421    hdb_start_seq_get,
422    hdb_next_entry,
423    hdb_end_seq_get,
424    NULL,		/* add */
425    NULL		/* remove */
426};
427