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