xref: /original-bsd/usr.bin/rlogin/rlogin.c (revision f0fd5f8a)
1 #ifndef lint
2 static char sccsid[] = "@(#)rlogin.c	4.6 82/12/05";
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 
17 /*
18  * rlogin - remote login
19  */
20 char	*index(), *rindex(), *malloc(), *getenv();
21 struct	passwd *getpwuid();
22 char	*name;
23 int	rem;
24 char	cmdchar = '~';
25 int	rcmdoptions = 0;
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;
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 (!strcmp(*argv, "-d")) {
54 		argv++, argc--;
55 		rcmdoptions |= SO_DEBUG;
56 		goto another;
57 	}
58 	if (!strcmp(*argv, "-l")) {
59 		argv++, argc--;
60 		if (argc == 0)
61 			goto usage;
62 		name = *argv++; argc--;
63 		goto another;
64 	}
65 	if (!strncmp(*argv, "-e", 2)) {
66 		cmdchar = argv[0][2];
67 		argv++, argc--;
68 		goto another;
69 	}
70 	if (!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 (gtty(0, &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 	uid = getuid();
102 	if (setuid(uid) < 0) {
103 		perror("rlogin: setuid");
104 		exit(1);
105 	}
106 	doit();
107 	/*NOTREACHED*/
108 usage:
109 	fprintf(stderr,
110 	    "usage: rlogin host [ -ex ] [ -l username ]\n");
111 	exit(1);
112 }
113 
114 #define CRLF "\r\n"
115 
116 int	child;
117 int	done();
118 
119 char	tkill, terase;	/* current input kill & erase */
120 char	defkill, deferase, defflags;
121 
122 struct	tchars deftchars;
123 struct	tchars notchars = { -1, -1, CTRL(q), CTRL(s), -1, -1 };
124 struct	ltchars defltchars;
125 struct	ltchars noltchars = { -1, -1, -1, -1, -1, -1 };
126 
127 doit()
128 {
129 	struct sgttyb stbuf;
130 	int exit();
131 
132 	ioctl(0, TIOCGETP, (char *)&stbuf);
133 	defkill = stbuf.sg_kill;
134 	deferase = stbuf.sg_erase;
135 	defflags = stbuf.sg_flags & (ECHO | CRMOD);
136 	ioctl(0, TIOCGETC, (char *)&deftchars);
137 	ioctl(0, TIOCGLTC, (char *)&defltchars);
138 	signal(SIGINT, exit);
139 	signal(SIGHUP, exit);
140 	signal(SIGQUIT, exit);
141 	child = fork();
142 	if (child == -1) {
143 		perror("rlogin: fork");
144 		done();
145 	}
146 	signal(SIGINT, SIG_IGN);
147 	if (child == 0) {
148 		signal(SIGPIPE, SIG_IGN);
149 		reader();
150 		prf("\007Lost connection.");
151 		exit(3);
152 	}
153 	signal(SIGCHLD, done);
154 	mode(1);
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 /*
170  * writer: write to remote: 0 -> line.
171  * ~.	terminate
172  * ~^Z	suspend rlogin process.
173  */
174 writer()
175 {
176 	char b[600], c;
177 	register char *p;
178 
179 top:
180 	p = b;
181 	while (read(0, &c, 1) > 0) {
182 		int local;
183 
184 		if (eight == 0)
185 			c &= 0177;
186 		/*
187 		 * If we're at the beginning of the line
188 		 * and recognize a command character, then
189 		 * we echo locally.  Otherwise, characters
190 		 * are echo'd remotely.  If the command
191 		 * character is doubled, this acts as a
192 		 * force and local echo is suppressed.
193 		 */
194 		if (p == b)
195 			local = (c == cmdchar);
196 		if (p == b + 1 && *b == cmdchar)
197 			local = (c != cmdchar);
198 		if (!local) {
199 			if (write(rem, &c, 1) == 0) {
200 				prf("line gone");
201 				return;
202 			}
203 			if (eight == 0)
204 				c &= 0177;
205 		} else {
206 			if (c == 0177)
207 				c = tkill;
208 			if (c == '\r' || c == '\n') {
209 				switch (b[1]) {
210 
211 				case '.':
212 				case CTRL(d):
213 					write(0, CRLF, sizeof(CRLF));
214 					return;
215 
216 				case CTRL(z):
217 					write(0, CRLF, sizeof(CRLF));
218 					mode(0);
219 					signal(SIGCHLD, SIG_IGN);
220 					kill(0, SIGTSTP);
221 					signal(SIGCHLD, done);
222 					mode(1);
223 					goto top;
224 				}
225 				*p++ = c;
226 				write(rem, b, p - b);
227 				goto top;
228 			}
229 			write(1, &c, 1);
230 		}
231 		*p++ = c;
232 		if (c == terase) {
233 			p -= 2;
234 			if (p < b)
235 				goto top;
236 		}
237 		if (c == tkill || c == 0177 || c == CTRL(d) ||
238 		    c == '\r' || c == '\n')
239 			goto top;
240 	}
241 }
242 
243 oob()
244 {
245 	int out = 1+1;
246 	char waste[BUFSIZ], mark;
247 
248 	signal(SIGURG, oob);
249 	ioctl(1, TIOCFLUSH, (char *)&out);
250 	for (;;) {
251 		if (ioctl(rem, SIOCATMARK, &mark) < 0) {
252 			perror("ioctl");
253 			break;
254 		}
255 		if (mark)
256 			break;
257 		(void) read(rem, waste, sizeof (waste));
258 	}
259 	recv(rem, &mark, 1, SOF_OOB);
260 	if (mark & TIOCPKT_NOSTOP) {
261 		notchars.t_stopc = -1;
262 		notchars.t_startc = -1;
263 		ioctl(0, TIOCSETC, (char *)&notchars);
264 	}
265 	if (mark & TIOCPKT_DOSTOP) {
266 		notchars.t_stopc = CTRL(s);
267 		notchars.t_startc = CTRL(q);
268 		ioctl(0, TIOCSETC, (char *)&notchars);
269 	}
270 }
271 
272 /*
273  * reader: read from remote: line -> 1
274  */
275 reader()
276 {
277 	char rb[BUFSIZ];
278 	register int cnt;
279 
280 	signal(SIGURG, oob);
281 	{ int pid = -getpid();
282 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
283 	for (;;) {
284 		cnt = read(rem, rb, sizeof (rb));
285 		if (cnt <= 0) {
286 			if (errno == EINTR)
287 				continue;
288 			break;
289 		}
290 		write(1, rb, cnt);
291 	}
292 }
293 
294 mode(f)
295 {
296 	struct sgttyb stbuf;
297 
298 	ioctl(0, TIOCGETP, (char *)&stbuf);
299 	if (f == 0) {
300 		stbuf.sg_flags &= ~CBREAK;
301 		stbuf.sg_flags |= defflags;
302 		ioctl(0, TIOCSETC, (char *)&deftchars);
303 		ioctl(0, TIOCSLTC, (char *)&defltchars);
304 		stbuf.sg_kill = defkill;
305 		stbuf.sg_erase = deferase;
306 	}
307 	if (f == 1) {
308 		stbuf.sg_flags |= CBREAK;
309 		stbuf.sg_flags &= ~(ECHO|CRMOD);
310 		ioctl(0, TIOCSETC, (char *)&notchars);
311 		ioctl(0, TIOCSLTC, (char *)&noltchars);
312 		stbuf.sg_kill = -1;
313 		stbuf.sg_erase = -1;
314 	}
315 	if (f == 2) {
316 		stbuf.sg_flags &= ~CBREAK;
317 		stbuf.sg_flags &= ~(ECHO|CRMOD);
318 		ioctl(0, TIOCSETC, (char *)&deftchars);
319 		ioctl(0, TIOCSLTC, (char *)&defltchars);
320 		stbuf.sg_kill = -1;
321 		stbuf.sg_erase = -1;
322 	}
323 	ioctl(0, TIOCSETN, (char *)&stbuf);
324 }
325 
326 /*VARARGS*/
327 prf(f, a1, a2, a3)
328 	char *f;
329 {
330 	fprintf(stderr, f, a1, a2, a3);
331 	fprintf(stderr, CRLF);
332 }
333 
334 lostpeer()
335 {
336 	signal(SIGPIPE, SIG_IGN);
337 	prf("\007Lost connection");
338 	done();
339 }
340