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.1 2000/08/24 17:08:00 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 128 errno = 0; 129 result = dbm_delete(dbm, key->dbm); 130 if (result != 0) 131 { 132 int save_errno = errno; 133 134 if (dbm_error(dbm)) 135 return SMDBE_IO_ERROR; 136 137 if (save_errno != 0) 138 return save_errno; 139 140 return SMDBE_NOT_FOUND; 141 } 142 return SMDBE_OK; 143 } 144 145 int 146 smdbm_fd(database, fd) 147 SMDB_DATABASE *database; 148 int *fd; 149 { 150 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 151 152 *fd = dbm_dirfno(dbm); 153 if (*fd <= 0) 154 return EINVAL; 155 156 return SMDBE_OK; 157 } 158 159 int 160 smdbm_lockfd(database) 161 SMDB_DATABASE *database; 162 { 163 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl; 164 165 return db->smndbm_lock_fd; 166 } 167 168 int 169 smdbm_get(database, key, data, flags) 170 SMDB_DATABASE *database; 171 SMDB_DBENT *key; 172 SMDB_DBENT *data; 173 u_int flags; 174 { 175 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 176 177 errno = 0; 178 data->dbm = dbm_fetch(dbm, key->dbm); 179 if (data->dbm.dptr == NULL) 180 { 181 int save_errno = errno; 182 183 if (dbm_error(dbm)) 184 return SMDBE_IO_ERROR; 185 186 if (save_errno != 0) 187 return save_errno; 188 189 return SMDBE_NOT_FOUND; 190 } 191 192 return SMDBE_OK; 193 } 194 195 int 196 smdbm_put(database, key, data, flags) 197 SMDB_DATABASE *database; 198 SMDB_DBENT *key; 199 SMDB_DBENT *data; 200 u_int flags; 201 { 202 int result; 203 int save_errno; 204 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 205 206 errno = 0; 207 result = dbm_store(dbm, key->dbm, data->dbm, 208 smdb_put_flags_to_ndbm_flags(flags)); 209 switch (result) 210 { 211 case 1: 212 return SMDBE_DUPLICATE; 213 214 case 0: 215 return SMDBE_OK; 216 217 default: 218 save_errno = errno; 219 220 if (dbm_error(dbm)) 221 return SMDBE_IO_ERROR; 222 223 if (save_errno != 0) 224 return save_errno; 225 226 return SMDBE_IO_ERROR; 227 } 228 /* NOTREACHED */ 229 } 230 231 int 232 smndbm_set_owner(database, uid, gid) 233 SMDB_DATABASE *database; 234 uid_t uid; 235 gid_t gid; 236 { 237 # if HASFCHOWN 238 int fd; 239 int result; 240 DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm; 241 242 fd = dbm_dirfno(dbm); 243 if (fd <= 0) 244 return EINVAL; 245 246 result = fchown(fd, uid, gid); 247 if (result < 0) 248 return errno; 249 250 fd = dbm_pagfno(dbm); 251 if (fd <= 0) 252 return EINVAL; 253 254 result = fchown(fd, uid, gid); 255 if (result < 0) 256 return errno; 257 # endif /* HASFCHOWN */ 258 259 return SMDBE_OK; 260 } 261 262 int 263 smdbm_sync(database, flags) 264 SMDB_DATABASE *database; 265 u_int flags; 266 { 267 return SMDBE_UNSUPPORTED; 268 } 269 270 int 271 smdbm_cursor_close(cursor) 272 SMDB_CURSOR *cursor; 273 { 274 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 275 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 276 277 if (!db->smndbm_cursor_in_use) 278 return SMDBE_NOT_A_VALID_CURSOR; 279 280 db->smndbm_cursor_in_use = FALSE; 281 free(dbm_cursor); 282 free(cursor); 283 284 return SMDBE_OK; 285 } 286 287 int 288 smdbm_cursor_del(cursor, flags) 289 SMDB_CURSOR *cursor; 290 u_int flags; 291 { 292 int result; 293 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 294 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 295 DBM *dbm = db->smndbm_dbm; 296 297 errno = 0; 298 result = dbm_delete(dbm, dbm_cursor->smndbmc_current_key); 299 if (result != 0) 300 { 301 int save_errno = errno; 302 303 if (dbm_error(dbm)) 304 return SMDBE_IO_ERROR; 305 306 if (save_errno != 0) 307 return save_errno; 308 309 return SMDBE_NOT_FOUND; 310 } 311 return SMDBE_OK; 312 } 313 314 int 315 smdbm_cursor_get(cursor, key, value, flags) 316 SMDB_CURSOR *cursor; 317 SMDB_DBENT *key; 318 SMDB_DBENT *value; 319 SMDB_FLAG flags; 320 { 321 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 322 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 323 DBM *dbm = db->smndbm_dbm; 324 325 if (flags == SMDB_CURSOR_GET_RANGE) 326 return SMDBE_UNSUPPORTED; 327 328 if (dbm_cursor->smndbmc_current_key.dptr == NULL) 329 { 330 dbm_cursor->smndbmc_current_key = dbm_firstkey(dbm); 331 if (dbm_cursor->smndbmc_current_key.dptr == NULL) 332 { 333 if (dbm_error(dbm)) 334 return SMDBE_IO_ERROR; 335 return SMDBE_LAST_ENTRY; 336 } 337 } 338 else 339 { 340 dbm_cursor->smndbmc_current_key = dbm_nextkey(dbm); 341 if (dbm_cursor->smndbmc_current_key.dptr == NULL) 342 { 343 if (dbm_error(dbm)) 344 return SMDBE_IO_ERROR; 345 return SMDBE_LAST_ENTRY; 346 } 347 } 348 349 errno = 0; 350 value->dbm = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key); 351 if (value->dbm.dptr == NULL) 352 { 353 int save_errno = errno; 354 355 if (dbm_error(dbm)) 356 return SMDBE_IO_ERROR; 357 358 if (save_errno != 0) 359 return save_errno; 360 361 return SMDBE_NOT_FOUND; 362 } 363 key->dbm = dbm_cursor->smndbmc_current_key; 364 365 return SMDBE_OK; 366 } 367 368 int 369 smdbm_cursor_put(cursor, key, value, flags) 370 SMDB_CURSOR *cursor; 371 SMDB_DBENT *key; 372 SMDB_DBENT *value; 373 SMDB_FLAG flags; 374 { 375 int result; 376 int save_errno; 377 SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl; 378 SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db; 379 DBM *dbm = db->smndbm_dbm; 380 381 errno = 0; 382 result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, value->dbm, 383 smdb_put_flags_to_ndbm_flags(flags)); 384 switch (result) 385 { 386 case 1: 387 return SMDBE_DUPLICATE; 388 389 case 0: 390 return SMDBE_OK; 391 392 default: 393 save_errno = errno; 394 395 if (dbm_error(dbm)) 396 return SMDBE_IO_ERROR; 397 398 if (save_errno != 0) 399 return save_errno; 400 401 return SMDBE_IO_ERROR; 402 } 403 /* NOTREACHED */ 404 } 405 406 int 407 smdbm_cursor(database, cursor, flags) 408 SMDB_DATABASE *database; 409 SMDB_CURSOR **cursor; 410 SMDB_FLAG flags; 411 { 412 SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl; 413 SMDB_CURSOR *cur; 414 SMDB_DBM_CURSOR *dbm_cursor; 415 416 if (db->smndbm_cursor_in_use) 417 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR; 418 419 db->smndbm_cursor_in_use = TRUE; 420 dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR)); 421 dbm_cursor->smndbmc_db = db; 422 dbm_cursor->smndbmc_current_key.dptr = NULL; 423 dbm_cursor->smndbmc_current_key.dsize = 0; 424 425 cur = (SMDB_CURSOR*) malloc(sizeof(SMDB_CURSOR)); 426 if (cur == NULL) 427 return SMDBE_MALLOC; 428 429 cur->smdbc_impl = dbm_cursor; 430 cur->smdbc_close = smdbm_cursor_close; 431 cur->smdbc_del = smdbm_cursor_del; 432 cur->smdbc_get = smdbm_cursor_get; 433 cur->smdbc_put = smdbm_cursor_put; 434 *cursor = cur; 435 436 return SMDBE_OK; 437 } 438 439 /* 440 ** SMDB_NDBM_OPEN -- Opens a ndbm database. 441 ** 442 ** Parameters: 443 ** database -- An unallocated database pointer to a pointer. 444 ** db_name -- The name of the database without extension. 445 ** mode -- File permisions on a created database. 446 ** mode_mask -- Mode bits that much match on an opened database. 447 ** sff -- Flags to safefile. 448 ** type -- The type of database to open. 449 ** Only SMDB_NDBM is supported. 450 ** user_info -- Information on the user to use for file 451 ** permissions. 452 ** db_params -- 453 ** No params are supported. 454 ** 455 ** Returns: 456 ** SMDBE_OK -- Success, otherwise errno: 457 ** SMDBE_MALLOC -- Cannot allocate memory. 458 ** SMDBE_UNSUPPORTED -- The type is not supported. 459 ** SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't 460 ** like it. 461 ** SMDBE_BAD_OPEN -- dbm_open failed and errno was not set. 462 ** Anything else: errno 463 */ 464 465 int 466 smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info, 467 db_params) 468 SMDB_DATABASE **database; 469 char *db_name; 470 int mode; 471 int mode_mask; 472 long sff; 473 SMDB_DBTYPE type; 474 SMDB_USER_INFO *user_info; 475 SMDB_DBPARAMS *db_params; 476 { 477 int result; 478 int lock_fd; 479 SMDB_DATABASE *smdb_db; 480 SMDB_DBM_DATABASE *db; 481 DBM *dbm = NULL; 482 struct stat dir_stat_info; 483 struct stat pag_stat_info; 484 485 result = SMDBE_OK; 486 *database = NULL; 487 488 if (type == NULL) 489 return SMDBE_UNKNOWN_DB_TYPE; 490 491 result = smdb_setup_file(db_name, SMNDB_DIR_FILE_EXTENSION, mode_mask, 492 sff, user_info, &dir_stat_info); 493 if (result != SMDBE_OK) 494 return result; 495 496 result = smdb_setup_file(db_name, SMNDB_PAG_FILE_EXTENSION, mode_mask, 497 sff, user_info, &pag_stat_info); 498 if (result != SMDBE_OK) 499 return result; 500 501 lock_fd = -1; 502 # if O_EXLOCK 503 mode |= O_EXLOCK; 504 # else /* O_EXLOCK */ 505 result = smdb_lock_file(&lock_fd, db_name, mode, sff, 506 SMNDB_DIR_FILE_EXTENSION); 507 if (result != SMDBE_OK) 508 return result; 509 # endif /* O_EXLOCK */ 510 511 smdb_db = smdb_malloc_database(); 512 if (smdb_db == NULL) 513 result = SMDBE_MALLOC; 514 515 db = smdbm_malloc_database(); 516 if (db == NULL) 517 result = SMDBE_MALLOC; 518 519 /* Try to open database */ 520 if (result == SMDBE_OK) 521 { 522 db->smndbm_lock_fd = lock_fd; 523 524 errno = 0; 525 dbm = dbm_open(db_name, mode, 0644); 526 if (dbm == NULL) 527 { 528 if (errno == 0) 529 result = SMDBE_BAD_OPEN; 530 else 531 result = errno; 532 } 533 db->smndbm_dbm = dbm; 534 } 535 536 /* Check for GDBM */ 537 if (result == SMDBE_OK) 538 { 539 if (dbm_dirfno(dbm) == dbm_pagfno(dbm)) 540 result = SMDBE_GDBM_IS_BAD; 541 } 542 543 /* Check for filechanged */ 544 if (result == SMDBE_OK) 545 { 546 result = smdb_filechanged(db_name, SMNDB_DIR_FILE_EXTENSION, 547 dbm_dirfno(dbm), &dir_stat_info); 548 if (result == SMDBE_OK) 549 { 550 result = smdb_filechanged(db_name, 551 SMNDB_PAG_FILE_EXTENSION, 552 dbm_pagfno(dbm), 553 &pag_stat_info); 554 } 555 } 556 557 /* XXX Got to get fchown stuff in here */ 558 559 /* Setup driver if everything is ok */ 560 if (result == SMDBE_OK) 561 { 562 *database = smdb_db; 563 564 smdb_db->smdb_close = smdbm_close; 565 smdb_db->smdb_del = smdbm_del; 566 smdb_db->smdb_fd = smdbm_fd; 567 smdb_db->smdb_lockfd = smdbm_lockfd; 568 smdb_db->smdb_get = smdbm_get; 569 smdb_db->smdb_put = smdbm_put; 570 smdb_db->smdb_set_owner = smndbm_set_owner; 571 smdb_db->smdb_sync = smdbm_sync; 572 smdb_db->smdb_cursor = smdbm_cursor; 573 574 smdb_db->smdb_impl = db; 575 576 return SMDBE_OK; 577 } 578 579 /* If we're here, something bad happened, clean up */ 580 if (dbm != NULL) 581 dbm_close(dbm); 582 583 smdb_unlock_file(db->smndbm_lock_fd); 584 free(db); 585 smdb_free_database(smdb_db); 586 587 return result; 588 } 589 #endif /* NDBM */ 590