xref: /original-bsd/usr.bin/rlogin/rlogin.c (revision b3b53e97)
1 #ifndef lint
2 static char sccsid[] = "@(#)rlogin.c	4.1 82/04/02";
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;
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 	ioctl(0, TIOCGETC, &deftchars);
132 	ioctl(0, TIOCGLTC, &defltchars);
133 	signal(SIGINT, exit);
134 	signal(SIGHUP, exit);
135 	signal(SIGQUIT, exit);
136 	pipe(pipes);
137 	parent = getpid();
138 	fk = fork();
139 	nhup = (int)signal(SIGINT, SIG_IGN);
140 	if (fk == 0) {
141 		rd();
142 		sleep(1);
143 		prf("\007Lost connection.");
144 		exit(3);
145 	}
146 	signal(SIGCHLD, done);
147 	mode(1);
148 	efk = fk;
149 	wr();
150 	if (fk != -1) kill(fk, SIGKILL);
151 	prf("Disconnected.");
152 	done();
153 }
154 
155 done()
156 {
157 
158 	mode(0);
159 	wait((int *)NULL);
160 	exit(0);
161 }
162 
163 /*
164  *	wr: write to remote: 0 -> line.
165  *	~.	terminate
166  *	~<file	send file
167  *	~!	local login-style shell
168  *	~!cmd	execute cmd locally
169  *	~$proc	execute proc locally, send output to line
170  *	~%cmd	execute builtin cmd (put and take)
171  *	~^Z	suspend cu process.
172  */
173 
174 wr()
175 {
176 	int ds,fk,lcl,x;
177 	char *p,b[600];
178 	for (;;) {
179 		p=b;
180 		while (rdc(0) == 1) {
181 			if (p == b) lcl=(c == cmdchar);
182 			if (p == b+1 && b[0] == cmdchar) lcl=(c!=cmdchar);
183 			if (!lcl) {
184 				c = oc;
185 				if (wrc(rem) == 0) {
186 					prf("line gone"); return;
187 				}
188 				if (eight == 0)
189 					c &= 0177;
190 			}
191 			if (lcl) {
192 				if (c == 0177) c=tkill;
193 				if (c == '\r' || c == '\n') goto A;
194 				wrc(0);
195 			}
196 			*p++=c;
197 			if (c == terase) {
198 				p=p-2;
199 				if (p<b) p=b;
200 			}
201 			if (c == tkill || c == 0177 || c == '\4' || c == '\r' || c == '\n') p=b;
202 		}
203 		return;
204 A:
205 		echo("");
206 		*p=0;
207 		switch (b[1]) {
208 		case '.':
209 		case '\004':
210 			return;
211 		case '!':
212 		case '$':
213 			fk = fork();
214 			signal(SIGCHLD, SIG_DFL);
215 			if (fk == 0) {
216 				char *shell = getenv("SHELL");
217 				if (shell == 0) shell = "/bin/sh";
218 				close(1);
219 				dup(b[1] == '$'? rem:2);
220 				close(rem);
221 				mode(0);
222 				if (!nhup) signal(SIGINT, SIG_DFL);
223 				if (b[2] == 0) execl(shell,shell,0);
224 				/* if (b[2] == 0) execl(shell,"-",0); */
225 				else execl(shell,"sh","-c",b+2,0);
226 				prf("Can't execute shell");
227 				exit(~0);
228 			}
229 			if (fk!=(-1)) {
230 				while (wait(&x)!=fk);
231 			}
232 			signal(SIGCHLD, done);
233 			mode(1);
234 			if (b[1] == '!') echo("!");
235 			break;
236 		case '<':
237 			if (b[2] == 0) break;
238 			if ((ds=open(b+2,0))<0) {
239 				prf("Can't divert %s",b+1);
240 				break;
241 			}
242 			intr=x=0;
243 			mode(2);
244 			if (!nhup) signal(SIGINT, sig2);
245 			while (!intr && rdc(ds) == 1) {
246 				if (wrc(rem) == 0) {
247 					x=1;
248 					break;
249 				}
250 			}
251 			signal(SIGINT, SIG_IGN);
252 			close(ds);
253 			mode(1);
254 			if (x) return;
255 			break;
256 		case '>':
257 		case ':':
258 			{
259 			register char *q;
260 
261 			q = b+1;
262 			if(*q=='>') q++;
263 			write(pipes[1],q,strlen(q)+1);
264 			if (efk != -1) kill(efk,SIGEMT);
265 			}
266 			break;
267 #ifdef SIGTSTP
268 #define CTRLZ	26
269 		case CTRLZ:
270 			mode(0);
271 			signal(SIGCHLD, SIG_IGN);
272 			kill(0, SIGTSTP);
273 			signal(SIGCHLD, done);
274 			mode(1);
275 			break;
276 #endif
277 		case '%':
278 			dopercen(&b[2]);
279 			break;
280 		default:
281 			prf("Use `%c%c' to start line with `%c'", cmdchar, cmdchar, cmdchar);
282 		}
283 		continue;
284 	}
285 }
286 
287 dopercen(line)
288 register char *line;
289 {
290 	char *args[10];
291 	register narg, f;
292 	int rcount;
293 	for (narg = 0; narg < 10;) {
294 		while(*line == ' ' || *line == '\t')
295 			line++;
296 		if (*line == '\0')
297 			break;
298 		args[narg++] = line;
299 		while(*line != '\0' && *line != ' ' && *line != '\t')
300 			line++;
301 		if (*line == '\0')
302 			break;
303 		*line++ = '\0';
304 	}
305 	if (equal(args[0], "take")) {
306 		if (narg < 2) {
307 			prf("usage: %c%%take from [to]", cmdchar);
308 			return;
309 		}
310 		if (narg < 3)
311 			args[2] = args[1];
312 		write(pipes[1], ">/dev/null",sizeof(">/dev/null"));
313 		if (efk != -1) kill(efk,SIGEMT);
314 		sleep(5);
315 		wrln("echo '%c>:", cmdchar);
316 		wrln(args[2]);
317 		wrln("'; tee /dev/null <");
318 		wrln(args[1]);
319 		wrln(";echo '%c>'\n", cmdchar);
320 		return;
321 	} else if (equal(args[0], "put")) {
322 		prf("%c%%put doesn't work yet (use rsh)", cmdchar);
323 		return;
324 /*
325 		if (narg < 2) {
326 			prf("usage: %c%%put from [to]", cmdchar);
327 			return;
328 		}
329 		if (narg < 3)
330 			args[2] = args[1];
331 		if ((f = open(args[1], 0)) < 0) {
332 			prf("cannot open: %s", args[1]);
333 			return;
334 		}
335 		wrln("stty -echo;cat >");
336 		wrln(args[2]);
337 		wrln(";stty echo\n");
338 		sleep(5);
339 		intr = 0;
340 		if (!nhup)
341 			signal(SIGINT, sig2);
342 		mode(2);
343 		rcount = 0;
344 		while(!intr && rdc(f) == 1) {
345 			rcount++;
346 			if (c == tkill || c == terase)
347 				wrln("\\");
348 			if (wrc(rem) != 1) {
349 				sleep(2);
350 				if (wrc(rem) != 1) {
351 					prf("character missed");
352 					intr = 1;
353 					break;
354 				}
355 			}
356 		}
357 		signal(SIGINT, SIG_IGN);
358 		close(f);
359 		if (intr) {
360 			wrln("\n");
361 			prf("stopped after %d bytes", rcount);
362 		}
363 		wrln("\004");
364 		sleep(5);
365 		mode(1);
366 		return;
367 */
368 	}
369 	prf("%c%%%s unknown\n", cmdchar, args[0]);
370 }
371 
372 equal(s1, s2)
373 register char *s1, *s2;
374 {
375 	while (*s1++ == *s2)
376 		if (*s2++ == '\0')
377 			return(1);
378 	return(0);
379 }
380 
381 wrln(s, p1, p2, p3)
382 register char *s;
383 int p1, p2, p3;
384 {
385 	char wbuf[256];
386 
387 	sprintf(wbuf, s, p1, p2, p3);
388 	s = wbuf;
389 	while (*s)
390 		write(rem, s++, 1);
391 }
392 int ds,slnt;
393 int justrung;
394 
395 /*
396  *	rd: read from remote: line -> 1
397  *	catch:
398  *	~>[>][:][file]
399  *	stuff from file...
400  *	~>	(ends diversion)
401  */
402 
403 int ds,slnt,taking;
404 int justrung;
405 readmsg(){
406 	static char dobuff[128], morejunk[256];
407 	int n;
408 	justrung = 1;
409 	signal(SIGEMT,readmsg);
410 	n = read(pipes[0],morejunk,256);
411 	dodiver(morejunk);
412 }
413 
414 dodiver(msg)
415 char *msg;
416 {
417 	register char *cp = msg;
418 
419 	if (*cp=='>') cp++;
420 	if (*cp==':') {
421 		cp++;
422 		if(*cp==0) {
423 			slnt ^= 1;
424 			return;
425 		} else  {
426 			slnt = 1;
427 		}
428 	}
429 	if (ds >= 0) close(ds);
430 	if (*cp==0) {
431 		slnt = 0;
432 		ds = -1;
433 		return;
434 	}
435 	if (*msg!='>' || (ds=open(cp,1))<0) ds=creat(cp,0644);
436 	lseek(ds, (long)0, 2);
437 	if(ds < 0) prf("Creat failed:"), prf(cp);
438 	if (ds<0) prf("Can't divert %s",cp+1);
439 }
440 
441 
442 /*
443  *	rd: read from remote: line -> 1
444  *	catch: diversion caught by interrupt routine
445  */
446 
447 #define ORDIN 0
448 #define SAWCR 1
449 #define EOL   2
450 #define SAWTL 3
451 #define DIVER 4
452 
453 oob()
454 {
455 	int mark, cc, out = 1+1;
456 	char waste[512];
457 
458 	signal(SIGURG, oob);
459 	ioctl(1, TIOCFLUSH, &out);
460 	for (;;) {
461 		if (ioctl(rem, SIOCATMARK, &mark) < 0) {
462 			perror("ioctl");
463 			break;
464 		}
465 		if (mark)
466 			break;
467 		cc = read(rem, waste, 512);
468 	}
469 	ioctl(rem, SIOCRCVOOB, &mark);
470 	if (mark & TIOCPKT_NOSTOP) {
471 		notchars.t_stopc = 0377;
472 		notchars.t_startc = 0377;
473 		ioctl(0, TIOCSETC, &notchars);
474 	}
475 	if (mark & TIOCPKT_DOSTOP) {
476 		notchars.t_stopc = 's'&037;
477 		notchars.t_startc = 'q'&037;
478 		ioctl(0, TIOCSETC, &notchars);
479 	}
480 }
481 
482 rd()
483 {
484 	extern int ds,slnt;
485 	char rb[600], lb[600], *rlim, *llim, c;
486 	register char *p,*q;
487 	int cnt, state = 0, mustecho, oldslnt, readmsg();
488 
489 	signal(SIGEMT,readmsg);  /* set up child for catching diversion msgs
490 				    from parent */
491 	signal(SIGURG,oob);
492 	{ int pid = -getpid();
493 	  ioctl(rem, SIOCSPGRP, &pid); }
494 	ds=(-1);
495 	p = lb; llim = lb+600;
496 agin:
497 	for (;;) {
498 		extern errno;
499 		errno = 0;
500 		cnt = read(rem,rb,600);
501 		if (cnt <= 0) {
502 			if (errno == EINTR) {
503 				errno = 0;
504 				continue;
505 			}
506 			break;
507 		}
508 		if(!slnt) write(1,rb,cnt);
509 		if(ds < 0) continue;
510 		oldslnt = slnt;
511 		for( q=rb, rlim = rb + cnt - 1; q <= rlim; ) {
512 			if (eight == 0)
513 			c &= 0177;
514 			if(p < llim) *p++ = c;
515 			switch(state) {
516 			case ORDIN:
517 				if(c=='\r') state = SAWCR;
518 				break;
519 			case SAWCR:
520 				if(c=='\n') {
521 					state = EOL;
522 					p--;
523 					p[-1] = '\n';
524 				} else state = ORDIN;
525 				break;
526 			case EOL:
527 				state = (c==cmdchar ? SAWTL :
528 					 (c=='\r' ? SAWCR : ORDIN));
529 				break;
530 			case SAWTL:
531 				state = (c=='>' ? DIVER :
532 					 (c=='\r' ? SAWCR : ORDIN));
533 				break;
534 			case DIVER:
535 				if(c=='\r') {
536 					p--;
537 				} else if (c=='\n') {
538 					state = ORDIN;
539 					p[-1] = 0;
540 					dodiver(lb+2);
541 					c = 0; p = lb;
542 				}
543 			}
544 			if(slnt==0 && oldslnt) {
545 				if(c=='\n') {
546 					write(rem,lb,p-lb-1);
547 					write(rem,CRLF,sizeof(CRLF));
548 				} else if(q==rlim) {
549 					write(rem,lb,p-lb);
550 					c = '\n';  /*force flush to file*/
551 				}
552 			}
553 			if(c=='\n') {
554 				if(ds >= 0)
555 					write(ds,lb,p-lb);
556 				p = lb;
557 			}
558 		}
559 	}
560 	if(justrung) {
561 		justrung = 0;
562 		goto agin;
563 	}
564 }
565 
566 struct {char lobyte; char hibyte;};
567 mode(f)
568 {
569 	struct sgttyb stbuf;
570 	ioctl(0, TIOCGETP, &stbuf);
571 	if (f == 0) {
572 		stbuf.sg_flags &= ~CBREAK;
573 		stbuf.sg_flags |= ECHO|CRMOD;
574 		ioctl(0, TIOCSETC, &deftchars);
575 		ioctl(0, TIOCSLTC, &defltchars);
576 		stbuf.sg_kill = defkill;
577 		stbuf.sg_erase = deferase;
578 	}
579 	if (f == 1) {
580 		stbuf.sg_flags |= CBREAK;
581 		stbuf.sg_flags &= ~(ECHO|CRMOD);
582 		ioctl(0, TIOCSETC, &notchars);
583 		ioctl(0, TIOCSLTC, &noltchars);
584 		stbuf.sg_kill = 0377;
585 		stbuf.sg_erase = 0377;
586 	}
587 	if (f == 2) {
588 		stbuf.sg_flags &= ~CBREAK;
589 		stbuf.sg_flags &= ~(ECHO|CRMOD);
590 		ioctl(0, TIOCSETC, &deftchars);
591 		ioctl(0, TIOCSLTC, &defltchars);
592 		stbuf.sg_kill = 0377;
593 		stbuf.sg_erase = 0377;
594 	}
595 	ioctl(0, TIOCSETN, &stbuf);
596 }
597 
598 echo(s)
599 char *s;
600 {
601 	char *p;
602 	for (p=s;*p;p++);
603 	if (p>s) write(0,s,p-s);
604 	write(0,CRLF, sizeof(CRLF));
605 }
606 
607 prf(f, a1, a2, a3)
608 char *f;
609 {
610 	fprintf(stderr, f, a1, a2, a3);
611 	fprintf(stderr, CRLF);
612 }
613 
614 exists(devname)
615 char *devname;
616 {
617 	if (access(devname, 0)==0)
618 		return(1);
619 	prf("%s does not exist", devname);
620 	return(0);
621 }
622 
623 rdc(ds)
624 {
625 
626 	ds=read(ds,&c,1);
627 	oc = c;
628 	if (eight == 0)
629 		c &= 0177;
630 	return (ds);
631 }
632 
633 sig2()
634 {
635 	signal(SIGINT, SIG_IGN);
636 	intr = 1;
637 }
638