]>
git.saurik.com Git - apple/network_cmds.git/blob - rlogind.tproj/rlogind.c
a75acdb3182e06dd21b9246f6fc3fc8aa1997a33
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1983, 1988, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 static char copyright
[] =
58 "@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
59 The Regents of the University of California. All rights reserved.\n";
63 static char sccsid
[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95";
67 * remote login server:
71 * terminal_type/speed\0
75 #define FD_SETSIZE 16 /* don't need many bits for select */
76 #include <sys/param.h>
78 #include <sys/ioctl.h>
81 #include <sys/termios.h>
86 #include <sys/socket.h>
87 #include <netinet/in.h>
88 #include <netinet/in_systm.h>
89 #include <netinet/ip.h>
90 #include <arpa/inet.h>
100 #include "pathnames.h"
102 #ifndef TIOCPKT_WINDOW
103 #define TIOCPKT_WINDOW 0x80
107 #include <kerberosIV/des.h>
108 #include <kerberosIV/krb.h>
109 #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
113 u_char auth_buf
[sizeof(AUTH_DAT
)];
114 u_char tick_buf
[sizeof(KTEXT_ST
)];
115 Key_schedule schedule
;
116 int doencrypt
, retval
, use_kerberos
, vacuous
;
118 #define ARGSTR "alnkvx"
121 #endif /* KERBEROS */
125 char lusername
[NMAX
+1], rusername
[NMAX
+1];
126 static char term
[64] = "TERM=";
127 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
133 void doit
__P((int, struct sockaddr_in
*));
134 int control
__P((int, char *, int));
135 void protocol
__P((int, int));
136 void cleanup
__P((int));
137 void fatal
__P((int, char *, int));
138 int do_rlogin
__P((struct sockaddr_in
*));
139 void getstr
__P((char *, int, char *));
140 void setup_term
__P((int));
141 int do_krb_login
__P((struct sockaddr_in
*));
142 void usage
__P((void));
143 int local_domain
__P((char *));
144 char *topdomain
__P((char *));
151 extern int __check_rhosts_file
;
152 struct sockaddr_in from
;
155 openlog("rlogind", LOG_PID
| LOG_CONS
, LOG_AUTH
);
158 while ((ch
= getopt(argc
, argv
, ARGSTR
)) != EOF
)
164 __check_rhosts_file
= 0;
191 if (use_kerberos
&& vacuous
) {
193 fatal(STDERR_FILENO
, "only one of -k and -v allowed", 0);
196 fromlen
= sizeof (from
);
197 if (getpeername(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
198 syslog(LOG_ERR
,"Can't get peer name of remote host: %m");
199 fatal(STDERR_FILENO
, "Can't get peer name of remote host", 1);
203 setsockopt(0, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof (on
)) < 0)
204 syslog(LOG_WARNING
, "setsockopt (SO_KEEPALIVE): %m");
206 if (setsockopt(0, IPPROTO_IP
, IP_TOS
, (char *)&on
, sizeof(int)) < 0)
207 syslog(LOG_WARNING
, "setsockopt (IP_TOS): %m");
213 char line
[MAXPATHLEN
];
216 struct winsize win
= { 0, 0, 0, 0 };
222 struct sockaddr_in
*fromp
;
224 int master
, pid
, on
= 1;
225 int authenticated
= 0;
226 register struct hostent
*hp
;
227 char hostname
[2 * MAXHOSTNAMELEN
+ 1];
237 fatal(f
, "Remote host requires Kerberos authentication", 0);
241 fromp
->sin_port
= ntohs((u_short
)fromp
->sin_port
);
242 hp
= gethostbyaddr((char *)&fromp
->sin_addr
, sizeof(struct in_addr
),
245 (void)strcpy(hostname
, hp
->h_name
);
247 (void)strcpy(hostname
, inet_ntoa(fromp
->sin_addr
));
251 retval
= do_krb_login(fromp
);
255 fatal(f
, krb_err_txt
[retval
], 0);
257 confirmed
= 1; /* we sent the null! */
261 if (fromp
->sin_family
!= AF_INET
||
262 fromp
->sin_port
>= IPPORT_RESERVED
||
263 fromp
->sin_port
< IPPORT_RESERVED
/2) {
264 syslog(LOG_NOTICE
, "Connection from %s on illegal port",
265 inet_ntoa(fromp
->sin_addr
));
266 fatal(f
, "Permission denied", 0);
270 u_char optbuf
[BUFSIZ
/3], *cp
;
271 char lbuf
[BUFSIZ
], *lp
;
272 int optsize
= sizeof(optbuf
), ipproto
;
275 if ((ip
= getprotobyname("ip")) != NULL
)
276 ipproto
= ip
->p_proto
;
278 ipproto
= IPPROTO_IP
;
279 if (getsockopt(0, ipproto
, IP_OPTIONS
, (char *)optbuf
,
280 &optsize
) == 0 && optsize
!= 0) {
282 for (cp
= optbuf
; optsize
> 0; cp
++, optsize
--, lp
+= 3)
283 sprintf(lp
, " %2.2x", *cp
);
285 "Connection received using IP options (ignored):%s",
287 if (setsockopt(0, ipproto
, IP_OPTIONS
,
288 (char *)NULL
, optsize
) != 0) {
290 "setsockopt IP_OPTIONS NULL: %m");
296 if (do_rlogin(fromp
) == 0)
299 if (confirmed
== 0) {
301 confirmed
= 1; /* we sent the null! */
306 (void) des_write(f
, SECURE_MESSAGE
, sizeof(SECURE_MESSAGE
) - 1);
311 pid
= forkpty(&master
, line
, NULL
, &win
);
314 fatal(f
, "Out of ptys", 0);
316 fatal(f
, "Forkpty", 1);
319 if (f
> 2) /* f should always be 0, but... */
324 if (use_kerberos
&& (pwd
->pw_uid
== 0))
325 syslog(LOG_INFO
|LOG_AUTH
,
326 "ROOT Kerberos login from %s.%s@%s on %s\n",
327 kdata
->pname
, kdata
->pinst
, kdata
->prealm
,
331 execle(_PATH_LOGIN
, "login", "-p",
332 "-h", hostname
, "-f", "--", lusername
, NULL
, env
);
334 execle(_PATH_LOGIN
, "login", "-p",
335 "-h", hostname
, "--", lusername
, NULL
, env
);
336 fatal(STDERR_FILENO
, _PATH_LOGIN
, 1);
342 * If encrypted, don't turn on NBIO or the des read/write
343 * routines will croak.
349 ioctl(f
, FIONBIO
, &on
);
350 ioctl(master
, FIONBIO
, &on
);
351 ioctl(master
, TIOCPKT
, &on
);
352 signal(SIGCHLD
, cleanup
);
354 signal(SIGCHLD
, SIG_IGN
);
358 char magic
[2] = { 0377, 0377 };
359 char oobdata
[] = {TIOCPKT_WINDOW
};
362 * Handle a "control" request (signaled by magic being present)
363 * in the data stream. For now, we are only willing to handle
364 * window size changes.
374 if (n
< 4+sizeof (w
) || cp
[2] != 's' || cp
[3] != 's')
376 oobdata
[0] &= ~TIOCPKT_WINDOW
; /* we know he heard */
377 memmove(&w
, cp
+4, sizeof(w
));
378 w
.ws_row
= ntohs(w
.ws_row
);
379 w
.ws_col
= ntohs(w
.ws_col
);
380 w
.ws_xpixel
= ntohs(w
.ws_xpixel
);
381 w
.ws_ypixel
= ntohs(w
.ws_ypixel
);
382 (void)ioctl(pty
, TIOCSWINSZ
, &w
);
383 return (4+sizeof (w
));
387 * rlogin "protocol" machine.
393 char pibuf
[1024+1], fibuf
[1024], *pbp
, *fbp
;
394 register pcc
= 0, fcc
= 0;
399 * Must ignore SIGTTOU, otherwise we'll stop
400 * when we try and set slave pty's window shape
401 * (our controlling tty is the master pty).
403 (void) signal(SIGTTOU
, SIG_IGN
);
404 send(f
, oobdata
, 1, MSG_OOB
); /* indicate new rlogin */
409 if (nfd
> FD_SETSIZE
) {
410 syslog(LOG_ERR
, "select mask too small, increase FD_SETSIZE");
411 fatal(f
, "internal error (select mask too small)", 0);
414 fd_set ibits
, obits
, ebits
, *omask
;
419 omask
= (fd_set
*)NULL
;
432 if ((n
= select(nfd
, &ibits
, omask
, &ebits
, 0)) < 0) {
435 fatal(f
, "select", 1);
438 /* shouldn't happen... */
442 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
443 if (FD_ISSET(p
, &ebits
)) {
444 cc
= read(p
, &cntl
, 1);
445 if (cc
== 1 && pkcontrol(cntl
)) {
447 send(f
, &cntl
, 1, MSG_OOB
);
448 if (cntl
& TIOCPKT_FLUSHWRITE
) {
454 if (FD_ISSET(f
, &ibits
)) {
458 fcc
= des_read(f
, fibuf
, sizeof(fibuf
));
462 fcc
= read(f
, fibuf
, sizeof(fibuf
));
463 if (fcc
< 0 && errno
== EWOULDBLOCK
)
474 for (cp
= fibuf
; cp
< fibuf
+fcc
-1; cp
++)
475 if (cp
[0] == magic
[0] &&
477 left
= fcc
- (cp
-fibuf
);
478 n
= control(p
, cp
, left
);
482 bcopy(cp
+n
, cp
, left
);
487 FD_SET(p
, &obits
); /* try write */
491 if (FD_ISSET(p
, &obits
) && fcc
> 0) {
492 cc
= write(p
, fbp
, fcc
);
499 if (FD_ISSET(p
, &ibits
)) {
500 pcc
= read(p
, pibuf
, sizeof (pibuf
));
502 if (pcc
< 0 && errno
== EWOULDBLOCK
)
506 else if (pibuf
[0] == 0) {
513 FD_SET(f
, &obits
); /* try write */
515 if (pkcontrol(pibuf
[0])) {
516 pibuf
[0] |= oobdata
[0];
517 send(f
, &pibuf
[0], 1, MSG_OOB
);
522 if ((FD_ISSET(f
, &obits
)) && pcc
> 0) {
526 cc
= des_write(f
, pbp
, pcc
);
530 cc
= write(f
, pbp
, pcc
);
531 if (cc
< 0 && errno
== EWOULDBLOCK
) {
533 * This happens when we try write after read
534 * from p, but some old kernels balk at large
535 * writes even when select returns true.
537 if (!FD_ISSET(p
, &ibits
))
555 p
= line
+ sizeof(_PATH_DEV
) - 1;
558 (void)chmod(line
, 0666);
559 (void)chown(line
, 0, 0);
561 (void)chmod(line
, 0666);
562 (void)chown(line
, 0, 0);
568 fatal(f
, msg
, syserr
)
574 char buf
[BUFSIZ
], *bp
= buf
;
577 * Prepend binary one to message if we haven't sent
578 * the magic null as confirmation.
581 *bp
++ = '\01'; /* error indicator */
583 len
= sprintf(bp
, "rlogind: %s: %s.\r\n",
584 msg
, strerror(errno
));
586 len
= sprintf(bp
, "rlogind: %s.\r\n", msg
);
587 (void) write(f
, buf
, bp
+ len
- buf
);
593 struct sockaddr_in
*dest
;
595 getstr(rusername
, sizeof(rusername
), "remuser too long");
596 getstr(lusername
, sizeof(lusername
), "locuser too long");
597 getstr(term
+ENVSIZE
, sizeof(term
)-ENVSIZE
, "Terminal type too long");
599 pwd
= getpwnam(lusername
);
602 "rlogin denied for user %s: getpwnam() failed\n",
606 if (pwd
->pw_uid
== 0 && strcmp("root", lusername
))
609 "rlogin denied for non-root user %s with uid 0\n",
613 return (iruserok(dest
->sin_addr
.s_addr
, 0, rusername
, lusername
));
617 getstr(buf
, cnt
, errmsg
)
625 if (read(0, &c
, 1) != 1)
628 fatal(STDOUT_FILENO
, errmsg
, 0);
637 register char *cp
= index(term
+ENVSIZE
, '/');
646 cp
= index(speed
, '/');
649 cfsetspeed(&tt
, atoi(speed
));
652 tt
.c_iflag
= TTYDEF_IFLAG
;
653 tt
.c_oflag
= TTYDEF_OFLAG
;
654 tt
.c_lflag
= TTYDEF_LFLAG
;
655 tcsetattr(fd
, TCSAFLUSH
, &tt
);
660 cp
= index(speed
, '/');
664 cfsetspeed(&tt
, atoi(speed
));
665 tcsetattr(fd
, TCSAFLUSH
, &tt
);
674 #define VERSION_SIZE 9
677 * Do the remote kerberos login to the named host with the
680 * Return 0 on valid authorization
681 * Return -1 on valid authentication, no authorization
682 * Return >0 for error conditions
686 struct sockaddr_in
*dest
;
689 char instance
[INST_SZ
], version
[VERSION_SIZE
];
690 long authopts
= 0L; /* !mutual */
691 struct sockaddr_in faddr
;
693 kdata
= (AUTH_DAT
*) auth_buf
;
694 ticket
= (KTEXT
) tick_buf
;
702 if (getsockname(0, (struct sockaddr
*)&faddr
, &rc
))
704 authopts
= KOPT_DO_MUTUAL
;
708 instance
, dest
, &faddr
,
709 kdata
, "", schedule
, version
);
710 des_set_key(kdata
->session
, schedule
);
717 instance
, dest
, (struct sockaddr_in
*) 0,
718 kdata
, "", (bit_64
*) 0, version
);
723 getstr(lusername
, sizeof(lusername
), "locuser");
724 /* get the "cmd" in the rcmd protocol */
725 getstr(term
+ENVSIZE
, sizeof(term
)-ENVSIZE
, "Terminal type");
727 pwd
= getpwnam(lusername
);
731 /* returns nonzero for no access */
732 if (kuserok(kdata
, lusername
) != 0)
738 #endif /* KERBEROS */
744 syslog(LOG_ERR
, "usage: rlogind [-aln] [-k | -v]");
746 syslog(LOG_ERR
, "usage: rlogind [-aln]");
751 * Check whether host h is in our local domain,
752 * defined as sharing the last two components of the domain part,
753 * or the entire domain part if the local domain has only one component.
754 * If either name is unqualified (contains no '.'),
755 * assume that the host is local, as it will be
756 * interpreted as such.
762 char localhost
[MAXHOSTNAMELEN
];
766 (void) gethostname(localhost
, sizeof(localhost
));
767 p1
= topdomain(localhost
);
769 if (p1
== NULL
|| p2
== NULL
|| !strcasecmp(p1
, p2
))
782 for (p
= h
+ strlen(h
); p
>= h
; p
--) {