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