1 /* 2 ** Copyright (c) 1999-2002 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.59 2004/08/03 20:58:39 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->smdb1_cursor_in_use = true; 401 db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR)); 402 db1_cursor->db = db1; 403 404 cur = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR)); 405 406 if (cur == NULL) 407 return SMDBE_MALLOC; 408 409 cur->smdbc_impl = db1_cursor; 410 cur->smdbc_close = smdb1_cursor_close; 411 cur->smdbc_del = smdb1_cursor_del; 412 cur->smdbc_get = smdb1_cursor_get; 413 cur->smdbc_put = smdb1_cursor_put; 414 *cursor = cur; 415 416 return SMDBE_OK; 417 } 418 /* 419 ** SMDB_DB_OPEN -- Opens a db1 database. 420 ** 421 ** Parameters: 422 ** database -- An unallocated database pointer to a pointer. 423 ** db_name -- The name of the database without extension. 424 ** mode -- File permisions on the database if created. 425 ** mode_mask -- Mode bits that must match on an existing database. 426 ** sff -- Flags for safefile. 427 ** type -- The type of database to open 428 ** See smdb_type_to_db1_type for valid types. 429 ** user_info -- Information on the user to use for file 430 ** permissions. 431 ** db_params -- 432 ** An SMDB_DBPARAMS struct including params. These 433 ** are processed according to the type of the 434 ** database. Currently supported params (only for 435 ** HASH type) are: 436 ** num_elements 437 ** cache_size 438 ** 439 ** Returns: 440 ** SMDBE_OK -- Success, otherwise errno. 441 */ 442 443 int 444 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, 445 db_params) 446 SMDB_DATABASE **database; 447 char *db_name; 448 int mode; 449 int mode_mask; 450 long sff; 451 SMDB_DBTYPE type; 452 SMDB_USER_INFO *user_info; 453 SMDB_DBPARAMS *db_params; 454 { 455 bool lockcreated = false; 456 int db_fd; 457 int lock_fd; 458 int result; 459 void *params; 460 SMDB_DATABASE *smdb_db; 461 SMDB_DB1_DATABASE *db1; 462 DB *db; 463 HASHINFO hash_info; 464 BTREEINFO btree_info; 465 DBTYPE db_type; 466 struct stat stat_info; 467 char db_file_name[MAXPATHLEN]; 468 469 if (type == NULL || 470 (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) != 0 && 471 strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) != 0)) 472 return SMDBE_UNKNOWN_DB_TYPE; 473 474 result = smdb_add_extension(db_file_name, sizeof db_file_name, 475 db_name, SMDB1_FILE_EXTENSION); 476 if (result != SMDBE_OK) 477 return result; 478 479 result = smdb_setup_file(db_name, SMDB1_FILE_EXTENSION, mode_mask, 480 sff, user_info, &stat_info); 481 if (result != SMDBE_OK) 482 return result; 483 484 if (stat_info.st_mode == ST_MODE_NOFILE && 485 bitset(mode, O_CREAT)) 486 lockcreated = true; 487 488 lock_fd = -1; 489 result = smdb_lock_file(&lock_fd, db_name, mode, sff, 490 SMDB1_FILE_EXTENSION); 491 if (result != SMDBE_OK) 492 return result; 493 494 if (lockcreated) 495 { 496 mode |= O_TRUNC; 497 mode &= ~(O_CREAT|O_EXCL); 498 } 499 500 *database = NULL; 501 502 smdb_db = smdb_malloc_database(); 503 db1 = smdb1_malloc_database(); 504 if (smdb_db == NULL || db1 == NULL) 505 return SMDBE_MALLOC; 506 db1->smdb1_lock_fd = lock_fd; 507 508 params = NULL; 509 if (db_params != NULL && 510 (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) == 0)) 511 { 512 (void) memset(&hash_info, '\0', sizeof hash_info); 513 hash_info.nelem = db_params->smdbp_num_elements; 514 hash_info.cachesize = db_params->smdbp_cache_size; 515 params = &hash_info; 516 } 517 518 if (db_params != NULL && 519 (strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) == 0)) 520 { 521 (void) memset(&btree_info, '\0', sizeof btree_info); 522 btree_info.cachesize = db_params->smdbp_cache_size; 523 if (db_params->smdbp_allow_dup) 524 btree_info.flags |= R_DUP; 525 params = &btree_info; 526 } 527 528 db_type = smdb_type_to_db1_type(type); 529 db = dbopen(db_file_name, mode, DBMMODE, db_type, params); 530 if (db != NULL) 531 { 532 db_fd = db->fd(db); 533 result = smdb_filechanged(db_name, SMDB1_FILE_EXTENSION, db_fd, 534 &stat_info); 535 } 536 else 537 { 538 if (errno == 0) 539 result = SMDBE_BAD_OPEN; 540 else 541 result = errno; 542 } 543 544 if (result == SMDBE_OK) 545 { 546 /* Everything is ok. Setup driver */ 547 db1->smdb1_db = db; 548 549 smdb_db->smdb_close = smdb1_close; 550 smdb_db->smdb_del = smdb1_del; 551 smdb_db->smdb_fd = smdb1_fd; 552 smdb_db->smdb_lockfd = smdb1_lockfd; 553 smdb_db->smdb_get = smdb1_get; 554 smdb_db->smdb_put = smdb1_put; 555 smdb_db->smdb_set_owner = smdb1_set_owner; 556 smdb_db->smdb_sync = smdb1_sync; 557 smdb_db->smdb_cursor = smdb1_cursor; 558 smdb_db->smdb_impl = db1; 559 560 *database = smdb_db; 561 return SMDBE_OK; 562 } 563 564 if (db != NULL) 565 (void) db->close(db); 566 567 /* Error opening database */ 568 (void) smdb_unlock_file(db1->smdb1_lock_fd); 569 free(db1); 570 smdb_free_database(smdb_db); 571 572 return result; 573 } 574 575 #endif /* (DB_VERSION_MAJOR == 1) */ 576