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: smdb.c,v 8.57 2002/05/24 23:09:11 gshapiro Exp $") 12 13 #include <fcntl.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 17 18 #include <sendmail/sendmail.h> 19 #include <libsmdb/smdb.h> 20 21 /* 22 ** SMDB_MALLOC_DATABASE -- Allocates a database structure. 23 ** 24 ** Parameters: 25 ** None 26 ** 27 ** Returns: 28 ** An pointer to an allocated SMDB_DATABASE structure or 29 ** NULL if it couldn't allocate the memory. 30 */ 31 32 SMDB_DATABASE * 33 smdb_malloc_database() 34 { 35 SMDB_DATABASE *db; 36 37 db = (SMDB_DATABASE *) malloc(sizeof(SMDB_DATABASE)); 38 39 if (db != NULL) 40 (void) memset(db, '\0', sizeof(SMDB_DATABASE)); 41 42 return db; 43 } 44 45 46 /* 47 ** SMDB_FREE_DATABASE -- Unallocates a database structure. 48 ** 49 ** Parameters: 50 ** database -- a SMDB_DATABASE pointer to deallocate. 51 ** 52 ** Returns: 53 ** None 54 */ 55 56 void 57 smdb_free_database(database) 58 SMDB_DATABASE *database; 59 { 60 if (database != NULL) 61 free(database); 62 } 63 /* 64 ** SMDB_LOCKFILE -- lock a file using flock or (shudder) fcntl locking 65 ** 66 ** Parameters: 67 ** fd -- the file descriptor of the file. 68 ** type -- type of the lock. Bits can be: 69 ** LOCK_EX -- exclusive lock. 70 ** LOCK_NB -- non-blocking. 71 ** 72 ** Returns: 73 ** true if the lock was acquired. 74 ** false otherwise. 75 */ 76 77 static bool 78 smdb_lockfile(fd, type) 79 int fd; 80 int type; 81 { 82 int i; 83 int save_errno; 84 #if !HASFLOCK 85 int action; 86 struct flock lfd; 87 88 (void) memset(&lfd, '\0', sizeof lfd); 89 if (bitset(LOCK_UN, type)) 90 lfd.l_type = F_UNLCK; 91 else if (bitset(LOCK_EX, type)) 92 lfd.l_type = F_WRLCK; 93 else 94 lfd.l_type = F_RDLCK; 95 96 if (bitset(LOCK_NB, type)) 97 action = F_SETLK; 98 else 99 action = F_SETLKW; 100 101 while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR) 102 continue; 103 if (i >= 0) 104 return true; 105 save_errno = errno; 106 107 /* 108 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 109 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 110 ** as type "tmp" (that is, served from swap space), the 111 ** previous fcntl will fail with "Invalid argument" errors. 112 ** Since this is fairly common during testing, we will assume 113 ** that this indicates that the lock is successfully grabbed. 114 */ 115 116 if (save_errno == EINVAL) 117 return true; 118 119 if (!bitset(LOCK_NB, type) || 120 (save_errno != EACCES && save_errno != EAGAIN)) 121 { 122 # if 0 123 int omode = fcntl(fd, F_GETFL, NULL); 124 int euid = (int) geteuid(); 125 126 syslog(LOG_ERR, "cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 127 filename, ext, fd, type, omode, euid); 128 # endif /* 0 */ 129 errno = save_errno; 130 return false; 131 } 132 #else /* !HASFLOCK */ 133 134 while ((i = flock(fd, type)) < 0 && errno == EINTR) 135 continue; 136 if (i >= 0) 137 return true; 138 save_errno = errno; 139 140 if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK) 141 { 142 # if 0 143 int omode = fcntl(fd, F_GETFL, NULL); 144 int euid = (int) geteuid(); 145 146 syslog(LOG_ERR, "cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 147 filename, ext, fd, type, omode, euid); 148 # endif /* 0 */ 149 errno = save_errno; 150 return false; 151 } 152 #endif /* !HASFLOCK */ 153 errno = save_errno; 154 return false; 155 } 156 /* 157 ** SMDB_OPEN_DATABASE -- Opens a database. 158 ** 159 ** This opens a database. If type is SMDB_DEFAULT it tries to 160 ** use a DB1 or DB2 hash. If that isn't available, it will try 161 ** to use NDBM. If a specific type is given it will try to open 162 ** a database of that type. 163 ** 164 ** Parameters: 165 ** database -- An pointer to a SMDB_DATABASE pointer where the 166 ** opened database will be stored. This should 167 ** be unallocated. 168 ** db_name -- The name of the database to open. Do not include 169 ** the file name extension. 170 ** mode -- The mode to set on the database file or files. 171 ** mode_mask -- Mode bits that must match on an opened database. 172 ** sff -- Flags to safefile. 173 ** type -- The type of database to open. Supported types 174 ** vary depending on what was compiled in. 175 ** user_info -- Information on the user to use for file 176 ** permissions. 177 ** params -- Params specific to the database being opened. 178 ** Only supports some DB hash options right now 179 ** (see smdb_db_open() for details). 180 ** 181 ** Returns: 182 ** SMDBE_OK -- Success. 183 ** Anything else is an error. Look up more info about the 184 ** error in the comments for the specific open() used. 185 */ 186 187 int 188 smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info, 189 params) 190 SMDB_DATABASE **database; 191 char *db_name; 192 int mode; 193 int mode_mask; 194 long sff; 195 SMDB_DBTYPE type; 196 SMDB_USER_INFO *user_info; 197 SMDB_DBPARAMS *params; 198 { 199 bool type_was_default = false; 200 201 if (type == SMDB_TYPE_DEFAULT) 202 { 203 type_was_default = true; 204 #ifdef NEWDB 205 type = SMDB_TYPE_HASH; 206 #else /* NEWDB */ 207 # ifdef NDBM 208 type = SMDB_TYPE_NDBM; 209 # endif /* NDBM */ 210 #endif /* NEWDB */ 211 } 212 213 if (type == SMDB_TYPE_DEFAULT) 214 return SMDBE_UNKNOWN_DB_TYPE; 215 216 if ((strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0) || 217 (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)) 218 { 219 #ifdef NEWDB 220 int result; 221 222 result = smdb_db_open(database, db_name, mode, mode_mask, sff, 223 type, user_info, params); 224 # ifdef NDBM 225 if (result == ENOENT && type_was_default) 226 type = SMDB_TYPE_NDBM; 227 else 228 # endif /* NDBM */ 229 return result; 230 #else /* NEWDB */ 231 return SMDBE_UNSUPPORTED_DB_TYPE; 232 #endif /* NEWDB */ 233 } 234 235 if (strncmp(type, SMDB_TYPE_NDBM, SMDB_TYPE_NDBM_LEN) == 0) 236 { 237 #ifdef NDBM 238 int result; 239 240 result = smdb_ndbm_open(database, db_name, mode, mode_mask, 241 sff, type, user_info, params); 242 return result; 243 #else /* NDBM */ 244 return SMDBE_UNSUPPORTED_DB_TYPE; 245 #endif /* NDBM */ 246 } 247 248 return SMDBE_UNKNOWN_DB_TYPE; 249 } 250 /* 251 ** SMDB_ADD_EXTENSION -- Adds an extension to a file name. 252 ** 253 ** Just adds a . followed by a string to a db_name if there 254 ** is room and the db_name does not already have that extension. 255 ** 256 ** Parameters: 257 ** full_name -- The final file name. 258 ** max_full_name_len -- The max length for full_name. 259 ** db_name -- The name of the db. 260 ** extension -- The extension to add. 261 ** 262 ** Returns: 263 ** SMDBE_OK -- Success. 264 ** Anything else is an error. Look up more info about the 265 ** error in the comments for the specific open() used. 266 */ 267 268 int 269 smdb_add_extension(full_name, max_full_name_len, db_name, extension) 270 char *full_name; 271 int max_full_name_len; 272 char *db_name; 273 char *extension; 274 { 275 int extension_len; 276 int db_name_len; 277 278 if (full_name == NULL || db_name == NULL || extension == NULL) 279 return SMDBE_INVALID_PARAMETER; 280 281 extension_len = strlen(extension); 282 db_name_len = strlen(db_name); 283 284 if (extension_len + db_name_len + 2 > max_full_name_len) 285 return SMDBE_DB_NAME_TOO_LONG; 286 287 if (db_name_len < extension_len + 1 || 288 db_name[db_name_len - extension_len - 1] != '.' || 289 strcmp(&db_name[db_name_len - extension_len], extension) != 0) 290 (void) sm_snprintf(full_name, max_full_name_len, "%s.%s", 291 db_name, extension); 292 else 293 (void) sm_strlcpy(full_name, db_name, max_full_name_len); 294 295 return SMDBE_OK; 296 } 297 /* 298 ** SMDB_LOCK_FILE -- Locks the database file. 299 ** 300 ** Locks the actual database file. 301 ** 302 ** Parameters: 303 ** lock_fd -- The resulting descriptor for the locked file. 304 ** db_name -- The name of the database without extension. 305 ** mode -- The open mode. 306 ** sff -- Flags to safefile. 307 ** extension -- The extension for the file. 308 ** 309 ** Returns: 310 ** SMDBE_OK -- Success, otherwise errno. 311 */ 312 313 int 314 smdb_lock_file(lock_fd, db_name, mode, sff, extension) 315 int *lock_fd; 316 char *db_name; 317 int mode; 318 long sff; 319 char *extension; 320 { 321 int result; 322 char file_name[MAXPATHLEN]; 323 324 result = smdb_add_extension(file_name, sizeof file_name, db_name, 325 extension); 326 if (result != SMDBE_OK) 327 return result; 328 329 *lock_fd = safeopen(file_name, mode & ~O_TRUNC, DBMMODE, sff); 330 if (*lock_fd < 0) 331 return errno; 332 333 return SMDBE_OK; 334 } 335 /* 336 ** SMDB_UNLOCK_FILE -- Unlocks a file 337 ** 338 ** Unlocks a file. 339 ** 340 ** Parameters: 341 ** lock_fd -- The descriptor for the locked file. 342 ** 343 ** Returns: 344 ** SMDBE_OK -- Success, otherwise errno. 345 */ 346 347 int 348 smdb_unlock_file(lock_fd) 349 int lock_fd; 350 { 351 int result; 352 353 result = close(lock_fd); 354 if (result != 0) 355 return errno; 356 357 return SMDBE_OK; 358 } 359 /* 360 ** SMDB_LOCK_MAP -- Locks a database. 361 ** 362 ** Parameters: 363 ** database -- database description. 364 ** type -- type of the lock. Bits can be: 365 ** LOCK_EX -- exclusive lock. 366 ** LOCK_NB -- non-blocking. 367 ** 368 ** Returns: 369 ** SMDBE_OK -- Success, otherwise errno. 370 */ 371 372 int 373 smdb_lock_map(database, type) 374 SMDB_DATABASE *database; 375 int type; 376 { 377 int fd; 378 379 fd = database->smdb_lockfd(database); 380 if (fd < 0) 381 return SMDBE_NOT_FOUND; 382 if (!smdb_lockfile(fd, type)) 383 return SMDBE_LOCK_NOT_GRANTED; 384 return SMDBE_OK; 385 } 386 /* 387 ** SMDB_UNLOCK_MAP -- Unlocks a database 388 ** 389 ** Parameters: 390 ** database -- database description. 391 ** 392 ** Returns: 393 ** SMDBE_OK -- Success, otherwise errno. 394 */ 395 396 int 397 smdb_unlock_map(database) 398 SMDB_DATABASE *database; 399 { 400 int fd; 401 402 fd = database->smdb_lockfd(database); 403 if (fd < 0) 404 return SMDBE_NOT_FOUND; 405 if (!smdb_lockfile(fd, LOCK_UN)) 406 return SMDBE_LOCK_NOT_HELD; 407 return SMDBE_OK; 408 } 409 /* 410 ** SMDB_SETUP_FILE -- Gets db file ready for use. 411 ** 412 ** Makes sure permissions on file are safe and creates it if it 413 ** doesn't exist. 414 ** 415 ** Parameters: 416 ** db_name -- The name of the database without extension. 417 ** extension -- The extension. 418 ** sff -- Flags to safefile. 419 ** mode_mask -- Mode bits that must match. 420 ** user_info -- Information on the user to use for file 421 ** permissions. 422 ** stat_info -- A place to put the stat info for the file. 423 ** Returns: 424 ** SMDBE_OK -- Success, otherwise errno. 425 */ 426 427 int 428 smdb_setup_file(db_name, extension, mode_mask, sff, user_info, stat_info) 429 char *db_name; 430 char *extension; 431 int mode_mask; 432 long sff; 433 SMDB_USER_INFO *user_info; 434 struct stat *stat_info; 435 { 436 int st; 437 int result; 438 char db_file_name[MAXPATHLEN]; 439 440 result = smdb_add_extension(db_file_name, sizeof db_file_name, db_name, 441 extension); 442 if (result != SMDBE_OK) 443 return result; 444 445 st = safefile(db_file_name, user_info->smdbu_id, 446 user_info->smdbu_group_id, user_info->smdbu_name, 447 sff, mode_mask, stat_info); 448 if (st != 0) 449 return st; 450 451 return SMDBE_OK; 452 } 453 /* 454 ** SMDB_FILECHANGED -- Checks to see if a file changed. 455 ** 456 ** Compares the passed in stat_info with a current stat on 457 ** the passed in file descriptor. Check filechanged for 458 ** return values. 459 ** 460 ** Parameters: 461 ** db_name -- The name of the database without extension. 462 ** extension -- The extension. 463 ** db_fd -- A file descriptor for the database file. 464 ** stat_info -- An old stat_info. 465 ** Returns: 466 ** SMDBE_OK -- Success, otherwise errno. 467 */ 468 469 int 470 smdb_filechanged(db_name, extension, db_fd, stat_info) 471 char *db_name; 472 char *extension; 473 int db_fd; 474 struct stat *stat_info; 475 { 476 int result; 477 char db_file_name[MAXPATHLEN]; 478 479 result = smdb_add_extension(db_file_name, sizeof db_file_name, db_name, 480 extension); 481 if (result != SMDBE_OK) 482 return result; 483 return filechanged(db_file_name, db_fd, stat_info); 484 } 485 /* 486 ** SMDB_PRINT_AVAILABLE_TYPES -- Prints the names of the available types. 487 ** 488 ** Parameters: 489 ** None 490 ** 491 ** Returns: 492 ** None 493 */ 494 495 void 496 smdb_print_available_types() 497 { 498 #ifdef NDBM 499 printf("dbm\n"); 500 #endif /* NDBM */ 501 #ifdef NEWDB 502 printf("hash\n"); 503 printf("btree\n"); 504 #endif /* NEWDB */ 505 } 506 /* 507 ** SMDB_DB_DEFINITION -- Given a database type, return database definition 508 ** 509 ** Reads though a structure making an association with the database 510 ** type and the required cpp define from sendmail/README. 511 ** List size is dynamic and must be NULL terminated. 512 ** 513 ** Parameters: 514 ** type -- The name of the database type. 515 ** 516 ** Returns: 517 ** definition for type, otherwise NULL. 518 */ 519 520 typedef struct 521 { 522 SMDB_DBTYPE type; 523 char *dbdef; 524 } dbtype; 525 526 static dbtype DatabaseDefs[] = 527 { 528 { SMDB_TYPE_HASH, "NEWDB" }, 529 { SMDB_TYPE_BTREE, "NEWDB" }, 530 { SMDB_TYPE_NDBM, "NDBM" }, 531 { NULL, "OOPS" } 532 }; 533 534 char * 535 smdb_db_definition(type) 536 SMDB_DBTYPE type; 537 { 538 dbtype *ptr = DatabaseDefs; 539 540 while (ptr != NULL && ptr->type != NULL) 541 { 542 if (strcmp(type, ptr->type) == 0) 543 return ptr->dbdef; 544 ptr++; 545 } 546 return NULL; 547 } 548