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