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