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