1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 8.104 (Berkeley) 10/08/94"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include "pathnames.h" 15 # include <sys/ioctl.h> 16 # include <sys/param.h> 17 # include <netdb.h> 18 # include <pwd.h> 19 20 /* 21 ** CONF.C -- Sendmail Configuration Tables. 22 ** 23 ** Defines the configuration of this installation. 24 ** 25 ** Configuration Variables: 26 ** HdrInfo -- a table describing well-known header fields. 27 ** Each entry has the field name and some flags, 28 ** which are described in sendmail.h. 29 ** 30 ** Notes: 31 ** I have tried to put almost all the reasonable 32 ** configuration information into the configuration 33 ** file read at runtime. My intent is that anything 34 ** here is a function of the version of UNIX you 35 ** are running, or is really static -- for example 36 ** the headers are a superset of widely used 37 ** protocols. If you find yourself playing with 38 ** this file too much, you may be making a mistake! 39 */ 40 41 42 43 44 /* 45 ** Header info table 46 ** Final (null) entry contains the flags used for any other field. 47 ** 48 ** Not all of these are actually handled specially by sendmail 49 ** at this time. They are included as placeholders, to let 50 ** you know that "someday" I intend to have sendmail do 51 ** something with them. 52 */ 53 54 struct hdrinfo HdrInfo[] = 55 { 56 /* originator fields, most to least significant */ 57 "resent-sender", H_FROM|H_RESENT, 58 "resent-from", H_FROM|H_RESENT, 59 "resent-reply-to", H_FROM|H_RESENT, 60 "sender", H_FROM, 61 "from", H_FROM, 62 "reply-to", H_FROM, 63 "full-name", H_ACHECK, 64 "return-receipt-to", H_FROM|H_RECEIPTTO, 65 "errors-to", H_FROM|H_ERRORSTO, 66 67 /* destination fields */ 68 "to", H_RCPT, 69 "resent-to", H_RCPT|H_RESENT, 70 "cc", H_RCPT, 71 "resent-cc", H_RCPT|H_RESENT, 72 "bcc", H_RCPT|H_ACHECK, 73 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 74 "apparently-to", H_RCPT, 75 76 /* message identification and control */ 77 "message-id", 0, 78 "resent-message-id", H_RESENT, 79 "message", H_EOH, 80 "text", H_EOH, 81 82 /* date fields */ 83 "date", 0, 84 "resent-date", H_RESENT, 85 86 /* trace fields */ 87 "received", H_TRACE|H_FORCE, 88 "x400-received", H_TRACE|H_FORCE, 89 "via", H_TRACE|H_FORCE, 90 "mail-from", H_TRACE|H_FORCE, 91 92 /* miscellaneous fields */ 93 "comments", H_FORCE, 94 "return-path", H_FORCE|H_ACHECK, 95 "content-transfer-encoding", H_CTE, 96 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 setdefaults(e) 157 register ENVELOPE *e; 158 { 159 int i; 160 161 SpaceSub = ' '; /* option B */ 162 QueueLA = 8; /* option x */ 163 RefuseLA = 12; /* option X */ 164 WkRecipFact = 30000L; /* option y */ 165 WkClassFact = 1800L; /* option z */ 166 WkTimeFact = 90000L; /* option Z */ 167 QueueFactor = WkRecipFact * 20; /* option q */ 168 FileMode = (RealUid != geteuid()) ? 0644 : 0600; 169 /* option F */ 170 DefUid = 1; /* option u */ 171 DefGid = 1; /* option g */ 172 CheckpointInterval = 10; /* option C */ 173 MaxHopCount = 25; /* option h */ 174 e->e_sendmode = SM_FORK; /* option d */ 175 e->e_errormode = EM_PRINT; /* option e */ 176 SevenBitInput = FALSE; /* option 7 */ 177 MaxMciCache = 1; /* option k */ 178 MciCacheTimeout = 300; /* option K */ 179 LogLevel = 9; /* option L */ 180 settimeouts(NULL); /* option r */ 181 PrivacyFlags = 0; /* option p */ 182 MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */ 183 for (i = 0; i < MAXTOCLASS; i++) 184 { 185 TimeOuts.to_q_return[i] = 5 DAYS; /* option T */ 186 TimeOuts.to_q_warning[i] = 0; /* option T */ 187 } 188 setdefuser(); 189 setupmaps(); 190 setupmailers(); 191 } 192 193 194 /* 195 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 196 */ 197 198 setdefuser() 199 { 200 struct passwd *defpwent; 201 static char defuserbuf[40]; 202 203 DefUser = defuserbuf; 204 if ((defpwent = getpwuid(DefUid)) != NULL) 205 strcpy(defuserbuf, defpwent->pw_name); 206 else 207 strcpy(defuserbuf, "nobody"); 208 } 209 /* 210 ** HOST_MAP_INIT -- initialize host class structures 211 */ 212 213 bool host_map_init __P((MAP *map, char *args)); 214 215 bool 216 host_map_init(map, args) 217 MAP *map; 218 char *args; 219 { 220 register char *p = args; 221 222 for (;;) 223 { 224 while (isascii(*p) && isspace(*p)) 225 p++; 226 if (*p != '-') 227 break; 228 switch (*++p) 229 { 230 case 'a': 231 map->map_app = ++p; 232 break; 233 } 234 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 235 p++; 236 if (*p != '\0') 237 *p++ = '\0'; 238 } 239 if (map->map_app != NULL) 240 map->map_app = newstr(map->map_app); 241 return TRUE; 242 } 243 /* 244 ** SETUPMAILERS -- initialize default mailers 245 */ 246 247 setupmailers() 248 { 249 char buf[100]; 250 251 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 252 makemailer(buf); 253 254 strcpy(buf, "*file*, P=/dev/null, F=lsDFMPEu, A=FILE"); 255 makemailer(buf); 256 257 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 258 makemailer(buf); 259 } 260 /* 261 ** SETUPMAPS -- set up map classes 262 */ 263 264 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \ 265 { \ 266 extern bool parse __P((MAP *, char *)); \ 267 extern bool open __P((MAP *, int)); \ 268 extern void close __P((MAP *)); \ 269 extern char *lookup __P((MAP *, char *, char **, int *)); \ 270 extern void store __P((MAP *, char *, char *)); \ 271 s = stab(name, ST_MAPCLASS, ST_ENTER); \ 272 s->s_mapclass.map_cname = name; \ 273 s->s_mapclass.map_ext = ext; \ 274 s->s_mapclass.map_cflags = flags; \ 275 s->s_mapclass.map_parse = parse; \ 276 s->s_mapclass.map_open = open; \ 277 s->s_mapclass.map_close = close; \ 278 s->s_mapclass.map_lookup = lookup; \ 279 s->s_mapclass.map_store = store; \ 280 } 281 282 setupmaps() 283 { 284 register STAB *s; 285 286 #ifdef NEWDB 287 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 288 map_parseargs, hash_map_open, db_map_close, 289 db_map_lookup, db_map_store); 290 291 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 292 map_parseargs, bt_map_open, db_map_close, 293 db_map_lookup, db_map_store); 294 #endif 295 296 #ifdef NDBM 297 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE, 298 map_parseargs, ndbm_map_open, ndbm_map_close, 299 ndbm_map_lookup, ndbm_map_store); 300 #endif 301 302 #ifdef NIS 303 MAPDEF("nis", NULL, MCF_ALIASOK, 304 map_parseargs, nis_map_open, null_map_close, 305 nis_map_lookup, null_map_store); 306 #endif 307 308 #ifdef NISPLUS 309 MAPDEF("nisplus", NULL, MCF_ALIASOK, 310 map_parseargs, nisplus_map_open, null_map_close, 311 nisplus_map_lookup, null_map_store); 312 #endif 313 314 #if NAMED_BIND 315 # if 0 316 MAPDEF("dns", NULL, 0, 317 dns_map_init, null_map_open, null_map_close, 318 dns_map_lookup, null_map_store); 319 # endif 320 321 /* old name for back compat */ 322 MAPDEF("host", NULL, 0, 323 host_map_init, null_map_open, null_map_close, 324 host_map_lookup, null_map_store); 325 #endif 326 327 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY, 328 map_parseargs, stab_map_open, null_map_close, 329 stab_map_lookup, stab_map_store); 330 331 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE, 332 map_parseargs, impl_map_open, impl_map_close, 333 impl_map_lookup, impl_map_store); 334 335 /* access to system passwd file */ 336 MAPDEF("user", NULL, 0, 337 map_parseargs, user_map_open, null_map_close, 338 user_map_lookup, null_map_store); 339 340 /* dequote map */ 341 MAPDEF("dequote", NULL, 0, 342 dequote_init, null_map_open, null_map_close, 343 dequote_map, null_map_store); 344 345 #if 0 346 # ifdef USERDB 347 /* user database */ 348 MAPDEF("udb", ".db", 0, 349 udb_map_parse, null_map_open, null_map_close, 350 udb_map_lookup, null_map_store); 351 # endif 352 #endif 353 354 /* sequenced maps */ 355 MAPDEF("sequence", NULL, MCF_ALIASOK, 356 seq_map_parse, null_map_open, null_map_close, 357 seq_map_lookup, seq_map_store); 358 } 359 360 #undef MAPDEF 361 /* 362 ** INITHOSTMAPS -- initial host-dependent maps 363 ** 364 ** This should act as an interface to any local service switch 365 ** provided by the host operating system. 366 ** 367 ** Parameters: 368 ** none 369 ** 370 ** Returns: 371 ** none 372 ** 373 ** Side Effects: 374 ** Should define maps "host" and "passwd" as necessary 375 ** for this OS. If they are not defined, they will get 376 ** a default value later. It should check to make sure 377 ** they are not defined first, since it's possible that 378 ** the config file has provided an override. 379 */ 380 381 void 382 inithostmaps() 383 { 384 #ifdef SOLARIS 385 #endif 386 } 387 /* 388 ** USERNAME -- return the user id of the logged in user. 389 ** 390 ** Parameters: 391 ** none. 392 ** 393 ** Returns: 394 ** The login name of the logged in user. 395 ** 396 ** Side Effects: 397 ** none. 398 ** 399 ** Notes: 400 ** The return value is statically allocated. 401 */ 402 403 char * 404 username() 405 { 406 static char *myname = NULL; 407 extern char *getlogin(); 408 register struct passwd *pw; 409 410 /* cache the result */ 411 if (myname == NULL) 412 { 413 myname = getlogin(); 414 if (myname == NULL || myname[0] == '\0') 415 { 416 pw = getpwuid(RealUid); 417 if (pw != NULL) 418 myname = newstr(pw->pw_name); 419 } 420 else 421 { 422 uid_t uid = RealUid; 423 424 myname = newstr(myname); 425 if ((pw = getpwnam(myname)) == NULL || 426 (uid != 0 && uid != pw->pw_uid)) 427 { 428 pw = getpwuid(uid); 429 if (pw != NULL) 430 myname = newstr(pw->pw_name); 431 } 432 } 433 if (myname == NULL || myname[0] == '\0') 434 { 435 syserr("554 Who are you?"); 436 myname = "postmaster"; 437 } 438 } 439 440 return (myname); 441 } 442 /* 443 ** TTYPATH -- Get the path of the user's tty 444 ** 445 ** Returns the pathname of the user's tty. Returns NULL if 446 ** the user is not logged in or if s/he has write permission 447 ** denied. 448 ** 449 ** Parameters: 450 ** none 451 ** 452 ** Returns: 453 ** pathname of the user's tty. 454 ** NULL if not logged in or write permission denied. 455 ** 456 ** Side Effects: 457 ** none. 458 ** 459 ** WARNING: 460 ** Return value is in a local buffer. 461 ** 462 ** Called By: 463 ** savemail 464 */ 465 466 char * 467 ttypath() 468 { 469 struct stat stbuf; 470 register char *pathn; 471 extern char *ttyname(); 472 extern char *getlogin(); 473 474 /* compute the pathname of the controlling tty */ 475 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 476 (pathn = ttyname(0)) == NULL) 477 { 478 errno = 0; 479 return (NULL); 480 } 481 482 /* see if we have write permission */ 483 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 484 { 485 errno = 0; 486 return (NULL); 487 } 488 489 /* see if the user is logged in */ 490 if (getlogin() == NULL) 491 return (NULL); 492 493 /* looks good */ 494 return (pathn); 495 } 496 /* 497 ** CHECKCOMPAT -- check for From and To person compatible. 498 ** 499 ** This routine can be supplied on a per-installation basis 500 ** to determine whether a person is allowed to send a message. 501 ** This allows restriction of certain types of internet 502 ** forwarding or registration of users. 503 ** 504 ** If the hosts are found to be incompatible, an error 505 ** message should be given using "usrerr" and 0 should 506 ** be returned. 507 ** 508 ** EF_NORETURN can be set in e->e_flags to suppress the return-to-sender 509 ** function; this should be done on huge messages. 510 ** 511 ** Parameters: 512 ** to -- the person being sent to. 513 ** 514 ** Returns: 515 ** an exit status 516 ** 517 ** Side Effects: 518 ** none (unless you include the usrerr stuff) 519 */ 520 521 checkcompat(to, e) 522 register ADDRESS *to; 523 register ENVELOPE *e; 524 { 525 # ifdef lint 526 if (to == NULL) 527 to++; 528 # endif /* lint */ 529 530 if (tTd(49, 1)) 531 printf("checkcompat(to=%s, from=%s)\n", 532 to->q_paddr, e->e_from.q_paddr); 533 534 # ifdef EXAMPLE_CODE 535 /* this code is intended as an example only */ 536 register STAB *s; 537 538 s = stab("arpa", ST_MAILER, ST_FIND); 539 if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 && 540 to->q_mailer == s->s_mailer) 541 { 542 usrerr("553 No ARPA mail through this machine: see your system administration"); 543 /* e->e_flags |= EF_NORETURN; to supress return copy */ 544 return (EX_UNAVAILABLE); 545 } 546 # endif /* EXAMPLE_CODE */ 547 return (EX_OK); 548 } 549 /* 550 ** SETSIGNAL -- set a signal handler 551 ** 552 ** This is essentially old BSD "signal(3)". 553 */ 554 555 sigfunc_t 556 setsignal(sig, handler) 557 int sig; 558 sigfunc_t handler; 559 { 560 #if defined(SYS5SIGNALS) || defined(BSD4_3) || defined(_AUX_SOURCE) 561 return signal(sig, handler); 562 #else 563 struct sigaction n, o; 564 565 bzero(&n, sizeof n); 566 n.sa_handler = handler; 567 # ifdef SA_RESTART 568 n.sa_flags = SA_RESTART; 569 # endif 570 if (sigaction(sig, &n, &o) < 0) 571 return SIG_ERR; 572 return o.sa_handler; 573 #endif 574 } 575 /* 576 ** HOLDSIGS -- arrange to hold all signals 577 ** 578 ** Parameters: 579 ** none. 580 ** 581 ** Returns: 582 ** none. 583 ** 584 ** Side Effects: 585 ** Arranges that signals are held. 586 */ 587 588 holdsigs() 589 { 590 } 591 /* 592 ** RLSESIGS -- arrange to release all signals 593 ** 594 ** This undoes the effect of holdsigs. 595 ** 596 ** Parameters: 597 ** none. 598 ** 599 ** Returns: 600 ** none. 601 ** 602 ** Side Effects: 603 ** Arranges that signals are released. 604 */ 605 606 rlsesigs() 607 { 608 } 609 /* 610 ** INIT_MD -- do machine dependent initializations 611 ** 612 ** Systems that have global modes that should be set should do 613 ** them here rather than in main. 614 */ 615 616 #ifdef _AUX_SOURCE 617 # include <compat.h> 618 #endif 619 620 init_md(argc, argv) 621 int argc; 622 char **argv; 623 { 624 #ifdef _AUX_SOURCE 625 setcompat(getcompat() | COMPAT_BSDPROT); 626 #endif 627 } 628 /* 629 ** GETLA -- get the current load average 630 ** 631 ** This code stolen from la.c. 632 ** 633 ** Parameters: 634 ** none. 635 ** 636 ** Returns: 637 ** The current load average as an integer. 638 ** 639 ** Side Effects: 640 ** none. 641 */ 642 643 /* try to guess what style of load average we have */ 644 #define LA_ZERO 1 /* always return load average as zero */ 645 #define LA_INT 2 /* read kmem for avenrun; interpret as long */ 646 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 647 #define LA_SUBR 4 /* call getloadavg */ 648 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */ 649 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */ 650 #define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */ 651 652 /* do guesses based on general OS type */ 653 #ifndef LA_TYPE 654 # define LA_TYPE LA_ZERO 655 #endif 656 657 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 658 659 #include <nlist.h> 660 661 #ifndef LA_AVENRUN 662 # ifdef SYSTEM5 663 # define LA_AVENRUN "avenrun" 664 # else 665 # define LA_AVENRUN "_avenrun" 666 # endif 667 #endif 668 669 /* _PATH_UNIX should be defined in <paths.h> */ 670 #ifndef _PATH_UNIX 671 # if defined(SYSTEM5) 672 # define _PATH_UNIX "/unix" 673 # else 674 # define _PATH_UNIX "/vmunix" 675 # endif 676 #endif 677 678 struct nlist Nl[] = 679 { 680 { LA_AVENRUN }, 681 #define X_AVENRUN 0 682 { 0 }, 683 }; 684 685 #ifndef FSHIFT 686 # if defined(unixpc) 687 # define FSHIFT 5 688 # endif 689 690 # if defined(__alpha) || defined(IRIX) 691 # define FSHIFT 10 692 # endif 693 #endif 694 695 #ifndef FSHIFT 696 # define FSHIFT 8 697 #endif 698 699 #ifndef FSCALE 700 # define FSCALE (1 << FSHIFT) 701 #endif 702 703 getla() 704 { 705 static int kmem = -1; 706 #if LA_TYPE == LA_INT 707 long avenrun[3]; 708 #else 709 # if LA_TYPE == LA_SHORT 710 short avenrun[3]; 711 # else 712 double avenrun[3]; 713 # endif 714 #endif 715 extern off_t lseek(); 716 extern int errno; 717 718 if (kmem < 0) 719 { 720 kmem = open("/dev/kmem", 0, 0); 721 if (kmem < 0) 722 { 723 if (tTd(3, 1)) 724 printf("getla: open(/dev/kmem): %s\n", 725 errstring(errno)); 726 return (-1); 727 } 728 (void) fcntl(kmem, F_SETFD, 1); 729 if (nlist(_PATH_UNIX, Nl) < 0) 730 { 731 if (tTd(3, 1)) 732 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 733 errstring(errno)); 734 return (-1); 735 } 736 if (Nl[X_AVENRUN].n_value == 0) 737 { 738 if (tTd(3, 1)) 739 printf("getla: nlist(%s, %s) ==> 0\n", 740 _PATH_UNIX, LA_AVENRUN); 741 return (-1); 742 } 743 #ifdef NAMELISTMASK 744 Nl[X_AVENRUN].n_value &= NAMELISTMASK; 745 #endif 746 } 747 if (tTd(3, 20)) 748 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 749 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 750 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 751 { 752 /* thank you Ian */ 753 if (tTd(3, 1)) 754 printf("getla: lseek or read: %s\n", errstring(errno)); 755 return (-1); 756 } 757 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 758 if (tTd(3, 5)) 759 { 760 printf("getla: avenrun = %d", avenrun[0]); 761 if (tTd(3, 15)) 762 printf(", %d, %d", avenrun[1], avenrun[2]); 763 printf("\n"); 764 } 765 if (tTd(3, 1)) 766 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 767 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 768 #else 769 if (tTd(3, 5)) 770 { 771 printf("getla: avenrun = %g", avenrun[0]); 772 if (tTd(3, 15)) 773 printf(", %g, %g", avenrun[1], avenrun[2]); 774 printf("\n"); 775 } 776 if (tTd(3, 1)) 777 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 778 return ((int) (avenrun[0] + 0.5)); 779 #endif 780 } 781 782 #else 783 #if LA_TYPE == LA_SUBR 784 785 #ifdef DGUX 786 787 #include <sys/dg_sys_info.h> 788 789 int getla() 790 { 791 struct dg_sys_info_load_info load_info; 792 793 dg_sys_info((long *)&load_info, 794 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); 795 796 return((int) (load_info.one_minute + 0.5)); 797 } 798 799 #else 800 801 getla() 802 { 803 double avenrun[3]; 804 805 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 806 { 807 if (tTd(3, 1)) 808 perror("getla: getloadavg failed:"); 809 return (-1); 810 } 811 if (tTd(3, 1)) 812 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 813 return ((int) (avenrun[0] + 0.5)); 814 } 815 816 #endif /* DGUX */ 817 #else 818 #if LA_TYPE == LA_MACH 819 820 /* 821 ** This has been tested on NEXTSTEP release 2.1/3.X. 822 */ 823 824 #if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 825 # include <mach/mach.h> 826 #else 827 # include <mach.h> 828 #endif 829 830 getla() 831 { 832 processor_set_t default_set; 833 kern_return_t error; 834 unsigned int info_count; 835 struct processor_set_basic_info info; 836 host_t host; 837 838 error = processor_set_default(host_self(), &default_set); 839 if (error != KERN_SUCCESS) 840 return -1; 841 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 842 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 843 &host, (processor_set_info_t)&info, 844 &info_count) != KERN_SUCCESS) 845 { 846 return -1; 847 } 848 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 849 } 850 851 852 #else 853 #if LA_TYPE == LA_PROCSTR 854 855 /* 856 ** Read /proc/loadavg for the load average. This is assumed to be 857 ** in a format like "0.15 0.12 0.06". 858 ** 859 ** Initially intended for Linux. This has been in the kernel 860 ** since at least 0.99.15. 861 */ 862 863 # ifndef _PATH_LOADAVG 864 # define _PATH_LOADAVG "/proc/loadavg" 865 # endif 866 867 int 868 getla() 869 { 870 double avenrun; 871 register int result; 872 FILE *fp; 873 874 fp = fopen(_PATH_LOADAVG, "r"); 875 if (fp == NULL) 876 { 877 if (tTd(3, 1)) 878 printf("getla: fopen(%s): %s\n", 879 _PATH_LOADAVG, errstring(errno)); 880 return -1; 881 } 882 result = fscanf(fp, "%lf", &avenrun); 883 fclose(fp); 884 if (result != 1) 885 { 886 if (tTd(3, 1)) 887 printf("getla: fscanf() = %d: %s\n", 888 result, errstring(errno)); 889 return -1; 890 } 891 892 if (tTd(3, 1)) 893 printf("getla(): %.2f\n", avenrun); 894 895 return ((int) (avenrun + 0.5)); 896 } 897 898 #else 899 900 getla() 901 { 902 if (tTd(3, 1)) 903 printf("getla: ZERO\n"); 904 return (0); 905 } 906 907 #endif 908 #endif 909 #endif 910 #endif 911 912 913 /* 914 * Copyright 1989 Massachusetts Institute of Technology 915 * 916 * Permission to use, copy, modify, distribute, and sell this software and its 917 * documentation for any purpose is hereby granted without fee, provided that 918 * the above copyright notice appear in all copies and that both that 919 * copyright notice and this permission notice appear in supporting 920 * documentation, and that the name of M.I.T. not be used in advertising or 921 * publicity pertaining to distribution of the software without specific, 922 * written prior permission. M.I.T. makes no representations about the 923 * suitability of this software for any purpose. It is provided "as is" 924 * without express or implied warranty. 925 * 926 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 927 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 928 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 929 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 930 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 931 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 932 * 933 * Authors: Many and varied... 934 */ 935 936 /* Non Apollo stuff removed by Don Lewis 11/15/93 */ 937 #ifndef lint 938 static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $"; 939 #endif /* !lint */ 940 941 #ifdef apollo 942 # undef volatile 943 # include <apollo/base.h> 944 945 /* ARGSUSED */ 946 int getloadavg( call_data ) 947 caddr_t call_data; /* pointer to (double) return value */ 948 { 949 double *avenrun = (double *) call_data; 950 int i; 951 status_$t st; 952 long loadav[3]; 953 proc1_$get_loadav(loadav, &st); 954 *avenrun = loadav[0] / (double) (1 << 16); 955 return(0); 956 } 957 # endif /* apollo */ 958 /* 959 ** SHOULDQUEUE -- should this message be queued or sent? 960 ** 961 ** Compares the message cost to the load average to decide. 962 ** 963 ** Parameters: 964 ** pri -- the priority of the message in question. 965 ** ctime -- the message creation time. 966 ** 967 ** Returns: 968 ** TRUE -- if this message should be queued up for the 969 ** time being. 970 ** FALSE -- if the load is low enough to send this message. 971 ** 972 ** Side Effects: 973 ** none. 974 */ 975 976 bool 977 shouldqueue(pri, ctime) 978 long pri; 979 time_t ctime; 980 { 981 if (CurrentLA < QueueLA) 982 return (FALSE); 983 if (CurrentLA >= RefuseLA) 984 return (TRUE); 985 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 986 } 987 /* 988 ** REFUSECONNECTIONS -- decide if connections should be refused 989 ** 990 ** Parameters: 991 ** none. 992 ** 993 ** Returns: 994 ** TRUE if incoming SMTP connections should be refused 995 ** (for now). 996 ** FALSE if we should accept new work. 997 ** 998 ** Side Effects: 999 ** none. 1000 */ 1001 1002 bool 1003 refuseconnections() 1004 { 1005 #ifdef XLA 1006 if (!xla_smtp_ok()) 1007 return TRUE; 1008 #endif 1009 1010 /* this is probably too simplistic */ 1011 return (CurrentLA >= RefuseLA); 1012 } 1013 /* 1014 ** SETPROCTITLE -- set process title for ps 1015 ** 1016 ** Parameters: 1017 ** fmt -- a printf style format string. 1018 ** a, b, c -- possible parameters to fmt. 1019 ** 1020 ** Returns: 1021 ** none. 1022 ** 1023 ** Side Effects: 1024 ** Clobbers argv of our main procedure so ps(1) will 1025 ** display the title. 1026 */ 1027 1028 #define SPT_NONE 0 /* don't use it at all */ 1029 #define SPT_REUSEARGV 1 /* cover argv with title information */ 1030 #define SPT_BUILTIN 2 /* use libc builtin */ 1031 #define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */ 1032 #define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */ 1033 #define SPT_WRITEUDOT 5 /* write u. area in kmem */ 1034 1035 #ifndef SPT_TYPE 1036 # define SPT_TYPE SPT_REUSEARGV 1037 #endif 1038 1039 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN 1040 1041 # if SPT_TYPE == SPT_PSTAT 1042 # include <sys/pstat.h> 1043 # endif 1044 # if SPT_TYPE == SPT_PSSTRINGS 1045 # include <machine/vmparam.h> 1046 # include <sys/exec.h> 1047 # ifndef PS_STRINGS /* hmmmm.... apparently not available after all */ 1048 # undef SPT_TYPE 1049 # define SPT_TYPE SPT_REUSEARGV 1050 # endif 1051 # endif 1052 1053 # if SPT_TYPE == SPT_PSSTRINGS 1054 # define SETPROC_STATIC static 1055 # else 1056 # define SETPROC_STATIC 1057 # endif 1058 1059 # ifndef SPT_PADCHAR 1060 # define SPT_PADCHAR ' ' 1061 # endif 1062 1063 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */ 1064 1065 #if SPT_TYPE != SPT_BUILTIN 1066 1067 /*VARARGS1*/ 1068 # ifdef __STDC__ 1069 setproctitle(char *fmt, ...) 1070 # else 1071 setproctitle(fmt, va_alist) 1072 char *fmt; 1073 va_dcl 1074 # endif 1075 { 1076 # if SPT_TYPE != SPT_NONE 1077 register char *p; 1078 register int i; 1079 SETPROC_STATIC char buf[MAXLINE]; 1080 VA_LOCAL_DECL 1081 # if SPT_TYPE == SPT_PSTAT 1082 union pstun pst; 1083 # endif 1084 extern char **Argv; 1085 extern char *LastArgv; 1086 1087 p = buf; 1088 1089 /* print sendmail: heading for grep */ 1090 (void) strcpy(p, "sendmail: "); 1091 p += strlen(p); 1092 1093 /* print the argument string */ 1094 VA_START(fmt); 1095 (void) vsprintf(p, fmt, ap); 1096 VA_END; 1097 1098 i = strlen(buf); 1099 1100 # if SPT_TYPE == SPT_PSTAT 1101 pst.pst_command = buf; 1102 pstat(PSTAT_SETCMD, pst, i, 0, 0); 1103 # else 1104 # if SPT_TYPE == SPT_PSSTRINGS 1105 PS_STRINGS->ps_nargvstr = 1; 1106 PS_STRINGS->ps_argvstr = buf; 1107 # else 1108 if (i > LastArgv - Argv[0] - 2) 1109 { 1110 i = LastArgv - Argv[0] - 2; 1111 buf[i] = '\0'; 1112 } 1113 (void) strcpy(Argv[0], buf); 1114 p = &Argv[0][i]; 1115 while (p < LastArgv) 1116 *p++ = SPT_PADCHAR; 1117 Argv[1] = NULL; 1118 # endif /* SPT_TYPE == SPT_PSSTRINGS */ 1119 # endif /* SPT_TYPE == SPT_PSTAT */ 1120 # endif /* SPT_TYPE != SPT_NONE */ 1121 } 1122 1123 #endif /* SPT_TYPE != SPT_BUILTIN */ 1124 /* 1125 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 1126 ** 1127 ** Parameters: 1128 ** none. 1129 ** 1130 ** Returns: 1131 ** none. 1132 ** 1133 ** Side Effects: 1134 ** Picks up extant zombies. 1135 */ 1136 1137 void 1138 reapchild() 1139 { 1140 int olderrno = errno; 1141 # ifdef HASWAITPID 1142 auto int status; 1143 int count; 1144 int pid; 1145 1146 count = 0; 1147 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 1148 { 1149 if (count++ > 1000) 1150 { 1151 #ifdef LOG 1152 syslog(LOG_ALERT, "reapchild: waitpid loop: pid=%d, status=%x", 1153 pid, status); 1154 #endif 1155 break; 1156 } 1157 } 1158 # else 1159 # ifdef WNOHANG 1160 union wait status; 1161 1162 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) 1163 continue; 1164 # else /* WNOHANG */ 1165 auto int status; 1166 1167 while (wait(&status) > 0) 1168 continue; 1169 # endif /* WNOHANG */ 1170 # endif 1171 # ifdef SYS5SIGNALS 1172 (void) setsignal(SIGCHLD, reapchild); 1173 # endif 1174 errno = olderrno; 1175 } 1176 /* 1177 ** UNSETENV -- remove a variable from the environment 1178 ** 1179 ** Not needed on newer systems. 1180 ** 1181 ** Parameters: 1182 ** name -- the string name of the environment variable to be 1183 ** deleted from the current environment. 1184 ** 1185 ** Returns: 1186 ** none. 1187 ** 1188 ** Globals: 1189 ** environ -- a pointer to the current environment. 1190 ** 1191 ** Side Effects: 1192 ** Modifies environ. 1193 */ 1194 1195 #ifndef HASUNSETENV 1196 1197 void 1198 unsetenv(name) 1199 char *name; 1200 { 1201 extern char **environ; 1202 register char **pp; 1203 int len = strlen(name); 1204 1205 for (pp = environ; *pp != NULL; pp++) 1206 { 1207 if (strncmp(name, *pp, len) == 0 && 1208 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 1209 break; 1210 } 1211 1212 for (; *pp != NULL; pp++) 1213 *pp = pp[1]; 1214 } 1215 1216 #endif 1217 /* 1218 ** GETDTABLESIZE -- return number of file descriptors 1219 ** 1220 ** Only on non-BSD systems 1221 ** 1222 ** Parameters: 1223 ** none 1224 ** 1225 ** Returns: 1226 ** size of file descriptor table 1227 ** 1228 ** Side Effects: 1229 ** none 1230 */ 1231 1232 #ifdef SOLARIS 1233 # include <sys/resource.h> 1234 #endif 1235 1236 int 1237 getdtsize() 1238 { 1239 #ifdef RLIMIT_NOFILE 1240 struct rlimit rl; 1241 1242 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 1243 return rl.rlim_cur; 1244 #endif 1245 1246 # ifdef HASGETDTABLESIZE 1247 return getdtablesize(); 1248 # else 1249 # ifdef _SC_OPEN_MAX 1250 return sysconf(_SC_OPEN_MAX); 1251 # else 1252 return NOFILE; 1253 # endif 1254 # endif 1255 } 1256 /* 1257 ** UNAME -- get the UUCP name of this system. 1258 */ 1259 1260 #ifndef HASUNAME 1261 1262 int 1263 uname(name) 1264 struct utsname *name; 1265 { 1266 FILE *file; 1267 char *n; 1268 1269 name->nodename[0] = '\0'; 1270 1271 /* try /etc/whoami -- one line with the node name */ 1272 if ((file = fopen("/etc/whoami", "r")) != NULL) 1273 { 1274 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 1275 (void) fclose(file); 1276 n = strchr(name->nodename, '\n'); 1277 if (n != NULL) 1278 *n = '\0'; 1279 if (name->nodename[0] != '\0') 1280 return (0); 1281 } 1282 1283 /* try /usr/include/whoami.h -- has a #define somewhere */ 1284 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 1285 { 1286 char buf[MAXLINE]; 1287 1288 while (fgets(buf, MAXLINE, file) != NULL) 1289 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 1290 NODE_LENGTH, name->nodename) > 0) 1291 break; 1292 (void) fclose(file); 1293 if (name->nodename[0] != '\0') 1294 return (0); 1295 } 1296 1297 #ifdef TRUST_POPEN 1298 /* 1299 ** Popen is known to have security holes. 1300 */ 1301 1302 /* try uuname -l to return local name */ 1303 if ((file = popen("uuname -l", "r")) != NULL) 1304 { 1305 (void) fgets(name, NODE_LENGTH + 1, file); 1306 (void) pclose(file); 1307 n = strchr(name, '\n'); 1308 if (n != NULL) 1309 *n = '\0'; 1310 if (name->nodename[0] != '\0') 1311 return (0); 1312 } 1313 #endif 1314 1315 return (-1); 1316 } 1317 #endif /* HASUNAME */ 1318 /* 1319 ** INITGROUPS -- initialize groups 1320 ** 1321 ** Stub implementation for System V style systems 1322 */ 1323 1324 #ifndef HASINITGROUPS 1325 1326 initgroups(name, basegid) 1327 char *name; 1328 int basegid; 1329 { 1330 return 0; 1331 } 1332 1333 #endif 1334 /* 1335 ** SETSID -- set session id (for non-POSIX systems) 1336 */ 1337 1338 #ifndef HASSETSID 1339 1340 pid_t 1341 setsid __P ((void)) 1342 { 1343 #ifdef TIOCNOTTY 1344 int fd; 1345 1346 fd = open("/dev/tty", O_RDWR, 0); 1347 if (fd >= 0) 1348 { 1349 (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0); 1350 (void) close(fd); 1351 } 1352 #endif /* TIOCNOTTY */ 1353 # ifdef SYS5SETPGRP 1354 return setpgrp(); 1355 # else 1356 return setpgid(0, getpid()); 1357 # endif 1358 } 1359 1360 #endif 1361 /* 1362 ** FSYNC -- dummy fsync 1363 */ 1364 1365 #ifdef NEEDFSYNC 1366 1367 fsync(fd) 1368 int fd; 1369 { 1370 # ifdef O_SYNC 1371 return fcntl(fd, F_SETFL, O_SYNC); 1372 # else 1373 /* nothing we can do */ 1374 return 0; 1375 # endif 1376 } 1377 1378 #endif 1379 /* 1380 ** DGUX_INET_ADDR -- inet_addr for DG/UX 1381 ** 1382 ** Data General DG/UX version of inet_addr returns a struct in_addr 1383 ** instead of a long. This patches things. Only needed on versions 1384 ** prior to 5.4.3. 1385 */ 1386 1387 #ifdef DGUX_5_4_2 1388 1389 #undef inet_addr 1390 1391 long 1392 dgux_inet_addr(host) 1393 char *host; 1394 { 1395 struct in_addr haddr; 1396 1397 haddr = inet_addr(host); 1398 return haddr.s_addr; 1399 } 1400 1401 #endif 1402 /* 1403 ** GETOPT -- for old systems or systems with bogus implementations 1404 */ 1405 1406 #ifdef NEEDGETOPT 1407 1408 /* 1409 * Copyright (c) 1985 Regents of the University of California. 1410 * All rights reserved. The Berkeley software License Agreement 1411 * specifies the terms and conditions for redistribution. 1412 */ 1413 1414 1415 /* 1416 ** this version hacked to add `atend' flag to allow state machine 1417 ** to reset if invoked by the program to scan args for a 2nd time 1418 */ 1419 1420 #if defined(LIBC_SCCS) && !defined(lint) 1421 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 1422 #endif /* LIBC_SCCS and not lint */ 1423 1424 #include <stdio.h> 1425 1426 /* 1427 * get option letter from argument vector 1428 */ 1429 #ifdef _CONVEX_SOURCE 1430 extern int optind, opterr; 1431 #else 1432 int opterr = 1; /* if error message should be printed */ 1433 int optind = 1; /* index into parent argv vector */ 1434 #endif 1435 int optopt; /* character checked for validity */ 1436 char *optarg; /* argument associated with option */ 1437 1438 #define BADCH (int)'?' 1439 #define EMSG "" 1440 #define tell(s) if (opterr) {fputs(*nargv,stderr);fputs(s,stderr); \ 1441 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);} 1442 1443 getopt(nargc,nargv,ostr) 1444 int nargc; 1445 char *const *nargv; 1446 const char *ostr; 1447 { 1448 static char *place = EMSG; /* option letter processing */ 1449 static char atend = 0; 1450 register char *oli; /* option letter list index */ 1451 1452 if (atend) { 1453 atend = 0; 1454 place = EMSG; 1455 } 1456 if(!*place) { /* update scanning pointer */ 1457 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 1458 atend++; 1459 return(EOF); 1460 } 1461 if (*place == '-') { /* found "--" */ 1462 ++optind; 1463 atend++; 1464 return(EOF); 1465 } 1466 } /* option letter okay? */ 1467 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 1468 if (!*place) ++optind; 1469 tell(": illegal option -- "); 1470 } 1471 if (*++oli != ':') { /* don't need argument */ 1472 optarg = NULL; 1473 if (!*place) ++optind; 1474 } 1475 else { /* need an argument */ 1476 if (*place) optarg = place; /* no white space */ 1477 else if (nargc <= ++optind) { /* no arg */ 1478 place = EMSG; 1479 tell(": option requires an argument -- "); 1480 } 1481 else optarg = nargv[optind]; /* white space */ 1482 place = EMSG; 1483 ++optind; 1484 } 1485 return(optopt); /* dump back option letter */ 1486 } 1487 1488 #endif 1489 /* 1490 ** VFPRINTF, VSPRINTF -- for old 4.3 BSD systems missing a real version 1491 */ 1492 1493 #ifdef NEEDVPRINTF 1494 1495 #define MAXARG 16 1496 1497 vfprintf(fp, fmt, ap) 1498 FILE * fp; 1499 char * fmt; 1500 char ** ap; 1501 { 1502 char * bp[MAXARG]; 1503 int i = 0; 1504 1505 while (*ap && i < MAXARG) 1506 bp[i++] = *ap++; 1507 fprintf(fp, fmt, bp[0], bp[1], bp[2], bp[3], 1508 bp[4], bp[5], bp[6], bp[7], 1509 bp[8], bp[9], bp[10], bp[11], 1510 bp[12], bp[13], bp[14], bp[15]); 1511 } 1512 1513 vsprintf(s, fmt, ap) 1514 char * s; 1515 char * fmt; 1516 char ** ap; 1517 { 1518 char * bp[MAXARG]; 1519 int i = 0; 1520 1521 while (*ap && i < MAXARG) 1522 bp[i++] = *ap++; 1523 sprintf(s, fmt, bp[0], bp[1], bp[2], bp[3], 1524 bp[4], bp[5], bp[6], bp[7], 1525 bp[8], bp[9], bp[10], bp[11], 1526 bp[12], bp[13], bp[14], bp[15]); 1527 } 1528 1529 #endif 1530 /* 1531 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 1532 ** 1533 ** Parameters: 1534 ** shell -- the user's shell from /etc/passwd 1535 ** 1536 ** Returns: 1537 ** TRUE -- if it is ok to use this for unrestricted access. 1538 ** FALSE -- if the shell is restricted. 1539 */ 1540 1541 #if !HASGETUSERSHELL 1542 1543 # ifndef _PATH_SHELLS 1544 # define _PATH_SHELLS "/etc/shells" 1545 # endif 1546 1547 char *DefaultUserShells[] = 1548 { 1549 "/bin/sh", 1550 "/usr/bin/sh", 1551 "/bin/csh", 1552 "/usr/bin/csh", 1553 #ifdef __hpux 1554 "/bin/rsh", 1555 "/bin/ksh", 1556 "/bin/rksh", 1557 "/bin/pam", 1558 "/usr/bin/keysh", 1559 "/bin/posix/sh", 1560 #endif 1561 NULL 1562 }; 1563 1564 #endif 1565 1566 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 1567 1568 bool 1569 usershellok(shell) 1570 char *shell; 1571 { 1572 #if HASGETUSERSHELL 1573 register char *p; 1574 extern char *getusershell(); 1575 1576 setusershell(); 1577 while ((p = getusershell()) != NULL) 1578 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 1579 break; 1580 endusershell(); 1581 return p != NULL; 1582 #else 1583 register FILE *shellf; 1584 char buf[MAXLINE]; 1585 1586 shellf = fopen(_PATH_SHELLS, "r"); 1587 if (shellf == NULL) 1588 { 1589 /* no /etc/shells; see if it is one of the std shells */ 1590 char **d; 1591 1592 for (d = DefaultUserShells; *d != NULL; d++) 1593 { 1594 if (strcmp(shell, *d) == 0) 1595 return TRUE; 1596 } 1597 return FALSE; 1598 } 1599 1600 while (fgets(buf, sizeof buf, shellf) != NULL) 1601 { 1602 register char *p, *q; 1603 1604 p = buf; 1605 while (*p != '\0' && *p != '#' && *p != '/') 1606 p++; 1607 if (*p == '#' || *p == '\0') 1608 continue; 1609 q = p; 1610 while (*p != '\0' && *p != '#' && !isspace(*p)) 1611 p++; 1612 *p = '\0'; 1613 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 1614 { 1615 fclose(shellf); 1616 return TRUE; 1617 } 1618 } 1619 fclose(shellf); 1620 return FALSE; 1621 #endif 1622 } 1623 /* 1624 ** FREESPACE -- see how much free space is on the queue filesystem 1625 ** 1626 ** Only implemented if you have statfs. 1627 ** 1628 ** Parameters: 1629 ** dir -- the directory in question. 1630 ** bsize -- a variable into which the filesystem 1631 ** block size is stored. 1632 ** 1633 ** Returns: 1634 ** The number of bytes free on the queue filesystem. 1635 ** -1 if the statfs call fails. 1636 ** 1637 ** Side effects: 1638 ** Puts the filesystem block size into bsize. 1639 */ 1640 1641 /* statfs types */ 1642 #define SFS_NONE 0 /* no statfs implementation */ 1643 #define SFS_USTAT 1 /* use ustat */ 1644 #define SFS_4ARGS 2 /* use four-argument statfs call */ 1645 #define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 1646 #define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 1647 #define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 1648 #define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */ 1649 1650 #ifndef SFS_TYPE 1651 # define SFS_TYPE SFS_NONE 1652 #endif 1653 1654 #if SFS_TYPE == SFS_USTAT 1655 # include <ustat.h> 1656 #endif 1657 #if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 1658 # include <sys/statfs.h> 1659 #endif 1660 #if SFS_TYPE == SFS_VFS 1661 # include <sys/vfs.h> 1662 #endif 1663 #if SFS_TYPE == SFS_MOUNT 1664 # include <sys/mount.h> 1665 #endif 1666 #if SFS_TYPE == SFS_STATVFS 1667 # include <sys/statvfs.h> 1668 #endif 1669 1670 long 1671 freespace(dir, bsize) 1672 char *dir; 1673 long *bsize; 1674 { 1675 #if SFS_TYPE != SFS_NONE 1676 # if SFS_TYPE == SFS_USTAT 1677 struct ustat fs; 1678 struct stat statbuf; 1679 # define FSBLOCKSIZE DEV_BSIZE 1680 # define f_bavail f_tfree 1681 # else 1682 # if defined(ultrix) 1683 struct fs_data fs; 1684 # define f_bavail fd_bfreen 1685 # define FSBLOCKSIZE 1024L 1686 # else 1687 # if SFS_TYPE == SFS_STATVFS 1688 struct statvfs fs; 1689 # define FSBLOCKSIZE fs.f_bsize 1690 # else 1691 struct statfs fs; 1692 # define FSBLOCKSIZE fs.f_bsize 1693 # if defined(_SCO_unix_) || defined(IRIX) || defined(apollo) 1694 # define f_bavail f_bfree 1695 # endif 1696 # endif 1697 # endif 1698 # endif 1699 extern int errno; 1700 1701 # if SFS_TYPE == SFS_USTAT 1702 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 1703 # else 1704 # if SFS_TYPE == SFS_4ARGS 1705 if (statfs(dir, &fs, sizeof fs, 0) == 0) 1706 # else 1707 # if SFS_TYPE == SFS_STATVFS 1708 if (statvfs(dir, &fs) == 0) 1709 # else 1710 # if defined(ultrix) 1711 if (statfs(dir, &fs) > 0) 1712 # else 1713 if (statfs(dir, &fs) == 0) 1714 # endif 1715 # endif 1716 # endif 1717 # endif 1718 { 1719 if (bsize != NULL) 1720 *bsize = FSBLOCKSIZE; 1721 return (fs.f_bavail); 1722 } 1723 #endif 1724 return (-1); 1725 } 1726 /* 1727 ** ENOUGHSPACE -- check to see if there is enough free space on the queue fs 1728 ** 1729 ** Only implemented if you have statfs. 1730 ** 1731 ** Parameters: 1732 ** msize -- the size to check against. If zero, we don't yet 1733 ** know how big the message will be, so just check for 1734 ** a "reasonable" amount. 1735 ** 1736 ** Returns: 1737 ** TRUE if there is enough space. 1738 ** FALSE otherwise. 1739 */ 1740 1741 bool 1742 enoughspace(msize) 1743 long msize; 1744 { 1745 long bfree, bsize; 1746 1747 if (MinBlocksFree <= 0 && msize <= 0) 1748 { 1749 if (tTd(4, 80)) 1750 printf("enoughspace: no threshold\n"); 1751 return TRUE; 1752 } 1753 1754 if ((bfree = freespace(QueueDir, &bsize)) >= 0) 1755 { 1756 if (tTd(4, 80)) 1757 printf("enoughspace: bavail=%ld, need=%ld\n", 1758 bfree, msize); 1759 1760 /* convert msize to block count */ 1761 msize = msize / bsize + 1; 1762 if (MinBlocksFree >= 0) 1763 msize += MinBlocksFree; 1764 1765 if (bfree < msize) 1766 { 1767 #ifdef LOG 1768 if (LogLevel > 0) 1769 syslog(LOG_ALERT, 1770 "%s: low on space (have %ld, %s needs %ld in %s)", 1771 CurEnv->e_id, bfree, 1772 CurHostName, msize, QueueDir); 1773 #endif 1774 return FALSE; 1775 } 1776 } 1777 else if (tTd(4, 80)) 1778 printf("enoughspace failure: min=%ld, need=%ld: %s\n", 1779 MinBlocksFree, msize, errstring(errno)); 1780 return TRUE; 1781 } 1782 /* 1783 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 1784 ** 1785 ** This looks at an errno value and tells if this is likely to 1786 ** go away if retried later. 1787 ** 1788 ** Parameters: 1789 ** err -- the errno code to classify. 1790 ** 1791 ** Returns: 1792 ** TRUE if this is probably transient. 1793 ** FALSE otherwise. 1794 */ 1795 1796 bool 1797 transienterror(err) 1798 int err; 1799 { 1800 switch (err) 1801 { 1802 case EIO: /* I/O error */ 1803 case ENXIO: /* Device not configured */ 1804 case EAGAIN: /* Resource temporarily unavailable */ 1805 case ENOMEM: /* Cannot allocate memory */ 1806 case ENODEV: /* Operation not supported by device */ 1807 case ENFILE: /* Too many open files in system */ 1808 case EMFILE: /* Too many open files */ 1809 case ENOSPC: /* No space left on device */ 1810 #ifdef ETIMEDOUT 1811 case ETIMEDOUT: /* Connection timed out */ 1812 #endif 1813 #ifdef ESTALE 1814 case ESTALE: /* Stale NFS file handle */ 1815 #endif 1816 #ifdef ENETDOWN 1817 case ENETDOWN: /* Network is down */ 1818 #endif 1819 #ifdef ENETUNREACH 1820 case ENETUNREACH: /* Network is unreachable */ 1821 #endif 1822 #ifdef ENETRESET 1823 case ENETRESET: /* Network dropped connection on reset */ 1824 #endif 1825 #ifdef ECONNABORTED 1826 case ECONNABORTED: /* Software caused connection abort */ 1827 #endif 1828 #ifdef ECONNRESET 1829 case ECONNRESET: /* Connection reset by peer */ 1830 #endif 1831 #ifdef ENOBUFS 1832 case ENOBUFS: /* No buffer space available */ 1833 #endif 1834 #ifdef ESHUTDOWN 1835 case ESHUTDOWN: /* Can't send after socket shutdown */ 1836 #endif 1837 #ifdef ECONNREFUSED 1838 case ECONNREFUSED: /* Connection refused */ 1839 #endif 1840 #ifdef EHOSTDOWN 1841 case EHOSTDOWN: /* Host is down */ 1842 #endif 1843 #ifdef EHOSTUNREACH 1844 case EHOSTUNREACH: /* No route to host */ 1845 #endif 1846 #ifdef EDQUOT 1847 case EDQUOT: /* Disc quota exceeded */ 1848 #endif 1849 #ifdef EPROCLIM 1850 case EPROCLIM: /* Too many processes */ 1851 #endif 1852 #ifdef EUSERS 1853 case EUSERS: /* Too many users */ 1854 #endif 1855 #ifdef EDEADLK 1856 case EDEADLK: /* Resource deadlock avoided */ 1857 #endif 1858 #ifdef EISCONN 1859 case EISCONN: /* Socket already connected */ 1860 #endif 1861 #ifdef EINPROGRESS 1862 case EINPROGRESS: /* Operation now in progress */ 1863 #endif 1864 #ifdef EALREADY 1865 case EALREADY: /* Operation already in progress */ 1866 #endif 1867 #ifdef EADDRINUSE 1868 case EADDRINUSE: /* Address already in use */ 1869 #endif 1870 #ifdef EADDRNOTAVAIL 1871 case EADDRNOTAVAIL: /* Can't assign requested address */ 1872 #endif 1873 #ifdef ETXTBSY 1874 case ETXTBSY: /* (Apollo) file locked */ 1875 #endif 1876 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 1877 case ENOSR: /* Out of streams resources */ 1878 #endif 1879 return TRUE; 1880 } 1881 1882 /* nope, must be permanent */ 1883 return FALSE; 1884 } 1885 /* 1886 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 1887 ** 1888 ** Parameters: 1889 ** fd -- the file descriptor of the file. 1890 ** filename -- the file name (for error messages). 1891 ** ext -- the filename extension. 1892 ** type -- type of the lock. Bits can be: 1893 ** LOCK_EX -- exclusive lock. 1894 ** LOCK_NB -- non-blocking. 1895 ** 1896 ** Returns: 1897 ** TRUE if the lock was acquired. 1898 ** FALSE otherwise. 1899 */ 1900 1901 bool 1902 lockfile(fd, filename, ext, type) 1903 int fd; 1904 char *filename; 1905 char *ext; 1906 int type; 1907 { 1908 # if !HASFLOCK 1909 int action; 1910 struct flock lfd; 1911 1912 if (ext == NULL) 1913 ext = ""; 1914 1915 bzero(&lfd, sizeof lfd); 1916 if (bitset(LOCK_UN, type)) 1917 lfd.l_type = F_UNLCK; 1918 else if (bitset(LOCK_EX, type)) 1919 lfd.l_type = F_WRLCK; 1920 else 1921 lfd.l_type = F_RDLCK; 1922 1923 if (bitset(LOCK_NB, type)) 1924 action = F_SETLK; 1925 else 1926 action = F_SETLKW; 1927 1928 if (tTd(55, 60)) 1929 printf("lockfile(%s%s, action=%d, type=%d): ", 1930 filename, ext, action, lfd.l_type); 1931 1932 if (fcntl(fd, action, &lfd) >= 0) 1933 { 1934 if (tTd(55, 60)) 1935 printf("SUCCESS\n"); 1936 return TRUE; 1937 } 1938 1939 if (tTd(55, 60)) 1940 printf("(%s) ", errstring(errno)); 1941 1942 /* 1943 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 1944 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 1945 ** as type "tmp" (that is, served from swap space), the 1946 ** previous fcntl will fail with "Invalid argument" errors. 1947 ** Since this is fairly common during testing, we will assume 1948 ** that this indicates that the lock is successfully grabbed. 1949 */ 1950 1951 if (errno == EINVAL) 1952 { 1953 if (tTd(55, 60)) 1954 printf("SUCCESS\n"); 1955 return TRUE; 1956 } 1957 1958 if (!bitset(LOCK_NB, type) || (errno != EACCES && errno != EAGAIN)) 1959 { 1960 int omode = -1; 1961 # ifdef F_GETFL 1962 int oerrno = errno; 1963 1964 (void) fcntl(fd, F_GETFL, &omode); 1965 errno = oerrno; 1966 # endif 1967 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1968 filename, ext, fd, type, omode, geteuid()); 1969 } 1970 # else 1971 if (ext == NULL) 1972 ext = ""; 1973 1974 if (tTd(55, 60)) 1975 printf("lockfile(%s%s, type=%o): ", filename, ext, type); 1976 1977 if (flock(fd, type) >= 0) 1978 { 1979 if (tTd(55, 60)) 1980 printf("SUCCESS\n"); 1981 return TRUE; 1982 } 1983 1984 if (tTd(55, 60)) 1985 printf("(%s) ", errstring(errno)); 1986 1987 if (!bitset(LOCK_NB, type) || errno != EWOULDBLOCK) 1988 { 1989 int omode = -1; 1990 # ifdef F_GETFL 1991 int oerrno = errno; 1992 1993 (void) fcntl(fd, F_GETFL, &omode); 1994 errno = oerrno; 1995 # endif 1996 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 1997 filename, ext, fd, type, omode, geteuid()); 1998 } 1999 # endif 2000 if (tTd(55, 60)) 2001 printf("FAIL\n"); 2002 return FALSE; 2003 } 2004 /* 2005 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 2006 ** 2007 ** Parameters: 2008 ** fd -- the file descriptor to check. 2009 ** 2010 ** Returns: 2011 ** TRUE -- if only root can chown the file to an arbitrary 2012 ** user. 2013 ** FALSE -- if an arbitrary user can give away a file. 2014 */ 2015 2016 bool 2017 chownsafe(fd) 2018 int fd; 2019 { 2020 #ifdef __hpux 2021 char *s; 2022 int tfd; 2023 uid_t o_uid, o_euid; 2024 gid_t o_gid, o_egid; 2025 bool rval; 2026 struct stat stbuf; 2027 2028 o_uid = getuid(); 2029 o_euid = geteuid(); 2030 o_gid = getgid(); 2031 o_egid = getegid(); 2032 fstat(fd, &stbuf); 2033 setresuid(stbuf.st_uid, stbuf.st_uid, -1); 2034 setresgid(stbuf.st_gid, stbuf.st_gid, -1); 2035 s = tmpnam(NULL); 2036 tfd = open(s, O_RDONLY|O_CREAT, 0600); 2037 rval = fchown(tfd, DefUid, DefGid) != 0; 2038 close(tfd); 2039 unlink(s); 2040 setreuid(o_uid, o_euid); 2041 setresgid(o_gid, o_egid, -1); 2042 return rval; 2043 #else 2044 # ifdef _POSIX_CHOWN_RESTRICTED 2045 # if _POSIX_CHOWN_RESTRICTED == -1 2046 return FALSE; 2047 # else 2048 return TRUE; 2049 # endif 2050 # else 2051 # ifdef _PC_CHOWN_RESTRICTED 2052 int rval; 2053 2054 /* 2055 ** Some systems (e.g., SunOS) seem to have the call and the 2056 ** #define _PC_CHOWN_RESTRICTED, but don't actually implement 2057 ** the call. This heuristic checks for that. 2058 */ 2059 2060 errno = 0; 2061 rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); 2062 if (errno == 0) 2063 return rval > 0; 2064 # endif 2065 # ifdef BSD 2066 return TRUE; 2067 # else 2068 return FALSE; 2069 # endif 2070 # endif 2071 #endif 2072 } 2073 /* 2074 ** RESETLIMITS -- reset system controlled resource limits 2075 ** 2076 ** This is to avoid denial-of-service attacks 2077 ** 2078 ** Parameters: 2079 ** none 2080 ** 2081 ** Returns: 2082 ** none 2083 */ 2084 2085 #if HASSETRLIMIT 2086 # include <sys/resource.h> 2087 #endif 2088 2089 resetlimits() 2090 { 2091 #if HASSETRLIMIT 2092 struct rlimit lim; 2093 2094 lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 2095 (void) setrlimit(RLIMIT_CPU, &lim); 2096 (void) setrlimit(RLIMIT_FSIZE, &lim); 2097 #else 2098 # if HASULIMIT 2099 (void) ulimit(2, 0x3fffff); 2100 # endif 2101 #endif 2102 } 2103 /* 2104 ** GETCFNAME -- return the name of the .cf file. 2105 ** 2106 ** Some systems (e.g., NeXT) determine this dynamically. 2107 */ 2108 2109 char * 2110 getcfname() 2111 { 2112 if (ConfFile != NULL) 2113 return ConfFile; 2114 #ifdef NETINFO 2115 { 2116 extern char *ni_propval(); 2117 char *cflocation; 2118 2119 cflocation = ni_propval("/locations/sendmail", "sendmail.cf"); 2120 if (cflocation != NULL) 2121 return cflocation; 2122 } 2123 #endif 2124 return _PATH_SENDMAILCF; 2125 } 2126 /* 2127 ** SETVENDOR -- process vendor code from V configuration line 2128 ** 2129 ** Parameters: 2130 ** vendor -- string representation of vendor. 2131 ** 2132 ** Returns: 2133 ** TRUE -- if ok. 2134 ** FALSE -- if vendor code could not be processed. 2135 ** 2136 ** Side Effects: 2137 ** It is reasonable to set mode flags here to tweak 2138 ** processing in other parts of the code if necessary. 2139 ** For example, if you are a vendor that uses $%y to 2140 ** indicate YP lookups, you could enable that here. 2141 */ 2142 2143 bool 2144 setvendor(vendor) 2145 char *vendor; 2146 { 2147 if (strcasecmp(vendor, "Berkeley") == 0) 2148 return TRUE; 2149 2150 /* add vendor extensions here */ 2151 2152 return FALSE; 2153 } 2154 /* 2155 ** STRTOL -- convert string to long integer 2156 ** 2157 ** For systems that don't have it in the C library. 2158 ** 2159 ** This is taken verbatim from the 4.4-Lite C library. 2160 */ 2161 2162 #ifdef NEEDSTRTOL 2163 2164 #if defined(LIBC_SCCS) && !defined(lint) 2165 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 2166 #endif /* LIBC_SCCS and not lint */ 2167 2168 #include <limits.h> 2169 2170 /* 2171 * Convert a string to a long integer. 2172 * 2173 * Ignores `locale' stuff. Assumes that the upper and lower case 2174 * alphabets and digits are each contiguous. 2175 */ 2176 2177 long 2178 strtol(nptr, endptr, base) 2179 const char *nptr; 2180 char **endptr; 2181 register int base; 2182 { 2183 register const char *s = nptr; 2184 register unsigned long acc; 2185 register int c; 2186 register unsigned long cutoff; 2187 register int neg = 0, any, cutlim; 2188 2189 /* 2190 * Skip white space and pick up leading +/- sign if any. 2191 * If base is 0, allow 0x for hex and 0 for octal, else 2192 * assume decimal; if base is already 16, allow 0x. 2193 */ 2194 do { 2195 c = *s++; 2196 } while (isspace(c)); 2197 if (c == '-') { 2198 neg = 1; 2199 c = *s++; 2200 } else if (c == '+') 2201 c = *s++; 2202 if ((base == 0 || base == 16) && 2203 c == '0' && (*s == 'x' || *s == 'X')) { 2204 c = s[1]; 2205 s += 2; 2206 base = 16; 2207 } 2208 if (base == 0) 2209 base = c == '0' ? 8 : 10; 2210 2211 /* 2212 * Compute the cutoff value between legal numbers and illegal 2213 * numbers. That is the largest legal value, divided by the 2214 * base. An input number that is greater than this value, if 2215 * followed by a legal input character, is too big. One that 2216 * is equal to this value may be valid or not; the limit 2217 * between valid and invalid numbers is then based on the last 2218 * digit. For instance, if the range for longs is 2219 * [-2147483648..2147483647] and the input base is 10, 2220 * cutoff will be set to 214748364 and cutlim to either 2221 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 2222 * a value > 214748364, or equal but the next digit is > 7 (or 8), 2223 * the number is too big, and we will return a range error. 2224 * 2225 * Set any if any `digits' consumed; make it negative to indicate 2226 * overflow. 2227 */ 2228 cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; 2229 cutlim = cutoff % (unsigned long)base; 2230 cutoff /= (unsigned long)base; 2231 for (acc = 0, any = 0;; c = *s++) { 2232 if (isdigit(c)) 2233 c -= '0'; 2234 else if (isalpha(c)) 2235 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 2236 else 2237 break; 2238 if (c >= base) 2239 break; 2240 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 2241 any = -1; 2242 else { 2243 any = 1; 2244 acc *= base; 2245 acc += c; 2246 } 2247 } 2248 if (any < 0) { 2249 acc = neg ? LONG_MIN : LONG_MAX; 2250 errno = ERANGE; 2251 } else if (neg) 2252 acc = -acc; 2253 if (endptr != 0) 2254 *endptr = (char *)(any ? s - 1 : nptr); 2255 return (acc); 2256 } 2257 2258 #endif 2259 /* 2260 ** SOLARIS_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 2261 ** 2262 ** Solaris versions at least through 2.3 don't properly deliver a 2263 ** canonical h_name field. This tries to work around it. 2264 */ 2265 2266 #ifdef SOLARIS 2267 2268 extern int h_errno; 2269 2270 struct hostent * 2271 solaris_gethostbyname(name) 2272 const char *name; 2273 { 2274 # ifdef SOLARIS_2_3 2275 static struct hostent hp; 2276 static char buf[1000]; 2277 extern struct hostent *_switch_gethostbyname_r(); 2278 2279 return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 2280 # else 2281 extern struct hostent *__switch_gethostbyname(); 2282 2283 return __switch_gethostbyname(name); 2284 # endif 2285 } 2286 2287 struct hostent * 2288 solaris_gethostbyaddr(addr, len, type) 2289 const char *addr; 2290 int len; 2291 int type; 2292 { 2293 # ifdef SOLARIS_2_3 2294 static struct hostent hp; 2295 static char buf[1000]; 2296 extern struct hostent *_switch_gethostbyaddr_r(); 2297 2298 return _switch_gethostbyaddr_r(addr, len, type, &hp, buf, sizeof(buf), &h_errno); 2299 # else 2300 extern struct hostent *__switch_gethostbyaddr(); 2301 2302 return __switch_gethostbyaddr(addr, len, type); 2303 # endif 2304 } 2305 2306 #endif 2307 /* 2308 ** NI_PROPVAL -- netinfo property value lookup routine 2309 ** 2310 ** Parameters: 2311 ** directory -- the Netinfo directory name. 2312 ** propname -- the Netinfo property name. 2313 ** 2314 ** Returns: 2315 ** NULL -- if: 2316 ** 1. the directory is not found 2317 ** 2. the property name is not found 2318 ** 3. the property contains multiple values 2319 ** 4. some error occured 2320 ** else -- the location of the config file. 2321 ** 2322 ** Notes: 2323 ** Caller should free the return value of ni_proval 2324 */ 2325 2326 #ifdef NETINFO 2327 2328 # include <netinfo/ni.h> 2329 2330 # define LOCAL_NETINFO_DOMAIN "." 2331 # define PARENT_NETINFO_DOMAIN ".." 2332 # define MAX_NI_LEVELS 256 2333 2334 char * 2335 ni_propval(directory, propname) 2336 char *directory; 2337 char *propname; 2338 { 2339 char *propval = NULL; 2340 int i; 2341 void *ni = NULL; 2342 void *lastni = NULL; 2343 ni_status nis; 2344 ni_id nid; 2345 ni_namelist ninl; 2346 2347 /* 2348 ** If the passed directory and property name are found 2349 ** in one of netinfo domains we need to search (starting 2350 ** from the local domain moving all the way back to the 2351 ** root domain) set propval to the property's value 2352 ** and return it. 2353 */ 2354 2355 for (i = 0; i < MAX_NI_LEVELS; ++i) 2356 { 2357 if (i == 0) 2358 { 2359 nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); 2360 } 2361 else 2362 { 2363 if (lastni != NULL) 2364 ni_free(lastni); 2365 lastni = ni; 2366 nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); 2367 } 2368 2369 /* 2370 ** Don't bother if we didn't get a handle on a 2371 ** proper domain. This is not necessarily an error. 2372 ** We would get a positive ni_status if, for instance 2373 ** we never found the directory or property and tried 2374 ** to open the parent of the root domain! 2375 */ 2376 2377 if (nis != 0) 2378 break; 2379 2380 /* 2381 ** Find the path to the server information. 2382 */ 2383 2384 if (ni_pathsearch(ni, &nid, directory) != 0) 2385 continue; 2386 2387 /* 2388 ** Find "host" information. 2389 */ 2390 2391 if (ni_lookupprop(ni, &nid, propname, &ninl) != 0) 2392 continue; 2393 2394 /* 2395 ** If there's only one name in 2396 ** the list, assume we've got 2397 ** what we want. 2398 */ 2399 2400 if (ninl.ni_namelist_len == 1) 2401 { 2402 propval = ni_name_dup(ninl.ni_namelist_val[0]); 2403 break; 2404 } 2405 } 2406 2407 /* 2408 ** Clean up. 2409 */ 2410 2411 if (ni != NULL) 2412 ni_free(ni); 2413 if (lastni != NULL && ni != lastni) 2414 ni_free(lastni); 2415 2416 return propval; 2417 } 2418 2419 #endif /* NETINFO */ 2420 /* 2421 ** HARD_SYSLOG -- call syslog repeatedly until it works 2422 ** 2423 ** Needed on HP-UX, which apparently doesn't guarantee that 2424 ** syslog succeeds during interrupt handlers. 2425 */ 2426 2427 #ifdef __hpux 2428 2429 # define MAXSYSLOGTRIES 100 2430 # undef syslog 2431 2432 # ifdef __STDC__ 2433 hard_syslog(int pri, char *msg, ...) 2434 # else 2435 hard_syslog(pri, msg, va_alist) 2436 int pri; 2437 char *msg; 2438 va_dcl 2439 # endif 2440 { 2441 int i; 2442 char buf[SYSLOG_BUFSIZE * 2]; 2443 VA_LOCAL_DECL; 2444 2445 VA_START(msg); 2446 vsprintf(buf, msg, ap); 2447 VA_END; 2448 2449 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, "%s", buf) < 0; ) 2450 continue; 2451 } 2452 2453 #endif 2454