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.15 (Berkeley) 02/18/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[] = "501"; /* 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 (isascii(*p) && 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' && !(isascii(*p) && 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) || defined(__alpha) 550 /* Ultrix or OSF/1 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 # ifndef _PATH_UNIX 592 # define _PATH_UNIX "/unix" 593 # endif 594 # endif 595 # ifndef _PATH_UNIX 596 # define _PATH_UNIX "/vmunix" 597 # endif 598 #endif 599 600 struct nlist Nl[] = 601 { 602 { LA_AVENRUN }, 603 #define X_AVENRUN 0 604 { 0 }, 605 }; 606 607 #if defined(unixpc) 608 # define FSHIFT 5 609 #endif 610 611 #if defined(__alpha) 612 # define FSHIFT 10 613 #endif 614 615 #if (LA_TYPE == LA_INT) && !defined(FSHIFT) 616 # define FSHIFT 8 617 #endif 618 #if (LA_TYPE == LA_INT) && !defined(FSCALE) 619 # define FSCALE (1 << FSHIFT) 620 #endif 621 622 getla() 623 { 624 static int kmem = -1; 625 #if LA_TYPE == LA_INT 626 long avenrun[3]; 627 #else 628 double avenrun[3]; 629 #endif 630 extern off_t lseek(); 631 extern char *errstring(); 632 extern int errno; 633 634 if (kmem < 0) 635 { 636 kmem = open("/dev/kmem", 0, 0); 637 if (kmem < 0) 638 { 639 if (tTd(3, 1)) 640 printf("getla: open(/dev/kmem): %s\n", 641 errstring(errno)); 642 return (-1); 643 } 644 (void) fcntl(kmem, F_SETFD, 1); 645 if (nlist(_PATH_UNIX, Nl) < 0) 646 { 647 if (tTd(3, 1)) 648 printf("getla: nlist(%s): %s\n", _PATH_UNIX, 649 errstring(errno)); 650 return (-1); 651 } 652 } 653 if (tTd(3, 20)) 654 printf("getla: symbol address = %#x\n", Nl[X_AVENRUN].n_value); 655 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 || 656 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 657 { 658 /* thank you Ian */ 659 if (tTd(3, 1)) 660 printf("getla: lseek or read: %s\n", errstring(errno)); 661 return (-1); 662 } 663 #if LA_TYPE == LA_INT 664 if (tTd(3, 5)) 665 { 666 printf("getla: avenrun = %d", avenrun[0]); 667 if (tTd(3, 15)) 668 printf(", %d, %d", avenrun[1], avenrun[2]); 669 printf("\n"); 670 } 671 if (tTd(3, 1)) 672 printf("getla: %d\n", (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 673 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 674 #else 675 if (tTd(3, 5)) 676 { 677 printf("getla: avenrun = %g", avenrun[0]); 678 if (tTd(3, 15)) 679 printf(", %g, %g", avenrun[1], avenrun[2]); 680 printf("\n"); 681 } 682 if (tTd(3, 1)) 683 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 684 return ((int) (avenrun[0] + 0.5)); 685 #endif 686 } 687 688 #else 689 #if LA_TYPE == LA_SUBR 690 691 getla() 692 { 693 double avenrun[3]; 694 695 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 696 { 697 if (tTd(3, 1)) 698 perror("getla: getloadavg failed:"); 699 return (-1); 700 } 701 if (tTd(3, 1)) 702 printf("getla: %d\n", (int) (avenrun[0] +0.5)); 703 return ((int) (avenrun[0] + 0.5)); 704 } 705 706 #else 707 708 getla() 709 { 710 if (tTd(3, 1)) 711 printf("getla: ZERO\n"); 712 return (0); 713 } 714 715 #endif 716 #endif 717 /* 718 ** SHOULDQUEUE -- should this message be queued or sent? 719 ** 720 ** Compares the message cost to the load average to decide. 721 ** 722 ** Parameters: 723 ** pri -- the priority of the message in question. 724 ** ctime -- the message creation time. 725 ** 726 ** Returns: 727 ** TRUE -- if this message should be queued up for the 728 ** time being. 729 ** FALSE -- if the load is low enough to send this message. 730 ** 731 ** Side Effects: 732 ** none. 733 */ 734 735 bool 736 shouldqueue(pri, ctime) 737 long pri; 738 time_t ctime; 739 { 740 if (CurrentLA < QueueLA) 741 return (FALSE); 742 return (pri > (QueueFactor / (CurrentLA - QueueLA + 1))); 743 } 744 /* 745 ** REFUSECONNECTIONS -- decide if connections should be refused 746 ** 747 ** Parameters: 748 ** none. 749 ** 750 ** Returns: 751 ** TRUE if incoming SMTP connections should be refused 752 ** (for now). 753 ** FALSE if we should accept new work. 754 ** 755 ** Side Effects: 756 ** none. 757 */ 758 759 bool 760 refuseconnections() 761 { 762 /* this is probably too simplistic */ 763 return (CurrentLA > RefuseLA); 764 } 765 /* 766 ** SETPROCTITLE -- set process title for ps 767 ** 768 ** Parameters: 769 ** fmt -- a printf style format string. 770 ** a, b, c -- possible parameters to fmt. 771 ** 772 ** Returns: 773 ** none. 774 ** 775 ** Side Effects: 776 ** Clobbers argv of our main procedure so ps(1) will 777 ** display the title. 778 */ 779 780 /*VARARGS1*/ 781 #ifdef __STDC__ 782 setproctitle(char *fmt, ...) 783 #else 784 setproctitle(fmt, va_alist) 785 char *fmt; 786 va_dcl 787 #endif 788 { 789 # ifdef SETPROCTITLE 790 register char *p; 791 register int i; 792 char buf[MAXLINE]; 793 VA_LOCAL_DECL 794 extern char **Argv; 795 extern char *LastArgv; 796 797 p = buf; 798 799 /* print sendmail: heading for grep */ 800 (void) strcpy(p, "sendmail: "); 801 p += strlen(p); 802 803 /* print the argument string */ 804 VA_START(fmt); 805 (void) vsprintf(p, fmt, ap); 806 VA_END; 807 808 i = strlen(buf); 809 if (i > LastArgv - Argv[0] - 2) 810 { 811 i = LastArgv - Argv[0] - 2; 812 buf[i] = '\0'; 813 } 814 (void) strcpy(Argv[0], buf); 815 p = &Argv[0][i]; 816 while (p < LastArgv) 817 *p++ = ' '; 818 # endif /* SETPROCTITLE */ 819 } 820 /* 821 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 822 ** 823 ** Parameters: 824 ** none. 825 ** 826 ** Returns: 827 ** none. 828 ** 829 ** Side Effects: 830 ** Picks up extant zombies. 831 */ 832 833 # include <sys/wait.h> 834 835 void 836 reapchild() 837 { 838 # ifdef WNOHANG 839 union wait status; 840 841 while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) 842 continue; 843 # else /* WNOHANG */ 844 auto int status; 845 846 while (wait((int *)&status) > 0) 847 continue; 848 # endif /* WNOHANG */ 849 } 850 /* 851 ** UNSETENV -- remove a variable from the environment 852 ** 853 ** Not needed on newer systems. 854 ** 855 ** Parameters: 856 ** name -- the string name of the environment variable to be 857 ** deleted from the current environment. 858 ** 859 ** Returns: 860 ** none. 861 ** 862 ** Globals: 863 ** environ -- a pointer to the current environment. 864 ** 865 ** Side Effects: 866 ** Modifies environ. 867 */ 868 869 #ifdef UNSETENV 870 871 void 872 unsetenv(name) 873 char *name; 874 { 875 extern char **environ; 876 register char **pp; 877 int len = strlen(name); 878 879 for (pp = environ; *pp != NULL; pp++) 880 { 881 if (strncmp(name, *pp, len) == 0 && 882 ((*pp)[len] == '=' || (*pp)[len] == '\0')) 883 break; 884 } 885 886 for (; *pp != NULL; pp++) 887 *pp = pp[1]; 888 } 889 890 #endif /* UNSETENV */ 891 /* 892 ** GETDTABLESIZE -- return number of file descriptors 893 ** 894 ** Only on non-BSD systems 895 ** 896 ** Parameters: 897 ** none 898 ** 899 ** Returns: 900 ** size of file descriptor table 901 ** 902 ** Side Effects: 903 ** none 904 */ 905 906 #ifdef SYSTEM5 907 908 int 909 getdtablesize() 910 { 911 return NOFILE; 912 } 913 914 #endif 915 /* 916 ** UNAME -- get the UUCP name of this system. 917 */ 918 919 #ifndef HASUNAME 920 921 int 922 uname(name) 923 struct utsname *name; 924 { 925 FILE *file; 926 char *n; 927 928 name->nodename[0] = '\0'; 929 930 /* try /etc/whoami -- one line with the node name */ 931 if ((file = fopen("/etc/whoami", "r")) != NULL) 932 { 933 (void) fgets(name->nodename, NODE_LENGTH + 1, file); 934 (void) fclose(file); 935 n = strchr(name->nodename, '\n'); 936 if (n != NULL) 937 *n = '\0'; 938 if (name->nodename[0] != '\0') 939 return (0); 940 } 941 942 /* try /usr/include/whoami.h -- has a #define somewhere */ 943 if ((file = fopen("/usr/include/whoami.h", "r")) != NULL) 944 { 945 char buf[MAXLINE]; 946 947 while (fgets(buf, MAXLINE, file) != NULL) 948 if (sscanf(buf, "#define sysname \"%*[^\"]\"", 949 NODE_LENGTH, name->nodename) > 0) 950 break; 951 (void) fclose(file); 952 if (name->nodename[0] != '\0') 953 return (0); 954 } 955 956 #ifdef TRUST_POPEN 957 /* 958 ** Popen is known to have security holes. 959 */ 960 961 /* try uuname -l to return local name */ 962 if ((file = popen("uuname -l", "r")) != NULL) 963 { 964 (void) fgets(name, NODE_LENGTH + 1, file); 965 (void) pclose(file); 966 n = strchr(name, '\n'); 967 if (n != NULL) 968 *n = '\0'; 969 if (name->nodename[0] != '\0') 970 return (0); 971 } 972 #endif 973 974 return (-1); 975 } 976 #endif /* HASUNAME */ 977