xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 16369)
1 #ifndef lint
2 static	char sccsid[] = "@(#)rlogind.c	4.20 (Berkeley) 04/11/84";
3 #endif
4 
5 /*
6  * remote login server:
7  *	remuser\0
8  *	locuser\0
9  *	terminal type\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 
19 #include <netinet/in.h>
20 
21 #include <errno.h>
22 #include <pwd.h>
23 #include <signal.h>
24 #include <sgtty.h>
25 #include <stdio.h>
26 #include <netdb.h>
27 
28 extern	errno;
29 int	reapchild();
30 struct	passwd *getpwnam();
31 char	*crypt(), *rindex(), *index(), *malloc(), *ntoa();
32 
33 main(argc, argv)
34 	int argc;
35 	char **argv;
36 {
37 	int options = 0, fromlen;
38 	struct sockaddr_in from;
39 
40 	fromlen = sizeof (from);
41 	if (getpeername(0, &from, &fromlen) < 0) {
42 		fprintf(stderr, "%s: ", argv[0]);
43 		perror("getpeername");
44 		_exit(1);
45 	}
46 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) {
47 		fprintf(stderr, "%s: ", argv[0]);
48 		perror("setsockopt (SO_KEEPALIVE)");
49 	}
50 	doit(0, &from);
51 }
52 
53 char	locuser[32], remuser[32];
54 char	buf[BUFSIZ];
55 int	child;
56 int	cleanup();
57 int	netf;
58 extern	errno;
59 char	*line;
60 
61 doit(f, fromp)
62 	int f;
63 	struct sockaddr_in *fromp;
64 {
65 	char c;
66 	int i, p, cc, t, pid;
67 	int stop = TIOCPKT_DOSTOP;
68 	register struct hostent *hp;
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 			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) {
125 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
126 		register pcc = 0, fcc = 0;
127 		int on = 1;
128 /* FILE *console = fopen("/dev/console", "w");  */
129 /* setbuf(console, 0); */
130 
131 /* fprintf(console, "f %d p %d\r\n", f, p); */
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 		for (;;) {
139 			int ibits = 0, obits = 0;
140 
141 			if (fcc)
142 				obits |= (1<<p);
143 			else
144 				ibits |= (1<<f);
145 			if (pcc >= 0)
146 				if (pcc)
147 					obits |= (1<<f);
148 				else
149 					ibits |= (1<<p);
150 /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
151 			if (select(16, &ibits, &obits, 0, 0) < 0) {
152 				if (errno == EINTR)
153 					continue;
154 				fatalperror(f, "select", errno);
155 			}
156 /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
157 			if (ibits == 0 && obits == 0) {
158 				/* shouldn't happen... */
159 				sleep(5);
160 				continue;
161 			}
162 			if (ibits & (1<<f)) {
163 				fcc = read(f, fibuf, sizeof (fibuf));
164 /* fprintf(console, "%d from f\r\n", fcc); */
165 				if (fcc < 0 && errno == EWOULDBLOCK)
166 					fcc = 0;
167 				else {
168 					if (fcc <= 0)
169 						break;
170 					fbp = fibuf;
171 				}
172 			}
173 			if (ibits & (1<<p)) {
174 				pcc = read(p, pibuf, sizeof (pibuf));
175 /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
176 				pbp = pibuf;
177 				if (pcc < 0 && errno == EWOULDBLOCK)
178 					pcc = 0;
179 				else if (pcc <= 0)
180 					break;
181 				else if (pibuf[0] == 0)
182 					pbp++, pcc--;
183 				else {
184 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
185 						      TIOCPKT_NOSTOP|
186 						      TIOCPKT_DOSTOP)) {
187 					/* The following 3 lines do nothing. */
188 						int nstop = pibuf[0] &
189 						    (TIOCPKT_NOSTOP|
190 						     TIOCPKT_DOSTOP);
191 						if (nstop)
192 							stop = nstop;
193 						pibuf[0] |= nstop;
194 						send(f,&pibuf[0],1,MSG_OOB);
195 					}
196 					pcc = 0;
197 				}
198 			}
199 			if ((obits & (1<<f)) && pcc > 0) {
200 				cc = write(f, pbp, pcc);
201 				if (cc < 0 && errno == EWOULDBLOCK) {
202 					/* also shouldn't happen */
203 					sleep(5);
204 					continue;
205 				}
206 /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
207 				if (cc > 0) {
208 					pcc -= cc;
209 					pbp += cc;
210 				}
211 			}
212 			if ((obits & (1<<p)) && fcc > 0) {
213 				cc = write(p, fbp, fcc);
214 /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
215 				if (cc > 0) {
216 					fcc -= cc;
217 					fbp += cc;
218 				}
219 			}
220 		}
221 		cleanup();
222 	}
223 	close(f);
224 	close(p);
225 	dup2(t, 0);
226 	dup2(t, 1);
227 	dup2(t, 2);
228 	close(t);
229 	execl("/bin/login", "login", "-r", hp->h_name, 0);
230 	fatalperror(2, "/bin/login", errno);
231 	/*NOTREACHED*/
232 }
233 
234 cleanup()
235 {
236 
237 	rmut();
238 	vhangup();		/* XXX */
239 	shutdown(netf, 2);
240 	kill(0, SIGKILL);
241 	exit(1);
242 }
243 
244 fatal(f, msg)
245 	int f;
246 	char *msg;
247 {
248 	char buf[BUFSIZ];
249 
250 	buf[0] = '\01';		/* error indicator */
251 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
252 	(void) write(f, buf, strlen(buf));
253 	exit(1);
254 }
255 
256 fatalperror(f, msg, errno)
257 	int f;
258 	char *msg;
259 	int errno;
260 {
261 	char buf[BUFSIZ];
262 	extern int sys_nerr;
263 	extern char *sys_errlist[];
264 
265 	if ((unsigned) errno < sys_nerr)
266 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
267 	else
268 		(void) sprintf(buf, "%s: Error %d", msg, errno);
269 	fatal(f, buf);
270 }
271 
272 #include <utmp.h>
273 
274 struct	utmp wtmp;
275 char	wtmpf[]	= "/usr/adm/wtmp";
276 char	utmp[] = "/etc/utmp";
277 #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
278 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
279 
280 rmut()
281 {
282 	register f;
283 	int found = 0;
284 
285 	f = open(utmp, 2);
286 	if (f >= 0) {
287 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
288 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
289 				continue;
290 			lseek(f, -(long)sizeof(wtmp), 1);
291 			SCPYN(wtmp.ut_name, "");
292 			SCPYN(wtmp.ut_host, "");
293 			time(&wtmp.ut_time);
294 			write(f, (char *)&wtmp, sizeof(wtmp));
295 			found++;
296 		}
297 		close(f);
298 	}
299 	if (found) {
300 		f = open(wtmpf, 1);
301 		if (f >= 0) {
302 			SCPYN(wtmp.ut_line, line+5);
303 			SCPYN(wtmp.ut_name, "");
304 			SCPYN(wtmp.ut_host, "");
305 			time(&wtmp.ut_time);
306 			lseek(f, (long)0, 2);
307 			write(f, (char *)&wtmp, sizeof(wtmp));
308 			close(f);
309 		}
310 	}
311 	chmod(line, 0666);
312 	chown(line, 0, 0);
313 	line[strlen("/dev/")] = 'p';
314 	chmod(line, 0666);
315 	chown(line, 0, 0);
316 }
317 
318 /*
319  * Convert network-format internet address
320  * to base 256 d.d.d.d representation.
321  */
322 char *
323 ntoa(in)
324 	struct in_addr in;
325 {
326 	static char b[18];
327 	register char *p;
328 
329 	p = (char *)&in;
330 #define	UC(b)	(((int)b)&0xff)
331 	sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
332 	return (b);
333 }
334