1: /* 2: * Copyright (c) 1983, 1988 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 The Regents of the University of California.\n\ 21: All rights reserved.\n"; 22: 23: static char sccsid[] = "@(#)rlogind.c 5.22.1.8 (2.11BSD) 1996/3/22"; 24: #endif 25: 26: /* 27: * remote login server: 28: * \0 29: * remuser\0 30: * locuser\0 31: * terminal_type/speed\0 32: * data 33: * 34: * Automatic login protocol is done here, using login -f upon success, 35: * unless OLD_LOGIN is defined (then done in login, ala 4.2/4.3BSD). 36: */ 37: 38: #include <stdio.h> 39: #include <sys/param.h> 40: #include <sys/stat.h> 41: #include <sys/socket.h> 42: #include <sys/wait.h> 43: #include <sys/file.h> 44: #include <sys/ioctl.h> 45: #ifdef FOURdotFOUR 46: #include <sys/termios.h> 47: #endif 48: 49: #include <netinet/in.h> 50: 51: #include <errno.h> 52: #include <pwd.h> 53: #include <signal.h> 54: #include <stdio.h> 55: #include <netdb.h> 56: #include <syslog.h> 57: #include <strings.h> 58: #include <arpa/nameser.h> 59: #include <resolv.h> 60: 61: #ifndef TIOCPKT_WINDOW 62: #define TIOCPKT_WINDOW 0x80 63: #endif 64: 65: char *env[2]; 66: #define NMAX 30 67: char lusername[NMAX+1], rusername[NMAX+1]; 68: static char term[64] = "TERM="; 69: #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 70: int keepalive = 1; 71: int check_all = 0; 72: 73: #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 74: 75: int reapchild(); 76: struct passwd *getpwnam(), *pwd; 77: 78: main(argc, argv) 79: int argc; 80: char **argv; 81: { 82: extern int opterr, optind, _check_rhosts_file; 83: int ch; 84: int on = 1, fromlen; 85: struct sockaddr_in from; 86: 87: openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 88: 89: opterr = 0; 90: while ((ch = getopt(argc, argv, "aln")) != EOF) 91: switch (ch) { 92: case 'a': 93: check_all = 1; 94: break; 95: case 'l': 96: _check_rhosts_file = 0; 97: break; 98: case 'n': 99: keepalive = 0; 100: break; 101: case '?': 102: default: 103: syslog(LOG_ERR, "usage: rlogind [-a] [-l] [-n]"); 104: break; 105: } 106: argc -= optind; 107: argv += optind; 108: 109: fromlen = sizeof (from); 110: if (getpeername(0, &from, &fromlen) < 0) { 111: syslog(LOG_ERR, "Couldn't get peer name of remote host: %m"); 112: fatalperror("Can't get peer name of remote host"); 113: } 114: if (keepalive && 115: setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 116: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 117: doit(0, &from); 118: } 119: 120: int child; 121: int cleanup(); 122: int netf; 123: char *line; 124: extern char *inet_ntoa(); 125: 126: struct winsize win = { 0, 0, 0, 0 }; 127: 128: 129: doit(f, fromp) 130: int f; 131: struct sockaddr_in *fromp; 132: { 133: int i, p, t, pid, on = 1; 134: #ifndef OLD_LOGIN 135: int authenticated = 0, hostok = 0; 136: char remotehost[2 * MAXHOSTNAMELEN + 1]; 137: #endif 138: register struct hostent *hp; 139: struct hostent hostent; 140: char c; 141: 142: alarm(60); 143: read(f, &c, 1); 144: if (c != 0) 145: exit(1); 146: 147: alarm(0); 148: fromp->sin_port = ntohs((u_short)fromp->sin_port); 149: hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 150: fromp->sin_family); 151: if (hp == 0) { 152: /* 153: * Only the name is used below. 154: */ 155: hp = &hostent; 156: hp->h_name = inet_ntoa(fromp->sin_addr); 157: #ifndef OLD_LOGIN 158: hostok++; 159: #endif 160: } 161: #ifndef OLD_LOGIN 162: else if (check_all || local_domain(hp->h_name)) { 163: /* 164: * If name returned by gethostbyaddr is in our domain, 165: * attempt to verify that we haven't been fooled by someone 166: * in a remote net; look up the name and check that this 167: * address corresponds to the name. 168: */ 169: strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 170: remotehost[sizeof(remotehost) - 1] = 0; 171: #ifdef RES_DNSRCH 172: /* 173: * gethostbyaddr returns a FQDN, so now the domain search 174: * action must be turned off to avoid unwanted queries to 175: * the nameservor. 176: */ 177: _res.options &= ~RES_DNSRCH; 178: #endif RES_DNSRCH 179: hp = gethostbyname(remotehost); 180: if (hp) 181: #ifdef h_addr /* 4.2 hack */ 182: for (; hp->h_addr_list[0]; hp->h_addr_list++) 183: if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 184: sizeof(fromp->sin_addr))) { 185: hostok++; 186: break; 187: } 188: #else 189: if (!bcmp(hp->h_addr, (caddr_t)&fromp->sin_addr, 190: sizeof(fromp->sin_addr))) 191: hostok++; 192: #endif 193: } else 194: hostok++; 195: #endif /* OLD_LOGIN */ 196: 197: if (fromp->sin_family != AF_INET || 198: fromp->sin_port >= IPPORT_RESERVED || 199: fromp->sin_port < IPPORT_RESERVED/2) { 200: syslog(LOG_NOTICE, "Connection from %s on illegal port", 201: inet_ntoa(fromp->sin_addr)); 202: fatal(f, "Permission denied"); 203: } 204: #ifdef IP_OPTIONS 205: { 206: u_char optbuf[BUFSIZ/3], *cp; 207: char lbuf[BUFSIZ], *lp; 208: int optsize = sizeof(optbuf), ipproto; 209: struct protoent *ip; 210: 211: if ((ip = getprotobyname("ip")) != NULL) 212: ipproto = ip->p_proto; 213: else 214: ipproto = IPPROTO_IP; 215: if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 && 216: optsize != 0) { 217: lp = lbuf; 218: for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 219: sprintf(lp, " %2.2x", *cp); 220: syslog(LOG_NOTICE, 221: "Connection received using IP options (ignored):%s", lbuf); 222: if (setsockopt(0, ipproto, IP_OPTIONS, 223: (char *)NULL, &optsize) != 0) { 224: syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 225: exit(1); 226: } 227: } 228: } 229: #endif 230: write(f, "", 1); 231: #ifndef OLD_LOGIN 232: if (do_rlogin(hp->h_name) == 0) { 233: if (hostok) 234: authenticated++; 235: else 236: write(f, "rlogind: Host address mismatch.\r\n", 237: sizeof("rlogind: Host address mismatch.\r\n") - 1); 238: } 239: #endif 240: 241: for (c = 'p'; c <= 's'; c++) { 242: struct stat stb; 243: line = "/dev/ptyXX"; 244: line[strlen("/dev/pty")] = c; 245: line[strlen("/dev/ptyp")] = '0'; 246: if (stat(line, &stb) < 0) 247: break; 248: for (i = 0; i < 16; i++) { 249: line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 250: p = open(line, O_RDWR); 251: if (p > 0) 252: goto gotpty; 253: } 254: } 255: fatal(f, "Out of ptys"); 256: /*NOTREACHED*/ 257: gotpty: 258: (void) ioctl(p, TIOCSWINSZ, &win); 259: netf = f; 260: line[strlen("/dev/")] = 't'; 261: t = open(line, O_RDWR); 262: if (t < 0) 263: fatalperror(f, line); 264: if (fchmod(t, 0)) 265: fatalperror(f, line); 266: (void)signal(SIGHUP, SIG_IGN); 267: vhangup(); 268: (void)signal(SIGHUP, SIG_DFL); 269: t = open(line, O_RDWR); 270: if (t < 0) 271: fatalperror(f, line); 272: setup_term(t); 273: pid = fork(); 274: if (pid < 0) 275: fatalperror(f, ""); 276: if (pid == 0) { 277: #ifdef FOURdotFOUR 278: if (setsid() < 0) 279: fatalperror(f, "setsid"); 280: if (ioctl(t, TIOCSCTTY, 0) < 0) 281: fatalperror(f, "ioctl(sctty)"); 282: #endif 283: close(f), close(p); 284: dup2(t, 0), dup2(t, 1), dup2(t, 2); 285: close(t); 286: #ifdef OLD_LOGIN 287: execl("/bin/login", "login", "-r", hp->h_name, 0); 288: #else /* OLD_LOGIN */ 289: if (authenticated) 290: execl("/bin/login", "login", "-p", "-h", hp->h_name, 291: "-f", lusername, 0); 292: else 293: execl("/bin/login", "login", "-p", "-h", hp->h_name, 294: lusername, 0); 295: #endif /* OLD_LOGIN */ 296: fatalperror(2, "/bin/login"); 297: /*NOTREACHED*/ 298: } 299: #ifndef DEBUG 300: { 301: int tt = open("/dev/tty", O_RDWR); 302: if (tt > 0) { 303: (void)ioctl(tt, TIOCNOTTY, 0); 304: (void)close(tt); 305: } 306: } 307: #endif 308: close(t); 309: 310: ioctl(f, FIONBIO, &on); 311: ioctl(p, FIONBIO, &on); 312: ioctl(p, TIOCPKT, &on); 313: signal(SIGTSTP, SIG_IGN); 314: signal(SIGCHLD, cleanup); 315: setpgrp(0, 0); 316: protocol(f, p); 317: signal(SIGCHLD, SIG_IGN); 318: cleanup(); 319: } 320: 321: char magic[2] = { 0377, 0377 }; 322: char oobdata[] = {TIOCPKT_WINDOW}; 323: 324: /* 325: * Handle a "control" request (signaled by magic being present) 326: * in the data stream. For now, we are only willing to handle 327: * window size changes. 328: */ 329: control(pty, cp, n) 330: int pty; 331: char *cp; 332: int n; 333: { 334: struct winsize w; 335: 336: if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 337: return (0); 338: oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 339: bcopy(cp+4, (char *)&w, sizeof(w)); 340: w.ws_row = ntohs(w.ws_row); 341: w.ws_col = ntohs(w.ws_col); 342: w.ws_xpixel = ntohs(w.ws_xpixel); 343: w.ws_ypixel = ntohs(w.ws_ypixel); 344: (void)ioctl(pty, TIOCSWINSZ, &w); 345: return (4+sizeof (w)); 346: } 347: 348: /* 349: * rlogin "protocol" machine. 350: */ 351: protocol(f, p) 352: register int f, p; 353: { 354: char pibuf[1024], fibuf[1024], *pbp, *fbp; 355: register pcc = 0, fcc = 0; 356: int cc, nfd, n; 357: char cntl; 358: 359: /* 360: * Must ignore SIGTTOU, otherwise we'll stop 361: * when we try and set slave pty's window shape 362: * (our controlling tty is the master pty). 363: */ 364: (void) signal(SIGTTOU, SIG_IGN); 365: send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 366: if (f > p) 367: nfd = f + 1; 368: else 369: nfd = p + 1; 370: for (;;) { 371: fd_set ibits, obits, ebits; 372: 373: FD_ZERO(&ibits); 374: FD_ZERO(&obits); 375: if (fcc) 376: FD_SET(p, &obits); 377: else 378: FD_SET(f, &ibits); 379: if (pcc >= 0) 380: if (pcc) 381: FD_SET(f, &obits); 382: else 383: FD_SET(p, &ibits); 384: FD_SET(p, &ebits); 385: if ((n = select(nfd, &ibits, &obits, &ebits, 0)) < 0) { 386: if (errno == EINTR) 387: continue; 388: fatalperror(f, "select"); 389: } 390: if (n == 0) { 391: /* shouldn't happen... */ 392: sleep(5); 393: continue; 394: } 395: #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 396: if (FD_ISSET(p, &ebits)) { 397: cc = read(p, &cntl, 1); 398: if (cc == 1 && pkcontrol(cntl)) { 399: cntl |= oobdata[0]; 400: send(f, &cntl, 1, MSG_OOB); 401: if (cntl & TIOCPKT_FLUSHWRITE) { 402: pcc = 0; 403: FD_CLR(p, &ibits); 404: } 405: } 406: } 407: if (FD_ISSET(f, &ibits)) { 408: fcc = read(f, fibuf, sizeof(fibuf)); 409: if (fcc < 0 && errno == EWOULDBLOCK) 410: fcc = 0; 411: else { 412: register char *cp; 413: int left, n; 414: 415: if (fcc <= 0) 416: break; 417: fbp = fibuf; 418: 419: top: 420: for (cp = fibuf; cp < fibuf+fcc-1; cp++) 421: if (cp[0] == magic[0] && 422: cp[1] == magic[1]) { 423: left = fcc - (cp-fibuf); 424: n = control(p, cp, left); 425: if (n) { 426: left -= n; 427: if (left > 0) 428: bcopy(cp+n, cp, left); 429: fcc -= n; 430: goto top; /* n^2 */ 431: } 432: } 433: FD_SET(p, &obits); /* try write */ 434: } 435: } 436: 437: if (FD_ISSET(p, &obits) && fcc > 0) { 438: cc = write(p, fbp, fcc); 439: if (cc > 0) { 440: fcc -= cc; 441: fbp += cc; 442: } 443: } 444: 445: if (FD_ISSET(p, &ibits)) { 446: pcc = read(p, pibuf, sizeof (pibuf)); 447: pbp = pibuf; 448: if (pcc < 0 && errno == EWOULDBLOCK) 449: pcc = 0; 450: else if (pcc <= 0) 451: break; 452: else if (pibuf[0] == 0) { 453: pbp++, pcc--; 454: FD_SET(f, &obits); /* try a write */ 455: } else { 456: if (pkcontrol(pibuf[0])) { 457: pibuf[0] |= oobdata[0]; 458: send(f, &pibuf[0], 1, MSG_OOB); 459: } 460: pcc = 0; 461: } 462: } 463: if ((FD_ISSET(f, &obits)) && pcc > 0) { 464: cc = write(f, pbp, pcc); 465: if (cc < 0 && errno == EWOULDBLOCK) { 466: /* also shouldn't happen */ 467: sleep(5); 468: continue; 469: } 470: if (cc > 0) { 471: pcc -= cc; 472: pbp += cc; 473: } 474: } 475: } 476: } 477: 478: cleanup() 479: { 480: char *p; 481: 482: p = line + sizeof("/dev/") - 1; 483: if (logout(p)) 484: logwtmp(p, "", ""); 485: (void)chmod(line, 0666); 486: (void)chown(line, 0, 0); 487: *p = 'p'; 488: (void)chmod(line, 0666); 489: (void)chown(line, 0, 0); 490: shutdown(netf, 2); 491: exit(1); 492: } 493: 494: fatal(f, msg) 495: int f; 496: char *msg; 497: { 498: char buf[BUFSIZ]; 499: 500: buf[0] = '\01'; /* error indicator */ 501: (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 502: (void) write(f, buf, strlen(buf)); 503: exit(1); 504: } 505: 506: fatalperror(f, msg) 507: int f; 508: char *msg; 509: { 510: char buf[BUFSIZ]; 511: 512: (void) sprintf(buf, "%s: %s", msg, strerror(errno)); 513: fatal(f, buf); 514: } 515: 516: #ifndef OLD_LOGIN 517: do_rlogin(host) 518: char *host; 519: { 520: 521: getstr(rusername, sizeof(rusername), "remuser too long"); 522: getstr(lusername, sizeof(lusername), "locuser too long"); 523: getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 524: 525: if (getuid()) 526: return(-1); 527: pwd = getpwnam(lusername); 528: if (pwd == NULL) 529: return(-1); 530: return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 531: } 532: 533: 534: getstr(buf, cnt, errmsg) 535: char *buf; 536: int cnt; 537: char *errmsg; 538: { 539: char c; 540: 541: do { 542: if (read(0, &c, 1) != 1) 543: exit(1); 544: if (--cnt < 0) 545: fatal(1, errmsg); 546: *buf++ = c; 547: } while (c != 0); 548: } 549: 550: extern char **environ; 551: 552: char *speeds[] = { 553: "0", "50", "75", "110", "134", "150", "200", "300", "600", 554: "1200", "1800", "2400", "4800", "9600", "19200", "38400", 555: }; 556: #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) 557: 558: setup_term(fd) 559: int fd; 560: { 561: register char *cp = index(term, '/'), **cpp; 562: char *speed; 563: #ifdef FOURdotFOUR 564: struct termios tt; 565: 566: tcgetattr(fd, &tt); 567: if (cp) { 568: *cp++ = '\0'; 569: speed = cp; 570: cp = index(speed, '/'); 571: if (cp) 572: *cp++ = '\0'; 573: cfsetspeed(&tt, atoi(speed)); 574: } 575: 576: tt.c_iflag = TTYDEF_IFLAG; 577: tt.c_oflag = TTYDEF_OFLAG; 578: tt.c_lflag = TTYDEF_LFLAG; 579: tcsetattr(fd, TCSADFLUSH, &tt); 580: #else 581: struct sgttyb sgttyb; 582: 583: (void)ioctl(fd, TIOCGETP, &sgttyb); 584: if (cp) { 585: *cp++ = '\0'; 586: speed = cp; 587: cp = index(speed, '/'); 588: if (cp) 589: *cp++ = '\0'; 590: for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 591: if (strcmp(*cpp, speed) == 0) { 592: sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds; 593: break; 594: } 595: } 596: sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS; 597: (void)ioctl(fd, TIOCSETP, &sgttyb); 598: #endif 599: 600: env[0] = term; 601: env[1] = 0; 602: environ = env; 603: } 604: 605: /* 606: * Check whether host h is in our local domain, 607: * defined as sharing the last two components of the domain part, 608: * or the entire domain part if the local domain has only one component. 609: * If either name is unqualified (contains no '.'), 610: * assume that the host is local, as it will be 611: * interpreted as such. 612: */ 613: local_domain(h) 614: char *h; 615: { 616: char localhost[MAXHOSTNAMELEN]; 617: char *p1, *p2, *topdomain(); 618: 619: localhost[0] = 0; 620: (void) gethostname(localhost, sizeof(localhost)); 621: p1 = topdomain(localhost); 622: p2 = topdomain(h); 623: if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 624: return(1); 625: return(0); 626: } 627: 628: char * 629: topdomain(h) 630: char *h; 631: { 632: register char *p; 633: char *maybe = NULL; 634: int dots = 0; 635: 636: for (p = h + strlen(h); p >= h; p--) { 637: if (*p == '.') { 638: if (++dots == 2) 639: return (p); 640: maybe = p; 641: } 642: } 643: return (maybe); 644: } 645: #endif /* OLD_LOGIN */