# 2.11BSD#431 - /usr/src/libexec/rshd/rshd.c

##### Functions

    doit              X
    error             X
    getstr            X
    local_domain      X
    main              X
    topdomain         X

##### Variables

    check_all         X
    copyright         X
    envinit           X
    environ           X
    errno             X
    homedir           X
    keepalive         X
    sent_null         X
    shell             X
    username          X

       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

- in line 110

error defined in line 398; used 11 times

- in line 60, 247, 261, 272, 287, 293, 300-305(2), 314-319(2), 422

getstr defined in line 410; used 3 times

- in line 281-283(3)

local_domain defined in line 436; used 1 times

- in line 236

main defined in line 64; never used
topdomain defined in line 451; used 3 times

- in line 440-445(3)

#### Defined variables

check_all defined in line 58; used 2 times

- in line 79, 236

copyright defined in line 19; never used
envinit defined in line 116; used 1 times

- in line 373

environ defined in line 118; used 1 times

- in line 373

errno defined in line 56; used 1 times

- in line 347

homedir defined in line 114; used 3 times

- in line 117, 374(2)

keepalive defined in line 57; used 2 times

- in line 85, 101

sccsid defined in line 23; never used
sent_null defined in line 61; used 2 times

- in line 310, 404

shell defined in line 115; used 3 times

- in line 117, 375(2)

username defined in line 113; used 3 times

- in line 117, 376(2)

Last modified: 1996-11-30 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1831 |