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: }