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