1 /* $NetBSD: rshd.c,v 1.31 2003/06/14 22:43:31 joff Exp $ */ 2 3 /* 4 * Copyright (C) 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by WIDE Project and 18 * its contributors. 19 * 4. Neither the name of the project nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /*- 37 * Copyright (c) 1988, 1989, 1992, 1993, 1994 38 * The Regents of the University of California. All rights reserved. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Berkeley and its contributors. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69 #include <sys/cdefs.h> 70 #ifndef lint 71 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\ 72 The Regents of the University of California. All rights reserved.\n"); 73 #if 0 74 static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; 75 #else 76 __RCSID("$NetBSD: rshd.c,v 1.31 2003/06/14 22:43:31 joff Exp $"); 77 #endif 78 #endif /* not lint */ 79 80 /* 81 * remote shell server: 82 * [port]\0 83 * remuser\0 84 * locuser\0 85 * command\0 86 * data 87 */ 88 #include <sys/param.h> 89 #include <sys/ioctl.h> 90 #include <sys/time.h> 91 #include <sys/socket.h> 92 93 #include <netinet/in.h> 94 #include <netinet/tcp.h> 95 #include <arpa/inet.h> 96 #include <netdb.h> 97 98 #include <errno.h> 99 #include <fcntl.h> 100 #include <paths.h> 101 #include <pwd.h> 102 #include <signal.h> 103 #include <stdio.h> 104 #include <stdlib.h> 105 #include <string.h> 106 #include <syslog.h> 107 #include <unistd.h> 108 #include <poll.h> 109 #ifdef LOGIN_CAP 110 #include <login_cap.h> 111 #endif 112 113 int keepalive = 1; 114 int check_all; 115 int log_success; /* If TRUE, log all successful accesses */ 116 int sent_null; 117 118 void doit __P((struct sockaddr *)); 119 void error __P((const char *, ...)) 120 __attribute__((__format__(__printf__, 1, 2))); 121 void getstr __P((char *, int, char *)); 122 int local_domain __P((char *)); 123 char *topdomain __P((char *)); 124 void usage __P((void)); 125 int main __P((int, char *[])); 126 127 #define OPTIONS "alnL" 128 extern int __check_rhosts_file; 129 extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ 130 131 int 132 main(int argc, char *argv[]) 133 { 134 struct linger linger; 135 int ch, on = 1, fromlen; 136 struct sockaddr_storage from; 137 struct protoent *proto; 138 139 openlog("rshd", LOG_PID, LOG_DAEMON); 140 141 opterr = 0; 142 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 143 switch (ch) { 144 case 'a': 145 check_all = 1; 146 break; 147 case 'l': 148 __check_rhosts_file = 0; 149 break; 150 case 'n': 151 keepalive = 0; 152 break; 153 case 'L': 154 log_success = 1; 155 break; 156 case '?': 157 default: 158 usage(); 159 break; 160 } 161 162 argc -= optind; 163 argv += optind; 164 165 fromlen = sizeof (from); /* xxx */ 166 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 167 syslog(LOG_ERR, "getpeername: %m"); 168 exit(1); 169 } 170 #if 0 171 if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 172 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) && 173 sizeof(struct sockaddr_in) <= sizeof(from)) { 174 struct sockaddr_in sin; 175 struct sockaddr_in6 *sin6; 176 const int off = sizeof(struct sockaddr_in6) - 177 sizeof(struct sockaddr_in); 178 179 sin6 = (struct sockaddr_in6 *)&from; 180 memset(&sin, 0, sizeof(sin)); 181 sin.sin_family = AF_INET; 182 sin.sin_len = sizeof(struct sockaddr_in); 183 memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off], 184 sizeof(sin.sin_addr)); 185 memcpy(&from, &sin, sizeof(sin)); 186 fromlen = sin.sin_len; 187 } 188 #else 189 if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 190 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) { 191 char hbuf[NI_MAXHOST]; 192 if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf, 193 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 194 strlcpy(hbuf, "invalid", sizeof(hbuf)); 195 } 196 syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)", 197 hbuf); 198 exit(1); 199 } 200 #endif 201 if (keepalive && 202 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 203 sizeof(on)) < 0) 204 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 205 linger.l_onoff = 1; 206 linger.l_linger = 60; /* XXX */ 207 if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 208 sizeof (linger)) < 0) 209 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 210 proto = getprotobyname("tcp"); 211 setsockopt(0, proto->p_proto, TCP_NODELAY, &on, sizeof(on)); 212 doit((struct sockaddr *)&from); 213 /* NOTREACHED */ 214 #ifdef __GNUC__ 215 exit(0); 216 #endif 217 } 218 219 char username[20] = "USER="; 220 char homedir[64] = "HOME="; 221 char shell[64] = "SHELL="; 222 char path[100] = "PATH="; 223 char *envinit[] = 224 {homedir, shell, path, username, 0}; 225 char **environ; 226 227 void 228 doit(struct sockaddr *fromp) 229 { 230 struct passwd *pwd; 231 in_port_t port; 232 struct pollfd set[2]; 233 int cc, pv[2], pid, s = -1; /* XXX gcc */ 234 int one = 1; 235 char *hostname, *errorstr, *errorhost = NULL; /* XXX gcc */ 236 const char *cp; 237 char sig, buf[BUFSIZ]; 238 char cmdbuf[NCARGS+1], locuser[16], remuser[16]; 239 char remotehost[2 * MAXHOSTNAMELEN + 1]; 240 char hostnamebuf[2 * MAXHOSTNAMELEN + 1]; 241 #ifdef LOGIN_CAP 242 login_cap_t *lc; 243 #endif 244 char naddr[NI_MAXHOST]; 245 char saddr[NI_MAXHOST]; 246 char raddr[NI_MAXHOST]; 247 char pbuf[NI_MAXSERV]; 248 int af = fromp->sa_family; 249 u_int16_t *portp; 250 struct addrinfo hints, *res, *res0; 251 int gaierror; 252 #ifdef NI_WITHSCOPEID 253 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID; 254 #else 255 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 256 #endif 257 258 (void) signal(SIGINT, SIG_DFL); 259 (void) signal(SIGQUIT, SIG_DFL); 260 (void) signal(SIGTERM, SIG_DFL); 261 #ifdef DEBUG 262 { int t = open(_PATH_TTY, 2); 263 if (t >= 0) { 264 ioctl(t, TIOCNOTTY, (char *)0); 265 (void) close(t); 266 } 267 } 268 #endif 269 switch (af) { 270 case AF_INET: 271 portp = &((struct sockaddr_in *)fromp)->sin_port; 272 break; 273 #ifdef INET6 274 case AF_INET6: 275 portp = &((struct sockaddr_in6 *)fromp)->sin6_port; 276 break; 277 #endif 278 default: 279 syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 280 exit(1); 281 } 282 if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr), 283 pbuf, sizeof(pbuf), niflags) != 0) { 284 syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 285 exit(1); 286 } 287 #ifdef IP_OPTIONS 288 if (af == AF_INET) 289 { 290 u_char optbuf[BUFSIZ/3], *cp; 291 char lbuf[BUFSIZ], *lp, *ep; 292 int optsize = sizeof(optbuf), ipproto; 293 struct protoent *ip; 294 295 if ((ip = getprotobyname("ip")) != NULL) 296 ipproto = ip->p_proto; 297 else 298 ipproto = IPPROTO_IP; 299 if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && 300 optsize != 0) { 301 lp = lbuf; 302 ep = lbuf + sizeof(lbuf); 303 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 304 snprintf(lp, ep - lp, " %2.2x", *cp); 305 syslog(LOG_NOTICE, 306 "Connection received from %s using IP options (ignored):%s", 307 naddr, lbuf); 308 if (setsockopt(0, ipproto, IP_OPTIONS, 309 (char *)NULL, optsize) != 0) { 310 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 311 exit(1); 312 } 313 } 314 } 315 #endif 316 317 if (ntohs(*portp) >= IPPORT_RESERVED 318 || ntohs(*portp) < IPPORT_RESERVED/2) { 319 syslog(LOG_NOTICE|LOG_AUTH, 320 "Connection from %s on illegal port %u", 321 naddr, ntohs(*portp)); 322 exit(1); 323 } 324 325 (void) alarm(60); 326 port = 0; 327 for (;;) { 328 char c; 329 330 if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { 331 if (cc < 0) 332 syslog(LOG_ERR, "read: %m"); 333 shutdown(0, SHUT_RDWR); 334 exit(1); 335 } 336 if (c == 0) 337 break; 338 port = port * 10 + c - '0'; 339 } 340 341 (void) alarm(0); 342 if (port != 0) { 343 int lport = IPPORT_RESERVED - 1; 344 s = rresvport_af(&lport, af); 345 if (s < 0) { 346 syslog(LOG_ERR, "can't get stderr port: %m"); 347 exit(1); 348 } 349 if (port >= IPPORT_RESERVED) { 350 syslog(LOG_ERR, "2nd port not reserved"); 351 exit(1); 352 } 353 *portp = htons(port); 354 if (connect(s, (struct sockaddr *)fromp, fromp->sa_len) < 0) { 355 syslog(LOG_ERR, "connect second port %d: %m", port); 356 exit(1); 357 } 358 } 359 360 361 #ifdef notdef 362 /* from inetd, socket is already on 0, 1, 2 */ 363 dup2(f, 0); 364 dup2(f, 1); 365 dup2(f, 2); 366 #endif 367 errorstr = NULL; 368 if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr), 369 NULL, 0, NI_NAMEREQD) == 0) { 370 /* 371 * If name returned by getnameinfo is in our domain, 372 * attempt to verify that we haven't been fooled by someone 373 * in a remote net; look up the name and check that this 374 * address corresponds to the name. 375 */ 376 hostname = saddr; 377 res0 = NULL; 378 if (check_all || local_domain(saddr)) { 379 strlcpy(remotehost, saddr, sizeof(remotehost)); 380 errorhost = remotehost; 381 memset(&hints, 0, sizeof(hints)); 382 hints.ai_family = fromp->sa_family; 383 hints.ai_socktype = SOCK_STREAM; 384 hints.ai_flags = AI_CANONNAME; 385 gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0); 386 if (gaierror) { 387 syslog(LOG_NOTICE, 388 "Couldn't look up address for %s: %s", 389 remotehost, gai_strerror(gaierror)); 390 errorstr = 391 "Couldn't look up address for your host (%s)\n"; 392 hostname = naddr; 393 } else { 394 for (res = res0; res; res = res->ai_next) { 395 if (res->ai_family != fromp->sa_family) 396 continue; 397 if (res->ai_addrlen != fromp->sa_len) 398 continue; 399 if (getnameinfo(res->ai_addr, 400 res->ai_addrlen, 401 raddr, sizeof(raddr), NULL, 0, 402 niflags) == 0 403 && strcmp(naddr, raddr) == 0) { 404 hostname = res->ai_canonname 405 ? res->ai_canonname 406 : saddr; 407 break; 408 } 409 } 410 if (res == NULL) { 411 syslog(LOG_NOTICE, 412 "Host addr %s not listed for host %s", 413 naddr, res0->ai_canonname 414 ? res0->ai_canonname 415 : saddr); 416 errorstr = 417 "Host address mismatch for %s\n"; 418 hostname = naddr; 419 } 420 } 421 } 422 strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf)); 423 hostname = hostnamebuf; 424 if (res0) 425 freeaddrinfo(res0); 426 } else { 427 strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf)); 428 errorhost = hostname = hostnamebuf; 429 } 430 431 getstr(remuser, sizeof(remuser), "remuser"); 432 getstr(locuser, sizeof(locuser), "locuser"); 433 getstr(cmdbuf, sizeof(cmdbuf), "command"); 434 setpwent(); 435 pwd = getpwnam(locuser); 436 if (pwd == NULL) { 437 syslog(LOG_INFO|LOG_AUTH, 438 "%s@%s as %s: unknown login. cmd='%.80s'", 439 remuser, hostname, locuser, cmdbuf); 440 if (errorstr == NULL) 441 errorstr = "Permission denied.\n"; 442 goto fail; 443 } 444 #ifdef LOGIN_CAP 445 lc = login_getclass(pwd ? pwd->pw_class : NULL); 446 #endif 447 448 if (chdir(pwd->pw_dir) < 0) { 449 #ifdef LOGIN_CAP 450 if (chdir("/") < 0 || 451 login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0)) { 452 syslog(LOG_INFO|LOG_AUTH, 453 "%s@%s as %s: no home directory. cmd='%.80s'", 454 remuser, hostname, locuser, cmdbuf); 455 error("No remote home directory.\n"); 456 exit(0); 457 } 458 #else 459 (void) chdir("/"); 460 #ifdef notdef 461 syslog(LOG_INFO|LOG_AUTH, 462 "%s@%s as %s: no home directory. cmd='%.80s'", 463 remuser, hostname, locuser, cmdbuf); 464 error("No remote directory.\n"); 465 exit(1); 466 #endif /* notdef */ 467 #endif /* LOGIN_CAP */ 468 } 469 470 471 if (errorstr || 472 (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 473 iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser, 474 locuser) < 0)) { 475 if (__rcmd_errstr) 476 syslog(LOG_INFO|LOG_AUTH, 477 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 478 remuser, hostname, locuser, __rcmd_errstr, 479 cmdbuf); 480 else 481 syslog(LOG_INFO|LOG_AUTH, 482 "%s@%s as %s: permission denied. cmd='%.80s'", 483 remuser, hostname, locuser, cmdbuf); 484 fail: 485 if (errorstr == NULL) 486 errorstr = "Permission denied.\n"; 487 error(errorstr, errorhost); 488 exit(1); 489 } 490 491 if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { 492 error("Logins currently disabled.\n"); 493 exit(1); 494 } 495 496 (void) write(STDERR_FILENO, "\0", 1); 497 sent_null = 1; 498 499 if (port) { 500 if (pipe(pv) < 0) { 501 error("Can't make pipe.\n"); 502 exit(1); 503 } 504 pid = fork(); 505 if (pid == -1) { 506 error("Can't fork; try again.\n"); 507 exit(1); 508 } 509 if (pid) { 510 { 511 (void) close(0); 512 (void) close(1); 513 } 514 (void) close(2); 515 (void) close(pv[1]); 516 517 set[0].fd = s; 518 set[0].events = POLLIN; 519 set[1].fd = pv[0]; 520 set[1].events = POLLIN; 521 ioctl(pv[0], FIONBIO, (char *)&one); 522 523 /* should set s nbio! */ 524 do { 525 if (poll(set, 2, INFTIM) < 0) 526 break; 527 if (set[0].revents & POLLIN) { 528 int ret; 529 530 ret = read(s, &sig, 1); 531 if (ret <= 0) 532 set[0].events = 0; 533 else 534 killpg(pid, sig); 535 } 536 if (set[1].revents & POLLIN) { 537 errno = 0; 538 cc = read(pv[0], buf, sizeof(buf)); 539 if (cc <= 0) { 540 shutdown(s, SHUT_RDWR); 541 set[1].events = 0; 542 } else { 543 (void) write(s, buf, cc); 544 } 545 } 546 547 } while ((set[0].revents | set[1].revents) & POLLIN); 548 exit(0); 549 } 550 (void) close(s); 551 (void) close(pv[0]); 552 dup2(pv[1], 2); 553 close(pv[1]); 554 } 555 setsid(); 556 557 if (*pwd->pw_shell == '\0') 558 pwd->pw_shell = _PATH_BSHELL; 559 #ifdef LOGIN_CAP 560 { 561 char *sh; 562 563 if((sh = login_getcapstr(lc, "shell", NULL, NULL))) { 564 if(!(sh = strdup(sh))) { 565 syslog(LOG_ERR, "Cannot alloc mem"); 566 exit(1); 567 } 568 pwd->pw_shell = sh; 569 } 570 } 571 #endif 572 environ = envinit; 573 strlcat(homedir, pwd->pw_dir, sizeof(homedir)); 574 strlcat(path, _PATH_DEFPATH, sizeof(path)); 575 strlcat(shell, pwd->pw_shell, sizeof(shell)); 576 strlcat(username, pwd->pw_name, sizeof(username)); 577 #ifdef LOGIN_CAP 578 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) { 579 syslog(LOG_ERR, "setusercontext: %m"); 580 exit(1); 581 } 582 login_close(lc); 583 #else 584 (void) setgid((gid_t)pwd->pw_gid); 585 initgroups(pwd->pw_name, pwd->pw_gid); 586 (void) setuid((uid_t)pwd->pw_uid); 587 #endif 588 589 endpwent(); 590 if (log_success || pwd->pw_uid == 0) { 591 syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", 592 remuser, hostname, locuser, cmdbuf); 593 } 594 cp = strrchr(pwd->pw_shell, '/'); 595 if (cp) 596 cp++; 597 else 598 cp = pwd->pw_shell; 599 execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL); 600 perror(pwd->pw_shell); 601 exit(1); 602 } 603 604 /* 605 * Report error to client. Note: can't be used until second socket has 606 * connected to client, or older clients will hang waiting for that 607 * connection first. 608 */ 609 610 #include <stdarg.h> 611 612 void error(const char *fmt, ...) 613 { 614 va_list ap; 615 int len; 616 char *bp, buf[BUFSIZ]; 617 va_start(ap, fmt); 618 bp = buf; 619 if (sent_null == 0) { 620 *bp++ = 1; 621 len = 1; 622 } else 623 len = 0; 624 (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap); 625 (void)write(STDERR_FILENO, buf, len + strlen(bp)); 626 va_end(ap); 627 } 628 629 void 630 getstr(char *buf, int cnt, char *err) 631 { 632 char c; 633 634 do { 635 if (read(STDIN_FILENO, &c, 1) != 1) 636 exit(1); 637 *buf++ = c; 638 if (--cnt == 0) { 639 error("%s too long\n", err); 640 exit(1); 641 } 642 } while (c != 0); 643 } 644 645 /* 646 * Check whether host h is in our local domain, 647 * defined as sharing the last two components of the domain part, 648 * or the entire domain part if the local domain has only one component. 649 * If either name is unqualified (contains no '.'), 650 * assume that the host is local, as it will be 651 * interpreted as such. 652 */ 653 int 654 local_domain(char *h) 655 { 656 char localhost[MAXHOSTNAMELEN + 1]; 657 char *p1, *p2; 658 659 localhost[0] = 0; 660 (void)gethostname(localhost, sizeof(localhost)); 661 localhost[sizeof(localhost) - 1] = '\0'; 662 p1 = topdomain(localhost); 663 p2 = topdomain(h); 664 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 665 return (1); 666 return (0); 667 } 668 669 char * 670 topdomain(char *h) 671 { 672 char *p, *maybe = NULL; 673 int dots = 0; 674 675 for (p = h + strlen(h); p >= h; p--) { 676 if (*p == '.') { 677 if (++dots == 2) 678 return (p); 679 maybe = p; 680 } 681 } 682 return (maybe); 683 } 684 685 void 686 usage(void) 687 { 688 689 syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 690 exit(2); 691 } 692