1 /* 2 * Copyright (c) 1983 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 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.18 (Berkeley) 12/08/88"; 26 #endif /* not lint */ 27 28 /* 29 * remote login server: 30 * remuser\0 31 * locuser\0 32 * terminal info\0 33 * data 34 */ 35 36 #include <stdio.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/socket.h> 40 #include <sys/wait.h> 41 #include <sys/file.h> 42 43 #include <netinet/in.h> 44 45 #include <errno.h> 46 #include <pwd.h> 47 #include <signal.h> 48 #include <sgtty.h> 49 #include <stdio.h> 50 #include <netdb.h> 51 #include <syslog.h> 52 #include <strings.h> 53 54 # ifndef TIOCPKT_WINDOW 55 # define TIOCPKT_WINDOW 0x80 56 # endif TIOCPKT_WINDOW 57 58 extern int errno; 59 int reapchild(); 60 struct passwd *getpwnam(); 61 char *malloc(); 62 63 /*ARGSUSED*/ 64 main(argc, argv) 65 int argc; 66 char **argv; 67 { 68 extern int opterr, optind, _check_rhosts_file; 69 int ch; 70 int on = 1, fromlen; 71 struct sockaddr_in from; 72 73 openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH); 74 75 opterr = 0; 76 while ((ch = getopt(argc, argv, "l")) != EOF) 77 switch((char)ch) { 78 case 'l': 79 _check_rhosts_file = 0; 80 break; 81 case '?': 82 default: 83 syslog(LOG_ERR, "usage: rlogind [-l]"); 84 break; 85 } 86 argc -= optind; 87 argv += optind; 88 89 fromlen = sizeof (from); 90 if (getpeername(0, &from, &fromlen) < 0) { 91 fprintf(stderr, "%s: ", argv[0]); 92 perror("getpeername"); 93 exit(1); 94 } 95 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { 96 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 97 } 98 doit(0, &from); 99 } 100 101 int child; 102 int cleanup(); 103 int netf; 104 char *line; 105 extern char *inet_ntoa(); 106 107 struct winsize win = { 0, 0, 0, 0 }; 108 109 110 doit(f, fromp) 111 int f; 112 struct sockaddr_in *fromp; 113 { 114 int i, p, t, pid, on = 1; 115 register struct hostent *hp; 116 struct hostent hostent; 117 char c; 118 119 alarm(60); 120 read(f, &c, 1); 121 if (c != 0) 122 exit(1); 123 alarm(0); 124 fromp->sin_port = ntohs((u_short)fromp->sin_port); 125 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 126 fromp->sin_family); 127 if (hp == 0) { 128 /* 129 * Only the name is used below. 130 */ 131 hp = &hostent; 132 hp->h_name = inet_ntoa(fromp->sin_addr); 133 } 134 if (fromp->sin_family != AF_INET || 135 fromp->sin_port >= IPPORT_RESERVED || 136 fromp->sin_port < IPPORT_RESERVED/2) 137 fatal(f, "Permission denied"); 138 write(f, "", 1); 139 for (c = 'p'; c <= 's'; c++) { 140 struct stat stb; 141 line = "/dev/ptyXX"; 142 line[strlen("/dev/pty")] = c; 143 line[strlen("/dev/ptyp")] = '0'; 144 if (stat(line, &stb) < 0) 145 break; 146 for (i = 0; i < 16; i++) { 147 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 148 p = open(line, O_RDWR); 149 if (p > 0) 150 goto gotpty; 151 } 152 } 153 fatal(f, "Out of ptys"); 154 /*NOTREACHED*/ 155 gotpty: 156 (void) ioctl(p, TIOCSWINSZ, &win); 157 netf = f; 158 line[strlen("/dev/")] = 't'; 159 t = open(line, O_RDWR); 160 if (t < 0) 161 fatalperror(f, line); 162 if (fchmod(t, 0)) 163 fatalperror(f, line); 164 (void)signal(SIGHUP, SIG_IGN); 165 vhangup(); 166 (void)signal(SIGHUP, SIG_DFL); 167 t = open(line, O_RDWR); 168 if (t < 0) 169 fatalperror(f, line); 170 { 171 struct sgttyb b; 172 173 (void)ioctl(t, TIOCGETP, &b); 174 b.sg_flags = RAW|ANYP; 175 (void)ioctl(t, TIOCSETP, &b); 176 } 177 #ifdef DEBUG 178 { 179 int tt = open("/dev/tty", O_RDWR); 180 if (tt > 0) { 181 (void)ioctl(tt, TIOCNOTTY, 0); 182 (void)close(tt); 183 } 184 } 185 #endif 186 pid = fork(); 187 if (pid < 0) 188 fatalperror(f, ""); 189 if (pid == 0) { 190 close(f), close(p); 191 dup2(t, 0), dup2(t, 1), dup2(t, 2); 192 close(t); 193 execl("/bin/login", "login", "-r", hp->h_name, 0); 194 fatalperror(2, "/bin/login"); 195 /*NOTREACHED*/ 196 } 197 close(t); 198 ioctl(f, FIONBIO, &on); 199 ioctl(p, FIONBIO, &on); 200 ioctl(p, TIOCPKT, &on); 201 signal(SIGTSTP, SIG_IGN); 202 signal(SIGCHLD, cleanup); 203 setpgrp(0, 0); 204 protocol(f, p); 205 signal(SIGCHLD, SIG_IGN); 206 cleanup(); 207 } 208 209 char magic[2] = { 0377, 0377 }; 210 char oobdata[] = {TIOCPKT_WINDOW}; 211 212 /* 213 * Handle a "control" request (signaled by magic being present) 214 * in the data stream. For now, we are only willing to handle 215 * window size changes. 216 */ 217 control(pty, cp, n) 218 int pty; 219 char *cp; 220 int n; 221 { 222 struct winsize w; 223 224 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 225 return (0); 226 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 227 bcopy(cp+4, (char *)&w, sizeof(w)); 228 w.ws_row = ntohs(w.ws_row); 229 w.ws_col = ntohs(w.ws_col); 230 w.ws_xpixel = ntohs(w.ws_xpixel); 231 w.ws_ypixel = ntohs(w.ws_ypixel); 232 (void)ioctl(pty, TIOCSWINSZ, &w); 233 return (4+sizeof (w)); 234 } 235 236 /* 237 * rlogin "protocol" machine. 238 */ 239 protocol(f, p) 240 int f, p; 241 { 242 char pibuf[1024], fibuf[1024], *pbp, *fbp; 243 register pcc = 0, fcc = 0; 244 int cc; 245 char cntl; 246 247 /* 248 * Must ignore SIGTTOU, otherwise we'll stop 249 * when we try and set slave pty's window shape 250 * (our controlling tty is the master pty). 251 */ 252 (void) signal(SIGTTOU, SIG_IGN); 253 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 254 for (;;) { 255 int ibits, obits, ebits; 256 257 ibits = 0; 258 obits = 0; 259 if (fcc) 260 obits |= (1<<p); 261 else 262 ibits |= (1<<f); 263 if (pcc >= 0) 264 if (pcc) 265 obits |= (1<<f); 266 else 267 ibits |= (1<<p); 268 ebits = (1<<p); 269 if (select(16, &ibits, &obits, &ebits, 0) < 0) { 270 if (errno == EINTR) 271 continue; 272 fatalperror(f, "select"); 273 } 274 if (ibits == 0 && obits == 0 && ebits == 0) { 275 /* shouldn't happen... */ 276 sleep(5); 277 continue; 278 } 279 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 280 if (ebits & (1<<p)) { 281 cc = read(p, &cntl, 1); 282 if (cc == 1 && pkcontrol(cntl)) { 283 cntl |= oobdata[0]; 284 send(f, &cntl, 1, MSG_OOB); 285 if (cntl & TIOCPKT_FLUSHWRITE) { 286 pcc = 0; 287 ibits &= ~(1<<p); 288 } 289 } 290 } 291 if (ibits & (1<<f)) { 292 fcc = read(f, fibuf, sizeof (fibuf)); 293 if (fcc < 0 && errno == EWOULDBLOCK) 294 fcc = 0; 295 else { 296 register char *cp; 297 int left, n; 298 299 if (fcc <= 0) 300 break; 301 fbp = fibuf; 302 303 top: 304 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 305 if (cp[0] == magic[0] && 306 cp[1] == magic[1]) { 307 left = fcc - (cp-fibuf); 308 n = control(p, cp, left); 309 if (n) { 310 left -= n; 311 if (left > 0) 312 bcopy(cp+n, cp, left); 313 fcc -= n; 314 goto top; /* n^2 */ 315 } 316 } 317 } 318 } 319 320 if ((obits & (1<<p)) && fcc > 0) { 321 cc = write(p, fbp, fcc); 322 if (cc > 0) { 323 fcc -= cc; 324 fbp += cc; 325 } 326 } 327 328 if (ibits & (1<<p)) { 329 pcc = read(p, pibuf, sizeof (pibuf)); 330 pbp = pibuf; 331 if (pcc < 0 && errno == EWOULDBLOCK) 332 pcc = 0; 333 else if (pcc <= 0) 334 break; 335 else if (pibuf[0] == 0) 336 pbp++, pcc--; 337 else { 338 if (pkcontrol(pibuf[0])) { 339 pibuf[0] |= oobdata[0]; 340 send(f, &pibuf[0], 1, MSG_OOB); 341 } 342 pcc = 0; 343 } 344 } 345 if ((obits & (1<<f)) && pcc > 0) { 346 cc = write(f, pbp, pcc); 347 if (cc < 0 && errno == EWOULDBLOCK) { 348 /* also shouldn't happen */ 349 sleep(5); 350 continue; 351 } 352 if (cc > 0) { 353 pcc -= cc; 354 pbp += cc; 355 } 356 } 357 } 358 } 359 360 cleanup() 361 { 362 char *p; 363 364 p = line + sizeof("/dev/") - 1; 365 if (logout(p)) 366 logwtmp(p, "", ""); 367 (void)chmod(line, 0666); 368 (void)chown(line, 0, 0); 369 *p = 'p'; 370 (void)chmod(line, 0666); 371 (void)chown(line, 0, 0); 372 shutdown(netf, 2); 373 exit(1); 374 } 375 376 fatal(f, msg) 377 int f; 378 char *msg; 379 { 380 char buf[BUFSIZ]; 381 382 buf[0] = '\01'; /* error indicator */ 383 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 384 (void) write(f, buf, strlen(buf)); 385 exit(1); 386 } 387 388 fatalperror(f, msg) 389 int f; 390 char *msg; 391 { 392 char buf[BUFSIZ]; 393 extern int sys_nerr; 394 extern char *sys_errlist[]; 395 396 if ((unsigned)errno < sys_nerr) 397 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 398 else 399 (void) sprintf(buf, "%s: Error %d", msg, errno); 400 fatal(f, buf); 401 } 402