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