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