1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 8.111 (Berkeley) 10/24/94"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include "pathnames.h" 15 # include <sys/ioctl.h> 16 # include <sys/param.h> 17 # include <netdb.h> 18 # include <pwd.h> 19 20 /* 21 ** CONF.C -- Sendmail Configuration Tables. 22 ** 23 ** Defines the configuration of this installation. 24 ** 25 ** Configuration Variables: 26 ** HdrInfo -- a table describing well-known header fields. 27 ** Each entry has the field name and some flags, 28 ** which are described in sendmail.h. 29 ** 30 ** Notes: 31 ** I have tried to put almost all the reasonable 32 ** configuration information into the configuration 33 ** file read at runtime. My intent is that anything 34 ** here is a function of the version of UNIX you 35 ** are running, or is really static -- for example 36 ** the headers are a superset of widely used 37 ** protocols. If you find yourself playing with 38 ** this file too much, you may be making a mistake! 39 */ 40 41 42 43 44 /* 45 ** Header info table 46 ** Final (null) entry contains the flags used for any other field. 47 ** 48 ** Not all of these are actually handled specially by sendmail 49 ** at this time. They are included as placeholders, to let 50 ** you know that "someday" I intend to have sendmail do 51 ** something with them. 52 */ 53 54 struct hdrinfo HdrInfo[] = 55 { 56 /* originator fields, most to least significant */ 57 "resent-sender", H_FROM|H_RESENT, 58 "resent-from", H_FROM|H_RESENT, 59 "resent-reply-to", H_FROM|H_RESENT, 60 "sender", H_FROM, 61 "from", H_FROM, 62 "reply-to", H_FROM, 63 "full-name", H_ACHECK, 64 "return-receipt-to", H_FROM|H_RECEIPTTO, 65 "errors-to", H_FROM|H_ERRORSTO, 66 67 /* destination fields */ 68 "to", H_RCPT, 69 "resent-to", H_RCPT|H_RESENT, 70 "cc", H_RCPT, 71 "resent-cc", H_RCPT|H_RESENT, 72 "bcc", H_RCPT|H_ACHECK, 73 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 74 "apparently-to", H_RCPT, 75 76 /* message identification and control */ 77 "message-id", 0, 78 "resent-message-id", H_RESENT, 79 "message", H_EOH, 80 "text", H_EOH, 81 82 /* date fields */ 83 "date", 0, 84 "resent-date", H_RESENT, 85 86 /* trace fields */ 87 "received", H_TRACE|H_FORCE, 88 "x400-received", H_TRACE|H_FORCE, 89 "via", H_TRACE|H_FORCE, 90 "mail-from", H_TRACE|H_FORCE, 91 92 /* miscellaneous fields */ 93 "comments", H_FORCE, 94 "return-path", H_FORCE|H_ACHECK, 95 "content-transfer-encoding", H_CTE, 96 97 NULL, 0, 98 }; 99 100 101 102 /* 103 ** Location of system files/databases/etc. 104 */ 105 106 char *PidFile = _PATH_SENDMAILPID; /* stores daemon proc id */ 107 108 109 110 /* 111 ** Privacy values 112 */ 113 114 struct prival PrivacyValues[] = 115 { 116 "public", PRIV_PUBLIC, 117 "needmailhelo", PRIV_NEEDMAILHELO, 118 "needexpnhelo", PRIV_NEEDEXPNHELO, 119 "needvrfyhelo", PRIV_NEEDVRFYHELO, 120 "noexpn", PRIV_NOEXPN, 121 "novrfy", PRIV_NOVRFY, 122 "restrictmailq", PRIV_RESTRICTMAILQ, 123 "restrictqrun", PRIV_RESTRICTQRUN, 124 "authwarnings", PRIV_AUTHWARNINGS, 125 "noreceipts", PRIV_NORECEIPTS, 126 "goaway", PRIV_GOAWAY, 127 NULL, 0, 128 }; 129 130 131 132 /* 133 ** Miscellaneous stuff. 134 */ 135 136 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 137 /* 138 ** SETDEFAULTS -- set default values 139 ** 140 ** Because of the way freezing is done, these must be initialized 141 ** using direct code. 142 ** 143 ** Parameters: 144 ** e -- the default envelope. 145 ** 146 ** Returns: 147 ** none. 148 ** 149 ** Side Effects: 150 ** Initializes a bunch of global variables to their 151 ** default values. 152 */ 153 154 #define DAYS * 24 * 60 * 60 155 156 setdefaults(e) 157 register ENVELOPE *e; 158 { 159 int i; 160 161 SpaceSub = ' '; /* option B */ 162 QueueLA = 8; /* option x */ 163 RefuseLA = 12; /* option X */ 164 WkRecipFact = 30000L; /* option y */ 165 WkClassFact = 1800L; /* option z */ 166 WkTimeFact = 90000L; /* option Z */ 167 QueueFactor = WkRecipFact * 20; /* option q */ 168 FileMode = (RealUid != geteuid()) ? 0644 : 0600; 169 /* option F */ 170 DefUid = 1; /* option u */ 171 DefGid = 1; /* option g */ 172 CheckpointInterval = 10; /* option C */ 173 MaxHopCount = 25; /* option h */ 174 e->e_sendmode = SM_FORK; /* option d */ 175 e->e_errormode = EM_PRINT; /* option e */ 176 SevenBitInput = FALSE; /* option 7 */ 177 MaxMciCache = 1; /* option k */ 178 MciCacheTimeout = 300; /* option K */ 179 LogLevel = 9; /* option L */ 180 settimeouts(NULL); /* option r */ 181 PrivacyFlags = 0; /* option p */ 182 MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */ 183 for (i = 0; i < MAXTOCLASS; i++) 184 { 185 TimeOuts.to_q_return[i] = 5 DAYS; /* option T */ 186 TimeOuts.to_q_warning[i] = 0; /* option T */ 187 } 188 ServiceSwitchFile = "/etc/service.switch"; 189 setdefuser(); 190 setupmaps(); 191 setupmailers(); 192 } 193 194 195 /* 196 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 197 */ 198 199 setdefuser() 200 { 201 struct passwd *defpwent; 202 static char defuserbuf[40]; 203 204 DefUser = defuserbuf; 205 if ((defpwent = getpwuid(DefUid)) != NULL) 206 strcpy(defuserbuf, defpwent->pw_name); 207 else 208 strcpy(defuserbuf, "nobody"); 209 } 210 /* 211 ** HOST_MAP_INIT -- initialize host class structures 212 */ 213 214 bool host_map_init __P((MAP *map, char *args)); 215 216 bool 217 host_map_init(map, args) 218 MAP *map; 219 char *args; 220 { 221 register char *p = args; 222 223 for (;;) 224 { 225 while (isascii(*p) && isspace(*p)) 226 p++; 227 if (*p != '-') 228 break; 229 switch (*++p) 230 { 231 case 'a': 232 map->map_app = ++p; 233 break; 234 } 235 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 236 p++; 237 if (*p != '\0') 238 *p++ = '\0'; 239 } 240 if (map->map_app != NULL) 241 map->map_app = newstr(map->map_app); 242 return TRUE; 243 } 244 /* 245 ** SETUPMAILERS -- initialize default mailers 246 */ 247 248 setupmailers() 249 { 250 char buf[100]; 251 252 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 253 makemailer(buf); 254 255 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE"); 256 makemailer(buf); 257 258 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 259 makemailer(buf); 260 } 261 /* 262 ** SETUPMAPS -- set up map classes 263 */ 264 265 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \ 266 { \ 267 extern bool parse __P((MAP *, char *)); \ 268 extern bool open __P((MAP *, int)); \ 269 extern void close __P((MAP *)); \ 270 extern char *lookup __P((MAP *, char *, char **, int *)); \ 271 extern void store __P((MAP *, char *, char *)); \ 272 s = stab(name, ST_MAPCLASS, ST_ENTER); \ 273 s->s_mapclass.map_cname = name; \ 274 s->s_mapclass.map_ext = ext; \ 275 s->s_mapclass.map_cflags = flags; \ 276 s->s_mapclass.map_parse = parse; \ 277 s->s_mapclass.map_open = open; \ 278 s->s_mapclass.map_close = close; \ 279 s->s_mapclass.map_lookup = lookup; \ 280 s->s_mapclass.map_store = store; \ 281 } 282 283 setupmaps() 284 { 285 register STAB *s; 286 287 #ifdef NEWDB 288 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 289 map_parseargs, hash_map_open, db_map_close, 290 db_map_lookup, db_map_store); 291 292 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 293 map_parseargs, bt_map_open, db_map_close, 294 db_map_lookup, db_map_store); 295 #endif 296 297 #ifdef NDBM 298 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE, 299 map_parseargs, ndbm_map_open, ndbm_map_close, 300 ndbm_map_lookup, ndbm_map_store); 301 #endif 302 303 #ifdef NIS 304 MAPDEF("nis", NULL, MCF_ALIASOK, 305 map_parseargs, nis_map_open, null_map_close, 306 nis_map_lookup, null_map_store); 307 #endif 308 309 #ifdef NISPLUS 310 MAPDEF("nisplus", NULL, MCF_ALIASOK, 311 map_parseargs, nisplus_map_open, null_map_close, 312 nisplus_map_lookup, null_map_store); 313 #endif 314 315 #ifdef HESIOD 316 MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY, 317 map_parseargs, null_map_open, null_map_close, 318 hesiod_map_lookup, null_map_store); 319 #endif 320 321 #ifdef NETINFO 322 MAPDEF("netinfo", NULL, MCF_ALIASOK, 323 map_parseargs, ni_map_open, null_map_close, 324 ni_map_lookup, null_map_store); 325 #endif 326 327 #if 0 328 MAPDEF("dns", NULL, 0, 329 dns_map_init, null_map_open, null_map_close, 330 dns_map_lookup, null_map_store); 331 #endif 332 333 MAPDEF("host", NULL, 0, 334 host_map_init, null_map_open, null_map_close, 335 host_map_lookup, null_map_store); 336 337 MAPDEF("text", NULL, MCF_ALIASOK, 338 map_parseargs, text_map_open, null_map_close, 339 text_map_lookup, null_map_store); 340 341 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY, 342 map_parseargs, stab_map_open, null_map_close, 343 stab_map_lookup, stab_map_store); 344 345 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE, 346 map_parseargs, impl_map_open, impl_map_close, 347 impl_map_lookup, impl_map_store); 348 349 /* access to system passwd file */ 350 MAPDEF("user", NULL, 0, 351 map_parseargs, user_map_open, null_map_close, 352 user_map_lookup, null_map_store); 353 354 /* dequote map */ 355 MAPDEF("dequote", NULL, 0, 356 dequote_init, null_map_open, null_map_close, 357 dequote_map, null_map_store); 358 359 #if 0 360 # ifdef USERDB 361 /* user database */ 362 MAPDEF("udb", ".db", 0, 363 udb_map_parse, null_map_open, null_map_close, 364 udb_map_lookup, null_map_store); 365 # endif 366 #endif 367 368 /* sequenced maps */ 369 MAPDEF("sequence", NULL, MCF_ALIASOK, 370 seq_map_parse, null_map_open, seq_map_close, 371 seq_map_lookup, seq_map_store); 372 373 /* switched interface to sequenced maps */ 374 MAPDEF("switch", NULL, MCF_ALIASOK|MCF_REBUILDABLE, 375 map_parseargs, switch_map_open, seq_map_close, 376 seq_map_lookup, seq_map_store); 377 } 378 379 #undef MAPDEF 380 /* 381 ** INITHOSTMAPS -- initial host-dependent maps 382 ** 383 ** This should act as an interface to any local service switch 384 ** provided by the host operating system. 385 ** 386 ** Parameters: 387 ** none 388 ** 389 ** Returns: 390 ** none 391 ** 392 ** Side Effects: 393 ** Should define maps "host" and "users" as necessary 394 ** for this OS. If they are not defined, they will get 395 ** a default value later. It should check to make sure 396 ** they are not defined first, since it's possible that 397 ** the config file has provided an override. 398 */ 399 400 void 401 inithostmaps() 402 { 403 char buf[MAXLINE]; 404 405 /* 406 ** Make sure we have a host map. 407 */ 408 409 if (stab("host", ST_MAP, ST_FIND) == NULL) 410 { 411 /* user didn't initialize: set up host map */ 412 strcpy(buf, "host host"); 413 #if NAMED_BIND 414 if (ConfigLevel >= 2) 415 strcat(buf, " -a."); 416 #endif 417 makemapentry(buf); 418 } 419 420 /* 421 ** Set up default aliases maps 422 */ 423 424 if (stab("aliases.files", ST_MAP, ST_FIND) == NULL) 425 { 426 strcpy(buf, "aliases.files implicit /etc/aliases"); 427 makemapentry(buf); 428 } 429 #ifdef NISPLUS 430 if (stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL) 431 { 432 strcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion -d mail_aliases.org_dir"); 433 makemapentry(buf); 434 } 435 #endif 436 #ifdef NIS 437 if (stab("aliases.nis", ST_MAP, ST_FIND) == NULL) 438 { 439 strcpy(buf, "aliases.nis nis -d mail.aliases"); 440 makemapentry(buf); 441 } 442 #endif 443 if (stab("aliases", ST_MAP, ST_FIND) == NULL) 444 { 445 strcpy(buf, "aliases switch aliases"); 446 makemapentry(buf); 447 } 448 strcpy(buf, "switch:aliases"); 449 setalias(buf); 450 451 #if 0 /* "user" map class is a better choice */ 452 /* 453 ** Set up default users maps. 454 */ 455 456 if (stab("users.files", ST_MAP, ST_FIND) == NULL) 457 { 458 strcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd"); 459 makemapentry(buf); 460 } 461 #ifdef NISPLUS 462 if (stab("users.nisplus", ST_MAP, ST_FIND) == NULL) 463 { 464 strcpy(buf, "users.nisplus nisplus -m -kname -vhome -d passwd.org_dir"); 465 makemapentry(buf); 466 } 467 #endif 468 #ifdef NIS 469 if (stab("users.nis", ST_MAP, ST_FIND) == NULL) 470 { 471 strcpy(buf, "users.nis nis -m -d passwd.byname"); 472 makemapentry(buf); 473 } 474 #endif 475 if (stab("users", ST_MAP, ST_FIND) == NULL) 476 { 477 strcpy(buf, "users switch -m passwd"); 478 makemapentry(buf); 479 } 480 #endif 481 } 482 /* 483 ** SWITCH_MAP_FIND -- find the list of types associated with a map 484 ** 485 ** This is the system-dependent interface to the service switch. 486 ** 487 ** Parameters: 488 ** service -- the name of the service of interest. 489 ** maptype -- an out-array of strings containing the types 490 ** of access to use for this service. There can 491 ** be at most MAXMAPSTACK types for a single service. 492 ** mapreturn -- an out-array of return information bitmaps 493 ** for the map. 494 ** 495 ** Returns: 496 ** The number of map types filled in, or -1 for failure. 497 */ 498 499 #ifdef SOLARIS 500 # include <nsswitch.h> 501 #endif 502 503 #if defined(ultrix) || defined(__osf__) 504 # include <sys/svcinfo.h> 505 #endif 506 507 int 508 switch_map_find(service, maptype, mapreturn) 509 char *service; 510 char *maptype[MAXMAPSTACK]; 511 short mapreturn[3]; 512 { 513 register FILE *fp; 514 int svcno; 515 static char buf[MAXLINE]; 516 517 #ifdef SOLARIS 518 struct __nsw_switchconfig *nsw_conf; 519 enum __nsw_parse_err pserr; 520 struct __nsw_lookup *lk; 521 int nsw_rc; 522 static struct __nsw_lookup lkp0 = 523 { "files", {1, 0, 0, 0}, NULL, NULL }; 524 static struct __nsw_switchconfig lkp_default = 525 { 0, "sendmail", 3, &lkp0 }; 526 527 if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL) 528 lk = lkp_default.lookups; 529 else 530 lk = nsw_conf->lookups; 531 svcno = 0; 532 while (lk != NULL) 533 { 534 maptype[svcno] = lk->service_name; 535 if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN) 536 mapreturn[MA_NOTFOUND] |= 1 << svcno; 537 if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN) 538 mapreturn[MA_TRYAGAIN] |= 1 << svcno; 539 if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN) 540 mapreturn[MA_TRYAGAIN] |= 1 << svcno; 541 svcno++; 542 } 543 return svcno; 544 #endif 545 546 #if defined(ultrix) || defined(__osf__) 547 struct svcinfo *svcinfo; 548 int svc; 549 550 svc = getsvc(); 551 if (strcmp(service, "hosts") == 0) 552 svc = SVC_HOSTS; 553 else if (strcmp(service, "aliases") == 0) 554 svc = SVC_ALIASES; 555 else if (strcmp(service, "passwd") == 0) 556 svc = SVC_PASSWD; 557 else 558 return -1; 559 for (svcno = 0; svcno < SVC_PATHSIZE; svcno++) 560 { 561 switch (svcinfo->svcpath[svc][svcno]) 562 { 563 case SVC_LOCAL: 564 maptype[svcno] = "files"; 565 break; 566 567 case SVC_YP: 568 maptype[svcno] = "nis"; 569 break; 570 571 case SVC_BIND: 572 maptype[svcno] = "dns"; 573 break; 574 575 #ifdef SVC_HESIOD 576 case SVC_HESIOD: 577 maptype[svcno] = "hesiod"; 578 break; 579 #endif 580 581 case SVC_LAST: 582 svcno = SVC_PATHSIZE; 583 break; 584 } 585 } 586 return svcno; 587 #endif 588 589 #if !defined(SOLARIS) && !defined(ultrix) && !defined(__osf__) 590 /* 591 ** Fall-back mechanism. 592 */ 593 594 svcno = 0; 595 fp = fopen(ServiceSwitchFile, "r"); 596 if (fp != NULL) 597 { 598 while (fgets(buf, sizeof buf, fp) != NULL) 599 { 600 register char *p; 601 602 p = strpbrk(buf, "#\n"); 603 if (p != NULL) 604 *p = '\0'; 605 p = strpbrk(buf, " \t"); 606 if (p != NULL) 607 *p++ = '\0'; 608 if (strcmp(buf, service) != 0) 609 continue; 610 611 /* got the right service -- extract data */ 612 do 613 { 614 while (isspace(*p)) 615 p++; 616 if (*p == '\0') 617 break; 618 maptype[svcno++] = p; 619 p = strpbrk(p, " \t"); 620 if (p != NULL) 621 *p++ = '\0'; 622 } while (p != NULL); 623 break; 624 } 625 fclose(fp); 626 return svcno; 627 } 628 629 /* if the service file doesn't work, use an absolute fallback */ 630 if (strcmp(service, "aliases") == 0) 631 { 632 maptype[0] = "files"; 633 return 1; 634 } 635 if (strcmp(service, "hosts") == 0) 636 { 637 # if NAMED_BIND 638 maptype[svcno++] = "dns"; 639 # else 640 # if defined(sun) && !defined(BSD) && !defined(SOLARIS) 641 /* SunOS */ 642 maptype[svcno++] = "nis"; 643 # endif 644 # endif 645 maptype[svcno++] = "files"; 646 return svcno; 647 } 648 return -1; 649 #endif 650 } 651 /* 652 ** USERNAME -- return the user id of the logged in user. 653 ** 654 ** Parameters: 655 ** none. 656 ** 657 ** Returns: 658 ** The login name of the logged in user. 659 ** 660 ** Side Effects: 661 ** none. 662 ** 663 ** Notes: 664 ** The return value is statically allocated. 665 */ 666 667 char * 668 username() 669 { 670 static char *myname = NULL; 671 extern char *getlogin(); 672 register struct passwd *pw; 673 674 /* cache the result */ 675 if (myname == NULL) 676 { 677 myname = getlogin(); 678 if (myname == NULL || myname[0] == '\0') 679 { 680 pw = getpwuid(RealUid); 681 if (pw != NULL) 682 myname = newstr(pw->pw_name); 683 } 684 else 685 { 686 uid_t uid = RealUid; 687 688 myname = newstr(myname); 689 if ((pw = getpwnam(myname)) == NULL || 690 (uid != 0 && uid != pw->pw_uid)) 691 { 692 pw = getpwuid(uid); 693 if (pw != NULL) 694 myname = newstr(pw->pw_name); 695 } 696 } 697 if (myname == NULL || myname[0] == '\0') 698 { 699 syserr("554 Who are you?"); 700 myname = "postmaster"; 701 } 702 } 703 704 return (myname); 705 } 706 /* 707 ** TTYPATH -- Get the path of the user's tty 708 ** 709 ** Returns the pathname of the user's tty. Returns NULL if 710 ** the user is not logged in or if s/he has write permission 711 ** denied. 712 ** 713 ** Parameters: 714 ** none 715 ** 716 ** Returns: 717 ** pathname of the user's tty. 718 ** NULL if not logged in or write permission denied. 719 ** 720 ** Side Effects: 721 ** none. 722 ** 723 ** WARNING: 724 ** Return value is in a local buffer. 725 ** 726 ** Called By: 727 ** savemail 728 */ 729 730 char * 731 ttypath() 732 { 733 struct stat stbuf; 734 register char *pathn; 735 extern char *ttyname(); 736 extern char *getlogin(); 737 738 /* compute the pathname of the controlling tty */ 739 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 740 (pathn = ttyname(0)) == NULL) 741 { 742 errno = 0; 743 return (NULL); 744 } 745 746 /* see if we have write permission */ 747 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 748 { 749 errno = 0; 750 return (NULL); 751 } 752 753 /* see if the user is logged in */ 754 if (getlogin() == NULL) 755 return (NULL); 756 757 /* looks good */ 758 return (pathn); 759 } 760 /* 761 ** CHECKCOMPAT -- check for From and To person compatible. 762 ** 763 ** This routine can be supplied on a per-installation basis 764 ** to determine whether a person is allowed to send a message. 765 ** This allows restriction of certain types of internet 766 ** forwarding or registration of users. 767 ** 768 ** If the hosts are found to be incompatible, an error 769 ** message should be given using "usrerr" and 0 should 770 ** be returned. 771 ** 772 ** EF_NORETURN can be set in e->e_flags to suppress the return-to-sender 773 ** function; this should be done on huge messages. 774 ** 775 ** Parameters: 776 ** to -- the person being sent to. 777 ** 778 ** Returns: 779 ** an exit status 780 ** 781 ** Side Effects: 782 ** none (unless you include the usrerr stuff) 783 */ 784 785 checkcompat(to, e) 786 register ADDRESS *to; 787 register ENVELOPE *e; 788 { 789 # ifdef lint 790 if (to == NULL) 791 to++; 792 # endif /* lint */ 793 794 if (tTd(49, 1)) 795 printf("checkcompat(to=%s, from=%s)\n", 796 to->q_paddr, e->e_from.q_paddr); 797 798 # ifdef EXAMPLE_CODE 799 /* this code is intended as an example only */ 800 register STAB *s; 801 802 s = stab("arpa", ST_MAILER, ST_FIND); 803 if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 && 804 to->q_mailer == s->s_mailer) 805 { 806 usrerr("553 No ARPA mail through this machine: see your system administration"); 807 /* e->e_flags |= EF_NORETURN; to supress return copy */ 808 return (EX_UNAVAILABLE); 809 } 810 # endif /* EXAMPLE_CODE */ 811 return (EX_OK); 812 } 813 /* 814 ** SETSIGNAL -- set a signal handler 815 ** 816 ** This is essentially old BSD "signal(3)". 817 */ 818 819 sigfunc_t 820 setsignal(sig, handler) 821 int sig; 822 sigfunc_t handler; 823 { 824 #if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE) 825 return signal(sig, handler); 826 #else 827 struct sigaction n, o; 828 829 bzero(&n, sizeof n); 830 n.sa_handler = handler; 831 # ifdef SA_RESTART 832 n.sa_flags = SA_RESTART; 833 # endif 834 if (sigaction(sig, &n, &o) < 0) 835 return SIG_ERR; 836 return o.sa_handler; 837 #endif 838 } 839 /* 840 ** HOLDSIGS -- arrange to hold all signals 841 ** 842 ** Parameters: 843 ** none. 844 ** 845 ** Returns: 846 ** none. 847 ** 848 ** Side Effects: 849 ** Arranges that signals are held. 850 */ 851 852 holdsigs() 853 { 854 } 855 /* 856 ** RLSESIGS -- arrange to release all signals 857 ** 858 ** This undoes the effect of holdsigs. 859 ** 860 ** Parameters: 861 ** none. 862 ** 863 ** Returns: 864 ** none. 865 ** 866 ** Side Effects: 867 ** Arranges that signals are released. 868 */ 869 870 rlsesigs() 871 { 872 } 873 /* 874 ** INIT_MD -- do machine dependent initializations 875 ** 876 ** Systems that have global modes that should be set should do 877 ** them here rather than in main. 878 */ 879 880 #ifdef _AUX_SOURCE 881 # include <compat.h> 882 #endif 883 884 init_md(argc, argv) 885 int argc; 886 char **argv; 887 { 888 #ifdef _AUX_SOURCE 889 setcompat(getcompat() | COMPAT_BSDPROT); 890 #endif 891 892 #ifdef VENDOR_DEFAULT 893 VendorCode = VENDOR_DEFAULT; 894 #else 895 VendorCode = VENDOR_BERKELEY; 896 #endif 897 } 898 /* 899 ** GETLA -- get the current load average 900 ** 901 ** This code stolen from la.c. 902 ** 903 ** Parameters: 904 ** none. 905 ** 906 ** Returns: 907 ** The current load average as an integer. 908 ** 909 ** Side Effects: 910 ** none. 911 */ 912 913 /* try to guess what style of load average we have */ 914 #define LA_ZERO 1 /* always return load average as zero */ 915 #define LA_INT 2 /* read kmem for avenrun; interpret as long */ 916 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 917 #define LA_SUBR 4 /* call getloadavg */ 918 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */ 919 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */ 920 #define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */ 921 922 /* do guesses based on general OS type */ 923 #ifndef LA_TYPE 924 # define LA_TYPE LA_ZERO 925 #endif 926 927 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 928 929 #include <nlist.h> 930 931 #ifndef LA_AVENRUN 932 # ifdef SYSTEM5 933 # define LA_AVENRUN "avenrun" 934 # else 935 # define LA_AVENRUN "_avenrun" 936 # endif 937 #endif 938 939 /* _PATH_UNIX should be defined in <paths.h> */ 940 #ifndef _PATH_UNIX 941 # if defined(SYSTEM5) 942 # define _PATH_UNIX "/unix" 943 # else 944 # define _PATH_UNIX "/vmunix" 945 # endif 946 #endif 947 948 struct nlist Nl[] = 949 { 950 { LA_AVENRUN }, 951 #define X_AVENRUN 0 952 { 0 }, 953 }; 954 955 #ifndef FSHIFT 956 # if defined(unixpc) 957 # define FSHIFT 5 958 # endif 959 960 # if defined(__alpha) || defined(IRIX) 961 # define FSHIFT 10 962 # endif 963 #endif 964 965 #ifndef FSHIFT 966 # define FSHIFT 8 967 #endif 968 969 #ifndef FSCALE 970 # define FSCALE (1 << FSHIFT) 971 #endif 972 973 getla() 974 { 975 static int kmem = -1; 976 #if LA_TYPE == LA_INT 977 long avenrun[3]; 978 #else 979 # if LA_TYPE == LA_SHORT 980 short avenrun[3]; 981 # else 982 double avenrun[3]; 983 # endif 984 #endif 985 extern off_t lseek(); 986 extern int errno; 987 988 if (kmem < 0) 989 { 990 kmem = open("/dev/kmem", 0, 0); 991 if (kmem < 0) 992 { 993 if (tTd(3, 1)) 994 printf("getla: open(/dev/kmem): %s\n", 995 errstring(errno)); 996 return (-1); 997 } 998 (void) fcntl(kmem, F_SETFD, 1); 999 if (nlist(_PATH_UNIX, Nl) < 0) 1000 { 1001 if (tTd(3, 1)) 1002 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 1003 errstring(errno)); 1004 return (-1); 1005 } 1006 if (Nl[X_AVENRUN].n_value == 0) 1007 { 1008 if (tTd(3, 1)) 1009 printf("getla: nlist(%s, %s) ==> 0\n", 1010 _PATH_UNIX, LA_AVENRUN); 1011 return (-1); 1012 } 1013 #ifdef NAMELISTMASK 1014 Nl[X_AVENRUN].n_value &= NAMELISTMASK; 1015 #endif 1016 } 1017 if (tTd(3, 20)) 1018 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 1019 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 1020 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 1021 { 1022 /* thank you Ian */ 1023 if (tTd(3, 1)) 1024 printf("getla: lseek or read: %s\n", errstring(errno)); 1025 return (-1); 1026 } 1027 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 1028 if (tTd(3, 5)) 1029 { 1030 printf("getla: avenrun = %d", avenrun[0]); 1031 if (tTd(3, 15)) 1032 printf(", %d, %d", avenrun[1], avenrun[2]); 1033 printf("\n"); 1034 } 1035 if (tTd(3, 1)) 1036 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1037 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1038 #else 1039 if (tTd(3, 5)) 1040 { 1041 printf("getla: avenrun = %g", avenrun[0]); 1042 if (tTd(3, 15)) 1043 printf(", %g, %g", avenrun[1], avenrun[2]); 1044 printf("\n"); 1045 } 1046 if (tTd(3, 1)) 1047 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 1048 return ((int) (avenrun[0] + 0.5)); 1049 #endif 1050 } 1051 1052 #else 1053 #if LA_TYPE == LA_SUBR 1054 1055 #ifdef DGUX 1056 1057 #include <sys/dg_sys_info.h> 1058 1059 int getla() 1060 { 1061 struct dg_sys_info_load_info load_info; 1062 1063 dg_sys_info((long *)&load_info, 1064 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); 1065 1066 return((int) (load_info.one_minute + 0.5)); 1067 } 1068 1069 #else 1070 1071 getla() 1072 { 1073 double avenrun[3]; 1074 1075 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 1076 { 1077 if (tTd(3, 1)) 1078 perror("getla: getloadavg failed:"); 1079 return (-1); 1080 } 1081 if (tTd(3, 1)) 1082 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 1083 return ((int) (avenrun[0] + 0.5)); 1084 } 1085 1086 #endif /* DGUX */ 1087 #else 1088 #if LA_TYPE == LA_MACH 1089 1090 /* 1091 ** This has been tested on NEXTSTEP release 2.1/3.X. 1092 */ 1093 1094 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 1095 # include <mach/mach.h> 1096 #else 1097 # include <mach.h> 1098 #endif 1099 1100 getla() 1101 { 1102 processor_set_t default_set; 1103 kern_return_t error; 1104 unsigned int info_count; 1105 struct processor_set_basic_info info; 1106 host_t host; 1107 1108 error = processor_set_default(host_self(), &default_set); 1109 if (error != KERN_SUCCESS) 1110 return -1; 1111 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 1112 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 1113 &host, (processor_set_info_t)&info, 1114 &info_count) != KERN_SUCCESS) 1115 { 1116 return -1; 1117 } 1118 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 1119 } 1120 1121 1122 #else 1123 #if LA_TYPE == LA_PROCSTR 1124 1125 /* 1126 ** Read /proc/loadavg for the load average. This is assumed to be 1127 ** in a format like "0.15 0.12 0.06". 1128 ** 1129 ** Initially intended for Linux. This has been in the kernel 1130 ** since at least 0.99.15. 1131 */ 1132 1133 # ifndef _PATH_LOADAVG 1134 # define _PATH_LOADAVG "/proc/loadavg" 1135 # endif 1136 1137 int 1138 getla() 1139 { 1140 double avenrun; 1141 register int result; 1142 FILE *fp; 1143 1144 fp = fopen(_PATH_LOADAVG, "r"); 1145 if (fp == NULL) 1146 { 1147 if (tTd(3, 1)) 1148 printf("getla: fopen(%s): %s\n", 1149 _PATH_LOADAVG, errstring(errno)); 1150 return -1; 1151 } 1152 result = fscanf(fp, "%lf", &avenrun); 1153 fclose(fp); 1154 if (result != 1) 1155 { 1156 if (tTd(3, 1)) 1157 printf("getla: fscanf() = %d: %s\n", 1158 result, errstring(errno)); 1159 return -1; 1160 } 1161 1162 if (tTd(3, 1)) 1163 printf("getla(): %.2f\n", avenrun); 1164 1165 return ((int) (avenrun + 0.5)); 1166 } 1167 1168 #else 1169 1170 getla() 1171 { 1172 if (tTd(3, 1)) 1173 printf("getla: ZERO\n"); 1174 return (0); 1175 } 1176 1177 #endif 1178 #endif 1179 #endif 1180 #endif 1181 1182 1183 /* 1184 * Copyright 1989 Massachusetts Institute of Technology 1185 * 1186 * Permission to use, copy, modify, distribute, and sell this software and its 1187 * documentation for any purpose is hereby granted without fee, provided that 1188 * the above copyright notice appear in all copies and that both that 1189 * copyright notice and this permission notice appear in supporting 1190 * documentation, and that the name of M.I.T. not be used in advertising or 1191 * publicity pertaining to distribution of the software without specific, 1192 * written prior permission. M.I.T. makes no representations about the 1193 * suitability of this software for any purpose. It is provided "as is" 1194 * without express or implied warranty. 1195 * 1196 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 1197 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 1198 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1199 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 1200 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 1201 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1202 * 1203 * Authors: Many and varied... 1204 */ 1205 1206 /* Non Apollo stuff removed by Don Lewis 11/15/93 */ 1207 #ifndef lint 1208 static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $"; 1209 #endif /* !lint */ 1210 1211 #ifdef apollo 1212 # undef volatile 1213 # include <apollo/base.h> 1214 1215 /* ARGSUSED */ 1216 int getloadavg( call_data ) 1217 caddr_t call_data; /* pointer to (double) return value */ 1218 { 1219 double *avenrun = (double *) call_data; 1220 int i; 1221 status_$t st; 1222 long loadav[3]; 1223 proc1_$get_loadav(loadav, &st); 1224 *avenrun = loadav[0] / (double) (1 << 16); 1225 return(0); 1226 } 1227 # endif /* apollo */ 1228 /* 1229 ** SHOULDQUEUE -- should this message be queued or sent? 1230 ** 1231 ** Compares the message cost to the load average to decide. 1232 ** 1233 ** Parameters: 1234 ** pri -- the priority of the message in question. 1235 ** ctime -- the message creation time. 1236 ** 1237 ** Returns: 1238 ** TRUE -- if this message should be queued up for the 1239 ** time being. 1240 ** FALSE -- if the load is low enough to send this message. 1241 ** 1242 ** Side Effects: 1243 ** none. 1244 */ 1245 1246 bool 1247 shouldqueue(pri, ctime) 1248 long pri; 1249 time_t ctime; 1250 { 1251 bool rval; 1252 1253 if (tTd(3, 30)) 1254 printf("shouldqueue: CurrentLA=%d, pri=%d: ", CurrentLA, pri); 1255 if (CurrentLA < QueueLA) 1256 { 1257 if (tTd(3, 30)) 1258 printf("FALSE (CurrentLA < QueueLA)\n"); 1259 return (FALSE); 1260 } 1261 if (CurrentLA >= RefuseLA) 1262 { 1263 if (tTd(3, 30)) 1264 printf("TRUE (CurrentLA >= RefuseLA)\n"); 1265 return (TRUE); 1266 } 1267 rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1)); 1268 if (tTd(3, 30)) 1269 printf("%s (by calculation)\n", rval ? "TRUE" : "FALSE"); 1270 return rval; 1271 } 1272 /* 1273 ** REFUSECONNECTIONS -- decide if connections should be refused 1274 ** 1275 ** Parameters: 1276 ** none. 1277 ** 1278 ** Returns: 1279 ** TRUE if incoming SMTP connections should be refused 1280 ** (for now). 1281 ** FALSE if we should accept new work. 1282 ** 1283 ** Side Effects: 1284 ** none. 1285 */ 1286 1287 bool 1288 refuseconnections() 1289 { 1290 #ifdef XLA 1291 if (!xla_smtp_ok()) 1292 return TRUE; 1293 #endif 1294 1295 /* this is probably too simplistic */ 1296 return (CurrentLA >= RefuseLA); 1297 } 1298 /* 1299 ** SETPROCTITLE -- set process title for ps 1300 ** 1301 ** Parameters: 1302 ** fmt -- a printf style format string. 1303 ** a, b, c -- possible parameters to fmt. 1304 ** 1305 ** Returns: 1306 ** none. 1307 ** 1308 ** Side Effects: 1309 ** Clobbers argv of our main procedure so ps(1) will 1310 ** display the title. 1311 */ 1312 1313 #define SPT_NONE 0 /* don't use it at all */ 1314 #define SPT_REUSEARGV 1 /* cover argv with title information */ 1315 #define SPT_BUILTIN 2 /* use libc builtin */ 1316 #define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */ 1317 #define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */ 1318 #define SPT_WRITEUDOT 5 /* write u. area in kmem */ 1319 1320 #ifndef SPT_TYPE 1321 # define SPT_TYPE SPT_REUSEARGV 1322 #endif 1323 1324 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN 1325 1326 # if SPT_TYPE == SPT_PSTAT 1327 # include <sys/pstat.h> 1328 # endif 1329 # if SPT_TYPE == SPT_PSSTRINGS 1330 # include <machine/vmparam.h> 1331 # include <sys/exec.h> 1332 # ifndef PS_STRINGS /* hmmmm.... apparently not available after all */ 1333 # undef SPT_TYPE 1334 # define SPT_TYPE SPT_REUSEARGV 1335 # endif 1336 # endif 1337 1338 # if SPT_TYPE == SPT_PSSTRINGS 1339 # define SETPROC_STATIC static 1340 # else 1341 # define SETPROC_STATIC 1342 # endif 1343 1344 # ifndef SPT_PADCHAR 1345 # define SPT_PADCHAR ' ' 1346 # endif 1347 1348 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */ 1349 1350 #if SPT_TYPE != SPT_BUILTIN 1351 1352 /*VARARGS1*/ 1353 # ifdef __STDC__ 1354 setproctitle(char *fmt, ...) 1355 # else 1356 setproctitle(fmt, va_alist) 1357 char *fmt; 1358 va_dcl 1359 # endif 1360 { 1361 # if SPT_TYPE != SPT_NONE 1362 register char *p; 1363 register int i; 1364 SETPROC_STATIC char buf[MAXLINE]; 1365 VA_LOCAL_DECL 1366 # if SPT_TYPE == SPT_PSTAT 1367 union pstun pst; 1368 # endif 1369 extern char **Argv; 1370 extern char *LastArgv; 1371 1372 p = buf; 1373 1374 /* print sendmail: heading for grep */ 1375 (void) strcpy(p, "sendmail: "); 1376 p += strlen(p); 1377 1378 /* print the argument string */ 1379 VA_START(fmt); 1380 (void) vsprintf(p, fmt, ap); 1381 VA_END; 1382 1383 i = strlen(buf); 1384 1385 # if SPT_TYPE == SPT_PSTAT 1386 pst.pst_command = buf; 1387 pstat(PSTAT_SETCMD, pst, i, 0, 0); 1388 # else 1389 # if SPT_TYPE == SPT_PSSTRINGS 1390 PS_STRINGS->ps_nargvstr = 1; 1391 PS_STRINGS->ps_argvstr = buf; 1392 # else 1393 if (i > LastArgv - Argv[0] - 2) 1394 { 1395 i = LastArgv - Argv[0] - 2; 1396 buf[i] = '\0'; 1397 } 1398 (void) strcpy(Argv[0], buf); 1399 p = &Argv[0][i]; 1400 while (p < LastArgv) 1401 *p++ = SPT_PADCHAR; 1402 Argv[1] = NULL; 1403 # endif /* SPT_TYPE == SPT_PSSTRINGS */ 1404 # endif /* SPT_TYPE == SPT_PSTAT */ 1405 # endif /* SPT_TYPE != SPT_NONE */ 1406 } 1407 1408 #endif /* SPT_TYPE != SPT_BUILTIN */ 1409 /* 1410 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 1411 ** 1412 ** Parameters: 1413 ** none. 1414 ** 1415 ** Returns: 1416 ** none. 1417 ** 1418 ** Side Effects: 1419 ** Picks up extant zombies. 1420 */ 1421 1422 void 1423 reapchild() 1424 { 1425 int olderrno = errno; 1426 # ifdef HASWAITPID 1427 auto int status; 1428 int count; 1429 int pid; 1430 1431 count = 0; 1432 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 1433 { 1434 if (count++ > 1000) 1435 { 1436 #ifdef LOG 1437 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 1438 pid, status); 1439 #endif 1440 break; 1441 } 1442 } 1443 # else 1444 # ifdef WNOHANG 1445 union wait status; 1446 1447 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 1448 continue; 1449 # else /* WNOHANG */ 1450 auto int status; 1451 1452 while (wait(&status) > 0) 1453 continue; 1454 # endif /* WNOHANG */ 1455 # endif 1456 # ifdef SYS5SIGNALS 1457 (void) setsignal(SIGCHLD, reapchild); 1458 # endif 1459 errno = olderrno; 1460 } 1461 /* 1462 ** UNSETENV -- remove a variable from the environment 1463 ** 1464 ** Not needed on newer systems. 1465 ** 1466 ** Parameters: 1467 ** name -- the string name of the environment variable to be 1468 ** deleted from the current environment. 1469 ** 1470 ** Returns: 1471 ** none. 1472 ** 1473 ** Globals: 1474 ** environ -- a pointer to the current environment. 1475 ** 1476 ** Side Effects: 1477 ** Modifies environ. 1478 */ 1479 1480 #ifndef HASUNSETENV 1481 1482 void 1483 unsetenv(name) 1484 char *name; 1485 { 1486 extern char **environ; 1487 register char **pp; 1488 int len = strlen(name); 1489 1490 for (pp = environ; *pp != NULL; pp++) 1491 { 1492 if (strncmp(name, *pp, len) == 0 && 1493 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 1494 break; 1495 } 1496 1497 for (; *pp != NULL; pp++) 1498 *pp = pp[1]; 1499 } 1500 1501 #endif 1502 /* 1503 ** GETDTABLESIZE -- return number of file descriptors 1504 ** 1505 ** Only on non-BSD systems 1506 ** 1507 ** Parameters: 1508 ** none 1509 ** 1510 ** Returns: 1511 ** size of file descriptor table 1512 ** 1513 ** Side Effects: 1514 ** none 1515 */ 1516 1517 #ifdef SOLARIS 1518 # include <sys/resource.h> 1519 #endif 1520 1521 int 1522 getdtsize() 1523 { 1524 #ifdef RLIMIT_NOFILE 1525 struct rlimit rl; 1526 1527 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1528 return rl.rlim_cur; 1529 #endif 1530 1531 # ifdef HASGETDTABLESIZE 1532 return getdtablesize(); 1533 # else 1534 # ifdef _SC_OPEN_MAX 1535 return sysconf(_SC_OPEN_MAX); 1536 # else 1537 return NOFILE; 1538 # endif 1539 # endif 1540 } 1541 /* 1542 ** UNAME -- get the UUCP name of this system. 1543 */ 1544 1545 #ifndef HASUNAME 1546 1547 int 1548 uname(name) 1549 struct utsname *name; 1550 { 1551 FILE *file; 1552 char *n; 1553 1554 name->nodename[0] = '\0'; 1555 1556 /* try /etc/whoami -- one line with the node name */ 1557 if ((file = fopen("/etc/whoami", "r")) != NULL) 1558 { 1559 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1560 (void) fclose(file); 1561 n = strchr(name->nodename, '\n'); 1562 if (n != NULL) 1563 *n = '\0'; 1564 if (name->nodename[0] != '\0') 1565 return (0); 1566 } 1567 1568 /* try /usr/include/whoami.h -- has a #define somewhere */ 1569 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1570 { 1571 char buf[MAXLINE]; 1572 1573 while (fgets(buf, MAXLINE, file) != NULL) 1574 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1575 NODE_LENGTH, name->nodename) > 0) 1576 break; 1577 (void) fclose(file); 1578 if (name->nodename[0] != '\0') 1579 return (0); 1580 } 1581 1582 #ifdef TRUST_POPEN 1583 /* 1584 ** Popen is known to have security holes. 1585 */ 1586 1587 /* try uuname -l to return local name */ 1588 if ((file = popen("uuname -l", "r")) != NULL) 1589 { 1590 (void) fgets(name, NODE_LENGTH + 1, file); 1591 (void) pclose(file); 1592 n = strchr(name, '\n'); 1593 if (n != NULL) 1594 *n = '\0'; 1595 if (name->nodename[0] != '\0') 1596 return (0); 1597 } 1598 #endif 1599 1600 return (-1); 1601 } 1602 #endif /* HASUNAME */ 1603 /* 1604 ** INITGROUPS -- initialize groups 1605 ** 1606 ** Stub implementation for System V style systems 1607 */ 1608 1609 #ifndef HASINITGROUPS 1610 1611 initgroups(name, basegid) 1612 char *name; 1613 int basegid; 1614 { 1615 return 0; 1616 } 1617 1618 #endif 1619 /* 1620 ** SETSID -- set session id (for non-POSIX systems) 1621 */ 1622 1623 #ifndef HASSETSID 1624 1625 pid_t 1626 setsid __P ((void)) 1627 { 1628 #ifdef TIOCNOTTY 1629 int fd; 1630 1631 fd = open("/dev/tty", O_RDWR, 0); 1632 if (fd >= 0) 1633 { 1634 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1635 (void) close(fd); 1636 } 1637 #endif /* TIOCNOTTY */ 1638 # ifdef SYS5SETPGRP 1639 return setpgrp(); 1640 # else 1641 return setpgid(0, getpid()); 1642 # endif 1643 } 1644 1645 #endif 1646 /* 1647 ** FSYNC -- dummy fsync 1648 */ 1649 1650 #ifdef NEEDFSYNC 1651 1652 fsync(fd) 1653 int fd; 1654 { 1655 # ifdef O_SYNC 1656 return fcntl(fd, F_SETFL, O_SYNC); 1657 # else 1658 /* nothing we can do */ 1659 return 0; 1660 # endif 1661 } 1662 1663 #endif 1664 /* 1665 ** DGUX_INET_ADDR -- inet_addr for DG/UX 1666 ** 1667 ** Data General DG/UX version of inet_addr returns a struct in_addr 1668 ** instead of a long. This patches things. Only needed on versions 1669 ** prior to 5.4.3. 1670 */ 1671 1672 #ifdef DGUX_5_4_2 1673 1674 #undef inet_addr 1675 1676 long 1677 dgux_inet_addr(host) 1678 char *host; 1679 { 1680 struct in_addr haddr; 1681 1682 haddr = inet_addr(host); 1683 return haddr.s_addr; 1684 } 1685 1686 #endif 1687 /* 1688 ** GETOPT -- for old systems or systems with bogus implementations 1689 */ 1690 1691 #ifdef NEEDGETOPT 1692 1693 /* 1694 * Copyright (c) 1985 Regents of the University of California. 1695 * All rights reserved. The Berkeley software License Agreement 1696 * specifies the terms and conditions for redistribution. 1697 */ 1698 1699 1700 /* 1701 ** this version hacked to add `atend' flag to allow state machine 1702 ** to reset if invoked by the program to scan args for a 2nd time 1703 */ 1704 1705 #if defined(LIBC_SCCS) && !defined(lint) 1706 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1707 #endif /* LIBC_SCCS and not lint */ 1708 1709 #include <stdio.h> 1710 1711 /* 1712 * get option letter from argument vector 1713 */ 1714 #ifdef _CONVEX_SOURCE 1715 extern int optind, opterr; 1716 #else 1717 int opterr = 1; /* if error message should be printed */ 1718 int optind = 1; /* index into parent argv vector */ 1719 #endif 1720 int optopt; /* character checked for validity */ 1721 char *optarg; /* argument associated with option */ 1722 1723 #define BADCH (int)'?' 1724 #define EMSG "" 1725 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1726 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1727 1728 getopt(nargc,nargv,ostr) 1729 int nargc; 1730 char *const *nargv; 1731 const char *ostr; 1732 { 1733 static char *place = EMSG; /* option letter processing */ 1734 static char atend = 0; 1735 register char *oli; /* option letter list index */ 1736 1737 if (atend) { 1738 atend = 0; 1739 place = EMSG; 1740 } 1741 if(!*place) { /* update scanning pointer */ 1742 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1743 atend++; 1744 return(EOF); 1745 } 1746 if (*place == '-') { /* found "--" */ 1747 ++optind; 1748 atend++; 1749 return(EOF); 1750 } 1751 } /* option letter okay? */ 1752 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1753 if (!*place) ++optind; 1754 tell(": illegal option -- "); 1755 } 1756 if (*++oli != ':') { /* don't need argument */ 1757 optarg = NULL; 1758 if (!*place) ++optind; 1759 } 1760 else { /* need an argument */ 1761 if (*place) optarg = place; /* no white space */ 1762 else if (nargc <= ++optind) { /* no arg */ 1763 place = EMSG; 1764 tell(": option requires an argument -- "); 1765 } 1766 else optarg = nargv[optind]; /* white space */ 1767 place = EMSG; 1768 ++optind; 1769 } 1770 return(optopt); /* dump back option letter */ 1771 } 1772 1773 #endif 1774 /* 1775 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1776 */ 1777 1778 #ifdef NEEDVPRINTF 1779 1780 #define MAXARG 16 1781 1782 vfprintf(fp, fmt, ap) 1783 FILE * fp; 1784 char * fmt; 1785 char ** ap; 1786 { 1787 char * bp[MAXARG]; 1788 int i = 0; 1789 1790 while (*ap && i < MAXARG) 1791 bp[i++] = *ap++; 1792 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1793 bp[4], bp[5], bp[6], bp[7], 1794 bp[8], bp[9], bp[10], bp[11], 1795 bp[12], bp[13], bp[14], bp[15]); 1796 } 1797 1798 vsprintf(s, fmt, ap) 1799 char * s; 1800 char * fmt; 1801 char ** ap; 1802 { 1803 char * bp[MAXARG]; 1804 int i = 0; 1805 1806 while (*ap && i < MAXARG) 1807 bp[i++] = *ap++; 1808 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1809 bp[4], bp[5], bp[6], bp[7], 1810 bp[8], bp[9], bp[10], bp[11], 1811 bp[12], bp[13], bp[14], bp[15]); 1812 } 1813 1814 #endif 1815 /* 1816 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 1817 ** 1818 ** Parameters: 1819 ** shell -- the user's shell from /etc/passwd 1820 ** 1821 ** Returns: 1822 ** TRUE -- if it is ok to use this for unrestricted access. 1823 ** FALSE -- if the shell is restricted. 1824 */ 1825 1826 #if !HASGETUSERSHELL 1827 1828 # ifndef _PATH_SHELLS 1829 # define _PATH_SHELLS "/etc/shells" 1830 # endif 1831 1832 char *DefaultUserShells[] = 1833 { 1834 "/bin/sh", 1835 "/usr/bin/sh", 1836 "/bin/csh", 1837 "/usr/bin/csh", 1838 #ifdef __hpux 1839 "/bin/rsh", 1840 "/bin/ksh", 1841 "/bin/rksh", 1842 "/bin/pam", 1843 "/usr/bin/keysh", 1844 "/bin/posix/sh", 1845 #endif 1846 NULL 1847 }; 1848 1849 #endif 1850 1851 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 1852 1853 bool 1854 usershellok(shell) 1855 char *shell; 1856 { 1857 #if HASGETUSERSHELL 1858 register char *p; 1859 extern char *getusershell(); 1860 1861 setusershell(); 1862 while ((p = getusershell()) != NULL) 1863 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 1864 break; 1865 endusershell(); 1866 return p != NULL; 1867 #else 1868 register FILE *shellf; 1869 char buf[MAXLINE]; 1870 1871 shellf = fopen(_PATH_SHELLS, "r"); 1872 if (shellf == NULL) 1873 { 1874 /* no /etc/shells; see if it is one of the std shells */ 1875 char **d; 1876 1877 for (d = DefaultUserShells; *d != NULL; d++) 1878 { 1879 if (strcmp(shell, *d) == 0) 1880 return TRUE; 1881 } 1882 return FALSE; 1883 } 1884 1885 while (fgets(buf, sizeof buf, shellf) != NULL) 1886 { 1887 register char *p, *q; 1888 1889 p = buf; 1890 while (*p != '\0' && *p != '#' && *p != '/') 1891 p++; 1892 if (*p == '#' || *p == '\0') 1893 continue; 1894 q = p; 1895 while (*p != '\0' && *p != '#' && !isspace(*p)) 1896 p++; 1897 *p = '\0'; 1898 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 1899 { 1900 fclose(shellf); 1901 return TRUE; 1902 } 1903 } 1904 fclose(shellf); 1905 return FALSE; 1906 #endif 1907 } 1908 /* 1909 ** FREESPACE -- see how much free space is on the queue filesystem 1910 ** 1911 ** Only implemented if you have statfs. 1912 ** 1913 ** Parameters: 1914 ** dir -- the directory in question. 1915 ** bsize -- a variable into which the filesystem 1916 ** block size is stored. 1917 ** 1918 ** Returns: 1919 ** The number of bytes free on the queue filesystem. 1920 ** -1 if the statfs call fails. 1921 ** 1922 ** Side effects: 1923 ** Puts the filesystem block size into bsize. 1924 */ 1925 1926 /* statfs types */ 1927 #define SFS_NONE 0 /* no statfs implementation */ 1928 #define SFS_USTAT 1 /* use ustat */ 1929 #define SFS_4ARGS 2 /* use four-argument statfs call */ 1930 #define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 1931 #define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 1932 #define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 1933 #define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */ 1934 1935 #ifndef SFS_TYPE 1936 # define SFS_TYPE SFS_NONE 1937 #endif 1938 1939 #if SFS_TYPE == SFS_USTAT 1940 # include <ustat.h> 1941 #endif 1942 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 1943 # include <sys/statfs.h> 1944 #endif 1945 #if SFS_TYPE == SFS_VFS 1946 # include <sys/vfs.h> 1947 #endif 1948 #if SFS_TYPE == SFS_MOUNT 1949 # include <sys/mount.h> 1950 #endif 1951 #if SFS_TYPE == SFS_STATVFS 1952 # include <sys/statvfs.h> 1953 #endif 1954 1955 long 1956 freespace(dir, bsize) 1957 char *dir; 1958 long *bsize; 1959 { 1960 #if SFS_TYPE != SFS_NONE 1961 # if SFS_TYPE == SFS_USTAT 1962 struct ustat fs; 1963 struct stat statbuf; 1964 # define FSBLOCKSIZE DEV_BSIZE 1965 # define f_bavail f_tfree 1966 # else 1967 # if defined(ultrix) 1968 struct fs_data fs; 1969 # define f_bavail fd_bfreen 1970 # define FSBLOCKSIZE 1024L 1971 # else 1972 # if SFS_TYPE == SFS_STATVFS 1973 struct statvfs fs; 1974 # define FSBLOCKSIZE fs.f_bsize 1975 # else 1976 struct statfs fs; 1977 # define FSBLOCKSIZE fs.f_bsize 1978 # if defined(_SCO_unix_) || defined(IRIX) || defined(apollo) 1979 # define f_bavail f_bfree 1980 # endif 1981 # endif 1982 # endif 1983 # endif 1984 extern int errno; 1985 1986 # if SFS_TYPE == SFS_USTAT 1987 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1988 # else 1989 # if SFS_TYPE == SFS_4ARGS 1990 if (statfs(dir, &fs, sizeof fs, 0) == 0) 1991 # else 1992 # if SFS_TYPE == SFS_STATVFS 1993 if (statvfs(dir, &fs) == 0) 1994 # else 1995 # if defined(ultrix) 1996 if (statfs(dir, &fs) > 0) 1997 # else 1998 if (statfs(dir, &fs) == 0) 1999 # endif 2000 # endif 2001 # endif 2002 # endif 2003 { 2004 if (bsize != NULL) 2005 *bsize = FSBLOCKSIZE; 2006 return (fs.f_bavail); 2007 } 2008 #endif 2009 return (-1); 2010 } 2011 /* 2012 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 2013 ** 2014 ** Only implemented if you have statfs. 2015 ** 2016 ** Parameters: 2017 ** msize -- the size to check against. If zero, we don't yet 2018 ** know how big the message will be, so just check for 2019 ** a "reasonable" amount. 2020 ** 2021 ** Returns: 2022 ** TRUE if there is enough space. 2023 ** FALSE otherwise. 2024 */ 2025 2026 bool 2027 enoughspace(msize) 2028 long msize; 2029 { 2030 long bfree, bsize; 2031 2032 if (MinBlocksFree <= 0 && msize <= 0) 2033 { 2034 if (tTd(4, 80)) 2035 printf("enoughspace: no threshold\n"); 2036 return TRUE; 2037 } 2038 2039 if ((bfree = freespace(QueueDir, &bsize)) >= 0) 2040 { 2041 if (tTd(4, 80)) 2042 printf("enoughspace: bavail=%ld, need=%ld\n", 2043 bfree, msize); 2044 2045 /* convert msize to block count */ 2046 msize = msize / bsize + 1; 2047 if (MinBlocksFree >= 0) 2048 msize += MinBlocksFree; 2049 2050 if (bfree < msize) 2051 { 2052 #ifdef LOG 2053 if (LogLevel > 0) 2054 syslog(LOG_ALERT, 2055 "%s: low on space (have %ld, %s needs %ld in %s)", 2056 CurEnv->e_id, bfree, 2057 CurHostName, msize, QueueDir); 2058 #endif 2059 return FALSE; 2060 } 2061 } 2062 else if (tTd(4, 80)) 2063 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 2064 MinBlocksFree, msize, errstring(errno)); 2065 return TRUE; 2066 } 2067 /* 2068 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 2069 ** 2070 ** This looks at an errno value and tells if this is likely to 2071 ** go away if retried later. 2072 ** 2073 ** Parameters: 2074 ** err -- the errno code to classify. 2075 ** 2076 ** Returns: 2077 ** TRUE if this is probably transient. 2078 ** FALSE otherwise. 2079 */ 2080 2081 bool 2082 transienterror(err) 2083 int err; 2084 { 2085 switch (err) 2086 { 2087 case EIO: /* I/O error */ 2088 case ENXIO: /* Device not configured */ 2089 case EAGAIN: /* Resource temporarily unavailable */ 2090 case ENOMEM: /* Cannot allocate memory */ 2091 case ENODEV: /* Operation not supported by device */ 2092 case ENFILE: /* Too many open files in system */ 2093 case EMFILE: /* Too many open files */ 2094 case ENOSPC: /* No space left on device */ 2095 #ifdef ETIMEDOUT 2096 case ETIMEDOUT: /* Connection timed out */ 2097 #endif 2098 #ifdef ESTALE 2099 case ESTALE: /* Stale NFS file handle */ 2100 #endif 2101 #ifdef ENETDOWN 2102 case ENETDOWN: /* Network is down */ 2103 #endif 2104 #ifdef ENETUNREACH 2105 case ENETUNREACH: /* Network is unreachable */ 2106 #endif 2107 #ifdef ENETRESET 2108 case ENETRESET: /* Network dropped connection on reset */ 2109 #endif 2110 #ifdef ECONNABORTED 2111 case ECONNABORTED: /* Software caused connection abort */ 2112 #endif 2113 #ifdef ECONNRESET 2114 case ECONNRESET: /* Connection reset by peer */ 2115 #endif 2116 #ifdef ENOBUFS 2117 case ENOBUFS: /* No buffer space available */ 2118 #endif 2119 #ifdef ESHUTDOWN 2120 case ESHUTDOWN: /* Can't send after socket shutdown */ 2121 #endif 2122 #ifdef ECONNREFUSED 2123 case ECONNREFUSED: /* Connection refused */ 2124 #endif 2125 #ifdef EHOSTDOWN 2126 case EHOSTDOWN: /* Host is down */ 2127 #endif 2128 #ifdef EHOSTUNREACH 2129 case EHOSTUNREACH: /* No route to host */ 2130 #endif 2131 #ifdef EDQUOT 2132 case EDQUOT: /* Disc quota exceeded */ 2133 #endif 2134 #ifdef EPROCLIM 2135 case EPROCLIM: /* Too many processes */ 2136 #endif 2137 #ifdef EUSERS 2138 case EUSERS: /* Too many users */ 2139 #endif 2140 #ifdef EDEADLK 2141 case EDEADLK: /* Resource deadlock avoided */ 2142 #endif 2143 #ifdef EISCONN 2144 case EISCONN: /* Socket already connected */ 2145 #endif 2146 #ifdef EINPROGRESS 2147 case EINPROGRESS: /* Operation now in progress */ 2148 #endif 2149 #ifdef EALREADY 2150 case EALREADY: /* Operation already in progress */ 2151 #endif 2152 #ifdef EADDRINUSE 2153 case EADDRINUSE: /* Address already in use */ 2154 #endif 2155 #ifdef EADDRNOTAVAIL 2156 case EADDRNOTAVAIL: /* Can't assign requested address */ 2157 #endif 2158 #ifdef ETXTBSY 2159 case ETXTBSY: /* (Apollo) file locked */ 2160 #endif 2161 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 2162 case ENOSR: /* Out of streams resources */ 2163 #endif 2164 return TRUE; 2165 } 2166 2167 /* nope, must be permanent */ 2168 return FALSE; 2169 } 2170 /* 2171 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 2172 ** 2173 ** Parameters: 2174 ** fd -- the file descriptor of the file. 2175 ** filename -- the file name (for error messages). 2176 ** ext -- the filename extension. 2177 ** type -- type of the lock. Bits can be: 2178 ** LOCK_EX -- exclusive lock. 2179 ** LOCK_NB -- non-blocking. 2180 ** 2181 ** Returns: 2182 ** TRUE if the lock was acquired. 2183 ** FALSE otherwise. 2184 */ 2185 2186 bool 2187 lockfile(fd, filename, ext, type) 2188 int fd; 2189 char *filename; 2190 char *ext; 2191 int type; 2192 { 2193 # if !HASFLOCK 2194 int action; 2195 struct flock lfd; 2196 2197 if (ext == NULL) 2198 ext = ""; 2199 2200 bzero(&lfd, sizeof lfd); 2201 if (bitset(LOCK_UN, type)) 2202 lfd.l_type = F_UNLCK; 2203 else if (bitset(LOCK_EX, type)) 2204 lfd.l_type = F_WRLCK; 2205 else 2206 lfd.l_type = F_RDLCK; 2207 2208 if (bitset(LOCK_NB, type)) 2209 action = F_SETLK; 2210 else 2211 action = F_SETLKW; 2212 2213 if (tTd(55, 60)) 2214 printf("lockfile(%s%s, action=%d, type=%d): ", 2215 filename, ext, action, lfd.l_type); 2216 2217 if (fcntl(fd, action, &lfd) >= 0) 2218 { 2219 if (tTd(55, 60)) 2220 printf("SUCCESS\n"); 2221 return TRUE; 2222 } 2223 2224 if (tTd(55, 60)) 2225 printf("(%s) ", errstring(errno)); 2226 2227 /* 2228 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 2229 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 2230 ** as type "tmp" (that is, served from swap space), the 2231 ** previous fcntl will fail with "Invalid argument" errors. 2232 ** Since this is fairly common during testing, we will assume 2233 ** that this indicates that the lock is successfully grabbed. 2234 */ 2235 2236 if (errno == EINVAL) 2237 { 2238 if (tTd(55, 60)) 2239 printf("SUCCESS\n"); 2240 return TRUE; 2241 } 2242 2243 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 2244 { 2245 int omode = -1; 2246 # ifdef F_GETFL 2247 int oerrno = errno; 2248 2249 (void) fcntl(fd, F_GETFL, &omode); 2250 errno = oerrno; 2251 # endif 2252 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 2253 filename, ext, fd, type, omode, geteuid()); 2254 } 2255 # else 2256 if (ext == NULL) 2257 ext = ""; 2258 2259 if (tTd(55, 60)) 2260 printf("lockfile(%s%s, type=%o): ", filename, ext, type); 2261 2262 if (flock(fd, type) >= 0) 2263 { 2264 if (tTd(55, 60)) 2265 printf("SUCCESS\n"); 2266 return TRUE; 2267 } 2268 2269 if (tTd(55, 60)) 2270 printf("(%s) ", errstring(errno)); 2271 2272 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 2273 { 2274 int omode = -1; 2275 # ifdef F_GETFL 2276 int oerrno = errno; 2277 2278 (void) fcntl(fd, F_GETFL, &omode); 2279 errno = oerrno; 2280 # endif 2281 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 2282 filename, ext, fd, type, omode, geteuid()); 2283 } 2284 # endif 2285 if (tTd(55, 60)) 2286 printf("FAIL\n"); 2287 return FALSE; 2288 } 2289 /* 2290 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 2291 ** 2292 ** Parameters: 2293 ** fd -- the file descriptor to check. 2294 ** 2295 ** Returns: 2296 ** TRUE -- if only root can chown the file to an arbitrary 2297 ** user. 2298 ** FALSE -- if an arbitrary user can give away a file. 2299 */ 2300 2301 bool 2302 chownsafe(fd) 2303 int fd; 2304 { 2305 #ifdef __hpux 2306 char *s; 2307 int tfd; 2308 uid_t o_uid, o_euid; 2309 gid_t o_gid, o_egid; 2310 bool rval; 2311 struct stat stbuf; 2312 2313 o_uid = getuid(); 2314 o_euid = geteuid(); 2315 o_gid = getgid(); 2316 o_egid = getegid(); 2317 fstat(fd, &stbuf); 2318 setresuid(stbuf.st_uid, stbuf.st_uid, -1); 2319 setresgid(stbuf.st_gid, stbuf.st_gid, -1); 2320 s = tmpnam(NULL); 2321 tfd = open(s, O_RDONLY|O_CREAT, 0600); 2322 rval = fchown(tfd, DefUid, DefGid) != 0; 2323 close(tfd); 2324 unlink(s); 2325 setreuid(o_uid, o_euid); 2326 setresgid(o_gid, o_egid, -1); 2327 return rval; 2328 #else 2329 # ifdef _POSIX_CHOWN_RESTRICTED 2330 # if _POSIX_CHOWN_RESTRICTED == -1 2331 return FALSE; 2332 # else 2333 return TRUE; 2334 # endif 2335 # else 2336 # ifdef _PC_CHOWN_RESTRICTED 2337 int rval; 2338 2339 /* 2340 ** Some systems (e.g., SunOS) seem to have the call and the 2341 ** #define _PC_CHOWN_RESTRICTED, but don't actually implement 2342 ** the call. This heuristic checks for that. 2343 */ 2344 2345 errno = 0; 2346 rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); 2347 if (errno == 0) 2348 return rval > 0; 2349 # endif 2350 # ifdef BSD 2351 return TRUE; 2352 # else 2353 return FALSE; 2354 # endif 2355 # endif 2356 #endif 2357 } 2358 /* 2359 ** RESETLIMITS -- reset system controlled resource limits 2360 ** 2361 ** This is to avoid denial-of-service attacks 2362 ** 2363 ** Parameters: 2364 ** none 2365 ** 2366 ** Returns: 2367 ** none 2368 */ 2369 2370 #if HASSETRLIMIT 2371 # include <sys/resource.h> 2372 #endif 2373 2374 resetlimits() 2375 { 2376 #if HASSETRLIMIT 2377 struct rlimit lim; 2378 2379 lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 2380 (void) setrlimit(RLIMIT_CPU, &lim); 2381 (void) setrlimit(RLIMIT_FSIZE, &lim); 2382 #else 2383 # if HASULIMIT 2384 (void) ulimit(2, 0x3fffff); 2385 # endif 2386 #endif 2387 } 2388 /* 2389 ** GETCFNAME -- return the name of the .cf file. 2390 ** 2391 ** Some systems (e.g., NeXT) determine this dynamically. 2392 */ 2393 2394 char * 2395 getcfname() 2396 { 2397 if (ConfFile != NULL) 2398 return ConfFile; 2399 #ifdef NETINFO 2400 { 2401 extern char *ni_propval(); 2402 char *cflocation; 2403 2404 cflocation = ni_propval("/locations", NULL, "sendmail", 2405 "sendmail.cf", '\0'); 2406 if (cflocation != NULL) 2407 return cflocation; 2408 } 2409 #endif 2410 return _PATH_SENDMAILCF; 2411 } 2412 /* 2413 ** SETVENDOR -- process vendor code from V configuration line 2414 ** 2415 ** Parameters: 2416 ** vendor -- string representation of vendor. 2417 ** 2418 ** Returns: 2419 ** TRUE -- if ok. 2420 ** FALSE -- if vendor code could not be processed. 2421 ** 2422 ** Side Effects: 2423 ** It is reasonable to set mode flags here to tweak 2424 ** processing in other parts of the code if necessary. 2425 ** For example, if you are a vendor that uses $%y to 2426 ** indicate YP lookups, you could enable that here. 2427 */ 2428 2429 bool 2430 setvendor(vendor) 2431 char *vendor; 2432 { 2433 if (strcasecmp(vendor, "Berkeley") == 0) 2434 { 2435 VendorCode = VENDOR_BERKELEY; 2436 return TRUE; 2437 } 2438 2439 /* add vendor extensions here */ 2440 2441 #ifdef SUN_EXTENSIONS 2442 if (strcasecmp(vendor, "Sun") == 0) 2443 { 2444 VendorCode = VENDOR_SUN; 2445 return TRUE; 2446 } 2447 #endif 2448 2449 return FALSE; 2450 } 2451 /* 2452 ** STRTOL -- convert string to long integer 2453 ** 2454 ** For systems that don't have it in the C library. 2455 ** 2456 ** This is taken verbatim from the 4.4-Lite C library. 2457 */ 2458 2459 #ifdef NEEDSTRTOL 2460 2461 #if defined(LIBC_SCCS) && !defined(lint) 2462 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 2463 #endif /* LIBC_SCCS and not lint */ 2464 2465 #include <limits.h> 2466 2467 /* 2468 * Convert a string to a long integer. 2469 * 2470 * Ignores `locale' stuff. Assumes that the upper and lower case 2471 * alphabets and digits are each contiguous. 2472 */ 2473 2474 long 2475 strtol(nptr, endptr, base) 2476 const char *nptr; 2477 char **endptr; 2478 register int base; 2479 { 2480 register const char *s = nptr; 2481 register unsigned long acc; 2482 register int c; 2483 register unsigned long cutoff; 2484 register int neg = 0, any, cutlim; 2485 2486 /* 2487 * Skip white space and pick up leading +/- sign if any. 2488 * If base is 0, allow 0x for hex and 0 for octal, else 2489 * assume decimal; if base is already 16, allow 0x. 2490 */ 2491 do { 2492 c = *s++; 2493 } while (isspace(c)); 2494 if (c == '-') { 2495 neg = 1; 2496 c = *s++; 2497 } else if (c == '+') 2498 c = *s++; 2499 if ((base == 0 || base == 16) && 2500 c == '0' && (*s == 'x' || *s == 'X')) { 2501 c = s[1]; 2502 s += 2; 2503 base = 16; 2504 } 2505 if (base == 0) 2506 base = c == '0' ? 8 : 10; 2507 2508 /* 2509 * Compute the cutoff value between legal numbers and illegal 2510 * numbers. That is the largest legal value, divided by the 2511 * base. An input number that is greater than this value, if 2512 * followed by a legal input character, is too big. One that 2513 * is equal to this value may be valid or not; the limit 2514 * between valid and invalid numbers is then based on the last 2515 * digit. For instance, if the range for longs is 2516 * [-2147483648..2147483647] and the input base is 10, 2517 * cutoff will be set to 214748364 and cutlim to either 2518 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 2519 * a value > 214748364, or equal but the next digit is > 7 (or 8), 2520 * the number is too big, and we will return a range error. 2521 * 2522 * Set any if any `digits' consumed; make it negative to indicate 2523 * overflow. 2524 */ 2525 cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; 2526 cutlim = cutoff % (unsigned long)base; 2527 cutoff /= (unsigned long)base; 2528 for (acc = 0, any = 0;; c = *s++) { 2529 if (isdigit(c)) 2530 c -= '0'; 2531 else if (isalpha(c)) 2532 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 2533 else 2534 break; 2535 if (c >= base) 2536 break; 2537 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 2538 any = -1; 2539 else { 2540 any = 1; 2541 acc *= base; 2542 acc += c; 2543 } 2544 } 2545 if (any < 0) { 2546 acc = neg ? LONG_MIN : LONG_MAX; 2547 errno = ERANGE; 2548 } else if (neg) 2549 acc = -acc; 2550 if (endptr != 0) 2551 *endptr = (char *)(any ? s - 1 : nptr); 2552 return (acc); 2553 } 2554 2555 #endif 2556 /* 2557 ** SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 2558 ** 2559 ** Solaris versions at least through 2.3 don't properly deliver a 2560 ** canonical h_name field. This tries to work around it. 2561 */ 2562 2563 #ifdef SOLARIS 2564 2565 extern int h_errno; 2566 2567 struct hostent * 2568 solaris_gethostbyname(name) 2569 const char *name; 2570 { 2571 # ifdef SOLARIS_2_3 2572 static struct hostent hp; 2573 static char buf[1000]; 2574 extern struct hostent *_switch_gethostbyname_r(); 2575 2576 return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 2577 # else 2578 extern struct hostent *__switch_gethostbyname(); 2579 2580 return __switch_gethostbyname(name); 2581 # endif 2582 } 2583 2584 struct hostent * 2585 solaris_gethostbyaddr(addr, len, type) 2586 const char *addr; 2587 int len; 2588 int type; 2589 { 2590 # ifdef SOLARIS_2_3 2591 static struct hostent hp; 2592 static char buf[1000]; 2593 extern struct hostent *_switch_gethostbyaddr_r(); 2594 2595 return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno); 2596 # else 2597 extern struct hostent *__switch_gethostbyaddr(); 2598 2599 return __switch_gethostbyaddr(addr, len, type); 2600 # endif 2601 } 2602 2603 #endif 2604 /* 2605 ** NI_PROPVAL -- netinfo property value lookup routine 2606 ** 2607 ** Parameters: 2608 ** keydir -- the Netinfo directory name in which to search 2609 ** for the key. 2610 ** keyprop -- the name of the property in which to find the 2611 ** property we are interested. Defaults to "name". 2612 ** keyval -- the value for which we are really searching. 2613 ** valprop -- the property name for the value in which we 2614 ** are interested. 2615 ** sepchar -- if non-nil, this can be multiple-valued, and 2616 ** we should return a string separated by this 2617 ** character. 2618 ** 2619 ** Returns: 2620 ** NULL -- if: 2621 ** 1. the directory is not found 2622 ** 2. the property name is not found 2623 ** 3. the property contains multiple values 2624 ** 4. some error occured 2625 ** else -- the location of the config file. 2626 ** 2627 ** Example: 2628 ** To search for an alias value, use: 2629 ** ni_propval("/aliases", "name", aliasname, "members", ',') 2630 ** 2631 ** Notes: 2632 ** Caller should free the return value of ni_proval 2633 */ 2634 2635 #ifdef NETINFO 2636 2637 # include <netinfo/ni.h> 2638 2639 # define LOCAL_NETINFO_DOMAIN "." 2640 # define PARENT_NETINFO_DOMAIN ".." 2641 # define MAX_NI_LEVELS 256 2642 2643 char * 2644 ni_propval(keydir, keyprop, keyval, valprop, sepchar) 2645 char *keydir; 2646 char *keyprop; 2647 char *keyval; 2648 char *valprop; 2649 char sepchar; 2650 { 2651 char *propval = NULL; 2652 int i; 2653 int j, alen; 2654 void *ni = NULL; 2655 void *lastni = NULL; 2656 ni_status nis; 2657 ni_id nid; 2658 ni_namelist ninl; 2659 register char *p; 2660 char keybuf[1024]; 2661 2662 /* 2663 ** Create the full key from the two parts. 2664 ** 2665 ** Note that directory can end with, e.g., "name=" to specify 2666 ** an alternate search property. 2667 */ 2668 2669 i = strlen(keydir) + strlen(keyval) + 2) 2670 if (keyprop != NULL) 2671 i += strlen(keyprop) + 1; 2672 if (i > sizeof keybuf) 2673 return NULL; 2674 strcpy(keybuf, keydir); 2675 strcat(keybuf, "/"); 2676 if (keyprop != NULL) 2677 { 2678 strcat(keybuf, keyprop); 2679 strcat(keybuf, "="); 2680 } 2681 strcat(keybuf, keyval); 2682 2683 /* 2684 ** If the passed directory and property name are found 2685 ** in one of netinfo domains we need to search (starting 2686 ** from the local domain moving all the way back to the 2687 ** root domain) set propval to the property's value 2688 ** and return it. 2689 */ 2690 2691 for (i = 0; i < MAX_NI_LEVELS; ++i) 2692 { 2693 if (i == 0) 2694 { 2695 nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); 2696 } 2697 else 2698 { 2699 if (lastni != NULL) 2700 ni_free(lastni); 2701 lastni = ni; 2702 nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); 2703 } 2704 2705 /* 2706 ** Don't bother if we didn't get a handle on a 2707 ** proper domain. This is not necessarily an error. 2708 ** We would get a positive ni_status if, for instance 2709 ** we never found the directory or property and tried 2710 ** to open the parent of the root domain! 2711 */ 2712 2713 if (nis != 0) 2714 break; 2715 2716 /* 2717 ** Find the path to the server information. 2718 */ 2719 2720 if (ni_pathsearch(ni, &nid, keybuf) != 0) 2721 continue; 2722 2723 /* 2724 ** Find associated value information. 2725 */ 2726 2727 if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0) 2728 continue; 2729 2730 /* 2731 ** See if we have an acceptable number of values. 2732 */ 2733 2734 if (ninl.ni_namelist_len <= 0) 2735 continue; 2736 2737 if (sepchar == '\0' && ninl.ni_namelist_len > 1) 2738 { 2739 ni_namelist_free(&ninl); 2740 continue; 2741 } 2742 2743 /* 2744 ** Calculate number of bytes needed and build result 2745 */ 2746 2747 alen = 1; 2748 for (j = 0; j < ninl.ni_namelist_len; j++) 2749 alen += strlen(ninl.ni_namelist_val[j]) + 1; 2750 propval = p = xalloc(alen); 2751 for (j = 0; j < ninl.ni_namelist_len; j++) 2752 { 2753 strcpy(p, ninl.ni_namelist_val[j]); 2754 p += strlen(p); 2755 *p++ = sepchar; 2756 } 2757 *--p = '\0'; 2758 2759 ni_namelist_free(&ninl); 2760 } 2761 2762 /* 2763 ** Clean up. 2764 */ 2765 2766 if (ni != NULL) 2767 ni_free(ni); 2768 if (lastni != NULL && ni != lastni) 2769 ni_free(lastni); 2770 2771 return propval; 2772 } 2773 2774 #endif /* NETINFO */ 2775 /* 2776 ** HARD_SYSLOG -- call syslog repeatedly until it works 2777 ** 2778 ** Needed on HP-UX, which apparently doesn't guarantee that 2779 ** syslog succeeds during interrupt handlers. 2780 */ 2781 2782 #ifdef __hpux 2783 2784 # define MAXSYSLOGTRIES 100 2785 # undef syslog 2786 2787 # ifdef __STDC__ 2788 hard_syslog(int pri, char *msg, ...) 2789 # else 2790 hard_syslog(pri, msg, va_alist) 2791 int pri; 2792 char *msg; 2793 va_dcl 2794 # endif 2795 { 2796 int i; 2797 char buf[SYSLOG_BUFSIZE * 2]; 2798 VA_LOCAL_DECL; 2799 2800 VA_START(msg); 2801 vsprintf(buf, msg, ap); 2802 VA_END; 2803 2804 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) 2805 continue; 2806 } 2807 2808 #endif 2809