xref: /freebsd/crypto/heimdal/lib/hdb/hdb.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*
2  * Copyright (c) 1997 - 2001 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 RCSID("$Id: hdb.c,v 1.44 2001/08/09 08:41:48 assar Exp $");
37 
38 struct hdb_method {
39     const char *prefix;
40     krb5_error_code (*create)(krb5_context, HDB **, const char *filename);
41 };
42 
43 static struct hdb_method methods[] = {
44 #if HAVE_DB1 || HAVE_DB3
45     {"db:",	hdb_db_create},
46 #endif
47 #if HAVE_NDBM
48     {"ndbm:",	hdb_ndbm_create},
49 #endif
50 #ifdef OPENLDAP
51     {"ldap:",	hdb_ldap_create},
52 #endif
53 #if HAVE_DB1 || HAVE_DB3
54     {"",	hdb_db_create},
55 #elif defined(HAVE_NDBM)
56     {"",	hdb_ndbm_create},
57 #elif defined(OPENLDAP)
58     {"",	hdb_ldap_create},
59 #endif
60     {NULL,	NULL}
61 };
62 
63 krb5_error_code
64 hdb_next_enctype2key(krb5_context context,
65 		     const hdb_entry *e,
66 		     krb5_enctype enctype,
67 		     Key **key)
68 {
69     Key *k;
70 
71     for (k = *key ? (*key) + 1 : e->keys.val;
72 	 k < e->keys.val + e->keys.len;
73 	 k++)
74 	if(k->key.keytype == enctype){
75 	    *key = k;
76 	    return 0;
77 	}
78     return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
79 }
80 
81 krb5_error_code
82 hdb_enctype2key(krb5_context context,
83 		hdb_entry *e,
84 		krb5_enctype enctype,
85 		Key **key)
86 {
87     *key = NULL;
88     return hdb_next_enctype2key(context, e, enctype, key);
89 }
90 
91 void
92 hdb_free_key(Key *key)
93 {
94     memset(key->key.keyvalue.data,
95 	   0,
96 	   key->key.keyvalue.length);
97     free_Key(key);
98     free(key);
99 }
100 
101 
102 krb5_error_code
103 hdb_lock(int fd, int operation)
104 {
105     int i, code = 0;
106 
107     for(i = 0; i < 3; i++){
108 	code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
109 	if(code == 0 || errno != EWOULDBLOCK)
110 	    break;
111 	sleep(1);
112     }
113     if(code == 0)
114 	return 0;
115     if(errno == EWOULDBLOCK)
116 	return HDB_ERR_DB_INUSE;
117     return HDB_ERR_CANT_LOCK_DB;
118 }
119 
120 krb5_error_code
121 hdb_unlock(int fd)
122 {
123     int code;
124     code = flock(fd, LOCK_UN);
125     if(code)
126 	return 4711 /* XXX */;
127     return 0;
128 }
129 
130 void
131 hdb_free_entry(krb5_context context, hdb_entry *ent)
132 {
133     int i;
134 
135     for(i = 0; i < ent->keys.len; ++i) {
136 	Key *k = &ent->keys.val[i];
137 
138 	memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
139     }
140     free_hdb_entry(ent);
141 }
142 
143 krb5_error_code
144 hdb_foreach(krb5_context context,
145 	    HDB *db,
146 	    unsigned flags,
147 	    hdb_foreach_func_t func,
148 	    void *data)
149 {
150     krb5_error_code ret;
151     hdb_entry entry;
152     ret = db->firstkey(context, db, flags, &entry);
153     while(ret == 0){
154 	ret = (*func)(context, db, &entry, data);
155 	hdb_free_entry(context, &entry);
156 	if(ret == 0)
157 	    ret = db->nextkey(context, db, flags, &entry);
158     }
159     if(ret == HDB_ERR_NOENTRY)
160 	ret = 0;
161     return ret;
162 }
163 
164 krb5_error_code
165 hdb_check_db_format(krb5_context context, HDB *db)
166 {
167     krb5_data tag;
168     krb5_data version;
169     krb5_error_code ret;
170     unsigned ver;
171     int foo;
172 
173     tag.data = HDB_DB_FORMAT_ENTRY;
174     tag.length = strlen(tag.data);
175     ret = (*db->_get)(context, db, tag, &version);
176     if(ret)
177 	return ret;
178     foo = sscanf(version.data, "%u", &ver);
179     krb5_data_free (&version);
180     if (foo != 1)
181 	return HDB_ERR_BADVERSION;
182     if(ver != HDB_DB_FORMAT)
183 	return HDB_ERR_BADVERSION;
184     return 0;
185 }
186 
187 krb5_error_code
188 hdb_init_db(krb5_context context, HDB *db)
189 {
190     krb5_error_code ret;
191     krb5_data tag;
192     krb5_data version;
193     char ver[32];
194 
195     ret = hdb_check_db_format(context, db);
196     if(ret != HDB_ERR_NOENTRY)
197 	return ret;
198 
199     tag.data = HDB_DB_FORMAT_ENTRY;
200     tag.length = strlen(tag.data);
201     snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
202     version.data = ver;
203     version.length = strlen(version.data) + 1; /* zero terminated */
204     ret = (*db->_put)(context, db, 0, tag, version);
205     return ret;
206 }
207 
208 /*
209  * find the relevant method for `filename', returning a pointer to the
210  * rest in `rest'.
211  * return NULL if there's no such method.
212  */
213 
214 static const struct hdb_method *
215 find_method (const char *filename, const char **rest)
216 {
217     const struct hdb_method *h;
218 
219     for (h = methods; h->prefix != NULL; ++h)
220 	if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
221 	    *rest = filename + strlen(h->prefix);
222 	    return h;
223 	}
224     return NULL;
225 }
226 
227 krb5_error_code
228 hdb_create(krb5_context context, HDB **db, const char *filename)
229 {
230     const struct hdb_method *h;
231     const char *residual;
232 
233     if(filename == NULL)
234 	filename = HDB_DEFAULT_DB;
235     krb5_add_et_list(context, initialize_hdb_error_table_r);
236     h = find_method (filename, &residual);
237     if (h == NULL)
238 	krb5_errx(context, 1, "No database support! (hdb_create)");
239     return (*h->create)(context, db, residual);
240 }
241