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