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