xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 16227)
1 #ifndef lint
2 static char sccsid[] = "@(#)rlogind.c	4.19 84/03/22";
3 #endif
4 
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/socket.h>
9 #include <sys/wait.h>
10 
11 #include <netinet/in.h>
12 
13 #include <errno.h>
14 #include <pwd.h>
15 #include <signal.h>
16 #include <sgtty.h>
17 #include <stdio.h>
18 #include <netdb.h>
19 
20 extern	errno;
21 int	reapchild();
22 struct	passwd *getpwnam();
23 char	*crypt(), *rindex(), *index(), *malloc(), *ntoa();
24 struct	sockaddr_in sin = { AF_INET };
25 /*
26  * remote login server:
27  *	remuser\0
28  *	locuser\0
29  *	terminal type\0
30  *	data
31  */
32 main(argc, argv)
33 	int argc;
34 	char **argv;
35 {
36 	int f, options = 0;
37 	struct sockaddr_in from;
38 	struct servent *sp;
39 
40 	sp = getservbyname("login", "tcp");
41 	if (sp == 0) {
42 		fprintf(stderr, "rlogind: tcp/rlogin: unknown service\n");
43 		exit(1);
44 	}
45 #ifndef DEBUG
46 	if (fork())
47 		exit(0);
48 	for (f = 0; f < 10; f++)
49 		(void) close(f);
50 	(void) open("/", 0);
51 	(void) dup2(0, 1);
52 	(void) dup2(0, 2);
53 	{ int tt = open("/dev/tty", 2);
54 	  if (tt > 0) {
55 		ioctl(tt, TIOCNOTTY, 0);
56 		close(tt);
57 	  }
58 	}
59 #endif
60 	sin.sin_port = sp->s_port;
61 	argc--, argv++;
62 	if (argc > 0 && !strcmp(argv[0], "-d")) {
63 		options |= SO_DEBUG;
64 		argc--, argv++;
65 	}
66 	if (argc > 0) {
67 		int port = atoi(argv[0]);
68 
69 		if (port < 0) {
70 			fprintf(stderr, "%s: bad port #\n", argv[0]);
71 			exit(1);
72 		}
73 		sin.sin_port = htons((u_short)port);
74 		argv++, argc--;
75 	}
76 	f = socket(AF_INET, SOCK_STREAM, 0, 0);
77 	if (f < 0) {
78 		perror("rlogind: socket");
79 		exit(1);
80 	}
81 	if (options & SO_DEBUG)
82 		if (setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
83 			perror("rlogind: setsockopt (SO_DEBUG)");
84 	if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0)
85 		perror("rlogind: setsockopt (SO_KEEPALIVE)");
86 	if (bind(f, &sin, sizeof (sin), 0) < 0) {
87 		perror("rlogind: bind");
88 		exit(1);
89 	}
90 	signal(SIGCHLD, reapchild);
91 	listen(f, 10);
92 	for (;;) {
93 		int s, len = sizeof (from);
94 
95 		s = accept(f, &from, &len, 0);
96 		if (s < 0) {
97 			if (errno == EINTR)
98 				continue;
99 			perror("rlogind: accept");
100 			continue;
101 		}
102 		if (fork() == 0) {
103 			signal(SIGCHLD, SIG_IGN);
104 			close(f);
105 			doit(s, &from);
106 		}
107 		close(s);
108 	}
109 }
110 
111 reapchild()
112 {
113 	union wait status;
114 
115 	while (wait3(&status, WNOHANG, 0) > 0)
116 		;
117 }
118 
119 char	locuser[32], remuser[32];
120 char	buf[BUFSIZ];
121 int	child;
122 int	cleanup();
123 int	netf;
124 extern	errno;
125 char	*line;
126 
127 doit(f, fromp)
128 	int f;
129 	struct sockaddr_in *fromp;
130 {
131 	char c;
132 	int i, p, cc, t, pid;
133 	int stop = TIOCPKT_DOSTOP;
134 	register struct hostent *hp;
135 
136 	alarm(60);
137 	read(f, &c, 1);
138 	if (c != 0)
139 		exit(1);
140 	alarm(0);
141 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
142 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
143 		fromp->sin_family);
144 	if (hp == 0) {
145 		char buf[BUFSIZ];
146 
147 		fatal(f, sprintf(buf, "Host name for your address (%s) unknown",
148 			ntoa(fromp->sin_addr)));
149 	}
150 	if (fromp->sin_family != AF_INET ||
151 	    fromp->sin_port >= IPPORT_RESERVED)
152 		fatal(f, "Permission denied");
153 	write(f, "", 1);
154 	for (c = 'p'; c <= 's'; c++) {
155 		struct stat stb;
156 		line = "/dev/ptyXX";
157 		line[strlen("/dev/pty")] = c;
158 		line[strlen("/dev/ptyp")] = '0';
159 		if (stat(line, &stb) < 0)
160 			break;
161 		for (i = 0; i < 16; i++) {
162 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
163 			p = open(line, 2);
164 			if (p > 0)
165 				goto gotpty;
166 		}
167 	}
168 	fatal(f, "All network ports in use");
169 	/*NOTREACHED*/
170 gotpty:
171 	netf = f;
172 	line[strlen("/dev/")] = 't';
173 #ifdef DEBUG
174 	{ int tt = open("/dev/tty", 2);
175 	  if (tt > 0) {
176 		ioctl(tt, TIOCNOTTY, 0);
177 		close(tt);
178 	  }
179 	}
180 #endif
181 	t = open(line, 2);
182 	if (t < 0)
183 		fatalperror(f, line, errno);
184 	{ struct sgttyb b;
185 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
186 	}
187 	pid = fork();
188 	if (pid < 0)
189 		fatalperror(f, "", errno);
190 	if (pid) {
191 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
192 		register pcc = 0, fcc = 0;
193 		int on = 1;
194 /* FILE *console = fopen("/dev/console", "w");  */
195 /* setbuf(console, 0); */
196 
197 /* fprintf(console, "f %d p %d\r\n", f, p); */
198 		close(t);
199 		ioctl(f, FIONBIO, &on);
200 		ioctl(p, FIONBIO, &on);
201 		ioctl(p, TIOCPKT, &on);
202 		signal(SIGTSTP, SIG_IGN);
203 		signal(SIGCHLD, cleanup);
204 		for (;;) {
205 			int ibits = 0, obits = 0;
206 
207 			if (fcc)
208 				obits |= (1<<p);
209 			else
210 				ibits |= (1<<f);
211 			if (pcc >= 0)
212 				if (pcc)
213 					obits |= (1<<f);
214 				else
215 					ibits |= (1<<p);
216 /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
217 			if (select(16, &ibits, &obits, 0, 0) < 0) {
218 				if (errno == EINTR)
219 					continue;
220 				fatalperror(f, "select", errno);
221 			}
222 /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
223 			if (ibits == 0 && obits == 0) {
224 				/* shouldn't happen... */
225 				sleep(5);
226 				continue;
227 			}
228 			if (ibits & (1<<f)) {
229 				fcc = read(f, fibuf, sizeof (fibuf));
230 /* fprintf(console, "%d from f\r\n", fcc); */
231 				if (fcc < 0 && errno == EWOULDBLOCK)
232 					fcc = 0;
233 				else {
234 					if (fcc <= 0)
235 						break;
236 					fbp = fibuf;
237 				}
238 			}
239 			if (ibits & (1<<p)) {
240 				pcc = read(p, pibuf, sizeof (pibuf));
241 /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
242 				pbp = pibuf;
243 				if (pcc < 0 && errno == EWOULDBLOCK)
244 					pcc = 0;
245 				else if (pcc <= 0)
246 					break;
247 				else if (pibuf[0] == 0)
248 					pbp++, pcc--;
249 				else {
250 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
251 						      TIOCPKT_NOSTOP|
252 						      TIOCPKT_DOSTOP)) {
253 					/* The following 3 lines do nothing. */
254 						int nstop = pibuf[0] &
255 						    (TIOCPKT_NOSTOP|
256 						     TIOCPKT_DOSTOP);
257 						if (nstop)
258 							stop = nstop;
259 						pibuf[0] |= nstop;
260 						send(f,&pibuf[0],1,MSG_OOB);
261 					}
262 					pcc = 0;
263 				}
264 			}
265 			if ((obits & (1<<f)) && pcc > 0) {
266 				cc = write(f, pbp, pcc);
267 				if (cc < 0 && errno == EWOULDBLOCK) {
268 					/* also shouldn't happen */
269 					sleep(5);
270 					continue;
271 				}
272 /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
273 				if (cc > 0) {
274 					pcc -= cc;
275 					pbp += cc;
276 				}
277 			}
278 			if ((obits & (1<<p)) && fcc > 0) {
279 				cc = write(p, fbp, fcc);
280 /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
281 				if (cc > 0) {
282 					fcc -= cc;
283 					fbp += cc;
284 				}
285 			}
286 		}
287 		cleanup();
288 	}
289 	close(f);
290 	close(p);
291 	dup2(t, 0);
292 	dup2(t, 1);
293 	dup2(t, 2);
294 	close(t);
295 	execl("/bin/login", "login", "-r", hp->h_name, 0);
296 	fatalperror(2, "/bin/login", errno);
297 	/*NOTREACHED*/
298 }
299 
300 cleanup()
301 {
302 
303 	rmut();
304 	vhangup();		/* XXX */
305 	shutdown(netf, 2);
306 	kill(0, SIGKILL);
307 	exit(1);
308 }
309 
310 fatal(f, msg)
311 	int f;
312 	char *msg;
313 {
314 	char buf[BUFSIZ];
315 
316 	buf[0] = '\01';		/* error indicator */
317 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
318 	(void) write(f, buf, strlen(buf));
319 	exit(1);
320 }
321 
322 fatalperror(f, msg, errno)
323 	int f;
324 	char *msg;
325 	int errno;
326 {
327 	char buf[BUFSIZ];
328 	extern int sys_nerr;
329 	extern char *sys_errlist[];
330 
331 	if ((unsigned) errno < sys_nerr)
332 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
333 	else
334 		(void) sprintf(buf, "%s: Error %d", msg, errno);
335 	fatal(f, buf);
336 }
337 
338 #include <utmp.h>
339 
340 struct	utmp wtmp;
341 char	wtmpf[]	= "/usr/adm/wtmp";
342 char	utmp[] = "/etc/utmp";
343 #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
344 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
345 
346 rmut()
347 {
348 	register f;
349 	int found = 0;
350 
351 	f = open(utmp, 2);
352 	if (f >= 0) {
353 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
354 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
355 				continue;
356 			lseek(f, -(long)sizeof(wtmp), 1);
357 			SCPYN(wtmp.ut_name, "");
358 			SCPYN(wtmp.ut_host, "");
359 			time(&wtmp.ut_time);
360 			write(f, (char *)&wtmp, sizeof(wtmp));
361 			found++;
362 		}
363 		close(f);
364 	}
365 	if (found) {
366 		f = open(wtmpf, 1);
367 		if (f >= 0) {
368 			SCPYN(wtmp.ut_line, line+5);
369 			SCPYN(wtmp.ut_name, "");
370 			SCPYN(wtmp.ut_host, "");
371 			time(&wtmp.ut_time);
372 			lseek(f, (long)0, 2);
373 			write(f, (char *)&wtmp, sizeof(wtmp));
374 			close(f);
375 		}
376 	}
377 	chmod(line, 0666);
378 	chown(line, 0, 0);
379 	line[strlen("/dev/")] = 'p';
380 	chmod(line, 0666);
381 	chown(line, 0, 0);
382 }
383 
384 /*
385  * Convert network-format internet address
386  * to base 256 d.d.d.d representation.
387  */
388 char *
389 ntoa(in)
390 	struct in_addr in;
391 {
392 	static char b[18];
393 	register char *p;
394 
395 	p = (char *)&in;
396 #define	UC(b)	(((int)b)&0xff)
397 	sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
398 	return (b);
399 }
400