xref: /original-bsd/libexec/rlogind/rlogind.c (revision f7be149a)
1 #ifndef lint
2 static	char sccsid[] = "@(#)rlogind.c	4.25 (Berkeley) 03/24/85";
3 #endif
4 
5 /*
6  * remote login server:
7  *	remuser\0
8  *	locuser\0
9  *	terminal info\0
10  *	data
11  */
12 
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/socket.h>
17 #include <sys/wait.h>
18 #include <sys/file.h>
19 
20 #include <netinet/in.h>
21 
22 #include <errno.h>
23 #include <pwd.h>
24 #include <signal.h>
25 #include <sgtty.h>
26 #include <stdio.h>
27 #include <netdb.h>
28 #include <syslog.h>
29 #include <strings.h>
30 
31 extern	errno;
32 int	reapchild();
33 struct	passwd *getpwnam();
34 char	*crypt(), *malloc();
35 
36 main(argc, argv)
37 	int argc;
38 	char **argv;
39 {
40 	int on = 1, options = 0, fromlen;
41 	struct sockaddr_in from;
42 
43 	fromlen = sizeof (from);
44 	if (getpeername(0, &from, &fromlen) < 0) {
45 		fprintf(stderr, "%s: ", argv[0]);
46 		perror("getpeername");
47 		_exit(1);
48 	}
49 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
50 		openlog(argv[0], LOG_PID, 0);
51 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
52 	}
53 	doit(0, &from);
54 }
55 
56 int	child;
57 int	cleanup();
58 int	netf;
59 extern	errno;
60 char	*line;
61 
62 doit(f, fromp)
63 	int f;
64 	struct sockaddr_in *fromp;
65 {
66 	int i, p, t, pid, on = 1;
67 	register struct hostent *hp;
68 	char c;
69 
70 	alarm(60);
71 	read(f, &c, 1);
72 	if (c != 0)
73 		exit(1);
74 	alarm(0);
75 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
76 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
77 		fromp->sin_family);
78 	if (hp == 0) {
79 		char buf[BUFSIZ];
80 
81 		fatal(f, sprintf(buf, "Host name for your address (%s) unknown",
82 			inet_ntoa(fromp->sin_addr)));
83 	}
84 	if (fromp->sin_family != AF_INET ||
85 	    fromp->sin_port >= IPPORT_RESERVED)
86 		fatal(f, "Permission denied");
87 	write(f, "", 1);
88 	for (c = 'p'; c <= 's'; c++) {
89 		struct stat stb;
90 		line = "/dev/ptyXX";
91 		line[strlen("/dev/pty")] = c;
92 		line[strlen("/dev/ptyp")] = '0';
93 		if (stat(line, &stb) < 0)
94 			break;
95 		for (i = 0; i < 16; i++) {
96 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
97 			p = open(line, 2);
98 			if (p > 0)
99 				goto gotpty;
100 		}
101 	}
102 	fatal(f, "All network ports in use");
103 	/*NOTREACHED*/
104 gotpty:
105 	netf = f;
106 	line[strlen("/dev/")] = 't';
107 #ifdef DEBUG
108 	{ int tt = open("/dev/tty", 2);
109 	  if (tt > 0) {
110 		ioctl(tt, TIOCNOTTY, 0);
111 		close(tt);
112 	  }
113 	}
114 #endif
115 	t = open(line, 2);
116 	if (t < 0)
117 		fatalperror(f, line, errno);
118 	{ struct sgttyb b;
119 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
120 	}
121 	pid = fork();
122 	if (pid < 0)
123 		fatalperror(f, "", errno);
124 	if (pid == 0) {
125 		close(f), close(p);
126 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
127 		close(t);
128 		execl("/bin/login", "login", "-r", hp->h_name, 0);
129 		fatalperror(2, "/bin/login", errno);
130 		/*NOTREACHED*/
131 	}
132 	close(t);
133 	ioctl(f, FIONBIO, &on);
134 	ioctl(p, FIONBIO, &on);
135 	ioctl(p, TIOCPKT, &on);
136 	signal(SIGTSTP, SIG_IGN);
137 	signal(SIGCHLD, cleanup);
138 	protocol(f, p);
139 	cleanup();
140 }
141 
142 char	magic[2] = { 0377, 0377 };
143 
144 /*
145  * Handle a "control" request (signaled by magic being present)
146  * in the data stream.  For now, we are only willing to handle
147  * window size changes.
148  */
149 control(pty, cp, n)
150 	int pty;
151 	char *cp;
152 	int n;
153 {
154 	struct winsize *wp;
155 
156 	if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's')
157 		return (0);
158 	wp = (struct winsize *)(cp+4);
159 	wp->ws_row = ntohs(wp->ws_row);
160 	wp->ws_col = ntohs(wp->ws_col);
161 	wp->ws_xpixel = ntohs(wp->ws_xpixel);
162 	wp->ws_ypixel = ntohs(wp->ws_ypixel);
163 	(void)ioctl(pty, TIOCSWINSZ, wp);
164 	return (4+sizeof (*wp));
165 }
166 
167 /*
168  * rlogin "protocol" machine.
169  */
170 protocol(f, p)
171 	int f, p;
172 {
173 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
174 	register pcc = 0, fcc = 0;
175 	int cc, stop = TIOCPKT_DOSTOP;
176 
177 	/*
178 	 * Must ignore SIGTTOU, otherwise we'll stop
179 	 * when we try and set slave pty's window shape
180 	 * (our pgrp is that of the master pty).
181 	 */
182 	(void) signal(SIGTTOU, SIG_IGN);
183 	for (;;) {
184 		int ibits = 0, obits = 0;
185 
186 		if (fcc)
187 			obits |= (1<<p);
188 		else
189 			ibits |= (1<<f);
190 		if (pcc >= 0)
191 			if (pcc)
192 				obits |= (1<<f);
193 			else
194 				ibits |= (1<<p);
195 		if (select(16, &ibits, &obits, 0, 0) < 0) {
196 			if (errno == EINTR)
197 				continue;
198 			fatalperror(f, "select", errno);
199 		}
200 		if (ibits == 0 && obits == 0) {
201 			/* shouldn't happen... */
202 			sleep(5);
203 			continue;
204 		}
205 		if (ibits & (1<<f)) {
206 			fcc = read(f, fibuf, sizeof (fibuf));
207 			if (fcc < 0 && errno == EWOULDBLOCK)
208 				fcc = 0;
209 			else {
210 				register char *cp;
211 				int left, n;
212 
213 				if (fcc <= 0)
214 					break;
215 				fbp = fibuf;
216 			top:
217 				for (cp = fibuf; cp < fibuf+fcc; cp++)
218 					if (cp[0] == magic[0] &&
219 					    cp[1] == magic[1]) {
220 						left = fcc - (cp-fibuf);
221 						n = control(p, cp, left);
222 						if (n) {
223 							left -= n;
224 							if (left > 0)
225 								bcopy(cp, cp+n, left);
226 							fcc -= n;
227 							goto top; /* n^2 */
228 						}
229 					}
230 			}
231 		}
232 		if (ibits & (1<<p)) {
233 			pcc = read(p, pibuf, sizeof (pibuf));
234 			pbp = pibuf;
235 			if (pcc < 0 && errno == EWOULDBLOCK)
236 				pcc = 0;
237 			else if (pcc <= 0)
238 				break;
239 			else if (pibuf[0] == 0)
240 				pbp++, pcc--;
241 			else {
242 #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
243 				if (pkcontrol(pibuf[0])) {
244 				/* The following 3 lines do nothing. */
245 					int nstop = pibuf[0] &
246 					    (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP);
247 
248 					if (nstop)
249 						stop = nstop;
250 					pibuf[0] |= nstop;
251 					send(f, &pibuf[0], 1, MSG_OOB);
252 				}
253 				pcc = 0;
254 			}
255 		}
256 		if ((obits & (1<<f)) && pcc > 0) {
257 			cc = write(f, pbp, pcc);
258 			if (cc < 0 && errno == EWOULDBLOCK) {
259 				/* also shouldn't happen */
260 				sleep(5);
261 				continue;
262 			}
263 			if (cc > 0) {
264 				pcc -= cc;
265 				pbp += cc;
266 			}
267 		}
268 		if ((obits & (1<<p)) && fcc > 0) {
269 			cc = write(p, fbp, fcc);
270 			if (cc > 0) {
271 				fcc -= cc;
272 				fbp += cc;
273 			}
274 		}
275 	}
276 }
277 
278 cleanup()
279 {
280 
281 	rmut();
282 	vhangup();		/* XXX */
283 	shutdown(netf, 2);
284 	kill(0, SIGKILL);
285 	exit(1);
286 }
287 
288 fatal(f, msg)
289 	int f;
290 	char *msg;
291 {
292 	char buf[BUFSIZ];
293 
294 	buf[0] = '\01';		/* error indicator */
295 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
296 	(void) write(f, buf, strlen(buf));
297 	exit(1);
298 }
299 
300 fatalperror(f, msg, errno)
301 	int f;
302 	char *msg;
303 	int errno;
304 {
305 	char buf[BUFSIZ];
306 	extern int sys_nerr;
307 	extern char *sys_errlist[];
308 
309 	if ((unsigned)errno < sys_nerr)
310 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
311 	else
312 		(void) sprintf(buf, "%s: Error %d", msg, errno);
313 	fatal(f, buf);
314 }
315 
316 #include <utmp.h>
317 
318 struct	utmp wtmp;
319 char	wtmpf[]	= "/usr/adm/wtmp";
320 char	utmp[] = "/etc/utmp";
321 #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
322 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
323 
324 rmut()
325 {
326 	register f;
327 	int found = 0;
328 
329 	f = open(utmp, O_RDWR);
330 	if (f >= 0) {
331 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
332 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
333 				continue;
334 			lseek(f, -(long)sizeof(wtmp), L_INCR);
335 			SCPYN(wtmp.ut_name, "");
336 			SCPYN(wtmp.ut_host, "");
337 			time(&wtmp.ut_time);
338 			write(f, (char *)&wtmp, sizeof(wtmp));
339 			found++;
340 		}
341 		close(f);
342 	}
343 	if (found) {
344 		f = open(wtmpf, O_WRONLY);
345 		if (f >= 0) {
346 			SCPYN(wtmp.ut_line, line+5);
347 			SCPYN(wtmp.ut_name, "");
348 			SCPYN(wtmp.ut_host, "");
349 			time(&wtmp.ut_time);
350 			lseek(f, (long)0, L_XTND);
351 			write(f, (char *)&wtmp, sizeof(wtmp));
352 			close(f);
353 		}
354 	}
355 	chmod(line, 0666);
356 	chown(line, 0, 0);
357 	line[strlen("/dev/")] = 'p';
358 	chmod(line, 0666);
359 	chown(line, 0, 0);
360 }
361