1 #ifndef lint 2 static char sccsid[] = "@(#)rlogind.c 4.11 83/02/21"; 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 signal(SIGCHLD, SIG_IGN); 106 doit(s, &from); 107 } 108 close(s); 109 } 110 } 111 112 reapchild() 113 { 114 union wait status; 115 116 while (wait3(&status, WNOHANG, 0) > 0) 117 ; 118 } 119 120 char locuser[32], remuser[32]; 121 char buf[BUFSIZ]; 122 int child; 123 int cleanup(); 124 int netf; 125 extern errno; 126 char *line; 127 128 doit(f, fromp) 129 int f; 130 struct sockaddr_in *fromp; 131 { 132 char c; 133 int i, p, cc, t, pid; 134 int stop = TIOCPKT_DOSTOP; 135 register struct hostent *hp; 136 137 alarm(60); 138 read(f, &c, 1); 139 if (c != 0) 140 exit(1); 141 alarm(0); 142 fromp->sin_port = htons((u_short)fromp->sin_port); 143 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 144 fromp->sin_family); 145 if (hp == 0) 146 fatal(f, "Host name for your address unknown"); 147 if (fromp->sin_family != AF_INET || 148 fromp->sin_port >= IPPORT_RESERVED || 149 hp == 0) 150 fatal(f, "Permission denied"); 151 write(f, "", 1); 152 for (c = 'p'; c <= 's'; c++) { 153 struct stat stb; 154 line = "/dev/ptyXX"; 155 line[strlen("/dev/pty")] = c; 156 line[strlen("/dev/ptyp")] = '0'; 157 if (stat(line, &stb) < 0) 158 break; 159 for (i = 0; i < 16; i++) { 160 line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 161 p = open(line, 2); 162 if (p > 0) 163 goto gotpty; 164 } 165 } 166 fatal(f, "All network ports in use"); 167 /*NOTREACHED*/ 168 gotpty: 169 dup2(f, 0); 170 line[strlen("/dev/")] = 't'; 171 #ifdef DEBUG 172 { int tt = open("/dev/tty", 2); 173 if (tt > 0) { 174 ioctl(tt, TIOCNOTTY, 0); 175 close(tt); 176 } 177 } 178 #endif 179 t = open(line, 2); 180 if (t < 0) 181 fatalperror(f, line, errno); 182 { struct sgttyb b; 183 gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b); 184 } 185 pid = fork(); 186 if (pid < 0) 187 fatalperror(f, "", errno); 188 if (pid) { 189 char pibuf[1024], fibuf[1024], *pbp, *fbp; 190 int pcc = 0, fcc = 0, on = 1; 191 /* FILE *console = fopen("/dev/console", "w"); */ 192 /* setbuf(console, 0); */ 193 194 /* fprintf(console, "f %d p %d\r\n", f, p); */ 195 ioctl(f, FIONBIO, &on); 196 ioctl(p, FIONBIO, &on); 197 ioctl(p, TIOCPKT, &on); 198 signal(SIGTSTP, SIG_IGN); 199 sigset(SIGCHLD, cleanup); 200 for (;;) { 201 int ibits = 0, obits = 0; 202 203 if (fcc) 204 obits |= (1<<p); 205 else 206 ibits |= (1<<f); 207 if (pcc >= 0) 208 if (pcc) 209 obits |= (1<<f); 210 else 211 ibits |= (1<<p); 212 if (fcc < 0 && pcc < 0) 213 break; 214 /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */ 215 select(16, &ibits, &obits, 0, 0, 0); 216 /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */ 217 if (ibits == 0 && obits == 0) { 218 sleep(5); 219 continue; 220 } 221 if (ibits & (1<<f)) { 222 fcc = read(f, fibuf, sizeof (fibuf)); 223 /* fprintf(console, "%d from f\r\n", fcc); */ 224 if (fcc < 0 && errno == EWOULDBLOCK) 225 fcc = 0; 226 else { 227 if (fcc <= 0) 228 break; 229 fbp = fibuf; 230 } 231 } 232 if (ibits & (1<<p)) { 233 pcc = read(p, pibuf, sizeof (pibuf)); 234 /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */ 235 pbp = pibuf; 236 if (pcc < 0 && errno == EWOULDBLOCK) 237 pcc = 0; 238 else if (pcc <= 0) 239 pcc = -1; 240 else if (pibuf[0] == 0) 241 pbp++, pcc--; 242 else { 243 if (pibuf[0]&(TIOCPKT_FLUSHWRITE| 244 TIOCPKT_NOSTOP| 245 TIOCPKT_DOSTOP)) { 246 int nstop = pibuf[0] & 247 (TIOCPKT_NOSTOP| 248 TIOCPKT_DOSTOP); 249 if (nstop) 250 stop = nstop; 251 pibuf[0] |= nstop; 252 send(f,&pibuf[0],1,SOF_OOB); 253 } 254 pcc = 0; 255 } 256 } 257 if ((obits & (1<<f)) && pcc > 0) { 258 cc = write(f, pbp, pcc); 259 /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */ 260 if (cc > 0) { 261 pcc -= cc; 262 pbp += cc; 263 } 264 } 265 if ((obits & (1<<p)) && fcc > 0) { 266 cc = write(p, fbp, fcc); 267 /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */ 268 if (cc > 0) { 269 fcc -= cc; 270 fbp += cc; 271 } 272 } 273 } 274 cleanup(); 275 } 276 close(f); 277 close(p); 278 dup2(t, 0); 279 dup2(t, 1); 280 dup2(t, 2); 281 close(t); 282 execl("/bin/login", "login", "-r", hp->h_name, 0); 283 fatalperror(2, "/bin/login", errno); 284 /*NOTREACHED*/ 285 } 286 287 cleanup() 288 { 289 290 rmut(); 291 vhangup(); /* XXX */ 292 shutdown(netf, 2); 293 kill(0, SIGKILL); 294 exit(1); 295 } 296 297 fatal(f, msg) 298 int f; 299 char *msg; 300 { 301 char buf[BUFSIZ]; 302 303 buf[0] = '\01'; /* error indicator */ 304 (void) sprintf(buf + 1, "rlogind: %s.\n", msg); 305 (void) write(f, buf, strlen(buf)); 306 exit(1); 307 } 308 309 fatalperror(f, msg, errno) 310 int f; 311 char *msg; 312 int errno; 313 { 314 char buf[BUFSIZ]; 315 extern char *sys_errlist[]; 316 317 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 318 fatal(f, buf); 319 } 320 321 #include <utmp.h> 322 323 struct utmp wtmp; 324 char wtmpf[] = "/usr/adm/wtmp"; 325 char utmp[] = "/etc/utmp"; 326 #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 327 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 328 329 rmut() 330 { 331 register f; 332 int found = 0; 333 334 f = open(utmp, 2); 335 if (f >= 0) { 336 while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { 337 if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 338 continue; 339 lseek(f, -(long)sizeof(wtmp), 1); 340 SCPYN(wtmp.ut_name, ""); 341 time(&wtmp.ut_time); 342 write(f, (char *)&wtmp, sizeof(wtmp)); 343 found++; 344 } 345 close(f); 346 } 347 if (found) { 348 f = open(wtmpf, 1); 349 if (f >= 0) { 350 SCPYN(wtmp.ut_line, line+5); 351 SCPYN(wtmp.ut_name, ""); 352 time(&wtmp.ut_time); 353 lseek(f, (long)0, 2); 354 write(f, (char *)&wtmp, sizeof(wtmp)); 355 close(f); 356 } 357 } 358 chmod(line, 0666); 359 chown(line, 0, 0); 360 line[strlen("/dev/")] = 'p'; 361 chmod(line, 0666); 362 chown(line, 0, 0); 363 } 364