makemap.c revision 38033
1/* 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3 * Copyright (c) 1992 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 13#ifndef lint 14static char sccsid[] = "@(#)makemap.c 8.62 (Berkeley) 6/24/98"; 15#endif /* not lint */ 16 17#include <sys/types.h> 18#include <sys/errno.h> 19#ifndef ISC_UNIX 20# include <sys/file.h> 21#endif 22#include "sendmail.h" 23#include "pathnames.h" 24 25#ifdef NDBM 26# include <ndbm.h> 27#endif 28 29#ifdef NEWDB 30# include <db.h> 31# ifndef DB_VERSION_MAJOR 32# define DB_VERSION_MAJOR 1 33# endif 34#endif 35 36enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN }; 37 38union dbent 39{ 40#ifdef NDBM 41 datum dbm; 42#endif 43#ifdef NEWDB 44 DBT db; 45#endif 46 struct 47 { 48 char *data; 49 size_t size; 50 } xx; 51}; 52 53uid_t RealUid; 54gid_t RealGid; 55char *RealUserName; 56uid_t RunAsUid; 57uid_t RunAsGid; 58char *RunAsUserName; 59int Verbose = 2; 60bool DontInitGroups = TRUE; 61long DontBlameSendmail = DBS_SAFE; 62u_char tTdvect[100]; 63uid_t TrustedFileUid = 0; 64 65#define BUFSIZE 1024 66 67int 68main(argc, argv) 69 int argc; 70 char **argv; 71{ 72 char *progname; 73 char *cfile; 74 bool inclnull = FALSE; 75 bool notrunc = FALSE; 76 bool allowreplace = FALSE; 77 bool allowdups = FALSE; 78 bool verbose = FALSE; 79 bool foldcase = TRUE; 80 int exitstat; 81 int opt; 82 char *typename; 83 char *mapname; 84 char *ext; 85 int lineno; 86 int st; 87 int mode; 88 int putflags; 89 long dbcachesize = 1024 * 1024; 90 enum type type; 91 int fd; 92 int sff = SFF_ROOTOK|SFF_REGONLY; 93 struct passwd *pw; 94 union 95 { 96#ifdef NDBM 97 DBM *dbm; 98#endif 99#ifdef NEWDB 100 DB *db; 101#endif 102 void *dbx; 103 } dbp; 104 union dbent key, val; 105#ifdef NEWDB 106# if DB_VERSION_MAJOR < 2 107 BTREEINFO bti; 108 HASHINFO hinfo; 109# else 110 DB_INFO dbinfo; 111# endif 112#endif 113 char ibuf[BUFSIZE]; 114 char fbuf[MAXNAME]; 115 char dbuf[MAXNAME]; 116#ifdef NDBM 117 char pbuf[MAXNAME]; 118#endif 119#if _FFR_TRUSTED_FILE_OWNER 120 FILE *cfp; 121 char buf[MAXLINE]; 122#endif 123 static char rnamebuf[MAXNAME]; /* holds RealUserName */ 124 struct stat std; 125#ifdef NDBM 126 struct stat stp; 127#endif 128 extern char *optarg; 129 extern int optind; 130 131 progname = argv[0]; 132 cfile = _PATH_SENDMAILCF; 133 134 RunAsUid = RealUid = getuid(); 135 RunAsGid = RealGid = getgid(); 136 pw = getpwuid(RealUid); 137 if (pw != NULL) 138 { 139 if (strlen(pw->pw_name) > MAXNAME - 1) 140 pw->pw_name[MAXNAME] = 0; 141 sprintf(rnamebuf, "%s", pw->pw_name); 142 } 143 else 144 sprintf(rnamebuf, "Unknown UID %d", (int) RealUid); 145 RunAsUserName = RealUserName = rnamebuf; 146 147#if _FFR_NEW_MAKEMAP_FLAGS 148#define OPTIONS "C:Nc:dforsv" 149#else 150#define OPTIONS "C:Ndforsv" 151#endif 152 while ((opt = getopt(argc, argv, OPTIONS)) != EOF) 153 { 154 switch (opt) 155 { 156 case 'C': 157 cfile = optarg; 158 break; 159 160 case 'N': 161 inclnull = TRUE; 162 break; 163 164#if _FFR_NEW_MAKEMAP_FLAGS 165 case 'c': 166 dbcachesize = atol(optarg); 167 break; 168#endif 169 170 case 'd': 171 allowdups = TRUE; 172 break; 173 174 case 'f': 175 foldcase = FALSE; 176 break; 177 178 case 'o': 179 notrunc = TRUE; 180 break; 181 182 case 'r': 183 allowreplace = TRUE; 184 break; 185 186 case 's': 187 DontBlameSendmail |= DBS_MAPINUNSAFEDIRPATH|DBS_WRITEMAPTOHARDLINK|DBS_WRITEMAPTOSYMLINK|DBS_LINKEDMAPINWRITABLEDIR; 188 break; 189 190 case 'v': 191 verbose = TRUE; 192 break; 193 194 default: 195 type = T_ERR; 196 break; 197 } 198 } 199 200 if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 201 sff |= SFF_NOSLINK; 202 if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 203 sff |= SFF_NOHLINK; 204 if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 205 sff |= SFF_NOWLINK; 206 207 argc -= optind; 208 argv += optind; 209 if (argc != 2) 210 type = T_ERR; 211 else 212 { 213 typename = argv[0]; 214 mapname = argv[1]; 215 ext = NULL; 216 217 if (strcmp(typename, "dbm") == 0) 218 { 219 type = T_DBM; 220 } 221 else if (strcmp(typename, "btree") == 0) 222 { 223 type = T_BTREE; 224 ext = ".db"; 225 } 226 else if (strcmp(typename, "hash") == 0) 227 { 228 type = T_HASH; 229 ext = ".db"; 230 } 231 else 232 type = T_UNKNOWN; 233 } 234 235#if _FFR_TRUSTED_FILE_OWNER 236 if ((cfp = fopen(cfile, "r")) == NULL) 237 { 238 fprintf(stderr, "mailstats: "); 239 perror(cfile); 240 exit(EX_NOINPUT); 241 } 242 while (fgets(buf, sizeof(buf), cfp) != NULL) 243 { 244 register char *b; 245 246 if ((b = strchr(buf, '\n')) != NULL) 247 *b = '\0'; 248 249 b = buf; 250 switch (*b++) 251 { 252 case 'O': /* option */ 253 if (strncasecmp(b, " TrustedFileOwner", 17) == 0 && 254 !(isascii(b[17]) && isalnum(b[17]))) 255 { 256 b = strchr(b, '='); 257 if (b == NULL) 258 continue; 259 while (isascii(*++b) && isspace(*b)) 260 continue; 261 if (isascii(*b) && isdigit(*b)) 262 TrustedFileUid = atoi(b); 263 else 264 { 265 register struct passwd *pw; 266 267 TrustedFileUid = 0; 268 pw = getpwnam(b); 269 if (pw == NULL) 270 fprintf(stderr, 271 "TrustedFileOwner: unknown user %s", b); 272 else 273 TrustedFileUid = pw->pw_uid; 274 } 275 276# ifdef UID_MAX 277 if (TrustedFileUid > UID_MAX) 278 { 279 syserr("TrustedFileOwner: uid value (%ld) > UID_MAX (%ld)", 280 TrustedFileUid, UID_MAX); 281 TrustedFileUid = 0; 282 } 283# endif 284 break; 285 } 286 287 288 default: 289 continue; 290 } 291 } 292 (void) fclose(cfp); 293#endif 294 switch (type) 295 { 296 case T_ERR: 297#if _FFR_NEW_MAKEMAP_FLAGS 298 fprintf(stderr, 299 "Usage: %s [-N] [-c cachesize] [-d] [-f] [-o] [-r] [-s] [-v] type mapname\n", 300 progname); 301#else 302 fprintf(stderr, "Usage: %s [-N] [-d] [-f] [-o] [-r] [-s] [-v] type mapname\n", progname); 303#endif 304 exit(EX_USAGE); 305 306 case T_UNKNOWN: 307 fprintf(stderr, "%s: Unknown database type %s\n", 308 progname, typename); 309 exit(EX_USAGE); 310 311#ifndef NDBM 312 case T_DBM: 313#endif 314#ifndef NEWDB 315 case T_BTREE: 316 case T_HASH: 317#endif 318 fprintf(stderr, "%s: Type %s not supported in this version\n", 319 progname, typename); 320 exit(EX_UNAVAILABLE); 321 322#ifdef NEWDB 323 case T_BTREE: 324# if DB_VERSION_MAJOR < 2 325 bzero(&bti, sizeof bti); 326# else 327 bzero(&dbinfo, sizeof dbinfo); 328# endif 329 if (allowdups) 330 { 331# if DB_VERSION_MAJOR < 2 332 bti.flags |= R_DUP; 333# else 334 dbinfo.flags |= DB_DUP; 335# endif 336 } 337 if (allowdups || allowreplace) 338 putflags = 0; 339 else 340 { 341# if DB_VERSION_MAJOR < 2 342 putflags = R_NOOVERWRITE; 343# else 344 putflags = DB_NOOVERWRITE; 345# endif 346 } 347 break; 348 349 case T_HASH: 350# if DB_VERSION_MAJOR < 2 351 bzero(&hinfo, sizeof hinfo); 352# else 353 bzero(&dbinfo, sizeof dbinfo); 354# endif 355 if (allowreplace) 356 putflags = 0; 357 else 358 { 359# if DB_VERSION_MAJOR < 2 360 putflags = R_NOOVERWRITE; 361# else 362 putflags = DB_NOOVERWRITE; 363# endif 364 } 365 break; 366#endif 367#ifdef NDBM 368 case T_DBM: 369 if (allowdups) 370 { 371 fprintf(stderr, "%s: Type %s does not support -d (allow dups)\n", 372 progname, typename); 373 exit(EX_UNAVAILABLE); 374 } 375 if (allowreplace) 376 putflags = DBM_REPLACE; 377 else 378 putflags = DBM_INSERT; 379 break; 380#endif 381 } 382 383 /* 384 ** Adjust file names. 385 */ 386 387 if (ext != NULL) 388 { 389 int el, fl; 390 391 el = strlen(ext); 392 fl = strlen(mapname); 393 if (el + fl + 1 >= sizeof fbuf) 394 { 395 fprintf(stderr, "%s: file name too long", mapname); 396 exit(EX_USAGE); 397 } 398 if (fl < el || strcmp(&mapname[fl - el], ext) != 0) 399 { 400 strcpy(fbuf, mapname); 401 strcat(fbuf, ext); 402 mapname = fbuf; 403 } 404 } 405 406 if (!notrunc) 407 sff |= SFF_CREAT; 408 switch (type) 409 { 410#ifdef NEWDB 411 case T_BTREE: 412 case T_HASH: 413 if (strlen(mapname) >= sizeof dbuf) 414 { 415 fprintf(stderr, 416 "%s: map name too long\n", mapname); 417 exit(EX_USAGE); 418 } 419 strcpy(dbuf, mapname); 420 if ((st = safefile(dbuf, RealUid, RealGid, RealUserName, 421 sff, S_IWUSR, &std)) != 0) 422 { 423 fprintf(stderr, 424 "%s: could not create: %s\n", 425 dbuf, errstring(st)); 426 exit(EX_CANTCREAT); 427 } 428 break; 429#endif 430#ifdef NDBM 431 case T_DBM: 432 if (strlen(mapname) + 5 > sizeof dbuf) 433 { 434 fprintf(stderr, 435 "%s: map name too long\n", mapname); 436 exit(EX_USAGE); 437 } 438 sprintf(dbuf, "%s.dir", mapname); 439 if ((st = safefile(dbuf, RealUid, RealGid, RealUserName, 440 sff, S_IWUSR, &std)) != 0) 441 { 442 fprintf(stderr, 443 "%s: could not create: %s\n", 444 dbuf, errstring(st)); 445 exit(EX_CANTCREAT); 446 } 447 sprintf(pbuf, "%s.pag", mapname); 448 if ((st = safefile(pbuf, RealUid, RealGid, RealUserName, 449 sff, S_IWUSR, &stp)) != 0) 450 { 451 fprintf(stderr, 452 "%s: could not create: %s\n", 453 pbuf, errstring(st)); 454 exit(EX_CANTCREAT); 455 } 456 break; 457#endif 458 default: 459 fprintf(stderr, 460 "%s: internal error: type %d\n", 461 progname, 462 type); 463 exit(EX_SOFTWARE); 464 } 465 466 /* 467 ** Create the database. 468 */ 469 470 mode = O_RDWR; 471 if (!notrunc) 472 mode |= O_CREAT|O_TRUNC; 473#if O_EXLOCK 474 mode |= O_EXLOCK; 475#else 476 /* pre-lock the database */ 477 fd = safeopen(dbuf, mode & ~O_TRUNC, 0644, sff); 478 if (fd < 0) 479 { 480 fprintf(stderr, "%s: cannot create type %s map %s\n", 481 progname, typename, mapname); 482 exit(EX_CANTCREAT); 483 } 484#endif 485 switch (type) 486 { 487#ifdef NDBM 488 case T_DBM: 489 dbp.dbm = dbm_open(mapname, mode, 0644); 490 if (dbp.dbm != NULL && 491 dbm_dirfno(dbp.dbm) == dbm_pagfno(dbp.dbm)) 492 { 493 fprintf(stderr, "dbm map %s: cannot run with GDBM\n", 494 mapname); 495 dbm_close(dbp.dbm); 496 exit(EX_CONFIG); 497 } 498 if (dbp.dbm != NULL && 499 (filechanged(dbuf, dbm_dirfno(dbp.dbm), &std) || 500 filechanged(pbuf, dbm_pagfno(dbp.dbm), &stp))) 501 { 502 fprintf(stderr, 503 "dbm map %s: file changed after open\n", 504 mapname); 505 dbm_close(dbp.dbm); 506 exit(EX_CANTCREAT); 507 } 508 if (geteuid() == 0 && TrustedFileUid != 0) 509 { 510 if (fchown(dbm_dirfno(dbp.dbm), TrustedFileUid, -1) < 0 || 511 fchown(dbm_pagfno(dbp.dbm), TrustedFileUid, -1) < 0) 512 { 513 fprintf(stderr, 514 "WARNING: ownership change on %s failed: %s", 515 mapname, errstring(errno)); 516 } 517 } 518 519 break; 520#endif 521 522#ifdef NEWDB 523 case T_HASH: 524 /* tweak some parameters for performance */ 525# if DB_VERSION_MAJOR < 2 526 hinfo.nelem = 4096; 527 hinfo.cachesize = dbcachesize; 528# else 529 dbinfo.h_nelem = 4096; 530 dbinfo.db_cachesize = dbcachesize; 531# endif 532 533# if DB_VERSION_MAJOR < 2 534 dbp.db = dbopen(mapname, mode, 0644, DB_HASH, &hinfo); 535# else 536 { 537 int flags = 0; 538 539 if (bitset(O_CREAT, mode)) 540 flags |= DB_CREATE; 541 if (bitset(O_TRUNC, mode)) 542 flags |= DB_TRUNCATE; 543 544 dbp.db = NULL; 545 errno = db_open(mapname, DB_HASH, flags, 0644, 546 NULL, &dbinfo, &dbp.db); 547 } 548# endif 549 if (dbp.db != NULL) 550 { 551 int fd; 552 553# if DB_VERSION_MAJOR < 2 554 fd = dbp.db->fd(dbp.db); 555# else 556 fd = -1; 557 errno = dbp.db->fd(dbp.db, &fd); 558# endif 559 if (filechanged(dbuf, fd, &std)) 560 { 561 fprintf(stderr, 562 "db map %s: file changed after open\n", 563 mapname); 564# if DB_VERSION_MAJOR < 2 565 dbp.db->close(dbp.db); 566# else 567 errno = dbp.db->close(dbp.db, 0); 568# endif 569 exit(EX_CANTCREAT); 570 } 571 (void) (*dbp.db->sync)(dbp.db, 0); 572 if (geteuid() == 0 && TrustedFileUid != 0) 573 { 574 if (fchown(fd, TrustedFileUid, -1) < 0) 575 { 576 fprintf(stderr, 577 "WARNING: ownership change on %s failed: %s", 578 mapname, errstring(errno)); 579 } 580 } 581 } 582 break; 583 584 case T_BTREE: 585 /* tweak some parameters for performance */ 586# if DB_VERSION_MAJOR < 2 587 bti.cachesize = dbcachesize; 588# else 589 dbinfo.db_cachesize = dbcachesize; 590# endif 591 592# if DB_VERSION_MAJOR < 2 593 dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, &bti); 594# else 595 { 596 int flags = 0; 597 598 if (bitset(O_CREAT, mode)) 599 flags |= DB_CREATE; 600 if (bitset(O_TRUNC, mode)) 601 flags |= DB_TRUNCATE; 602 603 dbp.db = NULL; 604 errno = db_open(mapname, DB_BTREE, flags, 0644, 605 NULL, &dbinfo, &dbp.db); 606 } 607# endif 608 if (dbp.db != NULL) 609 { 610 int fd; 611 612# if DB_VERSION_MAJOR < 2 613 fd = dbp.db->fd(dbp.db); 614# else 615 fd = -1; 616 errno = dbp.db->fd(dbp.db, &fd); 617# endif 618 if (filechanged(dbuf, fd, &std)) 619 { 620 fprintf(stderr, 621 "db map %s: file changed after open\n", 622 mapname); 623# if DB_VERSION_MAJOR < 2 624 dbp.db->close(dbp.db); 625# else 626 errno = dbp.db->close(dbp.db, 0); 627# endif 628 exit(EX_CANTCREAT); 629 } 630 (void) (*dbp.db->sync)(dbp.db, 0); 631 if (geteuid() == 0 && TrustedFileUid != 0) 632 { 633 if (fchown(fd, TrustedFileUid, -1) < 0) 634 { 635 fprintf(stderr, 636 "WARNING: ownership change on %s failed: %s", 637 mapname, errstring(errno)); 638 } 639 } 640 } 641 break; 642#endif 643 644 default: 645 fprintf(stderr, "%s: internal error: type %d\n", 646 progname, type); 647 exit(EX_SOFTWARE); 648 } 649 650 if (dbp.dbx == NULL) 651 { 652 fprintf(stderr, "%s: cannot open type %s map %s\n", 653 progname, typename, mapname); 654 exit(EX_CANTCREAT); 655 } 656 657 /* 658 ** Copy the data 659 */ 660 661 lineno = 0; 662 exitstat = EX_OK; 663 while (fgets(ibuf, sizeof ibuf, stdin) != NULL) 664 { 665 register char *p; 666 667 lineno++; 668 669 /* 670 ** Parse the line. 671 */ 672 673 p = strchr(ibuf, '\n'); 674 if (p != NULL) 675 *p = '\0'; 676 else if (!feof(stdin)) 677 { 678 fprintf(stderr, "%s: %s: line %d: line too long (%ld bytes max)\n", 679 progname, mapname, lineno, (long) sizeof ibuf); 680 continue; 681 } 682 683 if (ibuf[0] == '\0' || ibuf[0] == '#') 684 continue; 685 if (isascii(ibuf[0]) && isspace(ibuf[0])) 686 { 687 fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n", 688 progname, mapname, lineno); 689 continue; 690 } 691#ifdef NEWDB 692 if (type == T_HASH || type == T_BTREE) 693 { 694 bzero(&key.db, sizeof key.db); 695 bzero(&val.db, sizeof val.db); 696 } 697#endif 698 699 key.xx.data = ibuf; 700 for (p = ibuf; *p != '\0' && !(isascii(*p) && isspace(*p)); p++) 701 { 702 if (foldcase && isascii(*p) && isupper(*p)) 703 *p = tolower(*p); 704 } 705 key.xx.size = p - key.xx.data; 706 if (inclnull) 707 key.xx.size++; 708 if (*p != '\0') 709 *p++ = '\0'; 710 while (isascii(*p) && isspace(*p)) 711 p++; 712 if (*p == '\0') 713 { 714 fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n", 715 progname, mapname, lineno, key.xx.data); 716 continue; 717 } 718 val.xx.data = p; 719 val.xx.size = strlen(p); 720 if (inclnull) 721 val.xx.size++; 722 723 /* 724 ** Do the database insert. 725 */ 726 727 if (verbose) 728 { 729 printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data); 730 } 731 732 switch (type) 733 { 734#ifdef NDBM 735 case T_DBM: 736 st = dbm_store(dbp.dbm, key.dbm, val.dbm, putflags); 737 break; 738#endif 739 740#ifdef NEWDB 741 case T_BTREE: 742 case T_HASH: 743# if DB_VERSION_MAJOR < 2 744 st = (*dbp.db->put)(dbp.db, &key.db, &val.db, putflags); 745# else 746 errno = (*dbp.db->put)(dbp.db, NULL, &key.db, 747 &val.db, putflags); 748 switch (errno) 749 { 750 case DB_KEYEXIST: 751 st = 1; 752 break; 753 754 case 0: 755 st = 0; 756 break; 757 758 default: 759 st = -1; 760 break; 761 } 762# endif 763 break; 764#endif 765 default: 766 break; 767 } 768 769 if (st < 0) 770 { 771 fprintf(stderr, "%s: %s: line %d: key %s: put error\n", 772 progname, mapname, lineno, key.xx.data); 773 perror(mapname); 774 exitstat = EX_IOERR; 775 } 776 else if (st > 0) 777 { 778 fprintf(stderr, 779 "%s: %s: line %d: key %s: duplicate key\n", 780 progname, mapname, lineno, key.xx.data); 781 } 782 } 783 784 /* 785 ** Now close the database. 786 */ 787 788 switch (type) 789 { 790#ifdef NDBM 791 case T_DBM: 792 dbm_close(dbp.dbm); 793 break; 794#endif 795 796#ifdef NEWDB 797 case T_HASH: 798 case T_BTREE: 799# if DB_VERSION_MAJOR < 2 800 if ((*dbp.db->close)(dbp.db) < 0) 801# else 802 if ((errno = (*dbp.db->close)(dbp.db, 0)) != 0) 803# endif 804 { 805 fprintf(stderr, "%s: %s: error on close\n", 806 progname, mapname); 807 perror(mapname); 808 exitstat = EX_IOERR; 809 } 810#endif 811 default: 812 break; 813 } 814 815#if !O_EXLOCK 816 /* release locks */ 817 close(fd); 818#endif 819 820 exit (exitstat); 821} 822/* 823** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 824** 825** Parameters: 826** fd -- the file descriptor of the file. 827** filename -- the file name (for error messages). 828** ext -- the filename extension. 829** type -- type of the lock. Bits can be: 830** LOCK_EX -- exclusive lock. 831** LOCK_NB -- non-blocking. 832** 833** Returns: 834** TRUE if the lock was acquired. 835** FALSE otherwise. 836*/ 837 838bool 839lockfile(fd, filename, ext, type) 840 int fd; 841 char *filename; 842 char *ext; 843 int type; 844{ 845# if !HASFLOCK 846 int action; 847 struct flock lfd; 848 extern int errno; 849 850 bzero(&lfd, sizeof lfd); 851 if (bitset(LOCK_UN, type)) 852 lfd.l_type = F_UNLCK; 853 else if (bitset(LOCK_EX, type)) 854 lfd.l_type = F_WRLCK; 855 else 856 lfd.l_type = F_RDLCK; 857 if (bitset(LOCK_NB, type)) 858 action = F_SETLK; 859 else 860 action = F_SETLKW; 861 862 if (fcntl(fd, action, &lfd) >= 0) 863 return TRUE; 864 865 /* 866 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 867 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 868 ** as type "tmp" (that is, served from swap space), the 869 ** previous fcntl will fail with "Invalid argument" errors. 870 ** Since this is fairly common during testing, we will assume 871 ** that this indicates that the lock is successfully grabbed. 872 */ 873 874 if (errno == EINVAL) 875 return TRUE; 876 877# else /* HASFLOCK */ 878 879 if (flock(fd, type) >= 0) 880 return TRUE; 881 882# endif 883 884 return FALSE; 885} 886 887/*VARARGS1*/ 888void 889#ifdef __STDC__ 890message(const char *msg, ...) 891#else 892message(msg, va_alist) 893 const char *msg; 894 va_dcl 895#endif 896{ 897 const char *m; 898 VA_LOCAL_DECL 899 900 m = msg; 901 if (isascii(m[0]) && isdigit(m[0]) && 902 isascii(m[1]) && isdigit(m[1]) && 903 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 904 m += 4; 905 VA_START(msg); 906 vfprintf(stderr, m, ap); 907 VA_END; 908 fprintf(stderr, "\n"); 909} 910 911/*VARARGS1*/ 912void 913#ifdef __STDC__ 914syserr(const char *msg, ...) 915#else 916syserr(msg, va_alist) 917 const char *msg; 918 va_dcl 919#endif 920{ 921 const char *m; 922 VA_LOCAL_DECL 923 924 m = msg; 925 if (isascii(m[0]) && isdigit(m[0]) && 926 isascii(m[1]) && isdigit(m[1]) && 927 isascii(m[2]) && isdigit(m[2]) && m[3] == ' ') 928 m += 4; 929 VA_START(msg); 930 vfprintf(stderr, m, ap); 931 VA_END; 932 fprintf(stderr, "\n"); 933} 934 935const char * 936errstring(err) 937 int err; 938{ 939 static char errstr[64]; 940#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 941 extern char *sys_errlist[]; 942 extern int sys_nerr; 943#endif 944 945 /* handle pseudo-errors internal to sendmail */ 946 switch (err) 947 { 948 case E_SM_OPENTIMEOUT: 949 return "Timeout on file open"; 950 951 case E_SM_NOSLINK: 952 return "Symbolic links not allowed"; 953 954 case E_SM_NOHLINK: 955 return "Hard links not allowed"; 956 957 case E_SM_REGONLY: 958 return "Regular files only"; 959 960 case E_SM_ISEXEC: 961 return "Executable files not allowed"; 962 963 case E_SM_WWDIR: 964 return "World writable directory"; 965 966 case E_SM_GWDIR: 967 return "Group writable directory"; 968 969 case E_SM_FILECHANGE: 970 return "File changed after open"; 971 972 case E_SM_WWFILE: 973 return "World writable file"; 974 975 case E_SM_GWFILE: 976 return "Group writable file"; 977 } 978 979#if HASSTRERROR 980 return strerror(err); 981#else 982 if (err < 0 || err >= sys_nerr) 983 { 984 sprintf(errstr, "Error %d", err); 985 return errstr; 986 } 987 return sys_errlist[err]; 988#endif 989} 990