rshd.c revision 270111
182498Sroberto/*- 282498Sroberto * Copyright (c) 1988, 1989, 1992, 1993, 1994 382498Sroberto * The Regents of the University of California. All rights reserved. 482498Sroberto * Copyright (c) 2002 Networks Associates Technology, Inc. 582498Sroberto * All rights reserved. 682498Sroberto * 782498Sroberto * Portions of this software were developed for the FreeBSD Project by 882498Sroberto * ThinkSec AS and NAI Labs, the Security Research Division of Network 982498Sroberto * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 1082498Sroberto * ("CBOSS"), as part of the DARPA CHATS research program. 1182498Sroberto * 1282498Sroberto * Redistribution and use in source and binary forms, with or without 1382498Sroberto * modification, are permitted provided that the following conditions 1482498Sroberto * are met: 1582498Sroberto * 1. Redistributions of source code must retain the above copyright 1682498Sroberto * notice, this list of conditions and the following disclaimer. 1782498Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1882498Sroberto * notice, this list of conditions and the following disclaimer in the 1982498Sroberto * documentation and/or other materials provided with the distribution. 2082498Sroberto * 3. Neither the name of the University nor the names of its contributors 2182498Sroberto * may be used to endorse or promote products derived from this software 2282498Sroberto * without specific prior written permission. 2382498Sroberto * 2482498Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2582498Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2682498Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2782498Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2882498Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2982498Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3082498Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3182498Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3282498Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3382498Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3482498Sroberto * SUCH DAMAGE. 3582498Sroberto */ 3682498Sroberto 3782498Sroberto#ifndef lint 3882498Srobertostatic const char copyright[] = 3982498Sroberto"@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\ 4082498Sroberto The Regents of the University of California. All rights reserved.\n"; 4182498Sroberto#endif /* not lint */ 4282498Sroberto 4382498Sroberto#ifndef lint 4482498Sroberto#if 0 4582498Srobertostatic const char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; 4682498Sroberto#endif 4782498Sroberto#endif /* not lint */ 4882498Sroberto 4982498Sroberto#include <sys/cdefs.h> 5082498Sroberto__FBSDID("$FreeBSD: head/libexec/rshd/rshd.c 270111 2014-08-17 19:06:26Z neel $"); 51132451Sroberto 5282498Sroberto/* 5382498Sroberto * remote shell server: 5482498Sroberto * [port]\0 5582498Sroberto * ruser\0 5682498Sroberto * luser\0 5782498Sroberto * command\0 5882498Sroberto * data 5982498Sroberto */ 6082498Sroberto#include <sys/param.h> 6182498Sroberto#include <sys/ioctl.h> 6282498Sroberto#include <sys/time.h> 6382498Sroberto#include <sys/socket.h> 6482498Sroberto 6582498Sroberto#include <netinet/in_systm.h> 6682498Sroberto#include <netinet/in.h> 6782498Sroberto#include <netinet/ip.h> 6882498Sroberto#include <netinet/tcp.h> 6982498Sroberto#include <arpa/inet.h> 7082498Sroberto#include <netdb.h> 7182498Sroberto 7282498Sroberto#include <err.h> 7382498Sroberto#include <errno.h> 7482498Sroberto#include <fcntl.h> 7582498Sroberto#include <libutil.h> 7682498Sroberto#include <paths.h> 7782498Sroberto#include <pwd.h> 7882498Sroberto#include <signal.h> 7982498Sroberto#include <stdarg.h> 8082498Sroberto#include <stdio.h> 8182498Sroberto#include <stdlib.h> 8282498Sroberto#include <string.h> 8382498Sroberto#include <syslog.h> 8482498Sroberto#include <unistd.h> 8582498Sroberto#include <login_cap.h> 8682498Sroberto 8782498Sroberto#include <security/pam_appl.h> 8882498Sroberto#include <security/openpam.h> 8982498Sroberto#include <sys/wait.h> 9082498Sroberto 9182498Srobertostatic struct pam_conv pamc = { openpam_nullconv, NULL }; 9282498Srobertostatic pam_handle_t *pamh; 9382498Srobertostatic int pam_err; 9482498Sroberto 9582498Sroberto#define PAM_END { \ 9682498Sroberto if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \ 9782498Sroberto syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", pam_strerror(pamh, pam_err)); \ 9882498Sroberto if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \ 9982498Sroberto syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", pam_strerror(pamh, pam_err)); \ 10082498Sroberto if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \ 10182498Sroberto syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", pam_strerror(pamh, pam_err)); \ 10282498Sroberto} 10382498Sroberto 10482498Srobertoint keepalive = 1; 10582498Srobertoint log_success; /* If TRUE, log all successful accesses */ 10682498Srobertoint sent_null; 10782498Srobertoint no_delay; 10882498Sroberto 10982498Srobertovoid doit(struct sockaddr *); 11082498Srobertostatic void rshd_errx(int, const char *, ...) __printf0like(2, 3); 11182498Srobertovoid getstr(char *, int, const char *); 11282498Srobertoint local_domain(char *); 11382498Srobertochar *topdomain(char *); 11482498Srobertovoid usage(void); 11582498Sroberto 11682498Srobertochar slash[] = "/"; 11782498Srobertochar bshell[] = _PATH_BSHELL; 11882498Sroberto 11982498Sroberto#define OPTIONS "aDLln" 12082498Sroberto 12182498Srobertoint 12282498Srobertomain(int argc, char *argv[]) 12382498Sroberto{ 12482498Sroberto extern int __check_rhosts_file; 12582498Sroberto struct linger linger; 12682498Sroberto socklen_t fromlen; 127290001Sglebius int ch, on = 1; 12882498Sroberto struct sockaddr_storage from; 12982498Sroberto 13082498Sroberto openlog("rshd", LOG_PID, LOG_DAEMON); 13182498Sroberto 13282498Sroberto opterr = 0; 13382498Sroberto while ((ch = getopt(argc, argv, OPTIONS)) != -1) 134290001Sglebius switch (ch) { 135290001Sglebius case 'a': 136290001Sglebius /* ignored for compatibility */ 13782498Sroberto break; 13882498Sroberto case 'l': 13982498Sroberto __check_rhosts_file = 0; 14082498Sroberto break; 14182498Sroberto case 'n': 14282498Sroberto keepalive = 0; 143290001Sglebius break; 14482498Sroberto case 'D': 145132451Sroberto no_delay = 1; 146290001Sglebius break; 14782498Sroberto case 'L': 14882498Sroberto log_success = 1; 14982498Sroberto break; 15082498Sroberto case '?': 15182498Sroberto default: 15282498Sroberto usage(); 153290001Sglebius break; 154290001Sglebius } 155290001Sglebius 156290001Sglebius argc -= optind; 157290001Sglebius argv += optind; 158290001Sglebius 15982498Sroberto fromlen = sizeof (from); 16082498Sroberto if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 16182498Sroberto syslog(LOG_ERR, "getpeername: %m"); 16282498Sroberto exit(1); 16382498Sroberto } 16482498Sroberto if (keepalive && 16582498Sroberto setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 16682498Sroberto sizeof(on)) < 0) 16782498Sroberto syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 16882498Sroberto linger.l_onoff = 1; 16982498Sroberto linger.l_linger = 60; /* XXX */ 17082498Sroberto if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 17182498Sroberto sizeof (linger)) < 0) 17282498Sroberto syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 17382498Sroberto if (no_delay && 17482498Sroberto setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 17582498Sroberto syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 17682498Sroberto doit((struct sockaddr *)&from); 177290001Sglebius /* NOTREACHED */ 178290001Sglebius return(0); 17982498Sroberto} 18082498Sroberto 18182498Srobertoextern char **environ; 18282498Sroberto 18382498Srobertovoid 18482498Srobertodoit(struct sockaddr *fromp) 18582498Sroberto{ 18682498Sroberto extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ 18782498Sroberto struct passwd *pwd; 18882498Sroberto u_short port; 18982498Sroberto fd_set ready, readfrom; 19082498Sroberto int cc, fd, nfd, pv[2], pid, s; 19182498Sroberto int one = 1; 19282498Sroberto const char *cp, *errorstr; 19382498Sroberto char sig, buf[BUFSIZ]; 19482498Sroberto char *cmdbuf, luser[16], ruser[16]; 19582498Sroberto char rhost[2 * MAXHOSTNAMELEN + 1]; 19682498Sroberto char numericname[INET6_ADDRSTRLEN]; 197290001Sglebius int af, srcport; 198290001Sglebius int maxcmdlen; 199290001Sglebius login_cap_t *lc; 20082498Sroberto 20182498Sroberto maxcmdlen = (int)sysconf(_SC_ARG_MAX); 20282498Sroberto if (maxcmdlen <= 0 || (cmdbuf = malloc(maxcmdlen)) == NULL) 20382498Sroberto exit(1); 20482498Sroberto 20582498Sroberto (void) signal(SIGINT, SIG_DFL); 20682498Sroberto (void) signal(SIGQUIT, SIG_DFL); 20782498Sroberto (void) signal(SIGTERM, SIG_DFL); 20882498Sroberto af = fromp->sa_family; 209132451Sroberto srcport = ntohs(*((in_port_t *)&fromp->sa_data)); 21082498Sroberto if (af == AF_INET) { 21182498Sroberto inet_ntop(af, &((struct sockaddr_in *)fromp)->sin_addr, 21282498Sroberto numericname, sizeof numericname); 21382498Sroberto } else if (af == AF_INET6) { 21482498Sroberto inet_ntop(af, &((struct sockaddr_in6 *)fromp)->sin6_addr, 215290001Sglebius numericname, sizeof numericname); 216290001Sglebius } else { 217290001Sglebius syslog(LOG_ERR, "malformed \"from\" address (af %d)", af); 218290001Sglebius exit(1); 219290001Sglebius } 220132451Sroberto#ifdef IP_OPTIONS 22182498Sroberto if (af == AF_INET) { 22282498Sroberto u_char optbuf[BUFSIZ/3]; 22382498Sroberto socklen_t optsize = sizeof(optbuf), ipproto, i; 22482498Sroberto struct protoent *ip; 22582498Sroberto 22682498Sroberto if ((ip = getprotobyname("ip")) != NULL) 22782498Sroberto ipproto = ip->p_proto; 22882498Sroberto else 22982498Sroberto ipproto = IPPROTO_IP; 23082498Sroberto if (!getsockopt(0, ipproto, IP_OPTIONS, optbuf, &optsize) && 23182498Sroberto optsize != 0) { 23282498Sroberto for (i = 0; i < optsize; ) { 23382498Sroberto u_char c = optbuf[i]; 23482498Sroberto if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 23582498Sroberto syslog(LOG_NOTICE, 23682498Sroberto "connection refused from %s with IP option %s", 23782498Sroberto numericname, 23882498Sroberto c == IPOPT_LSRR ? "LSRR" : "SSRR"); 23982498Sroberto exit(1); 24082498Sroberto } 24182498Sroberto if (c == IPOPT_EOL) 24282498Sroberto break; 24382498Sroberto i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 24482498Sroberto } 24582498Sroberto } 24682498Sroberto } 24782498Sroberto#endif 24882498Sroberto 24982498Sroberto if (srcport >= IPPORT_RESERVED || 250132451Sroberto srcport < IPPORT_RESERVED/2) { 25182498Sroberto syslog(LOG_NOTICE|LOG_AUTH, 25282498Sroberto "connection from %s on illegal port %u", 25382498Sroberto numericname, 25482498Sroberto srcport); 25582498Sroberto exit(1); 25682498Sroberto } 25782498Sroberto 25882498Sroberto (void) alarm(60); 259 port = 0; 260 s = 0; /* not set or used if port == 0 */ 261 for (;;) { 262 char c; 263 if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { 264 if (cc < 0) 265 syslog(LOG_NOTICE, "read: %m"); 266 shutdown(0, SHUT_RDWR); 267 exit(1); 268 } 269 if (c == 0) 270 break; 271 port = port * 10 + c - '0'; 272 } 273 274 (void) alarm(0); 275 if (port != 0) { 276 int lport = IPPORT_RESERVED - 1; 277 s = rresvport_af(&lport, af); 278 if (s < 0) { 279 syslog(LOG_ERR, "can't get stderr port: %m"); 280 exit(1); 281 } 282 if (port >= IPPORT_RESERVED || 283 port < IPPORT_RESERVED/2) { 284 syslog(LOG_NOTICE|LOG_AUTH, 285 "2nd socket from %s on unreserved port %u", 286 numericname, 287 port); 288 exit(1); 289 } 290 *((in_port_t *)&fromp->sa_data) = htons(port); 291 if (connect(s, fromp, fromp->sa_len) < 0) { 292 syslog(LOG_INFO, "connect second port %d: %m", port); 293 exit(1); 294 } 295 } 296 297 errorstr = NULL; 298 realhostname_sa(rhost, sizeof(rhost) - 1, fromp, fromp->sa_len); 299 rhost[sizeof(rhost) - 1] = '\0'; 300 /* XXX truncation! */ 301 302 (void) alarm(60); 303 getstr(ruser, sizeof(ruser), "ruser"); 304 getstr(luser, sizeof(luser), "luser"); 305 getstr(cmdbuf, maxcmdlen, "command"); 306 (void) alarm(0); 307 308 pam_err = pam_start("rsh", luser, &pamc, &pamh); 309 if (pam_err != PAM_SUCCESS) { 310 syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s", 311 pam_strerror(pamh, pam_err)); 312 rshd_errx(1, "Login incorrect."); 313 } 314 315 if ((pam_err = pam_set_item(pamh, PAM_RUSER, ruser)) != PAM_SUCCESS || 316 (pam_err = pam_set_item(pamh, PAM_RHOST, rhost)) != PAM_SUCCESS) { 317 syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s", 318 pam_strerror(pamh, pam_err)); 319 rshd_errx(1, "Login incorrect."); 320 } 321 322 pam_err = pam_authenticate(pamh, 0); 323 if (pam_err == PAM_SUCCESS) { 324 if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) { 325 strncpy(luser, cp, sizeof(luser)); 326 luser[sizeof(luser) - 1] = '\0'; 327 /* XXX truncation! */ 328 } 329 pam_err = pam_acct_mgmt(pamh, 0); 330 } 331 if (pam_err != PAM_SUCCESS) { 332 syslog(LOG_INFO|LOG_AUTH, 333 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 334 ruser, rhost, luser, pam_strerror(pamh, pam_err), cmdbuf); 335 rshd_errx(1, "Login incorrect."); 336 } 337 338 setpwent(); 339 pwd = getpwnam(luser); 340 if (pwd == NULL) { 341 syslog(LOG_INFO|LOG_AUTH, 342 "%s@%s as %s: unknown login. cmd='%.80s'", 343 ruser, rhost, luser, cmdbuf); 344 if (errorstr == NULL) 345 errorstr = "Login incorrect."; 346 rshd_errx(1, errorstr, rhost); 347 } 348 349 lc = login_getpwclass(pwd); 350 if (pwd->pw_uid) 351 auth_checknologin(lc); 352 353 if (chdir(pwd->pw_dir) < 0) { 354 if (chdir("/") < 0 || 355 login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) { 356 syslog(LOG_INFO|LOG_AUTH, 357 "%s@%s as %s: no home directory. cmd='%.80s'", 358 ruser, rhost, luser, cmdbuf); 359 rshd_errx(0, "No remote home directory."); 360 } 361 pwd->pw_dir = slash; 362 } 363 364 if (lc != NULL && fromp->sa_family == AF_INET) { /*XXX*/ 365 char remote_ip[MAXHOSTNAMELEN]; 366 367 strncpy(remote_ip, numericname, 368 sizeof(remote_ip) - 1); 369 remote_ip[sizeof(remote_ip) - 1] = 0; 370 /* XXX truncation! */ 371 if (!auth_hostok(lc, rhost, remote_ip)) { 372 syslog(LOG_INFO|LOG_AUTH, 373 "%s@%s as %s: permission denied (%s). cmd='%.80s'", 374 ruser, rhost, luser, __rcmd_errstr, 375 cmdbuf); 376 rshd_errx(1, "Login incorrect."); 377 } 378 if (!auth_timeok(lc, time(NULL))) 379 rshd_errx(1, "Logins not available right now"); 380 } 381 382 /* 383 * PAM modules might add supplementary groups in 384 * pam_setcred(), so initialize them first. 385 * But we need to open the session as root. 386 */ 387 if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) { 388 syslog(LOG_ERR, "setusercontext: %m"); 389 exit(1); 390 } 391 392 if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) { 393 syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, pam_err)); 394 } else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 395 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err)); 396 } 397 398 (void) write(STDERR_FILENO, "\0", 1); 399 sent_null = 1; 400 401 if (port) { 402 if (pipe(pv) < 0) 403 rshd_errx(1, "Can't make pipe."); 404 pid = fork(); 405 if (pid == -1) 406 rshd_errx(1, "Can't fork; try again."); 407 if (pid) { 408 (void) close(0); 409 (void) close(1); 410 (void) close(2); 411 (void) close(pv[1]); 412 413 FD_ZERO(&readfrom); 414 FD_SET(s, &readfrom); 415 FD_SET(pv[0], &readfrom); 416 if (pv[0] > s) 417 nfd = pv[0]; 418 else 419 nfd = s; 420 ioctl(pv[0], FIONBIO, (char *)&one); 421 422 /* should set s nbio! */ 423 nfd++; 424 do { 425 ready = readfrom; 426 if (select(nfd, &ready, (fd_set *)0, 427 (fd_set *)0, (struct timeval *)0) < 0) 428 break; 429 if (FD_ISSET(s, &ready)) { 430 int ret; 431 ret = read(s, &sig, 1); 432 if (ret <= 0) 433 FD_CLR(s, &readfrom); 434 else 435 killpg(pid, sig); 436 } 437 if (FD_ISSET(pv[0], &ready)) { 438 errno = 0; 439 cc = read(pv[0], buf, sizeof(buf)); 440 if (cc <= 0) { 441 shutdown(s, SHUT_RDWR); 442 FD_CLR(pv[0], &readfrom); 443 } else { 444 (void)write(s, buf, cc); 445 } 446 } 447 448 } while (FD_ISSET(s, &readfrom) || 449 FD_ISSET(pv[0], &readfrom)); 450 PAM_END; 451 exit(0); 452 } 453 (void) close(s); 454 (void) close(pv[0]); 455 dup2(pv[1], 2); 456 close(pv[1]); 457 } 458 else { 459 pid = fork(); 460 if (pid == -1) 461 rshd_errx(1, "Can't fork; try again."); 462 if (pid) { 463 /* Parent. */ 464 while (wait(NULL) > 0 || errno == EINTR) 465 /* nothing */ ; 466 PAM_END; 467 exit(0); 468 } 469 } 470 471 for (fd = getdtablesize(); fd > 2; fd--) 472 (void) close(fd); 473 if (setsid() == -1) 474 syslog(LOG_ERR, "setsid() failed: %m"); 475 if (setlogin(pwd->pw_name) < 0) 476 syslog(LOG_ERR, "setlogin() failed: %m"); 477 478 if (*pwd->pw_shell == '\0') 479 pwd->pw_shell = bshell; 480 (void) pam_setenv(pamh, "HOME", pwd->pw_dir, 1); 481 (void) pam_setenv(pamh, "SHELL", pwd->pw_shell, 1); 482 (void) pam_setenv(pamh, "USER", pwd->pw_name, 1); 483 (void) pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1); 484 environ = pam_getenvlist(pamh); 485 (void) pam_end(pamh, pam_err); 486 cp = strrchr(pwd->pw_shell, '/'); 487 if (cp) 488 cp++; 489 else 490 cp = pwd->pw_shell; 491 492 if (setusercontext(lc, pwd, pwd->pw_uid, 493 LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) { 494 syslog(LOG_ERR, "setusercontext(): %m"); 495 exit(1); 496 } 497 login_close(lc); 498 endpwent(); 499 if (log_success || pwd->pw_uid == 0) { 500 syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", 501 ruser, rhost, luser, cmdbuf); 502 } 503 execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL); 504 err(1, "%s", pwd->pw_shell); 505 exit(1); 506} 507 508/* 509 * Report error to client. Note: can't be used until second socket has 510 * connected to client, or older clients will hang waiting for that 511 * connection first. 512 */ 513 514static void 515rshd_errx(int errcode, const char *fmt, ...) 516{ 517 va_list ap; 518 519 va_start(ap, fmt); 520 521 if (sent_null == 0) 522 write(STDERR_FILENO, "\1", 1); 523 524 verrx(errcode, fmt, ap); 525 /* NOTREACHED */ 526} 527 528void 529getstr(char *buf, int cnt, const char *error) 530{ 531 char c; 532 533 do { 534 if (read(STDIN_FILENO, &c, 1) != 1) 535 exit(1); 536 *buf++ = c; 537 if (--cnt == 0) 538 rshd_errx(1, "%s too long", error); 539 } while (c != 0); 540} 541 542/* 543 * Check whether host h is in our local domain, 544 * defined as sharing the last two components of the domain part, 545 * or the entire domain part if the local domain has only one component. 546 * If either name is unqualified (contains no '.'), 547 * assume that the host is local, as it will be 548 * interpreted as such. 549 */ 550int 551local_domain(char *h) 552{ 553 char localhost[MAXHOSTNAMELEN]; 554 char *p1, *p2; 555 556 localhost[0] = 0; 557 (void) gethostname(localhost, sizeof(localhost) - 1); 558 localhost[sizeof(localhost) - 1] = '\0'; 559 /* XXX truncation! */ 560 p1 = topdomain(localhost); 561 p2 = topdomain(h); 562 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 563 return (1); 564 return (0); 565} 566 567char * 568topdomain(char *h) 569{ 570 char *p, *maybe = NULL; 571 int dots = 0; 572 573 for (p = h + strlen(h); p >= h; p--) { 574 if (*p == '.') { 575 if (++dots == 2) 576 return (p); 577 maybe = p; 578 } 579 } 580 return (maybe); 581} 582 583void 584usage(void) 585{ 586 587 syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 588 exit(2); 589} 590