1 #ifndef lint 2 static char sccsid[] = "@(#)rlogin.c 4.14 83/06/13"; 3 #endif 4 5 /* 6 * rlogin - remote login 7 */ 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 11 #include <netinet/in.h> 12 13 #include <stdio.h> 14 #include <sgtty.h> 15 #include <errno.h> 16 #include <pwd.h> 17 #include <signal.h> 18 #include <netdb.h> 19 #include <wait.h> 20 21 char *index(), *rindex(), *malloc(), *getenv(); 22 struct passwd *getpwuid(); 23 char *name; 24 int rem; 25 char cmdchar = '~'; 26 int eight; 27 char *speeds[] = 28 { "0", "50", "75", "110", "134", "150", "200", "300", 29 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 30 char term[64] = "network"; 31 extern int errno; 32 int lostpeer(); 33 34 main(argc, argv) 35 int argc; 36 char **argv; 37 { 38 char *host, *cp; 39 struct sgttyb ttyb; 40 struct passwd *pwd; 41 struct servent *sp; 42 int uid, options = 0; 43 44 host = rindex(argv[0], '/'); 45 if (host) 46 host++; 47 else 48 host = argv[0]; 49 argv++, --argc; 50 if (!strcmp(host, "rlogin")) 51 host = *argv++, --argc; 52 another: 53 if (argc > 0 && !strcmp(*argv, "-d")) { 54 argv++, argc--; 55 options |= SO_DEBUG; 56 goto another; 57 } 58 if (argc > 0 && !strcmp(*argv, "-l")) { 59 argv++, argc--; 60 if (argc == 0) 61 goto usage; 62 name = *argv++; argc--; 63 goto another; 64 } 65 if (argc > 0 && !strncmp(*argv, "-e", 2)) { 66 cmdchar = argv[0][2]; 67 argv++, argc--; 68 goto another; 69 } 70 if (argc > 0 && !strcmp(*argv, "-8")) { 71 eight = 1; 72 argv++, argc--; 73 goto another; 74 } 75 if (host == 0) 76 goto usage; 77 if (argc > 0) 78 goto usage; 79 pwd = getpwuid(getuid()); 80 if (pwd == 0) { 81 fprintf(stderr, "Who are you?\n"); 82 exit(1); 83 } 84 sp = getservbyname("login", "tcp"); 85 if (sp == 0) { 86 fprintf(stderr, "rlogin: login/tcp: unknown service\n"); 87 exit(2); 88 } 89 cp = getenv("TERM"); 90 if (cp) 91 strcpy(term, cp); 92 if (ioctl(0, TIOCGETP, &ttyb)==0) { 93 strcat(term, "/"); 94 strcat(term, speeds[ttyb.sg_ospeed]); 95 } 96 signal(SIGPIPE, lostpeer); 97 rem = rcmd(&host, sp->s_port, pwd->pw_name, 98 name ? name : pwd->pw_name, term, 0); 99 if (rem < 0) 100 exit(1); 101 if (options & SO_DEBUG && 102 setsockopt(rem, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 103 perror("rlogin: setsockopt (SO_DEBUG)"); 104 uid = getuid(); 105 if (setuid(uid) < 0) { 106 perror("rlogin: setuid"); 107 exit(1); 108 } 109 doit(); 110 /*NOTREACHED*/ 111 usage: 112 fprintf(stderr, 113 "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n"); 114 exit(1); 115 } 116 117 #define CRLF "\r\n" 118 119 int child; 120 int catchild(); 121 122 int defflags, tabflag; 123 char deferase, defkill; 124 struct tchars deftc; 125 struct ltchars defltc; 126 struct tchars notc = { -1, -1, -1, -1, -1, -1 }; 127 struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; 128 129 doit() 130 { 131 int exit(); 132 struct sgttyb sb; 133 134 ioctl(0, TIOCGETP, (char *)&sb); 135 defflags = sb.sg_flags; 136 tabflag = defflags & TBDELAY; 137 defflags &= ECHO | CRMOD; 138 deferase = sb.sg_erase; 139 defkill = sb.sg_kill; 140 ioctl(0, TIOCGETC, (char *)&deftc); 141 notc.t_startc = deftc.t_startc; 142 notc.t_stopc = deftc.t_stopc; 143 ioctl(0, TIOCGLTC, (char *)&defltc); 144 signal(SIGINT, exit); 145 signal(SIGHUP, exit); 146 signal(SIGQUIT, exit); 147 child = fork(); 148 if (child == -1) { 149 perror("rlogin: fork"); 150 done(); 151 } 152 signal(SIGINT, SIG_IGN); 153 mode(1); 154 if (child == 0) { 155 reader(); 156 sleep(1); 157 prf("\007Connection closed."); 158 exit(3); 159 } 160 signal(SIGCHLD, catchild); 161 writer(); 162 prf("Closed connection."); 163 done(); 164 } 165 166 done() 167 { 168 169 mode(0); 170 if (child > 0 && kill(child, SIGKILL) >= 0) 171 wait((int *)0); 172 exit(0); 173 } 174 175 catchild() 176 { 177 union wait status; 178 int pid; 179 180 again: 181 pid = wait3(&status, WNOHANG|WUNTRACED, 0); 182 if (pid == 0) 183 return; 184 /* 185 * if the child (reader) dies, just quit 186 */ 187 if (pid < 0 || pid == child && !WIFSTOPPED(status)) 188 done(); 189 goto again; 190 } 191 192 /* 193 * writer: write to remote: 0 -> line. 194 * ~. terminate 195 * ~^Z suspend rlogin process. 196 * ~^Y suspend rlogin process, but leave reader alone. 197 */ 198 writer() 199 { 200 char b[600], c; 201 register char *p; 202 register n; 203 204 top: 205 p = b; 206 for (;;) { 207 int local; 208 209 n = read(0, &c, 1); 210 if (n == 0) 211 break; 212 if (n < 0) 213 if (errno == EINTR) 214 continue; 215 else 216 break; 217 218 if (eight == 0) 219 c &= 0177; 220 /* 221 * If we're at the beginning of the line 222 * and recognize a command character, then 223 * we echo locally. Otherwise, characters 224 * are echo'd remotely. If the command 225 * character is doubled, this acts as a 226 * force and local echo is suppressed. 227 */ 228 if (p == b) 229 local = (c == cmdchar); 230 if (p == b + 1 && *b == cmdchar) 231 local = (c != cmdchar); 232 if (!local) { 233 if (write(rem, &c, 1) == 0) { 234 prf("line gone"); 235 return; 236 } 237 if (eight == 0) 238 c &= 0177; 239 } else { 240 if (c == '\r' || c == '\n') { 241 char cmdc = b[1]; 242 243 if (cmdc == '.' || cmdc == deftc.t_eofc) { 244 write(0, CRLF, sizeof(CRLF)); 245 return; 246 } 247 if (cmdc == defltc.t_suspc || 248 cmdc == defltc.t_dsuspc) { 249 write(0, CRLF, sizeof(CRLF)); 250 mode(0); 251 signal(SIGCHLD, SIG_IGN); 252 kill(cmdc == defltc.t_suspc ? 253 0 : getpid(), SIGTSTP); 254 signal(SIGCHLD, catchild); 255 mode(1); 256 goto top; 257 } 258 *p++ = c; 259 write(rem, b, p - b); 260 goto top; 261 } 262 write(1, &c, 1); 263 } 264 *p++ = c; 265 if (c == deferase) { 266 p -= 2; 267 if (p < b) 268 goto top; 269 } 270 if (c == defkill || c == deftc.t_eofc || 271 c == '\r' || c == '\n') 272 goto top; 273 if (p >= &b[sizeof b]) 274 p--; 275 } 276 } 277 278 oob() 279 { 280 int out = 1+1, atmark; 281 char waste[BUFSIZ], mark; 282 283 ioctl(1, TIOCFLUSH, (char *)&out); 284 for (;;) { 285 if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 286 perror("ioctl"); 287 break; 288 } 289 if (atmark) 290 break; 291 (void) read(rem, waste, sizeof (waste)); 292 } 293 recv(rem, &mark, 1, MSG_OOB); 294 if (mark & TIOCPKT_NOSTOP) { 295 notc.t_stopc = -1; 296 notc.t_startc = -1; 297 ioctl(0, TIOCSETC, (char *)¬c); 298 } 299 if (mark & TIOCPKT_DOSTOP) { 300 notc.t_stopc = deftc.t_stopc; 301 notc.t_startc = deftc.t_startc; 302 ioctl(0, TIOCSETC, (char *)¬c); 303 } 304 } 305 306 /* 307 * reader: read from remote: line -> 1 308 */ 309 reader() 310 { 311 char rb[BUFSIZ]; 312 register int cnt; 313 314 signal(SIGURG, oob); 315 { int pid = -getpid(); 316 ioctl(rem, SIOCSPGRP, (char *)&pid); } 317 for (;;) { 318 cnt = read(rem, rb, sizeof (rb)); 319 if (cnt == 0) 320 break; 321 if (cnt < 0) { 322 if (errno == EINTR) 323 continue; 324 break; 325 } 326 write(1, rb, cnt); 327 } 328 } 329 330 mode(f) 331 { 332 struct tchars *tc; 333 struct ltchars *ltc; 334 struct sgttyb sb; 335 336 ioctl(0, TIOCGETP, (char *)&sb); 337 switch (f) { 338 339 case 0: 340 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); 341 sb.sg_flags |= defflags|tabflag; 342 tc = &deftc; 343 ltc = &defltc; 344 sb.sg_kill = defkill; 345 sb.sg_erase = deferase; 346 break; 347 348 case 1: 349 sb.sg_flags |= (eight ? RAW : CBREAK); 350 sb.sg_flags &= ~defflags; 351 /* preserve tab delays, but turn off XTABS */ 352 if ((sb.sg_flags & TBDELAY) == XTABS) 353 sb.sg_flags &= ~TBDELAY; 354 tc = ¬c; 355 ltc = &noltc; 356 sb.sg_kill = sb.sg_erase = -1; 357 break; 358 359 default: 360 return; 361 } 362 ioctl(0, TIOCSLTC, (char *)ltc); 363 ioctl(0, TIOCSETC, (char *)tc); 364 ioctl(0, TIOCSETN, (char *)&sb); 365 } 366 367 /*VARARGS*/ 368 prf(f, a1, a2, a3) 369 char *f; 370 { 371 fprintf(stderr, f, a1, a2, a3); 372 fprintf(stderr, CRLF); 373 } 374 375 lostpeer() 376 { 377 signal(SIGPIPE, SIG_IGN); 378 prf("\007Connection closed."); 379 done(); 380 } 381