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