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