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