smdb1.c revision 266692
1/* 2** Copyright (c) 1999-2002, 2004, 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> 11SM_RCSID("@(#)$Id: smdb1.c,v 8.63 2013-11-22 20:51:49 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 24struct smdb_db1_struct 25{ 26 DB *smdb1_db; 27 int smdb1_lock_fd; 28 bool smdb1_cursor_in_use; 29}; 30typedef struct smdb_db1_struct SMDB_DB1_DATABASE; 31 32struct smdb_db1_cursor 33{ 34 SMDB_DB1_DATABASE *db; 35}; 36typedef struct smdb_db1_cursor SMDB_DB1_CURSOR; 37 38static DBTYPE smdb_type_to_db1_type __P((SMDB_DBTYPE)); 39static unsigned int smdb_put_flags_to_db1_flags __P((SMDB_FLAG)); 40static int smdb_cursor_get_flags_to_smdb1 __P((SMDB_FLAG)); 41static SMDB_DB1_DATABASE *smdb1_malloc_database __P((void)); 42static int smdb1_close __P((SMDB_DATABASE *)); 43static int smdb1_del __P((SMDB_DATABASE *, SMDB_DBENT *, unsigned int)); 44static int smdb1_fd __P((SMDB_DATABASE *, int *)); 45static int smdb1_lockfd __P((SMDB_DATABASE *)); 46static int smdb1_get __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int)); 47static int smdb1_put __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int)); 48static int smdb1_set_owner __P((SMDB_DATABASE *, uid_t, gid_t)); 49static int smdb1_sync __P((SMDB_DATABASE *, unsigned int)); 50static int smdb1_cursor_close __P((SMDB_CURSOR *)); 51static int smdb1_cursor_del __P((SMDB_CURSOR *, unsigned int)); 52static int smdb1_cursor_get __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG)); 53static int smdb1_cursor_put __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG)); 54static 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 68static DBTYPE 69smdb_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 98static unsigned int 99smdb_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 125static int 126smdb_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 152static SMDB_DB1_DATABASE * 153smdb1_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 168static int 169smdb1_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 186static int 187smdb1_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 201static int 202smdb1_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 215static int 216smdb1_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 225static int 226smdb1_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 253static int 254smdb1_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 274static int 275smdb1_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 297static int 298smdb1_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 307static int 308smdb1_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 323static int 324smdb1_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 335static int 336smdb1_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 365static int 366smdb1_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 387static int 388smdb1_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 447int 448smdb_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