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