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