1 /* 2 ** Copyright (c) 1999-2000 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 #ifndef lint 11 static char id[] = "@(#)$Id: smndbm.c,v 8.40.4.3 2000/10/05 22:27:50 gshapiro Exp $"; 12 #endif /* ! lint */ 13 14 #include <fcntl.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 18 #include <sendmail/sendmail.h> 19 #include <libsmdb/smdb.h> 20 21 #ifdef NDBM 22 23 # define SMNDB_DIR_FILE_EXTENSION "dir" 24 # define SMNDB_PAG_FILE_EXTENSION "pag" 25 26 struct smdb_dbm_database_struct 27 { 28 DBM *smndbm_dbm; 29 int smndbm_lock_fd; 30 bool smndbm_cursor_in_use; 31 }; 32 typedef struct smdb_dbm_database_struct SMDB_DBM_DATABASE; 33 34 struct smdb_dbm_cursor_struct 35 { 36 SMDB_DBM_DATABASE *smndbmc_db; 37 datum smndbmc_current_key; 38 }; 39 typedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR; 40 41 /* 42 ** SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags. 43 ** 44 ** Parameters: 45 ** flags -- The flags to translate. 46 ** 47 ** Returns: 48 ** The ndbm flags that are equivalent to the smdb flags. 49 ** 50 ** Notes: 51 ** Any invalid flags are ignored. 52 ** 53 */ 54 55 int 56 smdb_put_flags_to_ndbm_flags(flags) 57 SMDB_FLAG flags; 58 { 59 int return_flags; 60 61 return_flags = 0; 62 if (bitset(SMDBF_NO_OVERWRITE, flags)) 63 return_flags = DBM_INSERT; 64 else 65 return_flags = DBM_REPLACE; 66 67 return return_flags; 68 } 69 70 /* 71 ** smdbm_malloc_database -- Create and initialize SMDB_DBM_DATABASE 72 ** 73 ** Parameters: 74 ** None 75 ** 76 ** Returns: 77 ** A pointer to an allocated SMDB_DBM_DATABASE or NULL 78 ** 79 */ 80 81 SMDB_DBM_DATABASE * 82 smdbm_malloc_database() 83 { 84 SMDB_DBM_DATABASE *db; 85 86 db = (SMDB_DBM_DATABASE *) malloc(sizeof(SMDB_DBM_DATABASE)); 87 if (db != NULL) 88 { 89 db->smndbm_dbm = NULL; 90 db->smndbm_lock_fd = -1; 91 db->smndbm_cursor_in_use = FALSE; 92 } 93 94 return db; 95 } 96 97 /* 98 ** Except for smdb_ndbm_open, the rest of these function correspond to the 99 ** interface laid out in smdb.h. 100 */ 101 102 int 103 smdbm_close(database) 104 SMDB_DATABASE *database; 105 { 106 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl; 107 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 108 109 dbm_close(dbm); 110 if (db->smndbm_lock_fd != -1) 111 close(db->smndbm_lock_fd); 112 113 free(db); 114 database->smdb_impl = NULL; 115 116 return SMDBE_OK; 117 } 118 119 int 120 smdbm_del(database, key, flags) 121 SMDB_DATABASE *database; 122 SMDB_DBENT *key; 123 u_int flags; 124 { 125 int result; 126 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 127 datum dbkey; 128 129 memset(&dbkey, '\0', sizeof dbkey); 130 dbkey.dptr = key->data; 131 dbkey.dsize = key->size; 132 133 errno = 0; 134 result = dbm_delete(dbm, dbkey); 135 if (result != 0) 136 { 137 int save_errno = errno; 138 139 if (dbm_error(dbm)) 140 return SMDBE_IO_ERROR; 141 142 if (save_errno != 0) 143 return save_errno; 144 145 return SMDBE_NOT_FOUND; 146 } 147 return SMDBE_OK; 148 } 149 150 int 151 smdbm_fd(database, fd) 152 SMDB_DATABASE *database; 153 int *fd; 154 { 155 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 156 157 *fd = dbm_dirfno(dbm); 158 if (*fd <= 0) 159 return EINVAL; 160 161 return SMDBE_OK; 162 } 163 164 int 165 smdbm_lockfd(database) 166 SMDB_DATABASE *database; 167 { 168 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl; 169 170 return db->smndbm_lock_fd; 171 } 172 173 int 174 smdbm_get(database, key, data, flags) 175 SMDB_DATABASE *database; 176 SMDB_DBENT *key; 177 SMDB_DBENT *data; 178 u_int flags; 179 { 180 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 181 datum dbkey, dbdata; 182 183 memset(&dbkey, '\0', sizeof dbkey); 184 memset(&dbdata, '\0', sizeof dbdata); 185 dbkey.dptr = key->data; 186 dbkey.dsize = key->size; 187 188 errno = 0; 189 dbdata = dbm_fetch(dbm, dbkey); 190 if (dbdata.dptr == NULL) 191 { 192 int save_errno = errno; 193 194 if (dbm_error(dbm)) 195 return SMDBE_IO_ERROR; 196 197 if (save_errno != 0) 198 return save_errno; 199 200 return SMDBE_NOT_FOUND; 201 } 202 data->data = dbdata.dptr; 203 data->size = dbdata.dsize; 204 return SMDBE_OK; 205 } 206 207 int 208 smdbm_put(database, key, data, flags) 209 SMDB_DATABASE *database; 210 SMDB_DBENT *key; 211 SMDB_DBENT *data; 212 u_int flags; 213 { 214 int result; 215 int save_errno; 216 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 217 datum dbkey, dbdata; 218 219 memset(&dbkey, '\0', sizeof dbkey); 220 memset(&dbdata, '\0', sizeof dbdata); 221 dbkey.dptr = key->data; 222 dbkey.dsize = key->size; 223 dbdata.dptr = data->data; 224 dbdata.dsize = data->size; 225 226 errno = 0; 227 result = dbm_store(dbm, dbkey, dbdata, 228 smdb_put_flags_to_ndbm_flags(flags)); 229 switch (result) 230 { 231 case 1: 232 return SMDBE_DUPLICATE; 233 234 case 0: 235 return SMDBE_OK; 236 237 default: 238 save_errno = errno; 239 240 if (dbm_error(dbm)) 241 return SMDBE_IO_ERROR; 242 243 if (save_errno != 0) 244 return save_errno; 245 246 return SMDBE_IO_ERROR; 247 } 248 /* NOTREACHED */ 249 } 250 251 int 252 smndbm_set_owner(database, uid, gid) 253 SMDB_DATABASE *database; 254 uid_t uid; 255 gid_t gid; 256 { 257 # if HASFCHOWN 258 int fd; 259 int result; 260 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 261 262 fd = dbm_dirfno(dbm); 263 if (fd <= 0) 264 return EINVAL; 265 266 result = fchown(fd, uid, gid); 267 if (result < 0) 268 return errno; 269 270 fd = dbm_pagfno(dbm); 271 if (fd <= 0) 272 return EINVAL; 273 274 result = fchown(fd, uid, gid); 275 if (result < 0) 276 return errno; 277 # endif /* HASFCHOWN */ 278 279 return SMDBE_OK; 280 } 281 282 int 283 smdbm_sync(database, flags) 284 SMDB_DATABASE *database; 285 u_int flags; 286 { 287 return SMDBE_UNSUPPORTED; 288 } 289 290 int 291 smdbm_cursor_close(cursor) 292 SMDB_CURSOR *cursor; 293 { 294 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 295 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 296 297 if (!db->smndbm_cursor_in_use) 298 return SMDBE_NOT_A_VALID_CURSOR; 299 300 db->smndbm_cursor_in_use = FALSE; 301 free(dbm_cursor); 302 free(cursor); 303 304 return SMDBE_OK; 305 } 306 307 int 308 smdbm_cursor_del(cursor, flags) 309 SMDB_CURSOR *cursor; 310 u_int flags; 311 { 312 int result; 313 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 314 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 315 DBM *dbm = db->smndbm_dbm; 316 317 errno = 0; 318 result = dbm_delete(dbm, dbm_cursor->smndbmc_current_key); 319 if (result != 0) 320 { 321 int save_errno = errno; 322 323 if (dbm_error(dbm)) 324 return SMDBE_IO_ERROR; 325 326 if (save_errno != 0) 327 return save_errno; 328 329 return SMDBE_NOT_FOUND; 330 } 331 return SMDBE_OK; 332 } 333 334 int 335 smdbm_cursor_get(cursor, key, value, flags) 336 SMDB_CURSOR *cursor; 337 SMDB_DBENT *key; 338 SMDB_DBENT *value; 339 SMDB_FLAG flags; 340 { 341 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 342 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 343 DBM *dbm = db->smndbm_dbm; 344 datum dbkey, dbdata; 345 346 memset(&dbkey, '\0', sizeof dbkey); 347 memset(&dbdata, '\0', sizeof dbdata); 348 349 if (flags == SMDB_CURSOR_GET_RANGE) 350 return SMDBE_UNSUPPORTED; 351 352 if (dbm_cursor->smndbmc_current_key.dptr == NULL) 353 { 354 dbm_cursor->smndbmc_current_key = dbm_firstkey(dbm); 355 if (dbm_cursor->smndbmc_current_key.dptr == NULL) 356 { 357 if (dbm_error(dbm)) 358 return SMDBE_IO_ERROR; 359 return SMDBE_LAST_ENTRY; 360 } 361 } 362 else 363 { 364 dbm_cursor->smndbmc_current_key = dbm_nextkey(dbm); 365 if (dbm_cursor->smndbmc_current_key.dptr == NULL) 366 { 367 if (dbm_error(dbm)) 368 return SMDBE_IO_ERROR; 369 return SMDBE_LAST_ENTRY; 370 } 371 } 372 373 errno = 0; 374 dbdata = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key); 375 if (dbdata.dptr == NULL) 376 { 377 int save_errno = errno; 378 379 if (dbm_error(dbm)) 380 return SMDBE_IO_ERROR; 381 382 if (save_errno != 0) 383 return save_errno; 384 385 return SMDBE_NOT_FOUND; 386 } 387 value->data = dbdata.dptr; 388 value->size = dbdata.dsize; 389 key->data = dbm_cursor->smndbmc_current_key.dptr; 390 key->size = dbm_cursor->smndbmc_current_key.dsize; 391 392 return SMDBE_OK; 393 } 394 395 int 396 smdbm_cursor_put(cursor, key, value, flags) 397 SMDB_CURSOR *cursor; 398 SMDB_DBENT *key; 399 SMDB_DBENT *value; 400 SMDB_FLAG flags; 401 { 402 int result; 403 int save_errno; 404 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 405 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 406 DBM *dbm = db->smndbm_dbm; 407 datum dbdata; 408 409 memset(&dbdata, '\0', sizeof dbdata); 410 dbdata.dptr = value->data; 411 dbdata.dsize = value->size; 412 413 errno = 0; 414 result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, dbdata, 415 smdb_put_flags_to_ndbm_flags(flags)); 416 switch (result) 417 { 418 case 1: 419 return SMDBE_DUPLICATE; 420 421 case 0: 422 return SMDBE_OK; 423 424 default: 425 save_errno = errno; 426 427 if (dbm_error(dbm)) 428 return SMDBE_IO_ERROR; 429 430 if (save_errno != 0) 431 return save_errno; 432 433 return SMDBE_IO_ERROR; 434 } 435 /* NOTREACHED */ 436 } 437 438 int 439 smdbm_cursor(database, cursor, flags) 440 SMDB_DATABASE *database; 441 SMDB_CURSOR **cursor; 442 SMDB_FLAG flags; 443 { 444 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl; 445 SMDB_CURSOR *cur; 446 SMDB_DBM_CURSOR *dbm_cursor; 447 448 if (db->smndbm_cursor_in_use) 449 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR; 450 451 db->smndbm_cursor_in_use = TRUE; 452 dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR)); 453 dbm_cursor->smndbmc_db = db; 454 dbm_cursor->smndbmc_current_key.dptr = NULL; 455 dbm_cursor->smndbmc_current_key.dsize = 0; 456 457 cur = (SMDB_CURSOR*) malloc(sizeof(SMDB_CURSOR)); 458 if (cur == NULL) 459 return SMDBE_MALLOC; 460 461 cur->smdbc_impl = dbm_cursor; 462 cur->smdbc_close = smdbm_cursor_close; 463 cur->smdbc_del = smdbm_cursor_del; 464 cur->smdbc_get = smdbm_cursor_get; 465 cur->smdbc_put = smdbm_cursor_put; 466 *cursor = cur; 467 468 return SMDBE_OK; 469 } 470 471 /* 472 ** SMDB_NDBM_OPEN -- Opens a ndbm database. 473 ** 474 ** Parameters: 475 ** database -- An unallocated database pointer to a pointer. 476 ** db_name -- The name of the database without extension. 477 ** mode -- File permisions on a created database. 478 ** mode_mask -- Mode bits that much match on an opened database. 479 ** sff -- Flags to safefile. 480 ** type -- The type of database to open. 481 ** Only SMDB_NDBM is supported. 482 ** user_info -- Information on the user to use for file 483 ** permissions. 484 ** db_params -- 485 ** No params are supported. 486 ** 487 ** Returns: 488 ** SMDBE_OK -- Success, otherwise errno: 489 ** SMDBE_MALLOC -- Cannot allocate memory. 490 ** SMDBE_UNSUPPORTED -- The type is not supported. 491 ** SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't 492 ** like it. 493 ** SMDBE_BAD_OPEN -- dbm_open failed and errno was not set. 494 ** Anything else: errno 495 */ 496 497 int 498 smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info, 499 db_params) 500 SMDB_DATABASE **database; 501 char *db_name; 502 int mode; 503 int mode_mask; 504 long sff; 505 SMDB_DBTYPE type; 506 SMDB_USER_INFO *user_info; 507 SMDB_DBPARAMS *db_params; 508 { 509 int result; 510 int lock_fd; 511 SMDB_DATABASE *smdb_db; 512 SMDB_DBM_DATABASE *db; 513 DBM *dbm = NULL; 514 struct stat dir_stat_info; 515 struct stat pag_stat_info; 516 517 result = SMDBE_OK; 518 *database = NULL; 519 520 if (type == NULL) 521 return SMDBE_UNKNOWN_DB_TYPE; 522 523 result = smdb_setup_file(db_name, SMNDB_DIR_FILE_EXTENSION, mode_mask, 524 sff, user_info, &dir_stat_info); 525 if (result != SMDBE_OK) 526 return result; 527 528 result = smdb_setup_file(db_name, SMNDB_PAG_FILE_EXTENSION, mode_mask, 529 sff, user_info, &pag_stat_info); 530 if (result != SMDBE_OK) 531 return result; 532 533 lock_fd = -1; 534 # if O_EXLOCK 535 mode |= O_EXLOCK; 536 # else /* O_EXLOCK */ 537 result = smdb_lock_file(&lock_fd, db_name, mode, sff, 538 SMNDB_DIR_FILE_EXTENSION); 539 if (result != SMDBE_OK) 540 return result; 541 # endif /* O_EXLOCK */ 542 543 smdb_db = smdb_malloc_database(); 544 if (smdb_db == NULL) 545 result = SMDBE_MALLOC; 546 547 db = smdbm_malloc_database(); 548 if (db == NULL) 549 result = SMDBE_MALLOC; 550 551 /* Try to open database */ 552 if (result == SMDBE_OK) 553 { 554 db->smndbm_lock_fd = lock_fd; 555 556 errno = 0; 557 dbm = dbm_open(db_name, mode, 0644); 558 if (dbm == NULL) 559 { 560 if (errno == 0) 561 result = SMDBE_BAD_OPEN; 562 else 563 result = errno; 564 } 565 db->smndbm_dbm = dbm; 566 } 567 568 /* Check for GDBM */ 569 if (result == SMDBE_OK) 570 { 571 if (dbm_dirfno(dbm) == dbm_pagfno(dbm)) 572 result = SMDBE_GDBM_IS_BAD; 573 } 574 575 /* Check for filechanged */ 576 if (result == SMDBE_OK) 577 { 578 result = smdb_filechanged(db_name, SMNDB_DIR_FILE_EXTENSION, 579 dbm_dirfno(dbm), &dir_stat_info); 580 if (result == SMDBE_OK) 581 { 582 result = smdb_filechanged(db_name, 583 SMNDB_PAG_FILE_EXTENSION, 584 dbm_pagfno(dbm), 585 &pag_stat_info); 586 } 587 } 588 589 /* XXX Got to get fchown stuff in here */ 590 591 /* Setup driver if everything is ok */ 592 if (result == SMDBE_OK) 593 { 594 *database = smdb_db; 595 596 smdb_db->smdb_close = smdbm_close; 597 smdb_db->smdb_del = smdbm_del; 598 smdb_db->smdb_fd = smdbm_fd; 599 smdb_db->smdb_lockfd = smdbm_lockfd; 600 smdb_db->smdb_get = smdbm_get; 601 smdb_db->smdb_put = smdbm_put; 602 smdb_db->smdb_set_owner = smndbm_set_owner; 603 smdb_db->smdb_sync = smdbm_sync; 604 smdb_db->smdb_cursor = smdbm_cursor; 605 606 smdb_db->smdb_impl = db; 607 608 return SMDBE_OK; 609 } 610 611 /* If we're here, something bad happened, clean up */ 612 if (dbm != NULL) 613 dbm_close(dbm); 614 615 smdb_unlock_file(db->smndbm_lock_fd); 616 free(db); 617 smdb_free_database(smdb_db); 618 619 return result; 620 } 621 #endif /* NDBM */ 622