Import NetBSD rcmd, rcp, rsh, rshd
Change-Id: I83d908bbe17f04826e9b5c3a220a5bb2c3a51c80
This commit is contained in:
parent
ed223591a8
commit
93d36fc9d8
35 changed files with 3375 additions and 2239 deletions
|
@ -2,7 +2,7 @@
|
|||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
SUBDIR= cat chmod cp date dd df domainname echo ed expr hostname \
|
||||
kill ksh ln ls mkdir mv pax pwd rm rmdir sh \
|
||||
kill ksh ln ls mkdir mv pax pwd rcp rcmd rm rmdir sh \
|
||||
sleep stty sync test
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
15
bin/rcmd/Makefile
Normal file
15
bin/rcmd/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $NetBSD: Makefile,v 1.11 2007/05/28 12:06:17 tls Exp $
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
USE_FORT?=yes # setuid
|
||||
# XXX Unsupported Kerberos options were removed from man page
|
||||
# XXX Don't forget to update the man page if you fix Kerberos
|
||||
PROG= rcmd
|
||||
SRCS= rsh.c getport.c
|
||||
CPPFLAGS+=-DIN_RCMD
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
.PATH: ${NETBSDSRCDIR}/usr.bin/rsh
|
||||
|
||||
.include <bsd.prog.mk>
|
199
bin/rcmd/rcmd.1
Normal file
199
bin/rcmd/rcmd.1
Normal file
|
@ -0,0 +1,199 @@
|
|||
.\" $NetBSD: rcmd.1,v 1.21 2011/05/31 11:31:10 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997 Matthew R. Green.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1990 The Regents of the University of California.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from: @(#)rsh.1 6.10 (Berkeley) 7/24/91
|
||||
.\" from: NetBSD: rsh.1,v 1.3 1997/01/09 20:21:14 tls Exp
|
||||
.\"
|
||||
.Dd May 31, 2011
|
||||
.Dt RCMD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rcmd
|
||||
.Nd backend driver for
|
||||
.Xr rcmd 3
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 46dn
|
||||
.Op Fl l Ar username
|
||||
.Op Fl p Ar port
|
||||
.Op Fl u Ar localusername
|
||||
.Ar host
|
||||
.Ar command
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
executes
|
||||
.Ar command
|
||||
on
|
||||
.Ar host .
|
||||
.Pp
|
||||
.Nm
|
||||
copies its standard input to the remote command, the standard
|
||||
output of the remote command to its standard output, and the
|
||||
standard error of the remote command to its standard error.
|
||||
Interrupt, quit and terminate signals are propagated to the remote
|
||||
command;
|
||||
.Nm
|
||||
normally terminates when the remote command does.
|
||||
The options are as follows:
|
||||
.Bl -tag -width flag
|
||||
.It Fl 4
|
||||
Use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Use IPv6 addresses only.
|
||||
.It Fl d
|
||||
The
|
||||
.Fl d
|
||||
option turns on socket debugging (using
|
||||
.Xr setsockopt 2 )
|
||||
on the
|
||||
.Tn TCP
|
||||
sockets used for communication with the remote host.
|
||||
.It Fl l
|
||||
By default, the remote username is the same as the local username.
|
||||
The
|
||||
.Fl l
|
||||
option allows the remote name to be specified.
|
||||
Another possible way to specify the remote username
|
||||
is the notation
|
||||
.Ar user@host .
|
||||
.It Fl n
|
||||
The
|
||||
.Fl n
|
||||
option redirects input from the special device
|
||||
.Pa /dev/null
|
||||
(see the
|
||||
.Sx BUGS
|
||||
section of this manual page).
|
||||
.It Fl p Ar port
|
||||
Uses the given
|
||||
.Pa port
|
||||
instead of the one assigned to the service
|
||||
.Dq shell .
|
||||
May be given either as symbolic name or as number.
|
||||
.It Fl u
|
||||
The
|
||||
.Fl u
|
||||
option allows the local username to be specified.
|
||||
Only the superuser is allowed to use this option.
|
||||
.El
|
||||
.Pp
|
||||
Shell metacharacters which are not quoted are interpreted on local machine,
|
||||
while quoted metacharacters are interpreted on the remote machine.
|
||||
For example, the command
|
||||
.Pp
|
||||
.Dl rcmd otherhost cat remotefile \*[Gt]\*[Gt] localfile
|
||||
.Pp
|
||||
appends the remote file
|
||||
.Ar remotefile
|
||||
to the local file
|
||||
.Ar localfile ,
|
||||
while
|
||||
.Pp
|
||||
.Dl rcmd otherhost cat remotefile \&"\*[Gt]\*[Gt]\&" other_remotefile
|
||||
.Pp
|
||||
appends
|
||||
.Ar remotefile
|
||||
to
|
||||
.Ar other_remotefile .
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/hosts -compact
|
||||
.It Pa /etc/hosts
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rsh 1 ,
|
||||
.Xr rcmd 3 ,
|
||||
.Xr environ 7
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Nx 1.3
|
||||
and is primarily derived from
|
||||
.Xr rsh 1 .
|
||||
Its purpose was to create a backend driver for
|
||||
.Xr rcmd 3
|
||||
that would allow the users of
|
||||
.Xr rcmd 3
|
||||
to no longer require super-user privileges.
|
||||
.Sh BUGS
|
||||
If you are using
|
||||
.Xr csh 1
|
||||
and put a
|
||||
.Nm
|
||||
in the background without redirecting its input away from the terminal,
|
||||
it will block even if no reads are posted by the remote command.
|
||||
If no input is desired you should redirect the input of
|
||||
.Nm
|
||||
to
|
||||
.Pa /dev/null
|
||||
using the
|
||||
.Fl n
|
||||
option.
|
||||
.Pp
|
||||
You cannot use
|
||||
.Nm rcmd
|
||||
to run an interactive command (like
|
||||
.Xr rogue 6
|
||||
or
|
||||
.Xr vi 1 ) .
|
||||
Use
|
||||
.Xr rlogin 1
|
||||
instead.
|
||||
.Pp
|
||||
The stop signal,
|
||||
.Dv SIGSTOP ,
|
||||
will stop the local
|
||||
.Nm
|
||||
process only.
|
||||
This is arguably wrong, but currently hard to fix for reasons
|
||||
too complicated to explain here.
|
11
bin/rcp/Makefile
Normal file
11
bin/rcp/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.25 2009/02/14 08:31:13 lukem Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 7/19/93
|
||||
|
||||
WARNS=3
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= rcp
|
||||
SRCS= rcp.c util.c
|
||||
|
||||
.include <bsd.prog.mk>
|
49
bin/rcp/extern.h
Normal file
49
bin/rcp/extern.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* $NetBSD: extern.h,v 1.6 2005/03/11 02:55:23 ginsbach Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int cnt;
|
||||
char *buf;
|
||||
} BUF;
|
||||
|
||||
extern int iamremote;
|
||||
|
||||
BUF *allocbuf(BUF *, int, int);
|
||||
char *colon(char *);
|
||||
void lostconn(int);
|
||||
void nospace(void);
|
||||
int okname(char *);
|
||||
void run_err(const char *, ...);
|
||||
int susystem(char *);
|
||||
char *unbracket(char *);
|
||||
void verifydir(char *);
|
42
bin/rcp/pathnames.h
Normal file
42
bin/rcp/pathnames.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* $NetBSD: pathnames.h,v 1.7 2004/08/19 23:05:00 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#ifdef RESCUEDIR
|
||||
#define _PATH_CP RESCUEDIR "/cp"
|
||||
#define _PATH_RSH RESCUEDIR "/rsh"
|
||||
#else
|
||||
#define _PATH_CP "/bin/cp"
|
||||
#define _PATH_RSH "/usr/bin/rsh"
|
||||
#endif
|
172
bin/rcp/rcp.1
Normal file
172
bin/rcp/rcp.1
Normal file
|
@ -0,0 +1,172 @@
|
|||
.\" $NetBSD: rcp.1,v 1.22 2012/03/22 07:58:17 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)rcp.1 8.1 (Berkeley) 5/31/93
|
||||
.\"
|
||||
.Dd March 8, 2005
|
||||
.Dt RCP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rcp
|
||||
.Nd remote file copy
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 46p
|
||||
.Ar file1 file2
|
||||
.Nm
|
||||
.Op Fl 46pr
|
||||
.Ar file ...
|
||||
.Ar directory
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
copies files between machines.
|
||||
Each
|
||||
.Ar file
|
||||
or
|
||||
.Ar directory
|
||||
argument is either a remote file name of the
|
||||
form
|
||||
.Dq rname@rhost:path ,
|
||||
or a local file name (containing no
|
||||
.Sq \&:
|
||||
(colon) characters,
|
||||
or a
|
||||
.Sq /
|
||||
(slash) before any
|
||||
.Sq \&:
|
||||
(colon) characters).
|
||||
.Pp
|
||||
The
|
||||
.Ar rhost
|
||||
can be an IPv4 or an IPv6 address string.
|
||||
Since IPv6 addresses already contain
|
||||
.Sq \&:
|
||||
(colon) characters,
|
||||
an IPv6 address string must be enclosed between
|
||||
.Sq \&[
|
||||
(left square bracket) and
|
||||
.Sq \&]
|
||||
(right square bracket) characters.
|
||||
Otherwise, the first occurrence of a
|
||||
.Sq \&:
|
||||
(colon) character would be
|
||||
interpreted as the separator between the
|
||||
.Ar rhost
|
||||
and the
|
||||
.Ar path .
|
||||
For example,
|
||||
.Pp
|
||||
.Dl [2001:DB8::800:200C:417A]:tmp/file
|
||||
.Pp
|
||||
Options:
|
||||
.Bl -tag -width flag
|
||||
.It Fl 4
|
||||
Use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Use IPv6 addresses only.
|
||||
.It Fl p
|
||||
The
|
||||
.Fl p
|
||||
option causes
|
||||
.Nm
|
||||
to attempt to preserve (duplicate) in its copies the modification
|
||||
times and modes of the source files, ignoring the
|
||||
.Ar umask .
|
||||
By default, the mode and owner of
|
||||
.Ar file2
|
||||
are preserved if it already existed; otherwise the mode of the source file
|
||||
modified by the
|
||||
.Xr umask 2
|
||||
on the destination host is used.
|
||||
.It Fl r
|
||||
If any of the source files are directories,
|
||||
.Nm
|
||||
copies each subtree rooted at that name; in this case
|
||||
the destination must be a directory.
|
||||
.El
|
||||
.Pp
|
||||
If
|
||||
.Ar path
|
||||
is not a full path name, it is interpreted relative to
|
||||
the login directory of the specified user
|
||||
.Ar ruser
|
||||
on
|
||||
.Ar rhost ,
|
||||
or your current user name if no other remote user name is specified.
|
||||
A
|
||||
.Ar path
|
||||
on a remote host may be quoted (using \e, ", or \(aa)
|
||||
so that the metacharacters are interpreted remotely.
|
||||
.Pp
|
||||
.Nm
|
||||
does not prompt for passwords; it performs remote execution
|
||||
via
|
||||
.Xr rsh 1 ,
|
||||
and requires the same authorization.
|
||||
.Pp
|
||||
.Nm
|
||||
handles third party copies, where neither source nor target files
|
||||
are on the current machine.
|
||||
.Sh SEE ALSO
|
||||
.Xr cp 1 ,
|
||||
.Xr ftp 1 ,
|
||||
.Xr rcmd 1 ,
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr rcmd 3 ,
|
||||
.Xr hosts.equiv 5 ,
|
||||
.Xr rhosts 5 ,
|
||||
.Xr environ 7
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility appeared in
|
||||
.Bx 4.2 .
|
||||
The version of
|
||||
.Nm
|
||||
described here
|
||||
has been reimplemented with Kerberos in
|
||||
.Bx 4.3 Reno .
|
||||
.Sh BUGS
|
||||
Doesn't detect all cases where the target of a copy might
|
||||
be a file in cases where only a directory should be legal.
|
||||
.Pp
|
||||
Is confused by any output generated by commands in a
|
||||
.Pa \&.login ,
|
||||
.Pa \&.profile ,
|
||||
or
|
||||
.Pa \&.cshrc
|
||||
file on the remote host.
|
||||
.Pp
|
||||
The destination user and hostname may have to be specified as
|
||||
.Dq rhost.rname
|
||||
when the destination machine is running the
|
||||
.Bx 4.2
|
||||
version of
|
||||
.Nm .
|
813
bin/rcp/rcp.c
Normal file
813
bin/rcp/rcp.c
Normal file
|
@ -0,0 +1,813 @@
|
|||
/* $NetBSD: rcp.c,v 1.49 2012/05/07 15:22:54 chs Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1990, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1983, 1990, 1992, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rcp.c 8.2 (Berkeley) 4/2/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: rcp.c,v 1.49 2012/05/07 15:22:54 chs Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define OPTIONS "46dfprt"
|
||||
|
||||
struct passwd *pwd;
|
||||
char *pwname;
|
||||
u_short port;
|
||||
uid_t userid;
|
||||
int errs, rem;
|
||||
int pflag, iamremote, iamrecursive, targetshouldbedirectory;
|
||||
int family = AF_UNSPEC;
|
||||
static char dot[] = ".";
|
||||
|
||||
#define CMDNEEDS 64
|
||||
char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
|
||||
|
||||
int response(void);
|
||||
void rsource(char *, struct stat *);
|
||||
void sink(int, char *[]);
|
||||
void source(int, char *[]);
|
||||
void tolocal(int, char *[]);
|
||||
void toremote(char *, int, char *[]);
|
||||
void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct servent *sp;
|
||||
int ch, fflag, tflag;
|
||||
char *targ;
|
||||
const char *shell;
|
||||
|
||||
setprogname(argv[0]);
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
fflag = tflag = 0;
|
||||
while ((ch = getopt(argc, argv, OPTIONS)) != -1)
|
||||
switch(ch) { /* User-visible flags. */
|
||||
case '4':
|
||||
family = AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
family = AF_INET6;
|
||||
break;
|
||||
case 'K':
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
case 'r':
|
||||
iamrecursive = 1;
|
||||
break;
|
||||
/* Server options. */
|
||||
case 'd':
|
||||
targetshouldbedirectory = 1;
|
||||
break;
|
||||
case 'f': /* "from" */
|
||||
iamremote = 1;
|
||||
fflag = 1;
|
||||
break;
|
||||
case 't': /* "to" */
|
||||
iamremote = 1;
|
||||
tflag = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
sp = getservbyname(shell = "shell", "tcp");
|
||||
if (sp == NULL)
|
||||
errx(1, "%s/tcp: unknown service", shell);
|
||||
port = sp->s_port;
|
||||
|
||||
if ((pwd = getpwuid(userid = getuid())) == NULL)
|
||||
errx(1, "unknown user %d", (int)userid);
|
||||
|
||||
if ((pwname = strdup(pwd->pw_name)) == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
rem = STDIN_FILENO; /* XXX */
|
||||
|
||||
if (fflag) { /* Follow "protocol", send data. */
|
||||
(void)response();
|
||||
source(argc, argv);
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
if (tflag) { /* Receive data. */
|
||||
sink(argc, argv);
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
if (argc > 2)
|
||||
targetshouldbedirectory = 1;
|
||||
|
||||
rem = -1;
|
||||
/* Command to be executed on remote system using "rsh". */
|
||||
(void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s",
|
||||
iamrecursive ? " -r" : "", pflag ? " -p" : "",
|
||||
targetshouldbedirectory ? " -d" : "");
|
||||
|
||||
(void)signal(SIGPIPE, lostconn);
|
||||
|
||||
if ((targ = colon(argv[argc - 1])) != NULL)/* Dest is remote host. */
|
||||
toremote(targ, argc, argv);
|
||||
else {
|
||||
tolocal(argc, argv); /* Dest is local host. */
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(argv[argc - 1]);
|
||||
}
|
||||
exit(errs);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void
|
||||
toremote(char *targ, int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
char *bp, *host, *src, *suser, *thost, *tuser;
|
||||
|
||||
*targ++ = 0;
|
||||
if (*targ == 0)
|
||||
targ = dot;
|
||||
|
||||
if ((thost = strchr(argv[argc - 1], '@')) != NULL) {
|
||||
/* user@host */
|
||||
*thost++ = 0;
|
||||
tuser = argv[argc - 1];
|
||||
if (*tuser == '\0')
|
||||
tuser = NULL;
|
||||
else if (!okname(tuser))
|
||||
exit(1);
|
||||
} else {
|
||||
thost = argv[argc - 1];
|
||||
tuser = NULL;
|
||||
}
|
||||
thost = unbracket(thost);
|
||||
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
src = colon(argv[i]);
|
||||
if (src) { /* remote to remote */
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
src = dot;
|
||||
host = strchr(argv[i], '@');
|
||||
len = strlen(_PATH_RSH) + strlen(argv[i]) +
|
||||
strlen(src) + (tuser ? strlen(tuser) : 0) +
|
||||
strlen(thost) + strlen(targ) + CMDNEEDS + 20;
|
||||
if (!(bp = malloc(len)))
|
||||
err(1, NULL);
|
||||
if (host) {
|
||||
*host++ = 0;
|
||||
host = unbracket(host);
|
||||
suser = argv[i];
|
||||
if (*suser == '\0')
|
||||
suser = pwname;
|
||||
else if (!okname(suser)) {
|
||||
(void)free(bp);
|
||||
continue;
|
||||
}
|
||||
(void)snprintf(bp, len,
|
||||
"%s %s -l %s -n %s %s '%s%s%s:%s'",
|
||||
_PATH_RSH, host, suser, cmd, src,
|
||||
tuser ? tuser : "", tuser ? "@" : "",
|
||||
thost, targ);
|
||||
} else {
|
||||
host = unbracket(argv[i]);
|
||||
(void)snprintf(bp, len,
|
||||
"exec %s %s -n %s %s '%s%s%s:%s'",
|
||||
_PATH_RSH, argv[i], cmd, src,
|
||||
tuser ? tuser : "", tuser ? "@" : "",
|
||||
thost, targ);
|
||||
}
|
||||
(void)susystem(bp);
|
||||
(void)free(bp);
|
||||
} else { /* local to remote */
|
||||
if (rem == -1) {
|
||||
len = strlen(targ) + CMDNEEDS + 20;
|
||||
if (!(bp = malloc(len)))
|
||||
err(1, NULL);
|
||||
(void)snprintf(bp, len, "%s -t %s", cmd, targ);
|
||||
host = thost;
|
||||
rem = rcmd_af(&host, port, pwname,
|
||||
tuser ? tuser : pwname,
|
||||
bp, NULL, family);
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
if (response() < 0)
|
||||
exit(1);
|
||||
(void)free(bp);
|
||||
}
|
||||
source(1, argv+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tolocal(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
char *bp, *host, *src, *suser;
|
||||
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
if (!(src = colon(argv[i]))) { /* Local to local. */
|
||||
len = strlen(_PATH_CP) + strlen(argv[i]) +
|
||||
strlen(argv[argc - 1]) + 20;
|
||||
if (!(bp = malloc(len)))
|
||||
err(1, NULL);
|
||||
(void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
|
||||
iamrecursive ? " -r" : "", pflag ? " -p" : "",
|
||||
argv[i], argv[argc - 1]);
|
||||
if (susystem(bp))
|
||||
++errs;
|
||||
(void)free(bp);
|
||||
continue;
|
||||
}
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
src = dot;
|
||||
if ((host = strchr(argv[i], '@')) == NULL) {
|
||||
host = argv[i];
|
||||
suser = pwname;
|
||||
} else {
|
||||
*host++ = 0;
|
||||
suser = argv[i];
|
||||
if (*suser == '\0')
|
||||
suser = pwname;
|
||||
else if (!okname(suser))
|
||||
continue;
|
||||
}
|
||||
host = unbracket(host);
|
||||
len = strlen(src) + CMDNEEDS + 20;
|
||||
if ((bp = malloc(len)) == NULL)
|
||||
err(1, NULL);
|
||||
(void)snprintf(bp, len, "%s -f %s", cmd, src);
|
||||
rem =
|
||||
rcmd_af(&host, port, pwname, suser, bp, NULL, family);
|
||||
(void)free(bp);
|
||||
if (rem < 0) {
|
||||
++errs;
|
||||
continue;
|
||||
}
|
||||
sink(1, argv + argc - 1);
|
||||
(void)close(rem);
|
||||
rem = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
source(int argc, char *argv[])
|
||||
{
|
||||
struct stat stb;
|
||||
static BUF buffer;
|
||||
BUF *bp;
|
||||
off_t i;
|
||||
off_t amt;
|
||||
int fd, haderr, indx, result;
|
||||
char *last, *name, buf[BUFSIZ];
|
||||
|
||||
for (indx = 0; indx < argc; ++indx) {
|
||||
name = argv[indx];
|
||||
if ((fd = open(name, O_RDONLY, 0)) < 0)
|
||||
goto syserr;
|
||||
if (fstat(fd, &stb)) {
|
||||
syserr: run_err("%s: %s", name, strerror(errno));
|
||||
goto next;
|
||||
}
|
||||
switch (stb.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
break;
|
||||
case S_IFDIR:
|
||||
if (iamrecursive) {
|
||||
rsource(name, &stb);
|
||||
goto next;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
run_err("%s: not a regular file", name);
|
||||
goto next;
|
||||
}
|
||||
if ((last = strrchr(name, '/')) == NULL)
|
||||
last = name;
|
||||
else
|
||||
++last;
|
||||
if (pflag) {
|
||||
/*
|
||||
* Make it compatible with possible future
|
||||
* versions expecting microseconds.
|
||||
*/
|
||||
(void)snprintf(buf, sizeof(buf), "T%lld %ld %lld %ld\n",
|
||||
(long long)stb.st_mtimespec.tv_sec,
|
||||
(long)stb.st_mtimespec.tv_nsec / 1000,
|
||||
(long long)stb.st_atimespec.tv_sec,
|
||||
(long)stb.st_atimespec.tv_nsec / 1000);
|
||||
(void)write(rem, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
}
|
||||
#define RCPMODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
|
||||
(void)snprintf(buf, sizeof(buf), "C%04o %lld %s\n",
|
||||
stb.st_mode & RCPMODEMASK, (long long)stb.st_size, last);
|
||||
(void)write(rem, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
|
||||
next: (void)close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Keep writing after an error so that we stay sync'd up. */
|
||||
haderr = 0;
|
||||
for (i = 0; i < stb.st_size; i += bp->cnt) {
|
||||
amt = bp->cnt;
|
||||
if (i + amt > stb.st_size)
|
||||
amt = stb.st_size - i;
|
||||
if (!haderr) {
|
||||
result = read(fd, bp->buf, (size_t)amt);
|
||||
if (result != amt)
|
||||
haderr = result >= 0 ? EIO : errno;
|
||||
}
|
||||
if (haderr)
|
||||
(void)write(rem, bp->buf, (size_t)amt);
|
||||
else {
|
||||
result = write(rem, bp->buf, (size_t)amt);
|
||||
if (result != amt)
|
||||
haderr = result >= 0 ? EIO : errno;
|
||||
}
|
||||
}
|
||||
if (close(fd) && !haderr)
|
||||
haderr = errno;
|
||||
if (!haderr)
|
||||
(void)write(rem, "", 1);
|
||||
else
|
||||
run_err("%s: %s", name, strerror(haderr));
|
||||
(void)response();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rsource(char *name, struct stat *statp)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char *last, *vect[1], path[MAXPATHLEN];
|
||||
|
||||
if (!(dirp = opendir(name))) {
|
||||
run_err("%s: %s", name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
last = strrchr(name, '/');
|
||||
if (last == 0)
|
||||
last = name;
|
||||
else
|
||||
last++;
|
||||
if (pflag) {
|
||||
(void)snprintf(path, sizeof(path), "T%lld %ld %lld %ld\n",
|
||||
(long long)statp->st_mtimespec.tv_sec,
|
||||
(long)statp->st_mtimespec.tv_nsec / 1000,
|
||||
(long long)statp->st_atimespec.tv_sec,
|
||||
(long)statp->st_atimespec.tv_nsec / 1000);
|
||||
(void)write(rem, path, strlen(path));
|
||||
if (response() < 0) {
|
||||
(void)closedir(dirp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
(void)snprintf(path, sizeof(path),
|
||||
"D%04o %d %s\n", statp->st_mode & RCPMODEMASK, 0, last);
|
||||
(void)write(rem, path, strlen(path));
|
||||
if (response() < 0) {
|
||||
(void)closedir(dirp);
|
||||
return;
|
||||
}
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (!strcmp(dp->d_name, dot) || !strcmp(dp->d_name, ".."))
|
||||
continue;
|
||||
if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
|
||||
run_err("%s/%s: name too long", name, dp->d_name);
|
||||
continue;
|
||||
}
|
||||
(void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
|
||||
vect[0] = path;
|
||||
source(1, vect);
|
||||
}
|
||||
(void)closedir(dirp);
|
||||
(void)write(rem, "E\n", 2);
|
||||
(void)response();
|
||||
}
|
||||
|
||||
void
|
||||
sink(int argc, char *argv[])
|
||||
{
|
||||
static BUF buffer;
|
||||
struct stat stb;
|
||||
struct timeval tv[2];
|
||||
enum { YES, NO, DISPLAYED } wrerr;
|
||||
BUF *bp;
|
||||
ssize_t j;
|
||||
off_t i;
|
||||
off_t amt;
|
||||
off_t count;
|
||||
int exists, first, ofd;
|
||||
mode_t mask;
|
||||
mode_t mode;
|
||||
mode_t omode;
|
||||
int setimes, targisdir;
|
||||
int wrerrno = 0; /* pacify gcc */
|
||||
char ch, *cp, *np, *targ, *vect[1], buf[BUFSIZ];
|
||||
const char *why;
|
||||
off_t size;
|
||||
char *namebuf = NULL;
|
||||
size_t cursize = 0;
|
||||
|
||||
#define atime tv[0]
|
||||
#define mtime tv[1]
|
||||
#define SCREWUP(str) { why = str; goto screwup; }
|
||||
|
||||
setimes = targisdir = 0;
|
||||
mask = umask(0);
|
||||
if (!pflag)
|
||||
(void)umask(mask);
|
||||
if (argc != 1) {
|
||||
run_err("ambiguous target");
|
||||
exit(1);
|
||||
}
|
||||
targ = *argv;
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(targ);
|
||||
(void)write(rem, "", 1);
|
||||
if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
|
||||
targisdir = 1;
|
||||
for (first = 1;; first = 0) {
|
||||
cp = buf;
|
||||
if (read(rem, cp, 1) <= 0)
|
||||
goto out;
|
||||
if (*cp++ == '\n')
|
||||
SCREWUP("unexpected <newline>");
|
||||
do {
|
||||
if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
|
||||
SCREWUP("lost connection");
|
||||
*cp++ = ch;
|
||||
} while (cp < &buf[BUFSIZ - 1] && ch != '\n');
|
||||
*cp = 0;
|
||||
|
||||
if (buf[0] == '\01' || buf[0] == '\02') {
|
||||
if (iamremote == 0)
|
||||
(void)write(STDERR_FILENO,
|
||||
buf + 1, strlen(buf + 1));
|
||||
if (buf[0] == '\02')
|
||||
exit(1);
|
||||
++errs;
|
||||
continue;
|
||||
}
|
||||
if (buf[0] == 'E') {
|
||||
(void)write(rem, "", 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ch == '\n')
|
||||
*--cp = 0;
|
||||
|
||||
#define getnum(t) (t) = 0; while (isdigit((unsigned char)*cp)) (t) = (t) * 10 + (*cp++ - '0');
|
||||
cp = buf;
|
||||
if (*cp == 'T') {
|
||||
setimes++;
|
||||
cp++;
|
||||
getnum(mtime.tv_sec);
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("mtime.sec not delimited");
|
||||
getnum(mtime.tv_usec);
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("mtime.usec not delimited");
|
||||
getnum(atime.tv_sec);
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("atime.sec not delimited");
|
||||
getnum(atime.tv_usec);
|
||||
if (*cp++ != '\0')
|
||||
SCREWUP("atime.usec not delimited");
|
||||
(void)write(rem, "", 1);
|
||||
continue;
|
||||
}
|
||||
if (*cp != 'C' && *cp != 'D') {
|
||||
/*
|
||||
* Check for the case "rcp remote:foo\* local:bar".
|
||||
* In this case, the line "No match." can be returned
|
||||
* by the shell before the rcp command on the remote is
|
||||
* executed so the ^Aerror_message convention isn't
|
||||
* followed.
|
||||
*/
|
||||
if (first) {
|
||||
run_err("%s", cp);
|
||||
exit(1);
|
||||
}
|
||||
SCREWUP("expected control record");
|
||||
}
|
||||
mode = 0;
|
||||
for (++cp; cp < buf + 5; cp++) {
|
||||
if (*cp < '0' || *cp > '7')
|
||||
SCREWUP("bad mode");
|
||||
mode = (mode << 3) | (*cp - '0');
|
||||
}
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("mode not delimited");
|
||||
|
||||
for (size = 0; isdigit((unsigned char)*cp);)
|
||||
size = size * 10 + (*cp++ - '0');
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("size not delimited");
|
||||
if (targisdir) {
|
||||
char *newnamebuf;
|
||||
size_t need;
|
||||
|
||||
need = strlen(targ) + strlen(cp) + 2;
|
||||
if (need > cursize) {
|
||||
need += 256;
|
||||
newnamebuf = realloc(namebuf, need);
|
||||
if (newnamebuf != NULL) {
|
||||
namebuf = newnamebuf;
|
||||
cursize = need;
|
||||
} else {
|
||||
run_err("%s", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
(void)snprintf(namebuf, cursize, "%s%s%s", targ,
|
||||
*targ ? "/" : "", cp);
|
||||
np = namebuf;
|
||||
} else
|
||||
np = targ;
|
||||
exists = stat(np, &stb) == 0;
|
||||
if (buf[0] == 'D') {
|
||||
int mod_flag = pflag;
|
||||
if (exists) {
|
||||
if (!S_ISDIR(stb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
goto bad;
|
||||
}
|
||||
if (pflag)
|
||||
(void)chmod(np, mode);
|
||||
} else {
|
||||
/* Handle copying from a read-only directory */
|
||||
mod_flag = 1;
|
||||
if (mkdir(np, mode | S_IRWXU) < 0)
|
||||
goto bad;
|
||||
}
|
||||
vect[0] = np;
|
||||
sink(1, vect);
|
||||
if (setimes) {
|
||||
setimes = 0;
|
||||
if (utimes(np, tv) < 0)
|
||||
run_err("%s: set times: %s",
|
||||
np, strerror(errno));
|
||||
}
|
||||
if (mod_flag)
|
||||
(void)chmod(np, mode);
|
||||
continue;
|
||||
}
|
||||
omode = mode;
|
||||
mode |= S_IWRITE;
|
||||
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
|
||||
bad: run_err("%s: %s", np, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
(void)write(rem, "", 1);
|
||||
if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
|
||||
(void)close(ofd);
|
||||
continue;
|
||||
}
|
||||
cp = bp->buf;
|
||||
wrerr = NO;
|
||||
count = 0;
|
||||
for (i = 0; i < size; i += BUFSIZ) {
|
||||
amt = BUFSIZ;
|
||||
if (i + amt > size)
|
||||
amt = size - i;
|
||||
count += amt;
|
||||
do {
|
||||
j = read(rem, cp, (size_t)amt);
|
||||
if (j == -1) {
|
||||
run_err("%s", j ? strerror(errno) :
|
||||
"dropped connection");
|
||||
exit(1);
|
||||
}
|
||||
amt -= j;
|
||||
cp += j;
|
||||
} while (amt > 0);
|
||||
if (count == bp->cnt) {
|
||||
/* Keep reading so we stay sync'd up. */
|
||||
if (wrerr == NO) {
|
||||
j = write(ofd, bp->buf, (size_t)count);
|
||||
if (j != count) {
|
||||
wrerr = YES;
|
||||
wrerrno = j >= 0 ? EIO : errno;
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
cp = bp->buf;
|
||||
}
|
||||
}
|
||||
if (count != 0 && wrerr == NO &&
|
||||
(j = write(ofd, bp->buf, (size_t)count)) != count) {
|
||||
wrerr = YES;
|
||||
wrerrno = j >= 0 ? EIO : errno;
|
||||
}
|
||||
if (ftruncate(ofd, size)) {
|
||||
run_err("%s: truncate: %s", np, strerror(errno));
|
||||
wrerr = DISPLAYED;
|
||||
}
|
||||
if (pflag) {
|
||||
if (exists || omode != mode)
|
||||
if (fchmod(ofd, omode))
|
||||
run_err("%s: set mode: %s",
|
||||
np, strerror(errno));
|
||||
} else {
|
||||
if (!exists && omode != mode)
|
||||
if (fchmod(ofd, omode & ~mask))
|
||||
run_err("%s: set mode: %s",
|
||||
np, strerror(errno));
|
||||
}
|
||||
#ifndef __SVR4
|
||||
if (setimes && wrerr == NO) {
|
||||
setimes = 0;
|
||||
if (futimes(ofd, tv) < 0) {
|
||||
run_err("%s: set times: %s",
|
||||
np, strerror(errno));
|
||||
wrerr = DISPLAYED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void)close(ofd);
|
||||
#ifdef __SVR4
|
||||
if (setimes && wrerr == NO) {
|
||||
setimes = 0;
|
||||
if (utimes(np, tv) < 0) {
|
||||
run_err("%s: set times: %s",
|
||||
np, strerror(errno));
|
||||
wrerr = DISPLAYED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void)response();
|
||||
switch(wrerr) {
|
||||
case YES:
|
||||
run_err("%s: write: %s", np, strerror(wrerrno));
|
||||
break;
|
||||
case NO:
|
||||
(void)write(rem, "", 1);
|
||||
break;
|
||||
case DISPLAYED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (namebuf) {
|
||||
free(namebuf);
|
||||
}
|
||||
return;
|
||||
|
||||
screwup:
|
||||
run_err("protocol error: %s", why);
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
response(void)
|
||||
{
|
||||
char ch, *cp, resp, rbuf[BUFSIZ];
|
||||
|
||||
if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
|
||||
lostconn(0);
|
||||
|
||||
cp = rbuf;
|
||||
switch(resp) {
|
||||
case 0: /* ok */
|
||||
return (0);
|
||||
default:
|
||||
*cp++ = resp;
|
||||
/* FALLTHROUGH */
|
||||
case 1: /* error, followed by error msg */
|
||||
case 2: /* fatal error, "" */
|
||||
do {
|
||||
if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
|
||||
lostconn(0);
|
||||
*cp++ = ch;
|
||||
} while (cp < &rbuf[BUFSIZ] && ch != '\n');
|
||||
|
||||
if (!iamremote)
|
||||
(void)write(STDERR_FILENO, rbuf, (size_t)(cp - rbuf));
|
||||
++errs;
|
||||
if (resp == 1)
|
||||
return (-1);
|
||||
exit(1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: rcp [-46p] f1 f2; or: rcp [-46pr] f1 ... fn directory\n");
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
void
|
||||
run_err(const char *fmt, ...)
|
||||
{
|
||||
static FILE *fp;
|
||||
va_list ap;
|
||||
|
||||
++errs;
|
||||
if (fp == NULL && !(fp = fdopen(rem, "w")))
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
(void)fprintf(fp, "%c", 0x01);
|
||||
(void)fprintf(fp, "rcp: ");
|
||||
(void)vfprintf(fp, fmt, ap);
|
||||
(void)fprintf(fp, "\n");
|
||||
(void)fflush(fp);
|
||||
va_end(ap);
|
||||
|
||||
if (!iamremote) {
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
184
bin/rcp/util.c
Normal file
184
bin/rcp/util.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/* $NetBSD: util.c,v 1.11 2006/12/15 22:45:34 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)util.c 8.2 (Berkeley) 4/2/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: util.c,v 1.11 2006/12/15 22:45:34 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
char *
|
||||
colon(char *cp)
|
||||
{
|
||||
if (*cp == ':') /* Leading colon is part of file name. */
|
||||
return (0);
|
||||
|
||||
for (; *cp; ++cp) {
|
||||
if (*cp == ':')
|
||||
return (cp);
|
||||
if (*cp == '/')
|
||||
return (0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *
|
||||
unbracket(char *cp)
|
||||
{
|
||||
char *ep;
|
||||
|
||||
if (*cp == '[') {
|
||||
ep = cp + (strlen(cp) - 1);
|
||||
if (*ep == ']') {
|
||||
*ep = '\0';
|
||||
++cp;
|
||||
}
|
||||
}
|
||||
return (cp);
|
||||
}
|
||||
|
||||
void
|
||||
verifydir(char *cp)
|
||||
{
|
||||
struct stat stb;
|
||||
|
||||
if (!stat(cp, &stb)) {
|
||||
if (S_ISDIR(stb.st_mode))
|
||||
return;
|
||||
errno = ENOTDIR;
|
||||
}
|
||||
run_err("%s: %s", cp, strerror(errno));
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
okname(char *cp0)
|
||||
{
|
||||
int c;
|
||||
char *cp;
|
||||
|
||||
cp = cp0;
|
||||
do {
|
||||
c = *cp;
|
||||
if (c & 0200)
|
||||
goto bad;
|
||||
if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
|
||||
goto bad;
|
||||
} while (*++cp);
|
||||
return (1);
|
||||
|
||||
bad: warnx("%s: invalid user name", cp0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
susystem(char *s)
|
||||
{
|
||||
sig_t istat, qstat;
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
pid = vfork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return (127);
|
||||
|
||||
case 0:
|
||||
(void)execl(_PATH_BSHELL, "sh", "-c", s, NULL);
|
||||
_exit(127);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
istat = signal(SIGINT, SIG_IGN);
|
||||
qstat = signal(SIGQUIT, SIG_IGN);
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
status = -1;
|
||||
(void)signal(SIGINT, istat);
|
||||
(void)signal(SIGQUIT, qstat);
|
||||
return (status);
|
||||
}
|
||||
|
||||
BUF *
|
||||
allocbuf(BUF *bp, int fd, int blksize)
|
||||
{
|
||||
struct stat stb;
|
||||
size_t size;
|
||||
char *nbuf;
|
||||
|
||||
if (fstat(fd, &stb) < 0) {
|
||||
run_err("fstat: %s", strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
size = roundup(stb.st_blksize, blksize);
|
||||
if (size == 0)
|
||||
size = blksize;
|
||||
if (bp->cnt >= size)
|
||||
return (bp);
|
||||
if ((nbuf = realloc(bp->buf, size)) == NULL) {
|
||||
free(bp->buf);
|
||||
bp->buf = NULL;
|
||||
bp->cnt = 0;
|
||||
run_err("%s", strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
bp->buf = nbuf;
|
||||
bp->cnt = size;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
void
|
||||
/*ARGSUSED*/
|
||||
lostconn(int signo __unused)
|
||||
{
|
||||
if (!iamremote)
|
||||
warnx("lost connection");
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -39,6 +39,8 @@
|
|||
./bin/printconfig minix-sys
|
||||
./bin/printroot minix-sys
|
||||
./bin/pwd minix-sys
|
||||
./bin/rcmd minix-sys
|
||||
./bin/rcp minix-sys
|
||||
./bin/read minix-sys obsolete
|
||||
./bin/readclock minix-sys
|
||||
./bin/rm minix-sys
|
||||
|
@ -360,7 +362,7 @@
|
|||
./usr/bin/info minix-sys
|
||||
./usr/bin/infocmp minix-sys
|
||||
./usr/bin/infokey minix-sys
|
||||
./usr/bin/in.rshd minix-sys
|
||||
./usr/bin/in.rshd minix-sys obsolete
|
||||
./usr/bin/install minix-sys
|
||||
./usr/bin/install-info minix-sys
|
||||
./usr/bin/in.telnetd minix-sys
|
||||
|
@ -458,7 +460,7 @@
|
|||
./usr/bin/ranlib minix-sys binutils
|
||||
./usr/bin/rarpd minix-sys
|
||||
./usr/bin/rawspeed minix-sys
|
||||
./usr/bin/rcp minix-sys
|
||||
./usr/bin/rcp minix-sys obsolete
|
||||
./usr/bin/readelf minix-sys binutils
|
||||
./usr/bin/readlink minix-sys
|
||||
./usr/bin/recwave minix-sys
|
||||
|
@ -2292,6 +2294,7 @@
|
|||
./usr/libexec/kyua-plain-tester minix-sys kyua
|
||||
./usr/libexec/ld.elf_so minix-sys
|
||||
./usr/libexec/makewhatis minix-sys
|
||||
./usr/libexec/rshd minix-sys
|
||||
./usr/libexec/virecover minix-sys
|
||||
./usr/log minix-sys
|
||||
./usr/log/messages minix-sys
|
||||
|
@ -2542,6 +2545,7 @@
|
|||
./usr/man/man1/pwhash.1 minix-sys
|
||||
./usr/man/man1/ranlib.1 minix-sys binutils
|
||||
./usr/man/man1/rcp.1 minix-sys
|
||||
./usr/man/man1/rcmd.1 minix-sys
|
||||
./usr/man/man1/read.1 minix-sys obsolete
|
||||
./usr/man/man1/readelf.1 minix-sys binutils
|
||||
./usr/man/man1/readlink.1 minix-sys
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
daemonize talkd
|
||||
daemonize tcpd shell in.rshd
|
||||
daemonize tcpd shell /usr/libexec/rshd
|
||||
daemonize tcpd telnet in.telnetd
|
||||
daemonize tcpd ftp /usr/libexec/ftpd
|
||||
daemonize tcpd finger /usr/libexec/fingerd
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
SUBDIR= \
|
||||
fingerd ftpd getty \
|
||||
ld.elf_so \
|
||||
\
|
||||
rshd \
|
||||
|
||||
|
||||
|
||||
|
|
26
libexec/rshd/Makefile
Normal file
26
libexec/rshd/Makefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
# $NetBSD: Makefile,v 1.19 2011/08/16 10:35:03 christos Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
PROG= rshd
|
||||
MAN= rshd.8
|
||||
|
||||
DPADD+= ${LIBUTIL}
|
||||
LDADD+= -lutil
|
||||
|
||||
CPPFLAGS+=-DLOGIN_CAP
|
||||
|
||||
.if (${USE_INET6} != "no")
|
||||
CPPFLAGS+=-DINET6
|
||||
.endif
|
||||
|
||||
.if (${USE_PAM} != "no")
|
||||
CPPFLAGS+=-DUSE_PAM
|
||||
DPADD+= ${LIBPAM} ${PAM_STATIC_DPADD}
|
||||
LDADD+= -lpam ${PAM_STATIC_LDADD}
|
||||
.endif
|
||||
|
||||
COPTS.rshd.c = -Wno-format-nonliteral
|
||||
|
||||
.include <bsd.prog.mk>
|
235
libexec/rshd/rshd.8
Normal file
235
libexec/rshd/rshd.8
Normal file
|
@ -0,0 +1,235 @@
|
|||
.\" $NetBSD: rshd.8,v 1.18 2005/03/09 16:42:49 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1989, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from: @(#)rshd.8 8.1 (Berkeley) 6/4/93
|
||||
.\"
|
||||
.Dd March 9, 2005
|
||||
.Dt RSHD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rshd
|
||||
.Nd remote shell server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl aLln
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
server is the server for the
|
||||
.Xr rcmd 3
|
||||
routine and, consequently, for the
|
||||
.Xr rsh 1
|
||||
program.
|
||||
The server provides remote execution facilities
|
||||
with authentication based on privileged port numbers from trusted hosts.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
server listens for service requests at the port indicated in
|
||||
the
|
||||
.Dq cmd
|
||||
service specification; see
|
||||
.Xr services 5 .
|
||||
When a service request is received the following protocol
|
||||
is initiated:
|
||||
.Bl -enum
|
||||
.It
|
||||
The server checks the client's source port.
|
||||
If the port is not in the range 512-1023, the server
|
||||
aborts the connection.
|
||||
.It
|
||||
The server reads characters from the socket up
|
||||
to a null
|
||||
.Pq Sq \e0
|
||||
byte.
|
||||
The resultant string is interpreted as an
|
||||
.Tn ASCII
|
||||
number, base 10.
|
||||
.It
|
||||
If the number received in step 2 is non-zero,
|
||||
it is interpreted as the port number of a secondary
|
||||
stream to be used for the
|
||||
.Em stderr .
|
||||
A second connection is then created to the specified
|
||||
port on the client's machine.
|
||||
The source port of this
|
||||
second connection is also in the range 512-1023.
|
||||
.It
|
||||
The server checks the client's source address
|
||||
and requests the corresponding host name (see
|
||||
.Xr getnameinfo 3 ,
|
||||
.Xr hosts 5 ,
|
||||
and
|
||||
.Xr named 8 ) .
|
||||
If the hostname cannot be determined,
|
||||
the dot-notation representation of the host address is used.
|
||||
If the hostname is in the same domain as the server (according to
|
||||
the last two components of the domain name), or if the
|
||||
.Fl a
|
||||
option is given,
|
||||
the addresses for the hostname are requested,
|
||||
verifying that the name and address correspond.
|
||||
If address verification fails, the connection is aborted
|
||||
with the message
|
||||
.Dq Host address mismatch.
|
||||
.It
|
||||
A null terminated user name of at most 16 characters
|
||||
is retrieved on the initial socket.
|
||||
This user name is interpreted as the user identity on the
|
||||
.Em client Ns 's
|
||||
machine.
|
||||
.It
|
||||
A null terminated user name of at most 16 characters
|
||||
is retrieved on the initial socket.
|
||||
This user name is interpreted as a user identity to use on the
|
||||
.Sy server Ns 's
|
||||
machine.
|
||||
.It
|
||||
A null terminated command to be passed to a
|
||||
shell is retrieved on the initial socket.
|
||||
The length of the command is limited by the upper
|
||||
bound on the size of the system's argument list.
|
||||
.It
|
||||
.Nm
|
||||
then validates the user using
|
||||
.Xr ruserok 3 ,
|
||||
which uses the file
|
||||
.Pa /etc/hosts.equiv
|
||||
and the
|
||||
.Pa .rhosts
|
||||
file found in the user's home directory.
|
||||
The
|
||||
.Fl l
|
||||
option prevents
|
||||
.Xr ruserok 3
|
||||
from doing any validation based on the user's
|
||||
.Dq Pa .rhosts
|
||||
file, unless the user is the superuser.
|
||||
.It
|
||||
If the file
|
||||
.Pa /etc/nologin
|
||||
exists and the user is not the superuser,
|
||||
the connection is closed.
|
||||
.It
|
||||
A null byte is returned on the initial socket
|
||||
and the command line is passed to the normal login
|
||||
shell of the user.
|
||||
The shell inherits the network connections established by
|
||||
.Nm .
|
||||
.El
|
||||
.Pp
|
||||
Transport-level keepalive messages are enabled unless the
|
||||
.Fl n
|
||||
option is present.
|
||||
The use of keepalive messages allows sessions to be timed out
|
||||
if the client crashes or becomes unreachable.
|
||||
.Pp
|
||||
The
|
||||
.Fl L
|
||||
option causes all successful accesses to be logged to
|
||||
.Xr syslogd 8
|
||||
as
|
||||
.Li auth.info
|
||||
messages.
|
||||
.Sh DIAGNOSTICS
|
||||
Except for the last one listed below,
|
||||
all diagnostic messages
|
||||
are returned on the initial socket,
|
||||
after which any network connections are closed.
|
||||
An error is indicated by a leading byte with a value of
|
||||
1 (0 is returned in step 10 above upon successful completion
|
||||
of all the steps prior to the execution of the login shell).
|
||||
.Bl -tag -width indent
|
||||
.It Sy Locuser too long.
|
||||
The name of the user on the client's machine is
|
||||
longer than 16 characters.
|
||||
.It Sy Ruser too long.
|
||||
The name of the user on the remote machine is
|
||||
longer than 16 characters.
|
||||
.It Sy Command too long .
|
||||
The command line passed exceeds the size of the argument
|
||||
list (as configured into the system).
|
||||
.It Sy Login incorrect.
|
||||
No password file entry for the user name existed.
|
||||
.It Sy Remote directory.
|
||||
The
|
||||
.Xr chdir 2
|
||||
to the home directory failed.
|
||||
.It Sy Permission denied.
|
||||
The authentication procedure described above failed.
|
||||
.It Sy Can't make pipe.
|
||||
The pipe needed for the
|
||||
.Em stderr ,
|
||||
wasn't created.
|
||||
.It Sy Can't fork; try again.
|
||||
A
|
||||
.Xr fork 2
|
||||
by the server failed.
|
||||
.It Sy \*[Lt]shellname\*[Gt]: ...
|
||||
The user's login shell could not be started.
|
||||
This message is returned on the connection associated with the
|
||||
.Em stderr ,
|
||||
and is not preceded by a flag byte.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rsh 1 ,
|
||||
.Xr ssh 1 ,
|
||||
.Xr rcmd 3 ,
|
||||
.Xr ruserok 3 ,
|
||||
.Xr hosts_access 5 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr sshd 8
|
||||
.Sh BUGS
|
||||
The authentication procedure used here assumes the integrity
|
||||
of every machine and every network that can reach the rshd/rlogind
|
||||
ports on the server.
|
||||
This is insecure, but is useful in an
|
||||
.Dq open
|
||||
environment.
|
||||
.Xr sshd 8
|
||||
or a Kerberized version of this server are much more secure.
|
||||
.Pp
|
||||
A facility to allow all data exchanges to be encrypted should be
|
||||
present.
|
||||
.Pp
|
||||
A more extensible protocol (such as Telnet) should be used.
|
||||
.Pp
|
||||
.Nm
|
||||
intentionally rejects accesses from IPv4 mapped address on top of
|
||||
.Dv AF_INET6
|
||||
socket, since IPv4 mapped address complicates
|
||||
host-address based authentication.
|
||||
If you would like to accept connections from IPv4 peers, you will
|
||||
need to run
|
||||
.Nm
|
||||
on top of an
|
||||
.Dv AF_INET
|
||||
socket, not an
|
||||
.Dv AF_INET6
|
||||
socket.
|
809
libexec/rshd/rshd.c
Normal file
809
libexec/rshd/rshd.c
Normal file
|
@ -0,0 +1,809 @@
|
|||
/* $NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by WIDE Project and
|
||||
* its contributors.
|
||||
* 4. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1988, 1989, 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* remote shell server:
|
||||
* [port]\0
|
||||
* remuser\0
|
||||
* locuser\0
|
||||
* command\0
|
||||
* data
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#ifdef LOGIN_CAP
|
||||
#include <login_cap.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
static struct pam_conv pamc = { openpam_nullconv, NULL };
|
||||
static pam_handle_t *pamh;
|
||||
static int pam_err;
|
||||
|
||||
#define PAM_END do { \
|
||||
if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", \
|
||||
pam_strerror(pamh, pam_err)); \
|
||||
if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", \
|
||||
pam_strerror(pamh, pam_err)); \
|
||||
if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", \
|
||||
pam_strerror(pamh, pam_err)); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#else
|
||||
#define PAM_END
|
||||
#endif
|
||||
|
||||
static int keepalive = 1;
|
||||
static int check_all;
|
||||
static int log_success; /* If TRUE, log all successful accesses */
|
||||
static int sent_null;
|
||||
|
||||
__dead static void doit(struct sockaddr *, struct sockaddr *);
|
||||
__dead static void rshd_errx(int, const char *, ...) __printflike(2, 3);
|
||||
static void getstr(char *, int, const char *);
|
||||
static int local_domain(char *);
|
||||
static char *topdomain(char *);
|
||||
__dead static void usage(void);
|
||||
|
||||
#define OPTIONS "aLln"
|
||||
extern int __check_rhosts_file;
|
||||
extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
|
||||
#ifdef USE_PAM
|
||||
static const char incorrect[] = "Login incorrect.";
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct linger linger;
|
||||
int ch, on = 1;
|
||||
socklen_t fromlen;
|
||||
socklen_t locallen;
|
||||
struct sockaddr_storage from;
|
||||
struct sockaddr_storage local;
|
||||
struct protoent *proto;
|
||||
|
||||
openlog("rshd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
opterr = 0;
|
||||
while ((ch = getopt(argc, argv, OPTIONS)) != -1)
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
check_all = 1;
|
||||
break;
|
||||
case 'l':
|
||||
__check_rhosts_file = 0;
|
||||
break;
|
||||
case 'n':
|
||||
keepalive = 0;
|
||||
break;
|
||||
case 'L':
|
||||
log_success = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
fromlen = sizeof(from); /* xxx */
|
||||
locallen = sizeof(local); /* xxx */
|
||||
if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) {
|
||||
syslog(LOG_ERR, "getpeername: %m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (getsockname(STDIN_FILENO, (struct sockaddr *)&local,
|
||||
&locallen) < 0) {
|
||||
syslog(LOG_ERR, "getsockname: %m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#if 0
|
||||
if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) &&
|
||||
sizeof(struct sockaddr_in) <= sizeof(from)) {
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 *sin6;
|
||||
const int off = sizeof(struct sockaddr_in6) -
|
||||
sizeof(struct sockaddr_in);
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)&from;
|
||||
(void)memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(struct sockaddr_in);
|
||||
(void)memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off],
|
||||
sizeof(sin.sin_addr));
|
||||
(void)memcpy(&from, &sin, sizeof(sin));
|
||||
fromlen = sin.sin_len;
|
||||
}
|
||||
#else
|
||||
if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) {
|
||||
char hbuf[NI_MAXHOST];
|
||||
if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf,
|
||||
sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
|
||||
strlcpy(hbuf, "invalid", sizeof(hbuf));
|
||||
}
|
||||
syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)",
|
||||
hbuf);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
if (keepalive &&
|
||||
setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
|
||||
sizeof(on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 60; /* XXX */
|
||||
if (setsockopt(STDIN_FILENO, SOL_SOCKET, SO_LINGER, (char *)&linger,
|
||||
sizeof (linger)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
|
||||
proto = getprotobyname("tcp");
|
||||
(void)setsockopt(STDIN_FILENO, proto->p_proto, TCP_NODELAY, &on,
|
||||
sizeof(on));
|
||||
doit((struct sockaddr *)&from, (struct sockaddr *)&local);
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static void
|
||||
doit(struct sockaddr *fromp, struct sockaddr *localp)
|
||||
{
|
||||
struct passwd *pwd, pwres;
|
||||
in_port_t port;
|
||||
struct pollfd set[2];
|
||||
int cc, pv[2], pid, s = -1; /* XXX gcc */
|
||||
int one = 1;
|
||||
char *hostname, *errorhost = NULL; /* XXX gcc */
|
||||
const char *cp;
|
||||
char sig, buf[BUFSIZ];
|
||||
char cmdbuf[NCARGS+1], locuser[16], remuser[16];
|
||||
char remotehost[2 * MAXHOSTNAMELEN + 1];
|
||||
char hostnamebuf[2 * MAXHOSTNAMELEN + 1];
|
||||
#ifdef LOGIN_CAP
|
||||
login_cap_t *lc;
|
||||
#endif
|
||||
char naddr[NI_MAXHOST];
|
||||
char saddr[NI_MAXHOST];
|
||||
char raddr[NI_MAXHOST];
|
||||
char pbuf[NI_MAXSERV];
|
||||
int af = fromp->sa_family;
|
||||
u_int16_t *portp;
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int gaierror;
|
||||
const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
|
||||
const char *errormsg = NULL, *errorstr = NULL;
|
||||
char pwbuf[1024];
|
||||
|
||||
(void)signal(SIGINT, SIG_DFL);
|
||||
(void)signal(SIGQUIT, SIG_DFL);
|
||||
(void)signal(SIGTERM, SIG_DFL);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
int t = open(_PATH_TTY, O_RDWR);
|
||||
if (t >= 0) {
|
||||
ioctl(t, TIOCNOTTY, NULL);
|
||||
(void)close(t);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
portp = &((struct sockaddr_in *)fromp)->sin_port;
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
portp = &((struct sockaddr_in6 *)fromp)->sin6_port;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr),
|
||||
pbuf, sizeof(pbuf), niflags) != 0) {
|
||||
syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#ifdef IP_OPTIONS
|
||||
if (af == AF_INET) {
|
||||
|
||||
u_char optbuf[BUFSIZ/3];
|
||||
socklen_t optsize = sizeof(optbuf);
|
||||
int ipproto;
|
||||
unsigned int i;
|
||||
struct protoent *ip;
|
||||
|
||||
if ((ip = getprotobyname("ip")) != NULL)
|
||||
ipproto = ip->p_proto;
|
||||
else
|
||||
ipproto = IPPROTO_IP;
|
||||
if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
|
||||
optsize != 0) {
|
||||
for (i = 0; i < optsize;) {
|
||||
u_char c = optbuf[i];
|
||||
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
|
||||
syslog(LOG_NOTICE,
|
||||
"Connection refused from %s "
|
||||
"with IP option %s",
|
||||
inet_ntoa((
|
||||
(struct sockaddr_in *)fromp)->sin_addr),
|
||||
c == IPOPT_LSRR ? "LSRR" : "SSRR");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (c == IPOPT_EOL)
|
||||
break;
|
||||
i += (c == IPOPT_NOP) ? 1 : optbuf[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ntohs(*portp) >= IPPORT_RESERVED
|
||||
|| ntohs(*portp) < IPPORT_RESERVED / 2) {
|
||||
syslog(LOG_NOTICE|LOG_AUTH,
|
||||
"Connection from %s on illegal port %u",
|
||||
naddr, ntohs(*portp));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
(void) alarm(60);
|
||||
port = 0;
|
||||
for (;;) {
|
||||
char c;
|
||||
|
||||
if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
|
||||
if (cc < 0)
|
||||
syslog(LOG_ERR, "read: %m");
|
||||
(void)shutdown(0, SHUT_RDWR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (c == 0)
|
||||
break;
|
||||
port = port * 10 + c - '0';
|
||||
}
|
||||
|
||||
(void) alarm(0);
|
||||
if (port != 0) {
|
||||
int lport = IPPORT_RESERVED - 1;
|
||||
s = rresvport_af_addr(&lport, af, localp);
|
||||
if (s < 0) {
|
||||
syslog(LOG_ERR, "can't get stderr port: %m");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (port >= IPPORT_RESERVED) {
|
||||
syslog(LOG_ERR, "2nd port not reserved");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*portp = htons(port);
|
||||
if (connect(s, fromp, fromp->sa_len) < 0) {
|
||||
syslog(LOG_ERR, "connect second port %d: %m", port);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef notdef
|
||||
/* from inetd, socket is already on 0, 1, 2 */
|
||||
(void)dup2(f, STDIN_FILENO);
|
||||
(void)dup2(f, STDOUT_FILENO);
|
||||
(void)dup2(f, STDERR_FILENO);
|
||||
#endif
|
||||
if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr),
|
||||
NULL, 0, NI_NAMEREQD) == 0) {
|
||||
/*
|
||||
* If name returned by getnameinfo is in our domain,
|
||||
* attempt to verify that we haven't been fooled by someone
|
||||
* in a remote net; look up the name and check that this
|
||||
* address corresponds to the name.
|
||||
*/
|
||||
hostname = saddr;
|
||||
res0 = NULL;
|
||||
if (check_all || local_domain(saddr)) {
|
||||
(void)strlcpy(remotehost, saddr, sizeof(remotehost));
|
||||
errorhost = remotehost;
|
||||
(void)memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = fromp->sa_family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0);
|
||||
if (gaierror) {
|
||||
syslog(LOG_NOTICE,
|
||||
"Couldn't look up address for %s: %s",
|
||||
remotehost, gai_strerror(gaierror));
|
||||
errorstr =
|
||||
"Couldn't look up address for your host (%s)\n";
|
||||
hostname = naddr;
|
||||
} else {
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
if (res->ai_family != fromp->sa_family)
|
||||
continue;
|
||||
if (res->ai_addrlen != fromp->sa_len)
|
||||
continue;
|
||||
if (getnameinfo(res->ai_addr,
|
||||
res->ai_addrlen,
|
||||
raddr, sizeof(raddr), NULL, 0,
|
||||
niflags) == 0
|
||||
&& strcmp(naddr, raddr) == 0) {
|
||||
hostname = res->ai_canonname
|
||||
? res->ai_canonname
|
||||
: saddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res == NULL) {
|
||||
syslog(LOG_NOTICE,
|
||||
"Host addr %s not listed for host %s",
|
||||
naddr, res0->ai_canonname
|
||||
? res0->ai_canonname
|
||||
: saddr);
|
||||
errorstr =
|
||||
"Host address mismatch for %s\n";
|
||||
hostname = naddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf));
|
||||
hostname = hostnamebuf;
|
||||
if (res0)
|
||||
freeaddrinfo(res0);
|
||||
} else {
|
||||
(void)strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf));
|
||||
errorhost = hostname = hostnamebuf;
|
||||
}
|
||||
|
||||
(void)alarm(60);
|
||||
getstr(remuser, sizeof(remuser), "remuser");
|
||||
getstr(locuser, sizeof(locuser), "locuser");
|
||||
getstr(cmdbuf, sizeof(cmdbuf), "command");
|
||||
(void)alarm(0);
|
||||
|
||||
#ifdef USE_PAM
|
||||
pam_err = pam_start("rsh", locuser, &pamc, &pamh);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
rshd_errx(EXIT_FAILURE, incorrect);
|
||||
}
|
||||
|
||||
if ((pam_err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS ||
|
||||
(pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS){
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
rshd_errx(EXIT_FAILURE, incorrect);
|
||||
}
|
||||
|
||||
pam_err = pam_authenticate(pamh, 0);
|
||||
if (pam_err == PAM_SUCCESS) {
|
||||
if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
|
||||
(void)strlcpy(locuser, cp, sizeof(locuser));
|
||||
/* XXX truncation! */
|
||||
}
|
||||
pam_err = pam_acct_mgmt(pamh, 0);
|
||||
}
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
errorstr = incorrect;
|
||||
errormsg = pam_strerror(pamh, pam_err);
|
||||
goto badlogin;
|
||||
}
|
||||
#endif /* USE_PAM */
|
||||
setpwent();
|
||||
if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
|
||||
pwd == NULL) {
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: unknown login. cmd='%.80s'",
|
||||
remuser, hostname, locuser, cmdbuf);
|
||||
if (errorstr == NULL)
|
||||
errorstr = "Permission denied.";
|
||||
rshd_errx(EXIT_FAILURE, errorstr, errorhost);
|
||||
}
|
||||
#ifdef LOGIN_CAP
|
||||
lc = login_getclass(pwd ? pwd->pw_class : NULL);
|
||||
#endif
|
||||
|
||||
if (chdir(pwd->pw_dir) < 0) {
|
||||
if (chdir("/") < 0
|
||||
#ifdef LOGIN_CAP
|
||||
|| login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0)
|
||||
#endif
|
||||
) {
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: no home directory. cmd='%.80s'",
|
||||
remuser, hostname, locuser, cmdbuf);
|
||||
rshd_errx(EXIT_SUCCESS, "No remote home directory.");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_PAM
|
||||
if (errorstr ||
|
||||
(pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
|
||||
iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser,
|
||||
locuser) < 0)) {
|
||||
errormsg = __rcmd_errstr ? __rcmd_errstr : "unknown error";
|
||||
if (errorstr == NULL)
|
||||
errorstr = "Permission denied.";
|
||||
goto badlogin;
|
||||
}
|
||||
|
||||
if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK))
|
||||
rshd_errx(EXIT_FAILURE, "Logins currently disabled.");
|
||||
#endif
|
||||
|
||||
#ifdef LOGIN_CAP
|
||||
/*
|
||||
* PAM modules might add supplementary groups in
|
||||
* pam_setcred(), so initialize them first.
|
||||
* But we need to open the session as root.
|
||||
*/
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
|
||||
syslog(LOG_ERR, "setusercontext: %m");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
initgroups(pwd->pw_name, pwd->pw_gid);
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
|
||||
syslog(LOG_ERR, "pam_open_session: %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
} else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED))
|
||||
!= PAM_SUCCESS) {
|
||||
syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err));
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)write(STDERR_FILENO, "\0", 1);
|
||||
sent_null = 1;
|
||||
|
||||
if (port) {
|
||||
if (pipe(pv) < 0)
|
||||
rshd_errx(EXIT_FAILURE, "Can't make pipe. (%s)",
|
||||
strerror(errno));
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
|
||||
strerror(errno));
|
||||
if (pid) {
|
||||
(void)close(STDIN_FILENO);
|
||||
(void)close(STDOUT_FILENO);
|
||||
(void)close(STDERR_FILENO);
|
||||
(void)close(pv[1]);
|
||||
|
||||
set[0].fd = s;
|
||||
set[0].events = POLLIN;
|
||||
set[1].fd = pv[0];
|
||||
set[1].events = POLLIN;
|
||||
ioctl(pv[0], FIONBIO, (char *)&one);
|
||||
|
||||
/* should set s nbio! */
|
||||
do {
|
||||
#ifdef __minix
|
||||
if (set[0].events == 0 && set[1].events == 0)
|
||||
break;
|
||||
#endif /* __minix */
|
||||
if (poll(set, 2, INFTIM) < 0)
|
||||
break;
|
||||
if (set[0].revents & POLLIN) {
|
||||
int ret;
|
||||
|
||||
ret = read(s, &sig, 1);
|
||||
if (ret <= 0)
|
||||
set[0].events = 0;
|
||||
else
|
||||
killpg(pid, sig);
|
||||
}
|
||||
if (set[1].revents & POLLIN) {
|
||||
errno = 0;
|
||||
cc = read(pv[0], buf, sizeof(buf));
|
||||
if (cc <= 0) {
|
||||
shutdown(s, SHUT_RDWR);
|
||||
set[1].events = 0;
|
||||
} else {
|
||||
(void)write(s, buf, cc);
|
||||
}
|
||||
}
|
||||
|
||||
} while ((set[0].revents | set[1].revents) & POLLIN);
|
||||
PAM_END;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
(void)close(s);
|
||||
(void)close(pv[0]);
|
||||
(void)dup2(pv[1], STDERR_FILENO);
|
||||
close(pv[1]);
|
||||
}
|
||||
#ifdef USE_PAM
|
||||
else {
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
|
||||
strerror(errno));
|
||||
if (pid) {
|
||||
pid_t xpid;
|
||||
int status;
|
||||
if ((xpid = waitpid(pid, &status, 0)) != pid) {
|
||||
pam_err = pam_close_session(pamh, 0);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
syslog(LOG_ERR,
|
||||
"pam_close_session: %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
}
|
||||
PAM_END;
|
||||
if (xpid != -1)
|
||||
syslog(LOG_WARNING,
|
||||
"wrong PID: %d != %d", pid, xpid);
|
||||
else
|
||||
syslog(LOG_WARNING,
|
||||
"wait pid=%d failed %m", pid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_CLOSEM
|
||||
(void)fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);
|
||||
#else
|
||||
for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
|
||||
(void)close(fd);
|
||||
#endif
|
||||
if (setsid() == -1)
|
||||
syslog(LOG_ERR, "setsid() failed: %m");
|
||||
#ifdef USE_PAM
|
||||
if (setlogin(pwd->pw_name) < 0)
|
||||
syslog(LOG_ERR, "setlogin() failed: %m");
|
||||
|
||||
if (*pwd->pw_shell == '\0')
|
||||
pwd->pw_shell = __UNCONST(_PATH_BSHELL);
|
||||
|
||||
(void)pam_setenv(pamh, "HOME", pwd->pw_dir, 1);
|
||||
(void)pam_setenv(pamh, "SHELL", pwd->pw_shell, 1);
|
||||
(void)pam_setenv(pamh, "USER", pwd->pw_name, 1);
|
||||
(void)pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1);
|
||||
environ = pam_getenvlist(pamh);
|
||||
(void)pam_end(pamh, pam_err);
|
||||
#else
|
||||
#ifdef LOGIN_CAP
|
||||
{
|
||||
char *sh;
|
||||
if ((sh = login_getcapstr(lc, "shell", NULL, NULL))) {
|
||||
if(!(sh = strdup(sh))) {
|
||||
syslog(LOG_ERR, "Cannot alloc mem");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pwd->pw_shell = sh;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
static char *envinit[] = { NULL };
|
||||
environ = envinit;
|
||||
}
|
||||
setenv("PATH", _PATH_DEFPATH, 1);
|
||||
setenv("HOME", pwd->pw_dir, 1);
|
||||
setenv("SHELL", pwd->pw_shell, 1);
|
||||
setenv("USER", pwd->pw_name, 1);
|
||||
#endif
|
||||
|
||||
cp = strrchr(pwd->pw_shell, '/');
|
||||
if (cp)
|
||||
cp++;
|
||||
else
|
||||
cp = pwd->pw_shell;
|
||||
|
||||
#ifdef LOGIN_CAP
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid,
|
||||
LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
|
||||
syslog(LOG_ERR, "setusercontext(): %m");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
login_close(lc);
|
||||
#else
|
||||
(void)setgid((gid_t)pwd->pw_gid);
|
||||
(void)setuid((uid_t)pwd->pw_uid);
|
||||
#endif
|
||||
endpwent();
|
||||
if (log_success || pwd->pw_uid == 0) {
|
||||
syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
|
||||
remuser, hostname, locuser, cmdbuf);
|
||||
}
|
||||
(void)execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL);
|
||||
rshd_errx(EXIT_FAILURE, "%s: %s", pwd->pw_shell, strerror(errno));
|
||||
badlogin:
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
|
||||
remuser, hostname, locuser, errormsg, cmdbuf);
|
||||
rshd_errx(EXIT_FAILURE, errorstr, errorhost);
|
||||
}
|
||||
|
||||
/*
|
||||
* Report error to client. Note: can't be used until second socket has
|
||||
* connected to client, or older clients will hang waiting for that
|
||||
* connection first.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void
|
||||
rshd_errx(int error, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int len, rv;
|
||||
char *bp, buf[BUFSIZ];
|
||||
va_start(ap, fmt);
|
||||
bp = buf;
|
||||
if (sent_null == 0) {
|
||||
*bp++ = 1;
|
||||
len = 1;
|
||||
} else
|
||||
len = 0;
|
||||
rv = vsnprintf(bp, sizeof(buf) - 2, fmt, ap);
|
||||
bp[rv++] = '\n';
|
||||
(void)write(STDERR_FILENO, buf, len + rv);
|
||||
va_end(ap);
|
||||
exit(error);
|
||||
}
|
||||
|
||||
static void
|
||||
getstr(char *buf, int cnt, const char *err)
|
||||
{
|
||||
char c;
|
||||
|
||||
do {
|
||||
if (read(STDIN_FILENO, &c, 1) != 1)
|
||||
exit(EXIT_FAILURE);
|
||||
*buf++ = c;
|
||||
if (--cnt == 0)
|
||||
rshd_errx(EXIT_FAILURE, "%s too long", err);
|
||||
} while (c != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether host h is in our local domain,
|
||||
* defined as sharing the last two components of the domain part,
|
||||
* or the entire domain part if the local domain has only one component.
|
||||
* If either name is unqualified (contains no '.'),
|
||||
* assume that the host is local, as it will be
|
||||
* interpreted as such.
|
||||
*/
|
||||
static int
|
||||
local_domain(char *h)
|
||||
{
|
||||
char localhost[MAXHOSTNAMELEN + 1];
|
||||
char *p1, *p2;
|
||||
|
||||
localhost[0] = 0;
|
||||
(void)gethostname(localhost, sizeof(localhost));
|
||||
localhost[sizeof(localhost) - 1] = '\0';
|
||||
p1 = topdomain(localhost);
|
||||
p2 = topdomain(h);
|
||||
if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static char *
|
||||
topdomain(char *h)
|
||||
{
|
||||
char *p, *maybe = NULL;
|
||||
int dots = 0;
|
||||
|
||||
for (p = h + strlen(h); p >= h; p--) {
|
||||
if (*p == '.') {
|
||||
if (++dots == 2)
|
||||
return (p);
|
||||
maybe = p;
|
||||
}
|
||||
}
|
||||
return (maybe);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
syslog(LOG_ERR, "Usage: %s [-%s]", getprogname(), OPTIONS);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
|
@ -19,9 +19,9 @@ SUBDIR= add_route arp at backup btrace \
|
|||
nonamed \
|
||||
postinstall prep printroot \
|
||||
profile progressbar pr_routes ps pwdauth \
|
||||
ramdisk rarpd rawspeed rcp readclock \
|
||||
ramdisk rarpd rawspeed readclock \
|
||||
remsync rget rlogin \
|
||||
rotate rsh rshd service setup \
|
||||
rotate service setup \
|
||||
slip spell sprofalyze sprofdiff srccrc \
|
||||
svclog svrctl swifi synctree sysenv \
|
||||
tcpd tcpdp tcpstat telnet \
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
PROG= rcp
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,849 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1983 Regents of the University of California.
|
||||
* All rights reserved. The Berkeley software License Agreement
|
||||
* specifies the terms and conditions for redistribution.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
|
||||
All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rcp.c 1.1 87/12/21 SMI"; /* from UCB 5.3 6/8/85"*/
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* rcp
|
||||
*/
|
||||
|
||||
#define NAMESERVER
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <utime.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <net/netlib.h>
|
||||
|
||||
#if __STDC__
|
||||
#define PROTO(func, args) func args
|
||||
#else
|
||||
#define PROTO(func, args) func ()
|
||||
#endif /* __STDC__ */
|
||||
|
||||
PROTO (int main, (int argc, char *argv[]));
|
||||
PROTO (void lostconn, (int sig));
|
||||
PROTO (void error, (char *fmt, ...) );
|
||||
PROTO (int response, (void) );
|
||||
PROTO (void source, (int argc, char *argv[]) );
|
||||
PROTO (void sink, (int argc, char *argv[]) );
|
||||
PROTO (void usage, (void) );
|
||||
PROTO (char *colon, (char *cp) );
|
||||
PROTO (int okname, (char *cp0) );
|
||||
PROTO (int susystem, (char *s) );
|
||||
PROTO (void verifydir, (char *cp) );
|
||||
PROTO (void rsource, (char *name, struct stat *statp) );
|
||||
PROTO (struct buffer *allocbuf, (struct buffer *bp, int fd, int blksize) );
|
||||
|
||||
#define vfork fork
|
||||
|
||||
int rem;
|
||||
int errs;
|
||||
int errno;
|
||||
int iamremote, targetshouldbedirectory;
|
||||
int iamrecursive;
|
||||
int myuid; /* uid of invoker */
|
||||
int pflag;
|
||||
struct passwd *pwd;
|
||||
int userid;
|
||||
int port;
|
||||
|
||||
struct buffer {
|
||||
int cnt;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
|
||||
#define ga() (void) write(rem, "", 1)
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *targ, *host, *src;
|
||||
#ifndef NAMESERVER
|
||||
char *suser, *tuser;
|
||||
#else /* NAMESERVER */
|
||||
char *suser, *tuser, *thost;
|
||||
#endif /* NAMESERVER */
|
||||
int i;
|
||||
char buf[BUFSIZ], cmd[16];
|
||||
struct servent *sp;
|
||||
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL) {
|
||||
fprintf(stderr, "rcp: shell/tcp: unknown service\n");
|
||||
exit(1);
|
||||
}
|
||||
port = sp->s_port;
|
||||
pwd = getpwuid(userid = getuid());
|
||||
if (pwd == 0) {
|
||||
fprintf(stderr, "who are you?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef NOT_DEF
|
||||
/*
|
||||
* This is a kludge to allow seteuid to user before touching
|
||||
* files and seteuid root before doing rcmd so we can open
|
||||
* the socket.
|
||||
*/
|
||||
myuid = getuid();
|
||||
if (setruid(0) < 0) {
|
||||
perror("setruid root");
|
||||
exit(1);
|
||||
}
|
||||
seteuid(myuid);
|
||||
#endif
|
||||
|
||||
for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
|
||||
(*argv)++;
|
||||
while (**argv) switch (*(*argv)++) {
|
||||
|
||||
case 'r':
|
||||
iamrecursive++;
|
||||
break;
|
||||
|
||||
case 'p': /* preserve mtimes and atimes */
|
||||
pflag++;
|
||||
break;
|
||||
|
||||
/* The rest of these are not for users. */
|
||||
case 'd':
|
||||
targetshouldbedirectory = 1;
|
||||
break;
|
||||
|
||||
case 'f': /* "from" */
|
||||
iamremote = 1;
|
||||
(void) response();
|
||||
source(--argc, ++argv);
|
||||
exit(errs);
|
||||
|
||||
case 't': /* "to" */
|
||||
iamremote = 1;
|
||||
sink(--argc, ++argv);
|
||||
exit(errs);
|
||||
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (iamremote)
|
||||
{
|
||||
close(2);
|
||||
open("/dev/tty", 2);
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
rem = -1;
|
||||
if (argc > 2)
|
||||
targetshouldbedirectory = 1;
|
||||
(void) sprintf(cmd, "rcp%s%s%s",
|
||||
iamrecursive ? " -r" : "", pflag ? " -p" : "",
|
||||
targetshouldbedirectory ? " -d" : "");
|
||||
(void) signal(SIGPIPE, lostconn);
|
||||
targ = colon(argv[argc - 1]);
|
||||
if (targ) { /* ... to remote */
|
||||
*targ++ = 0;
|
||||
if (*targ == 0)
|
||||
targ = ".";
|
||||
#ifndef NAMESERVER
|
||||
tuser = strrchr(argv[argc - 1], '.');
|
||||
if (tuser) {
|
||||
*tuser++ = 0;
|
||||
if (!okname(tuser))
|
||||
exit(1);
|
||||
} else
|
||||
tuser = pwd->pw_name;
|
||||
#else /* NAMESERVER */
|
||||
thost = strchr(argv[argc - 1], '@');
|
||||
if (thost) {
|
||||
*thost++ = 0;
|
||||
tuser = argv[argc - 1];
|
||||
if (*tuser == '\0')
|
||||
tuser = pwd->pw_name;
|
||||
else if (!okname(tuser))
|
||||
exit(1);
|
||||
} else {
|
||||
thost = argv[argc - 1];
|
||||
tuser = pwd->pw_name;
|
||||
}
|
||||
#endif /* NAMESERVER */
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
src = colon(argv[i]);
|
||||
if (src) { /* remote to remote */
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
src = ".";
|
||||
#ifndef NAMESERVER
|
||||
suser = strrchr(argv[i], '.');
|
||||
if (suser) {
|
||||
*suser++ = 0;
|
||||
if (!okname(suser))
|
||||
#else /* NAMESERVER */
|
||||
host = strchr(argv[i], '@');
|
||||
if (host) {
|
||||
*host++ = 0;
|
||||
suser = argv[i];
|
||||
if (*suser == '\0')
|
||||
suser = pwd->pw_name;
|
||||
else if (!okname(suser))
|
||||
#endif /* NAMESERVER */
|
||||
continue;
|
||||
#ifndef NAMESERVER
|
||||
(void) sprintf(buf, "rsh %s -l %s -n %s %s '%s.%s:%s'",
|
||||
argv[i], suser, cmd, src,
|
||||
argv[argc - 1], tuser, targ);
|
||||
} else
|
||||
(void) sprintf(buf, "rsh %s -n %s %s '%s.%s:%s'",
|
||||
argv[i], cmd, src,
|
||||
argv[argc - 1], tuser, targ);
|
||||
#else /* NAMESERVER */
|
||||
(void) sprintf(buf, "rsh %s -l %s -n %s %s '%s@%s:%s'",
|
||||
host, suser, cmd, src,
|
||||
tuser, thost, targ);
|
||||
} else
|
||||
(void) sprintf(buf, "rsh %s -n %s %s '%s@%s:%s'",
|
||||
argv[i], cmd, src,
|
||||
tuser, thost, targ);
|
||||
#endif /* NAMESERVER */
|
||||
(void) susystem(buf);
|
||||
} else { /* local to remote */
|
||||
if (rem == -1) {
|
||||
(void) sprintf(buf, "%s -t %s",
|
||||
cmd, targ);
|
||||
#ifndef NAMESERVER
|
||||
host = argv[argc - 1];
|
||||
#else /* NAMESERVER */
|
||||
host = thost;
|
||||
#endif /* NAMESERVER */
|
||||
#ifdef NOT_DEF
|
||||
if (seteuid(0) < 0) {
|
||||
perror("seteuid root");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
rem = rcmd(&host, port, pwd->pw_name,
|
||||
tuser, buf, 0);
|
||||
#ifdef NO_DEF
|
||||
seteuid(myuid);
|
||||
#endif
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
if (response() < 0)
|
||||
exit(1);
|
||||
}
|
||||
source(1, argv+i);
|
||||
}
|
||||
}
|
||||
} else { /* ... to local */
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(argv[argc - 1]);
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
src = colon(argv[i]);
|
||||
if (src == 0) { /* local to local */
|
||||
(void) sprintf(buf, "cp%s%s %s %s",
|
||||
iamrecursive ? " -r" : "",
|
||||
pflag ? " -p" : "",
|
||||
argv[i], argv[argc - 1]);
|
||||
(void) susystem(buf);
|
||||
} else { /* remote to local */
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
src = ".";
|
||||
#ifndef NAMESERVER
|
||||
suser = strrchr(argv[i], '.');
|
||||
if (suser) {
|
||||
*suser++ = 0;
|
||||
if (!okname(suser))
|
||||
#else /* NAMESERVER */
|
||||
host = strchr(argv[i], '@');
|
||||
if (host) {
|
||||
*host++ = 0;
|
||||
suser = argv[i];
|
||||
if (*suser == '\0')
|
||||
suser = pwd->pw_name;
|
||||
else if (!okname(suser))
|
||||
#endif /* NAMESERVER */
|
||||
continue;
|
||||
#ifndef NAMESERVER
|
||||
} else
|
||||
#else /* NAMESERVER */
|
||||
} else {
|
||||
host = argv[i];
|
||||
#endif /* NAMESERVER */
|
||||
suser = pwd->pw_name;
|
||||
#ifdef NAMESERVER
|
||||
}
|
||||
#endif /* NAMESERVER */
|
||||
(void) sprintf(buf, "%s -f %s", cmd, src);
|
||||
#ifndef NAMESERVER
|
||||
host = argv[i];
|
||||
#endif /* NAMESERVER */
|
||||
#ifdef NOT_DEF
|
||||
if (seteuid(0) < 0) {
|
||||
perror("seteuid root");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
rem = rcmd(&host, port, pwd->pw_name, suser,
|
||||
buf, 0);
|
||||
#ifdef NOT_DEF
|
||||
seteuid(myuid);
|
||||
#endif
|
||||
if (rem < 0) {
|
||||
errs++;
|
||||
continue;
|
||||
}
|
||||
sink(1, argv+argc-1);
|
||||
(void) close(rem);
|
||||
rem = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
void
|
||||
verifydir(cp)
|
||||
char *cp;
|
||||
{
|
||||
struct stat stb;
|
||||
|
||||
if (stat(cp, &stb) >= 0) {
|
||||
if ((stb.st_mode & S_IFMT) == S_IFDIR)
|
||||
return;
|
||||
errno = ENOTDIR;
|
||||
}
|
||||
error("rcp: %s: %s.\n", cp, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *
|
||||
colon(cp)
|
||||
char *cp;
|
||||
{
|
||||
|
||||
while (*cp) {
|
||||
if (*cp == ':')
|
||||
return (cp);
|
||||
if (*cp == '/')
|
||||
return (0);
|
||||
cp++;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
okname(cp0)
|
||||
char *cp0;
|
||||
{
|
||||
register char *cp = cp0;
|
||||
register int c;
|
||||
|
||||
do {
|
||||
c = *cp;
|
||||
if (c & 0200)
|
||||
goto bad;
|
||||
if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
|
||||
goto bad;
|
||||
cp++;
|
||||
} while (*cp);
|
||||
return (1);
|
||||
bad:
|
||||
fprintf(stderr, "rcp: invalid user name %s\n", cp0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
susystem(s)
|
||||
char *s;
|
||||
{
|
||||
int status, pid, w;
|
||||
register void PROTO ((*istat), (int) ), PROTO ((*qstat), (int) );
|
||||
|
||||
if ((pid = vfork()) == 0) {
|
||||
#ifdef NOT_DEF
|
||||
(void) setruid(myuid);
|
||||
#endif
|
||||
execl("/bin/sh", "sh", "-c", s, (char *)0);
|
||||
_exit(127);
|
||||
}
|
||||
istat = signal(SIGINT, SIG_IGN);
|
||||
qstat = signal(SIGQUIT, SIG_IGN);
|
||||
while ((w = wait(&status)) != pid && w != -1)
|
||||
;
|
||||
if (w == -1)
|
||||
status = -1;
|
||||
(void) signal(SIGINT, istat);
|
||||
(void) signal(SIGQUIT, qstat);
|
||||
return (status);
|
||||
}
|
||||
|
||||
void
|
||||
source(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *last, *name;
|
||||
struct stat stb;
|
||||
static struct buffer buffer;
|
||||
struct buffer *bp;
|
||||
int x, sizerr, f, amt;
|
||||
off_t i;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
for (x = 0; x < argc; x++) {
|
||||
name = argv[x];
|
||||
if ((f = open(name, 0)) < 0) {
|
||||
error("rcp: %s: %s\n", name, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (fstat(f, &stb) < 0)
|
||||
goto notreg;
|
||||
switch (stb.st_mode&S_IFMT) {
|
||||
|
||||
case S_IFREG:
|
||||
break;
|
||||
|
||||
case S_IFDIR:
|
||||
if (iamrecursive) {
|
||||
(void) close(f);
|
||||
rsource(name, &stb);
|
||||
continue;
|
||||
}
|
||||
/* fall into ... */
|
||||
default:
|
||||
notreg:
|
||||
(void) close(f);
|
||||
error("rcp: %s: not a plain file\n", name);
|
||||
continue;
|
||||
}
|
||||
last = strrchr(name, '/');
|
||||
if (last == 0)
|
||||
last = name;
|
||||
else
|
||||
last++;
|
||||
if (pflag) {
|
||||
/*
|
||||
* Make it compatible with possible future
|
||||
* versions expecting microseconds.
|
||||
*/
|
||||
(void) sprintf(buf, "T%d 0 %d 0\n",
|
||||
stb.st_mtime, stb.st_atime);
|
||||
(void) write(rem, buf, strlen(buf));
|
||||
if (response() < 0) {
|
||||
(void) close(f);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(void) sprintf(buf, "C%04o %lld %s\n",
|
||||
stb.st_mode&07777, stb.st_size, last);
|
||||
(void) write(rem, buf, strlen(buf));
|
||||
if (response() < 0) {
|
||||
(void) close(f);
|
||||
continue;
|
||||
}
|
||||
if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
|
||||
(void) close(f);
|
||||
continue;
|
||||
}
|
||||
sizerr = 0;
|
||||
for (i = 0; i < stb.st_size; i += bp->cnt) {
|
||||
amt = bp->cnt;
|
||||
if (i + amt > stb.st_size)
|
||||
amt = stb.st_size - i;
|
||||
if (sizerr == 0 && read(f, bp->buf, amt) != amt)
|
||||
sizerr = 1;
|
||||
(void) write(rem, bp->buf, amt);
|
||||
}
|
||||
(void) close(f);
|
||||
if (sizerr == 0)
|
||||
ga();
|
||||
else
|
||||
error("rcp: %s: file changed size\n", name);
|
||||
(void) response();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rsource(name, statp)
|
||||
char *name;
|
||||
struct stat *statp;
|
||||
{
|
||||
DIR *d = opendir(name);
|
||||
char *last;
|
||||
struct dirent *dp;
|
||||
char buf[BUFSIZ];
|
||||
char *bufv[1];
|
||||
|
||||
if (d == 0) {
|
||||
error("rcp: %s: %s\n", name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
last = strrchr(name, '/');
|
||||
if (last == 0)
|
||||
last = name;
|
||||
else
|
||||
last++;
|
||||
if (pflag) {
|
||||
(void) sprintf(buf, "T%d 0 %d 0\n",
|
||||
statp->st_mtime, statp->st_atime);
|
||||
(void) write(rem, buf, strlen(buf));
|
||||
if (response() < 0) {
|
||||
closedir(d);
|
||||
return;
|
||||
}
|
||||
}
|
||||
(void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
|
||||
(void) write(rem, buf, strlen(buf));
|
||||
if (response() < 0) {
|
||||
closedir(d);
|
||||
return;
|
||||
}
|
||||
while ((dp = readdir(d))) {
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
|
||||
continue;
|
||||
if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
|
||||
error("%s/%s: Name too long.\n", name, dp->d_name);
|
||||
continue;
|
||||
}
|
||||
(void) sprintf(buf, "%s/%s", name, dp->d_name);
|
||||
bufv[0] = buf;
|
||||
source(1, bufv);
|
||||
}
|
||||
closedir(d);
|
||||
(void) write(rem, "E\n", 2);
|
||||
(void) response();
|
||||
}
|
||||
|
||||
int
|
||||
response()
|
||||
{
|
||||
char resp, c, rbuf[BUFSIZ], *cp = rbuf;
|
||||
|
||||
if (read(rem, &resp, 1) != 1)
|
||||
lostconn(0);
|
||||
switch (resp) {
|
||||
|
||||
case 0: /* ok */
|
||||
return (0);
|
||||
|
||||
default:
|
||||
*cp++ = resp;
|
||||
/* fall into... */
|
||||
case 1: /* error, followed by err msg */
|
||||
case 2: /* fatal error, "" */
|
||||
do {
|
||||
if (read(rem, &c, 1) != 1)
|
||||
lostconn(0);
|
||||
*cp++ = c;
|
||||
} while (cp < &rbuf[BUFSIZ] && c != '\n');
|
||||
if (iamremote == 0)
|
||||
(void) write(2, rbuf, cp - rbuf);
|
||||
errs++;
|
||||
if (resp == 1)
|
||||
return (-1);
|
||||
exit(1);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
void
|
||||
lostconn(sig)
|
||||
int sig;
|
||||
{
|
||||
|
||||
if (iamremote == 0)
|
||||
fprintf(stderr, "rcp: lost connection\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
sink(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
off_t i, j, size;
|
||||
char *targ, *whopp, *cp;
|
||||
int of, mode, wrerr, exists, first, count, amt;
|
||||
struct buffer *bp;
|
||||
static struct buffer buffer;
|
||||
struct stat stb;
|
||||
int targisdir = 0;
|
||||
int mask = umask(0);
|
||||
char *myargv[1];
|
||||
char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
|
||||
int setimes = 0;
|
||||
struct utimbuf utimbuf;
|
||||
#define atime utimbuf.actime
|
||||
#define mtime utimbuf.modtime
|
||||
time_t dummy;
|
||||
#define SCREWUP(str) { whopp = str; goto screwup; }
|
||||
|
||||
#ifdef NOT_DEF
|
||||
seteuid(pwd->pw_uid);
|
||||
#endif
|
||||
if (!pflag)
|
||||
(void) umask(mask);
|
||||
if (argc != 1) {
|
||||
error("rcp: ambiguous target\n");
|
||||
exit(1);
|
||||
}
|
||||
targ = *argv;
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(targ);
|
||||
ga();
|
||||
if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
|
||||
targisdir = 1;
|
||||
for (first = 1; ; first = 0) {
|
||||
cp = cmdbuf;
|
||||
if (read(rem, cp, 1) <= 0)
|
||||
return;
|
||||
if (*cp++ == '\n')
|
||||
SCREWUP("unexpected '\\n'");
|
||||
do {
|
||||
if (read(rem, cp, 1) != 1)
|
||||
SCREWUP("lost connection");
|
||||
} while (*cp++ != '\n');
|
||||
*cp = 0;
|
||||
if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
|
||||
if (iamremote == 0)
|
||||
(void) write(2, cmdbuf+1, strlen(cmdbuf+1));
|
||||
if (cmdbuf[0] == '\02')
|
||||
exit(1);
|
||||
errs++;
|
||||
continue;
|
||||
}
|
||||
*--cp = 0;
|
||||
cp = cmdbuf;
|
||||
if (*cp == 'E') {
|
||||
ga();
|
||||
return;
|
||||
}
|
||||
|
||||
#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
|
||||
if (*cp == 'T') {
|
||||
setimes++;
|
||||
cp++;
|
||||
getnum(mtime);
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("mtime.sec not delimited");
|
||||
getnum(dummy);
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("mtime.usec not delimited");
|
||||
getnum(atime);
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("atime.sec not delimited");
|
||||
getnum(dummy);
|
||||
if (*cp++ != '\0')
|
||||
SCREWUP("atime.usec not delimited");
|
||||
ga();
|
||||
continue;
|
||||
}
|
||||
if (*cp != 'C' && *cp != 'D') {
|
||||
/*
|
||||
* Check for the case "rcp remote:foo\* local:bar".
|
||||
* In this case, the line "No match." can be returned
|
||||
* by the shell before the rcp command on the remote is
|
||||
* executed so the ^Aerror_message convention isn't
|
||||
* followed.
|
||||
*/
|
||||
if (first) {
|
||||
error("%s\n", cp);
|
||||
exit(1);
|
||||
}
|
||||
SCREWUP("expected control record");
|
||||
}
|
||||
cp++;
|
||||
mode = 0;
|
||||
for (; cp < cmdbuf+5; cp++) {
|
||||
if (*cp < '0' || *cp > '7')
|
||||
SCREWUP("bad mode");
|
||||
mode = (mode << 3) | (*cp - '0');
|
||||
}
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("mode not delimited");
|
||||
size = 0;
|
||||
while (isdigit(*cp))
|
||||
size = size * 10 + (*cp++ - '0');
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("size not delimited");
|
||||
if (targisdir)
|
||||
(void) sprintf(nambuf, "%s%s%s", targ,
|
||||
*targ ? "/" : "", cp);
|
||||
else
|
||||
(void) strcpy(nambuf, targ);
|
||||
exists = stat(nambuf, &stb) == 0;
|
||||
if (cmdbuf[0] == 'D') {
|
||||
if (exists) {
|
||||
if ((stb.st_mode&S_IFMT) != S_IFDIR) {
|
||||
errno = ENOTDIR;
|
||||
goto bad;
|
||||
}
|
||||
if (pflag)
|
||||
(void) chmod(nambuf, mode);
|
||||
} else if (mkdir(nambuf, mode) < 0)
|
||||
goto bad;
|
||||
myargv[0] = nambuf;
|
||||
sink(1, myargv);
|
||||
if (setimes) {
|
||||
setimes = 0;
|
||||
if (utime(nambuf, &utimbuf) < 0)
|
||||
error("rcp: can't set times on %s: %s\n",
|
||||
nambuf, strerror(errno));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((of = creat(nambuf, mode)) < 0) {
|
||||
bad:
|
||||
error("rcp: %s: %s\n", nambuf, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (exists && pflag)
|
||||
(void) chmod(nambuf, mode);
|
||||
ga();
|
||||
if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) {
|
||||
(void) close(of);
|
||||
continue;
|
||||
}
|
||||
cp = bp->buf;
|
||||
count = 0;
|
||||
wrerr = 0;
|
||||
for (i = 0; i < size; i += BUFSIZ) {
|
||||
amt = BUFSIZ;
|
||||
if (i + amt > size)
|
||||
amt = size - i;
|
||||
count += amt;
|
||||
do {
|
||||
j = read(rem, cp, amt);
|
||||
if (j <= 0)
|
||||
exit(1);
|
||||
amt -= j;
|
||||
cp += j;
|
||||
} while (amt > 0);
|
||||
if (count == bp->cnt) {
|
||||
if (wrerr == 0 &&
|
||||
write(of, bp->buf, count) != count)
|
||||
wrerr++;
|
||||
count = 0;
|
||||
cp = bp->buf;
|
||||
}
|
||||
}
|
||||
if (count != 0 && wrerr == 0 &&
|
||||
write(of, bp->buf, count) != count)
|
||||
wrerr++;
|
||||
(void) close(of);
|
||||
(void) response();
|
||||
if (setimes) {
|
||||
setimes = 0;
|
||||
if (utime(nambuf, &utimbuf) < 0)
|
||||
error("rcp: can't set times on %s: %s\n",
|
||||
nambuf, strerror(errno));
|
||||
}
|
||||
if (wrerr)
|
||||
error("rcp: %s: %s\n", nambuf, strerror(errno));
|
||||
else
|
||||
ga();
|
||||
}
|
||||
screwup:
|
||||
error("rcp: protocol screwup: %s\n", whopp);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct buffer *
|
||||
allocbuf(bp, fd, blksize)
|
||||
struct buffer *bp;
|
||||
int fd, blksize;
|
||||
{
|
||||
struct stat stb;
|
||||
int size;
|
||||
|
||||
if (fstat(fd, &stb) < 0) {
|
||||
error("rcp: fstat: %s\n", strerror(errno));
|
||||
return ((struct buffer *)0);
|
||||
}
|
||||
size= 0;
|
||||
#if NOT_DEF
|
||||
size = roundup(stb.st_blksize, blksize);
|
||||
#endif
|
||||
if (size == 0)
|
||||
size = blksize;
|
||||
if (bp->cnt < size) {
|
||||
if (bp->buf != 0)
|
||||
free(bp->buf);
|
||||
bp->buf = (char *)malloc((unsigned) size);
|
||||
if (bp->buf == 0) {
|
||||
error("rcp: malloc: out of memory\n");
|
||||
return ((struct buffer *)0);
|
||||
}
|
||||
}
|
||||
bp->cnt = size;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
#if __STDC__
|
||||
void
|
||||
error (char *fmt, ...)
|
||||
#else
|
||||
error(fmt)
|
||||
char *fmt;
|
||||
#endif
|
||||
{
|
||||
char buf[BUFSIZ], *cp = buf;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
errs++;
|
||||
*cp++ = 1;
|
||||
(void) vsprintf(cp, fmt, ap);
|
||||
va_end(ap);
|
||||
(void) write(rem, buf, strlen(buf));
|
||||
if (iamremote == 0)
|
||||
(void) write(2, buf+1, strlen(buf+1));
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n");
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
PROG= rsh
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,571 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 1983, 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
|
||||
All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rsh.c 5.24 (Berkeley) 7/1/91";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* $Source$
|
||||
* $Header$
|
||||
*/
|
||||
|
||||
#if defined(__minix)
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/netlib.h>
|
||||
#include <netdb.h>
|
||||
int main( int argc, char *argv[] );
|
||||
void usage( void );
|
||||
char *copyargs( char **argv );
|
||||
void sendsig( int signo );
|
||||
void talk( int nflag, long omask, int pid, int rem );
|
||||
|
||||
#define _PATH_RLOGIN1 "/bin/rlogin"
|
||||
#define _PATH_RLOGIN2 "/usr/bin/rlogin"
|
||||
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <varargs.h>
|
||||
#include "pathnames.h"
|
||||
#endif
|
||||
|
||||
#ifdef KERBEROS
|
||||
#include <kerberosIV/des.h>
|
||||
#include <kerberosIV/krb.h>
|
||||
|
||||
CREDENTIALS cred;
|
||||
Key_schedule schedule;
|
||||
int use_kerberos = 1, doencrypt;
|
||||
char dst_realm_buf[REALM_SZ], *dest_realm;
|
||||
extern char *krb_realmofhost();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* rsh - remote shell
|
||||
*/
|
||||
extern int errno;
|
||||
int rfd2;
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
struct passwd *pw;
|
||||
struct servent *sp;
|
||||
long omask;
|
||||
int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
|
||||
register char *p;
|
||||
char *args, *host, *user;
|
||||
#if !defined(__minix)
|
||||
char *copyargs();
|
||||
void sendsig();
|
||||
#endif
|
||||
|
||||
argoff = asrsh = dflag = nflag = 0;
|
||||
one = 1;
|
||||
host = user = NULL;
|
||||
|
||||
/* if called as something other than "rsh", use it as the host name */
|
||||
if ((p = rindex(argv[0], '/')))
|
||||
++p;
|
||||
else
|
||||
p = argv[0];
|
||||
if (strcmp(p, "rsh"))
|
||||
host = p;
|
||||
else
|
||||
asrsh = 1;
|
||||
|
||||
/* handle "rsh host flags" */
|
||||
if (!host && argc > 2 && argv[1][0] != '-') {
|
||||
host = argv[1];
|
||||
argoff = 1;
|
||||
}
|
||||
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
#define OPTIONS "8KLdek:l:nwx"
|
||||
#else
|
||||
#define OPTIONS "8KLdek:l:nw"
|
||||
#endif
|
||||
#else
|
||||
#define OPTIONS "8KLdel:nw"
|
||||
#endif
|
||||
while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
|
||||
switch(ch) {
|
||||
case 'K':
|
||||
#ifdef KERBEROS
|
||||
use_kerberos = 0;
|
||||
#endif
|
||||
break;
|
||||
case 'L': /* -8Lew are ignored to allow rlogin aliases */
|
||||
case 'e':
|
||||
case 'w':
|
||||
case '8':
|
||||
break;
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'l':
|
||||
user = optarg;
|
||||
break;
|
||||
#ifdef KERBEROS
|
||||
case 'k':
|
||||
dest_realm = dst_realm_buf;
|
||||
strncpy(dest_realm, optarg, REALM_SZ);
|
||||
break;
|
||||
#endif
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
case 'x':
|
||||
doencrypt = 1;
|
||||
des_set_key(cred.session, schedule);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
optind += argoff;
|
||||
|
||||
/* if haven't gotten a host yet, do so */
|
||||
if (!host && !(host = argv[optind++]))
|
||||
usage();
|
||||
|
||||
/* if no further arguments, must have been called as rlogin. */
|
||||
if (!argv[optind]) {
|
||||
if (asrsh)
|
||||
*argv = "rlogin";
|
||||
execv(_PATH_RLOGIN1, argv);
|
||||
execv(_PATH_RLOGIN2, argv);
|
||||
(void)fprintf(stderr, "rsh: can't exec rlogin\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!(pw = getpwuid(uid = getuid()))) {
|
||||
(void)fprintf(stderr, "rsh: unknown user id.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!user)
|
||||
user = pw->pw_name;
|
||||
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
/* -x turns off -n */
|
||||
if (doencrypt)
|
||||
nflag = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
args = copyargs(argv);
|
||||
|
||||
sp = NULL;
|
||||
#ifdef KERBEROS
|
||||
if (use_kerberos) {
|
||||
sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
|
||||
if (sp == NULL) {
|
||||
use_kerberos = 0;
|
||||
warning("can't get entry for %s/tcp service",
|
||||
doencrypt ? "ekshell" : "kshell");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (sp == NULL)
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL) {
|
||||
(void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef KERBEROS
|
||||
try_connect:
|
||||
if (use_kerberos) {
|
||||
rem = KSUCCESS;
|
||||
errno = 0;
|
||||
if (dest_realm == NULL)
|
||||
dest_realm = krb_realmofhost(host);
|
||||
|
||||
#ifdef CRYPT
|
||||
if (doencrypt)
|
||||
rem = krcmd_mutual(&host, sp->s_port, user, args,
|
||||
&rfd2, dest_realm, &cred, schedule);
|
||||
else
|
||||
#endif
|
||||
rem = krcmd(&host, sp->s_port, user, args, &rfd2,
|
||||
dest_realm);
|
||||
if (rem < 0) {
|
||||
use_kerberos = 0;
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL) {
|
||||
(void)fprintf(stderr,
|
||||
"rsh: unknown service shell/tcp.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (errno == ECONNREFUSED)
|
||||
warning("remote host doesn't support Kerberos");
|
||||
if (errno == ENOENT)
|
||||
warning("can't provide Kerberos auth data");
|
||||
goto try_connect;
|
||||
}
|
||||
} else {
|
||||
if (doencrypt) {
|
||||
(void)fprintf(stderr,
|
||||
"rsh: the -x flag requires Kerberos authentication.\n");
|
||||
exit(1);
|
||||
}
|
||||
rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
|
||||
}
|
||||
#else
|
||||
rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
|
||||
#endif
|
||||
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
|
||||
if (rfd2 < 0) {
|
||||
(void)fprintf(stderr, "rsh: can't establish stderr.\n");
|
||||
exit(1);
|
||||
}
|
||||
#if !defined(__minix)
|
||||
if (dflag) {
|
||||
if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
|
||||
sizeof(one)) < 0)
|
||||
(void)fprintf(stderr, "rsh: setsockopt: %s.\n",
|
||||
strerror(errno));
|
||||
if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
|
||||
sizeof(one)) < 0)
|
||||
(void)fprintf(stderr, "rsh: setsockopt: %s.\n",
|
||||
strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
(void)setuid(uid);
|
||||
#if !defined(__minix)
|
||||
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
|
||||
#endif
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
(void)signal(SIGINT, sendsig);
|
||||
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
|
||||
(void)signal(SIGQUIT, sendsig);
|
||||
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
|
||||
(void)signal(SIGTERM, sendsig);
|
||||
|
||||
if (!nflag) {
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
(void)fprintf(stderr,
|
||||
"rsh: fork: %s.\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
if (!doencrypt)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#if defined(__minix)
|
||||
;
|
||||
#else
|
||||
(void)ioctl(rfd2, FIONBIO, &one);
|
||||
(void)ioctl(rem, FIONBIO, &one);
|
||||
#endif
|
||||
}
|
||||
|
||||
talk(nflag, omask, pid, rem);
|
||||
|
||||
if (!nflag && pid)
|
||||
{
|
||||
#if DEBUG
|
||||
printf("killing %d with %d\n", pid, SIGKILL);
|
||||
#endif
|
||||
(void)kill(pid, SIGKILL);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
talk(nflag, omask, pid, rem)
|
||||
int nflag, pid;
|
||||
long omask;
|
||||
register int rem;
|
||||
{
|
||||
register int cc, wc;
|
||||
register char *bp;
|
||||
#if !defined(__minix)
|
||||
int readfrom, ready, rembits;
|
||||
#endif
|
||||
char buf[BUFSIZ];
|
||||
#if defined(__minix)
|
||||
int pid1;
|
||||
#endif
|
||||
|
||||
if (!nflag && pid == 0) {
|
||||
(void)close(rfd2);
|
||||
|
||||
reread: errno = 0;
|
||||
if ((cc = read(0, buf, sizeof buf)) <= 0)
|
||||
goto done;
|
||||
bp = buf;
|
||||
|
||||
rewrite:
|
||||
#if !defined(__minix)
|
||||
rembits = 1 << rem;
|
||||
if (select(16, 0, &rembits, 0, 0) < 0) {
|
||||
if (errno != EINTR) {
|
||||
(void)fprintf(stderr,
|
||||
"rsh: select: %s.\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
goto rewrite;
|
||||
}
|
||||
if ((rembits & (1 << rem)) == 0)
|
||||
goto rewrite;
|
||||
#endif
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
if (doencrypt)
|
||||
wc = des_write(rem, bp, cc);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
wc = write(rem, bp, cc);
|
||||
if (wc < 0) {
|
||||
#if !defined(__minix)
|
||||
if (errno == EWOULDBLOCK)
|
||||
goto rewrite;
|
||||
#endif
|
||||
goto done;
|
||||
}
|
||||
bp += wc;
|
||||
cc -= wc;
|
||||
if (cc == 0)
|
||||
goto reread;
|
||||
goto rewrite;
|
||||
done:
|
||||
#if defined(__minix)
|
||||
ioctl(rem, NWIOTCPSHUTDOWN, NULL);
|
||||
#else
|
||||
(void)shutdown(rem, 1);
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if defined(__minix)
|
||||
pid1= fork();
|
||||
if (pid1 == -1)
|
||||
{
|
||||
(void)fprintf(stderr, "rsh: fork: %s.\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close (pid1 ? rfd2 : rem);
|
||||
for(;;)
|
||||
{
|
||||
errno = 0;
|
||||
cc = read(pid1 ? rem : rfd2, buf, sizeof buf);
|
||||
if (cc <= 0)
|
||||
{
|
||||
if (pid1)
|
||||
{
|
||||
#if DEBUG
|
||||
printf("killing %d with %d\n", pid1, SIGKILL);
|
||||
#endif
|
||||
kill(pid1, SIGKILL);
|
||||
return;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
(void)write(pid1 ? 1 : 2, buf, cc);
|
||||
}
|
||||
#else
|
||||
(void)sigsetmask(omask);
|
||||
readfrom = (1 << rfd2) | (1 << rem);
|
||||
do {
|
||||
ready = readfrom;
|
||||
if (select(16, &ready, 0, 0, 0) < 0) {
|
||||
if (errno != EINTR) {
|
||||
(void)fprintf(stderr,
|
||||
"rsh: select: %s.\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ready & (1 << rfd2)) {
|
||||
errno = 0;
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
if (doencrypt)
|
||||
cc = des_read(rfd2, buf, sizeof buf);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
cc = read(rfd2, buf, sizeof buf);
|
||||
if (cc <= 0) {
|
||||
if (errno != EWOULDBLOCK)
|
||||
readfrom &= ~(1 << rfd2);
|
||||
} else
|
||||
(void)write(2, buf, cc);
|
||||
}
|
||||
if (ready & (1 << rem)) {
|
||||
errno = 0;
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
if (doencrypt)
|
||||
cc = des_read(rem, buf, sizeof buf);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
cc = read(rem, buf, sizeof buf);
|
||||
if (cc <= 0) {
|
||||
if (errno != EWOULDBLOCK)
|
||||
readfrom &= ~(1 << rem);
|
||||
} else
|
||||
(void)write(1, buf, cc);
|
||||
}
|
||||
} while (readfrom);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sendsig(signo)
|
||||
char signo;
|
||||
{
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
if (doencrypt)
|
||||
(void)des_write(rfd2, &signo, 1);
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
(void)write(rfd2, &signo, 1);
|
||||
}
|
||||
|
||||
#ifdef KERBEROS
|
||||
/* VARARGS */
|
||||
warning(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
char *fmt;
|
||||
|
||||
(void)fprintf(stderr, "rsh: warning, using standard rsh: ");
|
||||
va_start(ap);
|
||||
fmt = va_arg(ap, char *);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
(void)fprintf(stderr, ".\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
copyargs(argv)
|
||||
char **argv;
|
||||
{
|
||||
register int cc;
|
||||
register char **ap, *p;
|
||||
char *args;
|
||||
#if !defined(__minix)
|
||||
char *malloc();
|
||||
#endif
|
||||
|
||||
cc = 0;
|
||||
for (ap = argv; *ap; ++ap)
|
||||
cc += strlen(*ap) + 1;
|
||||
if (!(args = malloc((u_int)cc))) {
|
||||
(void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
|
||||
exit(1);
|
||||
}
|
||||
for (p = args, ap = argv; *ap; ++ap) {
|
||||
(void)strcpy(p, *ap);
|
||||
for (p = strcpy(p, *ap); *p; ++p);
|
||||
if (ap[1])
|
||||
*p++ = ' ';
|
||||
}
|
||||
return(args);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: rsh [-nd%s]%s[-l login] host [command]\n",
|
||||
#ifdef KERBEROS
|
||||
#ifdef CRYPT
|
||||
"x", " [-k realm] ");
|
||||
#else
|
||||
"", " [-k realm] ");
|
||||
#endif
|
||||
#else
|
||||
"", " ");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
PROG= in.rshd
|
||||
SRCS= rshd.c
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,445 +0,0 @@
|
|||
/*
|
||||
in.rshd.c
|
||||
*/
|
||||
|
||||
/*
|
||||
main channel:
|
||||
|
||||
back channel\0
|
||||
remuser\0
|
||||
locuser\0
|
||||
command\0
|
||||
data
|
||||
|
||||
back channel:
|
||||
signal\0
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/gen/in.h>
|
||||
#include <net/gen/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/gen/socket.h>
|
||||
#include <net/gen/tcp.h>
|
||||
#include <net/gen/tcp_io.h>
|
||||
#include <net/hton.h>
|
||||
#include <net/netlib.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define where() fprintf(stderr, "%s, %d: ", __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
char cmdbuf[_POSIX_ARG_MAX+1], locuser[16], remuser[16];
|
||||
extern char **environ;
|
||||
char username[20]="USER=";
|
||||
char homedir[64]="HOME=";
|
||||
char shell[64]="SHELL=";
|
||||
char tz[1024]="TZ=";
|
||||
char *envinit[]= {homedir, shell, username, tz, "PATH=:/bin:/usr/bin", 0};
|
||||
char *prog_name;
|
||||
char buffer[PIPE_BUF];
|
||||
|
||||
#if __STDC__
|
||||
#define PROTO(func, args) func args
|
||||
#else
|
||||
#define PROTO(func, args) func ()
|
||||
#endif
|
||||
|
||||
PROTO (int main, (int argc, char *argv[]));
|
||||
PROTO (void getstr, (char*buf, int cnt, char *err));
|
||||
PROTO (void close_on_exec, (int fd));
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int result, result1;
|
||||
nwio_tcpconf_t tcpconf, err_tcpconf;
|
||||
nwio_tcpcl_t tcpconnopt;
|
||||
nwio_tcpatt_t tcpattachopt;
|
||||
tcpport_t tcpport;
|
||||
tcpport_t err_port;
|
||||
int err_fd, pds[2];
|
||||
pid_t pid, pid1, new_pg;
|
||||
#if USEATTACH
|
||||
int err2_fd;
|
||||
#endif
|
||||
struct passwd *pwent;
|
||||
char *cp, *buff_ptr, *TZ;
|
||||
char sig;
|
||||
|
||||
prog_name= argv[0];
|
||||
if (argc != 1)
|
||||
{
|
||||
fprintf(stderr, "%s: wrong number of arguments (%d)\n",
|
||||
prog_name, argc);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
signal(SIGINT, SIG_DFL);
|
||||
signal(SIGQUIT, SIG_DFL);
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
result= ioctl (0, NWIOGTCPCONF, &tcpconf);
|
||||
if (result<0)
|
||||
{
|
||||
fprintf(stderr, "%s: ioctl(NWIOGTCPCONF)= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
|
||||
tcpport= ntohs(tcpconf.nwtc_remport);
|
||||
if (tcpport >= TCPPORT_RESERVED || tcpport < TCPPORT_RESERVED/2)
|
||||
{
|
||||
printf("\1%s: unprotected port (%d)\n", prog_name, tcpport);
|
||||
exit(1);
|
||||
}
|
||||
alarm(60);
|
||||
err_port= 0;
|
||||
for (;;)
|
||||
{
|
||||
char c;
|
||||
result= read(0, &c, 1);
|
||||
if (result <0)
|
||||
{
|
||||
fprintf(stderr, "%s: read= %d : %s\n", prog_name,
|
||||
errno, strerror(errno));
|
||||
}
|
||||
if (result<1)
|
||||
exit(1);
|
||||
if (c == 0)
|
||||
break;
|
||||
err_port= err_port*10 + c - '0';
|
||||
}
|
||||
alarm(0);
|
||||
if (err_port != 0)
|
||||
{
|
||||
int n, pid, lport;
|
||||
|
||||
pid= getpid();
|
||||
lport= 1;
|
||||
do {
|
||||
lport= (lport << 1) | (pid & 1);
|
||||
pid >>= 1;
|
||||
} while (lport < TCPPORT_RESERVED/2);
|
||||
|
||||
n= TCPPORT_RESERVED/2;
|
||||
do
|
||||
{
|
||||
if (--lport < TCPPORT_RESERVED/2)
|
||||
lport= TCPPORT_RESERVED-1;
|
||||
err_fd= open ("/dev/tcp", O_RDWR);
|
||||
if (err_fd<0)
|
||||
{
|
||||
fprintf(stderr, "%s: open= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close_on_exec(err_fd);
|
||||
err_tcpconf.nwtc_flags= NWTC_LP_SET | NWTC_SET_RA |
|
||||
NWTC_SET_RP | NWTC_EXCL;
|
||||
err_tcpconf.nwtc_locport= htons(lport);
|
||||
err_tcpconf.nwtc_remport= htons(err_port);
|
||||
err_tcpconf.nwtc_remaddr= tcpconf.nwtc_remaddr;
|
||||
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
|
||||
if (result == 0) break;
|
||||
if (errno != EADDRINUSE)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(err_fd);
|
||||
} while (--n > 0);
|
||||
if (n == 0)
|
||||
{
|
||||
printf("\1can't get stderr port\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err_tcpconf.nwtc_flags= NWTC_SHARED;
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
|
||||
if (result<0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
tcpconnopt.nwtcl_flags= 0;
|
||||
|
||||
n= 20;
|
||||
for (;;)
|
||||
{
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
result= ioctl (err_fd, NWIOTCPCONN, &tcpconnopt);
|
||||
if (result == 0) break;
|
||||
if (errno != EAGAIN && errno != ECONNREFUSED)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: ioctl(NWIOTCPCONN)= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (--n == 0) break;
|
||||
sleep(1);
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
}
|
||||
#if USEATTACH
|
||||
err2_fd= open ("/dev/tcp", O_RDWR);
|
||||
close_on_exec(err2_fd);
|
||||
if (err2_fd<0)
|
||||
{
|
||||
fprintf(stderr, "%s: open= %d : %s\n", errno,
|
||||
prog_name, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
result= ioctl (err2_fd, NWIOSTCPCONF, &err_tcpconf);
|
||||
if (result<0)
|
||||
{
|
||||
fprintf(stderr, "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
tcpattachopt.nwta_flags= 0;
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
result= ioctl (err2_fd, NWIOTCPATTACH, &tcpattachopt);
|
||||
if (result<0)
|
||||
{
|
||||
fprintf(stderr, "%s: ioctl(NWIOTCPATTACH)= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "\n"); }
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
getstr(remuser, sizeof(remuser), "remuser");
|
||||
getstr(locuser, sizeof(locuser), "locuser");
|
||||
getstr(cmdbuf, sizeof(cmdbuf), "cmdbuf");
|
||||
setpwent();
|
||||
pwent= getpwnam(locuser);
|
||||
if (!pwent)
|
||||
{
|
||||
printf("\1Login incorrect.\n");
|
||||
exit(1);
|
||||
}
|
||||
endpwent();
|
||||
if (chdir(pwent->pw_dir) < 0)
|
||||
{
|
||||
chdir("/");
|
||||
}
|
||||
#if DEBUG
|
||||
{ where(); fprintf(stderr, "calling iruserok(%s, %d, %s, %s)\n",
|
||||
inet_ntoa(tcpconf.nwtc_remaddr), 0, remuser, locuser); }
|
||||
#endif
|
||||
if (iruserok(tcpconf.nwtc_remaddr, 0, remuser, locuser) < 0)
|
||||
{
|
||||
printf("\1Permission denied.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (err_port)
|
||||
{
|
||||
/* Let's go to a different process group. */
|
||||
new_pg= setsid();
|
||||
pid= fork();
|
||||
if (pid<0)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
fprintf(stderr, "%s: fork()= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
}
|
||||
printf("\1Try again.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (pid)
|
||||
{
|
||||
close(0); /* stdin */
|
||||
close(1); /* stdout */
|
||||
#if USEATTACH
|
||||
close(err_fd); /* stderr for shell */
|
||||
#endif
|
||||
dup2(2,0);
|
||||
dup2(2,1);
|
||||
for (;;)
|
||||
{
|
||||
#if !USEATTACH
|
||||
if (read(err_fd, &sig, 1) <= 0)
|
||||
#else
|
||||
if (read(err2_fd, &sig, 1) <= 0)
|
||||
#endif
|
||||
{
|
||||
#if 0
|
||||
printf("read failed: %d\n", errno);
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
pid= 0;
|
||||
#if 0
|
||||
printf("killing %d with %d\n", -new_pg, sig);
|
||||
#endif
|
||||
kill(-new_pg, sig);
|
||||
}
|
||||
}
|
||||
#if USEATTACH
|
||||
close(err2_fd); /* signal channel for parent */
|
||||
#endif
|
||||
result= pipe(pds);
|
||||
if (result<0)
|
||||
{
|
||||
printf("\1Can't make pipe\n");
|
||||
kill(getppid(), SIGTERM);
|
||||
exit(1);
|
||||
}
|
||||
pid1= fork();
|
||||
if (pid1<0)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
fprintf(stderr, "%s: fork()= %d : %s\n",
|
||||
prog_name, errno, strerror(errno));
|
||||
}
|
||||
printf("\1Try again.\n");
|
||||
kill(-new_pg, SIGTERM);
|
||||
exit(1);
|
||||
}
|
||||
if (pid1)
|
||||
{
|
||||
close(pds[1]); /* write side of pipe */
|
||||
for (;;)
|
||||
{
|
||||
result= read(pds[0], buffer, sizeof(buffer));
|
||||
if (result<=0)
|
||||
{
|
||||
kill(pid, SIGTERM);
|
||||
exit(0);
|
||||
}
|
||||
buff_ptr= buffer;
|
||||
while (result>0)
|
||||
{
|
||||
result1= write (err_fd, buff_ptr,
|
||||
result);
|
||||
if (result1 <= 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: write()= %d : %s\n",
|
||||
prog_name, errno,
|
||||
strerror(errno));
|
||||
kill(-new_pg, SIGTERM);
|
||||
exit(1);
|
||||
}
|
||||
result -= result1;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(err_fd); /* file descriptor for error channel */
|
||||
close (pds[0]); /* read side of pipe */
|
||||
dup2(pds[1], 2);
|
||||
close (pds[1]); /* write side of pipe */
|
||||
}
|
||||
if (*pwent->pw_shell == '\0')
|
||||
pwent->pw_shell= "/bin/sh";
|
||||
#if __minix_vmd
|
||||
initgroups(pwent->pw_name, pwent->pw_gid);
|
||||
#endif
|
||||
setgid(pwent->pw_gid);
|
||||
setuid(pwent->pw_uid);
|
||||
TZ=getenv("TZ");
|
||||
environ= envinit;
|
||||
strncat(homedir, pwent->pw_dir, sizeof(homedir)-6);
|
||||
strncat(shell, pwent->pw_shell, sizeof(shell)-7);
|
||||
strncat(username, pwent->pw_name, sizeof(username)-6);
|
||||
if (TZ)
|
||||
strncat(tz, TZ, sizeof(tz)-4);
|
||||
else
|
||||
envinit[3]= NULL;
|
||||
|
||||
cp= strrchr(pwent->pw_shell, '/');
|
||||
if (cp)
|
||||
cp++;
|
||||
else
|
||||
cp= pwent->pw_shell;
|
||||
|
||||
if (!err_port)
|
||||
dup2(1, 2);
|
||||
write(1, "\0", 1);
|
||||
|
||||
execl(pwent->pw_shell, cp, "-c", cmdbuf, 0);
|
||||
close(2);
|
||||
open("/dev/tty", O_RDWR);
|
||||
fprintf(stderr, "%s: execl(%s, %s, .., %s)= %d : %s\n", prog_name,
|
||||
pwent->pw_shell, cp, cmdbuf, errno, strerror(errno));
|
||||
kill(getppid(), SIGTERM);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void getstr(buf, cnt, err)
|
||||
char *buf;
|
||||
int cnt;
|
||||
char *err;
|
||||
{
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
if (read(0, &c, 1) != 1)
|
||||
exit(1);
|
||||
*buf++ = c;
|
||||
if (--cnt == 0)
|
||||
{
|
||||
printf("\1%s too long", err);
|
||||
exit(1);
|
||||
}
|
||||
} while (c != 0);
|
||||
}
|
||||
|
||||
void close_on_exec(fd)
|
||||
int fd;
|
||||
{
|
||||
(void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
||||
}
|
|
@ -242,6 +242,7 @@ int main(int argc, char **argv)
|
|||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
dup2(client_fd, 0);
|
||||
dup2(client_fd, 1);
|
||||
dup2(client_fd, 2);
|
||||
close(client_fd);
|
||||
execvp(progv[0], progv);
|
||||
report(progv[0]);
|
||||
|
|
|
@ -12,8 +12,8 @@ MAN= at.1 \
|
|||
mixer.1 \
|
||||
mkproto.1 mount.1 mt.1 \
|
||||
playwave.1 prep.1 \
|
||||
profile.1 ps.1 rcp.1 recwave.1 \
|
||||
remsync.1 rget.1 rlogin.1 rsh.1 rz.1 \
|
||||
profile.1 ps.1 recwave.1 \
|
||||
remsync.1 rget.1 rlogin.1 rz.1 \
|
||||
spell.1 svc.1 svrctl.1 \
|
||||
synctree.1 sysenv.1 sz.1 telnet.1 template.1 \
|
||||
term.1 termcap.1 tget.1 time.1 \
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
.\" Copyright (c) 1983 Regents of the University of California.
|
||||
.\" All rights reserved. The Berkeley software License Agreement
|
||||
.\" specifies the terms and conditions for redistribution.
|
||||
.\"
|
||||
.\" @(#)rcp.1c 6.4 (Berkeley) 5/12/86
|
||||
.\"
|
||||
.TH RCP 1 "May 12, 1986"
|
||||
.UC 5
|
||||
.SH NAME
|
||||
rcp \- remote file copy
|
||||
.SH SYNOPSIS
|
||||
.B rcp
|
||||
.RB [ \-p ]
|
||||
.I file1 file2
|
||||
.br
|
||||
.B rcp
|
||||
.RB [ \-pr ]
|
||||
.I file
|
||||
\&...
|
||||
.I directory
|
||||
.SH DESCRIPTION
|
||||
.B Rcp
|
||||
copies files between machines. Each
|
||||
.I file
|
||||
or
|
||||
.I directory
|
||||
argument is either a remote file name of the
|
||||
form ``rhost:path'', or a local file name (containing no `:' characters,
|
||||
or a `/' before any `:'s).
|
||||
.PP
|
||||
If the
|
||||
.B \-r
|
||||
option
|
||||
is specified and any of the source files are directories,
|
||||
.B rcp
|
||||
copies each subtree rooted at that name; in this case
|
||||
the destination must be a directory.
|
||||
.PP
|
||||
By default, the mode and owner of
|
||||
.I file2
|
||||
are preserved if it already existed; otherwise the mode of the source file
|
||||
modified by the
|
||||
.BR umask (2)
|
||||
on the destination host is used.
|
||||
The
|
||||
.B \-p
|
||||
option causes
|
||||
.B rcp
|
||||
to attempt to preserve (duplicate) in its copies the modification
|
||||
times and modes of the source files, ignoring the
|
||||
.BR umask .
|
||||
.PP
|
||||
If
|
||||
.I path
|
||||
is not a full path name, it is interpreted relative to
|
||||
your login directory on
|
||||
.IR rhost .
|
||||
A
|
||||
.I path
|
||||
on a remote host may be quoted (using \e, ", or \(aa)
|
||||
so that the metacharacters are interpreted remotely.
|
||||
.PP
|
||||
.B Rcp
|
||||
does not prompt for passwords; your current local user name
|
||||
must exist on
|
||||
.I rhost
|
||||
and allow remote command execution via
|
||||
.BR rsh (1).
|
||||
.PP
|
||||
.B Rcp
|
||||
handles third party copies, where neither source nor target files
|
||||
are on the current machine.
|
||||
Hostnames may also take the form ``rname@rhost'' to use
|
||||
.I rname
|
||||
rather than the current user name on the remote host.
|
||||
The destination hostname may also take the form ``rhost.rname'' to
|
||||
support destination machines that are running 4.2BSD
|
||||
versions of
|
||||
.BR rcp .
|
||||
.SH SEE ALSO
|
||||
.BR cp (1),
|
||||
.BR ftp (1),
|
||||
.BR rsh (1),
|
||||
.BR rlogin (1).
|
||||
.SH BUGS
|
||||
Doesn't detect all cases where the target of a copy might
|
||||
be a file in cases where only a directory should be legal.
|
||||
.br
|
||||
Is confused by any output generated by commands in a
|
||||
\&.profile, or \&.*shrc file on the remote host.
|
|
@ -1,94 +0,0 @@
|
|||
.\" Copyright (c) 1983 Regents of the University of California.
|
||||
.\" All rights reserved. The Berkeley software License Agreement
|
||||
.\" specifies the terms and conditions for redistribution.
|
||||
.\"
|
||||
.\" @(#)rsh.1c 6.1 (Berkeley) 4/29/85
|
||||
.\"
|
||||
.TH RSH 1 "April 29, 1985"
|
||||
.UC 5
|
||||
.SH NAME
|
||||
rsh \- remote shell
|
||||
.SH SYNOPSIS
|
||||
.B rsh
|
||||
.RB [ \-n ]
|
||||
.RB [ \-l
|
||||
.IR username ]
|
||||
.I host
|
||||
.RI [ command ]
|
||||
.br
|
||||
.I host
|
||||
.RB [ \-n ]
|
||||
.RB [ \-l
|
||||
.IR username ]
|
||||
.RI [ command ]
|
||||
.SH DESCRIPTION
|
||||
.B Rsh
|
||||
connects to the specified
|
||||
.IR host ,
|
||||
and executes the specified \fIcommand\fR.
|
||||
.B Rsh
|
||||
copies its standard input to the remote command, the standard
|
||||
output of the remote command to its standard output, and the
|
||||
standard error of the remote command to its standard error.
|
||||
Interrupt, quit and terminate signals are propagated to the remote
|
||||
command; \fBrsh\fP normally terminates when the remote command does.
|
||||
.PP
|
||||
The remote username used is the same as your local username,
|
||||
unless you specify a different remote name with the
|
||||
.B \-l
|
||||
option.
|
||||
This remote name must be equivalent (in the sense of
|
||||
.BR rlogin (1))
|
||||
to the originating account; no provision
|
||||
is made for specifying a password with a command.
|
||||
.PP
|
||||
If you omit
|
||||
.IR command ,
|
||||
then instead of executing a single command, you will be logged in
|
||||
on the remote host using
|
||||
.BR rlogin (1).
|
||||
.PP
|
||||
Shell metacharacters which are not quoted are interpreted
|
||||
on local machine, while quoted metacharacters are interpreted on
|
||||
the remote machine.
|
||||
Thus the command
|
||||
.PP
|
||||
.RS
|
||||
rsh otherhost cat remotefile >> localfile
|
||||
.RE
|
||||
.PP
|
||||
appends the remote file
|
||||
.I remotefile
|
||||
to the localfile
|
||||
.IR localfile ,
|
||||
while
|
||||
.PP
|
||||
.RS
|
||||
rsh otherhost cat remotefile ">>" otherremotefile
|
||||
.RE
|
||||
.PP
|
||||
appends
|
||||
.I remotefile
|
||||
to
|
||||
.IR otherremotefile .
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-l " username"
|
||||
Specify the remote user name.
|
||||
.TP
|
||||
.B \-n
|
||||
Connect standard input of the remote command to /dev/null. Do this if
|
||||
.B rsh
|
||||
should not inadvertently read from standard input.
|
||||
.SH SEE ALSO
|
||||
.BR rcp (1),
|
||||
.BR rlogin (1),
|
||||
.BR rhosts (5).
|
||||
.SH BUGS
|
||||
You cannot run an interactive command
|
||||
(like
|
||||
.BR rogue (6)
|
||||
or
|
||||
.BR vi (1));
|
||||
use
|
||||
.BR rlogin (1).
|
|
@ -7,7 +7,7 @@ MAN= add_route.8 backup.8 boot.8 btrace.8 \
|
|||
ossdevlinks.8 part.8 partition.8 \
|
||||
printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
|
||||
readclock.8 repartition.8 \
|
||||
rshd.8 screendump.8 serial-ip.8 \
|
||||
screendump.8 serial-ip.8 \
|
||||
setup.8 shutdown.8 slip.8 srccrc.8 tcpd.8 \
|
||||
unix.8 update.8 usage.8 vbfs.8
|
||||
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
.\" Copyright (c) 1983 Regents of the University of California.
|
||||
.\" All rights reserved. The Berkeley software License Agreement
|
||||
.\" specifies the terms and conditions for redistribution.
|
||||
.\"
|
||||
.\" @(#)rshd.8c 6.3 (Berkeley) 5/24/86
|
||||
.\"
|
||||
.TH RSHD 8 "May 24, 1986"
|
||||
.UC 5
|
||||
.SH NAME
|
||||
rshd \- remote shell server
|
||||
.SH SYNOPSIS
|
||||
.B "shell stream tcp nowait root /usr/sbin/in.rshd in.rshd"
|
||||
.br
|
||||
.B "tcpd shell /usr/sbin/in.rshd"
|
||||
.SH DESCRIPTION
|
||||
.B Rshd
|
||||
is the server for the
|
||||
.BR rcmd (3)
|
||||
routine and, consequently, for the
|
||||
.BR rsh (1)
|
||||
program. The server provides remote execution facilities
|
||||
with authentication based on privileged port numbers from trusted hosts.
|
||||
.PP
|
||||
.B Rshd
|
||||
listens for service requests at the port indicated in
|
||||
the ``cmd'' service specification; see
|
||||
.BR services (5).
|
||||
When a service request is received the following protocol
|
||||
is initiated:
|
||||
.IP 1)
|
||||
The server checks the client's source port.
|
||||
If the port is not in the range 0-1023, the server
|
||||
aborts the connection.
|
||||
.IP 2)
|
||||
The server reads characters from the socket up
|
||||
to a null (`\e0') byte. The resultant string is
|
||||
interpreted as an ASCII number, base 10.
|
||||
.IP 3)
|
||||
If the number received in step 1 is non-zero,
|
||||
it is interpreted as the port number of a secondary
|
||||
stream to be used for the
|
||||
.BR stderr .
|
||||
A second connection is then created to the specified
|
||||
port on the client's machine. The source port of this
|
||||
second connection is also in the range 0-1023.
|
||||
.IP 4)
|
||||
The server checks the client's source address
|
||||
and requests the corresponding host name (see
|
||||
.BR gethostbyaddr (3N),
|
||||
.BR hosts (5)
|
||||
and
|
||||
.BR named (8)).
|
||||
If the hostname cannot be determined,
|
||||
the dot-notation representation of the host address is used.
|
||||
.IP 5)
|
||||
A null terminated user name of at most 16 characters
|
||||
is retrieved on the initial socket. This user name
|
||||
is interpreted as the user identity on the
|
||||
.BR client 's
|
||||
machine.
|
||||
.IP 6)
|
||||
A null terminated user name of at most 16 characters
|
||||
is retrieved on the initial socket. This user name
|
||||
is interpreted as a user identity to use on the
|
||||
.BR server 's
|
||||
machine.
|
||||
.IP 7)
|
||||
A null terminated command to be passed to a
|
||||
shell is retrieved on the initial socket. The length of
|
||||
the command is limited by the upper bound on the size of
|
||||
the system's argument list.
|
||||
.IP 8)
|
||||
.B Rshd
|
||||
then validates the user according to the following steps.
|
||||
The local (server-end) user name is looked up in the password file
|
||||
and a
|
||||
.B chdir
|
||||
is performed to the user's home directory. If either
|
||||
the lookup or
|
||||
.B chdir
|
||||
fail, the connection is terminated.
|
||||
If the user is not the super-user, (user id 0), the file
|
||||
.B /etc/hosts.equiv
|
||||
is consulted for a list of hosts considered ``equivalent''.
|
||||
If the client's host name is present in this file, the
|
||||
authentication is considered successful. If the lookup
|
||||
fails, or the user is the super-user, then the file
|
||||
.B .rhosts
|
||||
in the home directory of the remote user is checked for
|
||||
the machine name and identity of the user on the client's
|
||||
machine. If this lookup fails, the connection is terminated.
|
||||
.IP 9)
|
||||
A null byte is returned on the initial socket
|
||||
and the command line is passed to the normal login
|
||||
shell of the user. The
|
||||
shell inherits the network connections established
|
||||
by
|
||||
.IR rshd .
|
||||
.SH DIAGNOSTICS
|
||||
Except for the last one listed below,
|
||||
all diagnostic messages
|
||||
are returned on the initial socket,
|
||||
after which any network connections are closed.
|
||||
An error is indicated by a leading byte with a value of
|
||||
1 (0 is returned in step 9 above upon successful completion
|
||||
of all the steps prior to the execution of the login shell).
|
||||
.PP
|
||||
.B ``locuser too long''
|
||||
.br
|
||||
The name of the user on the client's machine is
|
||||
longer than 16 characters.
|
||||
.PP
|
||||
.B ``remuser too long''
|
||||
.br
|
||||
The name of the user on the remote machine is
|
||||
longer than 16 characters.
|
||||
.PP
|
||||
.B ``command too long ''
|
||||
.br
|
||||
The command line passed exceeds the size of the argument
|
||||
list (as configured into the system).
|
||||
.PP
|
||||
.B ``Login incorrect.''
|
||||
.br
|
||||
No password file entry for the user name existed.
|
||||
.PP
|
||||
.B ``No remote directory.''
|
||||
.br
|
||||
The
|
||||
.B chdir
|
||||
command to the home directory failed.
|
||||
.PP
|
||||
.B ``Permission denied.''
|
||||
.br
|
||||
The authentication procedure described above failed.
|
||||
.PP
|
||||
.B ``Can't make pipe.''
|
||||
.br
|
||||
The pipe needed for the
|
||||
.BR stderr ,
|
||||
wasn't created.
|
||||
.PP
|
||||
.B ``Try again.''
|
||||
.br
|
||||
A
|
||||
.B fork
|
||||
by the server failed.
|
||||
.PP
|
||||
.B ``<shellname>: ...''
|
||||
.br
|
||||
The user's login shell could not be started. This message is returned
|
||||
on the connection associated with the
|
||||
.BR stderr ,
|
||||
and is not preceded by a flag byte.
|
||||
.SH SEE ALSO
|
||||
.BR rsh (1),
|
||||
.BR rcmd (3).
|
||||
.SH BUGS
|
||||
The authentication procedure used here assumes the integrity
|
||||
of each client machine and the connecting medium. This is
|
||||
insecure, but is useful in an ``open'' environment.
|
||||
.PP
|
||||
A facility to allow all data exchanges to be encrypted should be
|
||||
present.
|
||||
.PP
|
||||
A more extensible protocol should be used.
|
|
@ -21,7 +21,7 @@ SUBDIR= asa \
|
|||
nbperf newgrp nice nl nohup \
|
||||
passwd paste patch pathchk pr \
|
||||
printenv printf pwhash \
|
||||
renice rev \
|
||||
renice rev rsh \
|
||||
\
|
||||
sdiff sed seq shar shlock \
|
||||
shuffle sort split stat su \
|
||||
|
|
13
usr.bin/rsh/Makefile
Normal file
13
usr.bin/rsh/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
# $NetBSD: Makefile,v 1.20 2009/04/14 22:15:25 lukem Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 7/19/93
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
USE_FORT?=yes # network client
|
||||
|
||||
PROG= rsh
|
||||
SRCS= rsh.c getport.c
|
||||
|
||||
.PATH: ${NETBSDSRCDIR}/usr.bin/rlogin
|
||||
|
||||
.include <bsd.prog.mk>
|
66
usr.bin/rsh/getport.c
Normal file
66
usr.bin/rsh/getport.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* $NetBSD: getport.c,v 1.2 2008/04/28 20:24:14 martin Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Christos Zoulas.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: getport.c,v 1.2 2008/04/28 20:24:14 martin Exp $");
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
#include <netdb.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "getport.h"
|
||||
|
||||
struct servent *
|
||||
getport(const char *service, const char *protocol)
|
||||
{
|
||||
long port;
|
||||
char *ep;
|
||||
struct servent *sp = getservbyname(service, protocol);
|
||||
if (sp != NULL)
|
||||
return sp;
|
||||
|
||||
if ((sp = calloc(1, sizeof(*sp))) == NULL)
|
||||
err(1, "malloc");
|
||||
sp->s_name = __UNCONST(service);
|
||||
sp->s_proto = __UNCONST(protocol);
|
||||
port = strtol(service, &ep, 0);
|
||||
if ((service[0] != '\0' && *ep != '\0') ||
|
||||
(errno == ERANGE &&
|
||||
(port == LONG_MAX || port == LONG_MIN)) ||
|
||||
(port <= 0 || port >= IPPORT_ANONMAX))
|
||||
errx(1,"port must be between 1 and %d",
|
||||
IPPORT_ANONMAX);
|
||||
sp->s_port = htons((uint16_t)port);
|
||||
return sp;
|
||||
}
|
29
usr.bin/rsh/getport.h
Normal file
29
usr.bin/rsh/getport.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-
|
||||
* Copyright (c) 2004 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Christos Zoulas.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
extern struct servent *getport(const char *, const char *);
|
35
usr.bin/rsh/pathnames.h
Normal file
35
usr.bin/rsh/pathnames.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* $NetBSD: pathnames.h,v 1.5 2003/08/07 11:15:43 agc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
* $NetBSD: pathnames.h,v 1.5 2003/08/07 11:15:43 agc Exp $
|
||||
*/
|
||||
|
||||
#define _PATH_RLOGIN "/usr/bin/rlogin"
|
187
usr.bin/rsh/rsh.1
Normal file
187
usr.bin/rsh/rsh.1
Normal file
|
@ -0,0 +1,187 @@
|
|||
.\" $NetBSD: rsh.1,v 1.20 2005/03/11 02:45:24 ginsbach Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)rsh.1 8.2 (Berkeley) 4/29/95
|
||||
.\"
|
||||
.Dd March 9, 2005
|
||||
.Dt RSH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rsh
|
||||
.Nd remote shell
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 46dn
|
||||
.Op Fl l Ar username
|
||||
.Op Fl p Ar port
|
||||
.Ar host
|
||||
.Op command
|
||||
.Nm
|
||||
.Op Fl 46dn
|
||||
.Op Fl p Ar port
|
||||
.Ar username@host
|
||||
.Op command
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
executes
|
||||
.Ar command
|
||||
on
|
||||
.Ar host .
|
||||
.Pp
|
||||
.Nm
|
||||
copies its standard input to the remote command, the standard
|
||||
output of the remote command to its standard output, and the
|
||||
standard error of the remote command to its standard error.
|
||||
Interrupt, quit and terminate signals are propagated to the remote
|
||||
command;
|
||||
.Nm
|
||||
normally terminates when the remote command does.
|
||||
The options are as follows:
|
||||
.Bl -tag -width XlXusernameX
|
||||
.It Fl 4
|
||||
Use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Use IPv6 addresses only.
|
||||
.It Fl d
|
||||
The
|
||||
.Fl d
|
||||
option turns on socket debugging (using
|
||||
.Xr setsockopt 2 )
|
||||
on the
|
||||
.Tn TCP
|
||||
sockets used for communication with the remote host.
|
||||
.It Fl l Ar username
|
||||
By default, the remote username is the same as the local username.
|
||||
The
|
||||
.Fl l
|
||||
option or the
|
||||
.Ar username@host
|
||||
format allow the remote name to be specified.
|
||||
.It Fl n
|
||||
The
|
||||
.Fl n
|
||||
option redirects input from the special device
|
||||
.Pa /dev/null
|
||||
(see the
|
||||
.Sx BUGS
|
||||
section of this manual page).
|
||||
.It Fl p Ar port
|
||||
Uses the given
|
||||
.Pa port
|
||||
instead of the one assigned to the service
|
||||
.Dq shell .
|
||||
May be given either as symbolic name or as number.
|
||||
If no command is given, note that
|
||||
.Xr rlogin 1
|
||||
is started, which may need a different daemon
|
||||
.No ( Xr rlogind 8
|
||||
instead of
|
||||
.Xr rshd 8 )
|
||||
running on the server; you want to pass the
|
||||
.Xr rshd 8
|
||||
port number in that case.
|
||||
.El
|
||||
.Pp
|
||||
If no
|
||||
.Ar command
|
||||
is specified, you will be logged in on the remote host using
|
||||
.Xr rlogin 1 .
|
||||
.Pp
|
||||
Shell metacharacters which are not quoted are interpreted on local machine,
|
||||
while quoted metacharacters are interpreted on the remote machine.
|
||||
For example, the command
|
||||
.Pp
|
||||
.Dl rsh otherhost cat remotefile \*[Gt]\*[Gt] localfile
|
||||
.Pp
|
||||
appends the remote file
|
||||
.Ar remotefile
|
||||
to the local file
|
||||
.Ar localfile ,
|
||||
while
|
||||
.Pp
|
||||
.Dl rsh otherhost cat remotefile \&"\*[Gt]\*[Gt]\&" other_remotefile
|
||||
.Pp
|
||||
appends
|
||||
.Ar remotefile
|
||||
to
|
||||
.Ar other_remotefile .
|
||||
.\" .Pp
|
||||
.\" Many sites specify a large number of host names as commands in the
|
||||
.\" directory
|
||||
.\" .Pa /usr/hosts .
|
||||
.\" If this directory is included in your search path, you can use the
|
||||
.\" shorthand
|
||||
.\" .Dq host command
|
||||
.\" for the longer form
|
||||
.\" .Dq rsh host command .
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/hosts -compact
|
||||
.It Pa /etc/hosts
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rcmd 1 ,
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rcmd 3 ,
|
||||
.Xr hosts.equiv 5 ,
|
||||
.Xr rhosts 5 ,
|
||||
.Xr environ 7
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
.Sh BUGS
|
||||
If you are using
|
||||
.Xr csh 1
|
||||
and put a
|
||||
.Nm
|
||||
in the background without redirecting its input away from the terminal,
|
||||
it will block even if no reads are posted by the remote command.
|
||||
If no input is desired you should redirect the input of
|
||||
.Nm
|
||||
to
|
||||
.Pa /dev/null
|
||||
using the
|
||||
.Fl n
|
||||
option.
|
||||
.Pp
|
||||
You cannot run an interactive command (like
|
||||
.Xr rogue 6
|
||||
or
|
||||
.Xr vi 1 )
|
||||
using
|
||||
.Nm ;
|
||||
use
|
||||
.Xr rlogin 1
|
||||
instead.
|
||||
.Pp
|
||||
Stop signals stop the local
|
||||
.Nm
|
||||
process only; this is arguably wrong, but currently hard to fix for reasons
|
||||
too complicated to explain here.
|
474
usr.bin/rsh/rsh.c
Normal file
474
usr.bin/rsh/rsh.c
Normal file
|
@ -0,0 +1,474 @@
|
|||
/* $NetBSD: rsh.c,v 1.33 2011/08/29 14:22:46 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1983, 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1983, 1990, 1993, 1994\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rsh.c 8.4 (Berkeley) 4/29/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: rsh.c,v 1.33 2011/08/29 14:22:46 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "getport.h"
|
||||
|
||||
|
||||
/*
|
||||
* rsh - remote shell
|
||||
*/
|
||||
int remerr;
|
||||
|
||||
static int sigs[] = { SIGINT, SIGTERM, SIGQUIT };
|
||||
|
||||
static char *copyargs(char **);
|
||||
static void sendsig(int);
|
||||
static int checkfd(struct pollfd *, int);
|
||||
static void talk(int, sigset_t *, pid_t, int);
|
||||
__dead static void usage(void);
|
||||
#ifdef IN_RCMD
|
||||
int orcmd(char **, int, const char *,
|
||||
const char *, const char *, int *);
|
||||
int orcmd_af(char **, int, const char *,
|
||||
const char *, const char *, int *, int);
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct passwd *pw;
|
||||
struct servent *sp;
|
||||
sigset_t oset, nset;
|
||||
struct protoent *proto;
|
||||
|
||||
#ifdef IN_RCMD
|
||||
char *locuser = 0, *loop;
|
||||
#endif /* IN_RCMD */
|
||||
int argoff, asrsh, ch, dflag, nflag, one, rem;
|
||||
size_t i;
|
||||
int family = AF_UNSPEC;
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
char *args, *host, *p, *user, *name;
|
||||
|
||||
argoff = asrsh = dflag = nflag = 0;
|
||||
one = 1;
|
||||
host = user = NULL;
|
||||
sp = NULL;
|
||||
|
||||
#ifndef IN_RCMD
|
||||
/*
|
||||
* If called as something other than "rsh" use it as the host name,
|
||||
* only for rsh.
|
||||
*/
|
||||
if (strcmp(getprogname(), "rsh") == 0)
|
||||
asrsh = 1;
|
||||
else {
|
||||
host = strdup(getprogname());
|
||||
if (host == NULL)
|
||||
err(1, NULL);
|
||||
}
|
||||
#endif /* IN_RCMD */
|
||||
|
||||
/* handle "rsh host flags" */
|
||||
if (!host && argc > 2 && argv[1][0] != '-') {
|
||||
host = argv[1];
|
||||
argoff = 1;
|
||||
}
|
||||
|
||||
#ifdef IN_RCMD
|
||||
if ((loop = getenv("RCMD_LOOP")) && strcmp(loop, "YES") == 0)
|
||||
warnx("rcmd appears to be looping!");
|
||||
|
||||
setenv("RCMD_LOOP", "YES", 1);
|
||||
|
||||
# define OPTIONS "468KLdel:np:u:w"
|
||||
|
||||
#else /* IN_RCMD */
|
||||
|
||||
# define OPTIONS "468KLdel:np:w"
|
||||
|
||||
#endif /* IN_RCMD */
|
||||
|
||||
if (!(pw = getpwuid(uid = getuid())))
|
||||
errx(1, "unknown user id");
|
||||
|
||||
if ((name = strdup(pw->pw_name)) == NULL)
|
||||
err(1, "malloc");
|
||||
while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
|
||||
switch(ch) {
|
||||
case '4':
|
||||
family = AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
family = AF_INET6;
|
||||
break;
|
||||
case 'K':
|
||||
break;
|
||||
case 'L': /* -8Lew are ignored to allow rlogin aliases */
|
||||
case 'e':
|
||||
case 'w':
|
||||
case '8':
|
||||
break;
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'l':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'p':
|
||||
sp = getport(optarg, "tcp");
|
||||
break;
|
||||
#ifdef IN_RCMD
|
||||
case 'u':
|
||||
if (getuid() != 0 && optarg && name &&
|
||||
strcmp(name, optarg) != 0)
|
||||
errx(1,"only super user can use the -u option");
|
||||
locuser = optarg;
|
||||
break;
|
||||
#endif /* IN_RCMD */
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
optind += argoff;
|
||||
|
||||
/* if haven't gotten a host yet, do so */
|
||||
if (!host && !(host = argv[optind++]))
|
||||
usage();
|
||||
|
||||
/* if no further arguments, must have been called as rlogin. */
|
||||
if (!argv[optind]) {
|
||||
#ifdef IN_RCMD
|
||||
usage();
|
||||
#else
|
||||
if (asrsh)
|
||||
*argv = __UNCONST("rlogin");
|
||||
execv(_PATH_RLOGIN, argv);
|
||||
err(1, "can't exec %s", _PATH_RLOGIN);
|
||||
#endif
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* Accept user1@host format, though "-l user2" overrides user1 */
|
||||
p = strchr(host, '@');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
if (!user && p > host)
|
||||
user = host;
|
||||
host = p + 1;
|
||||
if (*host == '\0')
|
||||
usage();
|
||||
}
|
||||
if (!user)
|
||||
user = name;
|
||||
|
||||
|
||||
args = copyargs(argv);
|
||||
|
||||
if (sp == NULL)
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL)
|
||||
errx(1, "shell/tcp: unknown service");
|
||||
|
||||
|
||||
#ifdef IN_RCMD
|
||||
rem = orcmd_af(&host, sp->s_port, locuser ? locuser :
|
||||
#else
|
||||
rem = rcmd_af(&host, sp->s_port,
|
||||
#endif
|
||||
name, user, args, &remerr, family);
|
||||
(void)free(name);
|
||||
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
|
||||
if (remerr < 0)
|
||||
errx(1, "can't establish stderr");
|
||||
if (dflag) {
|
||||
if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
|
||||
sizeof(one)) < 0)
|
||||
warn("setsockopt remote");
|
||||
if (setsockopt(remerr, SOL_SOCKET, SO_DEBUG, &one,
|
||||
sizeof(one)) < 0)
|
||||
warn("setsockopt stderr");
|
||||
}
|
||||
proto = getprotobyname("tcp");
|
||||
setsockopt(rem, proto->p_proto, TCP_NODELAY, &one, sizeof(one));
|
||||
setsockopt(remerr, proto->p_proto, TCP_NODELAY, &one, sizeof(one));
|
||||
|
||||
|
||||
(void)setuid(uid);
|
||||
|
||||
(void)sigemptyset(&nset);
|
||||
for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
|
||||
(void)sigaddset(&nset, sigs[i]);
|
||||
|
||||
(void)sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) {
|
||||
struct sigaction sa;
|
||||
|
||||
if (sa.sa_handler != SIG_IGN) {
|
||||
sa.sa_handler = sendsig;
|
||||
(void)sigaction(sigs[i], &sa, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nflag) {
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
err(1, "fork");
|
||||
}
|
||||
else
|
||||
pid = -1;
|
||||
|
||||
#if defined(KERBEROS) && defined(CRYPT)
|
||||
if (!doencrypt)
|
||||
#endif
|
||||
{
|
||||
(void)ioctl(remerr, FIONBIO, &one);
|
||||
(void)ioctl(rem, FIONBIO, &one);
|
||||
}
|
||||
|
||||
talk(nflag, &oset, pid, rem);
|
||||
|
||||
if (!nflag)
|
||||
(void)kill(pid, SIGKILL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
checkfd(struct pollfd *fdp, int outfd)
|
||||
{
|
||||
int nr, nw;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if (fdp->revents & (POLLNVAL|POLLERR|POLLHUP))
|
||||
return -1;
|
||||
|
||||
if ((fdp->revents & POLLIN) == 0)
|
||||
return 0;
|
||||
|
||||
errno = 0;
|
||||
#if defined(KERBEROS) && defined(CRYPT)
|
||||
if (doencrypt)
|
||||
nr = des_read(fdp->fd, buf, sizeof buf);
|
||||
else
|
||||
#endif
|
||||
nr = read(fdp->fd, buf, sizeof buf);
|
||||
|
||||
if (nr <= 0) {
|
||||
if (errno != EAGAIN)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
char *bc = buf;
|
||||
while (nr) {
|
||||
if ((nw = write(outfd, bc, nr)) <= 0)
|
||||
return -1;
|
||||
nr -= nw;
|
||||
bc += nw;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
talk(int nflag, sigset_t *oset, __pid_t pid, int rem)
|
||||
{
|
||||
int nr, nw, nfds;
|
||||
struct pollfd fds[2], *fdp = &fds[0];
|
||||
char *bp, buf[BUFSIZ];
|
||||
|
||||
if (!nflag && pid == 0) {
|
||||
(void)close(remerr);
|
||||
|
||||
fdp->events = POLLOUT|POLLNVAL|POLLERR|POLLHUP;
|
||||
fdp->fd = rem;
|
||||
nr = 0;
|
||||
bp = buf;
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
|
||||
if (nr == 0) {
|
||||
if ((nr = read(0, buf, sizeof buf)) == 0)
|
||||
goto done;
|
||||
if (nr == -1) {
|
||||
if (errno == EIO)
|
||||
goto done;
|
||||
if (errno == EINTR) {
|
||||
nr = 0;
|
||||
continue;
|
||||
}
|
||||
err(1, "read");
|
||||
}
|
||||
bp = buf;
|
||||
}
|
||||
|
||||
rewrite: if (poll(fdp, 1, INFTIM) == -1) {
|
||||
if (errno != EINTR)
|
||||
err(1, "poll");
|
||||
goto rewrite;
|
||||
}
|
||||
|
||||
if (fdp->revents & (POLLNVAL|POLLERR|POLLHUP))
|
||||
err(1, "poll");
|
||||
|
||||
if ((fdp->revents & POLLOUT) == 0)
|
||||
goto rewrite;
|
||||
|
||||
#if defined(KERBEROS) && defined(CRYPT)
|
||||
if (doencrypt)
|
||||
nw = des_write(rem, bp, nr);
|
||||
else
|
||||
#endif
|
||||
nw = write(rem, bp, nr);
|
||||
|
||||
if (nw < 0) {
|
||||
if (errno == EAGAIN)
|
||||
continue;
|
||||
err(1, "write");
|
||||
}
|
||||
bp += nw;
|
||||
nr -= nw;
|
||||
}
|
||||
done:
|
||||
(void)shutdown(rem, 1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
(void)sigprocmask(SIG_SETMASK, oset, NULL);
|
||||
fds[0].events = fds[1].events = POLLIN|POLLNVAL|POLLERR|POLLHUP;
|
||||
fds[0].fd = remerr;
|
||||
fds[1].fd = rem;
|
||||
fdp = &fds[0];
|
||||
nfds = 2;
|
||||
do {
|
||||
if (poll(fdp, nfds, INFTIM) == -1) {
|
||||
if (errno != EINTR)
|
||||
err(1, "poll");
|
||||
continue;
|
||||
}
|
||||
if (fds[0].events != 0 && checkfd(&fds[0], 2) == -1) {
|
||||
nfds--;
|
||||
fds[0].events = 0;
|
||||
fdp = &fds[1];
|
||||
}
|
||||
if (fds[1].events != 0 && checkfd(&fds[1], 1) == -1) {
|
||||
nfds--;
|
||||
fds[1].events = 0;
|
||||
}
|
||||
}
|
||||
while (nfds);
|
||||
}
|
||||
|
||||
static void
|
||||
sendsig(int sig)
|
||||
{
|
||||
char signo;
|
||||
|
||||
signo = sig;
|
||||
(void)write(remerr, &signo, 1);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
copyargs(char **argv)
|
||||
{
|
||||
int cc;
|
||||
char **ap, *args, *p, *ep;
|
||||
|
||||
cc = 0;
|
||||
for (ap = argv; *ap; ++ap)
|
||||
cc += strlen(*ap) + 1;
|
||||
if (!(args = malloc((u_int)cc)))
|
||||
err(1, "malloc");
|
||||
ep = args + cc;
|
||||
for (p = args, *p = '\0', ap = argv; *ap; ++ap) {
|
||||
(void)strlcpy(p, *ap, ep - p);
|
||||
p += strlen(p);
|
||||
if (ap[1])
|
||||
*p++ = ' ';
|
||||
}
|
||||
*p = '\0';
|
||||
return (args);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"usage: %s [-46dn] [-l login] [-p port]%s [login@]host command\n",
|
||||
getprogname(),
|
||||
#ifdef IN_RCMD
|
||||
" [-u locuser]"
|
||||
#else
|
||||
""
|
||||
#endif
|
||||
);
|
||||
exit(1);
|
||||
}
|
Loading…
Reference in a new issue