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