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> 11 SM_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 struct smdb_db1_struct 23 { 24 DB *smdb1_db; 25 int smdb1_lock_fd; 26 bool smdb1_cursor_in_use; 27 }; 28 typedef struct smdb_db1_struct SMDB_DB1_DATABASE; 29 30 struct smdb_db1_cursor 31 { 32 SMDB_DB1_DATABASE *db; 33 }; 34 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR; 35 36 static DBTYPE smdb_type_to_db1_type __P((SMDB_DBTYPE)); 37 static unsigned int smdb_put_flags_to_db1_flags __P((SMDB_FLAG)); 38 static int smdb_cursor_get_flags_to_smdb1 __P((SMDB_FLAG)); 39 static SMDB_DB1_DATABASE *smdb1_malloc_database __P((void)); 40 static int smdb1_close __P((SMDB_DATABASE *)); 41 static int smdb1_del __P((SMDB_DATABASE *, SMDB_DBENT *, unsigned int)); 42 static int smdb1_fd __P((SMDB_DATABASE *, int *)); 43 static int smdb1_lockfd __P((SMDB_DATABASE *)); 44 static int smdb1_get __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int)); 45 static int smdb1_put __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int)); 46 static int smdb1_set_owner __P((SMDB_DATABASE *, uid_t, gid_t)); 47 static int smdb1_sync __P((SMDB_DATABASE *, unsigned int)); 48 static int smdb1_cursor_close __P((SMDB_CURSOR *)); 49 static int smdb1_cursor_del __P((SMDB_CURSOR *, unsigned int)); 50 static int smdb1_cursor_get __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG)); 51 static int smdb1_cursor_put __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG)); 52 static 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 66 static DBTYPE 67 smdb_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 96 static unsigned int 97 smdb_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 123 static int 124 smdb_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 150 static SMDB_DB1_DATABASE * 151 smdb1_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 166 static int 167 smdb1_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 184 static int 185 smdb1_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 199 static int 200 smdb1_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 213 static int 214 smdb1_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 223 static int 224 smdb1_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 251 static int 252 smdb1_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 272 static int 273 smdb1_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 295 static int 296 smdb1_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 305 static int 306 smdb1_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 321 static int 322 smdb1_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 333 static int 334 smdb1_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 363 static int 364 smdb1_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 385 static int 386 smdb1_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 permissions 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 445 int 446 smdb_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