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