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