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