1 /* 2 * Copyright (c) 1997, 1998, 1999 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.35 1999/12/02 17:05:05 joda Exp $"); 37 38 krb5_error_code 39 hdb_next_enctype2key(krb5_context context, 40 hdb_entry *e, 41 krb5_enctype enctype, 42 Key **key) 43 { 44 Key *k; 45 46 for (k = *key ? *key : e->keys.val; 47 k < e->keys.val + e->keys.len; 48 k++) 49 if(k->key.keytype == enctype){ 50 *key = k; 51 return 0; 52 } 53 return KRB5_PROG_ETYPE_NOSUPP; /* XXX */ 54 } 55 56 krb5_error_code 57 hdb_enctype2key(krb5_context context, 58 hdb_entry *e, 59 krb5_enctype enctype, 60 Key **key) 61 { 62 *key = NULL; 63 return hdb_next_enctype2key(context, e, enctype, key); 64 } 65 66 /* this is a bit ugly, but will get better when the crypto framework 67 gets fixed */ 68 69 krb5_error_code 70 hdb_process_master_key(krb5_context context, EncryptionKey key, 71 krb5_data *schedule) 72 { 73 krb5_error_code ret; 74 75 if(key.keytype != ETYPE_DES_CBC_MD5) 76 return KRB5_PROG_KEYTYPE_NOSUPP; 77 78 ret = krb5_data_alloc (schedule, sizeof(des_key_schedule)); 79 if (ret) 80 return ret; 81 82 des_set_key((des_cblock*)key.keyvalue.data, schedule->data); 83 return 0; 84 } 85 86 krb5_error_code 87 hdb_read_master_key(krb5_context context, const char *filename, 88 EncryptionKey *key) 89 { 90 FILE *f; 91 unsigned char buf[256]; 92 size_t len; 93 krb5_error_code ret; 94 if(filename == NULL) 95 filename = HDB_DB_DIR "/m-key"; 96 f = fopen(filename, "r"); 97 if(f == NULL) 98 return errno; 99 len = fread(buf, 1, sizeof(buf), f); 100 if(ferror(f)) 101 ret = errno; 102 else 103 ret = decode_EncryptionKey(buf, len, key, &len); 104 fclose(f); 105 memset(buf, 0, sizeof(buf)); 106 return ret; 107 } 108 109 void 110 _hdb_unseal_keys_int(hdb_entry *ent, int key_version, krb5_data schedule) 111 { 112 int i; 113 for(i = 0; i < ent->keys.len; i++){ 114 des_cblock iv; 115 int num = 0; 116 if(ent->keys.val[i].mkvno == NULL) 117 continue; 118 if(*ent->keys.val[i].mkvno != key_version) 119 ; 120 memset(&iv, 0, sizeof(iv)); 121 122 des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data, 123 ent->keys.val[i].key.keyvalue.data, 124 ent->keys.val[i].key.keyvalue.length, 125 schedule.data, &iv, &num, 0); 126 free(ent->keys.val[i].mkvno); 127 ent->keys.val[i].mkvno = NULL; 128 } 129 } 130 131 void 132 hdb_unseal_keys(HDB *db, hdb_entry *ent) 133 { 134 if (db->master_key_set == 0) 135 return; 136 _hdb_unseal_keys_int(ent, db->master_key_version, db->master_key); 137 } 138 139 void 140 _hdb_seal_keys_int(hdb_entry *ent, int key_version, krb5_data schedule) 141 { 142 int i; 143 for(i = 0; i < ent->keys.len; i++){ 144 des_cblock iv; 145 int num = 0; 146 147 if(ent->keys.val[i].mkvno != NULL) 148 continue; 149 memset(&iv, 0, sizeof(iv)); 150 des_cfb64_encrypt(ent->keys.val[i].key.keyvalue.data, 151 ent->keys.val[i].key.keyvalue.data, 152 ent->keys.val[i].key.keyvalue.length, 153 schedule.data, &iv, &num, 1); 154 ent->keys.val[i].mkvno = malloc(sizeof(*ent->keys.val[i].mkvno)); 155 *ent->keys.val[i].mkvno = key_version; 156 } 157 } 158 159 void 160 hdb_seal_keys(HDB *db, hdb_entry *ent) 161 { 162 if (db->master_key_set == 0) 163 return; 164 165 _hdb_seal_keys_int(ent, db->master_key_version, db->master_key); 166 } 167 168 void 169 hdb_free_key(Key *key) 170 { 171 memset(key->key.keyvalue.data, 172 0, 173 key->key.keyvalue.length); 174 free_Key(key); 175 free(key); 176 } 177 178 179 krb5_error_code 180 hdb_lock(int fd, int operation) 181 { 182 int i, code; 183 for(i = 0; i < 3; i++){ 184 code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB); 185 if(code == 0 || errno != EWOULDBLOCK) 186 break; 187 sleep(1); 188 } 189 if(code == 0) 190 return 0; 191 if(errno == EWOULDBLOCK) 192 return HDB_ERR_DB_INUSE; 193 return HDB_ERR_CANT_LOCK_DB; 194 } 195 196 krb5_error_code 197 hdb_unlock(int fd) 198 { 199 int code; 200 code = flock(fd, LOCK_UN); 201 if(code) 202 return 4711 /* XXX */; 203 return 0; 204 } 205 206 void 207 hdb_free_entry(krb5_context context, hdb_entry *ent) 208 { 209 int i; 210 211 for(i = 0; i < ent->keys.len; ++i) { 212 Key *k = &ent->keys.val[i]; 213 214 memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); 215 } 216 free_hdb_entry(ent); 217 } 218 219 krb5_error_code 220 hdb_foreach(krb5_context context, 221 HDB *db, 222 unsigned flags, 223 hdb_foreach_func_t func, 224 void *data) 225 { 226 krb5_error_code ret; 227 hdb_entry entry; 228 ret = db->firstkey(context, db, flags, &entry); 229 while(ret == 0){ 230 ret = (*func)(context, db, &entry, data); 231 hdb_free_entry(context, &entry); 232 if(ret == 0) 233 ret = db->nextkey(context, db, flags, &entry); 234 } 235 if(ret == HDB_ERR_NOENTRY) 236 ret = 0; 237 return ret; 238 } 239 240 krb5_error_code 241 hdb_check_db_format(krb5_context context, HDB *db) 242 { 243 krb5_data tag; 244 krb5_data version; 245 krb5_error_code ret; 246 unsigned ver; 247 int foo; 248 249 tag.data = HDB_DB_FORMAT_ENTRY; 250 tag.length = strlen(tag.data); 251 ret = (*db->_get)(context, db, tag, &version); 252 if(ret) 253 return ret; 254 foo = sscanf(version.data, "%u", &ver); 255 krb5_data_free (&version); 256 if (foo != 1) 257 return HDB_ERR_BADVERSION; 258 if(ver != HDB_DB_FORMAT) 259 return HDB_ERR_BADVERSION; 260 return 0; 261 } 262 263 krb5_error_code 264 hdb_init_db(krb5_context context, HDB *db) 265 { 266 krb5_error_code ret; 267 krb5_data tag; 268 krb5_data version; 269 char ver[32]; 270 271 ret = hdb_check_db_format(context, db); 272 if(ret != HDB_ERR_NOENTRY) 273 return ret; 274 275 tag.data = HDB_DB_FORMAT_ENTRY; 276 tag.length = strlen(tag.data); 277 snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT); 278 version.data = ver; 279 version.length = strlen(version.data) + 1; /* zero terminated */ 280 ret = (*db->_put)(context, db, 0, tag, version); 281 return ret; 282 } 283 284 krb5_error_code 285 hdb_create(krb5_context context, HDB **db, const char *filename) 286 { 287 krb5_error_code ret = 0; 288 if(filename == NULL) 289 filename = HDB_DEFAULT_DB; 290 initialize_hdb_error_table_r(&context->et_list); 291 #ifdef HAVE_DB_H 292 ret = hdb_db_create(context, db, filename); 293 #elif HAVE_NDBM_H 294 ret = hdb_ndbm_create(context, db, filename); 295 #else 296 krb5_errx(context, 1, "No database support! (hdb_create)"); 297 #endif 298 return ret; 299 } 300 301 krb5_error_code 302 hdb_set_master_key (krb5_context context, 303 HDB *db, 304 EncryptionKey key) 305 { 306 krb5_error_code ret; 307 308 ret = hdb_process_master_key(context, key, &db->master_key); 309 if (ret) 310 return ret; 311 #if 0 /* XXX - why? */ 312 des_set_random_generator_seed(key.keyvalue.data); 313 #endif 314 db->master_key_set = 1; 315 db->master_key_version = 0; /* XXX */ 316 return 0; 317 } 318 319 krb5_error_code 320 hdb_set_master_keyfile (krb5_context context, 321 HDB *db, 322 const char *keyfile) 323 { 324 EncryptionKey key; 325 krb5_error_code ret; 326 327 ret = hdb_read_master_key(context, keyfile, &key); 328 if (ret) { 329 if (ret != ENOENT) 330 return ret; 331 return 0; 332 } 333 ret = hdb_set_master_key(context, db, key); 334 memset(key.keyvalue.data, 0, key.keyvalue.length); 335 free_EncryptionKey(&key); 336 return ret; 337 } 338 339 krb5_error_code 340 hdb_clear_master_key (krb5_context context, 341 HDB *db) 342 { 343 if (db->master_key_set) { 344 memset(db->master_key.data, 0, db->master_key.length); 345 krb5_data_free(&db->master_key); 346 db->master_key_set = 0; 347 } 348 return 0; 349 } 350