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
|
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||||
|
|
||||||
SUBDIR= cat chmod cp date dd df domainname echo ed expr hostname \
|
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
|
sleep stty sync test
|
||||||
|
|
||||||
.include <bsd.subdir.mk>
|
.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/printconfig minix-sys
|
||||||
./bin/printroot minix-sys
|
./bin/printroot minix-sys
|
||||||
./bin/pwd minix-sys
|
./bin/pwd minix-sys
|
||||||
|
./bin/rcmd minix-sys
|
||||||
|
./bin/rcp minix-sys
|
||||||
./bin/read minix-sys obsolete
|
./bin/read minix-sys obsolete
|
||||||
./bin/readclock minix-sys
|
./bin/readclock minix-sys
|
||||||
./bin/rm minix-sys
|
./bin/rm minix-sys
|
||||||
|
@ -360,7 +362,7 @@
|
||||||
./usr/bin/info minix-sys
|
./usr/bin/info minix-sys
|
||||||
./usr/bin/infocmp minix-sys
|
./usr/bin/infocmp minix-sys
|
||||||
./usr/bin/infokey 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 minix-sys
|
||||||
./usr/bin/install-info minix-sys
|
./usr/bin/install-info minix-sys
|
||||||
./usr/bin/in.telnetd minix-sys
|
./usr/bin/in.telnetd minix-sys
|
||||||
|
@ -458,7 +460,7 @@
|
||||||
./usr/bin/ranlib minix-sys binutils
|
./usr/bin/ranlib minix-sys binutils
|
||||||
./usr/bin/rarpd minix-sys
|
./usr/bin/rarpd minix-sys
|
||||||
./usr/bin/rawspeed 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/readelf minix-sys binutils
|
||||||
./usr/bin/readlink minix-sys
|
./usr/bin/readlink minix-sys
|
||||||
./usr/bin/recwave minix-sys
|
./usr/bin/recwave minix-sys
|
||||||
|
@ -2292,6 +2294,7 @@
|
||||||
./usr/libexec/kyua-plain-tester minix-sys kyua
|
./usr/libexec/kyua-plain-tester minix-sys kyua
|
||||||
./usr/libexec/ld.elf_so minix-sys
|
./usr/libexec/ld.elf_so minix-sys
|
||||||
./usr/libexec/makewhatis minix-sys
|
./usr/libexec/makewhatis minix-sys
|
||||||
|
./usr/libexec/rshd minix-sys
|
||||||
./usr/libexec/virecover minix-sys
|
./usr/libexec/virecover minix-sys
|
||||||
./usr/log minix-sys
|
./usr/log minix-sys
|
||||||
./usr/log/messages minix-sys
|
./usr/log/messages minix-sys
|
||||||
|
@ -2542,6 +2545,7 @@
|
||||||
./usr/man/man1/pwhash.1 minix-sys
|
./usr/man/man1/pwhash.1 minix-sys
|
||||||
./usr/man/man1/ranlib.1 minix-sys binutils
|
./usr/man/man1/ranlib.1 minix-sys binutils
|
||||||
./usr/man/man1/rcp.1 minix-sys
|
./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/read.1 minix-sys obsolete
|
||||||
./usr/man/man1/readelf.1 minix-sys binutils
|
./usr/man/man1/readelf.1 minix-sys binutils
|
||||||
./usr/man/man1/readlink.1 minix-sys
|
./usr/man/man1/readlink.1 minix-sys
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
daemonize talkd
|
daemonize talkd
|
||||||
daemonize tcpd shell in.rshd
|
daemonize tcpd shell /usr/libexec/rshd
|
||||||
daemonize tcpd telnet in.telnetd
|
daemonize tcpd telnet in.telnetd
|
||||||
daemonize tcpd ftp /usr/libexec/ftpd
|
daemonize tcpd ftp /usr/libexec/ftpd
|
||||||
daemonize tcpd finger /usr/libexec/fingerd
|
daemonize tcpd finger /usr/libexec/fingerd
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
SUBDIR= \
|
SUBDIR= \
|
||||||
fingerd ftpd getty \
|
fingerd ftpd getty \
|
||||||
ld.elf_so \
|
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 \
|
nonamed \
|
||||||
postinstall prep printroot \
|
postinstall prep printroot \
|
||||||
profile progressbar pr_routes ps pwdauth \
|
profile progressbar pr_routes ps pwdauth \
|
||||||
ramdisk rarpd rawspeed rcp readclock \
|
ramdisk rarpd rawspeed readclock \
|
||||||
remsync rget rlogin \
|
remsync rget rlogin \
|
||||||
rotate rsh rshd service setup \
|
rotate service setup \
|
||||||
slip spell sprofalyze sprofdiff srccrc \
|
slip spell sprofalyze sprofdiff srccrc \
|
||||||
svclog svrctl swifi synctree sysenv \
|
svclog svrctl swifi synctree sysenv \
|
||||||
tcpd tcpdp tcpstat telnet \
|
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);
|
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||||
dup2(client_fd, 0);
|
dup2(client_fd, 0);
|
||||||
dup2(client_fd, 1);
|
dup2(client_fd, 1);
|
||||||
|
dup2(client_fd, 2);
|
||||||
close(client_fd);
|
close(client_fd);
|
||||||
execvp(progv[0], progv);
|
execvp(progv[0], progv);
|
||||||
report(progv[0]);
|
report(progv[0]);
|
||||||
|
|
|
@ -12,8 +12,8 @@ MAN= at.1 \
|
||||||
mixer.1 \
|
mixer.1 \
|
||||||
mkproto.1 mount.1 mt.1 \
|
mkproto.1 mount.1 mt.1 \
|
||||||
playwave.1 prep.1 \
|
playwave.1 prep.1 \
|
||||||
profile.1 ps.1 rcp.1 recwave.1 \
|
profile.1 ps.1 recwave.1 \
|
||||||
remsync.1 rget.1 rlogin.1 rsh.1 rz.1 \
|
remsync.1 rget.1 rlogin.1 rz.1 \
|
||||||
spell.1 svc.1 svrctl.1 \
|
spell.1 svc.1 svrctl.1 \
|
||||||
synctree.1 sysenv.1 sz.1 telnet.1 template.1 \
|
synctree.1 sysenv.1 sz.1 telnet.1 template.1 \
|
||||||
term.1 termcap.1 tget.1 time.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 \
|
ossdevlinks.8 part.8 partition.8 \
|
||||||
printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
|
printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
|
||||||
readclock.8 repartition.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 \
|
setup.8 shutdown.8 slip.8 srccrc.8 tcpd.8 \
|
||||||
unix.8 update.8 usage.8 vbfs.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 \
|
nbperf newgrp nice nl nohup \
|
||||||
passwd paste patch pathchk pr \
|
passwd paste patch pathchk pr \
|
||||||
printenv printf pwhash \
|
printenv printf pwhash \
|
||||||
renice rev \
|
renice rev rsh \
|
||||||
\
|
\
|
||||||
sdiff sed seq shar shlock \
|
sdiff sed seq shar shlock \
|
||||||
shuffle sort split stat su \
|
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