1 /* 2 ** Copyright (c) 1999-2003, 2009 Proofpoint, 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: smdb2.c,v 8.83 2013-11-22 20:51:49 ca Exp $") 12 13 #include <fcntl.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 17 18 #include <sendmail/sendmail.h> 19 #include <libsmdb/smdb.h> 20 21 #if (DB_VERSION_MAJOR >= 2) 22 23 struct smdb_db2_database 24 { 25 DB *smdb2_db; 26 int smdb2_lock_fd; 27 }; 28 typedef struct smdb_db2_database SMDB_DB2_DATABASE; 29 30 /* 31 ** SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type. 32 ** 33 ** Parameters: 34 ** type -- The type to translate. 35 ** 36 ** Returns: 37 ** The DB2 type that corresponsds to the passed in SMDB type. 38 ** Returns -1 if there is no equivalent type. 39 ** 40 */ 41 42 static DBTYPE 43 smdb_type_to_db2_type(type) 44 SMDB_DBTYPE type; 45 { 46 if (type == SMDB_TYPE_DEFAULT) 47 return DB_HASH; 48 49 if (SMDB_IS_TYPE_HASH(type)) 50 return DB_HASH; 51 52 if (SMDB_IS_TYPE_BTREE(type)) 53 return DB_BTREE; 54 55 return DB_UNKNOWN; 56 } 57 /* 58 ** DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors 59 ** 60 ** Parameters: 61 ** error -- The error to translate. 62 ** 63 ** Returns: 64 ** The SMDBE error corresponding to the db2 error. 65 ** If we don't have a corresponding error, it returns errno. 66 ** 67 */ 68 69 static int 70 db2_error_to_smdb(error) 71 int error; 72 { 73 int result; 74 75 switch (error) 76 { 77 # ifdef DB_INCOMPLETE 78 case DB_INCOMPLETE: 79 result = SMDBE_INCOMPLETE; 80 break; 81 # endif 82 83 # ifdef DB_NOTFOUND 84 case DB_NOTFOUND: 85 result = SMDBE_NOT_FOUND; 86 break; 87 # endif 88 89 # ifdef DB_KEYEMPTY 90 case DB_KEYEMPTY: 91 result = SMDBE_KEY_EMPTY; 92 break; 93 # endif 94 95 # ifdef DB_KEYEXIST 96 case DB_KEYEXIST: 97 result = SMDBE_KEY_EXIST; 98 break; 99 # endif 100 101 # ifdef DB_LOCK_DEADLOCK 102 case DB_LOCK_DEADLOCK: 103 result = SMDBE_LOCK_DEADLOCK; 104 break; 105 # endif 106 107 # ifdef DB_LOCK_NOTGRANTED 108 case DB_LOCK_NOTGRANTED: 109 result = SMDBE_LOCK_NOT_GRANTED; 110 break; 111 # endif 112 113 # ifdef DB_LOCK_NOTHELD 114 case DB_LOCK_NOTHELD: 115 result = SMDBE_LOCK_NOT_HELD; 116 break; 117 # endif 118 119 # ifdef DB_RUNRECOVERY 120 case DB_RUNRECOVERY: 121 result = SMDBE_RUN_RECOVERY; 122 break; 123 # endif 124 125 # ifdef DB_OLD_VERSION 126 case DB_OLD_VERSION: 127 result = SMDBE_OLD_VERSION; 128 break; 129 # endif 130 131 case 0: 132 result = SMDBE_OK; 133 break; 134 135 default: 136 result = error; 137 } 138 return result; 139 } 140 /* 141 ** SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags. 142 ** 143 ** Parameters: 144 ** flags -- The flags to translate. 145 ** 146 ** Returns: 147 ** The db2 flags that are equivalent to the smdb flags. 148 ** 149 ** Notes: 150 ** Any invalid flags are ignored. 151 ** 152 */ 153 154 static unsigned int 155 smdb_put_flags_to_db2_flags(flags) 156 SMDB_FLAG flags; 157 { 158 int return_flags; 159 160 return_flags = 0; 161 162 if (bitset(SMDBF_NO_OVERWRITE, flags)) 163 return_flags |= DB_NOOVERWRITE; 164 165 return return_flags; 166 } 167 /* 168 ** SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2 169 ** getflags. 170 ** 171 ** Parameters: 172 ** flags -- The flags to translate. 173 ** 174 ** Returns: 175 ** The db2 flags that are equivalent to the smdb flags. 176 ** 177 ** Notes: 178 ** -1 is returned if flag is unknown. 179 ** 180 */ 181 182 static int 183 smdb_cursor_get_flags_to_db2(flags) 184 SMDB_FLAG flags; 185 { 186 switch (flags) 187 { 188 case SMDB_CURSOR_GET_FIRST: 189 return DB_FIRST; 190 191 case SMDB_CURSOR_GET_LAST: 192 return DB_LAST; 193 194 case SMDB_CURSOR_GET_NEXT: 195 return DB_NEXT; 196 197 case SMDB_CURSOR_GET_RANGE: 198 return DB_SET_RANGE; 199 200 default: 201 return -1; 202 } 203 } 204 205 /* 206 ** Except for smdb_db_open, the rest of these functions correspond to the 207 ** interface laid out in smdb.h. 208 */ 209 210 static SMDB_DB2_DATABASE * 211 smdb2_malloc_database() 212 { 213 SMDB_DB2_DATABASE *db2; 214 215 db2 = (SMDB_DB2_DATABASE *) malloc(sizeof(SMDB_DB2_DATABASE)); 216 if (db2 != NULL) 217 db2->smdb2_lock_fd = -1; 218 219 return db2; 220 } 221 222 static int 223 smdb2_close(database) 224 SMDB_DATABASE *database; 225 { 226 int result; 227 SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl; 228 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 229 230 result = db2_error_to_smdb(db->close(db, 0)); 231 if (db2->smdb2_lock_fd != -1) 232 close(db2->smdb2_lock_fd); 233 234 free(db2); 235 database->smdb_impl = NULL; 236 237 return result; 238 } 239 240 static int 241 smdb2_del(database, key, flags) 242 SMDB_DATABASE *database; 243 SMDB_DBENT *key; 244 unsigned int flags; 245 { 246 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 247 DBT dbkey; 248 249 (void) memset(&dbkey, '\0', sizeof dbkey); 250 dbkey.data = key->data; 251 dbkey.size = key->size; 252 return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags)); 253 } 254 255 static int 256 smdb2_fd(database, fd) 257 SMDB_DATABASE *database; 258 int *fd; 259 { 260 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 261 262 return db2_error_to_smdb(db->fd(db, fd)); 263 } 264 265 static int 266 smdb2_lockfd(database) 267 SMDB_DATABASE *database; 268 { 269 SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl; 270 271 return db2->smdb2_lock_fd; 272 } 273 274 static int 275 smdb2_get(database, key, data, flags) 276 SMDB_DATABASE *database; 277 SMDB_DBENT *key; 278 SMDB_DBENT *data; 279 unsigned int flags; 280 { 281 int result; 282 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 283 DBT dbkey, dbdata; 284 285 (void) memset(&dbdata, '\0', sizeof dbdata); 286 (void) memset(&dbkey, '\0', sizeof dbkey); 287 dbkey.data = key->data; 288 dbkey.size = key->size; 289 290 result = db->get(db, NULL, &dbkey, &dbdata, flags); 291 data->data = dbdata.data; 292 data->size = dbdata.size; 293 return db2_error_to_smdb(result); 294 } 295 296 static int 297 smdb2_put(database, key, data, flags) 298 SMDB_DATABASE *database; 299 SMDB_DBENT *key; 300 SMDB_DBENT *data; 301 unsigned int flags; 302 { 303 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 304 DBT dbkey, dbdata; 305 306 (void) memset(&dbdata, '\0', sizeof dbdata); 307 (void) memset(&dbkey, '\0', sizeof dbkey); 308 dbkey.data = key->data; 309 dbkey.size = key->size; 310 dbdata.data = data->data; 311 dbdata.size = data->size; 312 313 return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata, 314 smdb_put_flags_to_db2_flags(flags))); 315 } 316 317 318 static int 319 smdb2_set_owner(database, uid, gid) 320 SMDB_DATABASE *database; 321 uid_t uid; 322 gid_t gid; 323 { 324 # if HASFCHOWN 325 int fd; 326 int result; 327 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 328 329 result = db->fd(db, &fd); 330 if (result != 0) 331 return result; 332 333 result = fchown(fd, uid, gid); 334 if (result < 0) 335 return errno; 336 # endif /* HASFCHOWN */ 337 338 return SMDBE_OK; 339 } 340 341 static int 342 smdb2_sync(database, flags) 343 SMDB_DATABASE *database; 344 unsigned int flags; 345 { 346 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 347 348 return db2_error_to_smdb(db->sync(db, flags)); 349 } 350 351 static int 352 smdb2_cursor_close(cursor) 353 SMDB_CURSOR *cursor; 354 { 355 int ret; 356 DBC *dbc = (DBC *) cursor->smdbc_impl; 357 358 ret = db2_error_to_smdb(dbc->c_close(dbc)); 359 free(cursor); 360 return ret; 361 } 362 363 static int 364 smdb2_cursor_del(cursor, flags) 365 SMDB_CURSOR *cursor; 366 SMDB_FLAG flags; 367 { 368 DBC *dbc = (DBC *) cursor->smdbc_impl; 369 370 return db2_error_to_smdb(dbc->c_del(dbc, 0)); 371 } 372 373 static int 374 smdb2_cursor_get(cursor, key, value, flags) 375 SMDB_CURSOR *cursor; 376 SMDB_DBENT *key; 377 SMDB_DBENT *value; 378 SMDB_FLAG flags; 379 { 380 int db2_flags; 381 int result; 382 DBC *dbc = (DBC *) cursor->smdbc_impl; 383 DBT dbkey, dbdata; 384 385 (void) memset(&dbdata, '\0', sizeof dbdata); 386 (void) memset(&dbkey, '\0', sizeof dbkey); 387 388 db2_flags = smdb_cursor_get_flags_to_db2(flags); 389 result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags); 390 if (result == DB_NOTFOUND) 391 return SMDBE_LAST_ENTRY; 392 key->data = dbkey.data; 393 key->size = dbkey.size; 394 value->data = dbdata.data; 395 value->size = dbdata.size; 396 return db2_error_to_smdb(result); 397 } 398 399 static int 400 smdb2_cursor_put(cursor, key, value, flags) 401 SMDB_CURSOR *cursor; 402 SMDB_DBENT *key; 403 SMDB_DBENT *value; 404 SMDB_FLAG flags; 405 { 406 DBC *dbc = (DBC *) cursor->smdbc_impl; 407 DBT dbkey, dbdata; 408 409 (void) memset(&dbdata, '\0', sizeof dbdata); 410 (void) memset(&dbkey, '\0', sizeof dbkey); 411 dbkey.data = key->data; 412 dbkey.size = key->size; 413 dbdata.data = value->data; 414 dbdata.size = value->size; 415 416 return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0)); 417 } 418 419 static int 420 smdb2_cursor(database, cursor, flags) 421 SMDB_DATABASE *database; 422 SMDB_CURSOR **cursor; 423 SMDB_FLAG flags; 424 { 425 int result; 426 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 427 DBC *db2_cursor; 428 429 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 430 result = db->cursor(db, NULL, &db2_cursor, 0); 431 # else 432 result = db->cursor(db, NULL, &db2_cursor); 433 # endif 434 if (result != 0) 435 return db2_error_to_smdb(result); 436 437 *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR)); 438 if (*cursor == NULL) 439 return SMDBE_MALLOC; 440 441 (*cursor)->smdbc_close = smdb2_cursor_close; 442 (*cursor)->smdbc_del = smdb2_cursor_del; 443 (*cursor)->smdbc_get = smdb2_cursor_get; 444 (*cursor)->smdbc_put = smdb2_cursor_put; 445 (*cursor)->smdbc_impl = db2_cursor; 446 447 return SMDBE_OK; 448 } 449 450 # if DB_VERSION_MAJOR == 2 451 static int 452 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db) 453 char *db_name; 454 DBTYPE db_type; 455 int db_flags; 456 SMDB_DBPARAMS *db_params; 457 DB **db; 458 { 459 void *params; 460 DB_INFO db_info; 461 462 params = NULL; 463 (void) memset(&db_info, '\0', sizeof db_info); 464 if (db_params != NULL) 465 { 466 db_info.db_cachesize = db_params->smdbp_cache_size; 467 if (db_type == DB_HASH) 468 db_info.h_nelem = db_params->smdbp_num_elements; 469 if (db_params->smdbp_allow_dup) 470 db_info.flags |= DB_DUP; 471 params = &db_info; 472 } 473 return db_open(db_name, db_type, db_flags, DBMMODE, NULL, params, db); 474 } 475 # endif /* DB_VERSION_MAJOR == 2 */ 476 477 # if DB_VERSION_MAJOR > 2 478 479 static void 480 db_err_cb( 481 # if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3 482 dbenv, 483 # endif 484 errpfx, msg) 485 # if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3 486 const DB_ENV *dbenv; 487 const char *errpfx; 488 const char *msg; 489 # else 490 const char *errpfx; 491 char *msg; 492 # endif 493 { 494 /* do not print/log any errors... */ 495 return; 496 } 497 498 static int 499 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db) 500 char *db_name; 501 DBTYPE db_type; 502 int db_flags; 503 SMDB_DBPARAMS *db_params; 504 DB **db; 505 { 506 int result; 507 508 result = db_create(db, NULL, 0); 509 if (result != 0 || *db == NULL) 510 return result; 511 512 (*db)->set_errcall(*db, db_err_cb); 513 if (db_params != NULL) 514 { 515 result = (*db)->set_cachesize(*db, 0, 516 db_params->smdbp_cache_size, 0); 517 if (result != 0) 518 goto error; 519 if (db_type == DB_HASH) 520 { 521 result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements); 522 if (result != 0) 523 goto error; 524 } 525 if (db_params->smdbp_allow_dup) 526 { 527 result = (*db)->set_flags(*db, DB_DUP); 528 if (result != 0) 529 goto error; 530 } 531 } 532 533 result = (*db)->open(*db, 534 DBTXN /* transaction for DB 4.1 */ 535 db_name, NULL, db_type, db_flags, DBMMODE); 536 error: 537 if (result != 0) 538 { 539 (void) (*db)->close(*db, 0); 540 *db = NULL; 541 } 542 return db2_error_to_smdb(result); 543 } 544 # endif /* DB_VERSION_MAJOR > 2 */ 545 546 /* 547 ** SMDB_DB_OPEN -- Opens a db database. 548 ** 549 ** Parameters: 550 ** database -- An unallocated database pointer to a pointer. 551 ** db_name -- The name of the database without extension. 552 ** mode -- File permissions for a created database. 553 ** mode_mask -- Mode bits that must match on an opened database. 554 ** sff -- Flags for safefile. 555 ** type -- The type of database to open 556 ** See smdb_type_to_db2_type for valid types. 557 ** user_info -- User information for file permissions. 558 ** db_params -- 559 ** An SMDB_DBPARAMS struct including params. These 560 ** are processed according to the type of the 561 ** database. Currently supported params (only for 562 ** HASH type) are: 563 ** num_elements 564 ** cache_size 565 ** 566 ** Returns: 567 ** SMDBE_OK -- Success, other errno: 568 ** SMDBE_MALLOC -- Cannot allocate memory. 569 ** SMDBE_BAD_OPEN -- db_open didn't return an error, but 570 ** somehow the DB pointer is NULL. 571 ** Anything else: translated error from db2 572 */ 573 574 int 575 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params) 576 SMDB_DATABASE **database; 577 char *db_name; 578 int mode; 579 int mode_mask; 580 long sff; 581 SMDB_DBTYPE type; 582 SMDB_USER_INFO *user_info; 583 SMDB_DBPARAMS *db_params; 584 { 585 bool lockcreated = false; 586 int result; 587 int db_flags; 588 int lock_fd; 589 int db_fd; 590 int major_v, minor_v, patch_v; 591 SMDB_DATABASE *smdb_db; 592 SMDB_DB2_DATABASE *db2; 593 DB *db; 594 DBTYPE db_type; 595 struct stat stat_info; 596 char db_file_name[MAXPATHLEN]; 597 598 (void) db_version(&major_v, &minor_v, &patch_v); 599 if (major_v != DB_VERSION_MAJOR || minor_v != DB_VERSION_MINOR) 600 return SMDBE_VERSION_MISMATCH; 601 602 *database = NULL; 603 604 result = smdb_add_extension(db_file_name, sizeof db_file_name, 605 db_name, SMDB2_FILE_EXTENSION); 606 if (result != SMDBE_OK) 607 return result; 608 609 result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION, 610 mode_mask, sff, user_info, &stat_info); 611 if (result != SMDBE_OK) 612 return result; 613 614 lock_fd = -1; 615 616 if (stat_info.st_mode == ST_MODE_NOFILE && 617 bitset(mode, O_CREAT)) 618 lockcreated = true; 619 620 result = smdb_lock_file(&lock_fd, db_name, mode, sff, 621 SMDB2_FILE_EXTENSION); 622 if (result != SMDBE_OK) 623 return result; 624 625 if (lockcreated) 626 { 627 mode |= O_TRUNC; 628 mode &= ~(O_CREAT|O_EXCL); 629 } 630 631 smdb_db = smdb_malloc_database(); 632 db2 = smdb2_malloc_database(); 633 if (db2 == NULL || smdb_db == NULL) 634 { 635 smdb_unlock_file(lock_fd); 636 smdb_free_database(smdb_db); /* ok to be NULL */ 637 if (db2 != NULL) 638 free(db2); 639 return SMDBE_MALLOC; 640 } 641 642 db2->smdb2_lock_fd = lock_fd; 643 644 db_type = smdb_type_to_db2_type(type); 645 646 db = NULL; 647 648 db_flags = 0; 649 if (bitset(O_CREAT, mode)) 650 db_flags |= DB_CREATE; 651 if (bitset(O_TRUNC, mode)) 652 db_flags |= DB_TRUNCATE; 653 if (mode == O_RDONLY) 654 db_flags |= DB_RDONLY; 655 SM_DB_FLAG_ADD(db_flags); 656 657 result = smdb_db_open_internal(db_file_name, db_type, 658 db_flags, db_params, &db); 659 660 if (result == 0 && db != NULL) 661 { 662 result = db->fd(db, &db_fd); 663 if (result == 0) 664 result = SMDBE_OK; 665 } 666 else 667 { 668 /* Try and narrow down on the problem */ 669 if (result != 0) 670 result = db2_error_to_smdb(result); 671 else 672 result = SMDBE_BAD_OPEN; 673 } 674 675 if (result == SMDBE_OK) 676 result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd, 677 &stat_info); 678 679 if (result == SMDBE_OK) 680 { 681 /* Everything is ok. Setup driver */ 682 db2->smdb2_db = db; 683 684 smdb_db->smdb_close = smdb2_close; 685 smdb_db->smdb_del = smdb2_del; 686 smdb_db->smdb_fd = smdb2_fd; 687 smdb_db->smdb_lockfd = smdb2_lockfd; 688 smdb_db->smdb_get = smdb2_get; 689 smdb_db->smdb_put = smdb2_put; 690 smdb_db->smdb_set_owner = smdb2_set_owner; 691 smdb_db->smdb_sync = smdb2_sync; 692 smdb_db->smdb_cursor = smdb2_cursor; 693 smdb_db->smdb_impl = db2; 694 695 *database = smdb_db; 696 697 return SMDBE_OK; 698 } 699 700 if (db != NULL) 701 db->close(db, 0); 702 703 smdb_unlock_file(db2->smdb2_lock_fd); 704 free(db2); 705 smdb_free_database(smdb_db); 706 707 return result; 708 } 709 710 #endif /* (DB_VERSION_MAJOR >= 2) */ 711