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