xref: /original-bsd/usr.bin/rlogin/rlogin.c (revision ed6e4306)
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 *)&notc);
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 *)&notc);
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 = &notc;
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