xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 11222)
1 #ifndef lint
2 static char sccsid[] = "@(#)rlogind.c	4.11 83/02/21";
3 #endif
4 
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <sys/socket.h>
9 
10 #include <netinet/in.h>
11 
12 #include <errno.h>
13 #include <pwd.h>
14 #include <wait.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();
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 = SO_KEEPALIVE;
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 #ifdef notdef
85 	if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0)
86 		perror("rlogind: setsocktopt (SO_KEEPALIVE)");
87 #endif
88 	if (bind(f, &sin, sizeof (sin), 0) < 0) {
89 		perror("rlogind: bind");
90 		exit(1);
91 	}
92 	sigset(SIGCHLD, reapchild);
93 	listen(f, 10);
94 	for (;;) {
95 		int s, len = sizeof (from);
96 
97 		s = accept(f, &from, &len, 0);
98 		if (s < 0) {
99 			if (errno == EINTR)
100 				continue;
101 			perror("rlogind: accept");
102 			continue;
103 		}
104 		if (fork() == 0) {
105 			signal(SIGCHLD, SIG_IGN);
106 			doit(s, &from);
107 		}
108 		close(s);
109 	}
110 }
111 
112 reapchild()
113 {
114 	union wait status;
115 
116 	while (wait3(&status, WNOHANG, 0) > 0)
117 		;
118 }
119 
120 char	locuser[32], remuser[32];
121 char	buf[BUFSIZ];
122 int	child;
123 int	cleanup();
124 int	netf;
125 extern	errno;
126 char	*line;
127 
128 doit(f, fromp)
129 	int f;
130 	struct sockaddr_in *fromp;
131 {
132 	char c;
133 	int i, p, cc, t, pid;
134 	int stop = TIOCPKT_DOSTOP;
135 	register struct hostent *hp;
136 
137 	alarm(60);
138 	read(f, &c, 1);
139 	if (c != 0)
140 		exit(1);
141 	alarm(0);
142 	fromp->sin_port = htons((u_short)fromp->sin_port);
143 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
144 		fromp->sin_family);
145 	if (hp == 0)
146 		fatal(f, "Host name for your address unknown");
147 	if (fromp->sin_family != AF_INET ||
148 	    fromp->sin_port >= IPPORT_RESERVED ||
149 	    hp == 0)
150 		fatal(f, "Permission denied");
151 	write(f, "", 1);
152 	for (c = 'p'; c <= 's'; c++) {
153 		struct stat stb;
154 		line = "/dev/ptyXX";
155 		line[strlen("/dev/pty")] = c;
156 		line[strlen("/dev/ptyp")] = '0';
157 		if (stat(line, &stb) < 0)
158 			break;
159 		for (i = 0; i < 16; i++) {
160 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
161 			p = open(line, 2);
162 			if (p > 0)
163 				goto gotpty;
164 		}
165 	}
166 	fatal(f, "All network ports in use");
167 	/*NOTREACHED*/
168 gotpty:
169 	dup2(f, 0);
170 	line[strlen("/dev/")] = 't';
171 #ifdef DEBUG
172 	{ int tt = open("/dev/tty", 2);
173 	  if (tt > 0) {
174 		ioctl(tt, TIOCNOTTY, 0);
175 		close(tt);
176 	  }
177 	}
178 #endif
179 	t = open(line, 2);
180 	if (t < 0)
181 		fatalperror(f, line, errno);
182 	{ struct sgttyb b;
183 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
184 	}
185 	pid = fork();
186 	if (pid < 0)
187 		fatalperror(f, "", errno);
188 	if (pid) {
189 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
190 		int pcc = 0, fcc = 0, on = 1;
191 /* FILE *console = fopen("/dev/console", "w");  */
192 /* setbuf(console, 0); */
193 
194 /* fprintf(console, "f %d p %d\r\n", f, p); */
195 		ioctl(f, FIONBIO, &on);
196 		ioctl(p, FIONBIO, &on);
197 		ioctl(p, TIOCPKT, &on);
198 		signal(SIGTSTP, SIG_IGN);
199 		sigset(SIGCHLD, cleanup);
200 		for (;;) {
201 			int ibits = 0, obits = 0;
202 
203 			if (fcc)
204 				obits |= (1<<p);
205 			else
206 				ibits |= (1<<f);
207 			if (pcc >= 0)
208 				if (pcc)
209 					obits |= (1<<f);
210 				else
211 					ibits |= (1<<p);
212 			if (fcc < 0 && pcc < 0)
213 				break;
214 /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
215 			select(16, &ibits, &obits, 0, 0, 0);
216 /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
217 			if (ibits == 0 && obits == 0) {
218 				sleep(5);
219 				continue;
220 			}
221 			if (ibits & (1<<f)) {
222 				fcc = read(f, fibuf, sizeof (fibuf));
223 /* fprintf(console, "%d from f\r\n", fcc); */
224 				if (fcc < 0 && errno == EWOULDBLOCK)
225 					fcc = 0;
226 				else {
227 					if (fcc <= 0)
228 						break;
229 					fbp = fibuf;
230 				}
231 			}
232 			if (ibits & (1<<p)) {
233 				pcc = read(p, pibuf, sizeof (pibuf));
234 /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
235 				pbp = pibuf;
236 				if (pcc < 0 && errno == EWOULDBLOCK)
237 					pcc = 0;
238 				else if (pcc <= 0)
239 					pcc = -1;
240 				else if (pibuf[0] == 0)
241 					pbp++, pcc--;
242 				else {
243 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
244 						      TIOCPKT_NOSTOP|
245 						      TIOCPKT_DOSTOP)) {
246 						int nstop = pibuf[0] &
247 						    (TIOCPKT_NOSTOP|
248 						     TIOCPKT_DOSTOP);
249 						if (nstop)
250 							stop = nstop;
251 						pibuf[0] |= nstop;
252 						send(f,&pibuf[0],1,SOF_OOB);
253 					}
254 					pcc = 0;
255 				}
256 			}
257 			if ((obits & (1<<f)) && pcc > 0) {
258 				cc = write(f, pbp, pcc);
259 /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
260 				if (cc > 0) {
261 					pcc -= cc;
262 					pbp += cc;
263 				}
264 			}
265 			if ((obits & (1<<p)) && fcc > 0) {
266 				cc = write(p, fbp, fcc);
267 /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
268 				if (cc > 0) {
269 					fcc -= cc;
270 					fbp += cc;
271 				}
272 			}
273 		}
274 		cleanup();
275 	}
276 	close(f);
277 	close(p);
278 	dup2(t, 0);
279 	dup2(t, 1);
280 	dup2(t, 2);
281 	close(t);
282 	execl("/bin/login", "login", "-r", hp->h_name, 0);
283 	fatalperror(2, "/bin/login", errno);
284 	/*NOTREACHED*/
285 }
286 
287 cleanup()
288 {
289 
290 	rmut();
291 	vhangup();		/* XXX */
292 	shutdown(netf, 2);
293 	kill(0, SIGKILL);
294 	exit(1);
295 }
296 
297 fatal(f, msg)
298 	int f;
299 	char *msg;
300 {
301 	char buf[BUFSIZ];
302 
303 	buf[0] = '\01';		/* error indicator */
304 	(void) sprintf(buf + 1, "rlogind: %s.\n", msg);
305 	(void) write(f, buf, strlen(buf));
306 	exit(1);
307 }
308 
309 fatalperror(f, msg, errno)
310 	int f;
311 	char *msg;
312 	int errno;
313 {
314 	char buf[BUFSIZ];
315 	extern char *sys_errlist[];
316 
317 	(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
318 	fatal(f, buf);
319 }
320 
321 #include <utmp.h>
322 
323 struct	utmp wtmp;
324 char	wtmpf[]	= "/usr/adm/wtmp";
325 char	utmp[] = "/etc/utmp";
326 #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
327 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
328 
329 rmut()
330 {
331 	register f;
332 	int found = 0;
333 
334 	f = open(utmp, 2);
335 	if (f >= 0) {
336 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
337 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
338 				continue;
339 			lseek(f, -(long)sizeof(wtmp), 1);
340 			SCPYN(wtmp.ut_name, "");
341 			time(&wtmp.ut_time);
342 			write(f, (char *)&wtmp, sizeof(wtmp));
343 			found++;
344 		}
345 		close(f);
346 	}
347 	if (found) {
348 		f = open(wtmpf, 1);
349 		if (f >= 0) {
350 			SCPYN(wtmp.ut_line, line+5);
351 			SCPYN(wtmp.ut_name, "");
352 			time(&wtmp.ut_time);
353 			lseek(f, (long)0, 2);
354 			write(f, (char *)&wtmp, sizeof(wtmp));
355 			close(f);
356 		}
357 	}
358 	chmod(line, 0666);
359 	chown(line, 0, 0);
360 	line[strlen("/dev/")] = 'p';
361 	chmod(line, 0666);
362 	chown(line, 0, 0);
363 }
364