xref: /original-bsd/libexec/rlogind/rlogind.c (revision 6b7db209)
1 #ifndef lint
2 static char sccsid[] = "@(#)rlogind.c	4.5 82/11/15";
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 struct	passwd *getpwnam();
22 char	*crypt(), *rindex(), *index(), *malloc();
23 int	options = SO_ACCEPTCONN|SO_KEEPALIVE;
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 	union wait status;
37 	int f, debug = 0;
38 	struct sockaddr_in from;
39 	struct servent *sp;
40 
41 	sp = getservbyname("login", "tcp");
42 	if (sp == 0) {
43 		fprintf(stderr, "rlogind: tcp/rlogin: unknown service\n");
44 		exit(1);
45 	}
46 #ifndef DEBUG
47 	if (fork())
48 		exit(0);
49 	for (f = 0; f < 10; f++)
50 		(void) close(f);
51 	(void) open("/", 0);
52 	(void) dup2(0, 1);
53 	(void) dup2(0, 2);
54 	{ int tt = open("/dev/tty", 2);
55 	  if (tt > 0) {
56 		ioctl(tt, TIOCNOTTY, 0);
57 		close(tt);
58 	  }
59 	}
60 #endif
61 	sin.sin_port = htons(sp->s_port);
62 	argc--, argv++;
63 	if (argc > 0 && !strcmp(argv[0], "-d")) {
64 		int port = atoi(argv[0]);
65 
66 		if (port < 0) {
67 			fprintf(stderr, "%s: bad port #\n", argv[0]);
68 			exit(1);
69 		}
70 		sin.sin_port = htons(port);
71 		argv++, argc--;
72 	}
73 	f = socket(AF_INET, SOCK_STREAM, 0, 0);
74 	if (f < 0) {
75 		perror("rlogind: socket");
76 		exit(1);
77 	}
78 	if (bind(f, &sin, sizeof (sin), 0) < 0) {
79 		perror("rlogind: bind");
80 		exit(1);
81 	}
82 	listen(f, 10);
83 	for (;;) {
84 		int s, len = sizeof (from);
85 
86 		s = accept(f, &from, &len, 0);
87 		if (s < 0) {
88 			perror("rlogind: accept");
89 			sleep(1);
90 			continue;
91 		}
92 		if (fork() == 0)
93 			doit(s, &from);
94 		close(s);
95 		while (wait3(status, WNOHANG, 0) > 0)
96 			continue;
97 	}
98 }
99 
100 char	locuser[32], remuser[32];
101 char	buf[BUFSIZ];
102 int	child;
103 int	cleanup();
104 int	netf;
105 extern	errno;
106 char	*line;
107 
108 doit(f, fromp)
109 	int f;
110 	struct sockaddr_in *fromp;
111 {
112 	char c;
113 	int i, p, cc, t, pid;
114 	int stop = TIOCPKT_DOSTOP;
115 	register struct hostent *hp;
116 
117 	alarm(60);
118 	read(f, &c, 1);
119 	if (c != 0)
120 		exit(1);
121 	alarm(0);
122 	fromp->sin_port = htons(fromp->sin_port);
123 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
124 		fromp->sin_family);
125 	if (hp == 0)
126 		fatal(f, "Host name for your address unknown");
127 	if (fromp->sin_family != AF_INET ||
128 	    fromp->sin_port >= IPPORT_RESERVED ||
129 	    hp == 0)
130 		fatal(f, "Permission denied");
131 	write(f, "", 1);
132 	for (c = 'p'; c <= 's'; c++) {
133 		struct stat stb;
134 		line = "/dev/ptyXX";
135 		line[strlen("/dev/pty")] = c;
136 		line[strlen("/dev/ptyp")] = '0';
137 		if (stat(line, &stb) < 0)
138 			break;
139 		for (i = 0; i < 16; i++) {
140 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
141 			p = open(line, 2);
142 			if (p > 0)
143 				goto gotpty;
144 		}
145 	}
146 	fatal(f, "All network ports in use");
147 	/*NOTREACHED*/
148 gotpty:
149 	dup2(f, 0);
150 	line[strlen("/dev/")] = 't';
151 #ifdef DEBUG
152 	{ int tt = open("/dev/tty", 2);
153 	  if (tt > 0) {
154 		ioctl(tt, TIOCNOTTY, 0);
155 		close(tt);
156 	  }
157 	}
158 #endif
159 	t = open(line, 2);
160 	if (t < 0)
161 		fatalperror(f, line, errno);
162 	{ struct sgttyb b;
163 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
164 	}
165 	pid = fork();
166 	if (pid < 0)
167 		fatalperror(f, "", errno);
168 	if (pid) {
169 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
170 		int pcc = 0, fcc = 0, on = 1;
171 /* FILE *console = fopen("/dev/console", "w");  */
172 /* setbuf(console, 0); */
173 
174 /* fprintf(console, "f %d p %d\r\n", f, p); */
175 		ioctl(f, FIONBIO, &on);
176 		ioctl(p, FIONBIO, &on);
177 		ioctl(p, TIOCPKT, &on);
178 		signal(SIGTSTP, SIG_IGN);
179 		sigset(SIGCHLD, cleanup);
180 		for (;;) {
181 			int ibits = 0, obits = 0;
182 
183 			if (fcc)
184 				obits |= (1<<p);
185 			else
186 				ibits |= (1<<f);
187 			if (pcc >= 0)
188 				if (pcc)
189 					obits |= (1<<f);
190 				else
191 					ibits |= (1<<p);
192 			if (fcc < 0 && pcc < 0)
193 				break;
194 /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
195 			select(16, &ibits, &obits, 0, 0, 0);
196 /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
197 			if (ibits == 0 && obits == 0) {
198 				sleep(5);
199 				continue;
200 			}
201 			if (ibits & (1<<f)) {
202 				fcc = read(f, fibuf, sizeof (fibuf));
203 /* fprintf(console, "%d from f\r\n", fcc); */
204 				if (fcc < 0 && errno == EWOULDBLOCK)
205 					fcc = 0;
206 				else {
207 					if (fcc <= 0)
208 						break;
209 					fbp = fibuf;
210 				}
211 			}
212 			if (ibits & (1<<p)) {
213 				pcc = read(p, pibuf, sizeof (pibuf));
214 /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
215 				pbp = pibuf;
216 				if (pcc < 0 && errno == EWOULDBLOCK)
217 					pcc = 0;
218 				else if (pcc <= 0)
219 					pcc = -1;
220 				else if (pibuf[0] == 0)
221 					pbp++, pcc--;
222 				else {
223 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
224 						      TIOCPKT_NOSTOP|
225 						      TIOCPKT_DOSTOP)) {
226 						int nstop = pibuf[0] &
227 						    (TIOCPKT_NOSTOP|
228 						     TIOCPKT_DOSTOP);
229 						if (nstop)
230 							stop = nstop;
231 						pibuf[0] |= nstop;
232 						send(f,&pibuf[0],1,SOF_OOB);
233 					}
234 					pcc = 0;
235 				}
236 			}
237 			if ((obits & (1<<f)) && pcc > 0) {
238 				cc = write(f, pbp, pcc);
239 /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
240 				if (cc > 0) {
241 					pcc -= cc;
242 					pbp += cc;
243 				}
244 			}
245 			if ((obits & (1<<p)) && fcc > 0) {
246 				cc = write(p, fbp, fcc);
247 /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
248 				if (cc > 0) {
249 					fcc -= cc;
250 					fbp += cc;
251 				}
252 			}
253 		}
254 		cleanup();
255 	}
256 	close(f);
257 	close(p);
258 	dup2(t, 0);
259 	dup2(t, 1);
260 	dup2(t, 2);
261 	close(t);
262 	execl("/bin/login", "login", "-r", hp->h_name, 0);
263 	fatalperror(2, "/bin/login", errno);
264 	/*NOTREACHED*/
265 }
266 
267 cleanup()
268 {
269 	int how = 2;
270 
271 	rmut();
272 	ioctl(netf, SIOCDONE, &how);
273 	kill(0, SIGKILL);
274 	exit(1);
275 }
276 
277 fatal(f, msg)
278 	int f;
279 	char *msg;
280 {
281 	char buf[BUFSIZ];
282 
283 	buf[0] = '\01';		/* error indicator */
284 	(void) sprintf(buf + 1, "rlogind: %s.\n", msg);
285 	(void) write(f, buf, strlen(buf));
286 	exit(1);
287 }
288 
289 fatalperror(f, msg, errno)
290 	int f;
291 	char *msg;
292 	int errno;
293 {
294 	char buf[BUFSIZ];
295 	extern char *sys_errlist[];
296 
297 	(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
298 	fatal(f, buf);
299 }
300 
301 #include <utmp.h>
302 
303 struct	utmp wtmp;
304 char	wtmpf[]	= "/usr/adm/wtmp";
305 char	utmp[] = "/etc/utmp";
306 #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
307 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
308 
309 rmut()
310 {
311 	register f;
312 	int found = 0;
313 
314 	f = open(utmp, 2);
315 	if (f >= 0) {
316 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
317 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
318 				continue;
319 			lseek(f, -(long)sizeof(wtmp), 1);
320 			SCPYN(wtmp.ut_name, "");
321 			time(&wtmp.ut_time);
322 			write(f, (char *)&wtmp, sizeof(wtmp));
323 			found++;
324 		}
325 		close(f);
326 	}
327 	if (found) {
328 		f = open(wtmpf, 1);
329 		if (f >= 0) {
330 			SCPYN(wtmp.ut_line, line+5);
331 			SCPYN(wtmp.ut_name, "");
332 			time(&wtmp.ut_time);
333 			lseek(f, (long)0, 2);
334 			write(f, (char *)&wtmp, sizeof(wtmp));
335 			close(f);
336 		}
337 	}
338 	chmod(line, 0666);
339 	chown(line, 0, 0);
340 	line[strlen("/dev/")] = 'p';
341 	chmod(line, 0666);
342 	chown(line, 0, 0);
343 }
344