1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)conf.c 6.12 (Berkeley) 01/28/93"; 11 #endif /* not lint */ 12 13 # include <sys/ioctl.h> 14 # include <pwd.h> 15 # include "sendmail.h" 16 # include "pathnames.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 /* destination fields */ 65 "to", H_RCPT, 66 "resent-to", H_RCPT|H_RESENT, 67 "cc", H_RCPT, 68 "resent-cc", H_RCPT|H_RESENT, 69 "bcc", H_RCPT|H_ACHECK, 70 "resent-bcc", H_RCPT|H_ACHECK|H_RESENT, 71 "apparently-to", H_RCPT, 72 /* message identification and control */ 73 "message-id", 0, 74 "resent-message-id", H_RESENT, 75 "message", H_EOH, 76 "text", H_EOH, 77 /* date fields */ 78 "date", 0, 79 "resent-date", H_RESENT, 80 /* trace fields */ 81 "received", H_TRACE|H_FORCE, 82 "via", H_TRACE|H_FORCE, 83 "mail-from", H_TRACE|H_FORCE, 84 85 NULL, 0, 86 }; 87 88 89 /* 90 ** ARPANET error message numbers. 91 */ 92 93 char Arpa_Info[] = "050"; /* arbitrary info */ 94 char Arpa_TSyserr[] = "451"; /* some (transient) system error */ 95 char Arpa_PSyserr[] = "554"; /* some (permanent) system error */ 96 char Arpa_Usrerr[] = "554"; /* some (fatal) user error */ 97 98 99 100 /* 101 ** Location of system files/databases/etc. 102 */ 103 104 char *ConfFile = _PATH_SENDMAILCF; /* runtime configuration */ 105 char *FreezeFile = _PATH_SENDMAILFC; /* frozen version of above */ 106 107 108 109 /* 110 ** Miscellaneous stuff. 111 */ 112 113 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 114 /* 115 ** SETDEFAULTS -- set default values 116 ** 117 ** Because of the way freezing is done, these must be initialized 118 ** using direct code. 119 ** 120 ** Parameters: 121 ** none. 122 ** 123 ** Returns: 124 ** none. 125 ** 126 ** Side Effects: 127 ** Initializes a bunch of global variables to their 128 ** default values. 129 */ 130 131 setdefaults() 132 { 133 SpaceSub = ' '; /* option B */ 134 QueueLA = 8; /* option x */ 135 RefuseLA = 12; /* option X */ 136 WkRecipFact = 30000L; /* option y */ 137 WkClassFact = 1800L; /* option z */ 138 WkTimeFact = 90000L; /* option Z */ 139 QueueFactor = WkRecipFact * 20; /* option q */ 140 FileMode = (getuid() != geteuid()) ? 0644 : 0600; 141 /* option F */ 142 DefUid = 1; /* option u */ 143 DefGid = 1; /* option g */ 144 CheckpointInterval = 10; /* option C */ 145 MaxHopCount = 25; /* option h */ 146 SendMode = SM_FORK; /* option d */ 147 ErrorMode = EM_PRINT; /* option e */ 148 EightBit = FALSE; /* option 8 */ 149 MaxMciCache = 1; /* option k */ 150 MciCacheTimeout = 300; /* option K */ 151 LogLevel = 9; /* option L */ 152 ReadTimeout = 2 * 60 * 60; /* option r */ 153 TimeOut = 3 * 24 * 60 * 60; /* option T */ 154 setdefuser(); 155 setupmaps(); 156 setupmailers(); 157 } 158 159 160 /* 161 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 162 */ 163 164 setdefuser() 165 { 166 struct passwd *defpwent; 167 static char defuserbuf[40]; 168 169 DefUser = defuserbuf; 170 if ((defpwent = getpwuid(DefUid)) != NULL) 171 strcpy(defuserbuf, defpwent->pw_name); 172 else 173 strcpy(defuserbuf, "nobody"); 174 } 175 /* 176 ** SETUPMAPS -- set up map classes 177 ** 178 ** Since these are compiled in, they cannot be in the config file. 179 ** 180 */ 181 182 setupmaps() 183 { 184 register STAB *s; 185 extern bool host_map_init(); 186 extern char *maphostname(); 187 188 /* set up host name lookup map */ 189 s = stab("host", ST_MAPCLASS, ST_ENTER); 190 s->s_mapclass.map_init = host_map_init; 191 s->s_mapclass.map_lookup = maphostname; 192 193 /* 194 ** Set up other map classes. 195 */ 196 197 # ifdef DBM_MAP 198 /* dbm file access */ 199 { 200 extern bool dbm_map_init(); 201 extern char *dbm_map_lookup(); 202 203 s = stab("dbm", ST_MAPCLASS, ST_ENTER); 204 s->s_mapclass.map_init = dbm_map_init; 205 s->s_mapclass.map_lookup = dbm_map_lookup; 206 } 207 # endif 208 209 # ifdef BTREE_MAP 210 /* new database file access -- btree files */ 211 { 212 extern bool bt_map_init(); 213 extern char *db_map_lookup(); 214 215 s = stab("btree", ST_MAPCLASS, ST_ENTER); 216 s->s_mapclass.map_init = bt_map_init; 217 s->s_mapclass.map_lookup = db_map_lookup; 218 } 219 # endif 220 221 # ifdef HASH_MAP 222 /* new database file access -- hash files */ 223 { 224 extern bool hash_map_init(); 225 extern char *db_map_lookup(); 226 227 s = stab("hash", ST_MAPCLASS, ST_ENTER); 228 s->s_mapclass.map_init = hash_map_init; 229 s->s_mapclass.map_lookup = db_map_lookup; 230 } 231 # endif 232 233 # ifdef NIS_MAP 234 /* NIS map access */ 235 { 236 extern bool nis_map_init(); 237 extern char *nis_map_lookup(); 238 239 s = stab("nis", ST_MAPCLASS, ST_ENTER); 240 s->s_mapclass.map_init = nis_map_init; 241 s->s_mapclass.map_lookup = nis_map_lookup; 242 } 243 # endif 244 245 # ifdef USERDB_MAP 246 /* user database */ 247 { 248 extern bool udb_map_init(); 249 extern char *udb_map_lookup(); 250 251 s = stab("udb", ST_MAPCLASS, ST_ENTER); 252 s->s_mapclass.map_init = udb_map_init; 253 s->s_mapclass.map_lookup = udb_map_lookup; 254 } 255 # endif 256 } 257 /* 258 ** HOST_MAP_INIT -- initialize host class structures 259 */ 260 261 bool 262 host_map_init(map, mapname, args) 263 MAP *map; 264 char *mapname; 265 char *args; 266 { 267 register char *p = args; 268 269 for (;;) 270 { 271 while (isspace(*p)) 272 p++; 273 if (*p != '-') 274 break; 275 switch (*++p) 276 { 277 case 'a': 278 map->map_app = ++p; 279 break; 280 } 281 while (*p != '\0' && !isspace(*p)) 282 p++; 283 if (*p != '\0') 284 *p++ = '\0'; 285 } 286 if (map->map_app != NULL) 287 map->map_app = newstr(map->map_app); 288 return TRUE; 289 } 290 /* 291 ** SETUPMAILERS -- initialize default mailers 292 */ 293 294 setupmailers() 295 { 296 char buf[100]; 297 298 strcpy(buf, "prog, P=/bin/sh, F=lsD, A=sh -c $u"); 299 makemailer(buf); 300 301 strcpy(buf, "*file*, P=/dev/null, F=lsDEu, A=FILE"); 302 makemailer(buf); 303 304 strcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE"); 305 makemailer(buf); 306 } 307 /* 308 ** GETRUID -- get real user id (V7) 309 */ 310 311 getruid() 312 { 313 if (OpMode == MD_DAEMON) 314 return (RealUid); 315 else 316 return (getuid()); 317 } 318 319 320 /* 321 ** GETRGID -- get real group id (V7). 322 */ 323 324 getrgid() 325 { 326 if (OpMode == MD_DAEMON) 327 return (RealGid); 328 else 329 return (getgid()); 330 } 331 /* 332 ** USERNAME -- return the user id of the logged in user. 333 ** 334 ** Parameters: 335 ** none. 336 ** 337 ** Returns: 338 ** The login name of the logged in user. 339 ** 340 ** Side Effects: 341 ** none. 342 ** 343 ** Notes: 344 ** The return value is statically allocated. 345 */ 346 347 char * 348 username() 349 { 350 static char *myname = NULL; 351 extern char *getlogin(); 352 register struct passwd *pw; 353 354 /* cache the result */ 355 if (myname == NULL) 356 { 357 myname = getlogin(); 358 if (myname == NULL || myname[0] == '\0') 359 { 360 361 pw = getpwuid(getruid()); 362 if (pw != NULL) 363 myname = newstr(pw->pw_name); 364 } 365 else 366 { 367 368 myname = newstr(myname); 369 if ((pw = getpwnam(myname)) == NULL || 370 getuid() != pw->pw_uid) 371 { 372 pw = getpwuid(getuid()); 373 if (pw != NULL) 374 myname = newstr(pw->pw_name); 375 } 376 } 377 if (myname == NULL || myname[0] == '\0') 378 { 379 syserr("Who are you?"); 380 myname = "postmaster"; 381 } 382 } 383 384 return (myname); 385 } 386 /* 387 ** TTYPATH -- Get the path of the user's tty 388 ** 389 ** Returns the pathname of the user's tty. Returns NULL if 390 ** the user is not logged in or if s/he has write permission 391 ** denied. 392 ** 393 ** Parameters: 394 ** none 395 ** 396 ** Returns: 397 ** pathname of the user's tty. 398 ** NULL if not logged in or write permission denied. 399 ** 400 ** Side Effects: 401 ** none. 402 ** 403 ** WARNING: 404 ** Return value is in a local buffer. 405 ** 406 ** Called By: 407 ** savemail 408 */ 409 410 # include <sys/stat.h> 411 412 char * 413 ttypath() 414 { 415 struct stat stbuf; 416 register char *pathn; 417 extern char *ttyname(); 418 extern char *getlogin(); 419 420 /* compute the pathname of the controlling tty */ 421 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 422 (pathn = ttyname(0)) == NULL) 423 { 424 errno = 0; 425 return (NULL); 426 } 427 428 /* see if we have write permission */ 429 if (stat(pathn, &stbuf) < 0 || !bitset(02, stbuf.st_mode)) 430 { 431 errno = 0; 432 return (NULL); 433 } 434 435 /* see if the user is logged in */ 436 if (getlogin() == NULL) 437 return (NULL); 438 439 /* looks good */ 440 return (pathn); 441 } 442 /* 443 ** CHECKCOMPAT -- check for From and To person compatible. 444 ** 445 ** This routine can be supplied on a per-installation basis 446 ** to determine whether a person is allowed to send a message. 447 ** This allows restriction of certain types of internet 448 ** forwarding or registration of users. 449 ** 450 ** If the hosts are found to be incompatible, an error 451 ** message should be given using "usrerr" and 0 should 452 ** be returned. 453 ** 454 ** 'NoReturn' can be set to suppress the return-to-sender 455 ** function; this should be done on huge messages. 456 ** 457 ** Parameters: 458 ** to -- the person being sent to. 459 ** 460 ** Returns: 461 ** an exit status 462 ** 463 ** Side Effects: 464 ** none (unless you include the usrerr stuff) 465 */ 466 467 checkcompat(to, e) 468 register ADDRESS *to; 469 register ENVELOPE *e; 470 { 471 # ifdef lint 472 if (to == NULL) 473 to++; 474 # endif lint 475 # ifdef EXAMPLE_CODE 476 /* this code is intended as an example only */ 477 register STAB *s; 478 479 s = stab("arpa", ST_MAILER, ST_FIND); 480 if (s != NULL && e->e_from.q_mailer != LocalMailer && 481 to->q_mailer == s->s_mailer) 482 { 483 usrerr("No ARPA mail through this machine: see your system administration"); 484 /* NoReturn = TRUE; to supress return copy */ 485 return (EX_UNAVAILABLE); 486 } 487 # endif /* EXAMPLE_CODE */ 488 return (EX_OK); 489 } 490 /* 491 ** HOLDSIGS -- arrange to hold all signals 492 ** 493 ** Parameters: 494 ** none. 495 ** 496 ** Returns: 497 ** none. 498 ** 499 ** Side Effects: 500 ** Arranges that signals are held. 501 */ 502 503 holdsigs() 504 { 505 } 506 /* 507 ** RLSESIGS -- arrange to release all signals 508 ** 509 ** This undoes the effect of holdsigs. 510 ** 511 ** Parameters: 512 ** none. 513 ** 514 ** Returns: 515 ** none. 516 ** 517 ** Side Effects: 518 ** Arranges that signals are released. 519 */ 520 521 rlsesigs() 522 { 523 } 524 /* 525 ** GETLA -- get the current load average 526 ** 527 ** This code stolen from la.c. 528 ** 529 ** Parameters: 530 ** none. 531 ** 532 ** Returns: 533 ** The current load average as an integer. 534 ** 535 ** Side Effects: 536 ** none. 537 */ 538 539 /* try to guess what style of load average we have */ 540 #define LA_ZERO 1 /* always return load average as zero */ 541 #define LA_INT 2 /* read kmem for avenrun; interpret as int */ 542 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 543 #define LA_SUBR 4 /* call getloadavg */ 544 545 #ifndef LA_TYPE 546 # if defined(sun) 547 # define LA_TYPE LA_INT 548 # endif 549 # if defined(mips) 550 /* Ultrix or RISC/os */ 551 # define LA_TYPE LA_INT 552 # define LA_AVENRUN "avenrun" 553 # endif 554 # if defined(hpux) 555 # define LA_TYPE LA_FLOAT 556 # endif 557 558 # ifndef LA_TYPE 559 # if defined(SYSTEM5) 560 # define LA_TYPE LA_INT 561 # define LA_AVENRUN "avenrun" 562 # else 563 # if defined(BSD) 564 # define LA_TYPE LA_SUBR 565 # else 566 # define LA_TYPE LA_ZERO 567 # endif 568 # endif 569 # endif 570 #endif 571 572 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) 573 574 #include <nlist.h> 575 #include <fcntl.h> 576 577 #ifndef LA_AVENRUN 578 #define LA_AVENRUN "_avenrun" 579 #endif 580 581 /* _PATH_UNIX should be defined in <paths.h> */ 582 #ifndef _PATH_UNIX 583 # if defined(hpux) 584 # define _PATH_UNIX "/hp-ux" 585 # endif 586 # if defined(mips) && !defined(ultrix) 587 /* powerful RISC/os */ 588 # define _PATH_UNIX "/unix" 589 # endif 590 # if defined(SYSTEM5) 591 # define _PATH_UNIX "/unix" 592 # endif 593 # ifndef _PATH_UNIX 594 # define _PATH_UNIX "/vmunix" 595 # endif 596 #endif 597 598 struct nlist Nl[] = 599 { 600 { LA_AVENRUN }, 601 #define X_AVENRUN 0 602 { 0 }, 603 }; 604 605 #if defined(unixpc) 606 # define FSHIFT 5 607 #endif 608 609 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 610 # define FSHIFT 8 611 #endif 612 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 613 # define FSCALE (1 << FSHIFT) 614 #endif 615 616 getla() 617 { 618 static int kmem = -1; 619 #if LA_TYPE == LA_INT 620 long avenrun[3]; 621 #else 622 double avenrun[3]; 623 #endif 624 extern off_t lseek(); 625 extern char *errstring(); 626 extern int errno; 627 628 if (kmem < 0) 629 { 630 kmem = open("/dev/kmem", 0, 0); 631 if (kmem < 0) 632 { 633 if (tTd(3, 1)) 634 printf("getla: open(/dev/kmem): %s\n", 635 errstring(errno)); 636 return (-1); 637 } 638 (void) fcntl(kmem, F_SETFD, 1); 639 if (nlist(_PATH_UNIX, Nl) < 0) 640 { 641 if (tTd(3, 1)) 642 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 643 errstring(errno)); 644 return (-1); 645 } 646 } 647 if (tTd(3, 20)) 648 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 649 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 650 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 651 { 652 /* thank you Ian */ 653 if (tTd(3, 1)) 654 printf("getla: lseek or read: %s\n", errstring(errno)); 655 return (-1); 656 } 657 #if LA_TYPE == LA_INT 658 if (tTd(3, 5)) 659 { 660 printf("getla: avenrun = %d", avenrun[0]); 661 if (tTd(3, 15)) 662 printf(", %d, %d", avenrun[1], avenrun[2]); 663 printf("\n"); 664 } 665 if (tTd(3, 1)) 666 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 667 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 668 #else 669 if (tTd(3, 5)) 670 { 671 printf("getla: avenrun = %g", avenrun[0]); 672 if (tTd(3, 15)) 673 printf(", %g, %g", avenrun[1], avenrun[2]); 674 printf("\n"); 675 } 676 if (tTd(3, 1)) 677 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 678 return ((int) (avenrun[0] + 0.5)); 679 #endif 680 } 681 682 #else 683 #if LA_TYPE == LA_SUBR 684 685 getla() 686 { 687 double avenrun[3]; 688 689 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 690 { 691 if (tTd(3, 1)) 692 perror("getla: getloadavg failed:"); 693 return (-1); 694 } 695 if (tTd(3, 1)) 696 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 697 return ((int) (avenrun[0] + 0.5)); 698 } 699 700 #else 701 702 getla() 703 { 704 if (tTd(3, 1)) 705 printf("getla: ZERO\n"); 706 return (0); 707 } 708 709 #endif 710 #endif 711 /* 712 ** SHOULDQUEUE -- should this message be queued or sent? 713 ** 714 ** Compares the message cost to the load average to decide. 715 ** 716 ** Parameters: 717 ** pri -- the priority of the message in question. 718 ** ctime -- the message creation time. 719 ** 720 ** Returns: 721 ** TRUE -- if this message should be queued up for the 722 ** time being. 723 ** FALSE -- if the load is low enough to send this message. 724 ** 725 ** Side Effects: 726 ** none. 727 */ 728 729 bool 730 shouldqueue(pri, ctime) 731 long pri; 732 time_t ctime; 733 { 734 if (CurrentLA < QueueLA) 735 return (FALSE); 736 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 737 } 738 /* 739 ** REFUSECONNECTIONS -- decide if connections should be refused 740 ** 741 ** Parameters: 742 ** none. 743 ** 744 ** Returns: 745 ** TRUE if incoming SMTP connections should be refused 746 ** (for now). 747 ** FALSE if we should accept new work. 748 ** 749 ** Side Effects: 750 ** none. 751 */ 752 753 bool 754 refuseconnections() 755 { 756 /* this is probably too simplistic */ 757 return (CurrentLA > RefuseLA); 758 } 759 /* 760 ** SETPROCTITLE -- set process title for ps 761 ** 762 ** Parameters: 763 ** fmt -- a printf style format string. 764 ** a, b, c -- possible parameters to fmt. 765 ** 766 ** Returns: 767 ** none. 768 ** 769 ** Side Effects: 770 ** Clobbers argv of our main procedure so ps(1) will 771 ** display the title. 772 */ 773 774 /*VARARGS1*/ 775 #ifdef __STDC__ 776 setproctitle(char *fmt, ...) 777 #else 778 setproctitle(fmt, va_alist) 779 char *fmt; 780 va_dcl 781 #endif 782 { 783 # ifdef SETPROCTITLE 784 register char *p; 785 register int i; 786 char buf[MAXLINE]; 787 VA_LOCAL_DECL 788 extern char **Argv; 789 extern char *LastArgv; 790 791 p = buf; 792 793 /* print sendmail: heading for grep */ 794 (void) strcpy(p, "sendmail: "); 795 p += strlen(p); 796 797 /* print the argument string */ 798 VA_START(fmt); 799 (void) vsprintf(p, fmt, ap); 800 VA_END; 801 802 i = strlen(buf); 803 if (i > LastArgv - Argv[0] - 2) 804 { 805 i = LastArgv - Argv[0] - 2; 806 buf[i] = '\0'; 807 } 808 (void) strcpy(Argv[0], buf); 809 p = &Argv[0][i]; 810 while (p < LastArgv) 811 *p++ = ' '; 812 # endif /* SETPROCTITLE */ 813 } 814 /* 815 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 816 ** 817 ** Parameters: 818 ** none. 819 ** 820 ** Returns: 821 ** none. 822 ** 823 ** Side Effects: 824 ** Picks up extant zombies. 825 */ 826 827 # include <sys/wait.h> 828 829 void 830 reapchild() 831 { 832 # ifdef WNOHANG 833 union wait status; 834 835 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 836 continue; 837 # else /* WNOHANG */ 838 auto int status; 839 840 while (wait((int *)&status) > 0) 841 continue; 842 # endif /* WNOHANG */ 843 } 844 /* 845 ** UNSETENV -- remove a variable from the environment 846 ** 847 ** Not needed on newer systems. 848 ** 849 ** Parameters: 850 ** name -- the string name of the environment variable to be 851 ** deleted from the current environment. 852 ** 853 ** Returns: 854 ** none. 855 ** 856 ** Globals: 857 ** environ -- a pointer to the current environment. 858 ** 859 ** Side Effects: 860 ** Modifies environ. 861 */ 862 863 #ifdef UNSETENV 864 865 void 866 unsetenv(name) 867 char *name; 868 { 869 extern char **environ; 870 register char **pp; 871 int len = strlen(name); 872 873 for (pp = environ; *pp != NULL; pp++) 874 { 875 if (strncmp(name, *pp, len) == 0 && 876 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 877 break; 878 } 879 880 for (; *pp != NULL; pp++) 881 *pp = pp[1]; 882 } 883 884 #endif /* UNSETENV */ 885 /* 886 ** GETDTABLESIZE -- return number of file descriptors 887 ** 888 ** Only on non-BSD systems 889 ** 890 ** Parameters: 891 ** none 892 ** 893 ** Returns: 894 ** size of file descriptor table 895 ** 896 ** Side Effects: 897 ** none 898 */ 899 900 #ifdef SYSTEM5 901 902 int 903 getdtablesize() 904 { 905 return NOFILE; 906 } 907 908 #endif 909 /* 910 ** UNAME -- get the UUCP name of this system. 911 */ 912 913 #ifndef UNAME 914 915 int 916 uname(name) 917 struct utsname *name; 918 { 919 FILE *file; 920 char *n; 921 922 name->nodename[0] = '\0'; 923 924 /* try /etc/whoami -- one line with the node name */ 925 if ((file = fopen("/etc/whoami", "r")) != NULL) 926 { 927 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 928 (void) fclose(file); 929 n = strchr(name->nodename, '\n'); 930 if (n != NULL) 931 *n = '\0'; 932 if (name->nodename[0] != '\0') 933 return (0); 934 } 935 936 /* try /usr/include/whoami.h -- has a #define somewhere */ 937 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 938 { 939 char buf[MAXLINE]; 940 941 while (fgets(buf, MAXLINE, file) != NULL) 942 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 943 NODE_LENGTH, name->nodename) > 0) 944 break; 945 (void) fclose(file); 946 if (name->nodename[0] != '\0') 947 return (0); 948 } 949 950 #ifdef TRUST_POPEN 951 /* 952 ** Popen is known to have security holes. 953 */ 954 955 /* try uuname -l to return local name */ 956 if ((file = popen("uuname -l", "r")) != NULL) 957 { 958 (void) fgets(name, NODE_LENGTH + 1, file); 959 (void) pclose(file); 960 n = strchr(name, '\n'); 961 if (n != NULL) 962 *n = '\0'; 963 if (name->nodename[0] != '\0') 964 return (0); 965 } 966 #endif 967 968 return (-1); 969 } 970 #endif /* UNAME */ 971