Remove rcmds.
If they are still needed, you can find them in the net/bsdrcmds port. This was proposed June, 20th and approved by various committers [1]. They have been marked as deprecated on CURRENT in r320644 [2] on July, 4th. Both stable/11 and release/11.1 contain the deprecation notice (thanks to allanjude@). Note that ruptime(1)/rwho(1)/rwhod(8) were initially thought to be part of rcmds but this was a mistake and those are therefore NOT removed. [1] https://lists.freebsd.org/pipermail/freebsd-arch/2017-June/018239.html [2] https://svnweb.freebsd.org/base?view=revision&revision=320644 Reviewed by: bapt, brooks Differential Revision: https://reviews.freebsd.org/D12573
This commit is contained in:
parent
ac63ac6859
commit
e415aa2846
@ -38,6 +38,18 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20171003: remove RCMDS
|
||||
OLD_FILES+=bin/rcp
|
||||
OLD_FILES+=rescue/rcp
|
||||
OLD_FILES+=usr/bin/rlogin
|
||||
OLD_FILES+=usr/bin/rsh
|
||||
OLD_FILES+=usr/libexec/rlogind
|
||||
OLD_FILES+=usr/libexec/rshd
|
||||
OLD_FILES+=usr/share/man/man1/rcp.1.gz
|
||||
OLD_FILES+=usr/share/man/man1/rlogin.1.gz
|
||||
OLD_FILES+=usr/share/man/man1/rsh.1.gz
|
||||
OLD_FILES+=usr/share/man/man8/rlogind.8.gz
|
||||
OLD_FILES+=usr/share/man/man8/rshd.8.gz
|
||||
# 20170927: crshared
|
||||
OLD_FILES+=usr/share/man/man9/crshared.9.gz
|
||||
# 20170927: procctl
|
||||
|
@ -40,7 +40,6 @@ SUBDIR= cat \
|
||||
test \
|
||||
uuidgen
|
||||
|
||||
SUBDIR.${MK_RCMDS}+= rcp
|
||||
SUBDIR.${MK_SENDMAIL}+= rmail
|
||||
SUBDIR.${MK_TCSH}+= csh
|
||||
SUBDIR.${MK_TESTS}+= tests
|
||||
|
@ -1,19 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 7/19/93
|
||||
# $FreeBSD$
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
PACKAGE=rcmds
|
||||
PROG= rcp
|
||||
SRCS= rcp.c util.c
|
||||
CFLAGS+=-DBINDIR=${BINDIR}
|
||||
|
||||
PACKAGE=rcmds
|
||||
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
|
||||
HAS_TESTS=
|
||||
SUBDIR.${MK_TESTS}+= tests
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,18 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
gnu/lib/libgcc \
|
||||
include \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,47 +0,0 @@
|
||||
/*-
|
||||
* 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
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
size_t 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 *, ...) __printflike(1, 2);
|
||||
int susystem(char *, int);
|
||||
void verifydir(char *);
|
160
bin/rcp/rcp.1
160
bin/rcp/rcp.1
@ -1,160 +0,0 @@
|
||||
.\"-
|
||||
.\" 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
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 3, 2017
|
||||
.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
|
||||
.Ar directory
|
||||
.Sh DEPRECATION NOTICE
|
||||
.Nm
|
||||
is deprecated and will be removed from future versions of the
|
||||
.Fx
|
||||
base system.
|
||||
If
|
||||
.Nm
|
||||
is still required, it can be installed from ports or packages
|
||||
(net/bsdrcmds).
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility copies files between machines.
|
||||
Each
|
||||
.Ar file
|
||||
or
|
||||
.Ar directory
|
||||
argument is either a remote file name of the
|
||||
form
|
||||
.Dq ruser@rhost:path ,
|
||||
or a local file name (containing no
|
||||
.Ql :\&
|
||||
characters,
|
||||
or a
|
||||
.Ql /
|
||||
before any
|
||||
.Ql :\& Ns
|
||||
s).
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width indent
|
||||
.It Fl 4
|
||||
Use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Use IPv6 addresses only.
|
||||
.It Fl p
|
||||
Cause
|
||||
.Nm
|
||||
to attempt to preserve (duplicate) in its copies the modification
|
||||
times and modes of the source files, ignoring the
|
||||
.Xr umask 2 .
|
||||
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
|
||||
.Ql \e ,
|
||||
.Ql \&" ,
|
||||
or
|
||||
.Ql \(aa )
|
||||
so that the metacharacters are interpreted remotely.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility does not prompt for passwords; it performs remote execution
|
||||
via
|
||||
.Xr rsh 1 ,
|
||||
and requires the same authorization.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility 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 rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr hosts.equiv 5
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
The version of
|
||||
.Nm
|
||||
described here
|
||||
has been reimplemented with Kerberos in
|
||||
.Bx 4.3 Reno .
|
||||
.Sh BUGS
|
||||
Does not 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.ruser
|
||||
when the destination machine is running the
|
||||
.Bx 4.2
|
||||
version of
|
||||
.Nm .
|
791
bin/rcp/rcp.c
791
bin/rcp/rcp.c
@ -1,791 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1983, 1990, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Networks Associates Technology, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static char const copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1990, 1992, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)rcp.c 8.2 (Berkeley) 4/2/94";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#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 <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#define OPTIONS "46dfprt"
|
||||
|
||||
static struct passwd *pwd;
|
||||
static u_short port;
|
||||
static uid_t userid;
|
||||
static int errs, rem;
|
||||
int iamremote;
|
||||
static int pflag, iamrecursive, targetshouldbedirectory;
|
||||
static int family = PF_UNSPEC;
|
||||
|
||||
static int argc_copy;
|
||||
static const char **argv_copy;
|
||||
|
||||
static char period[] = ".";
|
||||
|
||||
#define CMDNEEDS 64
|
||||
static 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, i, tflag;
|
||||
char *targ;
|
||||
|
||||
/*
|
||||
* Prepare for execing ourselves.
|
||||
*/
|
||||
argc_copy = argc + 1;
|
||||
argv_copy = malloc((argc_copy + 1) * sizeof(*argv_copy));
|
||||
if (argv_copy == NULL)
|
||||
err(1, "malloc");
|
||||
argv_copy[0] = argv[0];
|
||||
argv_copy[1] = "-K";
|
||||
for (i = 1; i < argc; ++i) {
|
||||
argv_copy[i + 1] = strdup(argv[i]);
|
||||
if (argv_copy[i + 1] == NULL)
|
||||
errx(1, "strdup: out of memory");
|
||||
}
|
||||
argv_copy[argc + 1] = NULL;
|
||||
|
||||
fflag = tflag = 0;
|
||||
while ((ch = getopt(argc, argv, OPTIONS)) != -1)
|
||||
switch(ch) { /* User-visible flags. */
|
||||
case '4':
|
||||
family = PF_INET;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
family = PF_INET6;
|
||||
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", "tcp");
|
||||
if (sp == NULL)
|
||||
errx(1, "shell/tcp: unknown service");
|
||||
port = sp->s_port;
|
||||
|
||||
if ((pwd = getpwuid(userid = getuid())) == NULL)
|
||||
errx(1, "unknown user %d", (int)userid);
|
||||
|
||||
rem = STDIN_FILENO; /* XXX */
|
||||
|
||||
if (fflag) { /* Follow "protocol", send data. */
|
||||
(void)response();
|
||||
(void)setuid(userid);
|
||||
source(argc, argv);
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
if (tflag) { /* Receive data. */
|
||||
(void)setuid(userid);
|
||||
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]))) /* Dest is remote host. */
|
||||
toremote(targ, argc, argv);
|
||||
else {
|
||||
tolocal(argc, argv); /* Dest is local host. */
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(argv[argc - 1]);
|
||||
}
|
||||
exit(errs);
|
||||
}
|
||||
|
||||
void
|
||||
toremote(char *targ, int argc, char *argv[])
|
||||
{
|
||||
int i, tos;
|
||||
char *bp, *host, *src, *suser, *thost, *tuser;
|
||||
|
||||
*targ++ = 0;
|
||||
if (*targ == 0)
|
||||
targ = period;
|
||||
|
||||
if ((thost = strchr(argv[argc - 1], '@'))) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
src = colon(argv[i]);
|
||||
if (src) { /* remote to remote */
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
src = period;
|
||||
host = strchr(argv[i], '@');
|
||||
if (host) {
|
||||
*host++ = 0;
|
||||
suser = argv[i];
|
||||
if (*suser == '\0')
|
||||
suser = pwd->pw_name;
|
||||
else if (!okname(suser)) {
|
||||
++errs;
|
||||
continue;
|
||||
}
|
||||
if (asprintf(&bp,
|
||||
"%s %s -l %s -n %s %s '%s%s%s:%s'",
|
||||
_PATH_RSH, host, suser, cmd, src,
|
||||
tuser ? tuser : "", tuser ? "@" : "",
|
||||
thost, targ) == -1)
|
||||
err(1, "asprintf");
|
||||
} else
|
||||
if (asprintf(&bp,
|
||||
"exec %s %s -n %s %s '%s%s%s:%s'",
|
||||
_PATH_RSH, argv[i], cmd, src,
|
||||
tuser ? tuser : "", tuser ? "@" : "",
|
||||
thost, targ) == -1)
|
||||
err(1, "asprintf");
|
||||
(void)susystem(bp, userid);
|
||||
(void)free(bp);
|
||||
} else { /* local to remote */
|
||||
if (rem == -1) {
|
||||
if (asprintf(&bp, "%s -t %s", cmd, targ)
|
||||
== -1)
|
||||
err(1, "asprintf");
|
||||
host = thost;
|
||||
rem = rcmd_af(&host, port,
|
||||
pwd->pw_name,
|
||||
tuser ? tuser : pwd->pw_name,
|
||||
bp, 0, family);
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
if (family == PF_INET) {
|
||||
tos = IPTOS_THROUGHPUT;
|
||||
if (setsockopt(rem, IPPROTO_IP, IP_TOS,
|
||||
&tos, sizeof(int)) < 0)
|
||||
warn("TOS (ignored)");
|
||||
}
|
||||
if (response() < 0)
|
||||
exit(1);
|
||||
(void)free(bp);
|
||||
(void)setuid(userid);
|
||||
}
|
||||
source(1, argv+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tolocal(int argc, char *argv[])
|
||||
{
|
||||
int i, len, tos;
|
||||
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, "malloc");
|
||||
(void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
|
||||
iamrecursive ? " -PR" : "", pflag ? " -p" : "",
|
||||
argv[i], argv[argc - 1]);
|
||||
if (susystem(bp, userid))
|
||||
++errs;
|
||||
(void)free(bp);
|
||||
continue;
|
||||
}
|
||||
*src++ = 0;
|
||||
if (*src == 0)
|
||||
src = period;
|
||||
if ((host = strchr(argv[i], '@')) == NULL) {
|
||||
host = argv[i];
|
||||
suser = pwd->pw_name;
|
||||
} else {
|
||||
*host++ = 0;
|
||||
suser = argv[i];
|
||||
if (*suser == '\0')
|
||||
suser = pwd->pw_name;
|
||||
else if (!okname(suser)) {
|
||||
++errs;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
len = strlen(src) + CMDNEEDS + 20;
|
||||
if ((bp = malloc(len)) == NULL)
|
||||
err(1, "malloc");
|
||||
(void)snprintf(bp, len, "%s -f %s", cmd, src);
|
||||
rem = rcmd_af(&host, port, pwd->pw_name, suser, bp, 0,
|
||||
family);
|
||||
(void)free(bp);
|
||||
if (rem < 0) {
|
||||
++errs;
|
||||
continue;
|
||||
}
|
||||
(void)seteuid(userid);
|
||||
if (family == PF_INET) {
|
||||
tos = IPTOS_THROUGHPUT;
|
||||
if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos,
|
||||
sizeof(int)) < 0)
|
||||
warn("TOS (ignored)");
|
||||
}
|
||||
sink(1, argv + argc - 1);
|
||||
(void)seteuid(0);
|
||||
(void)close(rem);
|
||||
rem = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
source(int argc, char *argv[])
|
||||
{
|
||||
struct stat stb;
|
||||
static BUF buffer;
|
||||
BUF *bp;
|
||||
off_t i;
|
||||
int amt, 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%ld 0 %ld 0\n",
|
||||
(long)stb.st_mtim.tv_sec,
|
||||
(long)stb.st_atim.tv_sec);
|
||||
(void)write(rem, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
}
|
||||
#define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
|
||||
(void)snprintf(buf, sizeof(buf), "C%04o %jd %s\n",
|
||||
stb.st_mode & MODEMASK, (intmax_t)stb.st_size, last);
|
||||
(void)write(rem, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
|
||||
next: if (fd >= 0)
|
||||
(void)close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Keep writing after an error so that we stay sync'd up. */
|
||||
for (haderr = 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, amt);
|
||||
if (result != amt)
|
||||
haderr = result >= 0 ? EIO : errno;
|
||||
}
|
||||
if (haderr)
|
||||
(void)write(rem, bp->buf, amt);
|
||||
else {
|
||||
result = write(rem, bp->buf, 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[PATH_MAX];
|
||||
|
||||
if (!(dirp = opendir(name))) {
|
||||
run_err("%s: %s", name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
last = strrchr(name, '/');
|
||||
if (last == NULL)
|
||||
last = name;
|
||||
else
|
||||
last++;
|
||||
if (pflag) {
|
||||
(void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n",
|
||||
(long)statp->st_mtim.tv_sec,
|
||||
(long)statp->st_atim.tv_sec);
|
||||
(void)write(rem, path, strlen(path));
|
||||
if (response() < 0) {
|
||||
closedir(dirp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
(void)snprintf(path, sizeof(path),
|
||||
"D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last);
|
||||
(void)write(rem, path, strlen(path));
|
||||
if (response() < 0) {
|
||||
closedir(dirp);
|
||||
return;
|
||||
}
|
||||
while ((dp = readdir(dirp))) {
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
|
||||
continue;
|
||||
if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path)) {
|
||||
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;
|
||||
off_t i, j, size;
|
||||
int amt, exists, first, mask, mode, ofd, omode;
|
||||
size_t count;
|
||||
int setimes, targisdir, wrerrno = 0;
|
||||
char ch, *cp, *np, *targ, *vect[1], buf[BUFSIZ], path[PATH_MAX];
|
||||
const char *why;
|
||||
|
||||
#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)
|
||||
return;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch == '\n')
|
||||
*--cp = 0;
|
||||
|
||||
cp = buf;
|
||||
if (*cp == 'T') {
|
||||
setimes++;
|
||||
cp++;
|
||||
mtime.tv_sec = strtol(cp, &cp, 10);
|
||||
if (!cp || *cp++ != ' ')
|
||||
SCREWUP("mtime.sec not delimited");
|
||||
mtime.tv_usec = strtol(cp, &cp, 10);
|
||||
if (!cp || *cp++ != ' ')
|
||||
SCREWUP("mtime.usec not delimited");
|
||||
atime.tv_sec = strtol(cp, &cp, 10);
|
||||
if (!cp || *cp++ != ' ')
|
||||
SCREWUP("atime.sec not delimited");
|
||||
atime.tv_usec = strtol(cp, &cp, 10);
|
||||
if (!cp || *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(*cp);)
|
||||
size = size * 10 + (*cp++ - '0');
|
||||
if (*cp++ != ' ')
|
||||
SCREWUP("size not delimited");
|
||||
if (targisdir) {
|
||||
if (strlen(targ) + (*targ ? 1 : 0) + strlen(cp)
|
||||
>= sizeof(path)) {
|
||||
run_err("%s%s%s: name too long", targ,
|
||||
*targ ? "/" : "", cp);
|
||||
exit(1);
|
||||
}
|
||||
(void)snprintf(path, sizeof(path), "%s%s%s", targ,
|
||||
*targ ? "/" : "", cp);
|
||||
np = path;
|
||||
} 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;
|
||||
for (count = 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) {
|
||||
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, count);
|
||||
if (j != (off_t)count) {
|
||||
wrerr = YES;
|
||||
wrerrno = j >= 0 ? EIO : errno;
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
cp = bp->buf;
|
||||
}
|
||||
}
|
||||
if (count != 0 && wrerr == NO &&
|
||||
(j = write(ofd, bp->buf, count)) != (off_t)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));
|
||||
}
|
||||
(void)close(ofd);
|
||||
(void)response();
|
||||
if (setimes && wrerr == NO) {
|
||||
setimes = 0;
|
||||
if (utimes(np, tv) < 0) {
|
||||
run_err("%s: set times: %s",
|
||||
np, strerror(errno));
|
||||
wrerr = DISPLAYED;
|
||||
}
|
||||
}
|
||||
switch(wrerr) {
|
||||
case YES:
|
||||
run_err("%s: %s", np, strerror(wrerrno));
|
||||
break;
|
||||
case NO:
|
||||
(void)write(rem, "", 1);
|
||||
break;
|
||||
case DISPLAYED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
screwup:
|
||||
run_err("protocol error: %s", why);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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, cp - rbuf);
|
||||
++errs;
|
||||
if (resp == 1)
|
||||
return (-1);
|
||||
exit(1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "%s\n%s\n",
|
||||
"usage: rcp [-46p] file1 file2",
|
||||
" rcp [-46pr] file ... directory");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void
|
||||
run_err(const char *fmt, ...)
|
||||
{
|
||||
static FILE *fp;
|
||||
va_list ap;
|
||||
|
||||
++errs;
|
||||
if (fp == NULL && !(fp = fdopen(rem, "w")))
|
||||
return;
|
||||
(void)fprintf(fp, "%c", 0x01);
|
||||
(void)fprintf(fp, "rcp: ");
|
||||
va_start(ap, fmt);
|
||||
(void)vfprintf(fp, fmt, ap);
|
||||
va_end(ap);
|
||||
(void)fprintf(fp, "\n");
|
||||
(void)fflush(fp);
|
||||
|
||||
if (!iamremote) {
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
# $FreeBSD$
|
||||
|
||||
ATF_TESTS_SH+= rcp_test
|
||||
|
||||
.include <bsd.test.mk>
|
@ -1,60 +0,0 @@
|
||||
#
|
||||
# Copyright 2017 Shivansh Rai
|
||||
# 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 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 AUTHOR 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.
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
usage_output='usage: rcp'
|
||||
|
||||
atf_test_case invalid_usage
|
||||
invalid_usage_head()
|
||||
{
|
||||
atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message"
|
||||
}
|
||||
|
||||
invalid_usage_body()
|
||||
{
|
||||
atf_check -s not-exit:0 -e match:"$usage_output" rcp -4
|
||||
atf_check -s not-exit:0 -e match:"$usage_output" rcp -6
|
||||
atf_check -s not-exit:0 -e match:"$usage_output" rcp -p
|
||||
atf_check -s not-exit:0 -e match:"$usage_output" rcp -r
|
||||
}
|
||||
|
||||
atf_test_case no_arguments
|
||||
no_arguments_head()
|
||||
{
|
||||
atf_set "descr" "Verify that rcp(1) fails and generates a valid usage message when no arguments are supplied"
|
||||
}
|
||||
|
||||
no_arguments_body()
|
||||
{
|
||||
atf_check -s not-exit:0 -e match:"$usage_output" rcp
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case invalid_usage
|
||||
atf_add_test_case no_arguments
|
||||
}
|
159
bin/rcp/util.c
159
bin/rcp/util.c
@ -1,159 +0,0 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static const char sccsid[] = "@(#)util.c 8.2 (Berkeley) 4/2/94";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 != '-' && c != '.')
|
||||
goto bad;
|
||||
} while (*++cp);
|
||||
return (1);
|
||||
|
||||
bad: warnx("%s: invalid user name", cp0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
susystem(char *s, int userid)
|
||||
{
|
||||
sig_t istat, qstat;
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
pid = vfork();
|
||||
switch (pid) {
|
||||
case -1:
|
||||
return (127);
|
||||
|
||||
case 0:
|
||||
(void)setuid(userid);
|
||||
execl(_PATH_BSHELL, "sh", "-c", s, (char *)NULL);
|
||||
_exit(127);
|
||||
}
|
||||
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;
|
||||
|
||||
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 ((bp->buf = realloc(bp->buf, size)) == NULL) {
|
||||
bp->cnt = 0;
|
||||
run_err("%s", strerror(errno));
|
||||
return (0);
|
||||
}
|
||||
bp->cnt = size;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
void
|
||||
lostconn(int signo __unused)
|
||||
{
|
||||
if (!iamremote)
|
||||
warnx("lost connection");
|
||||
exit(1);
|
||||
}
|
@ -12,10 +12,10 @@
|
||||
#ssh stream tcp6 nowait root /usr/sbin/sshd sshd -i -6
|
||||
#telnet stream tcp nowait root /usr/libexec/telnetd telnetd
|
||||
#telnet stream tcp6 nowait root /usr/libexec/telnetd telnetd
|
||||
#shell stream tcp nowait root /usr/libexec/rshd rshd
|
||||
#shell stream tcp6 nowait root /usr/libexec/rshd rshd
|
||||
#login stream tcp nowait root /usr/libexec/rlogind rlogind
|
||||
#login stream tcp6 nowait root /usr/libexec/rlogind rlogind
|
||||
#shell stream tcp nowait root /usr/local/sbin/rshd rshd
|
||||
#shell stream tcp6 nowait root /usr/local/sbin/rshd rshd
|
||||
#login stream tcp nowait root /usr/local/sbin/rlogind rlogind
|
||||
#login stream tcp6 nowait root /usr/local/sbin/rlogind rlogind
|
||||
#finger stream tcp nowait/3/10 nobody /usr/libexec/fingerd fingerd -k -s
|
||||
#finger stream tcp6 nowait/3/10 nobody /usr/libexec/fingerd fingerd -k -s
|
||||
#
|
||||
|
@ -34,8 +34,6 @@
|
||||
..
|
||||
pwait
|
||||
..
|
||||
rcp
|
||||
..
|
||||
rmdir
|
||||
..
|
||||
sh
|
||||
|
@ -35,14 +35,6 @@ FTPMODE= ${FILESMODE}
|
||||
LINKS= ${FILESDIR}/ftpd ${FILESDIR}/ftp
|
||||
.endif
|
||||
|
||||
.if ${MK_RCMDS} != "no"
|
||||
FILESGROUPS+= RCMDS
|
||||
RCMDS+= rsh
|
||||
RCMDSPACKAGE+= rcmds
|
||||
RCMDSDIR= ${FILESDIR}
|
||||
RCMDSMODE= ${FILESMODE}
|
||||
.endif
|
||||
|
||||
.if ${MK_TELNET} != "no"
|
||||
FILESGROUPS+= TELNET
|
||||
TELNET+= telnetd
|
||||
|
@ -1,18 +0,0 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
# PAM configuration for the "rsh" service
|
||||
#
|
||||
|
||||
# auth
|
||||
auth required pam_rhosts.so no_warn
|
||||
|
||||
# account
|
||||
account required pam_nologin.so
|
||||
account required pam_unix.so
|
||||
|
||||
# session
|
||||
session required pam_permit.so
|
||||
|
||||
# password
|
||||
password required pam_deny.so
|
@ -79,11 +79,6 @@ _rtld-elf= rtld-elf
|
||||
SUBDIR+= rbootd
|
||||
.endif
|
||||
|
||||
.if ${MK_RCMDS} != "no"
|
||||
_rlogind= rlogind
|
||||
_rshd= rshd
|
||||
.endif
|
||||
|
||||
.if ${MK_SENDMAIL} != "no"
|
||||
_mail.local= mail.local
|
||||
_smrsh= smrsh
|
||||
|
@ -1,23 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
# $FreeBSD$
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
PACKAGE=rcmds
|
||||
PROG= rlogind
|
||||
MAN= rlogind.8
|
||||
PACKAGE=rcmds
|
||||
LIBADD= util
|
||||
WARNS?= 2
|
||||
|
||||
.if ${MK_INET6_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET6
|
||||
.endif
|
||||
|
||||
.if ${MK_BLACKLIST_SUPPORT} != "no"
|
||||
CFLAGS+= -DUSE_BLACKLIST -I${SRCTOP}/contrib/blacklist/include
|
||||
LIBADD+= blacklist
|
||||
LDFLAGS+=-L${LIBBLACKLISTDIR}
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,22 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
gnu/lib/libgcc \
|
||||
include \
|
||||
include/arpa \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libblacklist \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
lib/libthr \
|
||||
lib/libutil \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,202 +0,0 @@
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)rlogind.8 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 3, 2017
|
||||
.Dt RLOGIND 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rlogind
|
||||
.Nd remote login server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl Daln
|
||||
.Sh DEPRECATION NOTICE
|
||||
.Nm
|
||||
is deprecated and will be removed from future versions of the
|
||||
.Fx
|
||||
base system.
|
||||
If
|
||||
.Nm
|
||||
is still required, it can be installed from ports or packages
|
||||
(net/bsdrcmds).
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is the server for the
|
||||
.Xr rlogin 1
|
||||
program.
|
||||
The server provides a remote login facility
|
||||
with authentication based on privileged port numbers from trusted hosts.
|
||||
.Pp
|
||||
Options supported by
|
||||
.Nm :
|
||||
.Bl -tag -width indent
|
||||
.It Fl D
|
||||
Set TCP_NODELAY socket option.
|
||||
This improves responsiveness at the expense of
|
||||
some additional network traffic.
|
||||
.It Fl a
|
||||
Ask hostname for verification.
|
||||
.It Fl l
|
||||
Prevent any authentication based on the user's
|
||||
.Dq Pa .rhosts
|
||||
file, unless the user is logging in as the superuser.
|
||||
.It Fl n
|
||||
Disable keep-alive messages.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility listens for service requests at the port indicated in
|
||||
the
|
||||
.Dq login
|
||||
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 checks the client's source address
|
||||
and requests the corresponding host name (see
|
||||
.Xr gethostbyaddr 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.
|
||||
Normal authentication is bypassed if the address verification fails.
|
||||
.El
|
||||
.Pp
|
||||
Once the source port and address have been checked,
|
||||
.Nm
|
||||
proceeds with the authentication process described in
|
||||
.Xr rshd 8 .
|
||||
It then allocates a pseudo terminal (see
|
||||
.Xr pty 4 ) ,
|
||||
and manipulates file descriptors so that the slave
|
||||
half of the pseudo terminal becomes the
|
||||
.Em stdin ,
|
||||
.Em stdout ,
|
||||
and
|
||||
.Em stderr
|
||||
for a login process.
|
||||
The login process is an instance of the
|
||||
.Xr login 1
|
||||
program, invoked with the
|
||||
.Fl f
|
||||
option if authentication has succeeded.
|
||||
If automatic authentication fails, the user is
|
||||
prompted to log in as if on a standard terminal line.
|
||||
.Pp
|
||||
The parent of the login process manipulates the master side of
|
||||
the pseudo terminal, operating as an intermediary
|
||||
between the login process and the client instance of the
|
||||
.Xr rlogin 1
|
||||
program.
|
||||
In normal operation, the packet protocol described
|
||||
in
|
||||
.Xr pty 4
|
||||
is invoked to provide
|
||||
.Ql ^S/^Q
|
||||
type facilities and propagate
|
||||
interrupt signals to the remote programs.
|
||||
The login process
|
||||
propagates the client terminal's baud rate and terminal type,
|
||||
as found in the environment variable,
|
||||
.Ev TERM ;
|
||||
see
|
||||
.Xr environ 7 .
|
||||
The screen or window size of the terminal is requested from the client,
|
||||
and window size changes from the client are propagated to the pseudo terminal.
|
||||
.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.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/hostsxxxxxxxx -compact
|
||||
.It Pa /etc/hosts
|
||||
.It Pa /etc/hosts.equiv
|
||||
.It Ev $HOME Ns Pa /.rhosts
|
||||
.It Pa /var/run/nologin
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
All initial diagnostic messages are indicated
|
||||
by a leading byte with a value of 1,
|
||||
after which any network connections are closed.
|
||||
If there are no errors before
|
||||
.Xr login 1
|
||||
is invoked, a null byte is returned as in indication of success.
|
||||
.Bl -tag -width Ds
|
||||
.It Sy Try again.
|
||||
A
|
||||
.Xr fork 2
|
||||
by the server failed.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr login 1 ,
|
||||
.Xr ruserok 3 ,
|
||||
.Xr hosts 5 ,
|
||||
.Xr hosts.equiv 5 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr nologin 5 ,
|
||||
.Xr services 5 ,
|
||||
.Xr rshd 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility appeared in
|
||||
.Bx 4.2 .
|
||||
.Pp
|
||||
IPv6 support was added by WIDE/KAME project.
|
||||
.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
|
||||
.Dq open
|
||||
environment.
|
||||
.Pp
|
||||
A facility to allow all data exchanges to be encrypted should be
|
||||
present.
|
||||
.Pp
|
||||
A more extensible protocol should be used.
|
@ -1,583 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1983, 1988, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Networks Associates Technology, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* remote login server:
|
||||
* \0
|
||||
* remuser\0
|
||||
* locuser\0
|
||||
* terminal_type/speed\0
|
||||
* data
|
||||
*/
|
||||
|
||||
#define FD_SETSIZE 16 /* don't need many bits for select */
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
#include <paths.h>
|
||||
#include <poll.h>
|
||||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef USE_BLACKLIST
|
||||
#include <blacklist.h>
|
||||
#endif
|
||||
|
||||
#ifndef TIOCPKT_WINDOW
|
||||
#define TIOCPKT_WINDOW 0x80
|
||||
#endif
|
||||
|
||||
#define ARGSTR "Daln"
|
||||
|
||||
char *env[2];
|
||||
#define NMAX 30
|
||||
char lusername[NMAX+1], rusername[NMAX+1];
|
||||
static char term[64] = "TERM=";
|
||||
#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
|
||||
int keepalive = 1;
|
||||
int check_all = 0;
|
||||
int no_delay;
|
||||
|
||||
struct passwd *pwd;
|
||||
|
||||
union sockunion {
|
||||
struct sockinet {
|
||||
u_char si_len;
|
||||
u_char si_family;
|
||||
u_short si_port;
|
||||
} su_si;
|
||||
struct sockaddr_in su_sin;
|
||||
struct sockaddr_in6 su_sin6;
|
||||
};
|
||||
#define su_len su_si.si_len
|
||||
#define su_family su_si.si_family
|
||||
#define su_port su_si.si_port
|
||||
|
||||
void doit(int, union sockunion *);
|
||||
int control(int, char *, int);
|
||||
void protocol(int, int);
|
||||
void cleanup(int);
|
||||
void fatal(int, char *, int);
|
||||
int do_rlogin(union sockunion *);
|
||||
void getstr(char *, int, char *);
|
||||
void setup_term(int);
|
||||
int do_krb_login(struct sockaddr_in *);
|
||||
void usage(void);
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
extern int __check_rhosts_file;
|
||||
union sockunion from;
|
||||
socklen_t fromlen;
|
||||
int ch, on;
|
||||
|
||||
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
|
||||
|
||||
opterr = 0;
|
||||
while ((ch = getopt(argc, argv, ARGSTR)) != -1)
|
||||
switch (ch) {
|
||||
case 'D':
|
||||
no_delay = 1;
|
||||
break;
|
||||
case 'a':
|
||||
check_all = 1;
|
||||
break;
|
||||
case 'l':
|
||||
__check_rhosts_file = 0;
|
||||
break;
|
||||
case 'n':
|
||||
keepalive = 0;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
fromlen = sizeof (from);
|
||||
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
|
||||
syslog(LOG_ERR,"Can't get peer name of remote host: %m");
|
||||
fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
|
||||
}
|
||||
on = 1;
|
||||
if (keepalive &&
|
||||
setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
|
||||
if (no_delay &&
|
||||
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
|
||||
if (from.su_family == AF_INET)
|
||||
{
|
||||
on = IPTOS_LOWDELAY;
|
||||
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
|
||||
}
|
||||
|
||||
doit(0, &from);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int child;
|
||||
int netf;
|
||||
char line[MAXPATHLEN];
|
||||
int confirmed;
|
||||
|
||||
struct winsize win = { 0, 0, 0, 0 };
|
||||
|
||||
|
||||
void
|
||||
doit(int f, union sockunion *fromp)
|
||||
{
|
||||
int master, pid, on = 1;
|
||||
int authenticated = 0;
|
||||
char hostname[2 * MAXHOSTNAMELEN + 1];
|
||||
char nameinfo[2 * INET6_ADDRSTRLEN + 1];
|
||||
char c;
|
||||
|
||||
alarm(60);
|
||||
read(f, &c, 1);
|
||||
|
||||
if (c != 0)
|
||||
exit(1);
|
||||
|
||||
alarm(0);
|
||||
|
||||
realhostname_sa(hostname, sizeof(hostname) - 1,
|
||||
(struct sockaddr *)fromp, fromp->su_len);
|
||||
/* error check ? */
|
||||
fromp->su_port = ntohs((u_short)fromp->su_port);
|
||||
hostname[sizeof(hostname) - 1] = '\0';
|
||||
|
||||
{
|
||||
if ((fromp->su_family != AF_INET
|
||||
#ifdef INET6
|
||||
&& fromp->su_family != AF_INET6
|
||||
#endif
|
||||
) ||
|
||||
fromp->su_port >= IPPORT_RESERVED ||
|
||||
fromp->su_port < IPPORT_RESERVED/2) {
|
||||
getnameinfo((struct sockaddr *)fromp,
|
||||
fromp->su_len,
|
||||
nameinfo, sizeof(nameinfo), NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
/* error check ? */
|
||||
syslog(LOG_NOTICE, "Connection from %s on illegal port",
|
||||
nameinfo);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "illegal port");
|
||||
#endif
|
||||
fatal(f, "Permission denied", 0);
|
||||
}
|
||||
#ifdef IP_OPTIONS
|
||||
if (fromp->su_family == AF_INET)
|
||||
{
|
||||
u_char optbuf[BUFSIZ/3];
|
||||
socklen_t optsize = sizeof(optbuf);
|
||||
int ipproto, 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) == 0 && 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(fromp->su_sin.sin_addr),
|
||||
c == IPOPT_LSRR ? "LSRR" : "SSRR");
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "source routing present");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
if (c == IPOPT_EOL)
|
||||
break;
|
||||
i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (do_rlogin(fromp) == 0)
|
||||
authenticated++;
|
||||
}
|
||||
if (confirmed == 0) {
|
||||
write(f, "", 1);
|
||||
confirmed = 1; /* we sent the null! */
|
||||
}
|
||||
netf = f;
|
||||
|
||||
pid = forkpty(&master, line, NULL, &win);
|
||||
if (pid < 0) {
|
||||
if (errno == ENOENT)
|
||||
fatal(f, "Out of ptys", 0);
|
||||
else
|
||||
fatal(f, "Forkpty", 1);
|
||||
}
|
||||
if (pid == 0) {
|
||||
if (f > 2) /* f should always be 0, but... */
|
||||
(void) close(f);
|
||||
setup_term(0);
|
||||
if (*lusername=='-') {
|
||||
syslog(LOG_ERR, "tried to pass user \"%s\" to login",
|
||||
lusername);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "invalid user");
|
||||
#endif
|
||||
fatal(STDERR_FILENO, "invalid user", 0);
|
||||
}
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(0, STDIN_FILENO, "success");
|
||||
#endif
|
||||
if (authenticated) {
|
||||
execl(_PATH_LOGIN, "login", "-p",
|
||||
"-h", hostname, "-f", lusername, (char *)NULL);
|
||||
} else
|
||||
execl(_PATH_LOGIN, "login", "-p",
|
||||
"-h", hostname, lusername, (char *)NULL);
|
||||
fatal(STDERR_FILENO, _PATH_LOGIN, 1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
ioctl(f, FIONBIO, &on);
|
||||
ioctl(master, FIONBIO, &on);
|
||||
ioctl(master, TIOCPKT, &on);
|
||||
signal(SIGCHLD, cleanup);
|
||||
protocol(f, master);
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
cleanup(0);
|
||||
}
|
||||
|
||||
char magic[2] = { 0377, 0377 };
|
||||
char oobdata[] = {TIOCPKT_WINDOW};
|
||||
|
||||
/*
|
||||
* Handle a "control" request (signaled by magic being present)
|
||||
* in the data stream. For now, we are only willing to handle
|
||||
* window size changes.
|
||||
*/
|
||||
int
|
||||
control(int pty, char *cp, int n)
|
||||
{
|
||||
struct winsize w;
|
||||
|
||||
if (n < 4 + (int)sizeof(w) || cp[2] != 's' || cp[3] != 's')
|
||||
return (0);
|
||||
oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
|
||||
bcopy(cp+4, (char *)&w, sizeof(w));
|
||||
w.ws_row = ntohs(w.ws_row);
|
||||
w.ws_col = ntohs(w.ws_col);
|
||||
w.ws_xpixel = ntohs(w.ws_xpixel);
|
||||
w.ws_ypixel = ntohs(w.ws_ypixel);
|
||||
(void)ioctl(pty, TIOCSWINSZ, &w);
|
||||
return (4+sizeof (w));
|
||||
}
|
||||
|
||||
/*
|
||||
* rlogin "protocol" machine.
|
||||
*/
|
||||
void
|
||||
protocol(int f, int p)
|
||||
{
|
||||
char pibuf[1024+1], fibuf[1024], *pbp = NULL, *fbp = NULL;
|
||||
int pcc = 0, fcc = 0;
|
||||
int cc, nfd, n;
|
||||
char cntl;
|
||||
|
||||
/*
|
||||
* Must ignore SIGTTOU, otherwise we'll stop
|
||||
* when we try and set slave pty's window shape
|
||||
* (our controlling tty is the master pty).
|
||||
*/
|
||||
(void) signal(SIGTTOU, SIG_IGN);
|
||||
send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
|
||||
if (f > p)
|
||||
nfd = f + 1;
|
||||
else
|
||||
nfd = p + 1;
|
||||
for (;;) {
|
||||
struct pollfd set[2];
|
||||
|
||||
set[0].fd = p;
|
||||
set[0].events = POLLPRI;
|
||||
set[1].fd = f;
|
||||
set[1].events = 0;
|
||||
if (fcc)
|
||||
set[0].events |= POLLOUT;
|
||||
else
|
||||
set[1].events |= POLLIN;
|
||||
if (pcc >= 0) {
|
||||
if (pcc)
|
||||
set[1].events |= POLLOUT;
|
||||
else
|
||||
set[0].events |= POLLIN;
|
||||
}
|
||||
if ((n = poll(set, 2, INFTIM)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fatal(f, "poll", 1);
|
||||
}
|
||||
if (n == 0) {
|
||||
/* shouldn't happen... */
|
||||
sleep(5);
|
||||
continue;
|
||||
}
|
||||
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
|
||||
if (set[0].revents & POLLPRI) {
|
||||
cc = read(p, &cntl, 1);
|
||||
if (cc == 1 && pkcontrol(cntl)) {
|
||||
cntl |= oobdata[0];
|
||||
send(f, &cntl, 1, MSG_OOB);
|
||||
if (cntl & TIOCPKT_FLUSHWRITE)
|
||||
pcc = 0;
|
||||
}
|
||||
}
|
||||
if (set[1].revents & POLLIN) {
|
||||
fcc = read(f, fibuf, sizeof(fibuf));
|
||||
if (fcc < 0 && errno == EWOULDBLOCK)
|
||||
fcc = 0;
|
||||
else {
|
||||
char *cp;
|
||||
int left, n;
|
||||
|
||||
if (fcc <= 0)
|
||||
break;
|
||||
fbp = fibuf;
|
||||
|
||||
top:
|
||||
for (cp = fibuf; cp < fibuf+fcc-1; cp++)
|
||||
if (cp[0] == magic[0] &&
|
||||
cp[1] == magic[1]) {
|
||||
left = fcc - (cp-fibuf);
|
||||
n = control(p, cp, left);
|
||||
if (n) {
|
||||
left -= n;
|
||||
if (left > 0)
|
||||
bcopy(cp+n, cp, left);
|
||||
fcc -= n;
|
||||
goto top; /* n^2 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (set[0].revents & POLLOUT && fcc > 0) {
|
||||
cc = write(p, fbp, fcc);
|
||||
if (cc > 0) {
|
||||
fcc -= cc;
|
||||
fbp += cc;
|
||||
}
|
||||
}
|
||||
|
||||
if (set[0].revents & POLLIN) {
|
||||
pcc = read(p, pibuf, sizeof (pibuf));
|
||||
pbp = pibuf;
|
||||
if (pcc < 0 && errno == EWOULDBLOCK)
|
||||
pcc = 0;
|
||||
else if (pcc <= 0)
|
||||
break;
|
||||
else if (pibuf[0] == 0) {
|
||||
pbp++, pcc--;
|
||||
} else {
|
||||
if (pkcontrol(pibuf[0])) {
|
||||
pibuf[0] |= oobdata[0];
|
||||
send(f, &pibuf[0], 1, MSG_OOB);
|
||||
}
|
||||
pcc = 0;
|
||||
}
|
||||
}
|
||||
if (set[1].revents & POLLOUT && pcc > 0) {
|
||||
cc = write(f, pbp, pcc);
|
||||
if (cc > 0) {
|
||||
pcc -= cc;
|
||||
pbp += cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cleanup(int signo __unused)
|
||||
{
|
||||
|
||||
shutdown(netf, SHUT_RDWR);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
fatal(int f, char *msg, int syserr)
|
||||
{
|
||||
int len;
|
||||
char buf[BUFSIZ], *bp = buf;
|
||||
|
||||
/*
|
||||
* Prepend binary one to message if we haven't sent
|
||||
* the magic null as confirmation.
|
||||
*/
|
||||
if (!confirmed)
|
||||
*bp++ = '\01'; /* error indicator */
|
||||
if (syserr)
|
||||
len = snprintf(bp, sizeof(buf), "rlogind: %s: %s.\r\n",
|
||||
msg, strerror(errno));
|
||||
else
|
||||
len = snprintf(bp, sizeof(buf), "rlogind: %s.\r\n", msg);
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
(void) write(f, buf, bp + len - buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
do_rlogin(union sockunion *dest)
|
||||
{
|
||||
|
||||
getstr(rusername, sizeof(rusername), "remuser too long");
|
||||
getstr(lusername, sizeof(lusername), "locuser too long");
|
||||
getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
|
||||
|
||||
pwd = getpwnam(lusername);
|
||||
if (pwd == NULL)
|
||||
return (-1);
|
||||
/* XXX why don't we syslog() failure? */
|
||||
|
||||
return (iruserok_sa(dest, dest->su_len, pwd->pw_uid == 0, rusername,
|
||||
lusername));
|
||||
}
|
||||
|
||||
void
|
||||
getstr(char *buf, int cnt, char *errmsg)
|
||||
{
|
||||
char c;
|
||||
|
||||
do {
|
||||
if (read(STDIN_FILENO, &c, 1) != 1)
|
||||
exit(1);
|
||||
if (--cnt < 0) {
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "buffer overflow");
|
||||
#endif
|
||||
fatal(STDOUT_FILENO, errmsg, 0);
|
||||
}
|
||||
*buf++ = c;
|
||||
} while (c != 0);
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
|
||||
void
|
||||
setup_term(int fd)
|
||||
{
|
||||
char *cp;
|
||||
char *speed;
|
||||
struct termios tt, def;
|
||||
|
||||
cp = strchr(term + ENVSIZE, '/');
|
||||
#ifndef notyet
|
||||
tcgetattr(fd, &tt);
|
||||
if (cp) {
|
||||
*cp++ = '\0';
|
||||
speed = cp;
|
||||
cp = strchr(speed, '/');
|
||||
if (cp)
|
||||
*cp++ = '\0';
|
||||
cfsetspeed(&tt, atoi(speed));
|
||||
}
|
||||
|
||||
cfmakesane(&def);
|
||||
tt.c_iflag = def.c_iflag;
|
||||
tt.c_oflag = def.c_oflag;
|
||||
tt.c_lflag = def.c_lflag;
|
||||
tcsetattr(fd, TCSAFLUSH, &tt);
|
||||
#else
|
||||
if (cp) {
|
||||
*cp++ = '\0';
|
||||
speed = cp;
|
||||
cp = strchr(speed, '/');
|
||||
if (cp)
|
||||
*cp++ = '\0';
|
||||
tcgetattr(fd, &tt);
|
||||
cfsetspeed(&tt, atoi(speed));
|
||||
tcsetattr(fd, TCSAFLUSH, &tt);
|
||||
}
|
||||
#endif
|
||||
|
||||
env[0] = term;
|
||||
env[1] = 0;
|
||||
environ = env;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]");
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
# From: @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
# $FreeBSD$
|
||||
|
||||
PACKAGE=rcmds
|
||||
|
||||
.include <src.opts.mk>
|
||||
|
||||
PROG= rshd
|
||||
MAN= rshd.8
|
||||
|
||||
PACKAGE=rcmds
|
||||
|
||||
WARNS?= 3
|
||||
WFORMAT=0
|
||||
|
||||
LIBADD= util pam
|
||||
|
||||
.if ${MK_BLACKLIST_SUPPORT} != "no"
|
||||
CFLAGS+= -DUSE_BLACKLIST -I${SRCTOP}/contrib/blacklist/include
|
||||
LIBADD+= blacklist
|
||||
LDFLAGS+=-L${LIBBLACKLISTDIR}
|
||||
.endif
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,23 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
gnu/lib/libgcc \
|
||||
include \
|
||||
include/arpa \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libblacklist \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
lib/libpam/libpam \
|
||||
lib/libthr \
|
||||
lib/libutil \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,277 +0,0 @@
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)rshd.8 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 3, 2017
|
||||
.Dt RSHD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rshd
|
||||
.Nd remote shell server
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl aDLln
|
||||
.Sh DEPRECATION NOTICE
|
||||
.Nm
|
||||
is deprecated and will be removed from future versions of the
|
||||
.Fx
|
||||
base system.
|
||||
If
|
||||
.Nm
|
||||
is still required, it can be installed from ports or packages
|
||||
(net/bsdrcmds).
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility
|
||||
is the server for the
|
||||
.Xr rcmd 3
|
||||
routine and, consequently, for the
|
||||
.Xr rsh 1
|
||||
utility.
|
||||
The server provides remote execution facilities
|
||||
with authentication based on privileged port numbers from trusted hosts.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility 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
|
||||
.Tn NUL
|
||||
(`\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 gethostbyaddr 3 ,
|
||||
.Xr hosts 5
|
||||
and
|
||||
.Xr named 8 ) .
|
||||
If the hostname cannot be determined or the hostname and address do
|
||||
not match after verification,
|
||||
the dot-notation representation of the host address is used.
|
||||
.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
|
||||
.Em 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
|
||||
The
|
||||
.Nm
|
||||
utility 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
|
||||
.Pa .rhosts
|
||||
file,
|
||||
unless the user is the superuser.
|
||||
.It
|
||||
A
|
||||
.Tn NUL
|
||||
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
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a
|
||||
This flag is ignored, and is present for compatibility purposes.
|
||||
.It Fl D
|
||||
Sets the TCP_NODELAY socket option, which improves the performance
|
||||
of small back-to-back writes at the expense of additional network
|
||||
traffic.
|
||||
.It Fl L
|
||||
Causes all successful accesses to be logged to
|
||||
.Xr syslogd 8
|
||||
as
|
||||
.Li auth.info
|
||||
messages.
|
||||
.It Fl l
|
||||
Do not use the user's
|
||||
.Pa .rhosts
|
||||
file for authentication, unless the user is the superuser.
|
||||
.It Fl n
|
||||
Turn off transport level keepalive messages.
|
||||
This will prevent sessions
|
||||
from timing out if the client crashes or becomes unreachable.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/run/nologin -compact
|
||||
.It Pa /etc/hosts
|
||||
.It Pa /etc/hosts.equiv
|
||||
.It Pa /etc/login.conf
|
||||
.It Ev $HOME Ns Pa /.rhosts
|
||||
.Pp
|
||||
.It Pa /etc/pam.conf
|
||||
.Nm
|
||||
uses
|
||||
.Pa /etc/pam.conf
|
||||
entries with service name
|
||||
.Dq rsh .
|
||||
Authentication modules requiring passwords (such as
|
||||
.Nm pam_unix )
|
||||
are not supported.
|
||||
.El
|
||||
.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
|
||||
or the authentication procedure described above failed.
|
||||
.It Sy Remote directory.
|
||||
The
|
||||
.Xr chdir 2
|
||||
function to the home directory failed.
|
||||
.It Sy Logins not available right now.
|
||||
The
|
||||
.Xr rsh 1
|
||||
utility was attempted outside the allowed hours defined in
|
||||
.Pa /etc/login.conf
|
||||
for the local user's login class.
|
||||
.It Sy Can't make pipe.
|
||||
The pipe needed for the
|
||||
.Em stderr ,
|
||||
was not created.
|
||||
.It Sy Can't fork; try again.
|
||||
A
|
||||
.Xr fork 2
|
||||
by the server failed.
|
||||
.It Sy <shellname>: ...
|
||||
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 rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr gethostbyaddr 3 ,
|
||||
.Xr rcmd 3 ,
|
||||
.Xr ruserok 3 ,
|
||||
.Xr hosts 5 ,
|
||||
.Xr hosts.equiv 5 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr services 5 ,
|
||||
.Xr named 8 ,
|
||||
.Xr rlogind 8 ,
|
||||
.Xr syslogd 8
|
||||
.Sh HISTORY
|
||||
IPv6 support was added by WIDE/KAME project.
|
||||
.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
|
||||
.Dq open
|
||||
environment.
|
||||
.Pp
|
||||
A facility to allow all data exchanges to be encrypted should be
|
||||
present.
|
||||
.Pp
|
||||
Post-PAM,
|
||||
.Fx
|
||||
also needs the following patch applied besides properly configuring
|
||||
.Pa .rhosts :
|
||||
.Bd -literal -offset indent
|
||||
--- etc/pam.d/rsh.orig Wed Dec 17 14:36:20 2003
|
||||
+++ etc/pam.d/rsh Wed Dec 17 14:30:43 2003
|
||||
@@ -9 +9 @@
|
||||
-auth required pam_rhosts.so no_warn
|
||||
+auth required pam_rhosts.so no_warn allow_root
|
||||
.Ed
|
||||
.Pp
|
||||
A more extensible protocol (such as Telnet) should be used.
|
@ -1,617 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1988, 1989, 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Networks Associates Technology, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static const char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* remote shell server:
|
||||
* [port]\0
|
||||
* ruser\0
|
||||
* luser\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 <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libutil.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <login_cap.h>
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/openpam.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef USE_BLACKLIST
|
||||
#include <blacklist.h>
|
||||
#endif
|
||||
|
||||
static struct pam_conv pamc = { openpam_nullconv, NULL };
|
||||
static pam_handle_t *pamh;
|
||||
static int pam_err;
|
||||
|
||||
#define PAM_END { \
|
||||
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)); \
|
||||
}
|
||||
|
||||
int keepalive = 1;
|
||||
int log_success; /* If TRUE, log all successful accesses */
|
||||
int sent_null;
|
||||
int no_delay;
|
||||
|
||||
void doit(struct sockaddr *);
|
||||
static void rshd_errx(int, const char *, ...) __printf0like(2, 3);
|
||||
void getstr(char *, int, const char *);
|
||||
int local_domain(char *);
|
||||
char *topdomain(char *);
|
||||
void usage(void);
|
||||
|
||||
char slash[] = "/";
|
||||
char bshell[] = _PATH_BSHELL;
|
||||
|
||||
#define OPTIONS "aDLln"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
extern int __check_rhosts_file;
|
||||
struct linger linger;
|
||||
socklen_t fromlen;
|
||||
int ch, on = 1;
|
||||
struct sockaddr_storage from;
|
||||
|
||||
openlog("rshd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
opterr = 0;
|
||||
while ((ch = getopt(argc, argv, OPTIONS)) != -1)
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
/* ignored for compatibility */
|
||||
break;
|
||||
case 'l':
|
||||
__check_rhosts_file = 0;
|
||||
break;
|
||||
case 'n':
|
||||
keepalive = 0;
|
||||
break;
|
||||
case 'D':
|
||||
no_delay = 1;
|
||||
break;
|
||||
case 'L':
|
||||
log_success = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
fromlen = sizeof (from);
|
||||
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
|
||||
syslog(LOG_ERR, "getpeername: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (keepalive &&
|
||||
setsockopt(0, 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(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
|
||||
sizeof (linger)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
|
||||
if (no_delay &&
|
||||
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
|
||||
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
|
||||
doit((struct sockaddr *)&from);
|
||||
/* NOTREACHED */
|
||||
return(0);
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
|
||||
void
|
||||
doit(struct sockaddr *fromp)
|
||||
{
|
||||
extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
|
||||
struct passwd *pwd;
|
||||
u_short port;
|
||||
fd_set ready, readfrom;
|
||||
int cc, nfd, pv[2], pid, s;
|
||||
int one = 1;
|
||||
const char *cp, *errorstr;
|
||||
char sig, buf[BUFSIZ];
|
||||
char *cmdbuf, luser[16], ruser[16];
|
||||
char rhost[2 * MAXHOSTNAMELEN + 1];
|
||||
char numericname[INET6_ADDRSTRLEN];
|
||||
int af, srcport;
|
||||
int maxcmdlen;
|
||||
login_cap_t *lc;
|
||||
|
||||
maxcmdlen = (int)sysconf(_SC_ARG_MAX);
|
||||
if (maxcmdlen <= 0 || (cmdbuf = malloc(maxcmdlen)) == NULL)
|
||||
exit(1);
|
||||
|
||||
(void) signal(SIGINT, SIG_DFL);
|
||||
(void) signal(SIGQUIT, SIG_DFL);
|
||||
(void) signal(SIGTERM, SIG_DFL);
|
||||
af = fromp->sa_family;
|
||||
srcport = ntohs(*((in_port_t *)&fromp->sa_data));
|
||||
if (af == AF_INET) {
|
||||
inet_ntop(af, &((struct sockaddr_in *)fromp)->sin_addr,
|
||||
numericname, sizeof numericname);
|
||||
} else if (af == AF_INET6) {
|
||||
inet_ntop(af, &((struct sockaddr_in6 *)fromp)->sin6_addr,
|
||||
numericname, sizeof numericname);
|
||||
} else {
|
||||
syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
|
||||
exit(1);
|
||||
}
|
||||
#ifdef IP_OPTIONS
|
||||
if (af == AF_INET) {
|
||||
u_char optbuf[BUFSIZ/3];
|
||||
socklen_t optsize = sizeof(optbuf), ipproto, i;
|
||||
struct protoent *ip;
|
||||
|
||||
if ((ip = getprotobyname("ip")) != NULL)
|
||||
ipproto = ip->p_proto;
|
||||
else
|
||||
ipproto = IPPROTO_IP;
|
||||
if (!getsockopt(0, ipproto, IP_OPTIONS, 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",
|
||||
numericname,
|
||||
c == IPOPT_LSRR ? "LSRR" : "SSRR");
|
||||
exit(1);
|
||||
}
|
||||
if (c == IPOPT_EOL)
|
||||
break;
|
||||
i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (srcport >= IPPORT_RESERVED ||
|
||||
srcport < IPPORT_RESERVED/2) {
|
||||
syslog(LOG_NOTICE|LOG_AUTH,
|
||||
"connection from %s on illegal port %u",
|
||||
numericname,
|
||||
srcport);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "illegal port");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
||||
(void) alarm(60);
|
||||
port = 0;
|
||||
s = 0; /* not set or used if port == 0 */
|
||||
for (;;) {
|
||||
char c;
|
||||
if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
|
||||
if (cc < 0)
|
||||
syslog(LOG_NOTICE, "read: %m");
|
||||
shutdown(0, SHUT_RDWR);
|
||||
exit(1);
|
||||
}
|
||||
if (c == 0)
|
||||
break;
|
||||
port = port * 10 + c - '0';
|
||||
}
|
||||
|
||||
(void) alarm(0);
|
||||
if (port != 0) {
|
||||
int lport = IPPORT_RESERVED - 1;
|
||||
s = rresvport_af(&lport, af);
|
||||
if (s < 0) {
|
||||
syslog(LOG_ERR, "can't get stderr port: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (port >= IPPORT_RESERVED ||
|
||||
port < IPPORT_RESERVED/2) {
|
||||
syslog(LOG_NOTICE|LOG_AUTH,
|
||||
"2nd socket from %s on unreserved port %u",
|
||||
numericname,
|
||||
port);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "unreserved port");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
*((in_port_t *)&fromp->sa_data) = htons(port);
|
||||
if (connect(s, fromp, fromp->sa_len) < 0) {
|
||||
syslog(LOG_INFO, "connect second port %d: %m", port);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
errorstr = NULL;
|
||||
realhostname_sa(rhost, sizeof(rhost) - 1, fromp, fromp->sa_len);
|
||||
rhost[sizeof(rhost) - 1] = '\0';
|
||||
/* XXX truncation! */
|
||||
|
||||
(void) alarm(60);
|
||||
getstr(ruser, sizeof(ruser), "ruser");
|
||||
getstr(luser, sizeof(luser), "luser");
|
||||
getstr(cmdbuf, maxcmdlen, "command");
|
||||
(void) alarm(0);
|
||||
|
||||
pam_err = pam_start("rsh", luser, &pamc, &pamh);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "login incorrect");
|
||||
#endif
|
||||
rshd_errx(1, "Login incorrect.");
|
||||
}
|
||||
|
||||
if ((pam_err = pam_set_item(pamh, PAM_RUSER, ruser)) != PAM_SUCCESS ||
|
||||
(pam_err = pam_set_item(pamh, PAM_RHOST, rhost)) != PAM_SUCCESS) {
|
||||
syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
|
||||
pam_strerror(pamh, pam_err));
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "login incorrect");
|
||||
#endif
|
||||
rshd_errx(1, "Login incorrect.");
|
||||
}
|
||||
|
||||
pam_err = pam_authenticate(pamh, 0);
|
||||
if (pam_err == PAM_SUCCESS) {
|
||||
if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
|
||||
strlcpy(luser, cp, sizeof(luser));
|
||||
/* XXX truncation! */
|
||||
}
|
||||
pam_err = pam_acct_mgmt(pamh, 0);
|
||||
}
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
|
||||
ruser, rhost, luser, pam_strerror(pamh, pam_err), cmdbuf);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "permission denied");
|
||||
#endif
|
||||
rshd_errx(1, "Login incorrect.");
|
||||
}
|
||||
|
||||
setpwent();
|
||||
pwd = getpwnam(luser);
|
||||
if (pwd == NULL) {
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: unknown login. cmd='%.80s'",
|
||||
ruser, rhost, luser, cmdbuf);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "unknown login");
|
||||
#endif
|
||||
if (errorstr == NULL)
|
||||
errorstr = "Login incorrect.";
|
||||
rshd_errx(1, errorstr, rhost);
|
||||
}
|
||||
|
||||
lc = login_getpwclass(pwd);
|
||||
if (pwd->pw_uid)
|
||||
auth_checknologin(lc);
|
||||
|
||||
if (chdir(pwd->pw_dir) < 0) {
|
||||
if (chdir("/") < 0 ||
|
||||
login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) {
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: no home directory. cmd='%.80s'",
|
||||
ruser, rhost, luser, cmdbuf);
|
||||
rshd_errx(0, "No remote home directory.");
|
||||
}
|
||||
pwd->pw_dir = slash;
|
||||
}
|
||||
|
||||
if (lc != NULL && fromp->sa_family == AF_INET) { /*XXX*/
|
||||
char remote_ip[MAXHOSTNAMELEN];
|
||||
|
||||
strlcpy(remote_ip, numericname, sizeof(remote_ip));
|
||||
/* XXX truncation! */
|
||||
if (!auth_hostok(lc, rhost, remote_ip)) {
|
||||
syslog(LOG_INFO|LOG_AUTH,
|
||||
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
|
||||
ruser, rhost, luser, __rcmd_errstr,
|
||||
cmdbuf);
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "permission denied");
|
||||
#endif
|
||||
rshd_errx(1, "Login incorrect.");
|
||||
}
|
||||
if (!auth_timeok(lc, time(NULL)))
|
||||
rshd_errx(1, "Logins not available right now");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(1);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
(void) write(STDERR_FILENO, "\0", 1);
|
||||
sent_null = 1;
|
||||
|
||||
if (port) {
|
||||
if (pipe(pv) < 0)
|
||||
rshd_errx(1, "Can't make pipe.");
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
rshd_errx(1, "Can't fork; try again.");
|
||||
if (pid) {
|
||||
(void) close(0);
|
||||
(void) close(1);
|
||||
(void) close(2);
|
||||
(void) close(pv[1]);
|
||||
|
||||
FD_ZERO(&readfrom);
|
||||
FD_SET(s, &readfrom);
|
||||
FD_SET(pv[0], &readfrom);
|
||||
if (pv[0] > s)
|
||||
nfd = pv[0];
|
||||
else
|
||||
nfd = s;
|
||||
ioctl(pv[0], FIONBIO, (char *)&one);
|
||||
|
||||
/* should set s nbio! */
|
||||
nfd++;
|
||||
do {
|
||||
ready = readfrom;
|
||||
if (select(nfd, &ready, (fd_set *)0,
|
||||
(fd_set *)0, (struct timeval *)0) < 0)
|
||||
break;
|
||||
if (FD_ISSET(s, &ready)) {
|
||||
int ret;
|
||||
ret = read(s, &sig, 1);
|
||||
if (ret <= 0)
|
||||
FD_CLR(s, &readfrom);
|
||||
else
|
||||
killpg(pid, sig);
|
||||
}
|
||||
if (FD_ISSET(pv[0], &ready)) {
|
||||
errno = 0;
|
||||
cc = read(pv[0], buf, sizeof(buf));
|
||||
if (cc <= 0) {
|
||||
shutdown(s, SHUT_RDWR);
|
||||
FD_CLR(pv[0], &readfrom);
|
||||
} else {
|
||||
(void)write(s, buf, cc);
|
||||
}
|
||||
}
|
||||
|
||||
} while (FD_ISSET(s, &readfrom) ||
|
||||
FD_ISSET(pv[0], &readfrom));
|
||||
PAM_END;
|
||||
exit(0);
|
||||
}
|
||||
(void) close(s);
|
||||
(void) close(pv[0]);
|
||||
dup2(pv[1], 2);
|
||||
close(pv[1]);
|
||||
}
|
||||
else {
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
rshd_errx(1, "Can't fork; try again.");
|
||||
if (pid) {
|
||||
/* Parent. */
|
||||
while (wait(NULL) > 0 || errno == EINTR)
|
||||
/* nothing */ ;
|
||||
PAM_END;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(0, STDIN_FILENO, "success");
|
||||
#endif
|
||||
closefrom(3);
|
||||
if (setsid() == -1)
|
||||
syslog(LOG_ERR, "setsid() failed: %m");
|
||||
if (setlogin(pwd->pw_name) < 0)
|
||||
syslog(LOG_ERR, "setlogin() failed: %m");
|
||||
|
||||
if (*pwd->pw_shell == '\0')
|
||||
pwd->pw_shell = 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);
|
||||
cp = strrchr(pwd->pw_shell, '/');
|
||||
if (cp)
|
||||
cp++;
|
||||
else
|
||||
cp = pwd->pw_shell;
|
||||
|
||||
if (setusercontext(lc, pwd, pwd->pw_uid,
|
||||
LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
|
||||
syslog(LOG_ERR, "setusercontext(): %m");
|
||||
exit(1);
|
||||
}
|
||||
login_close(lc);
|
||||
endpwent();
|
||||
if (log_success || pwd->pw_uid == 0) {
|
||||
syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
|
||||
ruser, rhost, luser, cmdbuf);
|
||||
}
|
||||
execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL);
|
||||
err(1, "%s", pwd->pw_shell);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void
|
||||
rshd_errx(int errcode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (sent_null == 0)
|
||||
write(STDERR_FILENO, "\1", 1);
|
||||
|
||||
verrx(errcode, fmt, ap);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void
|
||||
getstr(char *buf, int cnt, const char *error)
|
||||
{
|
||||
char c;
|
||||
|
||||
do {
|
||||
if (read(STDIN_FILENO, &c, 1) != 1)
|
||||
exit(1);
|
||||
*buf++ = c;
|
||||
if (--cnt == 0) {
|
||||
#ifdef USE_BLACKLIST
|
||||
blacklist(1, STDIN_FILENO, "buffer overflow");
|
||||
#endif
|
||||
rshd_errx(1, "%s too long", error);
|
||||
}
|
||||
} 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.
|
||||
*/
|
||||
int
|
||||
local_domain(char *h)
|
||||
{
|
||||
char localhost[MAXHOSTNAMELEN];
|
||||
char *p1, *p2;
|
||||
|
||||
localhost[0] = 0;
|
||||
(void) gethostname(localhost, sizeof(localhost) - 1);
|
||||
localhost[sizeof(localhost) - 1] = '\0';
|
||||
/* XXX truncation! */
|
||||
p1 = topdomain(localhost);
|
||||
p2 = topdomain(h);
|
||||
if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
|
||||
exit(2);
|
||||
}
|
@ -67,10 +67,6 @@ CRUNCH_ALIAS_rm= unlink
|
||||
CRUNCH_ALIAS_ed= red
|
||||
CRUNCH_ALIAS_pkill= pgrep
|
||||
|
||||
.if ${MK_RCMDS} != "no"
|
||||
CRUNCH_PROGS_bin+= rcp
|
||||
.endif
|
||||
|
||||
.if ${MK_TCSH} != "no"
|
||||
CRUNCH_PROGS_bin+= csh
|
||||
CRUNCH_ALIAS_csh= -csh tcsh -tcsh
|
||||
|
@ -1294,14 +1294,6 @@ by proxy.
|
||||
.It Va WITHOUT_RBOOTD
|
||||
Set to not build or install
|
||||
.Xr rbootd 8 .
|
||||
.It Va WITH_RCMDS
|
||||
Enable building of the
|
||||
.Bx
|
||||
r-commands.
|
||||
This includes
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
etc.
|
||||
.It Va WITH_REPRODUCIBLE_BUILD
|
||||
Set to exclude build metadata (such as the build time, user, or host)
|
||||
from the kernel, boot loaders, and uname output, so that builds produce
|
||||
|
@ -184,7 +184,6 @@ __DEFAULT_NO_OPTIONS = \
|
||||
NAND \
|
||||
OFED \
|
||||
OPENLDAP \
|
||||
RCMDS \
|
||||
REPRODUCIBLE_BUILD \
|
||||
RPCBIND_WARMSTART_SUPPORT \
|
||||
SHARED_TOOLCHAIN \
|
||||
|
@ -7107,20 +7107,6 @@ OLD_FILES+=usr/libexec/rbootd
|
||||
OLD_FILES+=usr/share/man/man8/rbootd.8.gz
|
||||
.endif
|
||||
|
||||
.if ${MK_RCMDS} == no
|
||||
OLD_FILES+=bin/rcp
|
||||
OLD_FILES+=rescue/rcp
|
||||
OLD_FILES+=usr/bin/rlogin
|
||||
OLD_FILES+=usr/bin/rsh
|
||||
OLD_FILES+=usr/libexec/rlogind
|
||||
OLD_FILES+=usr/libexec/rshd
|
||||
OLD_FILES+=usr/share/man/man1/rcp.1.gz
|
||||
OLD_FILES+=usr/share/man/man1/rlogin.1.gz
|
||||
OLD_FILES+=usr/share/man/man1/rsh.1.gz
|
||||
OLD_FILES+=usr/share/man/man8/rlogind.8.gz
|
||||
OLD_FILES+=usr/share/man/man8/rshd.8.gz
|
||||
.endif
|
||||
|
||||
.if ${MK_RESCUE} == no
|
||||
. if exists(${DESTDIR}${TESTSBASE})
|
||||
RESCUE_DIRS!=find ${DESTDIR}/rescue -type d 2>/dev/null | sed -e 's,^${DESTDIR}/,,'; echo
|
||||
|
@ -1,8 +0,0 @@
|
||||
.\" $FreeBSD$
|
||||
Disable building of the
|
||||
.Bx
|
||||
r-commands.
|
||||
This includes
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
etc.
|
@ -1,8 +0,0 @@
|
||||
.\" $FreeBSD$
|
||||
Enable building of the
|
||||
.Bx
|
||||
r-commands.
|
||||
This includes
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
etc.
|
@ -129,7 +129,6 @@ WITHOUT_NLS=true
|
||||
WITHOUT_NS_CACHING=true
|
||||
WITHOUT_OBJC=true
|
||||
WITHOUT_PROFILE=true
|
||||
WITHOUT_RCMDS=true
|
||||
WITHOUT_SENDMAIL=true
|
||||
WITHOUT_SHAREDOCS=true
|
||||
WITHOUT_SYSCONS=true
|
||||
|
@ -160,7 +160,6 @@ WITHOUT_NLS=true
|
||||
WITHOUT_NS_CACHING=true
|
||||
WITHOUT_OBJC=true
|
||||
WITHOUT_PROFILE=true
|
||||
WITHOUT_RCMDS=true
|
||||
WITHOUT_SENDMAIL=true
|
||||
WITHOUT_SHAREDOCS=true
|
||||
WITHOUT_SYSCONS=true
|
||||
|
@ -140,7 +140,6 @@ WITHOUT_PMC=true
|
||||
WITHOUT_PORTSNAP=true
|
||||
WITHOUT_PROFILE=true
|
||||
WITHOUT_QUOTAS=true
|
||||
WITHOUT_RCMDS=true
|
||||
WITHOUT_RCS=true
|
||||
WITHOUT_RESCUE=true
|
||||
WITHOUT_SENDMAIL=true
|
||||
|
@ -250,8 +250,6 @@ SUBDIR.${MK_OPENSSL}+= chkey
|
||||
SUBDIR.${MK_OPENSSL}+= dc
|
||||
SUBDIR.${MK_OPENSSL}+= newkey
|
||||
SUBDIR.${MK_QUOTAS}+= quota
|
||||
SUBDIR.${MK_RCMDS}+= rlogin
|
||||
SUBDIR.${MK_RCMDS}+= rsh
|
||||
SUBDIR.${MK_SENDMAIL}+= vacation
|
||||
SUBDIR.${MK_TALK}+= talk
|
||||
SUBDIR.${MK_TELNET}+= telnet
|
||||
|
@ -1,11 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 7/19/93
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= rlogin
|
||||
|
||||
PACKAGE=rcmds
|
||||
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,18 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
gnu/lib/libgcc \
|
||||
include \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,167 +0,0 @@
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" @(#)rlogin.1 8.1 (Berkeley) 6/6/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 3, 2017
|
||||
.Dt RLOGIN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rlogin
|
||||
.Nd remote login
|
||||
.Sh SYNOPSIS
|
||||
.Ar rlogin
|
||||
.Op Fl 468DEd
|
||||
.Op Fl e Ar char
|
||||
.Op Fl i Ar localname
|
||||
.Op Fl l Ar username
|
||||
.Ar host
|
||||
.Sh DEPRECATION NOTICE
|
||||
.Nm
|
||||
is deprecated and will be removed from future versions of the
|
||||
.Fx
|
||||
base system.
|
||||
If
|
||||
.Nm
|
||||
is still required, it can be installed from ports or packages
|
||||
(net/bsdrcmds).
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility starts a terminal session on a remote host
|
||||
.Ar host .
|
||||
.Pp
|
||||
The standard Berkeley
|
||||
.Pa rhosts
|
||||
authorization mechanism is used.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width flag
|
||||
.It Fl 4
|
||||
Use IPv4 addresses only.
|
||||
.It Fl 6
|
||||
Use IPv6 addresses only.
|
||||
.It Fl 8
|
||||
Allow an eight-bit input data path at all times; otherwise
|
||||
parity bits are stripped except when the remote side's stop and start
|
||||
characters are other than
|
||||
^S/^Q.
|
||||
.It Fl D
|
||||
Set the TCP_NODELAY socket option which can improve interactive response
|
||||
at the expense of increased network load.
|
||||
.It Fl E
|
||||
Stop any character from being recognized as an escape character.
|
||||
When used with the
|
||||
.Fl 8
|
||||
option, this provides a completely transparent connection.
|
||||
.It Fl d
|
||||
Turn on socket debugging (see
|
||||
.Xr setsockopt 2 )
|
||||
on the TCP sockets used for communication with the remote host.
|
||||
.It Fl e
|
||||
Allow user specification of the escape character, which is
|
||||
.Dq ~
|
||||
by default.
|
||||
This specification may be as a literal character, or as an octal
|
||||
value in the form \ennn.
|
||||
.It Fl i
|
||||
Allow the caller to specify a different local name to be used
|
||||
for authentication.
|
||||
This option is restricted to processes with uid 0.
|
||||
.It Fl l
|
||||
Specify a different
|
||||
.Ar username
|
||||
for the remote login.
|
||||
If this option is not specified, your local username will be used.
|
||||
.El
|
||||
.Pp
|
||||
A line of the form
|
||||
.Dq Ao escape char Ac Ns \&.
|
||||
disconnects from the remote host.
|
||||
Similarly, the line
|
||||
.Dq Ao escape char Ac Ns ^Z
|
||||
will suspend the
|
||||
.Nm
|
||||
session, and
|
||||
.Dq Ao escape\ char Ac Ns Ao delayed-suspend\ char Ac
|
||||
suspends the
|
||||
send portion of the
|
||||
.Nm
|
||||
session, but allows output from the remote system.
|
||||
By default, the tilde
|
||||
.Pq Dq ~
|
||||
character is the escape character, and
|
||||
normally control-Y
|
||||
.Pq Dq ^Y
|
||||
is the delayed-suspend character.
|
||||
.Pp
|
||||
All echoing takes place at the remote site, so that (except for delays)
|
||||
the
|
||||
.Nm
|
||||
is transparent.
|
||||
Flow control via ^S/^Q and flushing of input and output on interrupts
|
||||
are handled properly.
|
||||
.Sh ENVIRONMENT
|
||||
The following environment variable is utilized by
|
||||
.Nm :
|
||||
.Bl -tag -width TERM
|
||||
.It Ev TERM
|
||||
Determines the user's terminal type.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/hosts -compact
|
||||
.It Pa /etc/hosts
|
||||
.It Pa /etc/hosts.equiv
|
||||
.It Ev $HOME Ns Pa /.rhosts
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr login 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr telnet 1 ,
|
||||
.Xr setsockopt 2 ,
|
||||
.Xr ruserok 3 ,
|
||||
.Xr tty 4 ,
|
||||
.Xr hosts 5 ,
|
||||
.Xr hosts.equiv 5 ,
|
||||
.Xr rlogind 8 ,
|
||||
.Xr rshd 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command appeared in
|
||||
.Bx 4.2 .
|
||||
.Pp
|
||||
IPv6 support was added by WIDE/KAME project.
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
utility will be replaced by
|
||||
.Xr telnet 1
|
||||
in the near future.
|
||||
.Pp
|
||||
More of the environment should be propagated.
|
@ -1,722 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1983, 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Networks Associates Technology, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
*
|
||||
* 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
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1990, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* rlogin - remote login
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <setjmp.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef TIOCPKT_WINDOW
|
||||
#define TIOCPKT_WINDOW 0x80
|
||||
#endif
|
||||
|
||||
/* concession to Sun */
|
||||
#ifndef SIGUSR1
|
||||
#define SIGUSR1 30
|
||||
#endif
|
||||
|
||||
static int eight, rem;
|
||||
static struct termios deftty;
|
||||
|
||||
static int family = PF_UNSPEC;
|
||||
|
||||
static int noescape;
|
||||
static u_char escapechar = '~';
|
||||
|
||||
#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
|
||||
static struct winsize winsize;
|
||||
|
||||
static void catch_child(int);
|
||||
static void copytochild(int);
|
||||
static _Noreturn void doit(long);
|
||||
static _Noreturn void done(int);
|
||||
static void echo(char);
|
||||
static u_int getescape(const char *);
|
||||
static void lostpeer(int);
|
||||
static void mode(int);
|
||||
static void msg(const char *);
|
||||
static void oob(int);
|
||||
static int reader(int);
|
||||
static void sendwindow(void);
|
||||
static void setsignal(int);
|
||||
static void sigwinch(int);
|
||||
static void stop(char);
|
||||
static _Noreturn void usage(void);
|
||||
static void writer(void);
|
||||
static void writeroob(int);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct passwd *pw;
|
||||
struct servent *sp;
|
||||
struct termios tty;
|
||||
long omask;
|
||||
int argoff, ch, dflag, Dflag, one;
|
||||
uid_t uid;
|
||||
char *host, *localname, *p, *user, term[1024] = "network";
|
||||
speed_t ospeed;
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t sslen;
|
||||
size_t len, len2;
|
||||
int i;
|
||||
|
||||
argoff = dflag = Dflag = 0;
|
||||
one = 1;
|
||||
host = localname = user = NULL;
|
||||
|
||||
if ((p = strrchr(argv[0], '/')))
|
||||
++p;
|
||||
else
|
||||
p = argv[0];
|
||||
|
||||
if (strcmp(p, "rlogin"))
|
||||
host = p;
|
||||
|
||||
/* handle "rlogin host flags" */
|
||||
if (!host && argc > 2 && argv[1][0] != '-') {
|
||||
host = argv[1];
|
||||
argoff = 1;
|
||||
}
|
||||
|
||||
#define OPTIONS "468DEde:i:l:"
|
||||
while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
|
||||
switch(ch) {
|
||||
case '4':
|
||||
family = PF_INET;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
family = PF_INET6;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
eight = 1;
|
||||
break;
|
||||
case 'D':
|
||||
Dflag = 1;
|
||||
break;
|
||||
case 'E':
|
||||
noescape = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'e':
|
||||
noescape = 0;
|
||||
escapechar = getescape(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
if (getuid() != 0)
|
||||
errx(1, "-i user: permission denied");
|
||||
localname = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
user = optarg;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
optind += argoff;
|
||||
|
||||
/* if haven't gotten a host yet, do so */
|
||||
if (!host && !(host = argv[optind++]))
|
||||
usage();
|
||||
|
||||
if (argv[optind])
|
||||
usage();
|
||||
|
||||
if (!(pw = getpwuid(uid = getuid())))
|
||||
errx(1, "unknown user id");
|
||||
if (!user)
|
||||
user = pw->pw_name;
|
||||
if (!localname)
|
||||
localname = pw->pw_name;
|
||||
|
||||
sp = NULL;
|
||||
sp = getservbyname("login", "tcp");
|
||||
if (sp == NULL)
|
||||
errx(1, "login/tcp: unknown service");
|
||||
|
||||
if ((p = getenv("TERM")) != NULL)
|
||||
(void)strlcpy(term, p, sizeof(term));
|
||||
len = strlen(term);
|
||||
if (len < (sizeof(term) - 1) && tcgetattr(0, &tty) == 0) {
|
||||
/* start at 2 to include the / */
|
||||
for (ospeed = i = cfgetospeed(&tty), len2 = 2; i > 9; len2++)
|
||||
i /= 10;
|
||||
if (len + len2 < sizeof(term))
|
||||
(void)snprintf(term + len, len2 + 1, "/%d", ospeed);
|
||||
}
|
||||
|
||||
(void)get_window_size(0, &winsize);
|
||||
|
||||
(void)signal(SIGPIPE, lostpeer);
|
||||
/* will use SIGUSR1 for window size hack, so hold it off */
|
||||
omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
|
||||
/*
|
||||
* We set SIGURG and SIGUSR1 below so that an
|
||||
* incoming signal will be held pending rather than being
|
||||
* discarded. Note that these routines will be ready to get
|
||||
* a signal by the time that they are unblocked below.
|
||||
*/
|
||||
(void)signal(SIGURG, copytochild);
|
||||
(void)signal(SIGUSR1, writeroob);
|
||||
|
||||
rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family);
|
||||
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
|
||||
if (dflag &&
|
||||
setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
|
||||
warn("setsockopt");
|
||||
if (Dflag &&
|
||||
setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
|
||||
warn("setsockopt NODELAY (ignored)");
|
||||
|
||||
sslen = sizeof(ss);
|
||||
one = IPTOS_LOWDELAY;
|
||||
if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 &&
|
||||
ss.ss_family == AF_INET) {
|
||||
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one,
|
||||
sizeof(int)) < 0)
|
||||
warn("setsockopt TOS (ignored)");
|
||||
} else
|
||||
if (ss.ss_family == AF_INET)
|
||||
warn("setsockopt getsockname failed");
|
||||
|
||||
(void)setuid(uid);
|
||||
doit(omask);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
static int child;
|
||||
|
||||
static void
|
||||
doit(long omask)
|
||||
{
|
||||
|
||||
(void)signal(SIGINT, SIG_IGN);
|
||||
setsignal(SIGHUP);
|
||||
setsignal(SIGQUIT);
|
||||
mode(1);
|
||||
child = fork();
|
||||
if (child == -1) {
|
||||
warn("fork");
|
||||
done(1);
|
||||
}
|
||||
if (child == 0) {
|
||||
if (reader(omask) == 0) {
|
||||
msg("connection closed");
|
||||
exit(0);
|
||||
}
|
||||
sleep(1);
|
||||
msg("\007connection closed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We may still own the socket, and may have a pending SIGURG (or might
|
||||
* receive one soon) that we really want to send to the reader. When
|
||||
* one of these comes in, the trap copytochild simply copies such
|
||||
* signals to the child. We can now unblock SIGURG and SIGUSR1
|
||||
* that were set above.
|
||||
*/
|
||||
(void)sigsetmask(omask);
|
||||
(void)signal(SIGCHLD, catch_child);
|
||||
writer();
|
||||
msg("closed connection");
|
||||
done(0);
|
||||
}
|
||||
|
||||
/* trap a signal, unless it is being ignored. */
|
||||
static void
|
||||
setsignal(int sig)
|
||||
{
|
||||
int omask = sigblock(sigmask(sig));
|
||||
|
||||
if (signal(sig, exit) == SIG_IGN)
|
||||
(void)signal(sig, SIG_IGN);
|
||||
(void)sigsetmask(omask);
|
||||
}
|
||||
|
||||
static void
|
||||
done(int status)
|
||||
{
|
||||
int w, wstatus;
|
||||
|
||||
mode(0);
|
||||
if (child > 0) {
|
||||
/* make sure catch_child does not snap it up */
|
||||
(void)signal(SIGCHLD, SIG_DFL);
|
||||
if (kill(child, SIGKILL) >= 0)
|
||||
while ((w = wait(&wstatus)) > 0 && w != child);
|
||||
}
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static int dosigwinch;
|
||||
|
||||
/*
|
||||
* This is called when the reader process gets the out-of-band (urgent)
|
||||
* request to turn on the window-changing protocol.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
writeroob(int signo __unused)
|
||||
{
|
||||
if (dosigwinch == 0) {
|
||||
sendwindow();
|
||||
(void)signal(SIGWINCH, sigwinch);
|
||||
}
|
||||
dosigwinch = 1;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
catch_child(int signo __unused)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
for (;;) {
|
||||
pid = wait3(&status, WNOHANG|WUNTRACED, NULL);
|
||||
if (pid == 0)
|
||||
return;
|
||||
/* if the child (reader) dies, just quit */
|
||||
if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
|
||||
done(WTERMSIG(status) | WEXITSTATUS(status));
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* writer: write to remote: 0 -> line.
|
||||
* ~. terminate
|
||||
* ~^Z suspend rlogin process.
|
||||
* ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
|
||||
*/
|
||||
static void
|
||||
writer(void)
|
||||
{
|
||||
int bol, local, n;
|
||||
char c;
|
||||
|
||||
bol = 1; /* beginning of line */
|
||||
local = 0;
|
||||
for (;;) {
|
||||
n = read(STDIN_FILENO, &c, 1);
|
||||
if (n <= 0) {
|
||||
if (n < 0 && errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If we're at the beginning of the line and recognize a
|
||||
* command character, then we echo locally. Otherwise,
|
||||
* characters are echo'd remotely. If the command character
|
||||
* is doubled, this acts as a force and local echo is
|
||||
* suppressed.
|
||||
*/
|
||||
if (bol) {
|
||||
bol = 0;
|
||||
if (!noescape && c == escapechar) {
|
||||
local = 1;
|
||||
continue;
|
||||
}
|
||||
} else if (local) {
|
||||
local = 0;
|
||||
if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) {
|
||||
echo(c);
|
||||
break;
|
||||
}
|
||||
if (CCEQ(deftty.c_cc[VSUSP], c) ||
|
||||
CCEQ(deftty.c_cc[VDSUSP], c)) {
|
||||
bol = 1;
|
||||
echo(c);
|
||||
stop(c);
|
||||
continue;
|
||||
}
|
||||
if (c != escapechar)
|
||||
(void)write(rem, &escapechar, 1);
|
||||
}
|
||||
|
||||
if (write(rem, &c, 1) == 0) {
|
||||
msg("line gone");
|
||||
break;
|
||||
}
|
||||
bol = CCEQ(deftty.c_cc[VKILL], c) ||
|
||||
CCEQ(deftty.c_cc[VEOF], c) ||
|
||||
CCEQ(deftty.c_cc[VINTR], c) ||
|
||||
CCEQ(deftty.c_cc[VSUSP], c) ||
|
||||
c == '\r' || c == '\n';
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
echo(char c)
|
||||
{
|
||||
char *p;
|
||||
char buf[8];
|
||||
|
||||
p = buf;
|
||||
c &= 0177;
|
||||
*p++ = escapechar;
|
||||
if (c < ' ') {
|
||||
*p++ = '^';
|
||||
*p++ = c + '@';
|
||||
} else if (c == 0177) {
|
||||
*p++ = '^';
|
||||
*p++ = '?';
|
||||
} else
|
||||
*p++ = c;
|
||||
*p++ = '\r';
|
||||
*p++ = '\n';
|
||||
(void)write(STDOUT_FILENO, buf, p - buf);
|
||||
}
|
||||
|
||||
static void
|
||||
stop(char cmdc)
|
||||
{
|
||||
mode(0);
|
||||
(void)signal(SIGCHLD, SIG_IGN);
|
||||
(void)kill(CCEQ(deftty.c_cc[VSUSP], cmdc) ? 0 : getpid(), SIGTSTP);
|
||||
(void)signal(SIGCHLD, catch_child);
|
||||
mode(1);
|
||||
sigwinch(0); /* check for size changes */
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
sigwinch(int signo __unused)
|
||||
{
|
||||
struct winsize ws;
|
||||
|
||||
if (dosigwinch && get_window_size(0, &ws) == 0 &&
|
||||
bcmp(&ws, &winsize, sizeof(ws))) {
|
||||
winsize = ws;
|
||||
sendwindow();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the window size to the server via the magic escape
|
||||
*/
|
||||
static void
|
||||
sendwindow(void)
|
||||
{
|
||||
struct winsize ws;
|
||||
char obuf[4 + sizeof (struct winsize)];
|
||||
|
||||
obuf[0] = 0377;
|
||||
obuf[1] = 0377;
|
||||
obuf[2] = 's';
|
||||
obuf[3] = 's';
|
||||
ws.ws_row = htons(winsize.ws_row);
|
||||
ws.ws_col = htons(winsize.ws_col);
|
||||
ws.ws_xpixel = htons(winsize.ws_xpixel);
|
||||
ws.ws_ypixel = htons(winsize.ws_ypixel);
|
||||
bcopy(&ws, obuf + 4, sizeof(ws));
|
||||
|
||||
(void)write(rem, obuf, sizeof(obuf));
|
||||
}
|
||||
|
||||
/*
|
||||
* reader: read from remote: line -> 1
|
||||
*/
|
||||
#define READING 1
|
||||
#define WRITING 2
|
||||
|
||||
static jmp_buf rcvtop;
|
||||
static int rcvcnt, rcvstate;
|
||||
static pid_t ppid;
|
||||
static char rcvbuf[8 * 1024];
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
oob(int signo __unused)
|
||||
{
|
||||
struct termios tty;
|
||||
int atmark, n, rcvd;
|
||||
char waste[BUFSIZ], mark;
|
||||
|
||||
rcvd = 0;
|
||||
while (recv(rem, &mark, 1, MSG_OOB) < 0) {
|
||||
switch (errno) {
|
||||
case EWOULDBLOCK:
|
||||
/*
|
||||
* Urgent data not here yet. It may not be possible
|
||||
* to send it yet if we are blocked for output and
|
||||
* our input buffer is full.
|
||||
*/
|
||||
if (rcvcnt < (int)sizeof(rcvbuf)) {
|
||||
n = read(rem, rcvbuf + rcvcnt,
|
||||
sizeof(rcvbuf) - rcvcnt);
|
||||
if (n <= 0)
|
||||
return;
|
||||
rcvd += n;
|
||||
} else {
|
||||
n = read(rem, waste, sizeof(waste));
|
||||
if (n <= 0)
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mark & TIOCPKT_WINDOW) {
|
||||
/* Let server know about window size changes */
|
||||
(void)kill(ppid, SIGUSR1);
|
||||
}
|
||||
if (!eight && (mark & TIOCPKT_NOSTOP)) {
|
||||
(void)tcgetattr(0, &tty);
|
||||
tty.c_iflag &= ~IXON;
|
||||
(void)tcsetattr(0, TCSANOW, &tty);
|
||||
}
|
||||
if (!eight && (mark & TIOCPKT_DOSTOP)) {
|
||||
(void)tcgetattr(0, &tty);
|
||||
tty.c_iflag |= (deftty.c_iflag & IXON);
|
||||
(void)tcsetattr(0, TCSANOW, &tty);
|
||||
}
|
||||
if (mark & TIOCPKT_FLUSHWRITE) {
|
||||
(void)tcflush(1, TCIOFLUSH);
|
||||
for (;;) {
|
||||
if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
|
||||
warn("ioctl");
|
||||
break;
|
||||
}
|
||||
if (atmark)
|
||||
break;
|
||||
n = read(rem, waste, sizeof (waste));
|
||||
if (n <= 0)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Don't want any pending data to be output, so clear the recv
|
||||
* buffer. If we were hanging on a write when interrupted,
|
||||
* don't want it to restart. If we were reading, restart
|
||||
* anyway.
|
||||
*/
|
||||
rcvcnt = 0;
|
||||
longjmp(rcvtop, 1);
|
||||
}
|
||||
|
||||
/* oob does not do FLUSHREAD (alas!) */
|
||||
|
||||
/*
|
||||
* If we filled the receive buffer while a read was pending, longjmp
|
||||
* to the top to restart appropriately. Don't abort a pending write,
|
||||
* however, or we won't know how much was written.
|
||||
*/
|
||||
if (rcvd && rcvstate == READING)
|
||||
longjmp(rcvtop, 1);
|
||||
}
|
||||
|
||||
/* reader: read from remote: line -> 1 */
|
||||
static int
|
||||
reader(int omask)
|
||||
{
|
||||
int n, remaining;
|
||||
char *bufp;
|
||||
pid_t pid;
|
||||
|
||||
pid = getpid();
|
||||
(void)signal(SIGTTOU, SIG_IGN);
|
||||
(void)signal(SIGURG, oob);
|
||||
(void)signal(SIGUSR1, oob); /* When propogating SIGURG from parent */
|
||||
ppid = getppid();
|
||||
(void)fcntl(rem, F_SETOWN, pid);
|
||||
(void)setjmp(rcvtop);
|
||||
(void)sigsetmask(omask);
|
||||
bufp = rcvbuf;
|
||||
for (;;) {
|
||||
while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
|
||||
rcvstate = WRITING;
|
||||
n = write(STDOUT_FILENO, bufp, remaining);
|
||||
if (n < 0) {
|
||||
if (errno != EINTR)
|
||||
return (-1);
|
||||
continue;
|
||||
}
|
||||
bufp += n;
|
||||
}
|
||||
bufp = rcvbuf;
|
||||
rcvcnt = 0;
|
||||
rcvstate = READING;
|
||||
|
||||
rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
|
||||
if (rcvcnt == 0)
|
||||
return (0);
|
||||
if (rcvcnt < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
warn("read");
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mode(int f)
|
||||
{
|
||||
struct termios tty;
|
||||
|
||||
switch (f) {
|
||||
case 0:
|
||||
(void)tcsetattr(0, TCSANOW, &deftty);
|
||||
break;
|
||||
case 1:
|
||||
(void)tcgetattr(0, &deftty);
|
||||
tty = deftty;
|
||||
/* This is loosely derived from sys/kern/tty_compat.c. */
|
||||
tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
|
||||
tty.c_iflag &= ~ICRNL;
|
||||
tty.c_oflag &= ~OPOST;
|
||||
tty.c_cc[VMIN] = 1;
|
||||
tty.c_cc[VTIME] = 0;
|
||||
if (eight) {
|
||||
tty.c_iflag &= IXOFF;
|
||||
tty.c_cflag &= ~(CSIZE|PARENB);
|
||||
tty.c_cflag |= CS8;
|
||||
}
|
||||
(void)tcsetattr(0, TCSANOW, &tty);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
lostpeer(int signo __unused)
|
||||
{
|
||||
(void)signal(SIGPIPE, SIG_IGN);
|
||||
msg("\007connection closed");
|
||||
done(1);
|
||||
}
|
||||
|
||||
/* copy SIGURGs to the child process via SIGUSR1. */
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
copytochild(int signo __unused)
|
||||
{
|
||||
(void)kill(child, SIGUSR1);
|
||||
}
|
||||
|
||||
static void
|
||||
msg(const char *str)
|
||||
{
|
||||
(void)fprintf(stderr, "rlogin: %s\r\n", str);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: rlogin [-46%s]%s[-e char] [-i localname] [-l username] host\n",
|
||||
"8DEd", " ");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static u_int
|
||||
getescape(const char *p)
|
||||
{
|
||||
long val;
|
||||
size_t len;
|
||||
|
||||
if ((len = strlen(p)) == 1) /* use any single char, including '\' */
|
||||
return ((u_int)*p);
|
||||
/* otherwise, \nnn */
|
||||
if (*p == '\\' && len >= 2 && len <= 4) {
|
||||
val = strtol(++p, NULL, 8);
|
||||
for (;;) {
|
||||
if (!*++p)
|
||||
return ((u_int)val);
|
||||
if (*p < '0' || *p > '8')
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg("illegal option value -- e");
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 7/19/93
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= rsh
|
||||
CFLAGS+=-I${SRCTOP}/libexec/rlogind
|
||||
|
||||
PACKAGE=rcmds
|
||||
|
||||
BINOWN= root
|
||||
BINMODE=4555
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,19 +0,0 @@
|
||||
# $FreeBSD$
|
||||
# Autogenerated - do NOT edit!
|
||||
|
||||
DIRDEPS = \
|
||||
gnu/lib/csu \
|
||||
gnu/lib/libgcc \
|
||||
include \
|
||||
include/xlocale \
|
||||
lib/${CSU_DIR} \
|
||||
lib/libc \
|
||||
lib/libcompiler_rt \
|
||||
lib/libutil \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
||||
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
|
||||
# local dependencies - needed for -jN in clean tree
|
||||
.endif
|
@ -1,191 +0,0 @@
|
||||
.\" 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.1 (Berkeley) 6/6/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 3, 2017
|
||||
.Dt RSH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rsh
|
||||
.Nd remote shell
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl 46dnN
|
||||
.Op Fl l Ar username
|
||||
.Op Fl t Ar timeout
|
||||
.Ar host
|
||||
.Op command
|
||||
.Sh DEPRECATION NOTICE
|
||||
.Nm
|
||||
is deprecated and will be removed from future versions of the
|
||||
.Fx
|
||||
base system.
|
||||
If
|
||||
.Nm
|
||||
is still required, it can be installed from ports or packages
|
||||
(net/bsdrcmds).
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility executes
|
||||
.Ar command
|
||||
on
|
||||
.Ar host .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility 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
|
||||
Turn on socket debugging (using
|
||||
.Xr setsockopt 2 )
|
||||
on the
|
||||
.Tn TCP
|
||||
sockets used for communication with the remote host.
|
||||
.It Fl l Ar username
|
||||
Allow the remote
|
||||
.Ar username
|
||||
to be specified.
|
||||
By default, the remote username is the same as the local username.
|
||||
Authorization is determined
|
||||
as in
|
||||
.Xr rlogin 1 .
|
||||
.It Fl N
|
||||
Opposite to
|
||||
.Fl n
|
||||
option: do not send the "end of file" (EOF) indication for input stream
|
||||
to the remote host. This option makes the
|
||||
.Nm
|
||||
utility compatible with protocol implementations confused by receiving
|
||||
EOF, like some Cisco IOS versions. Disables
|
||||
.Fl n .
|
||||
.It Fl n
|
||||
Redirect input from the special device
|
||||
.Pa /dev/null
|
||||
(see the
|
||||
.Sx BUGS
|
||||
section of this manual page). Disables
|
||||
.Fl N .
|
||||
.It Fl t Ar timeout
|
||||
Allow a
|
||||
.Ar timeout
|
||||
to be specified (in seconds).
|
||||
If no
|
||||
data is sent or received in this time,
|
||||
.Nm
|
||||
will exit.
|
||||
.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 >> localfile
|
||||
.Pp
|
||||
appends the remote file
|
||||
.Ar remotefile
|
||||
to the local file
|
||||
.Ar localfile ,
|
||||
while
|
||||
.Pp
|
||||
.Dl rsh otherhost cat remotefile \&">>\&" 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 /usr/hosts.
|
||||
.\" If this directory is included in your search path, you can use the
|
||||
.\" shorthand ``host command'' for the longer form ``rsh host command''.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/hosts -compact
|
||||
.It Pa /etc/hosts
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rlogin 1 ,
|
||||
.Xr setsockopt 2 ,
|
||||
.Xr rcmd 3 ,
|
||||
.Xr ruserok 3 ,
|
||||
.Xr hosts 5 ,
|
||||
.Xr hosts.equiv 5 ,
|
||||
.Xr rlogind 8 ,
|
||||
.Xr rshd 8
|
||||
.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 ee 1
|
||||
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.
|
@ -1,381 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1983, 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Networks Associates Technology, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
*
|
||||
* 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
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1983, 1990, 1993, 1994\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#if 0
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "From: @(#)rsh.c 8.3 (Berkeley) 4/6/94";
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* rsh - remote shell
|
||||
*/
|
||||
static int rfd2;
|
||||
|
||||
static int family = PF_UNSPEC;
|
||||
static char rlogin[] = "rlogin";
|
||||
|
||||
void connect_timeout(int);
|
||||
char *copyargs(char * const *);
|
||||
void sendsig(int);
|
||||
void talk(int, int, long, pid_t, int, int);
|
||||
void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct passwd const *pw;
|
||||
struct servent const *sp;
|
||||
long omask;
|
||||
int argoff, asrsh, ch, dflag, nflag, Nflag, one, rem;
|
||||
pid_t pid = 0;
|
||||
uid_t uid;
|
||||
char *args, *host, *p, *user;
|
||||
int timeout = 0;
|
||||
|
||||
argoff = asrsh = dflag = nflag = Nflag = 0;
|
||||
one = 1;
|
||||
host = user = NULL;
|
||||
|
||||
/* if called as something other than "rsh", use it as the host name */
|
||||
if ((p = strrchr(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;
|
||||
}
|
||||
|
||||
#define OPTIONS "468LNde:l:nt:w"
|
||||
while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
|
||||
switch(ch) {
|
||||
case '4':
|
||||
family = PF_INET;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
family = PF_INET6;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
Nflag = 1;
|
||||
nflag = 0;
|
||||
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;
|
||||
Nflag = 0;
|
||||
break;
|
||||
case 't':
|
||||
timeout = atoi(optarg);
|
||||
break;
|
||||
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_RLOGIN, argv);
|
||||
err(1, "can't exec %s", _PATH_RLOGIN);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!(pw = getpwuid(uid = getuid())))
|
||||
errx(1, "unknown user id");
|
||||
if (!user)
|
||||
user = pw->pw_name;
|
||||
|
||||
args = copyargs(argv);
|
||||
|
||||
sp = NULL;
|
||||
if (sp == NULL)
|
||||
sp = getservbyname("shell", "tcp");
|
||||
if (sp == NULL)
|
||||
errx(1, "shell/tcp: unknown service");
|
||||
|
||||
if (timeout) {
|
||||
signal(SIGALRM, connect_timeout);
|
||||
alarm(timeout);
|
||||
}
|
||||
rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
|
||||
family);
|
||||
if (timeout) {
|
||||
signal(SIGALRM, SIG_DFL);
|
||||
alarm(0);
|
||||
}
|
||||
|
||||
if (rem < 0)
|
||||
exit(1);
|
||||
|
||||
if (rfd2 < 0)
|
||||
errx(1, "can't establish stderr");
|
||||
if (dflag) {
|
||||
if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
|
||||
sizeof(one)) < 0)
|
||||
warn("setsockopt");
|
||||
if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
|
||||
sizeof(one)) < 0)
|
||||
warn("setsockopt");
|
||||
}
|
||||
|
||||
(void)setuid(uid);
|
||||
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
|
||||
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)
|
||||
err(1, "fork");
|
||||
}
|
||||
else
|
||||
(void)shutdown(rem, SHUT_WR);
|
||||
|
||||
(void)ioctl(rfd2, FIONBIO, &one);
|
||||
(void)ioctl(rem, FIONBIO, &one);
|
||||
|
||||
talk(nflag, Nflag, omask, pid, rem, timeout);
|
||||
|
||||
if (!nflag)
|
||||
(void)kill(pid, SIGKILL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
talk(int nflag, int Nflag, long omask, pid_t pid, int rem, int timeout)
|
||||
{
|
||||
int cc, wc;
|
||||
fd_set readfrom, ready, rembits;
|
||||
char buf[BUFSIZ];
|
||||
const char *bp;
|
||||
struct timeval tvtimeout;
|
||||
int nfds, srval;
|
||||
|
||||
if (!nflag && pid == 0) {
|
||||
(void)close(rfd2);
|
||||
|
||||
reread: errno = 0;
|
||||
if ((cc = read(0, buf, sizeof buf)) <= 0)
|
||||
goto done;
|
||||
bp = buf;
|
||||
|
||||
rewrite:
|
||||
if (rem >= FD_SETSIZE)
|
||||
errx(1, "descriptor too big");
|
||||
FD_ZERO(&rembits);
|
||||
FD_SET(rem, &rembits);
|
||||
nfds = rem + 1;
|
||||
if (select(nfds, 0, &rembits, 0, 0) < 0) {
|
||||
if (errno != EINTR)
|
||||
err(1, "select");
|
||||
goto rewrite;
|
||||
}
|
||||
if (!FD_ISSET(rem, &rembits))
|
||||
goto rewrite;
|
||||
wc = write(rem, bp, cc);
|
||||
if (wc < 0) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
goto rewrite;
|
||||
goto done;
|
||||
}
|
||||
bp += wc;
|
||||
cc -= wc;
|
||||
if (cc == 0)
|
||||
goto reread;
|
||||
goto rewrite;
|
||||
done: if (!Nflag)
|
||||
(void)shutdown(rem, SHUT_WR);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
tvtimeout.tv_sec = timeout;
|
||||
tvtimeout.tv_usec = 0;
|
||||
|
||||
(void)sigsetmask(omask);
|
||||
if (rfd2 >= FD_SETSIZE || rem >= FD_SETSIZE)
|
||||
errx(1, "descriptor too big");
|
||||
FD_ZERO(&readfrom);
|
||||
FD_SET(rfd2, &readfrom);
|
||||
FD_SET(rem, &readfrom);
|
||||
nfds = MAX(rfd2+1, rem+1);
|
||||
do {
|
||||
ready = readfrom;
|
||||
if (timeout) {
|
||||
srval = select(nfds, &ready, 0, 0, &tvtimeout);
|
||||
} else {
|
||||
srval = select(nfds, &ready, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (srval < 0) {
|
||||
if (errno != EINTR)
|
||||
err(1, "select");
|
||||
continue;
|
||||
}
|
||||
if (srval == 0)
|
||||
errx(1, "timeout reached (%d seconds)", timeout);
|
||||
if (FD_ISSET(rfd2, &ready)) {
|
||||
errno = 0;
|
||||
cc = read(rfd2, buf, sizeof buf);
|
||||
if (cc <= 0) {
|
||||
if (errno != EWOULDBLOCK)
|
||||
FD_CLR(rfd2, &readfrom);
|
||||
} else
|
||||
(void)write(STDERR_FILENO, buf, cc);
|
||||
}
|
||||
if (FD_ISSET(rem, &ready)) {
|
||||
errno = 0;
|
||||
cc = read(rem, buf, sizeof buf);
|
||||
if (cc <= 0) {
|
||||
if (errno != EWOULDBLOCK)
|
||||
FD_CLR(rem, &readfrom);
|
||||
} else
|
||||
(void)write(STDOUT_FILENO, buf, cc);
|
||||
}
|
||||
} while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
|
||||
}
|
||||
|
||||
void
|
||||
connect_timeout(int sig __unused)
|
||||
{
|
||||
char message[] = "timeout reached before connection completed.\n";
|
||||
|
||||
write(STDERR_FILENO, message, sizeof(message) - 1);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
sendsig(int sig)
|
||||
{
|
||||
char signo;
|
||||
|
||||
signo = sig;
|
||||
(void)write(rfd2, &signo, 1);
|
||||
}
|
||||
|
||||
char *
|
||||
copyargs(char * const *argv)
|
||||
{
|
||||
int cc;
|
||||
char *args, *p;
|
||||
char * const *ap;
|
||||
|
||||
cc = 0;
|
||||
for (ap = argv; *ap; ++ap)
|
||||
cc += strlen(*ap) + 1;
|
||||
if (!(args = malloc((u_int)cc)))
|
||||
err(1, NULL);
|
||||
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)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"usage: rsh [-46Ndn] [-l username] [-t timeout] host [command]\n");
|
||||
exit(1);
|
||||
}
|
Loading…
Reference in New Issue
Block a user