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[] = "@(#)rlogind.c 5.11 (Berkeley) 5/23/86"; 15: #endif not lint 16: 17: /* 18: * remote login server: 19: * remuser\0 20: * locuser\0 21: * terminal info\0 22: * data 23: */ 24: 25: #include <stdio.h> 26: #include <sys/types.h> 27: #include <sys/stat.h> 28: #include <sys/socket.h> 29: #include <sys/wait.h> 30: #include <sys/file.h> 31: 32: #include <netinet/in.h> 33: 34: #include <errno.h> 35: #include <pwd.h> 36: #include <signal.h> 37: #include <sgtty.h> 38: #include <stdio.h> 39: #include <netdb.h> 40: #include <syslog.h> 41: #include <strings.h> 42: 43: # ifndef TIOCPKT_WINDOW 44: # define TIOCPKT_WINDOW 0x80 45: # endif TIOCPKT_WINDOW 46: 47: extern errno; 48: int reapchild(); 49: struct passwd *getpwnam(); 50: char *malloc(); 51: 52: main(argc, argv) 53: int argc; 54: char **argv; 55: { 56: int on = 1, options = 0, fromlen; 57: struct sockaddr_in from; 58: 59: openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 60: fromlen = sizeof (from); 61: if (getpeername(0, &from, &fromlen) < 0) { 62: fprintf(stderr, "%s: ", argv[0]); 63: perror("getpeername"); 64: _exit(1); 65: } 66: if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 67: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 68: } 69: doit(0, &from); 70: } 71: 72: int child; 73: int cleanup(); 74: int netf; 75: extern errno; 76: char *line; 77: extern char *inet_ntoa(); 78: 79: struct winsize win = { 0, 0, 0, 0 }; 80: 81: 82: doit(f, fromp) 83: int f; 84: struct sockaddr_in *fromp; 85: { 86: int i, p, t, pid, on = 1; 87: register struct hostent *hp; 88: struct hostent hostent; 89: char c; 90: 91: alarm(60); 92: read(f, &c, 1); 93: if (c != 0) 94: exit(1); 95: alarm(0); 96: fromp->sin_port = ntohs((u_short)fromp->sin_port); 97: hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 98: fromp->sin_family); 99: if (hp == 0) { 100: /* 101: * Only the name is used below. 102: */ 103: hp = &hostent; 104: hp->h_name = inet_ntoa(fromp->sin_addr); 105: } 106: if (fromp->sin_family != AF_INET || 107: fromp->sin_port >= IPPORT_RESERVED) 108: fatal(f, "Permission denied"); 109: write(f, "", 1); 110: for (c = 'p'; c <= 's'; c++) { 111: struct stat stb; 112: line = "/dev/ptyXX"; 113: line[strlen("/dev/pty")] = c; 114: line[strlen("/dev/ptyp")] = '0'; 115: if (stat(line, &stb) < 0) 116: break; 117: for (i = 0; i < 16; i++) { 118: line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 119: p = open(line, 2); 120: if (p > 0) 121: goto gotpty; 122: } 123: } 124: fatal(f, "Out of ptys"); 125: /*NOTREACHED*/ 126: gotpty: 127: (void) ioctl(p, TIOCSWINSZ, &win); 128: netf = f; 129: line[strlen("/dev/")] = 't'; 130: #ifdef DEBUG 131: { int tt = open("/dev/tty", 2); 132: if (tt > 0) { 133: ioctl(tt, TIOCNOTTY, 0); 134: close(tt); 135: } 136: } 137: #endif 138: t = open(line, 2); 139: if (t < 0) 140: fatalperror(f, line, errno); 141: { struct sgttyb b; 142: gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 143: } 144: pid = fork(); 145: if (pid < 0) 146: fatalperror(f, "", errno); 147: if (pid == 0) { 148: close(f), close(p); 149: dup2(t, 0), dup2(t, 1), dup2(t, 2); 150: close(t); 151: execl("/bin/login", "login", "-r", hp->h_name, 0); 152: fatalperror(2, "/bin/login", errno); 153: /*NOTREACHED*/ 154: } 155: close(t); 156: ioctl(f, FIONBIO, &on); 157: ioctl(p, FIONBIO, &on); 158: ioctl(p, TIOCPKT, &on); 159: signal(SIGTSTP, SIG_IGN); 160: signal(SIGCHLD, cleanup); 161: setpgrp(0, 0); 162: protocol(f, p); 163: cleanup(); 164: } 165: 166: char magic[2] = { 0377, 0377 }; 167: char oobdata[] = {TIOCPKT_WINDOW}; 168: 169: /* 170: * Handle a "control" request (signaled by magic being present) 171: * in the data stream. For now, we are only willing to handle 172: * window size changes. 173: */ 174: control(pty, cp, n) 175: int pty; 176: char *cp; 177: int n; 178: { 179: struct winsize w; 180: 181: if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 182: return (0); 183: oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 184: bcopy(cp+4, (char *)&w, sizeof(w)); 185: w.ws_row = ntohs(w.ws_row); 186: w.ws_col = ntohs(w.ws_col); 187: w.ws_xpixel = ntohs(w.ws_xpixel); 188: w.ws_ypixel = ntohs(w.ws_ypixel); 189: (void)ioctl(pty, TIOCSWINSZ, &w); 190: return (4+sizeof (w)); 191: } 192: 193: /* 194: * rlogin "protocol" machine. 195: */ 196: protocol(f, p) 197: int f, p; 198: { 199: char pibuf[1024], fibuf[1024], *pbp, *fbp; 200: register pcc = 0, fcc = 0; 201: int cc; 202: char cntl; 203: 204: /* 205: * Must ignore SIGTTOU, otherwise we'll stop 206: * when we try and set slave pty's window shape 207: * (our controlling tty is the master pty). 208: */ 209: (void) signal(SIGTTOU, SIG_IGN); 210: send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 211: for (;;) { 212: int ibits, obits, ebits; 213: 214: ibits = 0; 215: obits = 0; 216: if (fcc) 217: obits |= (1<<p); 218: else 219: ibits |= (1<<f); 220: if (pcc >= 0) 221: if (pcc) 222: obits |= (1<<f); 223: else 224: ibits |= (1<<p); 225: ebits = (1<<p); 226: if (select(16, &ibits, &obits, &ebits, 0) < 0) { 227: if (errno == EINTR) 228: continue; 229: fatalperror(f, "select", errno); 230: } 231: if (ibits == 0 && obits == 0 && ebits == 0) { 232: /* shouldn't happen... */ 233: sleep(5); 234: continue; 235: } 236: #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 237: if (ebits & (1<<p)) { 238: cc = read(p, &cntl, 1); 239: if (cc == 1 && pkcontrol(cntl)) { 240: cntl |= oobdata[0]; 241: send(f, &cntl, 1, MSG_OOB); 242: if (cntl & TIOCPKT_FLUSHWRITE) { 243: pcc = 0; 244: ibits &= ~(1<<p); 245: } 246: } 247: } 248: if (ibits & (1<<f)) { 249: fcc = read(f, fibuf, sizeof (fibuf)); 250: if (fcc < 0 && errno == EWOULDBLOCK) 251: fcc = 0; 252: else { 253: register char *cp; 254: int left, n; 255: 256: if (fcc <= 0) 257: break; 258: fbp = fibuf; 259: 260: top: 261: for (cp = fibuf; cp < fibuf+fcc-1; cp++) 262: if (cp[0] == magic[0] && 263: cp[1] == magic[1]) { 264: left = fcc - (cp-fibuf); 265: n = control(p, cp, left); 266: if (n) { 267: left -= n; 268: if (left > 0) 269: bcopy(cp+n, cp, left); 270: fcc -= n; 271: goto top; /* n^2 */ 272: } 273: } 274: } 275: } 276: 277: if ((obits & (1<<p)) && fcc > 0) { 278: cc = write(p, fbp, fcc); 279: if (cc > 0) { 280: fcc -= cc; 281: fbp += cc; 282: } 283: } 284: 285: if (ibits & (1<<p)) { 286: pcc = read(p, pibuf, sizeof (pibuf)); 287: pbp = pibuf; 288: if (pcc < 0 && errno == EWOULDBLOCK) 289: pcc = 0; 290: else if (pcc <= 0) 291: break; 292: else if (pibuf[0] == 0) 293: pbp++, pcc--; 294: else { 295: if (pkcontrol(pibuf[0])) { 296: pibuf[0] |= oobdata[0]; 297: send(f, &pibuf[0], 1, MSG_OOB); 298: } 299: pcc = 0; 300: } 301: } 302: if ((obits & (1<<f)) && pcc > 0) { 303: cc = write(f, pbp, pcc); 304: if (cc < 0 && errno == EWOULDBLOCK) { 305: /* also shouldn't happen */ 306: sleep(5); 307: continue; 308: } 309: if (cc > 0) { 310: pcc -= cc; 311: pbp += cc; 312: } 313: } 314: } 315: } 316: 317: cleanup() 318: { 319: 320: rmut(); 321: vhangup(); /* XXX */ 322: shutdown(netf, 2); 323: exit(1); 324: } 325: 326: fatal(f, msg) 327: int f; 328: char *msg; 329: { 330: char buf[BUFSIZ]; 331: 332: buf[0] = '\01'; /* error indicator */ 333: (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 334: (void) write(f, buf, strlen(buf)); 335: exit(1); 336: } 337: 338: fatalperror(f, msg, errno) 339: int f; 340: char *msg; 341: int errno; 342: { 343: char buf[BUFSIZ]; 344: extern int sys_nerr; 345: extern char *sys_errlist[]; 346: 347: if ((unsigned)errno < sys_nerr) 348: (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 349: else 350: (void) sprintf(buf, "%s: Error %d", msg, errno); 351: fatal(f, buf); 352: } 353: 354: #include <utmp.h> 355: 356: struct utmp wtmp; 357: char wtmpf[] = "/usr/adm/wtmp"; 358: char utmpf[] = "/etc/utmp"; 359: #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 360: #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 361: 362: rmut() 363: { 364: register f; 365: int found = 0; 366: struct utmp *u, *utmp; 367: int nutmp; 368: struct stat statbf; 369: 370: f = open(utmpf, O_RDWR); 371: if (f >= 0) { 372: fstat(f, &statbf); 373: utmp = (struct utmp *)malloc(statbf.st_size); 374: if (!utmp) 375: syslog(LOG_ERR, "utmp malloc failed"); 376: if (statbf.st_size && utmp) { 377: nutmp = read(f, utmp, statbf.st_size); 378: nutmp /= sizeof(struct utmp); 379: 380: for (u = utmp ; u < &utmp[nutmp] ; u++) { 381: if (SCMPN(u->ut_line, line+5) || 382: u->ut_name[0]==0) 383: continue; 384: lseek(f, ((long)u)-((long)utmp), L_SET); 385: SCPYN(u->ut_name, ""); 386: SCPYN(u->ut_host, ""); 387: time(&u->ut_time); 388: write(f, (char *)u, sizeof(wtmp)); 389: found++; 390: } 391: } 392: close(f); 393: } 394: if (found) { 395: f = open(wtmpf, O_WRONLY|O_APPEND); 396: if (f >= 0) { 397: SCPYN(wtmp.ut_line, line+5); 398: SCPYN(wtmp.ut_name, ""); 399: SCPYN(wtmp.ut_host, ""); 400: time(&wtmp.ut_time); 401: write(f, (char *)&wtmp, sizeof(wtmp)); 402: close(f); 403: } 404: } 405: chmod(line, 0666); 406: chown(line, 0, 0); 407: line[strlen("/dev/")] = 'p'; 408: chmod(line, 0666); 409: chown(line, 0, 0); 410: }