1 #ifndef lint 2 static char sccsid[] = "@(#)rlogin.c 4.11 83/03/31"; 3 #endif 4 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 8 #include <netinet/in.h> 9 10 #include <stdio.h> 11 #include <sgtty.h> 12 #include <errno.h> 13 #include <pwd.h> 14 #include <signal.h> 15 #include <netdb.h> 16 #include <wait.h> 17 18 /* 19 * rlogin - remote login 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 sigset(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 ]\n"); 114 exit(1); 115 } 116 117 #define CRLF "\r\n" 118 119 int child; 120 int catchild(); 121 122 int defflags; 123 struct ttychars deftc; 124 struct ttychars notc = { 125 -1, -1, -1, -1, -1, 126 -1, -1, -1, -1, -1, 127 -1, -1, -1, -1 128 }; 129 130 doit() 131 { 132 int exit(); 133 134 ioctl(0, TIOCGET, (char *)&defflags); 135 defflags &= ECHO | CRMOD; 136 ioctl(0, TIOCCGET, (char *)&deftc); 137 notc.tc_startc = deftc.tc_startc; 138 notc.tc_stopc = deftc.tc_stopc; 139 sigset(SIGINT, exit); 140 sigset(SIGHUP, exit); 141 sigset(SIGQUIT, exit); 142 child = fork(); 143 if (child == -1) { 144 perror("rlogin: fork"); 145 done(); 146 } 147 sigignore(SIGINT); 148 mode(1); 149 if (child == 0) { 150 reader(); 151 prf("\007Lost connection."); 152 exit(3); 153 } 154 sigset(SIGCHLD, catchild); 155 writer(); 156 prf("Disconnected."); 157 done(); 158 } 159 160 done() 161 { 162 163 mode(0); 164 if (child > 0 && kill(child, SIGKILL) >= 0) 165 wait((int *)0); 166 exit(0); 167 } 168 169 catchild() 170 { 171 union wait status; 172 int pid; 173 174 again: 175 pid = wait3(&status, WNOHANG|WUNTRACED, 0); 176 if (pid == 0) 177 return; 178 /* 179 * if the child (reader) dies, just quit 180 */ 181 if (pid < 0 || pid == child && !WIFSTOPPED(status)) 182 done(); 183 goto again; 184 } 185 186 /* 187 * writer: write to remote: 0 -> line. 188 * ~. terminate 189 * ~^Z suspend rlogin process. 190 * ~^Y suspend rlogin process, but leave reader alone. 191 */ 192 writer() 193 { 194 char b[600], c; 195 register char *p; 196 register n; 197 198 top: 199 p = b; 200 for (;;) { 201 int local; 202 203 n = read(0, &c, 1); 204 if (n == 0) 205 break; 206 if (n < 0) 207 if (errno == EINTR) 208 continue; 209 else 210 break; 211 212 if (eight == 0) 213 c &= 0177; 214 /* 215 * If we're at the beginning of the line 216 * and recognize a command character, then 217 * we echo locally. Otherwise, characters 218 * are echo'd remotely. If the command 219 * character is doubled, this acts as a 220 * force and local echo is suppressed. 221 */ 222 if (p == b) 223 local = (c == cmdchar); 224 if (p == b + 1 && *b == cmdchar) 225 local = (c != cmdchar); 226 if (!local) { 227 if (write(rem, &c, 1) == 0) { 228 prf("line gone"); 229 return; 230 } 231 if (eight == 0) 232 c &= 0177; 233 } else { 234 if (c == 0177) 235 c = deftc.tc_kill; 236 if (c == '\r' || c == '\n') { 237 char cmdc = b[1]; 238 239 if (cmdc == '.' || cmdc == deftc.tc_eofc) { 240 write(0, CRLF, sizeof(CRLF)); 241 return; 242 } 243 if (cmdc == deftc.tc_suspc || 244 cmdc == deftc.tc_dsuspc) { 245 write(0, CRLF, sizeof(CRLF)); 246 mode(0); 247 sigignore(SIGCHLD); 248 kill(cmdc == deftc.tc_suspc ? 249 0 : getpid(), SIGTSTP); 250 sigrelse(SIGCHLD); 251 mode(1); 252 goto top; 253 } 254 *p++ = c; 255 write(rem, b, p - b); 256 goto top; 257 } 258 write(1, &c, 1); 259 } 260 *p++ = c; 261 if (c == deftc.tc_erase) { 262 p -= 2; 263 if (p < b) 264 goto top; 265 } 266 if (c == deftc.tc_kill || c == 0177 || c == deftc.tc_eofc || 267 c == '\r' || c == '\n') 268 goto top; 269 if (p >= &b[sizeof b]) 270 p--; 271 } 272 } 273 274 oob() 275 { 276 int out = 1+1, atmark; 277 char waste[BUFSIZ], mark; 278 279 ioctl(1, TIOCFLUSH, (char *)&out); 280 for (;;) { 281 if (ioctl(rem, SIOCATMARK, &atmark) < 0) { 282 perror("ioctl"); 283 break; 284 } 285 if (atmark) 286 break; 287 (void) read(rem, waste, sizeof (waste)); 288 } 289 recv(rem, &mark, 1, SOF_OOB); 290 if (mark & TIOCPKT_NOSTOP) { 291 notc.tc_stopc = -1; 292 notc.tc_startc = -1; 293 ioctl(0, TIOCCSET, (char *)¬c); 294 } 295 if (mark & TIOCPKT_DOSTOP) { 296 notc.tc_stopc = deftc.tc_stopc; 297 notc.tc_startc = deftc.tc_startc; 298 ioctl(0, TIOCCSET, (char *)¬c); 299 } 300 } 301 302 /* 303 * reader: read from remote: line -> 1 304 */ 305 reader() 306 { 307 char rb[BUFSIZ]; 308 register int cnt; 309 310 sigset(SIGURG, oob); 311 { int pid = -getpid(); 312 ioctl(rem, SIOCSPGRP, (char *)&pid); } 313 for (;;) { 314 cnt = read(rem, rb, sizeof (rb)); 315 if (cnt == 0) 316 break; 317 if (cnt < 0) { 318 if (errno == EINTR) 319 continue; 320 break; 321 } 322 write(1, rb, cnt); 323 } 324 } 325 326 mode(f) 327 { 328 struct ttychars *tc; 329 int flags; 330 331 ioctl(0, TIOCGET, (char *)&flags); 332 switch (f) { 333 334 case 0: 335 flags &= ~CBREAK; 336 flags |= defflags; 337 tc = &deftc; 338 break; 339 340 case 1: 341 flags |= CBREAK; 342 flags &= ~defflags; 343 tc = ¬c; 344 break; 345 346 default: 347 return; 348 } 349 ioctl(0, TIOCSET, (char *)&flags); 350 ioctl(0, TIOCCSET, (char *)tc); 351 } 352 353 /*VARARGS*/ 354 prf(f, a1, a2, a3) 355 char *f; 356 { 357 fprintf(stderr, f, a1, a2, a3); 358 fprintf(stderr, CRLF); 359 } 360 361 lostpeer() 362 { 363 sigignore(SIGPIPE); 364 prf("\007Lost connection"); 365 done(); 366 } 367