1: /*
   2:  * Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted
   6:  * provided that the above copyright notice and this paragraph are
   7:  * duplicated in all such forms and that any documentation,
   8:  * advertising materials, and other materials related to such
   9:  * distribution and use acknowledge that the software was developed
  10:  * by the University of California, Berkeley.  The name of the
  11:  * University may not be used to endorse or promote products derived
  12:  * from this software without specific prior written permission.
  13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16:  */
  17: 
  18: #if !defined(lint) && defined(DOSCCS)
  19: char copyright[] =
  20: "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\
  21:  All rights reserved.\n";
  22: 
  23: static char sccsid[] = "@(#)rshd.c	5.17.1.4 (Berkeley) 1996/11/29";
  24: #endif
  25: 
  26: /*
  27:  * remote shell server:
  28:  *	[port]\0
  29:  *	remuser\0
  30:  *	locuser\0
  31:  *	command\0
  32:  *	data
  33:  */
  34: #include <sys/param.h>
  35: #include <sys/ioctl.h>
  36: #include <sys/socket.h>
  37: #include <sys/file.h>
  38: #include <sys/signal.h>
  39: #include <sys/time.h>
  40: 
  41: #include <netinet/in.h>
  42: 
  43: #include <arpa/inet.h>
  44: 
  45: #include <stdio.h>
  46: #include <errno.h>
  47: #include <pwd.h>
  48: #include <netdb.h>
  49: #include <syslog.h>
  50: #include <arpa/nameser.h>
  51: #include <resolv.h>
  52: #include <stdlib.h>
  53: #include <string.h>
  54: #include "pathnames.h"
  55: 
  56: int errno;
  57: int keepalive = 1;
  58: int check_all = 0;
  59: /*VARARGS1*/
  60: int error();
  61: int sent_null;
  62: 
  63: /*ARGSUSED*/
  64: main(argc, argv)
  65:     int argc;
  66:     char **argv;
  67: {
  68:     extern int _check_rhosts_file;
  69:     struct linger linger;
  70:     int ch, on = 1, fromlen;
  71:     struct sockaddr_in from;
  72: 
  73:     openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  74: 
  75:     opterr = 0;
  76:     while ((ch = getopt(argc, argv, "aln")) != EOF)
  77:         switch (ch) {
  78:         case 'a':
  79:             check_all = 1;
  80:             break;
  81:         case 'l':
  82:             _check_rhosts_file = 0;
  83:             break;
  84:         case 'n':
  85:             keepalive = 0;
  86:             break;
  87:         case '?':
  88:         default:
  89:             syslog(LOG_ERR, "usage: rshd [-aln]");
  90:             break;
  91:         }
  92: 
  93:     argc -= optind;
  94:     argv += optind;
  95: 
  96:     fromlen = sizeof (from);
  97:     if (getpeername(0, &from, &fromlen) < 0) {
  98:         syslog(LOG_ERR, "getpeername: %m");
  99:         _exit(1);
 100:     }
 101:     if (keepalive &&
 102:         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
 103:         sizeof(on)) < 0)
 104:         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
 105:     linger.l_onoff = 1;
 106:     linger.l_linger = 60;           /* XXX */
 107:     if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
 108:         sizeof (linger)) < 0)
 109:         syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
 110:     doit(&from);
 111: }
 112: 
 113: char    username[20] = "USER=";
 114: char    homedir[64] = "HOME=";
 115: char    shell[64] = "SHELL=";
 116: char    *envinit[] =
 117:         {homedir, shell, _PATH_DEFPATH, username, 0};
 118: char    **environ;
 119: 
 120: doit(fromp)
 121:     struct sockaddr_in *fromp;
 122: {
 123:     char cmdbuf[NCARGS+1], *cp;
 124:     char locuser[16], remuser[16];
 125:     struct passwd *pwd;
 126:     int s;
 127:     struct hostent *hp;
 128:     char *hostname;
 129:     short port;
 130:     int pv[2], pid, cc;
 131:     int nfd;
 132:     fd_set ready, readfrom;
 133:     char buf[BUFSIZ], sig;
 134:     int one = 1;
 135:     char remotehost[2 * MAXHOSTNAMELEN + 1];
 136: 
 137:     (void) signal(SIGINT, SIG_DFL);
 138:     (void) signal(SIGQUIT, SIG_DFL);
 139:     (void) signal(SIGTERM, SIG_DFL);
 140: #ifdef DEBUG
 141:     { int t = open(_PATH_TTY, 2);
 142:       if (t >= 0) {
 143:         ioctl(t, TIOCNOTTY, (char *)0);
 144:         (void) close(t);
 145:       }
 146:     }
 147: #endif
 148:     fromp->sin_port = ntohs((u_short)fromp->sin_port);
 149:     if (fromp->sin_family != AF_INET) {
 150:         syslog(LOG_ERR, "malformed from address\n");
 151:         exit(1);
 152:     }
 153: #ifdef IP_OPTIONS
 154:       {
 155:     u_char optbuf[BUFSIZ/3], *cp;
 156:     char lbuf[BUFSIZ], *lp;
 157:     int optsize = sizeof(optbuf), ipproto;
 158:     struct protoent *ip;
 159: 
 160:     if ((ip = getprotobyname("ip")) != NULL)
 161:         ipproto = ip->p_proto;
 162:     else
 163:         ipproto = IPPROTO_IP;
 164:     if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 &&
 165:         optsize != 0) {
 166:         lp = lbuf;
 167:         for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
 168:             sprintf(lp, " %2.2x", *cp);
 169:         syslog(LOG_NOTICE,
 170:             "Connection received using IP options (ignored):%s", lbuf);
 171:         if (setsockopt(0, ipproto, IP_OPTIONS,
 172:             (char *)NULL, &optsize) != 0) {
 173:             syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
 174:             exit(1);
 175:         }
 176:     }
 177:       }
 178: #endif
 179: 
 180:     if (fromp->sin_port >= IPPORT_RESERVED ||
 181:         fromp->sin_port < IPPORT_RESERVED/2) {
 182:         syslog(LOG_NOTICE, "Connection from %s on illegal port",
 183:             inet_ntoa(fromp->sin_addr));
 184:         exit(1);
 185:     }
 186: 
 187:     (void) alarm(60);
 188:     port = 0;
 189:     for (;;) {
 190:         char c;
 191:         if ((cc = read(0, &c, 1)) != 1) {
 192:             if (cc < 0)
 193:                 syslog(LOG_NOTICE, "read: %m");
 194:             shutdown(0, 1+1);
 195:             exit(1);
 196:         }
 197:         if (c == 0)
 198:             break;
 199:         port = port * 10 + c - '0';
 200:     }
 201: 
 202:     (void) alarm(0);
 203:     if (port != 0) {
 204:         int lport = IPPORT_RESERVED - 1;
 205:         s = rresvport(&lport);
 206:         if (s < 0) {
 207:             syslog(LOG_ERR, "can't get stderr port: %m");
 208:             exit(1);
 209:         }
 210:         if (port >= IPPORT_RESERVED) {
 211:             syslog(LOG_ERR, "2nd port not reserved\n");
 212:             exit(1);
 213:         }
 214:         fromp->sin_port = htons((u_short)port);
 215:         if (connect(s, fromp, sizeof (*fromp)) < 0) {
 216:             syslog(LOG_INFO, "connect second port: %m");
 217:             exit(1);
 218:         }
 219:     }
 220: 
 221: #ifdef notdef
 222:     /* from inetd, socket is already on 0, 1, 2 */
 223:     dup2(f, 0);
 224:     dup2(f, 1);
 225:     dup2(f, 2);
 226: #endif
 227:     hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
 228:         fromp->sin_family);
 229:     if (hp) {
 230:         /*
 231: 		 * If name returned by gethostbyaddr is in our domain,
 232: 		 * attempt to verify that we haven't been fooled by someone
 233: 		 * in a remote net; look up the name and check that this
 234: 		 * address corresponds to the name.
 235: 		 */
 236:         if (check_all || local_domain(hp->h_name)) {
 237:             strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
 238:             remotehost[sizeof(remotehost) - 1] = 0;
 239: #ifdef  RES_DNSRCH
 240:             _res.options &= ~RES_DNSRCH;
 241: #endif
 242:             hp = gethostbyname(remotehost);
 243:             if (hp == NULL) {
 244:                 syslog(LOG_INFO,
 245:                     "Couldn't look up address for %s",
 246:                     remotehost);
 247:                 error("Couldn't look up address for your host\n");
 248:                 exit(1);
 249:             }
 250: #ifdef h_addr   /* 4.2 hack */
 251:             for (; ; hp->h_addr_list++) {
 252:                 if (!bcmp(hp->h_addr_list[0],
 253:                     (caddr_t)&fromp->sin_addr,
 254:                     sizeof(fromp->sin_addr)))
 255:                     break;
 256:                 if (hp->h_addr_list[0] == NULL) {
 257:                     syslog(LOG_NOTICE,
 258:                       "Host addr %s not listed for host %s",
 259:                         inet_ntoa(fromp->sin_addr),
 260:                         hp->h_name);
 261:                     error("Host address mismatch\n");
 262:                     exit(1);
 263:                 }
 264:             }
 265: #else
 266:             if (bcmp(hp->h_addr, (caddr_t)&fromp->sin_addr,
 267:                 sizeof(fromp->sin_addr))) {
 268:                 syslog(LOG_NOTICE,
 269:                   "Host addr %s not listed for host %s",
 270:                     inet_ntoa(fromp->sin_addr),
 271:                     hp->h_name);
 272:                 error("Host address mismatch\n");
 273:                 exit(1);
 274:             }
 275: #endif
 276:         }
 277:         hostname = hp->h_name;
 278:     } else
 279:         hostname = inet_ntoa(fromp->sin_addr);
 280: 
 281:     getstr(remuser, sizeof(remuser), "remuser");
 282:     getstr(locuser, sizeof(locuser), "locuser");
 283:     getstr(cmdbuf, sizeof(cmdbuf), "command");
 284:     setpwent();
 285:     pwd = getpwnam(locuser);
 286:     if (pwd == NULL) {
 287:         error("Login incorrect.\n");
 288:         exit(1);
 289:     }
 290:     if (chdir(pwd->pw_dir) < 0) {
 291:         (void) chdir("/");
 292: #ifdef notdef
 293:         error("No remote directory.\n");
 294:         exit(1);
 295: #endif
 296:     }
 297: 
 298:     if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
 299:         ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
 300:         error("Permission denied.\n");
 301:         exit(1);
 302:     }
 303: 
 304:     if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
 305:         error("Logins currently disabled.\n");
 306:         exit(1);
 307:     }
 308: 
 309:     (void) write(2, "\0", 1);
 310:     sent_null = 1;
 311: 
 312:     if (port) {
 313:         if (pipe(pv) < 0) {
 314:             error("Can't make pipe.\n");
 315:             exit(1);
 316:         }
 317:         pid = fork();
 318:         if (pid == -1)  {
 319:             error("Can't fork; try again.\n");
 320:             exit(1);
 321:         }
 322:         if (pv[0] > s)
 323:             nfd = pv[0];
 324:         else
 325:             nfd = s;
 326:         nfd++;
 327:         if (pid) {
 328:             (void) close(0); (void) close(1); (void) close(2);
 329:             (void) close(pv[1]);
 330:             FD_ZERO(&readfrom);
 331:             FD_SET(s, &readfrom);
 332:             FD_SET(pv[0], &readfrom);
 333:             ioctl(pv[0], FIONBIO, (char *)&one);
 334:             /* should set s nbio! */
 335:             do {
 336:                 ready = readfrom;
 337:                 if (select(nfd, &ready, (fd_set *)0,
 338:                     (fd_set *)0, (struct timeval *)0) < 0)
 339:                     break;
 340:                 if (FD_ISSET(s, &ready)) {
 341:                     if (read(s, &sig, 1) <= 0)
 342:                         FD_CLR(s, &readfrom);
 343:                     else
 344:                         killpg(pid, sig);
 345:                 }
 346:                 if (FD_ISSET(pv[0], &ready)) {
 347:                     errno = 0;
 348:                     cc = read(pv[0], buf, sizeof (buf));
 349:                     if (cc <= 0) {
 350:                         shutdown(s, 1+1);
 351:                         FD_CLR(pv[0], &readfrom);
 352:                     } else
 353:                         (void) write(s, buf, cc);
 354:                 }
 355:             } while (FD_ISSET(s, &readfrom) ||
 356:                 FD_ISSET(pv[0], &readfrom));
 357:             exit(0);
 358:         }
 359:         setpgrp(0, getpid());
 360:         (void) close(s); (void) close(pv[0]);
 361:         dup2(pv[1], 2);
 362:         close(pv[1]);
 363:     }
 364:     if (*pwd->pw_shell == '\0')
 365:         pwd->pw_shell = _PATH_BSHELL;
 366: #ifdef  FOURdotFOUR
 367:     if (setlogin(pwd->pw_name) < 0)
 368:         syslog(LOG_ERR, "setlogin() failed: %m");
 369: #endif
 370:     (void) setgid((gid_t)pwd->pw_gid);
 371:     initgroups(pwd->pw_name, pwd->pw_gid);
 372:     (void) setuid((uid_t)pwd->pw_uid);
 373:     environ = envinit;
 374:     strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
 375:     strncat(shell, pwd->pw_shell, sizeof(shell)-7);
 376:     strncat(username, pwd->pw_name, sizeof(username)-6);
 377:     cp = rindex(pwd->pw_shell, '/');
 378:     if (cp)
 379:         cp++;
 380:     else
 381:         cp = pwd->pw_shell;
 382:     endpwent();
 383:     if (pwd->pw_uid == 0)
 384:         syslog(LOG_INFO|LOG_AUTH, "ROOT shell from %s@%s, comm: %s\n",
 385:             remuser, hostname, cmdbuf);
 386:     execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
 387:     perror(pwd->pw_shell);
 388:     exit(1);
 389: }
 390: 
 391: /*
 392:  * Report error to client.
 393:  * Note: can't be used until second socket has connected
 394:  * to client, or older clients will hang waiting
 395:  * for that connection first.
 396:  */
 397: /*VARARGS1*/
 398: error(fmt, a1, a2, a3)
 399:     char *fmt;
 400:     int a1, a2, a3;
 401: {
 402:     char buf[BUFSIZ], *bp = buf;
 403: 
 404:     if (sent_null == 0)
 405:         *bp++ = 1;
 406:     (void) sprintf(bp, fmt, a1, a2, a3);
 407:     (void) write(2, buf, strlen(buf));
 408: }
 409: 
 410: getstr(buf, cnt, err)
 411:     char *buf;
 412:     int cnt;
 413:     char *err;
 414: {
 415:     char c;
 416: 
 417:     do {
 418:         if (read(0, &c, 1) != 1)
 419:             exit(1);
 420:         *buf++ = c;
 421:         if (--cnt == 0) {
 422:             error("%s too long\n", err);
 423:             exit(1);
 424:         }
 425:     } while (c != 0);
 426: }
 427: 
 428: /*
 429:  * Check whether host h is in our local domain,
 430:  * defined as sharing the last two components of the domain part,
 431:  * or the entire domain part if the local domain has only one component.
 432:  * If either name is unqualified (contains no '.'),
 433:  * assume that the host is local, as it will be
 434:  * interpreted as such.
 435:  */
 436: local_domain(h)
 437:     char *h;
 438: {
 439:     char localhost[MAXHOSTNAMELEN];
 440:     char *p1, *p2, *topdomain();
 441: 
 442:     localhost[0] = 0;
 443:     (void) gethostname(localhost, sizeof(localhost));
 444:     p1 = topdomain(localhost);
 445:     p2 = topdomain(h);
 446:     if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
 447:         return(1);
 448:     return(0);
 449: }
 450: 
 451: char *
 452: topdomain(h)
 453:     char *h;
 454: {
 455:     register char *p;
 456:     char *maybe = NULL;
 457:     int dots = 0;
 458: 
 459:     for (p = h + strlen(h); p >= h; p--) {
 460:         if (*p == '.') {
 461:             if (++dots == 2)
 462:                 return (p);
 463:             maybe = p;
 464:         }
 465:     }
 466:     return (maybe);
 467: }

Defined functions

doit defined in line 120; used 1 times
error defined in line 398; used 11 times
getstr defined in line 410; used 3 times
local_domain defined in line 436; used 1 times
main defined in line 64; never used
topdomain defined in line 451; used 3 times

Defined variables

check_all defined in line 58; used 2 times
copyright defined in line 19; never used
envinit defined in line 116; used 1 times
environ defined in line 118; used 1 times
errno defined in line 56; used 1 times
homedir defined in line 114; used 3 times
keepalive defined in line 57; used 2 times
sccsid defined in line 23; never used
sent_null defined in line 61; used 2 times
shell defined in line 115; used 3 times
username defined in line 113; used 3 times
Last modified: 1996-11-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4780
Valid CSS Valid XHTML 1.0 Strict