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.7 (Berkeley) 09/17/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 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 168 /* 169 * Handle a "control" request (signaled by magic being present) 170 * in the data stream. For now, we are only willing to handle 171 * window size changes. 172 */ 173 control(pty, cp, n) 174 int pty; 175 char *cp; 176 int n; 177 { 178 struct winsize *wp; 179 180 if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's') 181 return (0); 182 wp = (struct winsize *)(cp+4); 183 wp->ws_row = ntohs(wp->ws_row); 184 wp->ws_col = ntohs(wp->ws_col); 185 wp->ws_xpixel = ntohs(wp->ws_xpixel); 186 wp->ws_ypixel = ntohs(wp->ws_ypixel); 187 (void)ioctl(pty, TIOCSWINSZ, wp); 188 return (4+sizeof (*wp)); 189 } 190 191 /* 192 * rlogin "protocol" machine. 193 */ 194 protocol(f, p) 195 int f, p; 196 { 197 char pibuf[1024], fibuf[1024], *pbp, *fbp; 198 register pcc = 0, fcc = 0; 199 int cc, stop = TIOCPKT_DOSTOP, wsize; 200 static char oob[] = {TIOCPKT_WINDOW}; 201 202 /* 203 * Must ignore SIGTTOU, otherwise we'll stop 204 * when we try and set slave pty's window shape 205 * (our pgrp is that of the master pty). 206 */ 207 (void) signal(SIGTTOU, SIG_IGN); 208 send(f, oob, 1, MSG_OOB); /* indicate new rlogin */ 209 for (;;) { 210 int ibits = 0, obits = 0; 211 212 if (fcc) 213 obits |= (1<<p); 214 else 215 ibits |= (1<<f); 216 if (pcc >= 0) 217 if (pcc) 218 obits |= (1<<f); 219 else 220 ibits |= (1<<p); 221 if (select(16, &ibits, &obits, 0, 0) < 0) { 222 if (errno == EINTR) 223 continue; 224 fatalperror(f, "select", errno); 225 } 226 if (ibits == 0 && obits == 0) { 227 /* shouldn't happen... */ 228 sleep(5); 229 continue; 230 } 231 if (ibits & (1<<f)) { 232 fcc = read(f, fibuf, sizeof (fibuf)); 233 if (fcc < 0 && errno == EWOULDBLOCK) 234 fcc = 0; 235 else { 236 register char *cp; 237 int left, n; 238 239 if (fcc <= 0) 240 break; 241 fbp = fibuf; 242 243 top: 244 for (cp = fibuf; cp < fibuf+fcc; cp++) 245 if (cp[0] == magic[0] && 246 cp[1] == magic[1]) { 247 left = fcc - (cp-fibuf); 248 n = control(p, cp, left); 249 if (n) { 250 left -= n; 251 if (left > 0) 252 bcopy(cp, cp+n, left); 253 fcc -= n; 254 goto top; /* n^2 */ 255 } /* if (n) */ 256 } /* for (cp = ) */ 257 } /* else */ 258 } /* if (ibits & (1<<f)) */ 259 260 if ((obits & (1<<p)) && fcc > 0) { 261 wsize = fcc; 262 do { 263 cc = write(p, fbp, wsize); 264 wsize /= 2; 265 } while (cc<0 && errno==EWOULDBLOCK && wsize); 266 if (cc > 0) { 267 fcc -= cc; 268 fbp += cc; 269 } 270 } 271 272 if (ibits & (1<<p)) { 273 pcc = read(p, pibuf, sizeof (pibuf)); 274 pbp = pibuf; 275 if (pcc < 0 && errno == EWOULDBLOCK) 276 pcc = 0; 277 else if (pcc <= 0) 278 break; 279 else if (pibuf[0] == 0) 280 pbp++, pcc--; 281 else { 282 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 283 int out = FREAD; 284 285 if (pkcontrol(pibuf[0])) { 286 /* The following 3 lines do nothing. */ 287 int nstop = pibuf[0] & 288 (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); 289 290 if (nstop) 291 stop = nstop; 292 pibuf[0] |= nstop | oob[0]; 293 send(f, &pibuf[0], 1, MSG_OOB); 294 if (pibuf[0] & TIOCPKT_FLUSHWRITE) 295 ioctl(p, TIOCFLUSH, (char *)&out); 296 297 } 298 pcc = 0; 299 } 300 } 301 if ((obits & (1<<f)) && pcc > 0) { 302 wsize = pcc; 303 do { 304 cc = write(f, pbp, wsize); 305 wsize /= 2; 306 } while (cc<0 && errno==EWOULDBLOCK && wsize); 307 if (cc > 0) { 308 pcc -= cc; 309 pbp += cc; 310 } 311 } 312 } 313 } 314 315 cleanup() 316 { 317 318 rmut(); 319 vhangup(); /* XXX */ 320 shutdown(netf, 2); 321 kill(0, SIGKILL); 322 exit(1); 323 } 324 325 fatal(f, msg) 326 int f; 327 char *msg; 328 { 329 char buf[BUFSIZ]; 330 331 buf[0] = '\01'; /* error indicator */ 332 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 333 (void) write(f, buf, strlen(buf)); 334 exit(1); 335 } 336 337 fatalperror(f, msg, errno) 338 int f; 339 char *msg; 340 int errno; 341 { 342 char buf[BUFSIZ]; 343 extern int sys_nerr; 344 extern char *sys_errlist[]; 345 346 if ((unsigned)errno < sys_nerr) 347 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 348 else 349 (void) sprintf(buf, "%s: Error %d", msg, errno); 350 fatal(f, buf); 351 } 352 353 #include <utmp.h> 354 355 struct utmp wtmp; 356 char wtmpf[] = "/usr/adm/wtmp"; 357 char utmpf[] = "/etc/utmp"; 358 #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 359 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 360 361 rmut() 362 { 363 register f; 364 int found = 0; 365 struct utmp *u, *utmp; 366 int nutmp; 367 struct stat statbf; 368 369 f = open(utmpf, O_RDWR); 370 if (f >= 0) { 371 fstat(f, &statbf); 372 utmp = (struct utmp *)malloc(statbf.st_size); 373 if (!utmp) 374 syslog(LOG_ERR, "utmp malloc failed"); 375 if (statbf.st_size && utmp) { 376 nutmp = read(f, utmp, statbf.st_size); 377 nutmp /= sizeof(struct utmp); 378 379 for (u = utmp ; u < &utmp[nutmp] ; u++) { 380 if (SCMPN(u->ut_line, line+5) || 381 u->ut_name[0]==0) 382 continue; 383 lseek(f, ((long)u)-((long)utmp), L_SET); 384 SCPYN(u->ut_name, ""); 385 SCPYN(u->ut_host, ""); 386 time(&u->ut_time); 387 write(f, (char *)u, sizeof(wtmp)); 388 found++; 389 } 390 } 391 close(f); 392 } 393 if (found) { 394 f = open(wtmpf, O_WRONLY|O_APPEND); 395 if (f >= 0) { 396 SCPYN(wtmp.ut_line, line+5); 397 SCPYN(wtmp.ut_name, ""); 398 SCPYN(wtmp.ut_host, ""); 399 time(&wtmp.ut_time); 400 write(f, (char *)&wtmp, sizeof(wtmp)); 401 close(f); 402 } 403 } 404 chmod(line, 0666); 405 chown(line, 0, 0); 406 line[strlen("/dev/")] = 'p'; 407 chmod(line, 0666); 408 chown(line, 0, 0); 409 } 410