]>
git.saurik.com Git - apple/network_cmds.git/blob - rshd.tproj/rshd.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) 1988, 1989, 1992, 1993, 1994
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) 1988, 1989, 1992, 1993, 1994\n\
60 The Regents of the University of California. All rights reserved.\n";
64 static char sccsid
[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
68 * remote shell server:
75 #include <sys/param.h>
76 #include <sys/ioctl.h>
78 #include <sys/socket.h>
80 #include <netinet/in.h>
81 #include <arpa/inet.h>
97 int log_success
; /* If TRUE, log all successful accesses */
100 void doit
__P((struct sockaddr_in
*));
101 void error
__P((const char *, ...));
102 void getstr
__P((char *, int, char *));
103 int local_domain
__P((char *));
104 char *topdomain
__P((char *));
105 void usage
__P((void));
108 #include <kerberosIV/des.h>
109 #include <kerberosIV/krb.h>
110 #define VERSION_SIZE 9
111 #define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n"
112 #define OPTIONS "alnkvxL"
113 char authbuf
[sizeof(AUTH_DAT
)];
114 char tickbuf
[sizeof(KTEXT_ST
)];
115 int doencrypt
, use_kerberos
, vacuous
;
116 Key_schedule schedule
;
118 #define OPTIONS "alnL"
126 extern int __check_rhosts_file
;
127 struct linger linger
;
128 int ch
, on
= 1, fromlen
;
129 struct sockaddr_in from
;
131 openlog("rshd", LOG_PID
| LOG_ODELAY
, LOG_DAEMON
);
134 while ((ch
= getopt(argc
, argv
, OPTIONS
)) != EOF
)
140 __check_rhosts_file
= 0;
173 if (use_kerberos
&& vacuous
) {
174 syslog(LOG_ERR
, "only one of -k and -v allowed");
178 if (doencrypt
&& !use_kerberos
) {
179 syslog(LOG_ERR
, "-k is required for -x");
185 fromlen
= sizeof (from
);
186 if (getpeername(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
187 syslog(LOG_ERR
, "getpeername: %m");
191 setsockopt(0, SOL_SOCKET
, SO_KEEPALIVE
, (char *)&on
,
193 syslog(LOG_WARNING
, "setsockopt (SO_KEEPALIVE): %m");
195 linger
.l_linger
= 60; /* XXX */
196 if (setsockopt(0, SOL_SOCKET
, SO_LINGER
, (char *)&linger
,
197 sizeof (linger
)) < 0)
198 syslog(LOG_WARNING
, "setsockopt (SO_LINGER): %m");
203 char username
[20] = "USER=";
204 char homedir
[64] = "HOME=";
205 char shell
[64] = "SHELL=";
206 char path
[100] = "PATH=";
208 {homedir
, shell
, path
, username
, 0};
216 struct sockaddr_in
*fromp
;
218 extern char *__rcmd_errstr
; /* syslog hook from libc/net/rcmd.c. */
222 fd_set ready
, readfrom
;
223 int cc
, nfd
, pv
[2], pid
, s
;
225 char *hostname
, *errorstr
, *errorhost
;
226 char *cp
, sig
, buf
[BUFSIZ
];
227 char cmdbuf
[NCARGS
+1], locuser
[16], remuser
[16];
228 char remotehost
[2 * MAXHOSTNAMELEN
+ 1];
231 AUTH_DAT
*kdata
= (AUTH_DAT
*) NULL
;
232 KTEXT ticket
= (KTEXT
) NULL
;
233 char instance
[INST_SZ
], version
[VERSION_SIZE
];
234 struct sockaddr_in fromaddr
;
238 fd_set wready
, writeto
;
243 (void) signal(SIGINT
, SIG_DFL
);
244 (void) signal(SIGQUIT
, SIG_DFL
);
245 (void) signal(SIGTERM
, SIG_DFL
);
247 { int t
= open(_PATH_TTY
, 2);
249 ioctl(t
, TIOCNOTTY
, (char *)0);
254 fromp
->sin_port
= ntohs((u_short
)fromp
->sin_port
);
255 if (fromp
->sin_family
!= AF_INET
) {
256 syslog(LOG_ERR
, "malformed \"from\" address (af %d)",
262 u_char optbuf
[BUFSIZ
/3], *cp
;
263 char lbuf
[BUFSIZ
], *lp
;
264 int optsize
= sizeof(optbuf
), ipproto
;
267 if ((ip
= getprotobyname("ip")) != NULL
)
268 ipproto
= ip
->p_proto
;
270 ipproto
= IPPROTO_IP
;
271 if (!getsockopt(0, ipproto
, IP_OPTIONS
, (char *)optbuf
, &optsize
) &&
274 for (cp
= optbuf
; optsize
> 0; cp
++, optsize
--, lp
+= 3)
275 sprintf(lp
, " %2.2x", *cp
);
277 "Connection received from %s using IP options (ignored):%s",
278 inet_ntoa(fromp
->sin_addr
), lbuf
);
279 if (setsockopt(0, ipproto
, IP_OPTIONS
,
280 (char *)NULL
, optsize
) != 0) {
281 syslog(LOG_ERR
, "setsockopt IP_OPTIONS NULL: %m");
291 if (fromp
->sin_port
>= IPPORT_RESERVED
||
292 fromp
->sin_port
< IPPORT_RESERVED
/2) {
293 syslog(LOG_NOTICE
|LOG_AUTH
,
294 "Connection from %s on illegal port %u",
295 inet_ntoa(fromp
->sin_addr
),
304 if ((cc
= read(STDIN_FILENO
, &c
, 1)) != 1) {
306 syslog(LOG_NOTICE
, "read: %m");
312 port
= port
* 10 + c
- '0';
317 int lport
= IPPORT_RESERVED
- 1;
318 s
= rresvport(&lport
);
320 syslog(LOG_ERR
, "can't get stderr port: %m");
326 if (port
>= IPPORT_RESERVED
) {
327 syslog(LOG_ERR
, "2nd port not reserved");
330 fromp
->sin_port
= htons(port
);
331 if (connect(s
, (struct sockaddr
*)fromp
, sizeof (*fromp
)) < 0) {
332 syslog(LOG_INFO
, "connect second port %d: %m", port
);
339 error("rshd: remote host requires Kerberos authentication\n");
345 /* from inetd, socket is already on 0, 1, 2 */
351 hp
= gethostbyaddr((char *)&fromp
->sin_addr
, sizeof (struct in_addr
),
355 * If name returned by gethostbyaddr is in our domain,
356 * attempt to verify that we haven't been fooled by someone
357 * in a remote net; look up the name and check that this
358 * address corresponds to the name.
360 hostname
= hp
->h_name
;
364 if (check_all
|| local_domain(hp
->h_name
)) {
365 strncpy(remotehost
, hp
->h_name
, sizeof(remotehost
) - 1);
366 remotehost
[sizeof(remotehost
) - 1] = 0;
367 errorhost
= remotehost
;
368 hp
= gethostbyname(remotehost
);
371 "Couldn't look up address for %s",
374 "Couldn't look up address for your host (%s)\n";
375 hostname
= inet_ntoa(fromp
->sin_addr
);
376 } else for (; ; hp
->h_addr_list
++) {
377 if (hp
->h_addr_list
[0] == NULL
) {
379 "Host addr %s not listed for host %s",
380 inet_ntoa(fromp
->sin_addr
),
383 "Host address mismatch for %s\n";
384 hostname
= inet_ntoa(fromp
->sin_addr
);
387 if (!bcmp(hp
->h_addr_list
[0],
388 (caddr_t
)&fromp
->sin_addr
,
389 sizeof(fromp
->sin_addr
))) {
390 hostname
= hp
->h_name
;
396 errorhost
= hostname
= inet_ntoa(fromp
->sin_addr
);
400 kdata
= (AUTH_DAT
*) authbuf
;
401 ticket
= (KTEXT
) tickbuf
;
403 strcpy(instance
, "*");
404 version
[VERSION_SIZE
- 1] = '\0';
407 struct sockaddr_in local_addr
;
408 rc
= sizeof(local_addr
);
409 if (getsockname(0, (struct sockaddr
*)&local_addr
,
411 syslog(LOG_ERR
, "getsockname: %m");
412 error("rshd: getsockname: %m");
415 authopts
= KOPT_DO_MUTUAL
;
416 rc
= krb_recvauth(authopts
, 0, ticket
,
417 "rcmd", instance
, &fromaddr
,
418 &local_addr
, kdata
, "", schedule
,
420 des_set_key(kdata
->session
, schedule
);
423 rc
= krb_recvauth(authopts
, 0, ticket
, "rcmd",
425 (struct sockaddr_in
*) 0,
426 kdata
, "", (bit_64
*) 0, version
);
427 if (rc
!= KSUCCESS
) {
428 error("Kerberos authentication failure: %s\n",
434 getstr(remuser
, sizeof(remuser
), "remuser");
436 getstr(locuser
, sizeof(locuser
), "locuser");
437 getstr(cmdbuf
, sizeof(cmdbuf
), "command");
439 pwd
= getpwnam(locuser
);
441 syslog(LOG_INFO
|LOG_AUTH
,
442 "%s@%s as %s: unknown login. cmd='%.80s'",
443 remuser
, hostname
, locuser
, cmdbuf
);
444 if (errorstr
== NULL
)
445 errorstr
= "Login incorrect.\n";
448 if (chdir(pwd
->pw_dir
) < 0) {
451 syslog(LOG_INFO
|LOG_AUTH
,
452 "%s@%s as %s: no home directory. cmd='%.80s'",
453 remuser
, hostname
, locuser
, cmdbuf
);
454 error("No remote directory.\n");
461 if (pwd
->pw_passwd
!= 0 && *pwd
->pw_passwd
!= '\0') {
462 if (kuserok(kdata
, locuser
) != 0) {
463 syslog(LOG_INFO
|LOG_AUTH
,
464 "Kerberos rsh denied to %s.%s@%s",
465 kdata
->pname
, kdata
->pinst
, kdata
->prealm
);
466 error("Permission denied.\n");
474 pwd
->pw_passwd
!= 0 && *pwd
->pw_passwd
!= '\0' &&
475 iruserok(fromp
->sin_addr
.s_addr
, pwd
->pw_uid
== 0,
476 remuser
, locuser
) < 0) {
478 syslog(LOG_INFO
|LOG_AUTH
,
479 "%s@%s as %s: permission denied (%s). cmd='%.80s'",
480 remuser
, hostname
, locuser
, __rcmd_errstr
,
483 syslog(LOG_INFO
|LOG_AUTH
,
484 "%s@%s as %s: permission denied. cmd='%.80s'",
485 remuser
, hostname
, locuser
, cmdbuf
);
487 if (errorstr
== NULL
)
488 errorstr
= "Permission denied.\n";
489 error(errorstr
, errorhost
);
493 if (pwd
->pw_uid
&& !access(_PATH_NOLOGIN
, F_OK
)) {
494 error("Logins currently disabled.\n");
498 (void) write(STDERR_FILENO
, "\0", 1);
503 error("Can't make pipe.\n");
510 error("Can't make 2nd pipe.\n");
514 error("Can't make 3rd pipe.\n");
522 error("Can't fork; try again.\n");
529 static char msg
[] = SECURE_MESSAGE
;
530 (void) close(pv1
[1]);
531 (void) close(pv2
[1]);
532 des_write(s
, msg
, sizeof(msg
) - 1);
545 FD_SET(s
, &readfrom
);
546 FD_SET(pv
[0], &readfrom
);
555 FD_SET(pv2
[0], &writeto
);
556 FD_SET(pv1
[0], &readfrom
);
558 nfd
= MAX(nfd
, pv2
[0]);
559 nfd
= MAX(nfd
, pv1
[0]);
563 ioctl(pv
[0], FIONBIO
, (char *)&one
);
565 /* should set s nbio! */
573 if (select(nfd
, &ready
,
574 &wready
, (fd_set
*) 0,
575 (struct timeval
*) 0) < 0)
580 if (select(nfd
, &ready
, (fd_set
*)0,
581 (fd_set
*)0, (struct timeval
*)0) < 0)
583 if (FD_ISSET(s
, &ready
)) {
588 ret
= des_read(s
, &sig
, 1);
592 ret
= read(s
, &sig
, 1);
594 FD_CLR(s
, &readfrom
);
598 if (FD_ISSET(pv
[0], &ready
)) {
600 cc
= read(pv
[0], buf
, sizeof(buf
));
603 FD_CLR(pv
[0], &readfrom
);
609 des_write(s
, buf
, cc
);
619 if (doencrypt
&& FD_ISSET(pv1
[0], &ready
)) {
621 cc
= read(pv1
[0], buf
, sizeof(buf
));
623 shutdown(pv1
[0], 1+1);
624 FD_CLR(pv1
[0], &readfrom
);
626 (void) des_write(STDOUT_FILENO
,
630 if (doencrypt
&& FD_ISSET(pv2
[0], &wready
)) {
632 cc
= des_read(STDIN_FILENO
,
635 shutdown(pv2
[0], 1+1);
636 FD_CLR(pv2
[0], &writeto
);
638 (void) write(pv2
[0], buf
, cc
);
643 } while (FD_ISSET(s
, &readfrom
) ||
646 (doencrypt
&& FD_ISSET(pv1
[0], &readfrom
)) ||
649 FD_ISSET(pv
[0], &readfrom
));
652 setpgrp(0, getpid());
658 close(pv1
[0]); close(pv2
[0]);
669 if (*pwd
->pw_shell
== '\0')
670 pwd
->pw_shell
= _PATH_BSHELL
;
672 if (setlogin(pwd
->pw_name
) < 0)
673 syslog(LOG_ERR
, "setlogin() failed: %m");
675 (void) setgid((gid_t
)pwd
->pw_gid
);
676 initgroups(pwd
->pw_name
, pwd
->pw_gid
);
677 (void) setuid((uid_t
)pwd
->pw_uid
);
679 strncat(homedir
, pwd
->pw_dir
, sizeof(homedir
)-6);
680 strcat(path
, _PATH_DEFPATH
);
681 strncat(shell
, pwd
->pw_shell
, sizeof(shell
)-7);
682 strncat(username
, pwd
->pw_name
, sizeof(username
)-6);
683 cp
= strrchr(pwd
->pw_shell
, '/');
689 if (log_success
|| pwd
->pw_uid
== 0) {
692 syslog(LOG_INFO
|LOG_AUTH
,
693 "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'",
694 kdata
->pname
, kdata
->pinst
, kdata
->prealm
,
695 hostname
, locuser
, cmdbuf
);
698 syslog(LOG_INFO
|LOG_AUTH
, "%s@%s as %s: cmd='%.80s'",
699 remuser
, hostname
, locuser
, cmdbuf
);
701 execl(pwd
->pw_shell
, cp
, "-c", cmdbuf
, 0);
702 perror(pwd
->pw_shell
);
707 * Report error to client. Note: can't be used until second socket has
708 * connected to client, or older clients will hang waiting for that
719 error(const char *fmt
, ...)
728 char *bp
, buf
[BUFSIZ
];
735 if (sent_null
== 0) {
740 (void)vsnprintf(bp
, sizeof(buf
) - 1, fmt
, ap
);
741 (void)write(STDERR_FILENO
, buf
, len
+ strlen(bp
));
745 getstr(buf
, cnt
, err
)
752 if (read(STDIN_FILENO
, &c
, 1) != 1)
756 error("%s too long\n", err
);
763 * Check whether host h is in our local domain,
764 * defined as sharing the last two components of the domain part,
765 * or the entire domain part if the local domain has only one component.
766 * If either name is unqualified (contains no '.'),
767 * assume that the host is local, as it will be
768 * interpreted as such.
774 char localhost
[MAXHOSTNAMELEN
];
778 (void) gethostname(localhost
, sizeof(localhost
));
779 p1
= topdomain(localhost
);
781 if (p1
== NULL
|| p2
== NULL
|| !strcasecmp(p1
, p2
))
790 char *p
, *maybe
= NULL
;
793 for (p
= h
+ strlen(h
); p
>= h
; p
--) {
807 syslog(LOG_ERR
, "usage: rshd [-%s]", OPTIONS
);