]>
git.saurik.com Git - apple/network_cmds.git/blob - rlogind.tproj/rlogind.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1983, 1988, 1989, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char copyright
[] =
59 "@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
60 The Regents of the University of California. All rights reserved.\n";
64 static char sccsid
[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95";
68 * remote login server:
72 * terminal_type/speed\0
76 #define FD_SETSIZE 16 /* don't need many bits for select */
77 #include <sys/param.h>
79 #include <sys/ioctl.h>
82 #include <sys/termios.h>
87 #include <sys/socket.h>
88 #include <netinet/in.h>
89 #include <netinet/in_systm.h>
90 #include <netinet/ip.h>
91 #include <arpa/inet.h>
101 #include "pathnames.h"
103 #ifndef TIOCPKT_WINDOW
104 #define TIOCPKT_WINDOW 0x80
108 #include <kerberosIV/des.h>
109 #include <kerberosIV/krb.h>
110 #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
114 u_char auth_buf
[sizeof(AUTH_DAT
)];
115 u_char tick_buf
[sizeof(KTEXT_ST
)];
116 Key_schedule schedule
;
117 int doencrypt
, retval
, use_kerberos
, vacuous
;
119 #define ARGSTR "alnkvx"
122 #endif /* KERBEROS */
126 char lusername
[NMAX
+1], rusername
[NMAX
+1];
127 static char term
[64] = "TERM=";
128 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
134 void doit
__P((int, struct sockaddr_in
*));
135 int control
__P((int, char *, int));
136 void protocol
__P((int, int));
137 void cleanup
__P((int));
138 void fatal
__P((int, char *, int));
139 int do_rlogin
__P((struct sockaddr_in
*));
140 void getstr
__P((char *, int, char *));
141 void setup_term
__P((int));
142 int do_krb_login
__P((struct sockaddr_in
*));
143 void usage
__P((void));
144 int local_domain
__P((char *));
145 char *topdomain
__P((char *));
152 extern int __check_rhosts_file
;
153 struct sockaddr_in from
;
156 openlog("rlogind", LOG_PID
| LOG_CONS
, LOG_AUTH
);
159 while ((ch
= getopt(argc
, argv
, ARGSTR
)) != EOF
)
165 __check_rhosts_file
= 0;
192 if (use_kerberos
&& vacuous
) {
194 fatal(STDERR_FILENO
, "only one of -k and -v allowed", 0);
197 fromlen
= sizeof (from
);
198 if (getpeername(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
199 syslog(LOG_ERR
,"Can't get peer name of remote host: %m");
200 fatal(STDERR_FILENO
, "Can't get peer name of remote host", 1);
204 setsockopt(0, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof (on
)) < 0)
205 syslog(LOG_WARNING
, "setsockopt (SO_KEEPALIVE): %m");
207 if (setsockopt(0, IPPROTO_IP
, IP_TOS
, (char *)&on
, sizeof(int)) < 0)
208 syslog(LOG_WARNING
, "setsockopt (IP_TOS): %m");
214 char line
[MAXPATHLEN
];
217 struct winsize win
= { 0, 0, 0, 0 };
223 struct sockaddr_in
*fromp
;
225 int master
, pid
, on
= 1;
226 int authenticated
= 0;
227 register struct hostent
*hp
;
228 char hostname
[2 * MAXHOSTNAMELEN
+ 1];
238 fatal(f
, "Remote host requires Kerberos authentication", 0);
242 fromp
->sin_port
= ntohs((u_short
)fromp
->sin_port
);
243 hp
= gethostbyaddr((char *)&fromp
->sin_addr
, sizeof(struct in_addr
),
246 (void)strcpy(hostname
, hp
->h_name
);
248 (void)strcpy(hostname
, inet_ntoa(fromp
->sin_addr
));
252 retval
= do_krb_login(fromp
);
256 fatal(f
, krb_err_txt
[retval
], 0);
258 confirmed
= 1; /* we sent the null! */
262 if (fromp
->sin_family
!= AF_INET
||
263 fromp
->sin_port
>= IPPORT_RESERVED
||
264 fromp
->sin_port
< IPPORT_RESERVED
/2) {
265 syslog(LOG_NOTICE
, "Connection from %s on illegal port",
266 inet_ntoa(fromp
->sin_addr
));
267 fatal(f
, "Permission denied", 0);
271 u_char optbuf
[BUFSIZ
/3], *cp
;
272 char lbuf
[BUFSIZ
], *lp
;
273 int optsize
= sizeof(optbuf
), ipproto
;
276 if ((ip
= getprotobyname("ip")) != NULL
)
277 ipproto
= ip
->p_proto
;
279 ipproto
= IPPROTO_IP
;
280 if (getsockopt(0, ipproto
, IP_OPTIONS
, (char *)optbuf
,
281 &optsize
) == 0 && optsize
!= 0) {
283 for (cp
= optbuf
; optsize
> 0; cp
++, optsize
--, lp
+= 3)
284 sprintf(lp
, " %2.2x", *cp
);
286 "Connection received using IP options (ignored):%s",
288 if (setsockopt(0, ipproto
, IP_OPTIONS
,
289 (char *)NULL
, optsize
) != 0) {
291 "setsockopt IP_OPTIONS NULL: %m");
297 if (do_rlogin(fromp
) == 0)
300 if (confirmed
== 0) {
302 confirmed
= 1; /* we sent the null! */
307 (void) des_write(f
, SECURE_MESSAGE
, sizeof(SECURE_MESSAGE
) - 1);
312 pid
= forkpty(&master
, line
, NULL
, &win
);
315 fatal(f
, "Out of ptys", 0);
317 fatal(f
, "Forkpty", 1);
320 if (f
> 2) /* f should always be 0, but... */
325 if (use_kerberos
&& (pwd
->pw_uid
== 0))
326 syslog(LOG_INFO
|LOG_AUTH
,
327 "ROOT Kerberos login from %s.%s@%s on %s\n",
328 kdata
->pname
, kdata
->pinst
, kdata
->prealm
,
332 execle(_PATH_LOGIN
, "login", "-p",
333 "-h", hostname
, "-f", "--", lusername
, NULL
, env
);
335 execle(_PATH_LOGIN
, "login", "-p",
336 "-h", hostname
, "--", lusername
, NULL
, env
);
337 fatal(STDERR_FILENO
, _PATH_LOGIN
, 1);
343 * If encrypted, don't turn on NBIO or the des read/write
344 * routines will croak.
350 ioctl(f
, FIONBIO
, &on
);
351 ioctl(master
, FIONBIO
, &on
);
352 ioctl(master
, TIOCPKT
, &on
);
353 signal(SIGCHLD
, cleanup
);
355 signal(SIGCHLD
, SIG_IGN
);
359 char magic
[2] = { 0377, 0377 };
360 char oobdata
[] = {TIOCPKT_WINDOW
};
363 * Handle a "control" request (signaled by magic being present)
364 * in the data stream. For now, we are only willing to handle
365 * window size changes.
375 if (n
< 4+sizeof (w
) || cp
[2] != 's' || cp
[3] != 's')
377 oobdata
[0] &= ~TIOCPKT_WINDOW
; /* we know he heard */
378 memmove(&w
, cp
+4, sizeof(w
));
379 w
.ws_row
= ntohs(w
.ws_row
);
380 w
.ws_col
= ntohs(w
.ws_col
);
381 w
.ws_xpixel
= ntohs(w
.ws_xpixel
);
382 w
.ws_ypixel
= ntohs(w
.ws_ypixel
);
383 (void)ioctl(pty
, TIOCSWINSZ
, &w
);
384 return (4+sizeof (w
));
388 * rlogin "protocol" machine.
394 char pibuf
[1024+1], fibuf
[1024], *pbp
, *fbp
;
395 register pcc
= 0, fcc
= 0;
400 * Must ignore SIGTTOU, otherwise we'll stop
401 * when we try and set slave pty's window shape
402 * (our controlling tty is the master pty).
404 (void) signal(SIGTTOU
, SIG_IGN
);
405 send(f
, oobdata
, 1, MSG_OOB
); /* indicate new rlogin */
410 if (nfd
> FD_SETSIZE
) {
411 syslog(LOG_ERR
, "select mask too small, increase FD_SETSIZE");
412 fatal(f
, "internal error (select mask too small)", 0);
415 fd_set ibits
, obits
, ebits
, *omask
;
420 omask
= (fd_set
*)NULL
;
433 if ((n
= select(nfd
, &ibits
, omask
, &ebits
, 0)) < 0) {
436 fatal(f
, "select", 1);
439 /* shouldn't happen... */
443 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
444 if (FD_ISSET(p
, &ebits
)) {
445 cc
= read(p
, &cntl
, 1);
446 if (cc
== 1 && pkcontrol(cntl
)) {
448 send(f
, &cntl
, 1, MSG_OOB
);
449 if (cntl
& TIOCPKT_FLUSHWRITE
) {
455 if (FD_ISSET(f
, &ibits
)) {
459 fcc
= des_read(f
, fibuf
, sizeof(fibuf
));
463 fcc
= read(f
, fibuf
, sizeof(fibuf
));
464 if (fcc
< 0 && errno
== EWOULDBLOCK
)
475 for (cp
= fibuf
; cp
< fibuf
+fcc
-1; cp
++)
476 if (cp
[0] == magic
[0] &&
478 left
= fcc
- (cp
-fibuf
);
479 n
= control(p
, cp
, left
);
483 bcopy(cp
+n
, cp
, left
);
488 FD_SET(p
, &obits
); /* try write */
492 if (FD_ISSET(p
, &obits
) && fcc
> 0) {
493 cc
= write(p
, fbp
, fcc
);
500 if (FD_ISSET(p
, &ibits
)) {
501 pcc
= read(p
, pibuf
, sizeof (pibuf
));
503 if (pcc
< 0 && errno
== EWOULDBLOCK
)
507 else if (pibuf
[0] == 0) {
514 FD_SET(f
, &obits
); /* try write */
516 if (pkcontrol(pibuf
[0])) {
517 pibuf
[0] |= oobdata
[0];
518 send(f
, &pibuf
[0], 1, MSG_OOB
);
523 if ((FD_ISSET(f
, &obits
)) && pcc
> 0) {
527 cc
= des_write(f
, pbp
, pcc
);
531 cc
= write(f
, pbp
, pcc
);
532 if (cc
< 0 && errno
== EWOULDBLOCK
) {
534 * This happens when we try write after read
535 * from p, but some old kernels balk at large
536 * writes even when select returns true.
538 if (!FD_ISSET(p
, &ibits
))
556 p
= line
+ sizeof(_PATH_DEV
) - 1;
559 (void)chmod(line
, 0666);
560 (void)chown(line
, 0, 0);
562 (void)chmod(line
, 0666);
563 (void)chown(line
, 0, 0);
569 fatal(f
, msg
, syserr
)
575 char buf
[BUFSIZ
], *bp
= buf
;
578 * Prepend binary one to message if we haven't sent
579 * the magic null as confirmation.
582 *bp
++ = '\01'; /* error indicator */
584 len
= sprintf(bp
, "rlogind: %s: %s.\r\n",
585 msg
, strerror(errno
));
587 len
= sprintf(bp
, "rlogind: %s.\r\n", msg
);
588 (void) write(f
, buf
, bp
+ len
- buf
);
594 struct sockaddr_in
*dest
;
596 getstr(rusername
, sizeof(rusername
), "remuser too long");
597 getstr(lusername
, sizeof(lusername
), "locuser too long");
598 getstr(term
+ENVSIZE
, sizeof(term
)-ENVSIZE
, "Terminal type too long");
600 pwd
= getpwnam(lusername
);
603 if (pwd
->pw_uid
== 0)
605 /* XXX why don't we syslog() failure? */
606 return (iruserok(dest
->sin_addr
.s_addr
, 0, rusername
, lusername
));
610 getstr(buf
, cnt
, errmsg
)
618 if (read(0, &c
, 1) != 1)
621 fatal(STDOUT_FILENO
, errmsg
, 0);
630 register char *cp
= index(term
+ENVSIZE
, '/');
639 cp
= index(speed
, '/');
642 cfsetspeed(&tt
, atoi(speed
));
645 tt
.c_iflag
= TTYDEF_IFLAG
;
646 tt
.c_oflag
= TTYDEF_OFLAG
;
647 tt
.c_lflag
= TTYDEF_LFLAG
;
648 tcsetattr(fd
, TCSAFLUSH
, &tt
);
653 cp
= index(speed
, '/');
657 cfsetspeed(&tt
, atoi(speed
));
658 tcsetattr(fd
, TCSAFLUSH
, &tt
);
667 #define VERSION_SIZE 9
670 * Do the remote kerberos login to the named host with the
673 * Return 0 on valid authorization
674 * Return -1 on valid authentication, no authorization
675 * Return >0 for error conditions
679 struct sockaddr_in
*dest
;
682 char instance
[INST_SZ
], version
[VERSION_SIZE
];
683 long authopts
= 0L; /* !mutual */
684 struct sockaddr_in faddr
;
686 kdata
= (AUTH_DAT
*) auth_buf
;
687 ticket
= (KTEXT
) tick_buf
;
695 if (getsockname(0, (struct sockaddr
*)&faddr
, &rc
))
697 authopts
= KOPT_DO_MUTUAL
;
701 instance
, dest
, &faddr
,
702 kdata
, "", schedule
, version
);
703 des_set_key(kdata
->session
, schedule
);
710 instance
, dest
, (struct sockaddr_in
*) 0,
711 kdata
, "", (bit_64
*) 0, version
);
716 getstr(lusername
, sizeof(lusername
), "locuser");
717 /* get the "cmd" in the rcmd protocol */
718 getstr(term
+ENVSIZE
, sizeof(term
)-ENVSIZE
, "Terminal type");
720 pwd
= getpwnam(lusername
);
724 /* returns nonzero for no access */
725 if (kuserok(kdata
, lusername
) != 0)
731 #endif /* KERBEROS */
737 syslog(LOG_ERR
, "usage: rlogind [-aln] [-k | -v]");
739 syslog(LOG_ERR
, "usage: rlogind [-aln]");
744 * Check whether host h is in our local domain,
745 * defined as sharing the last two components of the domain part,
746 * or the entire domain part if the local domain has only one component.
747 * If either name is unqualified (contains no '.'),
748 * assume that the host is local, as it will be
749 * interpreted as such.
755 char localhost
[MAXHOSTNAMELEN
];
759 (void) gethostname(localhost
, sizeof(localhost
));
760 p1
= topdomain(localhost
);
762 if (p1
== NULL
|| p2
== NULL
|| !strcasecmp(p1
, p2
))
775 for (p
= h
+ strlen(h
); p
>= h
; p
--) {