1 /* $NetBSD: rshd.c,v 1.25 2002/03/18 23:59:57 mjl 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.25 2002/03/18 23:59:57 mjl 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 <arpa/inet.h> 95 #include <netdb.h> 96 97 #include <errno.h> 98 #include <fcntl.h> 99 #include <paths.h> 100 #include <pwd.h> 101 #include <signal.h> 102 #include <stdio.h> 103 #include <stdlib.h> 104 #include <string.h> 105 #include <syslog.h> 106 #include <unistd.h> 107 #ifdef LOGIN_CAP 108 #include <login_cap.h> 109 #endif 110 111 int keepalive = 1; 112 int check_all; 113 int log_success; /* If TRUE, log all successful accesses */ 114 int sent_null; 115 116 void doit __P((struct sockaddr *)); 117 void error __P((const char *, ...)) 118 __attribute__((__format__(__printf__, 1, 2))); 119 void getstr __P((char *, int, char *)); 120 int local_domain __P((char *)); 121 char *topdomain __P((char *)); 122 void usage __P((void)); 123 int main __P((int, char *[])); 124 125 #define OPTIONS "alnL" 126 extern int __check_rhosts_file; 127 extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ 128 129 int 130 main(int argc, char *argv[]) 131 { 132 struct linger linger; 133 int ch, on = 1, fromlen; 134 struct sockaddr_storage from; 135 136 openlog("rshd", LOG_PID, LOG_DAEMON); 137 138 opterr = 0; 139 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 140 switch (ch) { 141 case 'a': 142 check_all = 1; 143 break; 144 case 'l': 145 __check_rhosts_file = 0; 146 break; 147 case 'n': 148 keepalive = 0; 149 break; 150 case 'L': 151 log_success = 1; 152 break; 153 case '?': 154 default: 155 usage(); 156 break; 157 } 158 159 argc -= optind; 160 argv += optind; 161 162 fromlen = sizeof (from); /* xxx */ 163 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 164 syslog(LOG_ERR, "getpeername: %m"); 165 exit(1); 166 } 167 #if 0 168 if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 169 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) && 170 sizeof(struct sockaddr_in) <= sizeof(from)) { 171 struct sockaddr_in sin; 172 struct sockaddr_in6 *sin6; 173 const int off = sizeof(struct sockaddr_in6) - 174 sizeof(struct sockaddr_in); 175 176 sin6 = (struct sockaddr_in6 *)&from; 177 memset(&sin, 0, sizeof(sin)); 178 sin.sin_family = AF_INET; 179 sin.sin_len = sizeof(struct sockaddr_in); 180 memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off], 181 sizeof(sin.sin_addr)); 182 memcpy(&from, &sin, sizeof(sin)); 183 fromlen = sin.sin_len; 184 } 185 #else 186 if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 187 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) { 188 char hbuf[NI_MAXHOST]; 189 if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf, 190 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 191 strncpy(hbuf, "invalid", sizeof(hbuf)); 192 } 193 syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)", 194 hbuf); 195 exit(1); 196 } 197 #endif 198 if (keepalive && 199 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 200 sizeof(on)) < 0) 201 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 202 linger.l_onoff = 1; 203 linger.l_linger = 60; /* XXX */ 204 if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 205 sizeof (linger)) < 0) 206 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 207 doit((struct sockaddr *)&from); 208 /* NOTREACHED */ 209 #ifdef __GNUC__ 210 exit(0); 211 #endif 212 } 213 214 char username[20] = "USER="; 215 char homedir[64] = "HOME="; 216 char shell[64] = "SHELL="; 217 char path[100] = "PATH="; 218 char *envinit[] = 219 {homedir, shell, path, username, 0}; 220 char **environ; 221 222 void 223 doit(struct sockaddr *fromp) 224 { 225 struct passwd *pwd; 226 in_port_t port; 227 fd_set ready, readfrom; 228 int cc, nfd, pv[2], pid, s = -1; /* XXX gcc */ 229 int one = 1; 230 char *hostname, *errorstr, *errorhost = NULL; /* XXX gcc */ 231 const char *cp; 232 char sig, buf[BUFSIZ]; 233 char cmdbuf[NCARGS+1], locuser[16], remuser[16]; 234 char remotehost[2 * MAXHOSTNAMELEN + 1]; 235 char hostnamebuf[2 * MAXHOSTNAMELEN + 1]; 236 #ifdef LOGIN_CAP 237 login_cap_t *lc; 238 #endif 239 char naddr[NI_MAXHOST]; 240 char saddr[NI_MAXHOST]; 241 char raddr[NI_MAXHOST]; 242 char pbuf[NI_MAXSERV]; 243 int af = fromp->sa_family; 244 u_int16_t *portp; 245 struct addrinfo hints, *res, *res0; 246 int gaierror; 247 #ifdef NI_WITHSCOPEID 248 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID; 249 #else 250 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 251 #endif 252 253 (void) signal(SIGINT, SIG_DFL); 254 (void) signal(SIGQUIT, SIG_DFL); 255 (void) signal(SIGTERM, SIG_DFL); 256 #ifdef DEBUG 257 { int t = open(_PATH_TTY, 2); 258 if (t >= 0) { 259 ioctl(t, TIOCNOTTY, (char *)0); 260 (void) close(t); 261 } 262 } 263 #endif 264 switch (af) { 265 case AF_INET: 266 portp = &((struct sockaddr_in *)fromp)->sin_port; 267 break; 268 #ifdef INET6 269 case AF_INET6: 270 portp = &((struct sockaddr_in6 *)fromp)->sin6_port; 271 break; 272 #endif 273 default: 274 syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 275 exit(1); 276 } 277 if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr), 278 pbuf, sizeof(pbuf), niflags) != 0) { 279 syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 280 exit(1); 281 } 282 #ifdef IP_OPTIONS 283 if (af == AF_INET) 284 { 285 u_char optbuf[BUFSIZ/3], *cp; 286 char lbuf[BUFSIZ], *lp; 287 int optsize = sizeof(optbuf), ipproto; 288 struct protoent *ip; 289 290 if ((ip = getprotobyname("ip")) != NULL) 291 ipproto = ip->p_proto; 292 else 293 ipproto = IPPROTO_IP; 294 if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && 295 optsize != 0) { 296 lp = lbuf; 297 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 298 sprintf(lp, " %2.2x", *cp); 299 syslog(LOG_NOTICE, 300 "Connection received from %s using IP options (ignored):%s", 301 naddr, lbuf); 302 if (setsockopt(0, ipproto, IP_OPTIONS, 303 (char *)NULL, optsize) != 0) { 304 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 305 exit(1); 306 } 307 } 308 } 309 #endif 310 311 if (ntohs(*portp) >= IPPORT_RESERVED 312 || ntohs(*portp) < IPPORT_RESERVED/2) { 313 syslog(LOG_NOTICE|LOG_AUTH, 314 "Connection from %s on illegal port %u", 315 naddr, ntohs(*portp)); 316 exit(1); 317 } 318 319 (void) alarm(60); 320 port = 0; 321 for (;;) { 322 char c; 323 324 if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { 325 if (cc < 0) 326 syslog(LOG_ERR, "read: %m"); 327 shutdown(0, SHUT_RDWR); 328 exit(1); 329 } 330 if (c == 0) 331 break; 332 port = port * 10 + c - '0'; 333 } 334 335 (void) alarm(0); 336 if (port != 0) { 337 int lport = IPPORT_RESERVED - 1; 338 s = rresvport_af(&lport, af); 339 if (s < 0) { 340 syslog(LOG_ERR, "can't get stderr port: %m"); 341 exit(1); 342 } 343 if (port >= IPPORT_RESERVED) { 344 syslog(LOG_ERR, "2nd port not reserved"); 345 exit(1); 346 } 347 *portp = htons(port); 348 if (connect(s, (struct sockaddr *)fromp, fromp->sa_len) < 0) { 349 syslog(LOG_ERR, "connect second port %d: %m", port); 350 exit(1); 351 } 352 } 353 354 355 #ifdef notdef 356 /* from inetd, socket is already on 0, 1, 2 */ 357 dup2(f, 0); 358 dup2(f, 1); 359 dup2(f, 2); 360 #endif 361 errorstr = NULL; 362 if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr), 363 NULL, 0, NI_NAMEREQD) == 0) { 364 /* 365 * If name returned by getnameinfo is in our domain, 366 * attempt to verify that we haven't been fooled by someone 367 * in a remote net; look up the name and check that this 368 * address corresponds to the name. 369 */ 370 hostname = saddr; 371 res0 = NULL; 372 if (check_all || local_domain(saddr)) { 373 strlcpy(remotehost, saddr, sizeof(remotehost)); 374 errorhost = remotehost; 375 memset(&hints, 0, sizeof(hints)); 376 hints.ai_family = fromp->sa_family; 377 hints.ai_socktype = SOCK_STREAM; 378 hints.ai_flags = AI_CANONNAME; 379 gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0); 380 if (gaierror) { 381 syslog(LOG_NOTICE, 382 "Couldn't look up address for %s: %s", 383 remotehost, gai_strerror(gaierror)); 384 errorstr = 385 "Couldn't look up address for your host (%s)\n"; 386 hostname = naddr; 387 } else { 388 for (res = res0; res; res = res->ai_next) { 389 if (res->ai_family != fromp->sa_family) 390 continue; 391 if (res->ai_addrlen != fromp->sa_len) 392 continue; 393 if (getnameinfo(res->ai_addr, 394 res->ai_addrlen, 395 raddr, sizeof(raddr), NULL, 0, 396 niflags) == 0 397 && strcmp(naddr, raddr) == 0) { 398 hostname = res->ai_canonname 399 ? res->ai_canonname 400 : saddr; 401 break; 402 } 403 } 404 if (res == NULL) { 405 syslog(LOG_NOTICE, 406 "Host addr %s not listed for host %s", 407 naddr, res0->ai_canonname 408 ? res0->ai_canonname 409 : saddr); 410 errorstr = 411 "Host address mismatch for %s\n"; 412 hostname = naddr; 413 } 414 } 415 } 416 strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf)); 417 hostname = hostnamebuf; 418 if (res0) 419 freeaddrinfo(res0); 420 } else { 421 strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf)); 422 errorhost = hostname = hostnamebuf; 423 } 424 425 getstr(remuser, sizeof(remuser), "remuser"); 426 getstr(locuser, sizeof(locuser), "locuser"); 427 getstr(cmdbuf, sizeof(cmdbuf), "command"); 428 setpwent(); 429 pwd = getpwnam(locuser); 430 if (pwd == NULL) { 431 syslog(LOG_INFO|LOG_AUTH, 432 "%s@%s as %s: unknown login. cmd='%.80s'", 433 remuser, hostname, locuser, cmdbuf); 434 if (errorstr == NULL) 435 errorstr = "Permission denied.\n"; 436 goto fail; 437 } 438 #ifdef LOGIN_CAP 439 lc = login_getclass(pwd ? pwd->pw_class : NULL); 440 #endif 441 442 if (chdir(pwd->pw_dir) < 0) { 443 #ifdef LOGIN_CAP 444 if (chdir("/") < 0 || 445 login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0)) { 446 syslog(LOG_INFO|LOG_AUTH, 447 "%s@%s as %s: no home directory. cmd='%.80s'", 448 remuser, hostname, locuser, cmdbuf); 449 error("No remote home directory.\n"); 450 exit(0); 451 } 452 #else 453 (void) chdir("/"); 454 #ifdef notdef 455 syslog(LOG_INFO|LOG_AUTH, 456 "%s@%s as %s: no home directory. cmd='%.80s'", 457 remuser, hostname, locuser, cmdbuf); 458 error("No remote directory.\n"); 459 exit(1); 460 #endif /* notdef */ 461 #endif /* LOGIN_CAP */ 462 } 463 464 465 if (errorstr || 466 (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 467 iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser, 468 locuser) < 0)) { 469 if (__rcmd_errstr) 470 syslog(LOG_INFO|LOG_AUTH, 471 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 472 remuser, hostname, locuser, __rcmd_errstr, 473 cmdbuf); 474 else 475 syslog(LOG_INFO|LOG_AUTH, 476 "%s@%s as %s: permission denied. cmd='%.80s'", 477 remuser, hostname, locuser, cmdbuf); 478 fail: 479 if (errorstr == NULL) 480 errorstr = "Permission denied.\n"; 481 error(errorstr, errorhost); 482 exit(1); 483 } 484 485 if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { 486 error("Logins currently disabled.\n"); 487 exit(1); 488 } 489 490 (void) write(STDERR_FILENO, "\0", 1); 491 sent_null = 1; 492 493 if (port) { 494 if (pipe(pv) < 0) { 495 error("Can't make pipe.\n"); 496 exit(1); 497 } 498 pid = fork(); 499 if (pid == -1) { 500 error("Can't fork; try again.\n"); 501 exit(1); 502 } 503 if (pid) { 504 { 505 (void) close(0); 506 (void) close(1); 507 } 508 (void) close(2); 509 (void) close(pv[1]); 510 511 FD_ZERO(&readfrom); 512 FD_SET(s, &readfrom); 513 FD_SET(pv[0], &readfrom); 514 if (pv[0] > s) 515 nfd = pv[0]; 516 else 517 nfd = s; 518 ioctl(pv[0], FIONBIO, (char *)&one); 519 520 /* should set s nbio! */ 521 nfd++; 522 do { 523 ready = readfrom; 524 if (select(nfd, &ready, (fd_set *)0, 525 (fd_set *)0, (struct timeval *)0) < 0) 526 break; 527 if (FD_ISSET(s, &ready)) { 528 int ret; 529 530 ret = read(s, &sig, 1); 531 if (ret <= 0) 532 FD_CLR(s, &readfrom); 533 else 534 killpg(pid, sig); 535 } 536 if (FD_ISSET(pv[0], &ready)) { 537 errno = 0; 538 cc = read(pv[0], buf, sizeof(buf)); 539 if (cc <= 0) { 540 shutdown(s, SHUT_RDWR); 541 FD_CLR(pv[0], &readfrom); 542 } else { 543 (void) write(s, buf, cc); 544 } 545 } 546 547 } while (FD_ISSET(s, &readfrom) || 548 FD_ISSET(pv[0], &readfrom)); 549 exit(0); 550 } 551 setpgrp(0, getpid()); 552 (void) close(s); 553 (void) close(pv[0]); 554 dup2(pv[1], 2); 555 close(pv[1]); 556 } 557 #if BSD > 43 558 if (setlogin(pwd->pw_name) < 0) 559 syslog(LOG_ERR, "setlogin() failed: %m"); 560 #endif 561 562 if (*pwd->pw_shell == '\0') 563 pwd->pw_shell = _PATH_BSHELL; 564 #ifdef LOGIN_CAP 565 { 566 char *sh; 567 568 if((sh = login_getcapstr(lc, "shell", NULL, NULL))) { 569 if(!(sh = strdup(sh))) { 570 syslog(LOG_ERR, "Cannot alloc mem"); 571 exit(1); 572 } 573 pwd->pw_shell = sh; 574 } 575 } 576 #endif 577 environ = envinit; 578 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 579 strcat(path, _PATH_DEFPATH); 580 strncat(shell, pwd->pw_shell, sizeof(shell)-7); 581 strncat(username, pwd->pw_name, sizeof(username)-6); 582 #ifdef LOGIN_CAP 583 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) { 584 syslog(LOG_ERR, "setusercontext: %m"); 585 exit(1); 586 } 587 login_close(lc); 588 #else 589 (void) setgid((gid_t)pwd->pw_gid); 590 initgroups(pwd->pw_name, pwd->pw_gid); 591 (void) setuid((uid_t)pwd->pw_uid); 592 #endif 593 594 endpwent(); 595 if (log_success || pwd->pw_uid == 0) { 596 syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", 597 remuser, hostname, locuser, cmdbuf); 598 } 599 cp = strrchr(pwd->pw_shell, '/'); 600 if (cp) 601 cp++; 602 else 603 cp = pwd->pw_shell; 604 execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL); 605 perror(pwd->pw_shell); 606 exit(1); 607 } 608 609 /* 610 * Report error to client. Note: can't be used until second socket has 611 * connected to client, or older clients will hang waiting for that 612 * connection first. 613 */ 614 615 #include <stdarg.h> 616 617 void error(const char *fmt, ...) 618 { 619 va_list ap; 620 int len; 621 char *bp, buf[BUFSIZ]; 622 va_start(ap, fmt); 623 bp = buf; 624 if (sent_null == 0) { 625 *bp++ = 1; 626 len = 1; 627 } else 628 len = 0; 629 (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap); 630 (void)write(STDERR_FILENO, buf, len + strlen(bp)); 631 va_end(ap); 632 } 633 634 void 635 getstr(char *buf, int cnt, char *err) 636 { 637 char c; 638 639 do { 640 if (read(STDIN_FILENO, &c, 1) != 1) 641 exit(1); 642 *buf++ = c; 643 if (--cnt == 0) { 644 error("%s too long\n", err); 645 exit(1); 646 } 647 } while (c != 0); 648 } 649 650 /* 651 * Check whether host h is in our local domain, 652 * defined as sharing the last two components of the domain part, 653 * or the entire domain part if the local domain has only one component. 654 * If either name is unqualified (contains no '.'), 655 * assume that the host is local, as it will be 656 * interpreted as such. 657 */ 658 int 659 local_domain(char *h) 660 { 661 char localhost[MAXHOSTNAMELEN + 1]; 662 char *p1, *p2; 663 664 localhost[0] = 0; 665 (void)gethostname(localhost, sizeof(localhost)); 666 localhost[sizeof(localhost) - 1] = '\0'; 667 p1 = topdomain(localhost); 668 p2 = topdomain(h); 669 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 670 return (1); 671 return (0); 672 } 673 674 char * 675 topdomain(char *h) 676 { 677 char *p, *maybe = NULL; 678 int dots = 0; 679 680 for (p = h + strlen(h); p >= h; p--) { 681 if (*p == '.') { 682 if (++dots == 2) 683 return (p); 684 maybe = p; 685 } 686 } 687 return (maybe); 688 } 689 690 void 691 usage(void) 692 { 693 694 syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 695 exit(2); 696 } 697