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