branch-place-holder
[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
551b317a 14static char sccsid[] = "@(#)rlogind.c 5.2.1.1 (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
BJ
42
43extern errno;
92e31018 44int reapchild();
a10a364d 45struct passwd *getpwnam();
6632767b 46char *crypt(), *malloc();
bb933cc2 47
a10a364d
BJ
48main(argc, argv)
49 int argc;
50 char **argv;
51{
bcb894cb 52 int on = 1, options = 0, fromlen;
a10a364d
BJ
53 struct sockaddr_in from;
54
bb933cc2
MK
55 fromlen = sizeof (from);
56 if (getpeername(0, &from, &fromlen) < 0) {
57 fprintf(stderr, "%s: ", argv[0]);
58 perror("getpeername");
59 _exit(1);
92e31018 60 }
bcb894cb 61 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
3f99c0f7
RC
62 openlog(argv[0], LOG_PID, 0);
63 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
c6c678f1 64 }
bb933cc2 65 doit(0, &from);
92e31018
SL
66}
67
a10a364d
BJ
68int child;
69int cleanup();
70int netf;
71extern errno;
72char *line;
43368533 73extern char *inet_ntoa();
a10a364d
BJ
74
75doit(f, fromp)
76 int f;
77 struct sockaddr_in *fromp;
78{
6632767b 79 int i, p, t, pid, on = 1;
3f5b52bc 80 register struct hostent *hp;
43368533 81 struct hostent hostent;
6632767b 82 char c;
a10a364d
BJ
83
84 alarm(60);
85 read(f, &c, 1);
86 if (c != 0)
87 exit(1);
88 alarm(0);
1227078b 89 fromp->sin_port = ntohs((u_short)fromp->sin_port);
3f5b52bc
SL
90 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
91 fromp->sin_family);
8de87e4f 92 if (hp == 0) {
43368533
KM
93 /*
94 * Only the name is used below.
95 */
96 hp = &hostent;
97 hp->h_name = inet_ntoa(fromp->sin_addr);
8de87e4f 98 }
a10a364d 99 if (fromp->sin_family != AF_INET ||
1227078b 100 fromp->sin_port >= IPPORT_RESERVED)
82c973f2 101 fatal(f, "Permission denied");
a10a364d
BJ
102 write(f, "", 1);
103 for (c = 'p'; c <= 's'; c++) {
104 struct stat stb;
105 line = "/dev/ptyXX";
106 line[strlen("/dev/pty")] = c;
107 line[strlen("/dev/ptyp")] = '0';
108 if (stat(line, &stb) < 0)
109 break;
110 for (i = 0; i < 16; i++) {
111 line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
112 p = open(line, 2);
113 if (p > 0)
114 goto gotpty;
115 }
116 }
82c973f2
SL
117 fatal(f, "All network ports in use");
118 /*NOTREACHED*/
a10a364d 119gotpty:
1227078b 120 netf = f;
a10a364d
BJ
121 line[strlen("/dev/")] = 't';
122#ifdef DEBUG
123 { int tt = open("/dev/tty", 2);
124 if (tt > 0) {
125 ioctl(tt, TIOCNOTTY, 0);
126 close(tt);
127 }
128 }
129#endif
130 t = open(line, 2);
82c973f2
SL
131 if (t < 0)
132 fatalperror(f, line, errno);
a10a364d
BJ
133 { struct sgttyb b;
134 gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
135 }
82c973f2
SL
136 pid = fork();
137 if (pid < 0)
138 fatalperror(f, "", errno);
6632767b
SL
139 if (pid == 0) {
140 close(f), close(p);
141 dup2(t, 0), dup2(t, 1), dup2(t, 2);
1227078b 142 close(t);
6632767b
SL
143 execl("/bin/login", "login", "-r", hp->h_name, 0);
144 fatalperror(2, "/bin/login", errno);
145 /*NOTREACHED*/
146 }
147 close(t);
148 ioctl(f, FIONBIO, &on);
149 ioctl(p, FIONBIO, &on);
150 ioctl(p, TIOCPKT, &on);
151 signal(SIGTSTP, SIG_IGN);
152 signal(SIGCHLD, cleanup);
ad5d2c7f 153 setpgrp(0, 0);
6632767b
SL
154 protocol(f, p);
155 cleanup();
156}
82c973f2 157
6632767b
SL
158char magic[2] = { 0377, 0377 };
159
160/*
161 * Handle a "control" request (signaled by magic being present)
162 * in the data stream. For now, we are only willing to handle
163 * window size changes.
164 */
165control(pty, cp, n)
166 int pty;
167 char *cp;
168 int n;
169{
170 struct winsize *wp;
171
172 if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's')
173 return (0);
174 wp = (struct winsize *)(cp+4);
175 wp->ws_row = ntohs(wp->ws_row);
176 wp->ws_col = ntohs(wp->ws_col);
177 wp->ws_xpixel = ntohs(wp->ws_xpixel);
178 wp->ws_ypixel = ntohs(wp->ws_ypixel);
179 (void)ioctl(pty, TIOCSWINSZ, wp);
180 return (4+sizeof (*wp));
181}
182
183/*
184 * rlogin "protocol" machine.
185 */
186protocol(f, p)
187 int f, p;
188{
189 char pibuf[1024], fibuf[1024], *pbp, *fbp;
190 register pcc = 0, fcc = 0;
191 int cc, stop = TIOCPKT_DOSTOP;
192
ffaf1c0b 193 /*
9ee4d121
SL
194 * Must ignore SIGTTOU, otherwise we'll stop
195 * when we try and set slave pty's window shape
196 * (our pgrp is that of the master pty).
ffaf1c0b 197 */
9ee4d121 198 (void) signal(SIGTTOU, SIG_IGN);
6632767b
SL
199 for (;;) {
200 int ibits = 0, obits = 0;
201
202 if (fcc)
203 obits |= (1<<p);
204 else
205 ibits |= (1<<f);
206 if (pcc >= 0)
207 if (pcc)
208 obits |= (1<<f);
82c973f2 209 else
6632767b
SL
210 ibits |= (1<<p);
211 if (select(16, &ibits, &obits, 0, 0) < 0) {
212 if (errno == EINTR)
a10a364d 213 continue;
6632767b
SL
214 fatalperror(f, "select", errno);
215 }
216 if (ibits == 0 && obits == 0) {
217 /* shouldn't happen... */
218 sleep(5);
219 continue;
220 }
221 if (ibits & (1<<f)) {
222 fcc = read(f, fibuf, sizeof (fibuf));
223 if (fcc < 0 && errno == EWOULDBLOCK)
224 fcc = 0;
225 else {
226 register char *cp;
227 int left, n;
228
229 if (fcc <= 0)
1227078b 230 break;
6632767b
SL
231 fbp = fibuf;
232 top:
233 for (cp = fibuf; cp < fibuf+fcc; cp++)
234 if (cp[0] == magic[0] &&
235 cp[1] == magic[1]) {
236 left = fcc - (cp-fibuf);
237 n = control(p, cp, left);
238 if (n) {
239 left -= n;
240 if (left > 0)
241 bcopy(cp, cp+n, left);
242 fcc -= n;
243 goto top; /* n^2 */
244 }
a10a364d 245 }
a10a364d 246 }
6632767b
SL
247 }
248 if (ibits & (1<<p)) {
249 pcc = read(p, pibuf, sizeof (pibuf));
250 pbp = pibuf;
251 if (pcc < 0 && errno == EWOULDBLOCK)
252 pcc = 0;
253 else if (pcc <= 0)
254 break;
255 else if (pibuf[0] == 0)
256 pbp++, pcc--;
257 else {
258#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
259 if (pkcontrol(pibuf[0])) {
260 /* The following 3 lines do nothing. */
261 int nstop = pibuf[0] &
262 (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP);
263
264 if (nstop)
265 stop = nstop;
266 pibuf[0] |= nstop;
267 send(f, &pibuf[0], 1, MSG_OOB);
a10a364d 268 }
6632767b 269 pcc = 0;
a10a364d 270 }
6632767b
SL
271 }
272 if ((obits & (1<<f)) && pcc > 0) {
273 cc = write(f, pbp, pcc);
274 if (cc < 0 && errno == EWOULDBLOCK) {
275 /* also shouldn't happen */
276 sleep(5);
277 continue;
278 }
279 if (cc > 0) {
280 pcc -= cc;
281 pbp += cc;
282 }
283 }
284 if ((obits & (1<<p)) && fcc > 0) {
285 cc = write(p, fbp, fcc);
286 if (cc > 0) {
287 fcc -= cc;
288 fbp += cc;
a10a364d
BJ
289 }
290 }
a10a364d 291 }
a10a364d
BJ
292}
293
294cleanup()
295{
a10a364d
BJ
296
297 rmut();
dd83e8ac 298 vhangup(); /* XXX */
ff24c640 299 shutdown(netf, 2);
a10a364d
BJ
300 kill(0, SIGKILL);
301 exit(1);
302}
303
82c973f2
SL
304fatal(f, msg)
305 int f;
306 char *msg;
307{
308 char buf[BUFSIZ];
309
310 buf[0] = '\01'; /* error indicator */
560a8855 311 (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
82c973f2
SL
312 (void) write(f, buf, strlen(buf));
313 exit(1);
314}
315
316fatalperror(f, msg, errno)
317 int f;
318 char *msg;
319 int errno;
320{
321 char buf[BUFSIZ];
1227078b 322 extern int sys_nerr;
82c973f2
SL
323 extern char *sys_errlist[];
324
6632767b 325 if ((unsigned)errno < sys_nerr)
1227078b
MK
326 (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
327 else
328 (void) sprintf(buf, "%s: Error %d", msg, errno);
82c973f2
SL
329 fatal(f, buf);
330}
331
a10a364d
BJ
332#include <utmp.h>
333
334struct utmp wtmp;
335char wtmpf[] = "/usr/adm/wtmp";
0675fdb1 336char utmpf[] = "/etc/utmp";
a10a364d
BJ
337#define SCPYN(a, b) strncpy(a, b, sizeof(a))
338#define SCMPN(a, b) strncmp(a, b, sizeof(a))
339
340rmut()
341{
342 register f;
343 int found = 0;
0675fdb1
JB
344 struct utmp *u, *utmp;
345 int nutmp;
346 struct stat statbf;
a10a364d 347
0675fdb1 348 f = open(utmpf, O_RDWR);
a10a364d 349 if (f >= 0) {
0675fdb1
JB
350 fstat(f, &statbf);
351 utmp = (struct utmp *)malloc(statbf.st_size);
352 if (!utmp)
353 syslog(LOG_ERR, "utmp malloc failed");
354 if (statbf.st_size && utmp) {
355 nutmp = read(f, utmp, statbf.st_size);
356 nutmp /= sizeof(struct utmp);
357
358 for (u = utmp ; u < &utmp[nutmp] ; u++) {
359 if (SCMPN(u->ut_line, line+5) ||
360 u->ut_name[0]==0)
361 continue;
362 lseek(f, ((long)u)-((long)utmp), L_SET);
363 SCPYN(u->ut_name, "");
364 SCPYN(u->ut_host, "");
365 time(&u->ut_time);
366 write(f, (char *)u, sizeof(wtmp));
367 found++;
368 }
a10a364d
BJ
369 }
370 close(f);
371 }
372 if (found) {
0675fdb1 373 f = open(wtmpf, O_WRONLY|O_APPEND);
a10a364d
BJ
374 if (f >= 0) {
375 SCPYN(wtmp.ut_line, line+5);
376 SCPYN(wtmp.ut_name, "");
9b3ee53c 377 SCPYN(wtmp.ut_host, "");
a10a364d 378 time(&wtmp.ut_time);
a10a364d
BJ
379 write(f, (char *)&wtmp, sizeof(wtmp));
380 close(f);
381 }
382 }
383 chmod(line, 0666);
384 chown(line, 0, 0);
385 line[strlen("/dev/")] = 'p';
386 chmod(line, 0666);
387 chown(line, 0, 0);
388}