This commit was manufactured by cvs2svn to create tag
[heimdal.git] / lib / hdb / hdb.c
blob43e65eb5d72fea806a4a1e273f3030d9646a6304
1 /*
2 * Copyright (c) 1997, 1998, 1999 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_enctype2key(krb5_context context,
45 hdb_entry *e,
46 krb5_enctype enctype,
47 Key **key)
49 Key *k;
51 for (k = *key ? *key : e->keys.val;
52 k < e->keys.val + e->keys.len;
53 k++)
54 if(k->key.keytype == enctype){
55 *key = k;
56 return 0;
58 return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
61 krb5_error_code
62 hdb_enctype2key(krb5_context context,
63 hdb_entry *e,
64 krb5_enctype enctype,
65 Key **key)
67 *key = NULL;
68 return hdb_next_enctype2key(context, e, enctype, key);
71 /* this is a bit ugly, but will get better when the crypto framework
72 gets fixed */
74 krb5_error_code
75 hdb_process_master_key(krb5_context context, EncryptionKey key,
76 krb5_data *schedule)
78 krb5_error_code ret;
80 if(key.keytype != ETYPE_DES_CBC_MD5)
81 return KRB5_PROG_KEYTYPE_NOSUPP;
83 ret = krb5_data_alloc (schedule, sizeof(des_key_schedule));
84 if (ret)
85 return ret;
87 des_set_key((des_cblock*)key.keyvalue.data, schedule->data);
88 return 0;
91 krb5_error_code
92 hdb_read_master_key(krb5_context context, const char *filename,
93 EncryptionKey *key)
95 FILE *f;
96 unsigned char buf[256];
97 size_t len;
98 krb5_error_code ret;
99 if(filename == NULL)
100 filename = HDB_DB_DIR "/m-key";
101 f = fopen(filename, "r");
102 if(f == NULL)
103 return errno;
104 len = fread(buf, 1, sizeof(buf), f);
105 if(ferror(f))
106 ret = errno;
107 else
108 ret = decode_EncryptionKey(buf, len, key, &len);
109 fclose(f);
110 memset(buf, 0, sizeof(buf));
111 return ret;
114 void
115 _hdb_unseal_keys_int(hdb_entry *ent, int key_version, krb5_data schedule)
117 int i;
118 for(i = 0; i < ent->keys.len; i++){
119 des_cblock iv;
120 int num = 0;
121 if(ent->keys.val[i].mkvno == NULL)
122 continue;
123 if(*ent->keys.val[i].mkvno != key_version)
125 memset(&iv, 0, sizeof(iv));
127 des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data,
128 ent->keys.val[i].key.keyvalue.data,
129 ent->keys.val[i].key.keyvalue.length,
130 schedule.data, &iv, &num, 0);
131 free(ent->keys.val[i].mkvno);
132 ent->keys.val[i].mkvno = NULL;
136 void
137 hdb_unseal_keys(HDB *db, hdb_entry *ent)
139 if (db->master_key_set == 0)
140 return;
141 _hdb_unseal_keys_int(ent, db->master_key_version, db->master_key);
144 void
145 _hdb_seal_keys_int(hdb_entry *ent, int key_version, krb5_data schedule)
147 int i;
148 for(i = 0; i < ent->keys.len; i++){
149 des_cblock iv;
150 int num = 0;
152 if(ent->keys.val[i].mkvno != NULL)
153 continue;
154 memset(&iv, 0, sizeof(iv));
155 des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data,
156 ent->keys.val[i].key.keyvalue.data,
157 ent->keys.val[i].key.keyvalue.length,
158 schedule.data, &iv, &num, 1);
159 ent->keys.val[i].mkvno = malloc(sizeof(*ent->keys.val[i].mkvno));
160 *ent->keys.val[i].mkvno = key_version;
164 void
165 hdb_seal_keys(HDB *db, hdb_entry *ent)
167 if (db->master_key_set == 0)
168 return;
170 _hdb_seal_keys_int(ent, db->master_key_version, db->master_key);
173 void
174 hdb_free_key(Key *key)
176 memset(key->key.keyvalue.data,
178 key->key.keyvalue.length);
179 free_Key(key);
180 free(key);
184 krb5_error_code
185 hdb_lock(int fd, int operation)
187 int i, code;
188 for(i = 0; i < 3; i++){
189 code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
190 if(code == 0 || errno != EWOULDBLOCK)
191 break;
192 sleep(1);
194 if(code == 0)
195 return 0;
196 if(errno == EWOULDBLOCK)
197 return HDB_ERR_DB_INUSE;
198 return HDB_ERR_CANT_LOCK_DB;
201 krb5_error_code
202 hdb_unlock(int fd)
204 int code;
205 code = flock(fd, LOCK_UN);
206 if(code)
207 return 4711 /* XXX */;
208 return 0;
211 void
212 hdb_free_entry(krb5_context context, hdb_entry *ent)
214 int i;
216 for(i = 0; i < ent->keys.len; ++i) {
217 Key *k = &ent->keys.val[i];
219 memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
221 free_hdb_entry(ent);
224 krb5_error_code
225 hdb_foreach(krb5_context context,
226 HDB *db,
227 unsigned flags,
228 hdb_foreach_func_t func,
229 void *data)
231 krb5_error_code ret;
232 hdb_entry entry;
233 ret = db->firstkey(context, db, flags, &entry);
234 while(ret == 0){
235 ret = (*func)(context, db, &entry, data);
236 hdb_free_entry(context, &entry);
237 if(ret == 0)
238 ret = db->nextkey(context, db, flags, &entry);
240 if(ret == HDB_ERR_NOENTRY)
241 ret = 0;
242 return ret;
245 krb5_error_code
246 hdb_check_db_format(krb5_context context, HDB *db)
248 krb5_data tag;
249 krb5_data version;
250 krb5_error_code ret;
251 unsigned ver;
252 int foo;
254 tag.data = HDB_DB_FORMAT_ENTRY;
255 tag.length = strlen(tag.data);
256 ret = (*db->_get)(context, db, tag, &version);
257 if(ret)
258 return ret;
259 foo = sscanf(version.data, "%u", &ver);
260 krb5_data_free (&version);
261 if (foo != 1)
262 return HDB_ERR_BADVERSION;
263 if(ver != HDB_DB_FORMAT)
264 return HDB_ERR_BADVERSION;
265 return 0;
268 krb5_error_code
269 hdb_init_db(krb5_context context, HDB *db)
271 krb5_error_code ret;
272 krb5_data tag;
273 krb5_data version;
274 char ver[32];
276 ret = hdb_check_db_format(context, db);
277 if(ret != HDB_ERR_NOENTRY)
278 return ret;
280 tag.data = HDB_DB_FORMAT_ENTRY;
281 tag.length = strlen(tag.data);
282 snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
283 version.data = ver;
284 version.length = strlen(version.data) + 1; /* zero terminated */
285 ret = (*db->_put)(context, db, 0, tag, version);
286 return ret;
289 krb5_error_code
290 hdb_create(krb5_context context, HDB **db, const char *filename)
292 krb5_error_code ret = 0;
293 if(filename == NULL)
294 filename = HDB_DEFAULT_DB;
295 initialize_hdb_error_table_r(&context->et_list);
296 #ifdef HAVE_DB_H
297 ret = hdb_db_create(context, db, filename);
298 #elif HAVE_NDBM_H
299 ret = hdb_ndbm_create(context, db, filename);
300 #else
301 krb5_errx(context, 1, "No database support! (hdb_create)");
302 #endif
303 return ret;
306 krb5_error_code
307 hdb_set_master_key (krb5_context context,
308 HDB *db,
309 EncryptionKey key)
311 krb5_error_code ret;
313 ret = hdb_process_master_key(context, key, &db->master_key);
314 if (ret)
315 return ret;
316 des_set_random_generator_seed(key.keyvalue.data);
317 db->master_key_set = 1;
318 db->master_key_version = 0; /* XXX */
319 return 0;
322 krb5_error_code
323 hdb_set_master_keyfile (krb5_context context,
324 HDB *db,
325 const char *keyfile)
327 EncryptionKey key;
328 krb5_error_code ret;
330 ret = hdb_read_master_key(context, keyfile, &key);
331 if (ret) {
332 if (ret != ENOENT)
333 return ret;
334 return 0;
336 ret = hdb_set_master_key(context, db, key);
337 memset(key.keyvalue.data, 0, key.keyvalue.length);
338 free_EncryptionKey(&key);
339 return ret;
342 krb5_error_code
343 hdb_clear_master_key (krb5_context context,
344 HDB *db)
346 if (db->master_key_set) {
347 memset(db->master_key.data, 0, db->master_key.length);
348 krb5_data_free(&db->master_key);
349 db->master_key_set = 0;
351 return 0;