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 */
}

View File

@ -39,6 +39,8 @@
./bin/printconfig minix-sys
./bin/printroot minix-sys
./bin/pwd minix-sys
./bin/rcmd minix-sys
./bin/rcp minix-sys
./bin/read minix-sys obsolete
./bin/readclock minix-sys
./bin/rm minix-sys
@ -360,7 +362,7 @@
./usr/bin/info minix-sys
./usr/bin/infocmp minix-sys
./usr/bin/infokey minix-sys
./usr/bin/in.rshd minix-sys
./usr/bin/in.rshd minix-sys obsolete
./usr/bin/install minix-sys
./usr/bin/install-info minix-sys
./usr/bin/in.telnetd minix-sys
@ -458,7 +460,7 @@
./usr/bin/ranlib minix-sys binutils
./usr/bin/rarpd minix-sys
./usr/bin/rawspeed minix-sys
./usr/bin/rcp minix-sys
./usr/bin/rcp minix-sys obsolete
./usr/bin/readelf minix-sys binutils
./usr/bin/readlink minix-sys
./usr/bin/recwave minix-sys
@ -2292,6 +2294,7 @@
./usr/libexec/kyua-plain-tester minix-sys kyua
./usr/libexec/ld.elf_so minix-sys
./usr/libexec/makewhatis minix-sys
./usr/libexec/rshd minix-sys
./usr/libexec/virecover minix-sys
./usr/log minix-sys
./usr/log/messages minix-sys
@ -2542,6 +2545,7 @@
./usr/man/man1/pwhash.1 minix-sys
./usr/man/man1/ranlib.1 minix-sys binutils
./usr/man/man1/rcp.1 minix-sys
./usr/man/man1/rcmd.1 minix-sys
./usr/man/man1/read.1 minix-sys obsolete
./usr/man/man1/readelf.1 minix-sys binutils
./usr/man/man1/readlink.1 minix-sys

View File

@ -1,5 +1,5 @@
daemonize talkd
daemonize tcpd shell in.rshd
daemonize tcpd shell /usr/libexec/rshd
daemonize tcpd telnet in.telnetd
daemonize tcpd ftp /usr/libexec/ftpd
daemonize tcpd finger /usr/libexec/fingerd

View File

@ -6,7 +6,7 @@
SUBDIR= \
fingerd ftpd getty \
ld.elf_so \
\
rshd \

26
libexec/rshd/Makefile Normal file
View 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
View 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
View 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);
}

View File

@ -19,9 +19,9 @@ SUBDIR= add_route arp at backup btrace \
nonamed \
postinstall prep printroot \
profile progressbar pr_routes ps pwdauth \
ramdisk rarpd rawspeed rcp readclock \
ramdisk rarpd rawspeed readclock \
remsync rget rlogin \
rotate rsh rshd service setup \
rotate service setup \
slip spell sprofalyze sprofdiff srccrc \
svclog svrctl swifi synctree sysenv \
tcpd tcpdp tcpstat telnet \

View File

@ -1,4 +0,0 @@
PROG= rcp
MAN=
.include <bsd.prog.mk>

View File

@ -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");
}

View File

@ -1,4 +0,0 @@
PROG= rsh
MAN=
.include <bsd.prog.mk>

View File

@ -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);
}

View File

@ -1,5 +0,0 @@
PROG= in.rshd
SRCS= rshd.c
MAN=
.include <bsd.prog.mk>

View File

@ -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);
}

View File

@ -242,6 +242,7 @@ int main(int argc, char **argv)
sigprocmask(SIG_SETMASK, &oldmask, NULL);
dup2(client_fd, 0);
dup2(client_fd, 1);
dup2(client_fd, 2);
close(client_fd);
execvp(progv[0], progv);
report(progv[0]);

View File

@ -12,8 +12,8 @@ MAN= at.1 \
mixer.1 \
mkproto.1 mount.1 mt.1 \
playwave.1 prep.1 \
profile.1 ps.1 rcp.1 recwave.1 \
remsync.1 rget.1 rlogin.1 rsh.1 rz.1 \
profile.1 ps.1 recwave.1 \
remsync.1 rget.1 rlogin.1 rz.1 \
spell.1 svc.1 svrctl.1 \
synctree.1 sysenv.1 sz.1 telnet.1 template.1 \
term.1 termcap.1 tget.1 time.1 \

View File

@ -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.

View File

@ -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).

View File

@ -7,7 +7,7 @@ MAN= add_route.8 backup.8 boot.8 btrace.8 \
ossdevlinks.8 part.8 partition.8 \
printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
readclock.8 repartition.8 \
rshd.8 screendump.8 serial-ip.8 \
screendump.8 serial-ip.8 \
setup.8 shutdown.8 slip.8 srccrc.8 tcpd.8 \
unix.8 update.8 usage.8 vbfs.8

View File

@ -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.

View File

@ -21,7 +21,7 @@ SUBDIR= asa \
nbperf newgrp nice nl nohup \
passwd paste patch pathchk pr \
printenv printf pwhash \
renice rev \
renice rev rsh \
\
sdiff sed seq shar shlock \
shuffle sort split stat su \

13
usr.bin/rsh/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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);
}