smdb.c revision 94334
1/* 2** Copyright (c) 1999-2001 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> 11SM_RCSID("@(#)$Id: smdb.c,v 8.54 2002/04/04 21:32:14 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 32SMDB_DATABASE * 33smdb_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 56void 57smdb_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 77static bool 78smdb_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 187int 188smdb_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 268int 269smdb_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 313int 314smdb_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[SMDB_MAX_NAME_LEN]; 323 324 result = smdb_add_extension(file_name, SMDB_MAX_NAME_LEN, db_name, 325 extension); 326 if (result != SMDBE_OK) 327 return result; 328 329 *lock_fd = safeopen(file_name, mode & ~O_TRUNC, 0644, 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 347int 348smdb_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 372int 373smdb_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 396int 397smdb_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 427int 428smdb_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[SMDB_MAX_NAME_LEN]; 439 440 result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN, 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 469int 470smdb_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[SMDB_MAX_NAME_LEN]; 478 479 result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN, 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 495void 496smdb_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 520typedef struct 521{ 522 SMDB_DBTYPE type; 523 char *dbdef; 524} dbtype; 525 526static dbtype DatabaseDefs[] = 527{ 528 { SMDB_TYPE_HASH, "NEWDB" }, 529 { SMDB_TYPE_BTREE, "NEWDB" }, 530 { SMDB_TYPE_NDBM, "NDBM" }, 531 { NULL, "OOPS" } 532}; 533 534char * 535smdb_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