xref: /original-bsd/usr.bin/rlogin/rlogin.c (revision fbed46ce)
1 #ifndef lint
2 static char sccsid[] = "@(#)rlogin.c	4.2 82/04/06";
3 #endif
4 
5 #include <stdio.h>
6 #include <sgtty.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <net/in.h>
10 #include <errno.h>
11 #include <pwd.h>
12 
13 /*
14  * rlogin - remote login; this is a hacked version of cu
15  */
16 char	*index(), *rindex(), *malloc(), *getenv();
17 struct	passwd *getpwuid();
18 struct	passwd *pwd;
19 char	*name, *pass;
20 int	rem;
21 char	cmdchar = '~';
22 int	rcmdoptions = 0;
23 int	eight;
24 char	*speeds[] =
25     { "0", "50", "75", "110", "134", "150", "200", "300",
26       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
27 char	term[64];
28 
29 main(argc, argv)
30 	int argc;
31 	char **argv;
32 {
33 	int pid;
34 	char *host, *cp, **ap, buf[BUFSIZ];
35 	register int cc;
36 	struct sgttyb ttyb;
37 	struct passwd *pwd;
38 
39 	host = rindex(argv[0], '/');
40 	if (host)
41 		host++;
42 	else
43 		host = argv[0];
44 	argv++, --argc;
45 	if (!strcmp(host, "rlogin"))
46 		host = *argv++, --argc;
47 another:
48 	if (!strcmp(*argv, "-d")) {
49 		argv++, argc--;
50 		rcmdoptions |= SO_DEBUG;
51 		goto another;
52 	}
53 	if (!strcmp(*argv, "-l")) {
54 		argv++, argc--;
55 		if (argc == 0)
56 			goto usage;
57 		name = *argv++; argc--;
58 		goto another;
59 	}
60 	if (!strncmp(*argv, "-e", 2)) {
61 		cmdchar = argv[0][2];
62 		argv++, argc--;
63 		goto another;
64 	}
65 	if (!strcmp(*argv, "-8")) {
66 		eight = 1;
67 		argv++, argc--;
68 		goto another;
69 	}
70 	if (host == 0)
71 		goto usage;
72 	if (argc > 0)
73 		goto usage;
74 	pwd = getpwuid(getuid());
75 	if (pwd == 0) {
76 		fprintf(stderr, "Who are you?\n");
77 		exit(1);
78 	}
79 	cc = 0;
80 	strcpy(term, getenv("TERM"));
81 	if (gtty(0, &ttyb)==0) {
82 		strcat(term, "/");
83 		strcat(term, speeds[ttyb.sg_ospeed]);
84 	}
85         rem = rcmd(&host, IPPORT_LOGINSERVER, pwd->pw_name,
86 	    name ? name : pwd->pw_name, term, 0);
87         if (rem < 0)
88                 exit(1);
89 	setuid(getuid());
90 	cumain();
91 	exit(0);
92 usage:
93 	fprintf(stderr,
94 	    "usage: rlogin host [ -ex ] [ -l username ]\n");
95 	exit(1);
96 }
97 
98 #include <ctype.h>
99 #include <signal.h>
100 
101 #define CRLF "\r\n"
102 #define wrc(ds) write(ds,&c,1)
103 
104 char	tkill, terase;	/* current input kill & erase */
105 int	efk;		/* process of id of listener  */
106 char	c, oc;
107 int	pipes[] = {-1,-1};
108 int	intr, sig2();
109 int	parent;
110 
111 int	nhup;
112 int	done();
113 
114 struct tchars deftchars;
115 struct tchars notchars = { 0377, 0377, 'q'&037, 's'&037, 0377, 0377 };
116 struct ltchars defltchars;
117 struct ltchars noltchars = { 0377, 0377, 0377, 0377, 0377, 0377 };
118 char defkill, deferase, defflags;
119 
120 cumain()
121 {
122 	int fk;
123 	int speed;
124 	char *telno;
125 	struct sgttyb stbuf;
126 	int exit();
127 
128 	gtty(0, &stbuf);
129 	defkill = stbuf.sg_kill;
130 	deferase = stbuf.sg_erase;
131 	defflags = stbuf.sg_flags & (ECHO | CRMOD);
132 	ioctl(0, TIOCGETC, &deftchars);
133 	ioctl(0, TIOCGLTC, &defltchars);
134 	signal(SIGINT, exit);
135 	signal(SIGHUP, exit);
136 	signal(SIGQUIT, exit);
137 	pipe(pipes);
138 	parent = getpid();
139 	fk = fork();
140 	nhup = (int)signal(SIGINT, SIG_IGN);
141 	if (fk == 0) {
142 		rd();
143 		sleep(1);
144 		prf("\007Lost connection.");
145 		exit(3);
146 	}
147 	signal(SIGCHLD, done);
148 	mode(1);
149 	efk = fk;
150 	wr();
151 	if (fk != -1) kill(fk, SIGKILL);
152 	prf("Disconnected.");
153 	done();
154 }
155 
156 done()
157 {
158 
159 	mode(0);
160 	wait((int *)NULL);
161 	exit(0);
162 }
163 
164 /*
165  *	wr: write to remote: 0 -> line.
166  *	~.	terminate
167  *	~<file	send file
168  *	~!	local login-style shell
169  *	~!cmd	execute cmd locally
170  *	~$proc	execute proc locally, send output to line
171  *	~%cmd	execute builtin cmd (put and take)
172  *	~^Z	suspend cu process.
173  */
174 
175 wr()
176 {
177 	int ds,fk,lcl,x;
178 	char *p,b[600];
179 	for (;;) {
180 		p=b;
181 		while (rdc(0) == 1) {
182 			if (p == b) lcl=(c == cmdchar);
183 			if (p == b+1 && b[0] == cmdchar) lcl=(c!=cmdchar);
184 			if (!lcl) {
185 				c = oc;
186 				if (wrc(rem) == 0) {
187 					prf("line gone"); return;
188 				}
189 				if (eight == 0)
190 					c &= 0177;
191 			}
192 			if (lcl) {
193 				if (c == 0177) c=tkill;
194 				if (c == '\r' || c == '\n') goto A;
195 				wrc(0);
196 			}
197 			*p++=c;
198 			if (c == terase) {
199 				p=p-2;
200 				if (p<b) p=b;
201 			}
202 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
203 		}
204 		return;
205 A:
206 		echo("");
207 		*p=0;
208 		switch (b[1]) {
209 		case '.':
210 		case '\004':
211 			return;
212 		case '!':
213 		case '$':
214 			fk = fork();
215 			signal(SIGCHLD, SIG_DFL);
216 			if (fk == 0) {
217 				char *shell = getenv("SHELL");
218 				if (shell == 0) shell = "/bin/sh";
219 				close(1);
220 				dup(b[1] == '$'? rem:2);
221 				close(rem);
222 				mode(0);
223 				if (!nhup) signal(SIGINT, SIG_DFL);
224 				if (b[2] == 0) execl(shell,shell,0);
225 				/* if (b[2] == 0) execl(shell,"-",0); */
226 				else execl(shell,"sh","-c",b+2,0);
227 				prf("Can't execute shell");
228 				exit(~0);
229 			}
230 			if (fk!=(-1)) {
231 				while (wait(&x)!=fk);
232 			}
233 			signal(SIGCHLD, done);
234 			mode(1);
235 			if (b[1] == '!') echo("!");
236 			break;
237 		case '<':
238 			if (b[2] == 0) break;
239 			if ((ds=open(b+2,0))<0) {
240 				prf("Can't divert %s",b+1);
241 				break;
242 			}
243 			intr=x=0;
244 			mode(2);
245 			if (!nhup) signal(SIGINT, sig2);
246 			while (!intr && rdc(ds) == 1) {
247 				if (wrc(rem) == 0) {
248 					x=1;
249 					break;
250 				}
251 			}
252 			signal(SIGINT, SIG_IGN);
253 			close(ds);
254 			mode(1);
255 			if (x) return;
256 			break;
257 		case '>':
258 		case ':':
259 			{
260 			register char *q;
261 
262 			q = b+1;
263 			if(*q=='>') q++;
264 			write(pipes[1],q,strlen(q)+1);
265 			if (efk != -1) kill(efk,SIGEMT);
266 			}
267 			break;
268 #ifdef SIGTSTP
269 #define CTRLZ	26
270 		case CTRLZ:
271 			mode(0);
272 			signal(SIGCHLD, SIG_IGN);
273 			kill(0, SIGTSTP);
274 			signal(SIGCHLD, done);
275 			mode(1);
276 			break;
277 #endif
278 		case '%':
279 			dopercen(&b[2]);
280 			break;
281 		default:
282 			prf("Use `%c%c' to start line with `%c'", cmdchar, cmdchar, cmdchar);
283 		}
284 		continue;
285 	}
286 }
287 
288 dopercen(line)
289 register char *line;
290 {
291 	char *args[10];
292 	register narg, f;
293 	int rcount;
294 	for (narg = 0; narg < 10;) {
295 		while(*line == ' ' || *line == '\t')
296 			line++;
297 		if (*line == '\0')
298 			break;
299 		args[narg++] = line;
300 		while(*line != '\0' && *line != ' ' && *line != '\t')
301 			line++;
302 		if (*line == '\0')
303 			break;
304 		*line++ = '\0';
305 	}
306 	if (equal(args[0], "take")) {
307 		if (narg < 2) {
308 			prf("usage: %c%%take from [to]", cmdchar);
309 			return;
310 		}
311 		if (narg < 3)
312 			args[2] = args[1];
313 		write(pipes[1], ">/dev/null",sizeof(">/dev/null"));
314 		if (efk != -1) kill(efk,SIGEMT);
315 		sleep(5);
316 		wrln("echo '%c>:", cmdchar);
317 		wrln(args[2]);
318 		wrln("'; tee /dev/null <");
319 		wrln(args[1]);
320 		wrln(";echo '%c>'\n", cmdchar);
321 		return;
322 	} else if (equal(args[0], "put")) {
323 		prf("%c%%put doesn't work yet (use rsh)", cmdchar);
324 		return;
325 /*
326 		if (narg < 2) {
327 			prf("usage: %c%%put from [to]", cmdchar);
328 			return;
329 		}
330 		if (narg < 3)
331 			args[2] = args[1];
332 		if ((f = open(args[1], 0)) < 0) {
333 			prf("cannot open: %s", args[1]);
334 			return;
335 		}
336 		wrln("stty -echo;cat >");
337 		wrln(args[2]);
338 		wrln(";stty echo\n");
339 		sleep(5);
340 		intr = 0;
341 		if (!nhup)
342 			signal(SIGINT, sig2);
343 		mode(2);
344 		rcount = 0;
345 		while(!intr && rdc(f) == 1) {
346 			rcount++;
347 			if (c == tkill || c == terase)
348 				wrln("\\");
349 			if (wrc(rem) != 1) {
350 				sleep(2);
351 				if (wrc(rem) != 1) {
352 					prf("character missed");
353 					intr = 1;
354 					break;
355 				}
356 			}
357 		}
358 		signal(SIGINT, SIG_IGN);
359 		close(f);
360 		if (intr) {
361 			wrln("\n");
362 			prf("stopped after %d bytes", rcount);
363 		}
364 		wrln("\004");
365 		sleep(5);
366 		mode(1);
367 		return;
368 */
369 	}
370 	prf("%c%%%s unknown\n", cmdchar, args[0]);
371 }
372 
373 equal(s1, s2)
374 register char *s1, *s2;
375 {
376 	while (*s1++ == *s2)
377 		if (*s2++ == '\0')
378 			return(1);
379 	return(0);
380 }
381 
382 wrln(s, p1, p2, p3)
383 register char *s;
384 int p1, p2, p3;
385 {
386 	char wbuf[256];
387 
388 	sprintf(wbuf, s, p1, p2, p3);
389 	s = wbuf;
390 	while (*s)
391 		write(rem, s++, 1);
392 }
393 int ds,slnt;
394 int justrung;
395 
396 /*
397  *	rd: read from remote: line -> 1
398  *	catch:
399  *	~>[>][:][file]
400  *	stuff from file...
401  *	~>	(ends diversion)
402  */
403 
404 int ds,slnt,taking;
405 int justrung;
406 readmsg(){
407 	static char dobuff[128], morejunk[256];
408 	int n;
409 	justrung = 1;
410 	signal(SIGEMT,readmsg);
411 	n = read(pipes[0],morejunk,256);
412 	dodiver(morejunk);
413 }
414 
415 dodiver(msg)
416 char *msg;
417 {
418 	register char *cp = msg;
419 
420 	if (*cp=='>') cp++;
421 	if (*cp==':') {
422 		cp++;
423 		if(*cp==0) {
424 			slnt ^= 1;
425 			return;
426 		} else  {
427 			slnt = 1;
428 		}
429 	}
430 	if (ds >= 0) close(ds);
431 	if (*cp==0) {
432 		slnt = 0;
433 		ds = -1;
434 		return;
435 	}
436 	if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
437 	lseek(ds, (long)0, 2);
438 	if(ds < 0) prf("Creat failed:"), prf(cp);
439 	if (ds<0) prf("Can't divert %s",cp+1);
440 }
441 
442 
443 /*
444  *	rd: read from remote: line -> 1
445  *	catch: diversion caught by interrupt routine
446  */
447 
448 #define ORDIN 0
449 #define SAWCR 1
450 #define EOL   2
451 #define SAWTL 3
452 #define DIVER 4
453 
454 oob()
455 {
456 	int mark, cc, out = 1+1;
457 	char waste[512];
458 
459 	signal(SIGURG, oob);
460 	ioctl(1, TIOCFLUSH, &out);
461 	for (;;) {
462 		if (ioctl(rem, SIOCATMARK, &mark) < 0) {
463 			perror("ioctl");
464 			break;
465 		}
466 		if (mark)
467 			break;
468 		cc = read(rem, waste, 512);
469 	}
470 	ioctl(rem, SIOCRCVOOB, &mark);
471 	if (mark & TIOCPKT_NOSTOP) {
472 		notchars.t_stopc = 0377;
473 		notchars.t_startc = 0377;
474 		ioctl(0, TIOCSETC, &notchars);
475 	}
476 	if (mark & TIOCPKT_DOSTOP) {
477 		notchars.t_stopc = 's'&037;
478 		notchars.t_startc = 'q'&037;
479 		ioctl(0, TIOCSETC, &notchars);
480 	}
481 }
482 
483 rd()
484 {
485 	extern int ds,slnt;
486 	char rb[600], lb[600], *rlim, *llim, c;
487 	register char *p,*q;
488 	int cnt, state = 0, mustecho, oldslnt, readmsg();
489 
490 	signal(SIGEMT,readmsg);  /* set up child for catching diversion msgs
491 				    from parent */
492 	signal(SIGURG,oob);
493 	{ int pid = -getpid();
494 	  ioctl(rem, SIOCSPGRP, &pid); }
495 	ds=(-1);
496 	p = lb; llim = lb+600;
497 agin:
498 	for (;;) {
499 		extern errno;
500 		errno = 0;
501 		cnt = read(rem,rb,600);
502 		if (cnt <= 0) {
503 			if (errno == EINTR) {
504 				errno = 0;
505 				continue;
506 			}
507 			break;
508 		}
509 		if(!slnt) write(1,rb,cnt);
510 		if(ds < 0) continue;
511 		oldslnt = slnt;
512 		for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
513 			if (eight == 0)
514 			c &= 0177;
515 			if(p < llim) *p++ = c;
516 			switch(state) {
517 			case ORDIN:
518 				if(c=='\r') state = SAWCR;
519 				break;
520 			case SAWCR:
521 				if(c=='\n') {
522 					state = EOL;
523 					p--;
524 					p[-1] = '\n';
525 				} else state = ORDIN;
526 				break;
527 			case EOL:
528 				state = (c==cmdchar ? SAWTL :
529 					 (c=='\r' ? SAWCR : ORDIN));
530 				break;
531 			case SAWTL:
532 				state = (c=='>' ? DIVER :
533 					 (c=='\r' ? SAWCR : ORDIN));
534 				break;
535 			case DIVER:
536 				if(c=='\r') {
537 					p--;
538 				} else if (c=='\n') {
539 					state = ORDIN;
540 					p[-1] = 0;
541 					dodiver(lb+2);
542 					c = 0; p = lb;
543 				}
544 			}
545 			if(slnt==0 && oldslnt) {
546 				if(c=='\n') {
547 					write(rem,lb,p-lb-1);
548 					write(rem,CRLF,sizeof(CRLF));
549 				} else if(q==rlim) {
550 					write(rem,lb,p-lb);
551 					c = '\n';  /*force flush to file*/
552 				}
553 			}
554 			if(c=='\n') {
555 				if(ds >= 0)
556 					write(ds,lb,p-lb);
557 				p = lb;
558 			}
559 		}
560 	}
561 	if(justrung) {
562 		justrung = 0;
563 		goto agin;
564 	}
565 }
566 
567 struct {char lobyte; char hibyte;};
568 mode(f)
569 {
570 	struct sgttyb stbuf;
571 	ioctl(0, TIOCGETP, &stbuf);
572 	if (f == 0) {
573 		stbuf.sg_flags &= ~CBREAK;
574 		stbuf.sg_flags |= defflags;
575 		ioctl(0, TIOCSETC, &deftchars);
576 		ioctl(0, TIOCSLTC, &defltchars);
577 		stbuf.sg_kill = defkill;
578 		stbuf.sg_erase = deferase;
579 	}
580 	if (f == 1) {
581 		stbuf.sg_flags |= CBREAK;
582 		stbuf.sg_flags &= ~(ECHO|CRMOD);
583 		ioctl(0, TIOCSETC, &notchars);
584 		ioctl(0, TIOCSLTC, &noltchars);
585 		stbuf.sg_kill = 0377;
586 		stbuf.sg_erase = 0377;
587 	}
588 	if (f == 2) {
589 		stbuf.sg_flags &= ~CBREAK;
590 		stbuf.sg_flags &= ~(ECHO|CRMOD);
591 		ioctl(0, TIOCSETC, &deftchars);
592 		ioctl(0, TIOCSLTC, &defltchars);
593 		stbuf.sg_kill = 0377;
594 		stbuf.sg_erase = 0377;
595 	}
596 	ioctl(0, TIOCSETN, &stbuf);
597 }
598 
599 echo(s)
600 char *s;
601 {
602 	char *p;
603 	for (p=s;*p;p++);
604 	if (p>s) write(0,s,p-s);
605 	write(0,CRLF, sizeof(CRLF));
606 }
607 
608 prf(f, a1, a2, a3)
609 char *f;
610 {
611 	fprintf(stderr, f, a1, a2, a3);
612 	fprintf(stderr, CRLF);
613 }
614 
615 exists(devname)
616 char *devname;
617 {
618 	if (access(devname, 0)==0)
619 		return(1);
620 	prf("%s does not exist", devname);
621 	return(0);
622 }
623 
624 rdc(ds)
625 {
626 
627 	ds=read(ds,&c,1);
628 	oc = c;
629 	if (eight == 0)
630 		c &= 0177;
631 	return (ds);
632 }
633 
634 sig2()
635 {
636 	signal(SIGINT, SIG_IGN);
637 	intr = 1;
638 }
639