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