lint
[unix-history] / usr / src / libexec / rlogind / rlogind.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
13#ifndef lint
14static char sccsid[] = "@(#)rlogind.c 5.13 (Berkeley) %G%";
15#endif not lint
16
17/*
18 * remote login server:
19 * remuser\0
20 * locuser\0
21 * terminal info\0
22 * data
23 */
24
25#include <stdio.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/socket.h>
29#include <sys/wait.h>
30#include <sys/file.h>
31
32#include <netinet/in.h>
33
34#include <errno.h>
35#include <pwd.h>
36#include <signal.h>
37#include <sgtty.h>
38#include <stdio.h>
39#include <netdb.h>
40#include <syslog.h>
41#include <strings.h>
42
43# ifndef TIOCPKT_WINDOW
44# define TIOCPKT_WINDOW 0x80
45# endif TIOCPKT_WINDOW
46
47extern errno;
48int reapchild();
49struct passwd *getpwnam();
50char *malloc();
51
52main(argc, argv)
53 int argc;
54 char **argv;
55{
56 int on = 1, options = 0, fromlen;
57 struct sockaddr_in from;
58
59 openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
60 fromlen = sizeof (from);
61 if (getpeername(0, &from, &fromlen) < 0) {
62 fprintf(stderr, "%s: ", argv[0]);
63 perror("getpeername");
64 _exit(1);
65 }
66 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
67 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
68 }
69 doit(0, &from);
70}
71
72int child;
73int cleanup();
74int netf;
75extern errno;
76char *line;
77extern char *inet_ntoa();
78
79struct winsize win = { 0, 0, 0, 0 };
80
81
82doit(f, fromp)
83 int f;
84 struct sockaddr_in *fromp;
85{
86 int i, p, t, pid, on = 1;
87 register struct hostent *hp;
88 struct hostent hostent;
89 char c;
90
91 alarm(60);
92 read(f, &c, 1);
93 if (c != 0)
94 exit(1);
95 alarm(0);
96 fromp->sin_port = ntohs((u_short)fromp->sin_port);
97 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
98 fromp->sin_family);
99 if (hp == 0) {
100 /*
101 * Only the name is used below.
102 */
103 hp = &hostent;
104 hp->h_name = inet_ntoa(fromp->sin_addr);
105 }
106 if (fromp->sin_family != AF_INET ||
107 fromp->sin_port >= IPPORT_RESERVED ||
108 fromp->sin_port < IPPORT_RESERVED/2)
109 fatal(f, "Permission denied");
110 write(f, "", 1);
111 for (c = 'p'; c <= 's'; c++) {
112 struct stat stb;
113 line = "/dev/ptyXX";
114 line[strlen("/dev/pty")] = c;
115 line[strlen("/dev/ptyp")] = '0';
116 if (stat(line, &stb) < 0)
117 break;
118 for (i = 0; i < 16; i++) {
119 line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
120 p = open(line, 2);
121 if (p > 0)
122 goto gotpty;
123 }
124 }
125 fatal(f, "Out of ptys");
126 /*NOTREACHED*/
127gotpty:
128 (void) ioctl(p, TIOCSWINSZ, &win);
129 netf = f;
130 line[strlen("/dev/")] = 't';
131#ifdef DEBUG
132 { int tt = open("/dev/tty", 2);
133 if (tt > 0) {
134 ioctl(tt, TIOCNOTTY, 0);
135 close(tt);
136 }
137 }
138#endif
139 t = open(line, 2);
140 if (t < 0)
141 fatalperror(f, line, errno);
142 { struct sgttyb b;
143 gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
144 }
145 pid = fork();
146 if (pid < 0)
147 fatalperror(f, "", errno);
148 if (pid == 0) {
149 close(f), close(p);
150 dup2(t, 0), dup2(t, 1), dup2(t, 2);
151 close(t);
152 execl("/bin/login", "login", "-r", hp->h_name, 0);
153 fatalperror(2, "/bin/login", errno);
154 /*NOTREACHED*/
155 }
156 close(t);
157 ioctl(f, FIONBIO, &on);
158 ioctl(p, FIONBIO, &on);
159 ioctl(p, TIOCPKT, &on);
160 signal(SIGTSTP, SIG_IGN);
161 signal(SIGCHLD, cleanup);
162 setpgrp(0, 0);
163 protocol(f, p);
164 signal(SIGCHLD, SIG_IGN);
165 cleanup();
166}
167
168char magic[2] = { 0377, 0377 };
169char oobdata[] = {TIOCPKT_WINDOW};
170
171/*
172 * Handle a "control" request (signaled by magic being present)
173 * in the data stream. For now, we are only willing to handle
174 * window size changes.
175 */
176control(pty, cp, n)
177 int pty;
178 char *cp;
179 int n;
180{
181 struct winsize w;
182
183 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
184 return (0);
185 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
186 bcopy(cp+4, (char *)&w, sizeof(w));
187 w.ws_row = ntohs(w.ws_row);
188 w.ws_col = ntohs(w.ws_col);
189 w.ws_xpixel = ntohs(w.ws_xpixel);
190 w.ws_ypixel = ntohs(w.ws_ypixel);
191 (void)ioctl(pty, TIOCSWINSZ, &w);
192 return (4+sizeof (w));
193}
194
195/*
196 * rlogin "protocol" machine.
197 */
198protocol(f, p)
199 int f, p;
200{
201 char pibuf[1024], fibuf[1024], *pbp, *fbp;
202 register pcc = 0, fcc = 0;
203 int cc;
204 char cntl;
205
206 /*
207 * Must ignore SIGTTOU, otherwise we'll stop
208 * when we try and set slave pty's window shape
209 * (our controlling tty is the master pty).
210 */
211 (void) signal(SIGTTOU, SIG_IGN);
212 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
213 for (;;) {
214 int ibits, obits, ebits;
215
216 ibits = 0;
217 obits = 0;
218 if (fcc)
219 obits |= (1<<p);
220 else
221 ibits |= (1<<f);
222 if (pcc >= 0)
223 if (pcc)
224 obits |= (1<<f);
225 else
226 ibits |= (1<<p);
227 ebits = (1<<p);
228 if (select(16, &ibits, &obits, &ebits, 0) < 0) {
229 if (errno == EINTR)
230 continue;
231 fatalperror(f, "select", errno);
232 }
233 if (ibits == 0 && obits == 0 && ebits == 0) {
234 /* shouldn't happen... */
235 sleep(5);
236 continue;
237 }
238#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
239 if (ebits & (1<<p)) {
240 cc = read(p, &cntl, 1);
241 if (cc == 1 && pkcontrol(cntl)) {
242 cntl |= oobdata[0];
243 send(f, &cntl, 1, MSG_OOB);
244 if (cntl & TIOCPKT_FLUSHWRITE) {
245 pcc = 0;
246 ibits &= ~(1<<p);
247 }
248 }
249 }
250 if (ibits & (1<<f)) {
251 fcc = read(f, fibuf, sizeof (fibuf));
252 if (fcc < 0 && errno == EWOULDBLOCK)
253 fcc = 0;
254 else {
255 register char *cp;
256 int left, n;
257
258 if (fcc <= 0)
259 break;
260 fbp = fibuf;
261
262 top:
263 for (cp = fibuf; cp < fibuf+fcc-1; cp++)
264 if (cp[0] == magic[0] &&
265 cp[1] == magic[1]) {
266 left = fcc - (cp-fibuf);
267 n = control(p, cp, left);
268 if (n) {
269 left -= n;
270 if (left > 0)
271 bcopy(cp+n, cp, left);
272 fcc -= n;
273 goto top; /* n^2 */
274 }
275 }
276 }
277 }
278
279 if ((obits & (1<<p)) && fcc > 0) {
280 cc = write(p, fbp, fcc);
281 if (cc > 0) {
282 fcc -= cc;
283 fbp += cc;
284 }
285 }
286
287 if (ibits & (1<<p)) {
288 pcc = read(p, pibuf, sizeof (pibuf));
289 pbp = pibuf;
290 if (pcc < 0 && errno == EWOULDBLOCK)
291 pcc = 0;
292 else if (pcc <= 0)
293 break;
294 else if (pibuf[0] == 0)
295 pbp++, pcc--;
296 else {
297 if (pkcontrol(pibuf[0])) {
298 pibuf[0] |= oobdata[0];
299 send(f, &pibuf[0], 1, MSG_OOB);
300 }
301 pcc = 0;
302 }
303 }
304 if ((obits & (1<<f)) && pcc > 0) {
305 cc = write(f, pbp, pcc);
306 if (cc < 0 && errno == EWOULDBLOCK) {
307 /* also shouldn't happen */
308 sleep(5);
309 continue;
310 }
311 if (cc > 0) {
312 pcc -= cc;
313 pbp += cc;
314 }
315 }
316 }
317}
318
319cleanup()
320{
321
322 rmut();
323 vhangup(); /* XXX */
324 shutdown(netf, 2);
325 exit(1);
326}
327
328fatal(f, msg)
329 int f;
330 char *msg;
331{
332 char buf[BUFSIZ];
333
334 buf[0] = '\01'; /* error indicator */
335 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
336 (void) write(f, buf, strlen(buf));
337 exit(1);
338}
339
340fatalperror(f, msg, errno)
341 int f;
342 char *msg;
343 int errno;
344{
345 char buf[BUFSIZ];
346 extern int sys_nerr;
347 extern char *sys_errlist[];
348
349 if ((unsigned)errno < sys_nerr)
350 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
351 else
352 (void) sprintf(buf, "%s: Error %d", msg, errno);
353 fatal(f, buf);
354}
355
356#include <utmp.h>
357
358struct utmp wtmp;
359char wtmpf[] = "/usr/adm/wtmp";
360char utmpf[] = "/etc/utmp";
361#define SCPYN(a, b) strncpy(a, b, sizeof(a))
362#define SCMPN(a, b) strncmp(a, b, sizeof(a))
363
364rmut()
365{
366 register f;
367 int found = 0;
368 struct utmp *u, *utmp;
369 int nutmp;
370 struct stat statbf;
371
372 f = open(utmpf, O_RDWR);
373 if (f >= 0) {
374 fstat(f, &statbf);
375 utmp = (struct utmp *)malloc(statbf.st_size);
376 if (!utmp)
377 syslog(LOG_ERR, "utmp malloc failed");
378 if (statbf.st_size && utmp) {
379 nutmp = read(f, utmp, statbf.st_size);
380 nutmp /= sizeof(struct utmp);
381
382 for (u = utmp ; u < &utmp[nutmp] ; u++) {
383 if (SCMPN(u->ut_line, line+5) ||
384 u->ut_name[0]==0)
385 continue;
386 lseek(f, ((long)u)-((long)utmp), L_SET);
387 SCPYN(u->ut_name, "");
388 SCPYN(u->ut_host, "");
389 time(&u->ut_time);
390 write(f, (char *)u, sizeof(wtmp));
391 found++;
392 }
393 }
394 close(f);
395 }
396 if (found) {
397 f = open(wtmpf, O_WRONLY|O_APPEND);
398 if (f >= 0) {
399 SCPYN(wtmp.ut_line, line+5);
400 SCPYN(wtmp.ut_name, "");
401 SCPYN(wtmp.ut_host, "");
402 time(&wtmp.ut_time);
403 write(f, (char *)&wtmp, sizeof(wtmp));
404 close(f);
405 }
406 }
407 chmod(line, 0666);
408 chown(line, 0, 0);
409 line[strlen("/dev/")] = 'p';
410 chmod(line, 0666);
411 chown(line, 0, 0);
412}