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