1 /* 2 ** Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. 3 ** All rights reserved. 4 ** 5 ** By using this file, you agree to the terms and conditions set 6 ** forth in the LICENSE file which can be found at the top level of 7 ** the sendmail distribution. 8 */ 9 10 #include <sm/gen.h> 11 SM_RCSID("@(#)$Id: smdb1.c,v 8.58 2002/05/24 23:09:11 gshapiro Exp $") 12 13 #include <unistd.h> 14 #include <stdlib.h> 15 #include <fcntl.h> 16 17 #include <sendmail/sendmail.h> 18 #include <libsmdb/smdb.h> 19 20 #if (DB_VERSION_MAJOR == 1) 21 22 # define SMDB1_FILE_EXTENSION "db" 23 24 struct smdb_db1_struct 25 { 26 DB *smdb1_db; 27 int smdb1_lock_fd; 28 bool smdb1_cursor_in_use; 29 }; 30 typedef struct smdb_db1_struct SMDB_DB1_DATABASE; 31 32 struct smdb_db1_cursor 33 { 34 SMDB_DB1_DATABASE *db; 35 }; 36 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR; 37 38 /* 39 ** SMDB_TYPE_TO_DB1_TYPE -- Translates smdb database type to db1 type. 40 ** 41 ** Parameters: 42 ** type -- The type to translate. 43 ** 44 ** Returns: 45 ** The DB1 type that corresponsds to the passed in SMDB type. 46 ** Returns -1 if there is no equivalent type. 47 ** 48 */ 49 50 DBTYPE 51 smdb_type_to_db1_type(type) 52 SMDB_DBTYPE type; 53 { 54 if (type == SMDB_TYPE_DEFAULT) 55 return DB_HASH; 56 57 if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0) 58 return DB_HASH; 59 60 if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0) 61 return DB_BTREE; 62 63 /* Should never get here thanks to test in smdb_db_open() */ 64 return DB_HASH; 65 } 66 /* 67 ** SMDB_PUT_FLAGS_TO_DB1_FLAGS -- Translates smdb put flags to db1 put flags. 68 ** 69 ** Parameters: 70 ** flags -- The flags to translate. 71 ** 72 ** Returns: 73 ** The db1 flags that are equivalent to the smdb flags. 74 ** 75 ** Notes: 76 ** Any invalid flags are ignored. 77 ** 78 */ 79 80 unsigned int 81 smdb_put_flags_to_db1_flags(flags) 82 SMDB_FLAG flags; 83 { 84 int return_flags; 85 86 return_flags = 0; 87 88 if (bitset(SMDBF_NO_OVERWRITE, flags)) 89 return_flags |= R_NOOVERWRITE; 90 91 return return_flags; 92 } 93 /* 94 ** SMDB_CURSOR_GET_FLAGS_TO_SMDB1 95 ** 96 ** Parameters: 97 ** flags -- The flags to translate. 98 ** 99 ** Returns: 100 ** The db1 flags that are equivalent to the smdb flags. 101 ** 102 ** Notes: 103 ** Returns -1 if we don't support the flag. 104 ** 105 */ 106 107 int 108 smdb_cursor_get_flags_to_smdb1(flags) 109 SMDB_FLAG flags; 110 { 111 switch(flags) 112 { 113 case SMDB_CURSOR_GET_FIRST: 114 return R_FIRST; 115 116 case SMDB_CURSOR_GET_LAST: 117 return R_LAST; 118 119 case SMDB_CURSOR_GET_NEXT: 120 return R_NEXT; 121 122 case SMDB_CURSOR_GET_RANGE: 123 return R_CURSOR; 124 125 default: 126 return -1; 127 } 128 } 129 130 /* 131 ** The rest of these functions correspond to the interface laid out in smdb.h. 132 */ 133 134 SMDB_DB1_DATABASE * 135 smdb1_malloc_database() 136 { 137 SMDB_DB1_DATABASE *db1; 138 139 db1 = (SMDB_DB1_DATABASE *) malloc(sizeof(SMDB_DB1_DATABASE)); 140 141 if (db1 != NULL) 142 { 143 db1->smdb1_lock_fd = -1; 144 db1->smdb1_cursor_in_use = false; 145 } 146 147 return db1; 148 } 149 150 int 151 smdb1_close(database) 152 SMDB_DATABASE *database; 153 { 154 int result; 155 SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; 156 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 157 158 result = db->close(db); 159 if (db1->smdb1_lock_fd != -1) 160 (void) close(db1->smdb1_lock_fd); 161 162 free(db1); 163 database->smdb_impl = NULL; 164 165 return result; 166 } 167 168 int 169 smdb1_del(database, key, flags) 170 SMDB_DATABASE *database; 171 SMDB_DBENT *key; 172 unsigned int flags; 173 { 174 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 175 DBT dbkey; 176 177 (void) memset(&dbkey, '\0', sizeof dbkey); 178 dbkey.data = key->data; 179 dbkey.size = key->size; 180 return db->del(db, &dbkey, flags); 181 } 182 183 int 184 smdb1_fd(database, fd) 185 SMDB_DATABASE *database; 186 int *fd; 187 { 188 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 189 190 *fd = db->fd(db); 191 if (*fd == -1) 192 return errno; 193 194 return SMDBE_OK; 195 } 196 197 int 198 smdb1_lockfd(database) 199 SMDB_DATABASE *database; 200 { 201 SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; 202 203 return db1->smdb1_lock_fd; 204 } 205 206 207 int 208 smdb1_get(database, key, data, flags) 209 SMDB_DATABASE *database; 210 SMDB_DBENT *key; 211 SMDB_DBENT *data; 212 unsigned int flags; 213 { 214 int result; 215 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 216 DBT dbkey, dbdata; 217 218 (void) memset(&dbdata, '\0', sizeof dbdata); 219 (void) memset(&dbkey, '\0', sizeof dbkey); 220 dbkey.data = key->data; 221 dbkey.size = key->size; 222 223 result = db->get(db, &dbkey, &dbdata, flags); 224 if (result != 0) 225 { 226 if (result == 1) 227 return SMDBE_NOT_FOUND; 228 return errno; 229 } 230 data->data = dbdata.data; 231 data->size = dbdata.size; 232 return SMDBE_OK; 233 } 234 235 int 236 smdb1_put(database, key, data, flags) 237 SMDB_DATABASE *database; 238 SMDB_DBENT *key; 239 SMDB_DBENT *data; 240 unsigned int flags; 241 { 242 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 243 DBT dbkey, dbdata; 244 245 (void) memset(&dbdata, '\0', sizeof dbdata); 246 (void) memset(&dbkey, '\0', sizeof dbkey); 247 dbkey.data = key->data; 248 dbkey.size = key->size; 249 dbdata.data = data->data; 250 dbdata.size = data->size; 251 252 return db->put(db, &dbkey, &dbdata, 253 smdb_put_flags_to_db1_flags(flags)); 254 } 255 256 int 257 smdb1_set_owner(database, uid, gid) 258 SMDB_DATABASE *database; 259 uid_t uid; 260 gid_t gid; 261 { 262 # if HASFCHOWN 263 int fd; 264 int result; 265 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 266 267 fd = db->fd(db); 268 if (fd == -1) 269 return errno; 270 271 result = fchown(fd, uid, gid); 272 if (result < 0) 273 return errno; 274 # endif /* HASFCHOWN */ 275 276 return SMDBE_OK; 277 } 278 279 int 280 smdb1_sync(database, flags) 281 SMDB_DATABASE *database; 282 unsigned int flags; 283 { 284 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 285 286 return db->sync(db, flags); 287 } 288 289 int 290 smdb1_cursor_close(cursor) 291 SMDB_CURSOR *cursor; 292 { 293 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 294 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 295 296 if (!db1->smdb1_cursor_in_use) 297 return SMDBE_NOT_A_VALID_CURSOR; 298 299 db1->smdb1_cursor_in_use = false; 300 free(cursor); 301 302 return SMDBE_OK; 303 } 304 305 int 306 smdb1_cursor_del(cursor, flags) 307 SMDB_CURSOR *cursor; 308 unsigned int flags; 309 { 310 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 311 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 312 DB *db = db1->smdb1_db; 313 314 return db->del(db, NULL, R_CURSOR); 315 } 316 317 int 318 smdb1_cursor_get(cursor, key, value, flags) 319 SMDB_CURSOR *cursor; 320 SMDB_DBENT *key; 321 SMDB_DBENT *value; 322 SMDB_FLAG flags; 323 { 324 int db1_flags; 325 int result; 326 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 327 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 328 DB *db = db1->smdb1_db; 329 DBT dbkey, dbdata; 330 331 (void) memset(&dbdata, '\0', sizeof dbdata); 332 (void) memset(&dbkey, '\0', sizeof dbkey); 333 334 db1_flags = smdb_cursor_get_flags_to_smdb1(flags); 335 result = db->seq(db, &dbkey, &dbdata, db1_flags); 336 if (result == -1) 337 return errno; 338 if (result == 1) 339 return SMDBE_LAST_ENTRY; 340 value->data = dbdata.data; 341 value->size = dbdata.size; 342 key->data = dbkey.data; 343 key->size = dbkey.size; 344 return SMDBE_OK; 345 } 346 347 int 348 smdb1_cursor_put(cursor, key, value, flags) 349 SMDB_CURSOR *cursor; 350 SMDB_DBENT *key; 351 SMDB_DBENT *value; 352 SMDB_FLAG flags; 353 { 354 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 355 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 356 DB *db = db1->smdb1_db; 357 DBT dbkey, dbdata; 358 359 (void) memset(&dbdata, '\0', sizeof dbdata); 360 (void) memset(&dbkey, '\0', sizeof dbkey); 361 dbkey.data = key->data; 362 dbkey.size = key->size; 363 dbdata.data = value->data; 364 dbdata.size = value->size; 365 366 return db->put(db, &dbkey, &dbdata, R_CURSOR); 367 } 368 369 int 370 smdb1_cursor(database, cursor, flags) 371 SMDB_DATABASE *database; 372 SMDB_CURSOR **cursor; 373 unsigned int flags; 374 { 375 SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; 376 SMDB_CURSOR *cur; 377 SMDB_DB1_CURSOR *db1_cursor; 378 379 if (db1->smdb1_cursor_in_use) 380 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR; 381 382 db1->smdb1_cursor_in_use = true; 383 db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR)); 384 db1_cursor->db = db1; 385 386 cur = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR)); 387 388 if (cur == NULL) 389 return SMDBE_MALLOC; 390 391 cur->smdbc_impl = db1_cursor; 392 cur->smdbc_close = smdb1_cursor_close; 393 cur->smdbc_del = smdb1_cursor_del; 394 cur->smdbc_get = smdb1_cursor_get; 395 cur->smdbc_put = smdb1_cursor_put; 396 *cursor = cur; 397 398 return SMDBE_OK; 399 } 400 /* 401 ** SMDB_DB_OPEN -- Opens a db1 database. 402 ** 403 ** Parameters: 404 ** database -- An unallocated database pointer to a pointer. 405 ** db_name -- The name of the database without extension. 406 ** mode -- File permisions on the database if created. 407 ** mode_mask -- Mode bits that must match on an existing database. 408 ** sff -- Flags for safefile. 409 ** type -- The type of database to open 410 ** See smdb_type_to_db1_type for valid types. 411 ** user_info -- Information on the user to use for file 412 ** permissions. 413 ** db_params -- 414 ** An SMDB_DBPARAMS struct including params. These 415 ** are processed according to the type of the 416 ** database. Currently supported params (only for 417 ** HASH type) are: 418 ** num_elements 419 ** cache_size 420 ** 421 ** Returns: 422 ** SMDBE_OK -- Success, otherwise errno. 423 */ 424 425 int 426 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, 427 db_params) 428 SMDB_DATABASE **database; 429 char *db_name; 430 int mode; 431 int mode_mask; 432 long sff; 433 SMDB_DBTYPE type; 434 SMDB_USER_INFO *user_info; 435 SMDB_DBPARAMS *db_params; 436 { 437 bool lockcreated = false; 438 int db_fd; 439 int lock_fd; 440 int result; 441 void *params; 442 SMDB_DATABASE *smdb_db; 443 SMDB_DB1_DATABASE *db1; 444 DB *db; 445 HASHINFO hash_info; 446 BTREEINFO btree_info; 447 DBTYPE db_type; 448 struct stat stat_info; 449 char db_file_name[MAXPATHLEN]; 450 451 if (type == NULL || 452 (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) != 0 && 453 strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) != 0)) 454 return SMDBE_UNKNOWN_DB_TYPE; 455 456 result = smdb_add_extension(db_file_name, sizeof db_file_name, 457 db_name, SMDB1_FILE_EXTENSION); 458 if (result != SMDBE_OK) 459 return result; 460 461 result = smdb_setup_file(db_name, SMDB1_FILE_EXTENSION, mode_mask, 462 sff, user_info, &stat_info); 463 if (result != SMDBE_OK) 464 return result; 465 466 if (stat_info.st_mode == ST_MODE_NOFILE && 467 bitset(mode, O_CREAT)) 468 lockcreated = true; 469 470 lock_fd = -1; 471 result = smdb_lock_file(&lock_fd, db_name, mode, sff, 472 SMDB1_FILE_EXTENSION); 473 if (result != SMDBE_OK) 474 return result; 475 476 if (lockcreated) 477 { 478 mode |= O_TRUNC; 479 mode &= ~(O_CREAT|O_EXCL); 480 } 481 482 *database = NULL; 483 484 smdb_db = smdb_malloc_database(); 485 db1 = smdb1_malloc_database(); 486 if (smdb_db == NULL || db1 == NULL) 487 return SMDBE_MALLOC; 488 db1->smdb1_lock_fd = lock_fd; 489 490 params = NULL; 491 if (db_params != NULL && 492 (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) == 0)) 493 { 494 (void) memset(&hash_info, '\0', sizeof hash_info); 495 hash_info.nelem = db_params->smdbp_num_elements; 496 hash_info.cachesize = db_params->smdbp_cache_size; 497 params = &hash_info; 498 } 499 500 if (db_params != NULL && 501 (strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) == 0)) 502 { 503 (void) memset(&btree_info, '\0', sizeof btree_info); 504 btree_info.cachesize = db_params->smdbp_cache_size; 505 if (db_params->smdbp_allow_dup) 506 btree_info.flags |= R_DUP; 507 params = &btree_info; 508 } 509 510 db_type = smdb_type_to_db1_type(type); 511 db = dbopen(db_file_name, mode, DBMMODE, db_type, params); 512 if (db != NULL) 513 { 514 db_fd = db->fd(db); 515 result = smdb_filechanged(db_name, SMDB1_FILE_EXTENSION, db_fd, 516 &stat_info); 517 } 518 else 519 { 520 if (errno == 0) 521 result = SMDBE_BAD_OPEN; 522 else 523 result = errno; 524 } 525 526 if (result == SMDBE_OK) 527 { 528 /* Everything is ok. Setup driver */ 529 db1->smdb1_db = db; 530 531 smdb_db->smdb_close = smdb1_close; 532 smdb_db->smdb_del = smdb1_del; 533 smdb_db->smdb_fd = smdb1_fd; 534 smdb_db->smdb_lockfd = smdb1_lockfd; 535 smdb_db->smdb_get = smdb1_get; 536 smdb_db->smdb_put = smdb1_put; 537 smdb_db->smdb_set_owner = smdb1_set_owner; 538 smdb_db->smdb_sync = smdb1_sync; 539 smdb_db->smdb_cursor = smdb1_cursor; 540 smdb_db->smdb_impl = db1; 541 542 *database = smdb_db; 543 return SMDBE_OK; 544 } 545 546 if (db != NULL) 547 (void) db->close(db); 548 549 /* Error opening database */ 550 (void) smdb_unlock_file(db1->smdb1_lock_fd); 551 free(db1); 552 smdb_free_database(smdb_db); 553 554 return result; 555 } 556 557 #endif /* (DB_VERSION_MAJOR == 1) */ 558