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