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