Fix from Charles Hedrick at Rutgers - flush output when
[unix-history] / usr / src / libexec / rlogind / rlogind.c
CommitLineData
8c5eec2f
DF
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
a10a364d 13#ifndef lint
c7299f34 14static char sccsid[] = "@(#)rlogind.c 5.13 (Berkeley) %G%";
8c5eec2f 15#endif not lint
a10a364d 16
bb933cc2
MK
17/*
18 * remote login server:
19 * remuser\0
20 * locuser\0
6632767b 21 * terminal info\0
bb933cc2
MK
22 * data
23 */
24
a10a364d
BJ
25#include <stdio.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/socket.h>
560a8855 29#include <sys/wait.h>
6632767b 30#include <sys/file.h>
c6c678f1
SL
31
32#include <netinet/in.h>
33
a10a364d
BJ
34#include <errno.h>
35#include <pwd.h>
a10a364d
BJ
36#include <signal.h>
37#include <sgtty.h>
38#include <stdio.h>
3f5b52bc 39#include <netdb.h>
3f99c0f7 40#include <syslog.h>
6632767b 41#include <strings.h>
a10a364d 42
66feb14c
KM
43# ifndef TIOCPKT_WINDOW
44# define TIOCPKT_WINDOW 0x80
45# endif TIOCPKT_WINDOW
46
a10a364d 47extern errno;
92e31018 48int reapchild();
a10a364d 49struct passwd *getpwnam();
66feb14c 50char *malloc();
bb933cc2 51
a10a364d
BJ
52main(argc, argv)
53 int argc;
54 char **argv;
55{
bcb894cb 56 int on = 1, options = 0, fromlen;
a10a364d
BJ
57 struct sockaddr_in from;
58
076ae92c 59 openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
bb933cc2
MK
60 fromlen = sizeof (from);
61 if (getpeername(0, &from, &fromlen) < 0) {
62 fprintf(stderr, "%s: ", argv[0]);
63 perror("getpeername");
64 _exit(1);
92e31018 65 }
bcb894cb 66 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
3f99c0f7 67 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
c6c678f1 68 }
bb933cc2 69 doit(0, &from);
92e31018
SL
70}
71
a10a364d
BJ
72int child;
73int cleanup();
74int netf;
75extern errno;
76char *line;
43368533 77extern char *inet_ntoa();
a10a364d 78
8210fa73
KM
79struct winsize win = { 0, 0, 0, 0 };
80
66feb14c 81
a10a364d
BJ
82doit(f, fromp)
83 int f;
84 struct sockaddr_in *fromp;
85{
6632767b 86 int i, p, t, pid, on = 1;
3f5b52bc 87 register struct hostent *hp;
43368533 88 struct hostent hostent;
6632767b 89 char c;
a10a364d
BJ
90
91 alarm(60);
92 read(f, &c, 1);
93 if (c != 0)
94 exit(1);
95 alarm(0);
1227078b 96 fromp->sin_port = ntohs((u_short)fromp->sin_port);
3f5b52bc
SL
97 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
98 fromp->sin_family);
8de87e4f 99 if (hp == 0) {
43368533
KM
100 /*
101 * Only the name is used below.
102 */
103 hp = &hostent;
104 hp->h_name = inet_ntoa(fromp->sin_addr);
8de87e4f 105 }
a10a364d 106 if (fromp->sin_family != AF_INET ||
fdc1cc8b
MK
107 fromp->sin_port >= IPPORT_RESERVED ||
108 fromp->sin_port < IPPORT_RESERVED/2)
82c973f2 109 fatal(f, "Permission denied");
a10a364d
BJ
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 }
66feb14c 125 fatal(f, "Out of ptys");
82c973f2 126 /*NOTREACHED*/
a10a364d 127gotpty:
8210fa73 128 (void) ioctl(p, TIOCSWINSZ, &win);
1227078b 129 netf = f;
a10a364d
BJ
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);
82c973f2
SL
140 if (t < 0)
141 fatalperror(f, line, errno);
a10a364d
BJ
142 { struct sgttyb b;
143 gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
144 }
82c973f2
SL
145 pid = fork();
146 if (pid < 0)
147 fatalperror(f, "", errno);
6632767b
SL
148 if (pid == 0) {
149 close(f), close(p);
150 dup2(t, 0), dup2(t, 1), dup2(t, 2);
1227078b 151 close(t);
6632767b
SL
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);
ad5d2c7f 162 setpgrp(0, 0);
6632767b 163 protocol(f, p);
78c1c171 164 signal(SIGCHLD, SIG_IGN);
6632767b
SL
165 cleanup();
166}
82c973f2 167
6632767b 168char magic[2] = { 0377, 0377 };
87e80234 169char oobdata[] = {TIOCPKT_WINDOW};
6632767b
SL
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{
cfafdcf2 181 struct winsize w;
6632767b 182
cfafdcf2 183 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
6632767b 184 return (0);
87e80234 185 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
cfafdcf2
KM
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));
6632767b
SL
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;
87e80234 203 int cc;
2c360ad3 204 char cntl;
6632767b 205
ffaf1c0b 206 /*
9ee4d121
SL
207 * Must ignore SIGTTOU, otherwise we'll stop
208 * when we try and set slave pty's window shape
87e80234 209 * (our controlling tty is the master pty).
ffaf1c0b 210 */
9ee4d121 211 (void) signal(SIGTTOU, SIG_IGN);
87e80234 212 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
6632767b 213 for (;;) {
2c360ad3 214 int ibits, obits, ebits;
6632767b 215
2c360ad3
MK
216 ibits = 0;
217 obits = 0;
6632767b
SL
218 if (fcc)
219 obits |= (1<<p);
220 else
221 ibits |= (1<<f);
222 if (pcc >= 0)
223 if (pcc)
224 obits |= (1<<f);
82c973f2 225 else
6632767b 226 ibits |= (1<<p);
2c360ad3
MK
227 ebits = (1<<p);
228 if (select(16, &ibits, &obits, &ebits, 0) < 0) {
6632767b 229 if (errno == EINTR)
a10a364d 230 continue;
6632767b
SL
231 fatalperror(f, "select", errno);
232 }
2c360ad3 233 if (ibits == 0 && obits == 0 && ebits == 0) {
6632767b
SL
234 /* shouldn't happen... */
235 sleep(5);
236 continue;
237 }
2c360ad3
MK
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 }
6632767b
SL
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)
1227078b 259 break;
6632767b 260 fbp = fibuf;
66feb14c 261
6632767b 262 top:
87e80234 263 for (cp = fibuf; cp < fibuf+fcc-1; cp++)
6632767b
SL
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)
87e80234 271 bcopy(cp+n, cp, left);
6632767b
SL
272 fcc -= n;
273 goto top; /* n^2 */
87e80234
MK
274 }
275 }
276 }
277 }
66feb14c
KM
278
279 if ((obits & (1<<p)) && fcc > 0) {
87e80234 280 cc = write(p, fbp, fcc);
66feb14c
KM
281 if (cc > 0) {
282 fcc -= cc;
283 fbp += cc;
a10a364d 284 }
6632767b 285 }
66feb14c 286
6632767b
SL
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 {
6632767b 297 if (pkcontrol(pibuf[0])) {
87e80234 298 pibuf[0] |= oobdata[0];
6632767b 299 send(f, &pibuf[0], 1, MSG_OOB);
a10a364d 300 }
6632767b 301 pcc = 0;
a10a364d 302 }
6632767b
SL
303 }
304 if ((obits & (1<<f)) && pcc > 0) {
87e80234
MK
305 cc = write(f, pbp, pcc);
306 if (cc < 0 && errno == EWOULDBLOCK) {
307 /* also shouldn't happen */
308 sleep(5);
309 continue;
310 }
6632767b
SL
311 if (cc > 0) {
312 pcc -= cc;
313 pbp += cc;
314 }
315 }
a10a364d 316 }
a10a364d
BJ
317}
318
319cleanup()
320{
a10a364d
BJ
321
322 rmut();
dd83e8ac 323 vhangup(); /* XXX */
ff24c640 324 shutdown(netf, 2);
a10a364d
BJ
325 exit(1);
326}
327
82c973f2
SL
328fatal(f, msg)
329 int f;
330 char *msg;
331{
332 char buf[BUFSIZ];
333
334 buf[0] = '\01'; /* error indicator */
560a8855 335 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
82c973f2
SL
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];
1227078b 346 extern int sys_nerr;
82c973f2
SL
347 extern char *sys_errlist[];
348
6632767b 349 if ((unsigned)errno < sys_nerr)
1227078b
MK
350 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
351 else
352 (void) sprintf(buf, "%s: Error %d", msg, errno);
82c973f2
SL
353 fatal(f, buf);
354}
355
a10a364d
BJ
356#include <utmp.h>
357
358struct utmp wtmp;
359char wtmpf[] = "/usr/adm/wtmp";
0675fdb1 360char utmpf[] = "/etc/utmp";
a10a364d
BJ
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;
0675fdb1
JB
368 struct utmp *u, *utmp;
369 int nutmp;
370 struct stat statbf;
a10a364d 371
0675fdb1 372 f = open(utmpf, O_RDWR);
a10a364d 373 if (f >= 0) {
0675fdb1
JB
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 }
a10a364d
BJ
393 }
394 close(f);
395 }
396 if (found) {
0675fdb1 397 f = open(wtmpf, O_WRONLY|O_APPEND);
a10a364d
BJ
398 if (f >= 0) {
399 SCPYN(wtmp.ut_line, line+5);
400 SCPYN(wtmp.ut_name, "");
9b3ee53c 401 SCPYN(wtmp.ut_host, "");
a10a364d 402 time(&wtmp.ut_time);
a10a364d
BJ
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}