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