rlogind.c revision 1.32 1 /* $NetBSD: rlogind.c,v 1.32 2003/08/07 09:46:47 agc Exp $ */
2
3 /*
4 * Copyright (C) 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by WIDE Project and
18 * its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 /*-
37 * Copyright (c) 1983, 1988, 1989, 1993
38 * The Regents of the University of California. All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65 #include <sys/cdefs.h>
66 #ifndef lint
67 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
68 The Regents of the University of California. All rights reserved.\n");
69 #if 0
70 static char sccsid[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95";
71 #else
72 __RCSID("$NetBSD: rlogind.c,v 1.32 2003/08/07 09:46:47 agc Exp $");
73 #endif
74 #endif /* not lint */
75
76 /*
77 * remote login server:
78 * \0
79 * remuser\0
80 * locuser\0
81 * terminal_type/speed\0
82 * data
83 */
84
85 #include <sys/param.h>
86 #include <sys/stat.h>
87 #include <sys/ioctl.h>
88 #include <signal.h>
89 #include <termios.h>
90 #include <poll.h>
91
92 #include <sys/socket.h>
93 #include <netinet/in.h>
94 #include <netinet/in_systm.h>
95 #include <netinet/ip.h>
96 #include <arpa/inet.h>
97 #include <netdb.h>
98
99 #include <pwd.h>
100 #include <syslog.h>
101 #include <errno.h>
102 #include <stdio.h>
103 #include <unistd.h>
104 #include <stdlib.h>
105 #include <string.h>
106 #include <util.h>
107 #include "pathnames.h"
108
109 #ifndef TIOCPKT_WINDOW
110 #define TIOCPKT_WINDOW 0x80
111 #endif
112
113 #define OPTIONS "alnL"
114
115 char *env[2];
116 #define NMAX 30
117 char lusername[NMAX+1], rusername[NMAX+1];
118 static char term[64] = "TERM=";
119 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
120 int keepalive = 1;
121 int check_all = 0;
122 int log_success = 0;
123
124 struct passwd *pwd;
125
126 void doit __P((int, struct sockaddr *));
127 int control __P((int, char *, int));
128 void protocol __P((int, int));
129 void cleanup __P((int));
130 void fatal __P((int, char *, int));
131 int do_rlogin __P((struct sockaddr *, char *));
132 void getstr __P((char *, int, char *));
133 void setup_term __P((int));
134 #if 0
135 int do_krb_login __P((union sockunion *));
136 #endif
137 void usage __P((void));
138 int local_domain __P((char *));
139 char *topdomain __P((char *));
140 int main __P((int, char *[]));
141
142 extern int __check_rhosts_file;
143 extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c */
144 extern char **environ;
145
146 int
147 main(argc, argv)
148 int argc;
149 char *argv[];
150 {
151 struct sockaddr_storage from;
152 int ch, fromlen, on;
153
154 openlog("rlogind", LOG_PID, LOG_AUTH);
155
156 opterr = 0;
157 while ((ch = getopt(argc, argv, OPTIONS)) != -1)
158 switch (ch) {
159 case 'a':
160 check_all = 1;
161 break;
162 case 'l':
163 __check_rhosts_file = 0;
164 break;
165 case 'n':
166 keepalive = 0;
167 break;
168 case 'L':
169 log_success = 1;
170 break;
171 case '?':
172 default:
173 usage();
174 break;
175 }
176 argc -= optind;
177 argv += optind;
178
179 fromlen = sizeof (from); /* xxx */
180 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
181 syslog(LOG_ERR,"Can't get peer name of remote host: %m");
182 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
183 }
184 #ifdef INET6
185 if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
186 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) &&
187 sizeof(struct sockaddr_in) <= sizeof(from)) {
188 struct sockaddr_in sin;
189 struct sockaddr_in6 *sin6;
190 const int off = sizeof(struct sockaddr_in6) -
191 sizeof(struct sockaddr_in);
192
193 sin6 = (struct sockaddr_in6 *)&from;
194 memset(&sin, 0, sizeof(sin));
195 sin.sin_family = AF_INET;
196 sin.sin_len = sizeof(struct sockaddr_in);
197 memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off],
198 sizeof(sin.sin_addr));
199 memcpy(&from, &sin, sizeof(sin));
200 fromlen = sin.sin_len;
201 }
202 #else
203 if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
204 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) {
205 char hbuf[NI_MAXHOST];
206 if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf,
207 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
208 strlcpy(hbuf, "invalid", sizeof(hbuf));
209 }
210 syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)\n",
211 hbuf);
212 exit(1);
213 }
214 #endif
215 on = 1;
216 if (keepalive &&
217 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
218 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
219 #if defined(IP_TOS)
220 if (((struct sockaddr *)&from)->sa_family == AF_INET) {
221 on = IPTOS_LOWDELAY;
222 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
223 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
224 }
225 #endif
226 doit(0, (struct sockaddr *)&from);
227 /* NOTREACHED */
228 #ifdef __GNUC__
229 exit(0);
230 #endif
231 }
232
233 int child;
234 int netf;
235 char line[MAXPATHLEN];
236 int confirmed;
237
238 struct winsize win = { 0, 0, 0, 0 };
239
240
241 void
242 doit(f, fromp)
243 int f;
244 struct sockaddr *fromp;
245 {
246 int master, pid, on = 1;
247 int authenticated = 0;
248 char *hostname;
249 char hostnamebuf[2 * MAXHOSTNAMELEN + 1];
250 char c;
251 char naddr[NI_MAXHOST];
252 char saddr[NI_MAXHOST];
253 char raddr[NI_MAXHOST];
254 int af = fromp->sa_family;
255 u_int16_t *portp;
256 struct addrinfo hints, *res, *res0;
257 int gaierror;
258 #ifdef NI_WITHSCOPEID
259 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
260 #else
261 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
262 #endif
263
264 alarm(60);
265 read(f, &c, 1);
266
267 if (c != 0)
268 exit(1);
269
270 alarm(0);
271 switch (af) {
272 case AF_INET:
273 portp = &((struct sockaddr_in *)fromp)->sin_port;
274 break;
275 #ifdef INET6
276 case AF_INET6:
277 portp = &((struct sockaddr_in6 *)fromp)->sin6_port;
278 break;
279 #endif
280 default:
281 syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af);
282 exit(1);
283 }
284 if (getnameinfo((struct sockaddr *)fromp, fromp->sa_len,
285 naddr, sizeof(naddr), NULL, 0, niflags) != 0) {
286 syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af);
287 exit(1);
288 }
289
290 if (getnameinfo((struct sockaddr *)fromp, fromp->sa_len,
291 saddr, sizeof(saddr), NULL, 0, NI_NAMEREQD) == 0) {
292 /*
293 * If name returned by gethostbyaddr is in our domain,
294 * attempt to verify that we haven't been fooled by someone
295 * in a remote net; look up the name and check that this
296 * address corresponds to the name.
297 */
298 hostname = saddr;
299 res0 = NULL;
300 if (check_all || local_domain(saddr)) {
301 strlcpy(hostnamebuf, saddr, sizeof(hostnamebuf));
302 memset(&hints, 0, sizeof(hints));
303 hints.ai_family = fromp->sa_family;
304 hints.ai_socktype = SOCK_STREAM;
305 hints.ai_flags = AI_CANONNAME;
306 gaierror = getaddrinfo(hostnamebuf, "0", &hints, &res0);
307 if (gaierror) {
308 syslog(LOG_NOTICE,
309 "Couldn't look up address for %s: %s",
310 hostnamebuf, gai_strerror(gaierror));
311 hostname = naddr;
312 } else {
313 for (res = res0; res; res = res->ai_next) {
314 if (res->ai_family != fromp->sa_family)
315 continue;
316 if (res->ai_addrlen != fromp->sa_len)
317 continue;
318 if (getnameinfo(res->ai_addr,
319 res->ai_addrlen,
320 raddr, sizeof(raddr), NULL, 0,
321 niflags) == 0
322 && strcmp(naddr, raddr) == 0) {
323 hostname = res->ai_canonname
324 ? res->ai_canonname
325 : saddr;
326 break;
327 }
328 }
329 if (res == NULL) {
330 syslog(LOG_NOTICE,
331 "Host addr %s not listed for host %s",
332 naddr, res0->ai_canonname
333 ? res0->ai_canonname
334 : saddr);
335 hostname = naddr;
336 }
337 }
338 }
339 strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf));
340 hostname = hostnamebuf;
341 if (res0)
342 freeaddrinfo(res0);
343 } else {
344 strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf));
345 hostname = hostnamebuf;
346 }
347
348 if (ntohs(*portp) >= IPPORT_RESERVED ||
349 ntohs(*portp) < IPPORT_RESERVED/2) {
350 syslog(LOG_NOTICE, "Connection from %s on illegal port",
351 naddr);
352 fatal(f, "Permission denied", 0);
353 }
354 #ifdef IP_OPTIONS
355 if (fromp->sa_family == AF_INET) {
356 u_char optbuf[BUFSIZ/3], *cp;
357 char lbuf[BUFSIZ], *lp, *ep;
358 int optsize = sizeof(optbuf), ipproto;
359 struct protoent *ip;
360
361 if ((ip = getprotobyname("ip")) != NULL)
362 ipproto = ip->p_proto;
363 else
364 ipproto = IPPROTO_IP;
365 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
366 &optsize) == 0 && optsize != 0) {
367 lp = lbuf;
368 ep = lbuf + sizeof(lbuf);
369 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
370 snprintf(lp, ep - lp, " %2.2x", *cp);
371 syslog(LOG_NOTICE,
372 "Connection received using IP options (ignored):%s",
373 lbuf);
374 if (setsockopt(0, ipproto, IP_OPTIONS,
375 (char *)NULL, optsize) != 0) {
376 syslog(LOG_ERR,
377 "setsockopt IP_OPTIONS NULL: %m");
378 exit(1);
379 }
380 }
381 }
382 #endif
383 if (do_rlogin(fromp, hostname) == 0)
384 authenticated++;
385 if (confirmed == 0) {
386 write(f, "", 1);
387 confirmed = 1; /* we sent the null! */
388 }
389 netf = f;
390
391 pid = forkpty(&master, line, NULL, &win);
392 if (pid < 0) {
393 if (errno == ENOENT)
394 fatal(f, "Out of ptys", 0);
395 else
396 fatal(f, "Forkpty", 1);
397 }
398 if (pid == 0) {
399 if (f > 2) /* f should always be 0, but... */
400 (void) close(f);
401 setup_term(0);
402 if (authenticated)
403 execl(_PATH_LOGIN, "login", "-p",
404 "-h", hostname, "-f", "--", lusername, (char *)0);
405 else
406 execl(_PATH_LOGIN, "login", "-p",
407 "-h", hostname, "--", lusername, (char *)0);
408 fatal(STDERR_FILENO, _PATH_LOGIN, 1);
409 /*NOTREACHED*/
410 }
411 ioctl(f, FIONBIO, &on);
412 ioctl(master, FIONBIO, &on);
413 ioctl(master, TIOCPKT, &on);
414 signal(SIGCHLD, cleanup);
415 protocol(f, master);
416 signal(SIGCHLD, SIG_IGN);
417 cleanup(0);
418 }
419
420 char magic[2] = { 0377, 0377 };
421 char oobdata[] = {TIOCPKT_WINDOW};
422
423 /*
424 * Handle a "control" request (signaled by magic being present)
425 * in the data stream. For now, we are only willing to handle
426 * window size changes.
427 */
428 int
429 control(pty, cp, n)
430 int pty;
431 char *cp;
432 int n;
433 {
434 struct winsize w;
435
436 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
437 return (0);
438 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
439 memmove(&w, cp+4, sizeof(w));
440 w.ws_row = ntohs(w.ws_row);
441 w.ws_col = ntohs(w.ws_col);
442 w.ws_xpixel = ntohs(w.ws_xpixel);
443 w.ws_ypixel = ntohs(w.ws_ypixel);
444 (void)ioctl(pty, TIOCSWINSZ, &w);
445 return (4+sizeof (w));
446 }
447
448 /*
449 * rlogin "protocol" machine.
450 */
451 void
452 protocol(f, p)
453 int f, p;
454 {
455 char pibuf[1024+1], fibuf[1024], *pbp = NULL, *fbp = NULL;
456 /* XXX gcc above */
457 int pcc = 0, fcc = 0;
458 int cc, n;
459 char cntl;
460 struct pollfd set[2];
461
462 /*
463 * Must ignore SIGTTOU, otherwise we'll stop
464 * when we try and set slave pty's window shape
465 * (our controlling tty is the master pty).
466 */
467 (void) signal(SIGTTOU, SIG_IGN);
468 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
469 set[0].fd = p;
470 set[1].fd = f;
471 for (;;) {
472 set[0].events = POLLPRI;
473 set[1].events = 0;
474 if (fcc)
475 set[0].events |= POLLOUT;
476 else
477 set[1].events |= POLLIN;
478 if (pcc >= 0) {
479 if (pcc)
480 set[1].events |= POLLOUT;
481 else
482 set[0].events |= POLLIN;
483 }
484 if ((n = poll(set, 2, INFTIM)) < 0) {
485 if (errno == EINTR)
486 continue;
487 fatal(f, "poll", 1);
488 }
489 if (n == 0) {
490 /* shouldn't happen... */
491 sleep(5);
492 continue;
493 }
494 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
495 if (set[0].revents & POLLPRI) {
496 cc = read(p, &cntl, 1);
497 if (cc == 1 && pkcontrol(cntl)) {
498 cntl |= oobdata[0];
499 send(f, &cntl, 1, MSG_OOB);
500 if (cntl & TIOCPKT_FLUSHWRITE)
501 pcc = 0;
502 }
503 }
504 if (set[1].revents & POLLIN) {
505 fcc = read(f, fibuf, sizeof(fibuf));
506 if (fcc < 0 && errno == EWOULDBLOCK)
507 fcc = 0;
508 else {
509 char *cp;
510 int left, n;
511
512 if (fcc <= 0)
513 break;
514 fbp = fibuf;
515
516 top:
517 for (cp = fibuf; cp < fibuf+fcc-1; cp++)
518 if (cp[0] == magic[0] &&
519 cp[1] == magic[1]) {
520 left = fcc - (cp-fibuf);
521 n = control(p, cp, left);
522 if (n) {
523 left -= n;
524 if (left > 0)
525 memmove(cp,
526 cp+n,
527 left);
528 fcc -= n;
529 goto top; /* n^2 */
530 }
531 }
532 }
533 }
534
535 if (set[0].revents & POLLOUT && fcc > 0) {
536 cc = write(p, fbp, fcc);
537 if (cc > 0) {
538 fcc -= cc;
539 fbp += cc;
540 }
541 }
542
543 if (set[0].revents & POLLIN) {
544 pcc = read(p, pibuf, sizeof (pibuf));
545 pbp = pibuf;
546 if (pcc < 0 && errno == EWOULDBLOCK)
547 pcc = 0;
548 else if (pcc <= 0)
549 break;
550 else if (pibuf[0] == 0) {
551 pbp++, pcc--;
552 } else {
553 if (pkcontrol(pibuf[0])) {
554 pibuf[0] |= oobdata[0];
555 send(f, &pibuf[0], 1, MSG_OOB);
556 }
557 pcc = 0;
558 }
559 }
560 if (set[1].revents & POLLOUT && pcc > 0) {
561 cc = write(f, pbp, pcc);
562 if (cc > 0) {
563 pcc -= cc;
564 pbp += cc;
565 }
566 }
567 }
568 }
569
570 void
571 cleanup(signo)
572 int signo;
573 {
574 char *p, c;
575
576 p = line + sizeof(_PATH_DEV) - 1;
577 #ifdef SUPPORT_UTMP
578 if (logout(p))
579 logwtmp(p, "", "");
580 #endif
581 #ifdef SUPPORT_UTMPX
582 if (logoutx(p, 0, DEAD_PROCESS))
583 logwtmpx(p, "", "", 0, DEAD_PROCESS);
584 #endif
585 (void)chmod(line, 0666);
586 (void)chown(line, 0, 0);
587 c = *p; *p = 'p';
588 (void)chmod(line, 0666);
589 (void)chown(line, 0, 0);
590 *p = c;
591 if (ttyaction(line, "rlogind", "root"))
592 syslog(LOG_ERR, "%s: ttyaction failed", line);
593 shutdown(netf, 2);
594 exit(1);
595 }
596
597 void
598 fatal(f, msg, syserr)
599 int f;
600 char *msg;
601 int syserr;
602 {
603 int len;
604 char buf[BUFSIZ], *bp, *ep;
605
606 bp = buf;
607 ep = buf + sizeof(buf);
608
609 /*
610 * Prepend binary one to message if we haven't sent
611 * the magic null as confirmation.
612 */
613 if (!confirmed)
614 *bp++ = '\001'; /* error indicator */
615 if (syserr)
616 len = snprintf(bp, ep - bp, "rlogind: %s: %s.\r\n",
617 msg, strerror(errno));
618 else
619 len = snprintf(bp, ep - bp, "rlogind: %s.\r\n", msg);
620 (void) write(f, buf, bp + len - buf);
621 exit(1);
622 }
623
624 int
625 do_rlogin(dest, host)
626 struct sockaddr *dest;
627 char *host;
628 {
629 int retval;
630
631 getstr(rusername, sizeof(rusername), "remuser too long");
632 getstr(lusername, sizeof(lusername), "locuser too long");
633 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
634
635 pwd = getpwnam(lusername);
636 if (pwd == NULL) {
637 syslog(LOG_INFO,
638 "%s@%s as %s: unknown login.", rusername, host, lusername);
639 return (-1);
640 }
641
642 retval = iruserok_sa(dest, dest->sa_len, pwd->pw_uid == 0, rusername,
643 lusername);
644 /* XXX put inet_ntoa(dest->sin_addr.s_addr) into all messages below */
645 if (retval == 0) {
646 if (log_success)
647 syslog(LOG_INFO, "%s@%s as %s: iruserok succeeded",
648 rusername, host, lusername);
649 } else {
650 if (__rcmd_errstr)
651 syslog(LOG_INFO, "%s@%s as %s: iruserok failed (%s)",
652 rusername, host, lusername, __rcmd_errstr);
653 else
654 syslog(LOG_INFO, "%s@%s as %s: iruserok failed",
655 rusername, host, lusername);
656 }
657 return(retval);
658 }
659
660 void
661 getstr(buf, cnt, errmsg)
662 char *buf;
663 int cnt;
664 char *errmsg;
665 {
666 char c;
667
668 do {
669 if (read(0, &c, 1) != 1)
670 exit(1);
671 if (--cnt < 0)
672 fatal(STDOUT_FILENO, errmsg, 0);
673 *buf++ = c;
674 } while (c != 0);
675 }
676
677
678 void
679 setup_term(fd)
680 int fd;
681 {
682 char *cp = index(term+ENVSIZE, '/');
683 char *speed;
684 struct termios tt;
685
686 #ifndef notyet
687 tcgetattr(fd, &tt);
688 if (cp) {
689 *cp++ = '\0';
690 speed = cp;
691 cp = index(speed, '/');
692 if (cp)
693 *cp++ = '\0';
694 cfsetspeed(&tt, atoi(speed));
695 }
696
697 tt.c_iflag = TTYDEF_IFLAG;
698 tt.c_oflag = TTYDEF_OFLAG;
699 tt.c_lflag = TTYDEF_LFLAG;
700 tcsetattr(fd, TCSAFLUSH, &tt);
701 #else
702 if (cp) {
703 *cp++ = '\0';
704 speed = cp;
705 cp = index(speed, '/');
706 if (cp)
707 *cp++ = '\0';
708 tcgetattr(fd, &tt);
709 cfsetspeed(&tt, atoi(speed));
710 tcsetattr(fd, TCSAFLUSH, &tt);
711 }
712 #endif
713
714 env[0] = term;
715 env[1] = 0;
716 environ = env;
717 }
718
719
720 void
721 usage()
722 {
723 syslog(LOG_ERR, "usage: rlogind [-alnL]");
724 }
725
726 /*
727 * Check whether host h is in our local domain,
728 * defined as sharing the last two components of the domain part,
729 * or the entire domain part if the local domain has only one component.
730 * If either name is unqualified (contains no '.'),
731 * assume that the host is local, as it will be
732 * interpreted as such.
733 */
734 int
735 local_domain(h)
736 char *h;
737 {
738 char localhost[MAXHOSTNAMELEN + 1];
739 char *p1, *p2;
740
741 localhost[0] = 0;
742 (void) gethostname(localhost, sizeof(localhost));
743 localhost[sizeof(localhost) - 1] = '\0';
744 p1 = topdomain(localhost);
745 p2 = topdomain(h);
746 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
747 return (1);
748 return (0);
749 }
750
751 char *
752 topdomain(h)
753 char *h;
754 {
755 char *p;
756 char *maybe = NULL;
757 int dots = 0;
758
759 for (p = h + strlen(h); p >= h; p--) {
760 if (*p == '.') {
761 if (++dots == 2)
762 return (p);
763 maybe = p;
764 }
765 }
766 return (maybe);
767 }
768