|
|
1.1 ! root 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 provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1983, 1988, 1089 The Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)rshd.c 5.36.1.1 (Berkeley) 10/21/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* From: ! 31: * $Source: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v $ ! 32: * $Header: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v 5.2 89/07/31 19:30:04 kfall Exp $ ! 33: */ ! 34: ! 35: ! 36: /* ! 37: * remote shell server: ! 38: * [port]\0 ! 39: * remuser\0 ! 40: * locuser\0 ! 41: * command\0 ! 42: * data ! 43: */ ! 44: #include <sys/param.h> ! 45: #include <sys/ioctl.h> ! 46: #include <sys/socket.h> ! 47: #include <sys/file.h> ! 48: #include <sys/signal.h> ! 49: #include <sys/time.h> ! 50: ! 51: #include <netinet/in.h> ! 52: ! 53: #include <arpa/inet.h> ! 54: ! 55: #include <stdio.h> ! 56: #include <errno.h> ! 57: #include <pwd.h> ! 58: #include <netdb.h> ! 59: #include <syslog.h> ! 60: #include "pathnames.h" ! 61: ! 62: int errno; ! 63: int keepalive = 1; ! 64: int check_all = 0; ! 65: char *index(), *rindex(), *strncat(); ! 66: /*VARARGS1*/ ! 67: int error(); ! 68: int sent_null; ! 69: ! 70: #ifdef KERBEROS ! 71: #include <kerberosIV/des.h> ! 72: #include <kerberosIV/krb.h> ! 73: #define VERSION_SIZE 9 ! 74: #define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n" ! 75: #define OPTIONS "alknvx" ! 76: char authbuf[sizeof(AUTH_DAT)]; ! 77: char tickbuf[sizeof(KTEXT_ST)]; ! 78: int use_kerberos = 0, vacuous = 0; ! 79: int encrypt = 0; ! 80: Key_schedule schedule; ! 81: #else ! 82: #define OPTIONS "aln" ! 83: #endif ! 84: ! 85: /*ARGSUSED*/ ! 86: main(argc, argv) ! 87: int argc; ! 88: char **argv; ! 89: { ! 90: extern int opterr, optind; ! 91: extern int _check_rhosts_file; ! 92: struct linger linger; ! 93: int ch, on = 1, fromlen; ! 94: struct sockaddr_in from; ! 95: ! 96: openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); ! 97: ! 98: opterr = 0; ! 99: while ((ch = getopt(argc, argv, OPTIONS)) != EOF) ! 100: switch (ch) { ! 101: case 'a': ! 102: check_all = 1; ! 103: break; ! 104: case 'l': ! 105: _check_rhosts_file = 0; ! 106: break; ! 107: case 'n': ! 108: keepalive = 0; ! 109: break; ! 110: #ifdef KERBEROS ! 111: case 'k': ! 112: use_kerberos = 1; ! 113: break; ! 114: ! 115: case 'v': ! 116: vacuous = 1; ! 117: break; ! 118: ! 119: #endif ! 120: case '?': ! 121: default: ! 122: usage(); ! 123: exit(2); ! 124: } ! 125: ! 126: argc -= optind; ! 127: argv += optind; ! 128: ! 129: #ifdef KERBEROS ! 130: if (use_kerberos && vacuous) { ! 131: syslog(LOG_ERR, "only one of -k and -v allowed"); ! 132: exit(2); ! 133: } ! 134: #endif ! 135: ! 136: fromlen = sizeof (from); ! 137: if (getpeername(0, &from, &fromlen) < 0) { ! 138: syslog(LOG_ERR, "getpeername: %m"); ! 139: _exit(1); ! 140: } ! 141: if (keepalive && ! 142: setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, ! 143: sizeof(on)) < 0) ! 144: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); ! 145: linger.l_onoff = 1; ! 146: linger.l_linger = 60; /* XXX */ ! 147: if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, ! 148: sizeof (linger)) < 0) ! 149: syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); ! 150: doit(&from); ! 151: } ! 152: ! 153: char username[20] = "USER="; ! 154: char homedir[64] = "HOME="; ! 155: char shell[64] = "SHELL="; ! 156: char *envinit[] = ! 157: {homedir, shell, _PATH_DEFPATH, username, 0}; ! 158: char **environ; ! 159: ! 160: doit(fromp) ! 161: struct sockaddr_in *fromp; ! 162: { ! 163: char cmdbuf[NCARGS+1], *cp; ! 164: char locuser[16], remuser[16]; ! 165: struct passwd *pwd; ! 166: int s; ! 167: struct hostent *hp; ! 168: char *hostname, *errorstr = NULL, *errorhost; ! 169: u_short port; ! 170: int pv[2], pid, cc; ! 171: int nfd; ! 172: fd_set ready, readfrom; ! 173: char buf[BUFSIZ], sig; ! 174: int one = 1; ! 175: char remotehost[2 * MAXHOSTNAMELEN + 1]; ! 176: ! 177: #ifdef KERBEROS ! 178: AUTH_DAT *kdata = (AUTH_DAT *) NULL; ! 179: KTEXT ticket = (KTEXT) NULL; ! 180: char instance[INST_SZ], version[VERSION_SIZE]; ! 181: struct sockaddr_in fromaddr; ! 182: int rc; ! 183: long authopts; ! 184: int pv1[2], pv2[2]; ! 185: fd_set wready, writeto; ! 186: ! 187: fromaddr = *fromp; ! 188: #endif ! 189: ! 190: (void) signal(SIGINT, SIG_DFL); ! 191: (void) signal(SIGQUIT, SIG_DFL); ! 192: (void) signal(SIGTERM, SIG_DFL); ! 193: #ifdef DEBUG ! 194: { int t = open(_PATH_TTY, 2); ! 195: if (t >= 0) { ! 196: ioctl(t, TIOCNOTTY, (char *)0); ! 197: (void) close(t); ! 198: } ! 199: } ! 200: #endif ! 201: fromp->sin_port = ntohs((u_short)fromp->sin_port); ! 202: if (fromp->sin_family != AF_INET) { ! 203: syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", ! 204: fromp->sin_family); ! 205: exit(1); ! 206: } ! 207: #ifdef IP_OPTIONS ! 208: { ! 209: u_char optbuf[BUFSIZ/3], *cp; ! 210: char lbuf[BUFSIZ], *lp; ! 211: int optsize = sizeof(optbuf), ipproto; ! 212: struct protoent *ip; ! 213: ! 214: if ((ip = getprotobyname("ip")) != NULL) ! 215: ipproto = ip->p_proto; ! 216: else ! 217: ipproto = IPPROTO_IP; ! 218: if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && ! 219: optsize != 0) { ! 220: lp = lbuf; ! 221: for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) ! 222: sprintf(lp, " %2.2x", *cp); ! 223: syslog(LOG_NOTICE, ! 224: "Connection received from %s using IP options (ignored):%s", ! 225: inet_ntoa(fromp->sin_addr), lbuf); ! 226: if (setsockopt(0, ipproto, IP_OPTIONS, ! 227: (char *)NULL, &optsize) != 0) { ! 228: syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); ! 229: exit(1); ! 230: } ! 231: } ! 232: } ! 233: #endif ! 234: ! 235: #ifdef KERBEROS ! 236: if (!use_kerberos) ! 237: #endif ! 238: if (fromp->sin_port >= IPPORT_RESERVED || ! 239: fromp->sin_port < IPPORT_RESERVED/2) { ! 240: syslog(LOG_NOTICE|LOG_AUTH, ! 241: "Connection from %s on illegal port", ! 242: inet_ntoa(fromp->sin_addr)); ! 243: exit(1); ! 244: } ! 245: ! 246: (void) alarm(60); ! 247: port = 0; ! 248: for (;;) { ! 249: char c; ! 250: if ((cc = read(0, &c, 1)) != 1) { ! 251: if (cc < 0) ! 252: syslog(LOG_NOTICE, "read: %m"); ! 253: shutdown(0, 1+1); ! 254: exit(1); ! 255: } ! 256: if (c== 0) ! 257: break; ! 258: port = port * 10 + c - '0'; ! 259: } ! 260: ! 261: (void) alarm(0); ! 262: if (port != 0) { ! 263: int lport = IPPORT_RESERVED - 1; ! 264: s = rresvport(&lport); ! 265: if (s < 0) { ! 266: syslog(LOG_ERR, "can't get stderr port: %m"); ! 267: exit(1); ! 268: } ! 269: #ifdef KERBEROS ! 270: if (!use_kerberos) ! 271: #endif ! 272: if (port >= IPPORT_RESERVED) { ! 273: syslog(LOG_ERR, "2nd port not reserved\n"); ! 274: exit(1); ! 275: } ! 276: fromp->sin_port = htons(port); ! 277: if (connect(s, fromp, sizeof (*fromp)) < 0) { ! 278: syslog(LOG_INFO, "connect second port: %m"); ! 279: exit(1); ! 280: } ! 281: } ! 282: ! 283: #ifdef KERBEROS ! 284: if (vacuous) { ! 285: error("rshd: remote host requires Kerberos authentication\n"); ! 286: exit(1); ! 287: } ! 288: #endif ! 289: ! 290: #ifdef notdef ! 291: /* from inetd, socket is already on 0, 1, 2 */ ! 292: dup2(f, 0); ! 293: dup2(f, 1); ! 294: dup2(f, 2); ! 295: #endif ! 296: hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), ! 297: fromp->sin_family); ! 298: if (hp) { ! 299: /* ! 300: * If name returned by gethostbyaddr is in our domain, ! 301: * attempt to verify that we haven't been fooled by someone ! 302: * in a remote net; look up the name and check that this ! 303: * address corresponds to the name. ! 304: */ ! 305: hostname = hp->h_name; ! 306: #ifdef KERBEROS ! 307: if (!use_kerberos) ! 308: #endif ! 309: if (check_all || local_domain(hp->h_name)) { ! 310: strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); ! 311: remotehost[sizeof(remotehost) - 1] = 0; ! 312: errorhost = remotehost; ! 313: hp = gethostbyname(remotehost); ! 314: if (hp == NULL) { ! 315: syslog(LOG_INFO, ! 316: "Couldn't look up address for %s", ! 317: remotehost); ! 318: errorstr = ! 319: "Couldn't look up address for your host (%s)\n"; ! 320: hostname = inet_ntoa(fromp->sin_addr); ! 321: } else for (; ; hp->h_addr_list++) { ! 322: if (hp->h_addr_list[0] == NULL) { ! 323: syslog(LOG_NOTICE, ! 324: "Host addr %s not listed for host %s", ! 325: inet_ntoa(fromp->sin_addr), ! 326: hp->h_name); ! 327: errorstr = ! 328: "Host address mismatch for %s\n"; ! 329: hostname = inet_ntoa(fromp->sin_addr); ! 330: break; ! 331: } ! 332: if (!bcmp(hp->h_addr_list[0], ! 333: (caddr_t)&fromp->sin_addr, ! 334: sizeof(fromp->sin_addr))) { ! 335: hostname = hp->h_name; ! 336: break; ! 337: } ! 338: } ! 339: } ! 340: } else ! 341: errorhost = hostname = inet_ntoa(fromp->sin_addr); ! 342: ! 343: #ifdef KERBEROS ! 344: if (use_kerberos) { ! 345: kdata = (AUTH_DAT *) authbuf; ! 346: ticket = (KTEXT) tickbuf; ! 347: authopts = 0L; ! 348: strcpy(instance, "*"); ! 349: version[VERSION_SIZE - 1] = '\0'; ! 350: rc = krb_recvauth(authopts, 0, ticket, "rcmd", ! 351: instance, &fromaddr, ! 352: (struct sockaddr_in *) 0, ! 353: kdata, "", (bit_64 *) 0, version); ! 354: if (rc != KSUCCESS) { ! 355: error("Kerberos authentication failure: %s\n", ! 356: krb_err_txt[rc]); ! 357: exit(1); ! 358: } ! 359: } else ! 360: #endif ! 361: getstr(remuser, sizeof(remuser), "remuser"); ! 362: ! 363: getstr(locuser, sizeof(locuser), "locuser"); ! 364: getstr(cmdbuf, sizeof(cmdbuf), "command"); ! 365: setpwent(); ! 366: pwd = getpwnam(locuser); ! 367: if (pwd == NULL) { ! 368: if (errorstr == NULL) ! 369: errorstr = "Login incorrect.\n"; ! 370: goto fail; ! 371: } ! 372: if (chdir(pwd->pw_dir) < 0) { ! 373: (void) chdir("/"); ! 374: #ifdef notdef ! 375: error("No remote directory.\n"); ! 376: exit(1); ! 377: #endif ! 378: } ! 379: ! 380: #ifdef KERBEROS ! 381: if (use_kerberos) { ! 382: if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { ! 383: if (kuserok(kdata, locuser) != 0) { ! 384: syslog(LOG_NOTICE|LOG_AUTH, ! 385: "Kerberos rsh denied to %s.%s@%s", ! 386: kdata->pname, kdata->pinst, kdata->prealm); ! 387: error("Permission denied.\n"); ! 388: exit(1); ! 389: } ! 390: } ! 391: } else ! 392: #endif ! 393: ! 394: if (errorstr || ! 395: pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && ! 396: ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { ! 397: fail: ! 398: if (errorstr == NULL) ! 399: errorstr = "Permission denied.\n"; ! 400: error(errorstr, errorhost); ! 401: exit(1); ! 402: } ! 403: ! 404: if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { ! 405: error("Logins currently disabled.\n"); ! 406: exit(1); ! 407: } ! 408: ! 409: (void) write(2, "\0", 1); ! 410: sent_null = 1; ! 411: ! 412: if (port) { ! 413: if (pipe(pv) < 0) { ! 414: error("Can't make pipe.\n"); ! 415: exit(1); ! 416: } ! 417: pid = fork(); ! 418: if (pid == -1) { ! 419: error("Can't fork; try again.\n"); ! 420: exit(1); ! 421: } ! 422: if (pid) { ! 423: { ! 424: (void) close(0); (void) close(1); ! 425: } ! 426: (void) close(2); (void) close(pv[1]); ! 427: ! 428: FD_ZERO(&readfrom); ! 429: FD_SET(s, &readfrom); ! 430: FD_SET(pv[0], &readfrom); ! 431: if (pv[0] > s) ! 432: nfd = pv[0]; ! 433: else ! 434: nfd = s; ! 435: ioctl(pv[0], FIONBIO, (char *)&one); ! 436: ! 437: /* should set s nbio! */ ! 438: nfd++; ! 439: do { ! 440: ready = readfrom; ! 441: if (select(nfd, &ready, (fd_set *)0, ! 442: (fd_set *)0, (struct timeval *)0) < 0) ! 443: break; ! 444: if (FD_ISSET(s, &ready)) { ! 445: int ret; ! 446: ret = read(s, &sig, 1); ! 447: if (ret <= 0) ! 448: FD_CLR(s, &readfrom); ! 449: else ! 450: killpg(pid, sig); ! 451: } ! 452: if (FD_ISSET(pv[0], &ready)) { ! 453: errno = 0; ! 454: cc = read(pv[0], buf, sizeof(buf)); ! 455: if (cc <= 0) { ! 456: shutdown(s, 1+1); ! 457: FD_CLR(pv[0], &readfrom); ! 458: } else { ! 459: (void) ! 460: write(s, buf, cc); ! 461: } ! 462: } ! 463: ! 464: } while (FD_ISSET(s, &readfrom) || ! 465: FD_ISSET(pv[0], &readfrom)); ! 466: exit(0); ! 467: } ! 468: setpgrp(0, getpid()); ! 469: (void) close(s); (void) close(pv[0]); ! 470: dup2(pv[1], 2); ! 471: close(pv[1]); ! 472: } ! 473: if (*pwd->pw_shell == '\0') ! 474: pwd->pw_shell = _PATH_BSHELL; ! 475: #if BSD > 43 ! 476: if (setlogin(pwd->pw_name) < 0) ! 477: syslog(LOG_ERR, "setlogin() failed: %m"); ! 478: #endif ! 479: (void) setgid((gid_t)pwd->pw_gid); ! 480: initgroups(pwd->pw_name, pwd->pw_gid); ! 481: (void) setuid((uid_t)pwd->pw_uid); ! 482: environ = envinit; ! 483: strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); ! 484: strncat(shell, pwd->pw_shell, sizeof(shell)-7); ! 485: strncat(username, pwd->pw_name, sizeof(username)-6); ! 486: cp = rindex(pwd->pw_shell, '/'); ! 487: if (cp) ! 488: cp++; ! 489: else ! 490: cp = pwd->pw_shell; ! 491: endpwent(); ! 492: if (pwd->pw_uid == 0) { ! 493: #ifdef KERBEROS ! 494: if (use_kerberos) ! 495: syslog(LOG_INFO|LOG_AUTH, ! 496: "ROOT Kerberos shell from %s.%s@%s on %s, comm: %s\n", ! 497: kdata->pname, kdata->pinst, kdata->prealm, ! 498: hostname, cmdbuf); ! 499: else ! 500: #endif ! 501: syslog(LOG_INFO|LOG_AUTH, ! 502: "ROOT shell from %s@%s, comm: %s\n", ! 503: remuser, hostname, cmdbuf); ! 504: } ! 505: execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); ! 506: perror(pwd->pw_shell); ! 507: exit(1); ! 508: } ! 509: ! 510: /* ! 511: * Report error to client. ! 512: * Note: can't be used until second socket has connected ! 513: * to client, or older clients will hang waiting ! 514: * for that connection first. ! 515: */ ! 516: /*VARARGS1*/ ! 517: error(fmt, a1, a2, a3) ! 518: char *fmt; ! 519: int a1, a2, a3; ! 520: { ! 521: char buf[BUFSIZ], *bp = buf; ! 522: ! 523: if (sent_null == 0) ! 524: *bp++ = 1; ! 525: (void) sprintf(bp, fmt, a1, a2, a3); ! 526: (void) write(2, buf, strlen(buf)); ! 527: } ! 528: ! 529: getstr(buf, cnt, err) ! 530: char *buf; ! 531: int cnt; ! 532: char *err; ! 533: { ! 534: char c; ! 535: ! 536: do { ! 537: if (read(0, &c, 1) != 1) ! 538: exit(1); ! 539: *buf++ = c; ! 540: if (--cnt == 0) { ! 541: error("%s too long\n", err); ! 542: exit(1); ! 543: } ! 544: } while (c != 0); ! 545: } ! 546: ! 547: /* ! 548: * Check whether host h is in our local domain, ! 549: * defined as sharing the last two components of the domain part, ! 550: * or the entire domain part if the local domain has only one component. ! 551: * If either name is unqualified (contains no '.'), ! 552: * assume that the host is local, as it will be ! 553: * interpreted as such. ! 554: */ ! 555: local_domain(h) ! 556: char *h; ! 557: { ! 558: char localhost[MAXHOSTNAMELEN]; ! 559: char *p1, *p2, *topdomain(); ! 560: ! 561: localhost[0] = 0; ! 562: (void) gethostname(localhost, sizeof(localhost)); ! 563: p1 = topdomain(localhost); ! 564: p2 = topdomain(h); ! 565: if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) ! 566: return(1); ! 567: return(0); ! 568: } ! 569: ! 570: char * ! 571: topdomain(h) ! 572: char *h; ! 573: { ! 574: register char *p; ! 575: char *maybe = NULL; ! 576: int dots = 0; ! 577: ! 578: for (p = h + strlen(h); p >= h; p--) { ! 579: if (*p == '.') { ! 580: if (++dots == 2) ! 581: return (p); ! 582: maybe = p; ! 583: } ! 584: } ! 585: return (maybe); ! 586: } ! 587: ! 588: usage() ! 589: { ! 590: syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); ! 591: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.