Import NetBSD rcmd, rcp, rsh, rshd

Change-Id: I83d908bbe17f04826e9b5c3a220a5bb2c3a51c80
This commit is contained in:
David van Moolenbroek
2015-09-19 17:12:39 +00:00
parent ed223591a8
commit 93d36fc9d8
35 changed files with 3375 additions and 2239 deletions

View File

@@ -2,7 +2,7 @@
# @(#)Makefile 8.1 (Berkeley) 5/31/93
SUBDIR= cat chmod cp date dd df domainname echo ed expr hostname \
kill ksh ln ls mkdir mv pax pwd rm rmdir sh \
kill ksh ln ls mkdir mv pax pwd rcp rcmd rm rmdir sh \
sleep stty sync test
.include <bsd.subdir.mk>

15
bin/rcmd/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 */
}