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