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 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #include <sm/gen.h> 13 SM_RCSID("@(#)$Id: smdb1.c,v 8.59 2004/08/03 20:58:39 ca Exp $") 14 15 #include <unistd.h> 16 #include <stdlib.h> 17 #include <fcntl.h> 18 19 #include <sendmail/sendmail.h> 20 #include <libsmdb/smdb.h> 21 22 #if (DB_VERSION_MAJOR == 1) 23 24 # define SMDB1_FILE_EXTENSION "db" 25 26 struct smdb_db1_struct 27 { 28 DB *smdb1_db; 29 int smdb1_lock_fd; 30 bool smdb1_cursor_in_use; 31 }; 32 typedef struct smdb_db1_struct SMDB_DB1_DATABASE; 33 34 struct smdb_db1_cursor 35 { 36 SMDB_DB1_DATABASE *db; 37 }; 38 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR; 39 40 static DBTYPE smdb_type_to_db1_type __P((SMDB_DBTYPE)); 41 static unsigned int smdb_put_flags_to_db1_flags __P((SMDB_FLAG)); 42 static int smdb_cursor_get_flags_to_smdb1 __P((SMDB_FLAG)); 43 static SMDB_DB1_DATABASE *smdb1_malloc_database __P((void)); 44 static int smdb1_close __P((SMDB_DATABASE *)); 45 static int smdb1_del __P((SMDB_DATABASE *, SMDB_DBENT *, unsigned int)); 46 static int smdb1_fd __P((SMDB_DATABASE *, int *)); 47 static int smdb1_lockfd __P((SMDB_DATABASE *)); 48 static int smdb1_get __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int)); 49 static int smdb1_put __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int)); 50 static int smdb1_set_owner __P((SMDB_DATABASE *, uid_t, gid_t)); 51 static int smdb1_sync __P((SMDB_DATABASE *, unsigned int)); 52 static int smdb1_cursor_close __P((SMDB_CURSOR *)); 53 static int smdb1_cursor_del __P((SMDB_CURSOR *, unsigned int)); 54 static int smdb1_cursor_get __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG)); 55 static int smdb1_cursor_put __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG)); 56 static int smdb1_cursor __P((SMDB_DATABASE *, SMDB_CURSOR **, unsigned int)); 57 58 /* 59 ** SMDB_TYPE_TO_DB1_TYPE -- Translates smdb database type to db1 type. 60 ** 61 ** Parameters: 62 ** type -- The type to translate. 63 ** 64 ** Returns: 65 ** The DB1 type that corresponsds to the passed in SMDB type. 66 ** Returns -1 if there is no equivalent type. 67 ** 68 */ 69 70 static DBTYPE 71 smdb_type_to_db1_type(type) 72 SMDB_DBTYPE type; 73 { 74 if (type == SMDB_TYPE_DEFAULT) 75 return DB_HASH; 76 77 if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0) 78 return DB_HASH; 79 80 if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0) 81 return DB_BTREE; 82 83 /* Should never get here thanks to test in smdb_db_open() */ 84 return DB_HASH; 85 } 86 /* 87 ** SMDB_PUT_FLAGS_TO_DB1_FLAGS -- Translates smdb put flags to db1 put flags. 88 ** 89 ** Parameters: 90 ** flags -- The flags to translate. 91 ** 92 ** Returns: 93 ** The db1 flags that are equivalent to the smdb flags. 94 ** 95 ** Notes: 96 ** Any invalid flags are ignored. 97 ** 98 */ 99 100 static unsigned int 101 smdb_put_flags_to_db1_flags(flags) 102 SMDB_FLAG flags; 103 { 104 int return_flags; 105 106 return_flags = 0; 107 108 if (bitset(SMDBF_NO_OVERWRITE, flags)) 109 return_flags |= R_NOOVERWRITE; 110 111 return return_flags; 112 } 113 /* 114 ** SMDB_CURSOR_GET_FLAGS_TO_SMDB1 115 ** 116 ** Parameters: 117 ** flags -- The flags to translate. 118 ** 119 ** Returns: 120 ** The db1 flags that are equivalent to the smdb flags. 121 ** 122 ** Notes: 123 ** Returns -1 if we don't support the flag. 124 ** 125 */ 126 127 static int 128 smdb_cursor_get_flags_to_smdb1(flags) 129 SMDB_FLAG flags; 130 { 131 switch(flags) 132 { 133 case SMDB_CURSOR_GET_FIRST: 134 return R_FIRST; 135 136 case SMDB_CURSOR_GET_LAST: 137 return R_LAST; 138 139 case SMDB_CURSOR_GET_NEXT: 140 return R_NEXT; 141 142 case SMDB_CURSOR_GET_RANGE: 143 return R_CURSOR; 144 145 default: 146 return -1; 147 } 148 } 149 150 /* 151 ** The rest of these functions correspond to the interface laid out in smdb.h. 152 */ 153 154 static SMDB_DB1_DATABASE * 155 smdb1_malloc_database() 156 { 157 SMDB_DB1_DATABASE *db1; 158 159 db1 = (SMDB_DB1_DATABASE *) malloc(sizeof(SMDB_DB1_DATABASE)); 160 161 if (db1 != NULL) 162 { 163 db1->smdb1_lock_fd = -1; 164 db1->smdb1_cursor_in_use = false; 165 } 166 167 return db1; 168 } 169 170 static int 171 smdb1_close(database) 172 SMDB_DATABASE *database; 173 { 174 int result; 175 SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; 176 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 177 178 result = db->close(db); 179 if (db1->smdb1_lock_fd != -1) 180 (void) close(db1->smdb1_lock_fd); 181 182 free(db1); 183 database->smdb_impl = NULL; 184 185 return result; 186 } 187 188 static int 189 smdb1_del(database, key, flags) 190 SMDB_DATABASE *database; 191 SMDB_DBENT *key; 192 unsigned int flags; 193 { 194 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 195 DBT dbkey; 196 197 (void) memset(&dbkey, '\0', sizeof dbkey); 198 dbkey.data = key->data; 199 dbkey.size = key->size; 200 return db->del(db, &dbkey, flags); 201 } 202 203 static int 204 smdb1_fd(database, fd) 205 SMDB_DATABASE *database; 206 int *fd; 207 { 208 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 209 210 *fd = db->fd(db); 211 if (*fd == -1) 212 return errno; 213 214 return SMDBE_OK; 215 } 216 217 static int 218 smdb1_lockfd(database) 219 SMDB_DATABASE *database; 220 { 221 SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; 222 223 return db1->smdb1_lock_fd; 224 } 225 226 227 static int 228 smdb1_get(database, key, data, flags) 229 SMDB_DATABASE *database; 230 SMDB_DBENT *key; 231 SMDB_DBENT *data; 232 unsigned int flags; 233 { 234 int result; 235 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 236 DBT dbkey, dbdata; 237 238 (void) memset(&dbdata, '\0', sizeof dbdata); 239 (void) memset(&dbkey, '\0', sizeof dbkey); 240 dbkey.data = key->data; 241 dbkey.size = key->size; 242 243 result = db->get(db, &dbkey, &dbdata, flags); 244 if (result != 0) 245 { 246 if (result == 1) 247 return SMDBE_NOT_FOUND; 248 return errno; 249 } 250 data->data = dbdata.data; 251 data->size = dbdata.size; 252 return SMDBE_OK; 253 } 254 255 static int 256 smdb1_put(database, key, data, flags) 257 SMDB_DATABASE *database; 258 SMDB_DBENT *key; 259 SMDB_DBENT *data; 260 unsigned int flags; 261 { 262 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 263 DBT dbkey, dbdata; 264 265 (void) memset(&dbdata, '\0', sizeof dbdata); 266 (void) memset(&dbkey, '\0', sizeof dbkey); 267 dbkey.data = key->data; 268 dbkey.size = key->size; 269 dbdata.data = data->data; 270 dbdata.size = data->size; 271 272 return db->put(db, &dbkey, &dbdata, 273 smdb_put_flags_to_db1_flags(flags)); 274 } 275 276 static int 277 smdb1_set_owner(database, uid, gid) 278 SMDB_DATABASE *database; 279 uid_t uid; 280 gid_t gid; 281 { 282 # if HASFCHOWN 283 int fd; 284 int result; 285 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 286 287 fd = db->fd(db); 288 if (fd == -1) 289 return errno; 290 291 result = fchown(fd, uid, gid); 292 if (result < 0) 293 return errno; 294 # endif /* HASFCHOWN */ 295 296 return SMDBE_OK; 297 } 298 299 static int 300 smdb1_sync(database, flags) 301 SMDB_DATABASE *database; 302 unsigned int flags; 303 { 304 DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db; 305 306 return db->sync(db, flags); 307 } 308 309 static int 310 smdb1_cursor_close(cursor) 311 SMDB_CURSOR *cursor; 312 { 313 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 314 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 315 316 if (!db1->smdb1_cursor_in_use) 317 return SMDBE_NOT_A_VALID_CURSOR; 318 319 db1->smdb1_cursor_in_use = false; 320 free(cursor); 321 322 return SMDBE_OK; 323 } 324 325 static int 326 smdb1_cursor_del(cursor, flags) 327 SMDB_CURSOR *cursor; 328 unsigned int flags; 329 { 330 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 331 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 332 DB *db = db1->smdb1_db; 333 334 return db->del(db, NULL, R_CURSOR); 335 } 336 337 static int 338 smdb1_cursor_get(cursor, key, value, flags) 339 SMDB_CURSOR *cursor; 340 SMDB_DBENT *key; 341 SMDB_DBENT *value; 342 SMDB_FLAG flags; 343 { 344 int db1_flags; 345 int result; 346 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 347 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 348 DB *db = db1->smdb1_db; 349 DBT dbkey, dbdata; 350 351 (void) memset(&dbdata, '\0', sizeof dbdata); 352 (void) memset(&dbkey, '\0', sizeof dbkey); 353 354 db1_flags = smdb_cursor_get_flags_to_smdb1(flags); 355 result = db->seq(db, &dbkey, &dbdata, db1_flags); 356 if (result == -1) 357 return errno; 358 if (result == 1) 359 return SMDBE_LAST_ENTRY; 360 value->data = dbdata.data; 361 value->size = dbdata.size; 362 key->data = dbkey.data; 363 key->size = dbkey.size; 364 return SMDBE_OK; 365 } 366 367 static int 368 smdb1_cursor_put(cursor, key, value, flags) 369 SMDB_CURSOR *cursor; 370 SMDB_DBENT *key; 371 SMDB_DBENT *value; 372 SMDB_FLAG flags; 373 { 374 SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl; 375 SMDB_DB1_DATABASE *db1 = db1_cursor->db; 376 DB *db = db1->smdb1_db; 377 DBT dbkey, dbdata; 378 379 (void) memset(&dbdata, '\0', sizeof dbdata); 380 (void) memset(&dbkey, '\0', sizeof dbkey); 381 dbkey.data = key->data; 382 dbkey.size = key->size; 383 dbdata.data = value->data; 384 dbdata.size = value->size; 385 386 return db->put(db, &dbkey, &dbdata, R_CURSOR); 387 } 388 389 static int 390 smdb1_cursor(database, cursor, flags) 391 SMDB_DATABASE *database; 392 SMDB_CURSOR **cursor; 393 unsigned int flags; 394 { 395 SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl; 396 SMDB_CURSOR *cur; 397 SMDB_DB1_CURSOR *db1_cursor; 398 399 if (db1->smdb1_cursor_in_use) 400 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR; 401 402 db1->smdb1_cursor_in_use = true; 403 db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR)); 404 db1_cursor->db = db1; 405 406 cur = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR)); 407 408 if (cur == NULL) 409 return SMDBE_MALLOC; 410 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 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 (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) != 0 && 473 strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) != 0)) 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 return SMDBE_MALLOC; 508 db1->smdb1_lock_fd = lock_fd; 509 510 params = NULL; 511 if (db_params != NULL && 512 (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) == 0)) 513 { 514 (void) memset(&hash_info, '\0', sizeof hash_info); 515 hash_info.nelem = db_params->smdbp_num_elements; 516 hash_info.cachesize = db_params->smdbp_cache_size; 517 params = &hash_info; 518 } 519 520 if (db_params != NULL && 521 (strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) == 0)) 522 { 523 (void) memset(&btree_info, '\0', sizeof btree_info); 524 btree_info.cachesize = db_params->smdbp_cache_size; 525 if (db_params->smdbp_allow_dup) 526 btree_info.flags |= R_DUP; 527 params = &btree_info; 528 } 529 530 db_type = smdb_type_to_db1_type(type); 531 db = dbopen(db_file_name, mode, DBMMODE, db_type, params); 532 if (db != NULL) 533 { 534 db_fd = db->fd(db); 535 result = smdb_filechanged(db_name, SMDB1_FILE_EXTENSION, db_fd, 536 &stat_info); 537 } 538 else 539 { 540 if (errno == 0) 541 result = SMDBE_BAD_OPEN; 542 else 543 result = errno; 544 } 545 546 if (result == SMDBE_OK) 547 { 548 /* Everything is ok. Setup driver */ 549 db1->smdb1_db = db; 550 551 smdb_db->smdb_close = smdb1_close; 552 smdb_db->smdb_del = smdb1_del; 553 smdb_db->smdb_fd = smdb1_fd; 554 smdb_db->smdb_lockfd = smdb1_lockfd; 555 smdb_db->smdb_get = smdb1_get; 556 smdb_db->smdb_put = smdb1_put; 557 smdb_db->smdb_set_owner = smdb1_set_owner; 558 smdb_db->smdb_sync = smdb1_sync; 559 smdb_db->smdb_cursor = smdb1_cursor; 560 smdb_db->smdb_impl = db1; 561 562 *database = smdb_db; 563 return SMDBE_OK; 564 } 565 566 if (db != NULL) 567 (void) db->close(db); 568 569 /* Error opening database */ 570 (void) smdb_unlock_file(db1->smdb1_lock_fd); 571 free(db1); 572 smdb_free_database(smdb_db); 573 574 return result; 575 } 576 577 #endif /* (DB_VERSION_MAJOR == 1) */ 578