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