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