1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: char copyright[] = 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: #endif not lint 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)rshd.c 5.7 (Berkeley) 5/9/86"; 15: #endif not lint 16: 17: /* 18: * remote shell server: 19: * remuser\0 20: * locuser\0 21: * command\0 22: * data 23: */ 24: #include <sys/ioctl.h> 25: #include <sys/param.h> 26: #include <sys/socket.h> 27: #include <sys/time.h> 28: 29: #include <netinet/in.h> 30: 31: #include <arpa/inet.h> 32: 33: #include <stdio.h> 34: #include <errno.h> 35: #include <pwd.h> 36: #include <signal.h> 37: #include <netdb.h> 38: #include <syslog.h> 39: 40: int errno; 41: char *index(), *rindex(), *strncat(); 42: /*VARARGS1*/ 43: int error(); 44: 45: /*ARGSUSED*/ 46: main(argc, argv) 47: int argc; 48: char **argv; 49: { 50: struct linger linger; 51: int on = 1, fromlen; 52: struct sockaddr_in from; 53: 54: openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON); 55: fromlen = sizeof (from); 56: if (getpeername(0, &from, &fromlen) < 0) { 57: fprintf(stderr, "%s: ", argv[0]); 58: perror("getpeername"); 59: _exit(1); 60: } 61: if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 62: sizeof (on)) < 0) 63: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 64: linger.l_onoff = 1; 65: linger.l_linger = 60; /* XXX */ 66: if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 67: sizeof (linger)) < 0) 68: syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 69: doit(dup(0), &from); 70: } 71: 72: char username[20] = "USER="; 73: char homedir[64] = "HOME="; 74: char shell[64] = "SHELL="; 75: char *envinit[] = 76: {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; 77: char **environ; 78: 79: doit(f, fromp) 80: int f; 81: struct sockaddr_in *fromp; 82: { 83: char cmdbuf[NCARGS+1], *cp; 84: char locuser[16], remuser[16]; 85: struct passwd *pwd; 86: int s; 87: struct hostent *hp; 88: char *hostname; 89: short port; 90: int pv[2], pid, ready, readfrom, cc; 91: char buf[BUFSIZ], sig; 92: int one = 1; 93: 94: (void) signal(SIGINT, SIG_DFL); 95: (void) signal(SIGQUIT, SIG_DFL); 96: (void) signal(SIGTERM, SIG_DFL); 97: #ifdef DEBUG 98: { int t = open("/dev/tty", 2); 99: if (t >= 0) { 100: ioctl(t, TIOCNOTTY, (char *)0); 101: (void) close(t); 102: } 103: } 104: #endif 105: fromp->sin_port = ntohs((u_short)fromp->sin_port); 106: if (fromp->sin_family != AF_INET || 107: fromp->sin_port >= IPPORT_RESERVED) { 108: syslog(LOG_ERR, "malformed from address\n"); 109: exit(1); 110: } 111: (void) alarm(60); 112: port = 0; 113: for (;;) { 114: char c; 115: if (read(f, &c, 1) != 1) { 116: syslog(LOG_ERR, "read: %m"); 117: shutdown(f, 1+1); 118: exit(1); 119: } 120: if (c == 0) 121: break; 122: port = port * 10 + c - '0'; 123: } 124: (void) alarm(0); 125: if (port != 0) { 126: int lport = IPPORT_RESERVED - 1; 127: s = rresvport(&lport); 128: if (s < 0) { 129: syslog(LOG_ERR, "can't get stderr port: %m"); 130: exit(1); 131: } 132: if (port >= IPPORT_RESERVED) { 133: syslog(LOG_ERR, "2nd port not reserved\n"); 134: exit(1); 135: } 136: fromp->sin_port = htons((u_short)port); 137: if (connect(s, fromp, sizeof (*fromp)) < 0) { 138: syslog(LOG_INFO, "connect second port: %m"); 139: exit(1); 140: } 141: } 142: dup2(f, 0); 143: dup2(f, 1); 144: dup2(f, 2); 145: hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), 146: fromp->sin_family); 147: if (hp) 148: hostname = hp->h_name; 149: else 150: hostname = inet_ntoa(fromp->sin_addr); 151: getstr(remuser, sizeof(remuser), "remuser"); 152: getstr(locuser, sizeof(locuser), "locuser"); 153: getstr(cmdbuf, sizeof(cmdbuf), "command"); 154: setpwent(); 155: pwd = getpwnam(locuser); 156: if (pwd == NULL) { 157: error("Login incorrect.\n"); 158: exit(1); 159: } 160: endpwent(); 161: if (chdir(pwd->pw_dir) < 0) { 162: (void) chdir("/"); 163: #ifdef notdef 164: error("No remote directory.\n"); 165: exit(1); 166: #endif 167: } 168: if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 169: ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { 170: error("Permission denied.\n"); 171: exit(1); 172: } 173: (void) write(2, "\0", 1); 174: if (port) { 175: if (pipe(pv) < 0) { 176: error("Can't make pipe.\n"); 177: exit(1); 178: } 179: pid = fork(); 180: if (pid == -1) { 181: error("Try again.\n"); 182: exit(1); 183: } 184: if (pid) { 185: (void) close(0); (void) close(1); (void) close(2); 186: (void) close(f); (void) close(pv[1]); 187: readfrom = (1<<s) | (1<<pv[0]); 188: ioctl(pv[1], FIONBIO, (char *)&one); 189: /* should set s nbio! */ 190: do { 191: ready = readfrom; 192: if (select(16, &ready, (fd_set *)0, 193: (fd_set *)0, (struct timeval *)0) < 0) 194: break; 195: if (ready & (1<<s)) { 196: if (read(s, &sig, 1) <= 0) 197: readfrom &= ~(1<<s); 198: else 199: killpg(pid, sig); 200: } 201: if (ready & (1<<pv[0])) { 202: errno = 0; 203: cc = read(pv[0], buf, sizeof (buf)); 204: if (cc <= 0) { 205: shutdown(s, 1+1); 206: readfrom &= ~(1<<pv[0]); 207: } else 208: (void) write(s, buf, cc); 209: } 210: } while (readfrom); 211: exit(0); 212: } 213: setpgrp(0, getpid()); 214: (void) close(s); (void) close(pv[0]); 215: dup2(pv[1], 2); 216: } 217: if (*pwd->pw_shell == '\0') 218: pwd->pw_shell = "/bin/sh"; 219: (void) close(f); 220: (void) setgid((gid_t)pwd->pw_gid); 221: initgroups(pwd->pw_name, pwd->pw_gid); 222: (void) setuid((uid_t)pwd->pw_uid); 223: environ = envinit; 224: strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 225: strncat(shell, pwd->pw_shell, sizeof(shell)-7); 226: strncat(username, pwd->pw_name, sizeof(username)-6); 227: cp = rindex(pwd->pw_shell, '/'); 228: if (cp) 229: cp++; 230: else 231: cp = pwd->pw_shell; 232: execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 233: perror(pwd->pw_shell); 234: exit(1); 235: } 236: 237: /*VARARGS1*/ 238: error(fmt, a1, a2, a3) 239: char *fmt; 240: int a1, a2, a3; 241: { 242: char buf[BUFSIZ]; 243: 244: buf[0] = 1; 245: (void) sprintf(buf+1, fmt, a1, a2, a3); 246: (void) write(2, buf, strlen(buf)); 247: } 248: 249: getstr(buf, cnt, err) 250: char *buf; 251: int cnt; 252: char *err; 253: { 254: char c; 255: 256: do { 257: if (read(0, &c, 1) != 1) 258: exit(1); 259: *buf++ = c; 260: if (--cnt == 0) { 261: error("%s too long\n", err); 262: exit(1); 263: } 264: } while (c != 0); 265: }