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