1 /* $NetBSD: db.c,v 1.3 2019/12/15 22:50:49 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "hdb_locl.h" 37 38 #if defined(HAVE_DB1) 39 40 #if defined(HAVE_DB_185_H) 41 #include <db_185.h> 42 #elif defined(HAVE_DB_H) 43 #include <db.h> 44 #endif 45 46 typedef struct { 47 HDB hdb; /* generic members */ 48 int lock_fd; /* DB-specific */ 49 int do_sync; /* DB-specific */ 50 } DB1_HDB; 51 52 static krb5_error_code 53 DB_close(krb5_context context, HDB *db) 54 { 55 DB1_HDB *db1 = (DB1_HDB *)db; 56 DB *d = (DB*)db->hdb_db; 57 58 heim_assert(d != 0, "Closing already closed HDB"); 59 60 (*d->close)(d); 61 db->hdb_db = 0; 62 63 if (db1->lock_fd >= 0) { 64 close(db1->lock_fd); 65 db1->lock_fd = -1; 66 } 67 68 return 0; 69 } 70 71 static krb5_error_code 72 DB_destroy(krb5_context context, HDB *db) 73 { 74 krb5_error_code ret; 75 76 ret = hdb_clear_master_key (context, db); 77 free(db->hdb_name); 78 free(db); 79 return ret; 80 } 81 82 static krb5_error_code 83 DB_set_sync(krb5_context context, HDB *db, int on) 84 { 85 DB1_HDB *db1 = (DB1_HDB *)db; 86 DB *d = (DB*)db->hdb_db; 87 krb5_error_code ret = 0; 88 89 db1->do_sync = on; 90 if (on) { 91 ret = (*d->sync)(d, 0); 92 if (ret == -1) { 93 ret = errno; 94 krb5_set_error_message(context, ret, "Database %s put sync error: %s", 95 db->hdb_name, strerror(ret)); 96 } 97 } 98 return ret; 99 } 100 101 static krb5_error_code 102 DB_lock(krb5_context context, HDB *db, int operation) 103 { 104 105 return 0; 106 } 107 108 static krb5_error_code 109 DB_unlock(krb5_context context, HDB *db) 110 { 111 112 return 0; 113 } 114 115 116 static krb5_error_code 117 DB_seq(krb5_context context, HDB *db, 118 unsigned flags, hdb_entry_ex *entry, int flag) 119 { 120 DB *d = (DB*)db->hdb_db; 121 DBT key, value; 122 krb5_data key_data, data; 123 int code; 124 125 code = (*d->seq)(d, &key, &value, flag); 126 if(code == -1) { 127 code = errno; 128 krb5_set_error_message(context, code, "Database %s seq error: %s", 129 db->hdb_name, strerror(code)); 130 return code; 131 } 132 if(code == 1) { 133 krb5_clear_error_message(context); 134 return HDB_ERR_NOENTRY; 135 } 136 137 key_data.data = key.data; 138 key_data.length = key.size; 139 data.data = value.data; 140 data.length = value.size; 141 memset(entry, 0, sizeof(*entry)); 142 if (hdb_value2entry(context, &data, &entry->entry)) 143 return DB_seq(context, db, flags, entry, R_NEXT); 144 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 145 code = hdb_unseal_keys (context, db, &entry->entry); 146 if (code) 147 hdb_free_entry (context, entry); 148 } 149 if (code == 0 && entry->entry.principal == NULL) { 150 entry->entry.principal = malloc(sizeof(*entry->entry.principal)); 151 if (entry->entry.principal == NULL) { 152 code = ENOMEM; 153 krb5_set_error_message(context, code, "malloc: out of memory"); 154 hdb_free_entry (context, entry); 155 } else { 156 hdb_key2principal(context, &key_data, entry->entry.principal); 157 } 158 } 159 return code; 160 } 161 162 163 static krb5_error_code 164 DB_firstkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 165 { 166 return DB_seq(context, db, flags, entry, R_FIRST); 167 } 168 169 170 static krb5_error_code 171 DB_nextkey(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 172 { 173 return DB_seq(context, db, flags, entry, R_NEXT); 174 } 175 176 static krb5_error_code 177 DB_rename(krb5_context context, HDB *db, const char *new_name) 178 { 179 int ret; 180 char *old, *new; 181 182 if (strncmp(new_name, "db:", sizeof("db:") - 1) == 0) 183 new_name += sizeof("db:") - 1; 184 else if (strncmp(new_name, "db1:", sizeof("db1:") - 1) == 0) 185 new_name += sizeof("db1:") - 1; 186 asprintf(&old, "%s.db", db->hdb_name); 187 asprintf(&new, "%s.db", new_name); 188 ret = rename(old, new); 189 free(old); 190 free(new); 191 if(ret) 192 return errno; 193 194 free(db->hdb_name); 195 db->hdb_name = strdup(new_name); 196 return 0; 197 } 198 199 static krb5_error_code 200 DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) 201 { 202 DB *d = (DB*)db->hdb_db; 203 DBT k, v; 204 int code; 205 206 k.data = key.data; 207 k.size = key.length; 208 code = (*d->get)(d, &k, &v, 0); 209 if(code < 0) { 210 code = errno; 211 krb5_set_error_message(context, code, "Database %s get error: %s", 212 db->hdb_name, strerror(code)); 213 return code; 214 } 215 if(code == 1) { 216 krb5_clear_error_message(context); 217 return HDB_ERR_NOENTRY; 218 } 219 220 krb5_data_copy(reply, v.data, v.size); 221 return 0; 222 } 223 224 static krb5_error_code 225 DB__put(krb5_context context, HDB *db, int replace, 226 krb5_data key, krb5_data value) 227 { 228 DB1_HDB *db1 = (DB1_HDB *)db; 229 DB *d = (DB*)db->hdb_db; 230 DBT k, v; 231 int code; 232 233 k.data = key.data; 234 k.size = key.length; 235 v.data = value.data; 236 v.size = value.length; 237 krb5_clear_error_message(context); 238 code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); 239 if(code < 0) { 240 code = errno; 241 krb5_set_error_message(context, code, "Database %s put error: %s", 242 db->hdb_name, strerror(code)); 243 return code; 244 } 245 if(code == 1) { 246 return HDB_ERR_EXISTS; 247 } 248 249 return db->hdb_set_sync(context, db, db1->do_sync); 250 } 251 252 static krb5_error_code 253 DB__del(krb5_context context, HDB *db, krb5_data key) 254 { 255 DB1_HDB *db1 = (DB1_HDB *)db; 256 DB *d = (DB*)db->hdb_db; 257 DBT k; 258 krb5_error_code code; 259 k.data = key.data; 260 k.size = key.length; 261 krb5_clear_error_message(context); 262 code = (*d->del)(d, &k, 0); 263 if (code == 1) 264 return HDB_ERR_NOENTRY; 265 if (code < 0) { 266 code = errno; 267 krb5_set_error_message(context, code, "Database %s del error: %s", 268 db->hdb_name, strerror(code)); 269 return code; 270 } 271 return db->hdb_set_sync(context, db, db1->do_sync); 272 } 273 274 static DB * 275 _open_db(char *fn, int flags, int mode, int *fd) 276 { 277 #ifndef O_EXLOCK 278 int op; 279 int ret; 280 281 *fd = open(fn, flags, mode); 282 if (*fd == -1) 283 return NULL; 284 285 if ((flags & O_ACCMODE) == O_RDONLY) 286 op = LOCK_SH; 287 else 288 op = LOCK_EX; 289 290 ret = flock(*fd, op); 291 if (ret == -1) { 292 int saved_errno; 293 294 saved_errno = errno; 295 close(*fd); 296 errno = saved_errno; 297 return NULL; 298 } 299 #else 300 if ((flags & O_ACCMODE) == O_RDONLY) 301 flags |= O_SHLOCK; 302 else 303 flags |= O_EXLOCK; 304 #endif 305 306 return dbopen(fn, flags, mode, DB_BTREE, NULL); 307 } 308 309 static krb5_error_code 310 DB_open(krb5_context context, HDB *db, int flags, mode_t mode) 311 { 312 DB1_HDB *db1 = (DB1_HDB *)db; 313 char *fn; 314 krb5_error_code ret; 315 316 asprintf(&fn, "%s.db", db->hdb_name); 317 if (fn == NULL) { 318 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 319 return ENOMEM; 320 } 321 db->hdb_db = _open_db(fn, flags, mode, &db1->lock_fd); 322 free(fn); 323 /* try to open without .db extension */ 324 if(db->hdb_db == NULL && errno == ENOENT) 325 db->hdb_db = _open_db(db->hdb_name, flags, mode, &db1->lock_fd); 326 if(db->hdb_db == NULL) { 327 krb5_set_error_message(context, errno, "dbopen (%s): %s", 328 db->hdb_name, strerror(errno)); 329 return errno; 330 } 331 if((flags & O_ACCMODE) == O_RDONLY) 332 ret = hdb_check_db_format(context, db); 333 else 334 ret = hdb_init_db(context, db); 335 if(ret == HDB_ERR_NOENTRY) { 336 krb5_clear_error_message(context); 337 return 0; 338 } 339 if (ret) { 340 DB_close(context, db); 341 krb5_set_error_message(context, ret, "hdb_open: failed %s database %s", 342 (flags & O_ACCMODE) == O_RDONLY ? 343 "checking format of" : "initialize", 344 db->hdb_name); 345 } 346 return ret; 347 } 348 349 krb5_error_code 350 hdb_db1_create(krb5_context context, HDB **db, 351 const char *filename) 352 { 353 DB1_HDB **db1 = (DB1_HDB **)db; 354 *db = calloc(1, sizeof(**db1)); /* Allocate space for the larger db1 */ 355 if (*db == NULL) { 356 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 357 return ENOMEM; 358 } 359 360 (*db)->hdb_db = NULL; 361 (*db)->hdb_name = strdup(filename); 362 if ((*db)->hdb_name == NULL) { 363 free(*db); 364 *db = NULL; 365 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 366 return ENOMEM; 367 } 368 (*db)->hdb_master_key_set = 0; 369 (*db)->hdb_openp = 0; 370 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL; 371 (*db)->hdb_open = DB_open; 372 (*db)->hdb_close = DB_close; 373 (*db)->hdb_fetch_kvno = _hdb_fetch_kvno; 374 (*db)->hdb_store = _hdb_store; 375 (*db)->hdb_remove = _hdb_remove; 376 (*db)->hdb_firstkey = DB_firstkey; 377 (*db)->hdb_nextkey= DB_nextkey; 378 (*db)->hdb_lock = DB_lock; 379 (*db)->hdb_unlock = DB_unlock; 380 (*db)->hdb_rename = DB_rename; 381 (*db)->hdb__get = DB__get; 382 (*db)->hdb__put = DB__put; 383 (*db)->hdb__del = DB__del; 384 (*db)->hdb_destroy = DB_destroy; 385 (*db)->hdb_set_sync = DB_set_sync; 386 387 (*db1)->lock_fd = -1; 388 (*db1)->do_sync = 1; 389 return 0; 390 } 391 392 #endif /* defined(HAVE_DB1) */ 393