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