1 /* 2 * Copyright (c) 1983, 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)rlogind.c 5.22.1.2 (Berkeley) 01/06/89"; 26 #endif /* not lint */ 27 28 /* 29 * remote login server: 30 * \0 31 * remuser\0 32 * locuser\0 33 * terminal_type/speed\0 34 * data 35 * 36 * Automatic login protocol is done here, using login -f upon success, 37 * unless OLD_LOGIN is defined (then done in login, ala 4.2/4.3BSD). 38 */ 39 40 #include <stdio.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/socket.h> 44 #include <sys/wait.h> 45 #include <sys/file.h> 46 47 #include <netinet/in.h> 48 49 #include <errno.h> 50 #include <pwd.h> 51 #include <signal.h> 52 #include <sgtty.h> 53 #include <stdio.h> 54 #include <netdb.h> 55 #include <syslog.h> 56 #include <strings.h> 57 58 #ifndef TIOCPKT_WINDOW 59 #define TIOCPKT_WINDOW 0x80 60 #endif 61 62 char *env[2]; 63 #define NMAX 30 64 char lusername[NMAX+1], rusername[NMAX+1]; 65 static char term[64] = "TERM="; 66 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 67 int keepalive = 1; 68 69 #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 70 71 extern int errno; 72 int reapchild(); 73 struct passwd *getpwnam(), *pwd; 74 char *malloc(); 75 76 main(argc, argv) 77 int argc; 78 char **argv; 79 { 80 extern int opterr, optind, _check_rhosts_file; 81 int ch; 82 int on = 1, fromlen; 83 struct sockaddr_in from; 84 85 openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 86 87 opterr = 0; 88 while ((ch = getopt(argc, argv, "ln")) != EOF) 89 switch (ch) { 90 case 'l': 91 _check_rhosts_file = 0; 92 break; 93 case 'n': 94 keepalive = 0; 95 break; 96 case '?': 97 default: 98 syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 99 break; 100 } 101 argc -= optind; 102 argv += optind; 103 104 fromlen = sizeof (from); 105 if (getpeername(0, &from, &fromlen) < 0) { 106 fprintf(stderr, "%s: ", argv[0]); 107 perror("getpeername"); 108 exit(1); 109 } 110 if (keepalive && 111 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 112 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 113 doit(0, &from); 114 } 115 116 int child; 117 int cleanup(); 118 int netf; 119 char *line; 120 extern char *inet_ntoa(); 121 122 struct winsize win = { 0, 0, 0, 0 }; 123 124 125 doit(f, fromp) 126 int f; 127 struct sockaddr_in *fromp; 128 { 129 int i, p, t, pid, on = 1; 130 #ifndef OLD_LOGIN 131 int authenticated = 0; 132 #endif 133 register struct hostent *hp; 134 struct hostent hostent; 135 char c; 136 137 alarm(60); 138 read(f, &c, 1); 139 if (c != 0) 140 exit(1); 141 142 alarm(0); 143 fromp->sin_port = ntohs((u_short)fromp->sin_port); 144 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 145 fromp->sin_family); 146 if (hp == 0) { 147 /* 148 * Only the name is used below. 149 */ 150 hp = &hostent; 151 hp->h_name = inet_ntoa(fromp->sin_addr); 152 } 153 154 if (fromp->sin_family != AF_INET || 155 fromp->sin_port >= IPPORT_RESERVED || 156 fromp->sin_port < IPPORT_RESERVED/2) 157 fatal(f, "Permission denied"); 158 write(f, "", 1); 159 #ifndef OLD_LOGIN 160 if (do_rlogin(hp->h_name) == 0) 161 authenticated++; 162 #endif 163 164 for (c = 'p'; c <= 's'; c++) { 165 struct stat stb; 166 line = "/dev/ptyXX"; 167 line[strlen("/dev/pty")] = c; 168 line[strlen("/dev/ptyp")] = '0'; 169 if (stat(line, &stb) < 0) 170 break; 171 for (i = 0; i < 16; i++) { 172 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 173 p = open(line, O_RDWR); 174 if (p > 0) 175 goto gotpty; 176 } 177 } 178 fatal(f, "Out of ptys"); 179 /*NOTREACHED*/ 180 gotpty: 181 (void) ioctl(p, TIOCSWINSZ, &win); 182 netf = f; 183 line[strlen("/dev/")] = 't'; 184 t = open(line, O_RDWR); 185 if (t < 0) 186 fatalperror(f, line); 187 if (fchmod(t, 0)) 188 fatalperror(f, line); 189 (void)signal(SIGHUP, SIG_IGN); 190 vhangup(); 191 (void)signal(SIGHUP, SIG_DFL); 192 t = open(line, O_RDWR); 193 if (t < 0) 194 fatalperror(f, line); 195 setup_term(t); 196 #ifdef DEBUG 197 { 198 int tt = open("/dev/tty", O_RDWR); 199 if (tt > 0) { 200 (void)ioctl(tt, TIOCNOTTY, 0); 201 (void)close(tt); 202 } 203 } 204 #endif 205 pid = fork(); 206 if (pid < 0) 207 fatalperror(f, ""); 208 if (pid == 0) { 209 close(f), close(p); 210 dup2(t, 0), dup2(t, 1), dup2(t, 2); 211 close(t); 212 #ifdef OLD_LOGIN 213 execl("/bin/login", "login", "-r", hp->h_name, 0); 214 #else /* OLD_LOGIN */ 215 if (authenticated) 216 execl("/bin/login", "login", "-p", "-f", 217 "-h", hp->h_name, lusername, 0); 218 else 219 execl("/bin/login", "login", "-p", "-h", hp->h_name, 220 lusername, 0); 221 #endif /* OLD_LOGIN */ 222 fatalperror(2, "/bin/login"); 223 /*NOTREACHED*/ 224 } 225 close(t); 226 227 ioctl(f, FIONBIO, &on); 228 ioctl(p, FIONBIO, &on); 229 ioctl(p, TIOCPKT, &on); 230 signal(SIGTSTP, SIG_IGN); 231 signal(SIGCHLD, cleanup); 232 setpgrp(0, 0); 233 protocol(f, p); 234 signal(SIGCHLD, SIG_IGN); 235 cleanup(); 236 } 237 238 char magic[2] = { 0377, 0377 }; 239 char oobdata[] = {TIOCPKT_WINDOW}; 240 241 /* 242 * Handle a "control" request (signaled by magic being present) 243 * in the data stream. For now, we are only willing to handle 244 * window size changes. 245 */ 246 control(pty, cp, n) 247 int pty; 248 char *cp; 249 int n; 250 { 251 struct winsize w; 252 253 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 254 return (0); 255 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 256 bcopy(cp+4, (char *)&w, sizeof(w)); 257 w.ws_row = ntohs(w.ws_row); 258 w.ws_col = ntohs(w.ws_col); 259 w.ws_xpixel = ntohs(w.ws_xpixel); 260 w.ws_ypixel = ntohs(w.ws_ypixel); 261 (void)ioctl(pty, TIOCSWINSZ, &w); 262 return (4+sizeof (w)); 263 } 264 265 /* 266 * rlogin "protocol" machine. 267 */ 268 protocol(f, p) 269 int f, p; 270 { 271 char pibuf[1024], fibuf[1024], *pbp, *fbp; 272 register pcc = 0, fcc = 0; 273 int cc, nfd, pmask, fmask; 274 char cntl; 275 276 /* 277 * Must ignore SIGTTOU, otherwise we'll stop 278 * when we try and set slave pty's window shape 279 * (our controlling tty is the master pty). 280 */ 281 (void) signal(SIGTTOU, SIG_IGN); 282 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 283 if (f > p) 284 nfd = f + 1; 285 else 286 nfd = p + 1; 287 fmask = 1 << f; 288 pmask = 1 << p; 289 for (;;) { 290 int ibits, obits, ebits; 291 292 ibits = 0; 293 obits = 0; 294 if (fcc) 295 obits |= pmask; 296 else 297 ibits |= fmask; 298 if (pcc >= 0) 299 if (pcc) 300 obits |= fmask; 301 else 302 ibits |= pmask; 303 ebits = pmask; 304 if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 305 &ebits, 0) < 0) { 306 if (errno == EINTR) 307 continue; 308 fatalperror(f, "select"); 309 } 310 if (ibits == 0 && obits == 0 && ebits == 0) { 311 /* shouldn't happen... */ 312 sleep(5); 313 continue; 314 } 315 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 316 if (ebits & pmask) { 317 cc = read(p, &cntl, 1); 318 if (cc == 1 && pkcontrol(cntl)) { 319 cntl |= oobdata[0]; 320 send(f, &cntl, 1, MSG_OOB); 321 if (cntl & TIOCPKT_FLUSHWRITE) { 322 pcc = 0; 323 ibits &= ~pmask; 324 } 325 } 326 } 327 if (ibits & fmask) { 328 fcc = read(f, fibuf, sizeof(fibuf)); 329 if (fcc < 0 && errno == EWOULDBLOCK) 330 fcc = 0; 331 else { 332 register char *cp; 333 int left, n; 334 335 if (fcc <= 0) 336 break; 337 fbp = fibuf; 338 339 top: 340 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 341 if (cp[0] == magic[0] && 342 cp[1] == magic[1]) { 343 left = fcc - (cp-fibuf); 344 n = control(p, cp, left); 345 if (n) { 346 left -= n; 347 if (left > 0) 348 bcopy(cp+n, cp, left); 349 fcc -= n; 350 goto top; /* n^2 */ 351 } 352 } 353 obits |= pmask; /* try write */ 354 } 355 } 356 357 if ((obits & pmask) && fcc > 0) { 358 cc = write(p, fbp, fcc); 359 if (cc > 0) { 360 fcc -= cc; 361 fbp += cc; 362 } 363 } 364 365 if (ibits & pmask) { 366 pcc = read(p, pibuf, sizeof (pibuf)); 367 pbp = pibuf; 368 if (pcc < 0 && errno == EWOULDBLOCK) 369 pcc = 0; 370 else if (pcc <= 0) 371 break; 372 else if (pibuf[0] == 0) { 373 pbp++, pcc--; 374 obits |= fmask; /* try a write */ 375 } else { 376 if (pkcontrol(pibuf[0])) { 377 pibuf[0] |= oobdata[0]; 378 send(f, &pibuf[0], 1, MSG_OOB); 379 } 380 pcc = 0; 381 } 382 } 383 if ((obits & fmask) && pcc > 0) { 384 cc = write(f, pbp, pcc); 385 if (cc < 0 && errno == EWOULDBLOCK) { 386 /* also shouldn't happen */ 387 sleep(5); 388 continue; 389 } 390 if (cc > 0) { 391 pcc -= cc; 392 pbp += cc; 393 } 394 } 395 } 396 } 397 398 cleanup() 399 { 400 char *p; 401 402 p = line + sizeof("/dev/") - 1; 403 if (logout(p)) 404 logwtmp(p, "", ""); 405 (void)chmod(line, 0666); 406 (void)chown(line, 0, 0); 407 *p = 'p'; 408 (void)chmod(line, 0666); 409 (void)chown(line, 0, 0); 410 shutdown(netf, 2); 411 exit(1); 412 } 413 414 fatal(f, msg) 415 int f; 416 char *msg; 417 { 418 char buf[BUFSIZ]; 419 420 buf[0] = '\01'; /* error indicator */ 421 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 422 (void) write(f, buf, strlen(buf)); 423 exit(1); 424 } 425 426 fatalperror(f, msg) 427 int f; 428 char *msg; 429 { 430 char buf[BUFSIZ]; 431 extern int sys_nerr; 432 extern char *sys_errlist[]; 433 434 if ((unsigned)errno < sys_nerr) 435 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 436 else 437 (void) sprintf(buf, "%s: Error %d", msg, errno); 438 fatal(f, buf); 439 } 440 441 #ifndef OLD_LOGIN 442 do_rlogin(host) 443 char *host; 444 { 445 446 getstr(rusername, sizeof(rusername), "remuser too long"); 447 getstr(lusername, sizeof(lusername), "locuser too long"); 448 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 449 450 if (getuid()) 451 return(-1); 452 pwd = getpwnam(lusername); 453 if (pwd == NULL) 454 return(-1); 455 return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 456 } 457 458 459 getstr(buf, cnt, errmsg) 460 char *buf; 461 int cnt; 462 char *errmsg; 463 { 464 char c; 465 466 do { 467 if (read(0, &c, 1) != 1) 468 exit(1); 469 if (--cnt < 0) 470 fatal(1, errmsg); 471 *buf++ = c; 472 } while (c != 0); 473 } 474 475 extern char **environ; 476 477 char *speeds[] = { 478 "0", "50", "75", "110", "134", "150", "200", "300", "600", 479 "1200", "1800", "2400", "4800", "9600", "19200", "38400", 480 }; 481 #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) 482 483 setup_term(fd) 484 int fd; 485 { 486 register char *cp = index(term, '/'), **cpp; 487 struct sgttyb sgttyb; 488 char *speed; 489 490 (void)ioctl(fd, TIOCGETP, &sgttyb); 491 if (cp) { 492 *cp++ = '\0'; 493 speed = cp; 494 cp = index(speed, '/'); 495 if (cp) 496 *cp++ = '\0'; 497 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 498 if (strcmp(*cpp, speed) == 0) { 499 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds; 500 break; 501 } 502 } 503 sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS; 504 (void)ioctl(fd, TIOCSETP, &sgttyb); 505 506 env[0] = term; 507 env[1] = 0; 508 environ = env; 509 } 510 #endif /* OLD_LOGIN */ 511