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