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