1 #ifndef lint 2 static char sccsid[] = "@(#)rlogind.c 4.25 (Berkeley) 03/24/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 /* 178 * Must ignore SIGTTOU, otherwise we'll stop 179 * when we try and set slave pty's window shape 180 * (our pgrp is that of the master pty). 181 */ 182 (void) signal(SIGTTOU, SIG_IGN); 183 for (;;) { 184 int ibits = 0, obits = 0; 185 186 if (fcc) 187 obits |= (1<<p); 188 else 189 ibits |= (1<<f); 190 if (pcc >= 0) 191 if (pcc) 192 obits |= (1<<f); 193 else 194 ibits |= (1<<p); 195 if (select(16, &ibits, &obits, 0, 0) < 0) { 196 if (errno == EINTR) 197 continue; 198 fatalperror(f, "select", errno); 199 } 200 if (ibits == 0 && obits == 0) { 201 /* shouldn't happen... */ 202 sleep(5); 203 continue; 204 } 205 if (ibits & (1<<f)) { 206 fcc = read(f, fibuf, sizeof (fibuf)); 207 if (fcc < 0 && errno == EWOULDBLOCK) 208 fcc = 0; 209 else { 210 register char *cp; 211 int left, n; 212 213 if (fcc <= 0) 214 break; 215 fbp = fibuf; 216 top: 217 for (cp = fibuf; cp < fibuf+fcc; cp++) 218 if (cp[0] == magic[0] && 219 cp[1] == magic[1]) { 220 left = fcc - (cp-fibuf); 221 n = control(p, cp, left); 222 if (n) { 223 left -= n; 224 if (left > 0) 225 bcopy(cp, cp+n, left); 226 fcc -= n; 227 goto top; /* n^2 */ 228 } 229 } 230 } 231 } 232 if (ibits & (1<<p)) { 233 pcc = read(p, pibuf, sizeof (pibuf)); 234 pbp = pibuf; 235 if (pcc < 0 && errno == EWOULDBLOCK) 236 pcc = 0; 237 else if (pcc <= 0) 238 break; 239 else if (pibuf[0] == 0) 240 pbp++, pcc--; 241 else { 242 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 243 if (pkcontrol(pibuf[0])) { 244 /* The following 3 lines do nothing. */ 245 int nstop = pibuf[0] & 246 (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP); 247 248 if (nstop) 249 stop = nstop; 250 pibuf[0] |= nstop; 251 send(f, &pibuf[0], 1, MSG_OOB); 252 } 253 pcc = 0; 254 } 255 } 256 if ((obits & (1<<f)) && pcc > 0) { 257 cc = write(f, pbp, pcc); 258 if (cc < 0 && errno == EWOULDBLOCK) { 259 /* also shouldn't happen */ 260 sleep(5); 261 continue; 262 } 263 if (cc > 0) { 264 pcc -= cc; 265 pbp += cc; 266 } 267 } 268 if ((obits & (1<<p)) && fcc > 0) { 269 cc = write(p, fbp, fcc); 270 if (cc > 0) { 271 fcc -= cc; 272 fbp += cc; 273 } 274 } 275 } 276 } 277 278 cleanup() 279 { 280 281 rmut(); 282 vhangup(); /* XXX */ 283 shutdown(netf, 2); 284 kill(0, SIGKILL); 285 exit(1); 286 } 287 288 fatal(f, msg) 289 int f; 290 char *msg; 291 { 292 char buf[BUFSIZ]; 293 294 buf[0] = '\01'; /* error indicator */ 295 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 296 (void) write(f, buf, strlen(buf)); 297 exit(1); 298 } 299 300 fatalperror(f, msg, errno) 301 int f; 302 char *msg; 303 int errno; 304 { 305 char buf[BUFSIZ]; 306 extern int sys_nerr; 307 extern char *sys_errlist[]; 308 309 if ((unsigned)errno < sys_nerr) 310 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 311 else 312 (void) sprintf(buf, "%s: Error %d", msg, errno); 313 fatal(f, buf); 314 } 315 316 #include <utmp.h> 317 318 struct utmp wtmp; 319 char wtmpf[] = "/usr/adm/wtmp"; 320 char utmp[] = "/etc/utmp"; 321 #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 322 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 323 324 rmut() 325 { 326 register f; 327 int found = 0; 328 329 f = open(utmp, O_RDWR); 330 if (f >= 0) { 331 while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 332 if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 333 continue; 334 lseek(f, -(long)sizeof(wtmp), L_INCR); 335 SCPYN(wtmp.ut_name, ""); 336 SCPYN(wtmp.ut_host, ""); 337 time(&wtmp.ut_time); 338 write(f, (char *)&wtmp, sizeof(wtmp)); 339 found++; 340 } 341 close(f); 342 } 343 if (found) { 344 f = open(wtmpf, O_WRONLY); 345 if (f >= 0) { 346 SCPYN(wtmp.ut_line, line+5); 347 SCPYN(wtmp.ut_name, ""); 348 SCPYN(wtmp.ut_host, ""); 349 time(&wtmp.ut_time); 350 lseek(f, (long)0, L_XTND); 351 write(f, (char *)&wtmp, sizeof(wtmp)); 352 close(f); 353 } 354 } 355 chmod(line, 0666); 356 chown(line, 0, 0); 357 line[strlen("/dev/")] = 'p'; 358 chmod(line, 0666); 359 chown(line, 0, 0); 360 } 361