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