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