1 /* 2 * Copyright (c) 1983, 1988, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)rlogind.c 5.47 (Berkeley) 06/27/90"; 26 #endif /* not lint */ 27 28 #ifdef KERBEROS 29 /* From: 30 * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 31 * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 32 */ 33 #endif 34 35 /* 36 * remote login server: 37 * \0 38 * remuser\0 39 * locuser\0 40 * terminal_type/speed\0 41 * data 42 */ 43 44 #define FD_SETSIZE 16 /* don't need many bits for select */ 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/socket.h> 48 #include <sys/wait.h> 49 #include <sys/file.h> 50 #include <sys/signal.h> 51 #include <sys/ioctl.h> 52 #include <sys/termios.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/ip.h> 57 58 #include <errno.h> 59 #include <pwd.h> 60 #include <netdb.h> 61 #include <syslog.h> 62 #include <string.h> 63 #include <stdio.h> 64 #include <unistd.h> 65 #include "pathnames.h" 66 67 #ifndef TIOCPKT_WINDOW 68 #define TIOCPKT_WINDOW 0x80 69 #endif 70 71 #ifdef KERBEROS 72 #include <kerberosIV/des.h> 73 #include <kerberosIV/krb.h> 74 #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 75 76 AUTH_DAT *kdata; 77 KTEXT ticket; 78 u_char auth_buf[sizeof(AUTH_DAT)]; 79 u_char tick_buf[sizeof(KTEXT_ST)]; 80 Key_schedule schedule; 81 int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 82 83 #define ARGSTR "alnkvx" 84 #else 85 #define ARGSTR "aln" 86 #endif /* KERBEROS */ 87 88 char *env[2]; 89 #define NMAX 30 90 char lusername[NMAX+1], rusername[NMAX+1]; 91 static char term[64] = "TERM="; 92 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 93 int keepalive = 1; 94 int check_all = 0; 95 96 extern int errno; 97 int reapchild(); 98 struct passwd *getpwnam(), *pwd; 99 char *malloc(); 100 101 main(argc, argv) 102 int argc; 103 char **argv; 104 { 105 extern int opterr, optind; 106 extern int _check_rhosts_file; 107 int ch; 108 int on = 1, fromlen; 109 struct sockaddr_in from; 110 111 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 112 113 opterr = 0; 114 while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 115 switch (ch) { 116 case 'a': 117 check_all = 1; 118 break; 119 case 'l': 120 _check_rhosts_file = 0; 121 break; 122 case 'n': 123 keepalive = 0; 124 break; 125 #ifdef KERBEROS 126 case 'k': 127 use_kerberos = 1; 128 break; 129 case 'v': 130 vacuous = 1; 131 break; 132 case 'x': 133 encrypt = 1; 134 break; 135 #endif 136 case '?': 137 default: 138 usage(); 139 break; 140 } 141 argc -= optind; 142 argv += optind; 143 144 #ifdef KERBEROS 145 if (use_kerberos && vacuous) { 146 usage(); 147 fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 148 } 149 #endif 150 fromlen = sizeof (from); 151 if (getpeername(0, &from, &fromlen) < 0) { 152 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 153 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 154 } 155 if (keepalive && 156 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 157 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 158 on = IPTOS_LOWDELAY; 159 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 160 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 161 doit(0, &from); 162 } 163 164 int child; 165 int cleanup(); 166 int netf; 167 char *line; 168 int confirmed; 169 extern char *inet_ntoa(); 170 171 struct winsize win = { 0, 0, 0, 0 }; 172 173 174 doit(f, fromp) 175 int f; 176 struct sockaddr_in *fromp; 177 { 178 int i, p, t, pid, on = 1; 179 int authenticated = 0, hostok = 0; 180 register struct hostent *hp; 181 char remotehost[2 * MAXHOSTNAMELEN + 1]; 182 struct hostent hostent; 183 char c; 184 185 alarm(60); 186 read(f, &c, 1); 187 188 if (c != 0) 189 exit(1); 190 #ifdef KERBEROS 191 if (vacuous) 192 fatal(f, "Remote host requires Kerberos authentication", 0); 193 #endif 194 195 alarm(0); 196 fromp->sin_port = ntohs((u_short)fromp->sin_port); 197 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 198 fromp->sin_family); 199 if (hp == 0) { 200 /* 201 * Only the name is used below. 202 */ 203 hp = &hostent; 204 hp->h_name = inet_ntoa(fromp->sin_addr); 205 hostok++; 206 } else if (check_all || local_domain(hp->h_name)) { 207 /* 208 * If name returned by gethostbyaddr is in our domain, 209 * attempt to verify that we haven't been fooled by someone 210 * in a remote net; look up the name and check that this 211 * address corresponds to the name. 212 */ 213 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 214 remotehost[sizeof(remotehost) - 1] = 0; 215 hp = gethostbyname(remotehost); 216 if (hp) 217 for (; hp->h_addr_list[0]; hp->h_addr_list++) 218 if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 219 sizeof(fromp->sin_addr))) { 220 hostok++; 221 break; 222 } 223 } else 224 hostok++; 225 226 #ifdef KERBEROS 227 if (use_kerberos) { 228 if (!hostok) 229 fatal(f, "rlogind: Host address mismatch.", 0); 230 retval = do_krb_login(hp->h_name, fromp, encrypt); 231 if (retval == 0) 232 authenticated++; 233 else if (retval > 0) 234 fatal(f, krb_err_txt[retval], 0); 235 write(f, &c, 1); 236 confirmed = 1; /* we sent the null! */ 237 } else 238 #endif 239 { 240 if (fromp->sin_family != AF_INET || 241 fromp->sin_port >= IPPORT_RESERVED || 242 fromp->sin_port < IPPORT_RESERVED/2) { 243 syslog(LOG_NOTICE, "Connection from %s on illegal port", 244 inet_ntoa(fromp->sin_addr)); 245 fatal(f, "Permission denied", 0); 246 } 247 #ifdef IP_OPTIONS 248 { 249 u_char optbuf[BUFSIZ/3], *cp; 250 char lbuf[BUFSIZ], *lp; 251 int optsize = sizeof(optbuf), ipproto; 252 struct protoent *ip; 253 254 if ((ip = getprotobyname("ip")) != NULL) 255 ipproto = ip->p_proto; 256 else 257 ipproto = IPPROTO_IP; 258 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 259 &optsize) == 0 && optsize != 0) { 260 lp = lbuf; 261 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 262 sprintf(lp, " %2.2x", *cp); 263 syslog(LOG_NOTICE, 264 "Connection received using IP options (ignored):%s", 265 lbuf); 266 if (setsockopt(0, ipproto, IP_OPTIONS, 267 (char *)NULL, &optsize) != 0) { 268 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 269 exit(1); 270 } 271 } 272 } 273 #endif 274 if (do_rlogin(hp->h_name) == 0 && hostok) 275 authenticated++; 276 } 277 278 for (c = 'p'; c <= 's'; c++) { 279 struct stat stb; 280 line = "/dev/ptyXX"; 281 line[strlen("/dev/pty")] = c; 282 line[strlen("/dev/ptyp")] = '0'; 283 if (stat(line, &stb) < 0) 284 break; 285 for (i = 0; i < 16; i++) { 286 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 287 p = open(line, O_RDWR); 288 if (p > 0) 289 goto gotpty; 290 } 291 } 292 fatal(f, "Out of ptys", 0); 293 /*NOTREACHED*/ 294 gotpty: 295 (void) ioctl(p, TIOCSWINSZ, &win); 296 netf = f; 297 line[sizeof(_PATH_DEV) - 1] = 't'; 298 t = open(line, O_RDWR); 299 if (t < 0) 300 fatal(f, line, 1); 301 if (fchmod(t, 0)) 302 fatal(f, line, 1); 303 (void)signal(SIGHUP, SIG_IGN); 304 #ifdef notdef 305 vhangup(); 306 #endif 307 (void)signal(SIGHUP, SIG_DFL); 308 t = open(line, O_RDWR); 309 if (t < 0) 310 fatal(f, line, 1); 311 setup_term(t); 312 if (confirmed == 0) { 313 write(f, "", 1); 314 confirmed = 1; /* we sent the null! */ 315 } 316 #ifdef KERBEROS 317 if (encrypt) 318 (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 319 320 if (use_kerberos == 0) 321 #endif 322 if (!authenticated && !hostok) 323 write(f, "rlogind: Host address mismatch.\r\n", 324 sizeof("rlogind: Host address mismatch.\r\n") - 1); 325 326 pid = fork(); 327 if (pid < 0) 328 fatal(f, "", 1); 329 if (pid == 0) { 330 if (setsid() < 0) 331 fatal(f, "setsid", 1); 332 if (ioctl(t, TIOCSCTTY, 0) < 0) 333 fatal(f, "ioctl(sctty)", 1); 334 (void)close(f); 335 (void)close(p); 336 dup2(t, STDIN_FILENO); 337 dup2(t, STDOUT_FILENO); 338 dup2(t, STDERR_FILENO); 339 (void)close(t); 340 341 if (authenticated) { 342 #ifdef KERBEROS 343 if (use_kerberos && (pwd->pw_uid == 0)) 344 syslog(LOG_INFO|LOG_AUTH, 345 "ROOT Kerberos login from %s.%s@%s on %s\n", 346 kdata->pname, kdata->pinst, kdata->prealm, 347 hp->h_name); 348 #endif 349 350 execl(_PATH_LOGIN, "login", "-p", 351 "-h", hp->h_name, "-f", lusername, 0); 352 } else 353 execl(_PATH_LOGIN, "login", "-p", 354 "-h", hp->h_name, lusername, 0); 355 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 356 /*NOTREACHED*/ 357 } 358 close(t); 359 360 #ifdef KERBEROS 361 /* 362 * If encrypted, don't turn on NBIO or the des read/write 363 * routines will croak. 364 */ 365 366 if (!encrypt) 367 #endif 368 ioctl(f, FIONBIO, &on); 369 ioctl(p, FIONBIO, &on); 370 ioctl(p, TIOCPKT, &on); 371 signal(SIGCHLD, cleanup); 372 protocol(f, p); 373 signal(SIGCHLD, SIG_IGN); 374 cleanup(); 375 } 376 377 char magic[2] = { 0377, 0377 }; 378 char oobdata[] = {TIOCPKT_WINDOW}; 379 380 /* 381 * Handle a "control" request (signaled by magic being present) 382 * in the data stream. For now, we are only willing to handle 383 * window size changes. 384 */ 385 control(pty, cp, n) 386 int pty; 387 char *cp; 388 int n; 389 { 390 struct winsize w; 391 392 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 393 return (0); 394 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 395 bcopy(cp+4, (char *)&w, sizeof(w)); 396 w.ws_row = ntohs(w.ws_row); 397 w.ws_col = ntohs(w.ws_col); 398 w.ws_xpixel = ntohs(w.ws_xpixel); 399 w.ws_ypixel = ntohs(w.ws_ypixel); 400 (void)ioctl(pty, TIOCSWINSZ, &w); 401 return (4+sizeof (w)); 402 } 403 404 /* 405 * rlogin "protocol" machine. 406 */ 407 protocol(f, p) 408 register int f, p; 409 { 410 char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 411 register pcc = 0, fcc = 0; 412 int cc, nfd, n; 413 char cntl; 414 415 /* 416 * Must ignore SIGTTOU, otherwise we'll stop 417 * when we try and set slave pty's window shape 418 * (our controlling tty is the master pty). 419 */ 420 (void) signal(SIGTTOU, SIG_IGN); 421 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 422 if (f > p) 423 nfd = f + 1; 424 else 425 nfd = p + 1; 426 if (nfd > FD_SETSIZE) { 427 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 428 fatal(f, "internal error (select mask too small)", 0); 429 } 430 for (;;) { 431 fd_set ibits, obits, ebits, *omask; 432 433 FD_ZERO(&ebits); 434 FD_ZERO(&ibits); 435 FD_ZERO(&obits); 436 omask = (fd_set *)NULL; 437 if (fcc) { 438 FD_SET(p, &obits); 439 omask = &obits; 440 } else 441 FD_SET(f, &ibits); 442 if (pcc >= 0) 443 if (pcc) { 444 FD_SET(f, &obits); 445 omask = &obits; 446 } else 447 FD_SET(p, &ibits); 448 FD_SET(p, &ebits); 449 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 450 if (errno == EINTR) 451 continue; 452 fatal(f, "select", 1); 453 } 454 if (n == 0) { 455 /* shouldn't happen... */ 456 sleep(5); 457 continue; 458 } 459 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 460 if (FD_ISSET(p, &ebits)) { 461 cc = read(p, &cntl, 1); 462 if (cc == 1 && pkcontrol(cntl)) { 463 cntl |= oobdata[0]; 464 send(f, &cntl, 1, MSG_OOB); 465 if (cntl & TIOCPKT_FLUSHWRITE) { 466 pcc = 0; 467 FD_CLR(p, &ibits); 468 } 469 } 470 } 471 if (FD_ISSET(f, &ibits)) { 472 #ifdef KERBEROS 473 if (encrypt) 474 fcc = des_read(f, fibuf, sizeof(fibuf)); 475 else 476 #endif 477 fcc = read(f, fibuf, sizeof(fibuf)); 478 if (fcc < 0 && errno == EWOULDBLOCK) 479 fcc = 0; 480 else { 481 register char *cp; 482 int left, n; 483 484 if (fcc <= 0) 485 break; 486 fbp = fibuf; 487 488 top: 489 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 490 if (cp[0] == magic[0] && 491 cp[1] == magic[1]) { 492 left = fcc - (cp-fibuf); 493 n = control(p, cp, left); 494 if (n) { 495 left -= n; 496 if (left > 0) 497 bcopy(cp+n, cp, left); 498 fcc -= n; 499 goto top; /* n^2 */ 500 } 501 } 502 FD_SET(p, &obits); /* try write */ 503 } 504 } 505 506 if (FD_ISSET(p, &obits) && fcc > 0) { 507 cc = write(p, fbp, fcc); 508 if (cc > 0) { 509 fcc -= cc; 510 fbp += cc; 511 } 512 } 513 514 if (FD_ISSET(p, &ibits)) { 515 pcc = read(p, pibuf, sizeof (pibuf)); 516 pbp = pibuf; 517 if (pcc < 0 && errno == EWOULDBLOCK) 518 pcc = 0; 519 else if (pcc <= 0) 520 break; 521 else if (pibuf[0] == 0) { 522 pbp++, pcc--; 523 #ifdef KERBEROS 524 if (!encrypt) 525 #endif 526 FD_SET(f, &obits); /* try write */ 527 } else { 528 if (pkcontrol(pibuf[0])) { 529 pibuf[0] |= oobdata[0]; 530 send(f, &pibuf[0], 1, MSG_OOB); 531 } 532 pcc = 0; 533 } 534 } 535 if ((FD_ISSET(f, &obits)) && pcc > 0) { 536 #ifdef KERBEROS 537 if (encrypt) 538 cc = des_write(f, pbp, pcc); 539 else 540 #endif 541 cc = write(f, pbp, pcc); 542 if (cc < 0 && errno == EWOULDBLOCK) { 543 /* 544 * This happens when we try write after read 545 * from p, but some old kernels balk at large 546 * writes even when select returns true. 547 */ 548 if (!FD_ISSET(p, &ibits)) 549 sleep(5); 550 continue; 551 } 552 if (cc > 0) { 553 pcc -= cc; 554 pbp += cc; 555 } 556 } 557 } 558 } 559 560 cleanup() 561 { 562 char *p; 563 564 p = line + sizeof(_PATH_DEV) - 1; 565 if (logout(p)) 566 logwtmp(p, "", ""); 567 (void)chmod(line, 0666); 568 (void)chown(line, 0, 0); 569 *p = 'p'; 570 (void)chmod(line, 0666); 571 (void)chown(line, 0, 0); 572 shutdown(netf, 2); 573 exit(1); 574 } 575 576 fatal(f, msg, syserr) 577 int f, syserr; 578 char *msg; 579 { 580 int len; 581 char buf[BUFSIZ], *bp = buf; 582 583 /* 584 * Prepend binary one to message if we haven't sent 585 * the magic null as confirmation. 586 */ 587 if (!confirmed) 588 *bp++ = '\01'; /* error indicator */ 589 if (syserr) 590 len = sprintf(bp, "rlogind: %s: %s.\r\n", 591 msg, strerror(errno)); 592 else 593 len = sprintf(bp, "rlogind: %s.\r\n", msg); 594 (void) write(f, buf, bp + len - buf); 595 exit(1); 596 } 597 598 do_rlogin(host) 599 char *host; 600 { 601 getstr(rusername, sizeof(rusername), "remuser too long"); 602 getstr(lusername, sizeof(lusername), "locuser too long"); 603 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 604 605 pwd = getpwnam(lusername); 606 if (pwd == NULL) 607 return(-1); 608 if (pwd->pw_uid == 0) 609 return(-1); 610 return(ruserok(host, 0, rusername, lusername)); 611 } 612 613 614 getstr(buf, cnt, errmsg) 615 char *buf; 616 int cnt; 617 char *errmsg; 618 { 619 char c; 620 621 do { 622 if (read(0, &c, 1) != 1) 623 exit(1); 624 if (--cnt < 0) 625 fatal(STDOUT_FILENO, errmsg, 0); 626 *buf++ = c; 627 } while (c != 0); 628 } 629 630 extern char **environ; 631 632 setup_term(fd) 633 int fd; 634 { 635 register char *cp = index(term+ENVSIZE, '/'); 636 char *speed; 637 struct termios tt; 638 639 #ifndef notyet 640 tcgetattr(fd, &tt); 641 if (cp) { 642 *cp++ = '\0'; 643 speed = cp; 644 cp = index(speed, '/'); 645 if (cp) 646 *cp++ = '\0'; 647 cfsetspeed(&tt, atoi(speed)); 648 } 649 650 tt.c_iflag = TTYDEF_IFLAG; 651 tt.c_oflag = TTYDEF_OFLAG; 652 tt.c_lflag = TTYDEF_LFLAG; 653 tcsetattr(fd, TCSAFLUSH, &tt); 654 #else 655 if (cp) { 656 *cp++ = '\0'; 657 speed = cp; 658 cp = index(speed, '/'); 659 if (cp) 660 *cp++ = '\0'; 661 tcgetattr(fd, &tt); 662 cfsetspeed(&tt, atoi(speed)); 663 tcsetattr(fd, TCSAFLUSH, &tt); 664 } 665 #endif 666 667 env[0] = term; 668 env[1] = 0; 669 environ = env; 670 } 671 672 #ifdef KERBEROS 673 #define VERSION_SIZE 9 674 675 /* 676 * Do the remote kerberos login to the named host with the 677 * given inet address 678 * 679 * Return 0 on valid authorization 680 * Return -1 on valid authentication, no authorization 681 * Return >0 for error conditions 682 */ 683 do_krb_login(host, dest, encrypt) 684 char *host; 685 struct sockaddr_in *dest; 686 int encrypt; 687 { 688 int rc; 689 char instance[INST_SZ], version[VERSION_SIZE]; 690 long authopts = 0L; /* !mutual */ 691 struct sockaddr_in faddr; 692 693 kdata = (AUTH_DAT *) auth_buf; 694 ticket = (KTEXT) tick_buf; 695 696 instance[0] = '*'; 697 instance[1] = '\0'; 698 699 if (encrypt) { 700 rc = sizeof(faddr); 701 if (getsockname(0, &faddr, &rc)) 702 return(-1); 703 authopts = KOPT_DO_MUTUAL; 704 rc = krb_recvauth( 705 authopts, 0, 706 ticket, "rcmd", 707 instance, dest, &faddr, 708 kdata, "", schedule, version); 709 des_set_key(kdata->session, schedule); 710 711 } else { 712 rc = krb_recvauth( 713 authopts, 0, 714 ticket, "rcmd", 715 instance, dest, (struct sockaddr_in *) 0, 716 kdata, "", (bit_64 *) 0, version); 717 } 718 719 if (rc != KSUCCESS) 720 return(rc); 721 722 getstr(lusername, sizeof(lusername), "locuser"); 723 /* get the "cmd" in the rcmd protocol */ 724 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 725 726 pwd = getpwnam(lusername); 727 if (pwd == NULL) 728 return(-1); 729 730 /* returns nonzero for no access */ 731 if (kuserok(kdata,lusername) != 0) 732 return(-1); 733 734 return(0); 735 736 } 737 #endif /* KERBEROS */ 738 739 usage() 740 { 741 #ifdef KERBEROS 742 syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 743 #else 744 syslog(LOG_ERR, "usage: rlogind [-aln]"); 745 #endif 746 } 747 748 /* 749 * Check whether host h is in our local domain, 750 * defined as sharing the last two components of the domain part, 751 * or the entire domain part if the local domain has only one component. 752 * If either name is unqualified (contains no '.'), 753 * assume that the host is local, as it will be 754 * interpreted as such. 755 */ 756 local_domain(h) 757 char *h; 758 { 759 char localhost[MAXHOSTNAMELEN]; 760 char *p1, *p2, *topdomain(); 761 762 localhost[0] = 0; 763 (void) gethostname(localhost, sizeof(localhost)); 764 p1 = topdomain(localhost); 765 p2 = topdomain(h); 766 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 767 return(1); 768 return(0); 769 } 770 771 char * 772 topdomain(h) 773 char *h; 774 { 775 register char *p; 776 char *maybe = NULL; 777 int dots = 0; 778 779 for (p = h + strlen(h); p >= h; p--) { 780 if (*p == '.') { 781 if (++dots == 2) 782 return (p); 783 maybe = p; 784 } 785 } 786 return (maybe); 787 } 788