changed `struct fd_set' to `fd_set'
[heimdal.git] / lib / hdb / hdb.c
blob105994947248c1d0104a46f28c4b3fd1f1b5ed44
1 /*
2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "hdb_locl.h"
41 RCSID("$Id$");
43 krb5_error_code
44 hdb_next_keytype2key(krb5_context context,
45 hdb_entry *e,
46 krb5_keytype keytype,
47 Key **key)
49 int i;
50 if(*key)
51 i = *key - e->keys.val + 1;
52 else
53 i = 0;
54 for(; i < e->keys.len; i++)
55 if(e->keys.val[i].key.keytype == keytype){
56 *key = &e->keys.val[i];
57 return 0;
59 return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
62 krb5_error_code
63 hdb_keytype2key(krb5_context context,
64 hdb_entry *e,
65 krb5_keytype keytype,
66 Key **key)
68 *key = NULL;
69 return hdb_next_keytype2key(context,e, keytype, key);
72 krb5_error_code
73 hdb_next_etype2key(krb5_context context,
74 hdb_entry *e,
75 krb5_enctype etype,
76 Key **key)
78 krb5_keytype keytype;
79 krb5_error_code ret;
80 ret = krb5_etype_to_keytype(context, etype, &keytype);
81 if(ret)
82 return ret;
83 return hdb_next_keytype2key(context, e, keytype, key);
86 krb5_error_code
87 hdb_etype2key(krb5_context context,
88 hdb_entry *e,
89 krb5_enctype etype,
90 Key **key)
92 *key = NULL;
93 return hdb_next_etype2key(context,e, etype, key);
96 /* this is a bit ugly, but will get better when the crypto framework
97 gets fixed */
99 krb5_error_code
100 hdb_process_master_key(krb5_context context, EncryptionKey key,
101 krb5_data *schedule)
103 if(key.keytype != KEYTYPE_DES)
104 return KRB5_PROG_KEYTYPE_NOSUPP;
105 schedule->length = sizeof(des_key_schedule);
106 schedule->data = malloc(schedule->length);
108 des_set_key((des_cblock*)key.keyvalue.data, schedule->data);
109 return 0;
112 krb5_error_code
113 hdb_read_master_key(krb5_context context, const char *filename,
114 EncryptionKey *key)
116 FILE *f;
117 unsigned char buf[256];
118 size_t len;
119 krb5_error_code ret;
120 if(filename == NULL)
121 filename = HDB_DB_DIR "/m-key";
122 f = fopen(filename, "r");
123 if(f == NULL)
124 return errno;
125 len = fread(buf, 1, sizeof(buf), f);
126 if(ferror(f))
127 ret = errno;
128 else
129 ret = decode_EncryptionKey(buf, len, key, &len);
130 fclose(f);
131 memset(buf, 0, sizeof(buf));
132 return ret;
135 Key *
136 hdb_unseal_key(Key *key, krb5_data schedule)
138 des_cblock iv;
139 int num = 0;
140 Key *new_key;
142 new_key = malloc(sizeof(*new_key));
143 copy_Key(key, new_key);
144 memset(&iv, 0, sizeof(iv));
145 des_cfb64_encrypt(key->key.keyvalue.data,
146 new_key->key.keyvalue.data,
147 key->key.keyvalue.length,
148 schedule.data, &iv, &num, 0);
149 return new_key;
152 void
153 hdb_seal_key(Key *key, krb5_data schedule)
155 des_cblock iv;
156 int num = 0;
158 memset(&iv, 0, sizeof(iv));
159 des_cfb64_encrypt(key->key.keyvalue.data,
160 key->key.keyvalue.data,
161 key->key.keyvalue.length,
162 schedule.data, &iv, &num, 1);
165 void
166 hdb_unseal_keys(hdb_entry *ent, krb5_data schedule)
168 int i;
169 for(i = 0; i < ent->keys.len; i++){
170 des_cblock iv;
171 int num = 0;
172 memset(&iv, 0, sizeof(iv));
173 des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data,
174 ent->keys.val[i].key.keyvalue.data,
175 ent->keys.val[i].key.keyvalue.length,
176 schedule.data, &iv, &num, 0);
180 void
181 hdb_seal_keys(hdb_entry *ent, krb5_data schedule)
183 int i;
184 for(i = 0; i < ent->keys.len; i++)
185 hdb_seal_key(&ent->keys.val[i], schedule);
188 void
189 hdb_free_key(Key *key)
191 memset(key->key.keyvalue.data,
193 key->key.keyvalue.length);
194 free_Key(key);
195 free(key);
199 krb5_error_code
200 hdb_lock(int fd, int operation)
202 int i, code;
203 for(i = 0; i < 3; i++){
204 code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
205 if(code == 0 || errno != EWOULDBLOCK)
206 break;
207 sleep(1);
209 if(code == 0)
210 return 0;
211 if(errno == EWOULDBLOCK)
212 return HDB_ERR_DB_INUSE;
213 return HDB_ERR_CANT_LOCK_DB;
216 krb5_error_code
217 hdb_unlock(int fd)
219 int code;
220 code = flock(fd, LOCK_UN);
221 if(code)
222 return 4711 /* XXX */;
223 return 0;
226 void
227 hdb_free_entry(krb5_context context, hdb_entry *ent)
229 int i;
231 for(i = 0; i < ent->keys.len; ++i) {
232 Key *k = &ent->keys.val[i];
234 memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
236 free_hdb_entry(ent);
239 krb5_error_code
240 hdb_foreach(krb5_context context,
241 HDB *db,
242 hdb_foreach_func_t func,
243 void *data)
245 krb5_error_code ret;
246 hdb_entry entry;
247 ret = db->firstkey(context, db, &entry);
248 while(ret == 0){
249 ret = (*func)(context, db, &entry, data);
250 hdb_free_entry(context, &entry);
251 if(ret == 0)
252 ret = db->nextkey(context, db, &entry);
254 if(ret == HDB_ERR_NOENTRY)
255 ret = 0;
256 return ret;
259 krb5_error_code
260 hdb_check_db_format(krb5_context context, HDB *db)
262 krb5_data tag;
263 krb5_data version;
264 krb5_error_code ret;
265 unsigned ver;
266 int foo;
268 tag.data = HDB_DB_FORMAT_ENTRY;
269 tag.length = strlen(tag.data);
270 ret = (*db->_get)(context, db, tag, &version);
271 if(ret)
272 return ret;
273 foo = sscanf(version.data, "%u", &ver);
274 krb5_data_free (&version);
275 if (foo != 1)
276 return HDB_ERR_BADVERSION;
277 if(ver != HDB_DB_FORMAT)
278 return HDB_ERR_BADVERSION;
279 return 0;
282 krb5_error_code
283 hdb_init_db(krb5_context context, HDB *db)
285 krb5_error_code ret;
286 krb5_data tag;
287 krb5_data version;
288 char ver[32];
290 ret = hdb_check_db_format(context, db);
291 if(ret != HDB_ERR_NOENTRY)
292 return ret;
294 tag.data = HDB_DB_FORMAT_ENTRY;
295 tag.length = strlen(tag.data);
296 snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
297 version.data = ver;
298 version.length = strlen(version.data) + 1; /* zero terminated */
299 ret = (*db->_put)(context, db, 0, tag, version);
300 return ret;
303 krb5_error_code
304 hdb_create(krb5_context context, HDB **db, const char *filename)
306 krb5_error_code ret = 0;
307 if(filename == NULL)
308 filename = HDB_DEFAULT_DB;
309 initialize_hdb_error_table(&context->et_list);
310 #ifdef HAVE_DB_H
311 ret = hdb_db_create(context, db, filename);
312 #elif HAVE_NDBM_H
313 ret = hdb_ndbm_create(context, db, filename);
314 #else
315 krb5_errx(context, 1, "No database support! (hdb_create)");
316 #endif
317 return ret;
320 krb5_error_code
321 hdb_set_master_key (krb5_context context,
322 HDB *db,
323 const char *keyfile)
325 EncryptionKey key;
326 krb5_error_code ret;
328 ret = hdb_read_master_key(context, keyfile, &key);
329 if (ret) {
330 if (ret != ENOENT)
331 return ret;
332 } else {
333 ret = hdb_process_master_key(context, key, &db->master_key);
334 if (ret)
335 return ret;
336 des_set_random_generator_seed(key.keyvalue.data);
337 db->master_key_set = 1;
338 memset(key.keyvalue.data, 0, key.keyvalue.length);
339 free_EncryptionKey(&key);
341 return 0;
344 krb5_error_code
345 hdb_clear_master_key (krb5_context context,
346 HDB *db)
348 if (db->master_key_set) {
349 memset(db->master_key.data, 0, db->master_key.length);
350 krb5_data_free(&db->master_key);
351 db->master_key_set = 0;
353 return 0;