]> Zhao Yanbai Git Server - minix.git/commitdiff
Import NetBSD rcmd, rcp, rsh, rshd 81/3181/2
authorDavid van Moolenbroek <david@minix3.org>
Sat, 19 Sep 2015 17:12:39 +0000 (17:12 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Wed, 23 Sep 2015 12:03:06 +0000 (12:03 +0000)
Change-Id: I83d908bbe17f04826e9b5c3a220a5bb2c3a51c80

35 files changed:
bin/Makefile
bin/rcmd/Makefile [new file with mode: 0644]
bin/rcmd/rcmd.1 [new file with mode: 0644]
bin/rcp/Makefile [new file with mode: 0644]
bin/rcp/extern.h [new file with mode: 0644]
bin/rcp/pathnames.h [new file with mode: 0644]
bin/rcp/rcp.1 [new file with mode: 0644]
bin/rcp/rcp.c [new file with mode: 0644]
bin/rcp/util.c [new file with mode: 0644]
distrib/sets/lists/minix/mi
etc/rc.daemons.dist
libexec/Makefile
libexec/rshd/Makefile [new file with mode: 0644]
libexec/rshd/rshd.8 [new file with mode: 0644]
libexec/rshd/rshd.c [new file with mode: 0644]
minix/commands/Makefile
minix/commands/rcp/Makefile [deleted file]
minix/commands/rcp/rcp.c [deleted file]
minix/commands/rsh/Makefile [deleted file]
minix/commands/rsh/rsh.c [deleted file]
minix/commands/rshd/Makefile [deleted file]
minix/commands/rshd/rshd.c [deleted file]
minix/commands/tcpd/tcpd.c
minix/man/man1/Makefile
minix/man/man1/rcp.1 [deleted file]
minix/man/man1/rsh.1 [deleted file]
minix/man/man8/Makefile
minix/man/man8/rshd.8 [deleted file]
usr.bin/Makefile
usr.bin/rsh/Makefile [new file with mode: 0644]
usr.bin/rsh/getport.c [new file with mode: 0644]
usr.bin/rsh/getport.h [new file with mode: 0644]
usr.bin/rsh/pathnames.h [new file with mode: 0644]
usr.bin/rsh/rsh.1 [new file with mode: 0644]
usr.bin/rsh/rsh.c [new file with mode: 0644]

index 4c55e024dc348fed4bd59b963b7f721fc076efc9..ce4ea6c79a46153aa939642905cd925ee67cced4 100644 (file)
@@ -2,7 +2,7 @@
 #      @(#)Makefile    8.1 (Berkeley) 5/31/93
 
 SUBDIR=        cat chmod cp date dd df domainname echo ed expr hostname \
-       kill ksh ln ls mkdir mv pax pwd rm rmdir sh \
+       kill ksh ln ls mkdir mv pax pwd rcp rcmd rm rmdir sh \
        sleep stty sync test
 
 .include <bsd.subdir.mk>
diff --git a/bin/rcmd/Makefile b/bin/rcmd/Makefile
new file mode 100644 (file)
index 0000000..343d57b
--- /dev/null
@@ -0,0 +1,15 @@
+#      $NetBSD: Makefile,v 1.11 2007/05/28 12:06:17 tls Exp $
+
+.include <bsd.own.mk>
+
+USE_FORT?=yes  # setuid
+# XXX Unsupported Kerberos options were removed from man page
+# XXX Don't forget to update the man page if you fix Kerberos
+PROG=  rcmd
+SRCS=  rsh.c getport.c
+CPPFLAGS+=-DIN_RCMD
+BINOWN=        root
+BINMODE=4555
+.PATH: ${NETBSDSRCDIR}/usr.bin/rsh
+
+.include <bsd.prog.mk>
diff --git a/bin/rcmd/rcmd.1 b/bin/rcmd/rcmd.1
new file mode 100644 (file)
index 0000000..9d000d3
--- /dev/null
@@ -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 (file)
index 0000000..2eaa7a1
--- /dev/null
@@ -0,0 +1,11 @@
+#      $NetBSD: Makefile,v 1.25 2009/02/14 08:31:13 lukem Exp $
+#      @(#)Makefile    8.1 (Berkeley) 7/19/93
+
+WARNS=3
+
+.include <bsd.own.mk>
+
+PROG=          rcp
+SRCS=          rcp.c util.c
+
+.include <bsd.prog.mk>
diff --git a/bin/rcp/extern.h b/bin/rcp/extern.h
new file mode 100644 (file)
index 0000000..cc89bac
--- /dev/null
@@ -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 (file)
index 0000000..dd88d66
--- /dev/null
@@ -0,0 +1,42 @@
+/*     $NetBSD: pathnames.h,v 1.7 2004/08/19 23:05:00 christos Exp $   */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pathnames.h 8.1 (Berkeley) 5/31/93
+ */
+
+#include <paths.h>
+
+#ifdef RESCUEDIR
+#define        _PATH_CP        RESCUEDIR "/cp"
+#define        _PATH_RSH       RESCUEDIR "/rsh"
+#else
+#define        _PATH_CP        "/bin/cp"
+#define        _PATH_RSH       "/usr/bin/rsh"
+#endif
diff --git a/bin/rcp/rcp.1 b/bin/rcp/rcp.1
new file mode 100644 (file)
index 0000000..792c86e
--- /dev/null
@@ -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 (file)
index 0000000..84d5620
--- /dev/null
@@ -0,0 +1,813 @@
+/*     $NetBSD: rcp.c,v 1.49 2012/05/07 15:22:54 chs Exp $     */
+
+/*
+ * Copyright (c) 1983, 1990, 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1990, 1992, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rcp.c      8.2 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: rcp.c,v 1.49 2012/05/07 15:22:54 chs Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+#include "extern.h"
+
+#define        OPTIONS "46dfprt"
+
+struct passwd *pwd;
+char *pwname;
+u_short        port;
+uid_t  userid;
+int errs, rem;
+int pflag, iamremote, iamrecursive, targetshouldbedirectory;
+int family = AF_UNSPEC;
+static char dot[] = ".";
+
+#define        CMDNEEDS        64
+char cmd[CMDNEEDS];            /* must hold "rcp -r -p -d\0" */
+
+int     response(void);
+void    rsource(char *, struct stat *);
+void    sink(int, char *[]);
+void    source(int, char *[]);
+void    tolocal(int, char *[]);
+void    toremote(char *, int, char *[]);
+void    usage(void);
+
+int
+main(int argc, char *argv[])
+{
+       struct servent *sp;
+       int ch, fflag, tflag;
+       char *targ;
+       const char *shell;
+
+       setprogname(argv[0]);
+       (void)setlocale(LC_ALL, "");
+
+       fflag = tflag = 0;
+       while ((ch = getopt(argc, argv, OPTIONS)) != -1)
+               switch(ch) {                    /* User-visible flags. */
+               case '4':
+                       family = AF_INET;
+                       break;
+               case '6':
+                       family = AF_INET6;
+                       break;
+               case 'K':
+                       break;
+               case 'p':
+                       pflag = 1;
+                       break;
+               case 'r':
+                       iamrecursive = 1;
+                       break;
+                                               /* Server options. */
+               case 'd':
+                       targetshouldbedirectory = 1;
+                       break;
+               case 'f':                       /* "from" */
+                       iamremote = 1;
+                       fflag = 1;
+                       break;
+               case 't':                       /* "to" */
+                       iamremote = 1;
+                       tflag = 1;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       sp = getservbyname(shell = "shell", "tcp");
+       if (sp == NULL)
+               errx(1, "%s/tcp: unknown service", shell);
+       port = sp->s_port;
+
+       if ((pwd = getpwuid(userid = getuid())) == NULL)
+               errx(1, "unknown user %d", (int)userid);
+
+       if ((pwname = strdup(pwd->pw_name)) == NULL)
+               err(1, NULL);
+
+       rem = STDIN_FILENO;             /* XXX */
+
+       if (fflag) {                    /* Follow "protocol", send data. */
+               (void)response();
+               source(argc, argv);
+               exit(errs);
+       }
+
+       if (tflag) {                    /* Receive data. */
+               sink(argc, argv);
+               exit(errs);
+       }
+
+       if (argc < 2)
+               usage();
+       if (argc > 2)
+               targetshouldbedirectory = 1;
+
+       rem = -1;
+       /* Command to be executed on remote system using "rsh". */
+       (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s",
+           iamrecursive ? " -r" : "", pflag ? " -p" : "",
+           targetshouldbedirectory ? " -d" : "");
+
+       (void)signal(SIGPIPE, lostconn);
+
+       if ((targ = colon(argv[argc - 1])) != NULL)/* Dest is remote host. */
+               toremote(targ, argc, argv);
+       else {
+               tolocal(argc, argv);            /* Dest is local host. */
+               if (targetshouldbedirectory)
+                       verifydir(argv[argc - 1]);
+       }
+       exit(errs);
+       /* NOTREACHED */
+}
+
+void
+toremote(char *targ, int argc, char *argv[])
+{
+       int i;
+       size_t len;
+       char *bp, *host, *src, *suser, *thost, *tuser;
+
+       *targ++ = 0;
+       if (*targ == 0)
+               targ = dot;
+
+       if ((thost = strchr(argv[argc - 1], '@')) != NULL) {
+               /* user@host */
+               *thost++ = 0;
+               tuser = argv[argc - 1];
+               if (*tuser == '\0')
+                       tuser = NULL;
+               else if (!okname(tuser))
+                       exit(1);
+       } else {
+               thost = argv[argc - 1];
+               tuser = NULL;
+       }
+       thost = unbracket(thost);
+
+       for (i = 0; i < argc - 1; i++) {
+               src = colon(argv[i]);
+               if (src) {                      /* remote to remote */
+                       *src++ = 0;
+                       if (*src == 0)
+                               src = dot;
+                       host = strchr(argv[i], '@');
+                       len = strlen(_PATH_RSH) + strlen(argv[i]) +
+                           strlen(src) + (tuser ? strlen(tuser) : 0) +
+                           strlen(thost) + strlen(targ) + CMDNEEDS + 20;
+                       if (!(bp = malloc(len)))
+                               err(1, NULL);
+                       if (host) {
+                               *host++ = 0;
+                               host = unbracket(host);
+                               suser = argv[i];
+                               if (*suser == '\0')
+                                       suser = pwname;
+                               else if (!okname(suser)) {
+                                       (void)free(bp);
+                                       continue;
+                               }
+                               (void)snprintf(bp, len,
+                                   "%s %s -l %s -n %s %s '%s%s%s:%s'",
+                                   _PATH_RSH, host, suser, cmd, src,
+                                   tuser ? tuser : "", tuser ? "@" : "",
+                                   thost, targ);
+                       } else {
+                               host = unbracket(argv[i]);
+                               (void)snprintf(bp, len,
+                                   "exec %s %s -n %s %s '%s%s%s:%s'",
+                                   _PATH_RSH, argv[i], cmd, src,
+                                   tuser ? tuser : "", tuser ? "@" : "",
+                                   thost, targ);
+                       }
+                       (void)susystem(bp);
+                       (void)free(bp);
+               } else {                        /* local to remote */
+                       if (rem == -1) {
+                               len = strlen(targ) + CMDNEEDS + 20;
+                               if (!(bp = malloc(len)))
+                                       err(1, NULL);
+                               (void)snprintf(bp, len, "%s -t %s", cmd, targ);
+                               host = thost;
+                                       rem = rcmd_af(&host, port, pwname,
+                                           tuser ? tuser : pwname,
+                                           bp, NULL, family);
+                               if (rem < 0)
+                                       exit(1);
+                               if (response() < 0)
+                                       exit(1);
+                               (void)free(bp);
+                       }
+                       source(1, argv+i);
+               }
+       }
+}
+
+void
+tolocal(int argc, char *argv[])
+{
+       int i;
+       size_t len;
+       char *bp, *host, *src, *suser;
+
+       for (i = 0; i < argc - 1; i++) {
+               if (!(src = colon(argv[i]))) {          /* Local to local. */
+                       len = strlen(_PATH_CP) + strlen(argv[i]) +
+                           strlen(argv[argc - 1]) + 20;
+                       if (!(bp = malloc(len)))
+                               err(1, NULL);
+                       (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
+                           iamrecursive ? " -r" : "", pflag ? " -p" : "",
+                           argv[i], argv[argc - 1]);
+                       if (susystem(bp))
+                               ++errs;
+                       (void)free(bp);
+                       continue;
+               }
+               *src++ = 0;
+               if (*src == 0)
+                       src = dot;
+               if ((host = strchr(argv[i], '@')) == NULL) {
+                       host = argv[i];
+                       suser = pwname;
+               } else {
+                       *host++ = 0;
+                       suser = argv[i];
+                       if (*suser == '\0')
+                               suser = pwname;
+                       else if (!okname(suser))
+                               continue;
+               }
+               host = unbracket(host);
+               len = strlen(src) + CMDNEEDS + 20;
+               if ((bp = malloc(len)) == NULL)
+                       err(1, NULL);
+               (void)snprintf(bp, len, "%s -f %s", cmd, src);
+               rem = 
+                       rcmd_af(&host, port, pwname, suser, bp, NULL, family);
+               (void)free(bp);
+               if (rem < 0) {
+                       ++errs;
+                       continue;
+               }
+               sink(1, argv + argc - 1);
+               (void)close(rem);
+               rem = -1;
+       }
+}
+
+void
+source(int argc, char *argv[])
+{
+       struct stat stb;
+       static BUF buffer;
+       BUF *bp;
+       off_t i;
+       off_t amt;
+       int fd, haderr, indx, result;
+       char *last, *name, buf[BUFSIZ];
+
+       for (indx = 0; indx < argc; ++indx) {
+               name = argv[indx];
+               if ((fd = open(name, O_RDONLY, 0)) < 0)
+                       goto syserr;
+               if (fstat(fd, &stb)) {
+syserr:                        run_err("%s: %s", name, strerror(errno));
+                       goto next;
+               }
+               switch (stb.st_mode & S_IFMT) {
+               case S_IFREG:
+                       break;
+               case S_IFDIR:
+                       if (iamrecursive) {
+                               rsource(name, &stb);
+                               goto next;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       run_err("%s: not a regular file", name);
+                       goto next;
+               }
+               if ((last = strrchr(name, '/')) == NULL)
+                       last = name;
+               else
+                       ++last;
+               if (pflag) {
+                       /*
+                        * Make it compatible with possible future
+                        * versions expecting microseconds.
+                        */
+                       (void)snprintf(buf, sizeof(buf), "T%lld %ld %lld %ld\n",
+                           (long long)stb.st_mtimespec.tv_sec,
+                           (long)stb.st_mtimespec.tv_nsec / 1000,
+                           (long long)stb.st_atimespec.tv_sec,
+                           (long)stb.st_atimespec.tv_nsec / 1000);
+                       (void)write(rem, buf, strlen(buf));
+                       if (response() < 0)
+                               goto next;
+               }
+#define        RCPMODEMASK     (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
+               (void)snprintf(buf, sizeof(buf), "C%04o %lld %s\n",
+                   stb.st_mode & RCPMODEMASK, (long long)stb.st_size, last);
+               (void)write(rem, buf, strlen(buf));
+               if (response() < 0)
+                       goto next;
+               if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
+next:                  (void)close(fd);
+                       continue;
+               }
+
+               /* Keep writing after an error so that we stay sync'd up. */
+               haderr = 0;
+               for (i = 0; i < stb.st_size; i += bp->cnt) {
+                       amt = bp->cnt;
+                       if (i + amt > stb.st_size)
+                               amt = stb.st_size - i;
+                       if (!haderr) {
+                               result = read(fd, bp->buf, (size_t)amt);
+                               if (result != amt)
+                                       haderr = result >= 0 ? EIO : errno;
+                       }
+                       if (haderr)
+                               (void)write(rem, bp->buf, (size_t)amt);
+                       else {
+                               result = write(rem, bp->buf, (size_t)amt);
+                               if (result != amt)
+                                       haderr = result >= 0 ? EIO : errno;
+                       }
+               }
+               if (close(fd) && !haderr)
+                       haderr = errno;
+               if (!haderr)
+                       (void)write(rem, "", 1);
+               else
+                       run_err("%s: %s", name, strerror(haderr));
+               (void)response();
+       }
+}
+
+void
+rsource(char *name, struct stat *statp)
+{
+       DIR *dirp;
+       struct dirent *dp;
+       char *last, *vect[1], path[MAXPATHLEN];
+
+       if (!(dirp = opendir(name))) {
+               run_err("%s: %s", name, strerror(errno));
+               return;
+       }
+       last = strrchr(name, '/');
+       if (last == 0)
+               last = name;
+       else
+               last++;
+       if (pflag) {
+               (void)snprintf(path, sizeof(path), "T%lld %ld %lld %ld\n",
+                   (long long)statp->st_mtimespec.tv_sec,
+                   (long)statp->st_mtimespec.tv_nsec / 1000,
+                   (long long)statp->st_atimespec.tv_sec,
+                   (long)statp->st_atimespec.tv_nsec / 1000);
+               (void)write(rem, path, strlen(path));
+               if (response() < 0) {
+                       (void)closedir(dirp);
+                       return;
+               }
+       }
+       (void)snprintf(path, sizeof(path),
+           "D%04o %d %s\n", statp->st_mode & RCPMODEMASK, 0, last);
+       (void)write(rem, path, strlen(path));
+       if (response() < 0) {
+               (void)closedir(dirp);
+               return;
+       }
+       while ((dp = readdir(dirp)) != NULL) {
+               if (dp->d_ino == 0)
+                       continue;
+               if (!strcmp(dp->d_name, dot) || !strcmp(dp->d_name, ".."))
+                       continue;
+               if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
+                       run_err("%s/%s: name too long", name, dp->d_name);
+                       continue;
+               }
+               (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
+               vect[0] = path;
+               source(1, vect);
+       }
+       (void)closedir(dirp);
+       (void)write(rem, "E\n", 2);
+       (void)response();
+}
+
+void
+sink(int argc, char *argv[])
+{
+       static BUF buffer;
+       struct stat stb;
+       struct timeval tv[2];
+       enum { YES, NO, DISPLAYED } wrerr;
+       BUF *bp;
+       ssize_t j;
+       off_t i;
+       off_t amt;
+       off_t count;
+       int exists, first, ofd;
+       mode_t mask;
+       mode_t mode;
+       mode_t omode;
+       int setimes, targisdir;
+       int wrerrno = 0;        /* pacify gcc */
+       char ch, *cp, *np, *targ, *vect[1], buf[BUFSIZ];
+       const char *why;
+       off_t size;
+       char *namebuf = NULL;
+       size_t cursize = 0;
+
+#define        atime   tv[0]
+#define        mtime   tv[1]
+#define        SCREWUP(str)    { why = str; goto screwup; }
+
+       setimes = targisdir = 0;
+       mask = umask(0);
+       if (!pflag)
+               (void)umask(mask);
+       if (argc != 1) {
+               run_err("ambiguous target");
+               exit(1);
+       }
+       targ = *argv;
+       if (targetshouldbedirectory)
+               verifydir(targ);
+       (void)write(rem, "", 1);
+       if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
+               targisdir = 1;
+       for (first = 1;; first = 0) {
+               cp = buf;
+               if (read(rem, cp, 1) <= 0)
+                       goto out;
+               if (*cp++ == '\n')
+                       SCREWUP("unexpected <newline>");
+               do {
+                       if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
+                               SCREWUP("lost connection");
+                       *cp++ = ch;
+               } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
+               *cp = 0;
+
+               if (buf[0] == '\01' || buf[0] == '\02') {
+                       if (iamremote == 0)
+                               (void)write(STDERR_FILENO,
+                                   buf + 1, strlen(buf + 1));
+                       if (buf[0] == '\02')
+                               exit(1);
+                       ++errs;
+                       continue;
+               }
+               if (buf[0] == 'E') {
+                       (void)write(rem, "", 1);
+                       goto out;
+               }
+
+               if (ch == '\n')
+                       *--cp = 0;
+
+#define getnum(t) (t) = 0; while (isdigit((unsigned char)*cp)) (t) = (t) * 10 + (*cp++ - '0');
+               cp = buf;
+               if (*cp == 'T') {
+                       setimes++;
+                       cp++;
+                       getnum(mtime.tv_sec);
+                       if (*cp++ != ' ')
+                               SCREWUP("mtime.sec not delimited");
+                       getnum(mtime.tv_usec);
+                       if (*cp++ != ' ')
+                               SCREWUP("mtime.usec not delimited");
+                       getnum(atime.tv_sec);
+                       if (*cp++ != ' ')
+                               SCREWUP("atime.sec not delimited");
+                       getnum(atime.tv_usec);
+                       if (*cp++ != '\0')
+                               SCREWUP("atime.usec not delimited");
+                       (void)write(rem, "", 1);
+                       continue;
+               }
+               if (*cp != 'C' && *cp != 'D') {
+                       /*
+                        * Check for the case "rcp remote:foo\* local:bar".
+                        * In this case, the line "No match." can be returned
+                        * by the shell before the rcp command on the remote is
+                        * executed so the ^Aerror_message convention isn't
+                        * followed.
+                        */
+                       if (first) {
+                               run_err("%s", cp);
+                               exit(1);
+                       }
+                       SCREWUP("expected control record");
+               }
+               mode = 0;
+               for (++cp; cp < buf + 5; cp++) {
+                       if (*cp < '0' || *cp > '7')
+                               SCREWUP("bad mode");
+                       mode = (mode << 3) | (*cp - '0');
+               }
+               if (*cp++ != ' ')
+                       SCREWUP("mode not delimited");
+
+               for (size = 0; isdigit((unsigned char)*cp);)
+                       size = size * 10 + (*cp++ - '0');
+               if (*cp++ != ' ')
+                       SCREWUP("size not delimited");
+               if (targisdir) {
+                       char *newnamebuf;
+                       size_t need;
+
+                       need = strlen(targ) + strlen(cp) + 2;
+                       if (need > cursize) {
+                               need += 256;
+                               newnamebuf = realloc(namebuf, need);
+                               if (newnamebuf != NULL) {
+                                       namebuf = newnamebuf;
+                                       cursize = need;
+                               } else {
+                                       run_err("%s", strerror(errno));
+                                       exit(1);
+                               }
+                       }
+                       (void)snprintf(namebuf, cursize, "%s%s%s", targ,
+                           *targ ? "/" : "", cp);
+                       np = namebuf;
+               } else
+                       np = targ;
+               exists = stat(np, &stb) == 0;
+               if (buf[0] == 'D') {
+                       int mod_flag = pflag;
+                       if (exists) {
+                               if (!S_ISDIR(stb.st_mode)) {
+                                       errno = ENOTDIR;
+                                       goto bad;
+                               }
+                               if (pflag)
+                                       (void)chmod(np, mode);
+                       } else {
+                               /* Handle copying from a read-only directory */
+                               mod_flag = 1;
+                               if (mkdir(np, mode | S_IRWXU) < 0)
+                                       goto bad;
+                       }
+                       vect[0] = np;
+                       sink(1, vect);
+                       if (setimes) {
+                               setimes = 0;
+                               if (utimes(np, tv) < 0)
+                                   run_err("%s: set times: %s",
+                                       np, strerror(errno));
+                       }
+                       if (mod_flag)
+                               (void)chmod(np, mode);
+                       continue;
+               }
+               omode = mode;
+               mode |= S_IWRITE;
+               if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
+bad:                   run_err("%s: %s", np, strerror(errno));
+                       continue;
+               }
+               (void)write(rem, "", 1);
+               if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
+                       (void)close(ofd);
+                       continue;
+               }
+               cp = bp->buf;
+               wrerr = NO;
+               count = 0;
+               for (i = 0; i < size; i += BUFSIZ) {
+                       amt = BUFSIZ;
+                       if (i + amt > size)
+                               amt = size - i;
+                       count += amt;
+                       do {
+                               j = read(rem, cp, (size_t)amt);
+                               if (j == -1) {
+                                       run_err("%s", j ? strerror(errno) :
+                                           "dropped connection");
+                                       exit(1);
+                               }
+                               amt -= j;
+                               cp += j;
+                       } while (amt > 0);
+                       if (count == bp->cnt) {
+                               /* Keep reading so we stay sync'd up. */
+                               if (wrerr == NO) {
+                                       j = write(ofd, bp->buf, (size_t)count);
+                                       if (j != count) {
+                                               wrerr = YES;
+                                               wrerrno = j >= 0 ? EIO : errno; 
+                                       }
+                               }
+                               count = 0;
+                               cp = bp->buf;
+                       }
+               }
+               if (count != 0 && wrerr == NO &&
+                   (j = write(ofd, bp->buf, (size_t)count)) != count) {
+                       wrerr = YES;
+                       wrerrno = j >= 0 ? EIO : errno; 
+               }
+               if (ftruncate(ofd, size)) {
+                       run_err("%s: truncate: %s", np, strerror(errno));
+                       wrerr = DISPLAYED;
+               }
+               if (pflag) {
+                       if (exists || omode != mode)
+                               if (fchmod(ofd, omode))
+                                       run_err("%s: set mode: %s",
+                                           np, strerror(errno));
+               } else {
+                       if (!exists && omode != mode)
+                               if (fchmod(ofd, omode & ~mask))
+                                       run_err("%s: set mode: %s",
+                                           np, strerror(errno));
+               }
+#ifndef __SVR4
+               if (setimes && wrerr == NO) {
+                       setimes = 0;
+                       if (futimes(ofd, tv) < 0) {
+                               run_err("%s: set times: %s",
+                                   np, strerror(errno));
+                               wrerr = DISPLAYED;
+                       }
+               }
+#endif
+               (void)close(ofd);
+#ifdef __SVR4
+               if (setimes && wrerr == NO) {
+                       setimes = 0;
+                       if (utimes(np, tv) < 0) {
+                               run_err("%s: set times: %s",
+                                   np, strerror(errno));
+                               wrerr = DISPLAYED;
+                       }
+               }
+#endif
+               (void)response();
+               switch(wrerr) {
+               case YES:
+                       run_err("%s: write: %s", np, strerror(wrerrno));
+                       break;
+               case NO:
+                       (void)write(rem, "", 1);
+                       break;
+               case DISPLAYED:
+                       break;
+               }
+       }
+
+out:
+       if (namebuf) {
+               free(namebuf);
+       }
+       return;
+
+screwup:
+       run_err("protocol error: %s", why);
+       exit(1);
+       /* NOTREACHED */
+}
+
+
+int
+response(void)
+{
+       char ch, *cp, resp, rbuf[BUFSIZ];
+
+       if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
+               lostconn(0);
+
+       cp = rbuf;
+       switch(resp) {
+       case 0:                         /* ok */
+               return (0);
+       default:
+               *cp++ = resp;
+               /* FALLTHROUGH */
+       case 1:                         /* error, followed by error msg */
+       case 2:                         /* fatal error, "" */
+               do {
+                       if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
+                               lostconn(0);
+                       *cp++ = ch;
+               } while (cp < &rbuf[BUFSIZ] && ch != '\n');
+
+               if (!iamremote)
+                       (void)write(STDERR_FILENO, rbuf, (size_t)(cp - rbuf));
+               ++errs;
+               if (resp == 1)
+                       return (-1);
+               exit(1);
+       }
+       /* NOTREACHED */
+}
+
+void
+usage(void)
+{
+       (void)fprintf(stderr,
+           "usage: rcp [-46p] f1 f2; or: rcp [-46pr] f1 ... fn directory\n");
+       exit(1);
+       /* NOTREACHED */
+}
+
+#include <stdarg.h>
+
+
+void
+run_err(const char *fmt, ...)
+{
+       static FILE *fp;
+       va_list ap;
+
+       ++errs;
+       if (fp == NULL && !(fp = fdopen(rem, "w")))
+               return;
+
+       va_start(ap, fmt);
+
+       (void)fprintf(fp, "%c", 0x01);
+       (void)fprintf(fp, "rcp: ");
+       (void)vfprintf(fp, fmt, ap);
+       (void)fprintf(fp, "\n");
+       (void)fflush(fp);
+       va_end(ap);
+
+       if (!iamremote) {
+               va_start(ap, fmt);
+               vwarnx(fmt, ap);
+               va_end(ap);
+       }
+}
diff --git a/bin/rcp/util.c b/bin/rcp/util.c
new file mode 100644 (file)
index 0000000..e53aec9
--- /dev/null
@@ -0,0 +1,184 @@
+/*     $NetBSD: util.c,v 1.11 2006/12/15 22:45:34 christos Exp $       */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c     8.2 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: util.c,v 1.11 2006/12/15 22:45:34 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+char *
+colon(char *cp)
+{
+       if (*cp == ':')         /* Leading colon is part of file name. */
+               return (0);
+
+       for (; *cp; ++cp) {
+               if (*cp == ':')
+                       return (cp);
+               if (*cp == '/')
+                       return (0);
+       }
+       return (0);
+}
+
+char *
+unbracket(char *cp)
+{
+       char *ep;
+
+       if (*cp == '[') {
+               ep = cp + (strlen(cp) - 1);
+               if (*ep == ']') {
+                       *ep = '\0';
+                       ++cp;
+               }
+       }
+       return (cp);
+}
+
+void
+verifydir(char *cp)
+{
+       struct stat stb;
+
+       if (!stat(cp, &stb)) {
+               if (S_ISDIR(stb.st_mode))
+                       return;
+               errno = ENOTDIR;
+       }
+       run_err("%s: %s", cp, strerror(errno));
+       exit(1);
+       /* NOTREACHED */
+}
+
+int
+okname(char *cp0)
+{
+       int c;
+       char *cp;
+
+       cp = cp0;
+       do {
+               c = *cp;
+               if (c & 0200)
+                       goto bad;
+               if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
+                       goto bad;
+       } while (*++cp);
+       return (1);
+
+bad:   warnx("%s: invalid user name", cp0);
+       return (0);
+}
+
+int
+susystem(char *s)
+{
+       sig_t istat, qstat;
+       int status;
+       pid_t pid;
+
+       pid = vfork();
+       switch (pid) {
+       case -1:
+               return (127);
+       
+       case 0:
+               (void)execl(_PATH_BSHELL, "sh", "-c", s, NULL);
+               _exit(127);
+               /* NOTREACHED */
+       }
+       istat = signal(SIGINT, SIG_IGN);
+       qstat = signal(SIGQUIT, SIG_IGN);
+       if (waitpid(pid, &status, 0) < 0)
+               status = -1;
+       (void)signal(SIGINT, istat);
+       (void)signal(SIGQUIT, qstat);
+       return (status);
+}
+
+BUF *
+allocbuf(BUF *bp, int fd, int blksize)
+{
+       struct stat stb;
+       size_t size;
+       char *nbuf;
+
+       if (fstat(fd, &stb) < 0) {
+               run_err("fstat: %s", strerror(errno));
+               return (0);
+       }
+       size = roundup(stb.st_blksize, blksize);
+       if (size == 0)
+               size = blksize;
+       if (bp->cnt >= size)
+               return (bp);
+       if ((nbuf = realloc(bp->buf, size)) == NULL) {
+               free(bp->buf);
+               bp->buf = NULL;
+               bp->cnt = 0;
+               run_err("%s", strerror(errno));
+               return (0);
+       }
+       bp->buf = nbuf;
+       bp->cnt = size;
+       return (bp);
+}
+
+void
+/*ARGSUSED*/
+lostconn(int signo __unused)
+{
+       if (!iamremote)
+               warnx("lost connection");
+       exit(1);
+       /* NOTREACHED */
+}
index 7fe56d914501914932ca35f5390c1750649ff11e..1cf94a9b5f51078f097181dca001a040f8c43401 100644 (file)
@@ -39,6 +39,8 @@
 ./bin/printconfig                      minix-sys
 ./bin/printroot                                minix-sys
 ./bin/pwd                              minix-sys
+./bin/rcmd                             minix-sys
+./bin/rcp                              minix-sys
 ./bin/read                             minix-sys       obsolete
 ./bin/readclock                                minix-sys
 ./bin/rm                               minix-sys
 ./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
 ./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
 ./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
 ./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
index 7cd840bc39873827e62a38e3b1058a4030181c45..23e20d8605d479a59d5a63ddbaa54e6daebeed98 100644 (file)
@@ -1,5 +1,5 @@
 daemonize talkd
-daemonize tcpd shell in.rshd
+daemonize tcpd shell /usr/libexec/rshd
 daemonize tcpd telnet in.telnetd
 daemonize tcpd ftp /usr/libexec/ftpd
 daemonize tcpd finger /usr/libexec/fingerd
index 4c1de29ce14990e61249d55f9d3d5e2cce6ad854..8aa95ce375648869fd796a0e3253c987b3e28e2b 100644 (file)
@@ -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 (file)
index 0000000..c9ad897
--- /dev/null
@@ -0,0 +1,26 @@
+#      $NetBSD: Makefile,v 1.19 2011/08/16 10:35:03 christos Exp $
+#      from: @(#)Makefile      8.1 (Berkeley) 6/4/93
+
+.include <bsd.own.mk>
+
+PROG=  rshd
+MAN=   rshd.8
+
+DPADD+=        ${LIBUTIL}
+LDADD+=        -lutil
+
+CPPFLAGS+=-DLOGIN_CAP
+
+.if (${USE_INET6} != "no")
+CPPFLAGS+=-DINET6
+.endif
+
+.if (${USE_PAM} != "no")
+CPPFLAGS+=-DUSE_PAM
+DPADD+= ${LIBPAM} ${PAM_STATIC_DPADD}
+LDADD+= -lpam ${PAM_STATIC_LDADD}
+.endif
+
+COPTS.rshd.c = -Wno-format-nonliteral
+
+.include <bsd.prog.mk>
diff --git a/libexec/rshd/rshd.8 b/libexec/rshd/rshd.8
new file mode 100644 (file)
index 0000000..65158ce
--- /dev/null
@@ -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 (file)
index 0000000..abdbe2d
--- /dev/null
@@ -0,0 +1,809 @@
+/*     $NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $        */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by WIDE Project and
+ *    its contributors.
+ * 4. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1988, 1989, 1992, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#if 0
+static char sccsid[] = "@(#)rshd.c     8.2 (Berkeley) 4/6/94";
+#else
+__RCSID("$NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * remote shell server:
+ *     [port]\0
+ *     remuser\0
+ *     locuser\0
+ *     command\0
+ *     data
+ */
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <poll.h>
+#ifdef  LOGIN_CAP
+#include <login_cap.h>
+#endif
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+#include <sys/wait.h>
+
+static struct pam_conv pamc = { openpam_nullconv, NULL };
+static pam_handle_t *pamh;
+static int pam_err;
+
+#define PAM_END do { \
+       if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
+               syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", \
+                   pam_strerror(pamh, pam_err)); \
+       if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \
+               syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", \
+                   pam_strerror(pamh, pam_err)); \
+       if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \
+               syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", \
+                   pam_strerror(pamh, pam_err)); \
+} while (/*CONSTCOND*/0)
+#else
+#define PAM_END
+#endif
+
+static int     keepalive = 1;
+static int     check_all;
+static int     log_success;            /* If TRUE, log all successful accesses */
+static int     sent_null;
+
+__dead static void      doit(struct sockaddr *, struct sockaddr *);
+__dead static void      rshd_errx(int, const char *, ...) __printflike(2, 3);
+static void     getstr(char *, int, const char *);
+static int      local_domain(char *);
+static char    *topdomain(char *);
+__dead static void      usage(void);
+
+#define        OPTIONS "aLln"
+extern int __check_rhosts_file;
+extern char *__rcmd_errstr;    /* syslog hook from libc/net/rcmd.c. */
+#ifdef USE_PAM
+static const char incorrect[] = "Login incorrect.";
+#endif
+
+int
+main(int argc, char *argv[])
+{
+       struct linger linger;
+       int ch, on = 1;
+       socklen_t fromlen;
+       socklen_t locallen;
+       struct sockaddr_storage from;
+       struct sockaddr_storage local;
+       struct protoent *proto;
+
+       openlog("rshd", LOG_PID, LOG_DAEMON);
+
+       opterr = 0;
+       while ((ch = getopt(argc, argv, OPTIONS)) != -1)
+               switch (ch) {
+               case 'a':
+                       check_all = 1;
+                       break;
+               case 'l':
+                       __check_rhosts_file = 0;
+                       break;
+               case 'n':
+                       keepalive = 0;
+                       break;
+               case 'L':
+                       log_success = 1;
+                       break;
+               case '?':
+               default:
+                       usage();
+                       break;
+               }
+
+       argc -= optind;
+       argv += optind;
+
+       fromlen = sizeof(from); /* xxx */
+       locallen = sizeof(local); /* xxx */
+       if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) {
+               syslog(LOG_ERR, "getpeername: %m");
+               return EXIT_FAILURE;
+       }
+       if (getsockname(STDIN_FILENO, (struct sockaddr *)&local,
+           &locallen) < 0) {
+               syslog(LOG_ERR, "getsockname: %m");
+               return EXIT_FAILURE;
+       }
+#if 0
+       if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
+           IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) &&
+           sizeof(struct sockaddr_in) <= sizeof(from)) {
+               struct sockaddr_in sin;
+               struct sockaddr_in6 *sin6;
+               const int off = sizeof(struct sockaddr_in6) -
+                   sizeof(struct sockaddr_in);
+
+               sin6 = (struct sockaddr_in6 *)&from;
+               (void)memset(&sin, 0, sizeof(sin));
+               sin.sin_family = AF_INET;
+               sin.sin_len = sizeof(struct sockaddr_in);
+               (void)memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off],
+                   sizeof(sin.sin_addr));
+               (void)memcpy(&from, &sin, sizeof(sin));
+               fromlen = sin.sin_len;
+       }
+#else
+       if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
+           IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) {
+               char hbuf[NI_MAXHOST];
+               if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf,
+                               sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
+                       strlcpy(hbuf, "invalid", sizeof(hbuf));
+               }
+               syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)",
+                   hbuf);
+               return EXIT_FAILURE;
+       }
+#endif
+       if (keepalive &&
+           setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
+           sizeof(on)) < 0)
+               syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+       linger.l_onoff = 1;
+       linger.l_linger = 60;                   /* XXX */
+       if (setsockopt(STDIN_FILENO, SOL_SOCKET, SO_LINGER, (char *)&linger,
+           sizeof (linger)) < 0)
+               syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
+       proto = getprotobyname("tcp");
+       (void)setsockopt(STDIN_FILENO, proto->p_proto, TCP_NODELAY, &on,
+           sizeof(on));
+       doit((struct sockaddr *)&from, (struct sockaddr *)&local);
+}
+
+extern char    **environ;
+
+static void
+doit(struct sockaddr *fromp, struct sockaddr *localp)
+{
+       struct passwd *pwd, pwres;
+       in_port_t port;
+       struct pollfd set[2];
+       int cc, pv[2], pid, s = -1;     /* XXX gcc */
+       int one = 1;
+       char *hostname, *errorhost = NULL;      /* XXX gcc */
+       const char *cp;
+       char sig, buf[BUFSIZ];
+       char cmdbuf[NCARGS+1], locuser[16], remuser[16];
+       char remotehost[2 * MAXHOSTNAMELEN + 1];
+       char hostnamebuf[2 * MAXHOSTNAMELEN + 1];
+#ifdef  LOGIN_CAP
+       login_cap_t *lc;
+#endif
+       char naddr[NI_MAXHOST];
+       char saddr[NI_MAXHOST];
+       char raddr[NI_MAXHOST];
+       char pbuf[NI_MAXSERV];
+       int af = fromp->sa_family;
+       u_int16_t *portp;
+       struct addrinfo hints, *res, *res0;
+       int gaierror;
+       const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+       const char *errormsg = NULL, *errorstr = NULL;
+       char pwbuf[1024];
+
+       (void)signal(SIGINT, SIG_DFL);
+       (void)signal(SIGQUIT, SIG_DFL);
+       (void)signal(SIGTERM, SIG_DFL);
+#ifdef DEBUG
+       { 
+               int t = open(_PATH_TTY, O_RDWR);
+               if (t >= 0) {
+                       ioctl(t, TIOCNOTTY, NULL);
+                       (void)close(t);
+               }
+       }
+#endif
+       switch (af) {
+       case AF_INET:
+               portp = &((struct sockaddr_in *)fromp)->sin_port;
+               break;
+#ifdef INET6
+       case AF_INET6:
+               portp = &((struct sockaddr_in6 *)fromp)->sin6_port;
+               break;
+#endif
+       default:
+               syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
+               exit(EXIT_FAILURE);
+       }
+       if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr),
+                       pbuf, sizeof(pbuf), niflags) != 0) {
+               syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
+               exit(EXIT_FAILURE);
+       }
+#ifdef IP_OPTIONS
+       if (af == AF_INET) {
+
+       u_char optbuf[BUFSIZ/3];
+       socklen_t optsize = sizeof(optbuf);
+       int ipproto;
+       unsigned int i;
+       struct protoent *ip;
+
+       if ((ip = getprotobyname("ip")) != NULL)
+               ipproto = ip->p_proto;
+       else
+               ipproto = IPPROTO_IP;
+       if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
+           optsize != 0) {
+               for (i = 0; i < optsize;) {
+                       u_char c = optbuf[i];
+                       if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
+                               syslog(LOG_NOTICE,
+                                   "Connection refused from %s "
+                                   "with IP option %s",
+                                   inet_ntoa((
+                                   (struct sockaddr_in *)fromp)->sin_addr),
+                                   c == IPOPT_LSRR ? "LSRR" : "SSRR");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (c == IPOPT_EOL)
+                               break;
+                       i += (c == IPOPT_NOP) ? 1 : optbuf[i + 1];
+               }
+       }
+       }
+#endif
+       if (ntohs(*portp) >= IPPORT_RESERVED
+           || ntohs(*portp) < IPPORT_RESERVED / 2) {
+               syslog(LOG_NOTICE|LOG_AUTH,
+                   "Connection from %s on illegal port %u",
+                   naddr, ntohs(*portp));
+               exit(EXIT_FAILURE);
+       }
+
+       (void) alarm(60);
+       port = 0;
+       for (;;) {
+               char c;
+
+               if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
+                       if (cc < 0)
+                               syslog(LOG_ERR, "read: %m");
+                       (void)shutdown(0, SHUT_RDWR);
+                       exit(EXIT_FAILURE);
+               }
+               if (c == 0)
+                       break;
+               port = port * 10 + c - '0';
+       }
+
+       (void) alarm(0);
+       if (port != 0) {
+               int lport = IPPORT_RESERVED - 1;
+               s = rresvport_af_addr(&lport, af, localp);
+               if (s < 0) {
+                       syslog(LOG_ERR, "can't get stderr port: %m");
+                       exit(EXIT_FAILURE);
+               }
+               if (port >= IPPORT_RESERVED) {
+                       syslog(LOG_ERR, "2nd port not reserved");
+                       exit(EXIT_FAILURE);
+               }
+               *portp = htons(port);
+               if (connect(s, fromp, fromp->sa_len) < 0) {
+                       syslog(LOG_ERR, "connect second port %d: %m", port);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+
+#ifdef notdef
+       /* from inetd, socket is already on 0, 1, 2 */
+       (void)dup2(f, STDIN_FILENO);
+       (void)dup2(f, STDOUT_FILENO);
+       (void)dup2(f, STDERR_FILENO);
+#endif
+       if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr),
+                       NULL, 0, NI_NAMEREQD) == 0) {
+               /*
+                * If name returned by getnameinfo is in our domain,
+                * attempt to verify that we haven't been fooled by someone
+                * in a remote net; look up the name and check that this
+                * address corresponds to the name.
+                */
+               hostname = saddr;
+               res0 = NULL;
+               if (check_all || local_domain(saddr)) {
+                       (void)strlcpy(remotehost, saddr, sizeof(remotehost));
+                       errorhost = remotehost;
+                       (void)memset(&hints, 0, sizeof(hints));
+                       hints.ai_family = fromp->sa_family;
+                       hints.ai_socktype = SOCK_STREAM;
+                       hints.ai_flags = AI_CANONNAME;
+                       gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0);
+                       if (gaierror) {
+                               syslog(LOG_NOTICE,
+                                   "Couldn't look up address for %s: %s",
+                                   remotehost, gai_strerror(gaierror));
+                               errorstr =
+                               "Couldn't look up address for your host (%s)\n";
+                               hostname = naddr;
+                       } else {
+                               for (res = res0; res; res = res->ai_next) {
+                                       if (res->ai_family != fromp->sa_family)
+                                               continue;
+                                       if (res->ai_addrlen != fromp->sa_len)
+                                               continue;
+                                       if (getnameinfo(res->ai_addr,
+                                               res->ai_addrlen,
+                                               raddr, sizeof(raddr), NULL, 0,
+                                               niflags) == 0
+                                        && strcmp(naddr, raddr) == 0) {
+                                               hostname = res->ai_canonname
+                                                       ? res->ai_canonname
+                                                       : saddr;
+                                               break;
+                                       }
+                               }
+                               if (res == NULL) {
+                                       syslog(LOG_NOTICE,
+                                         "Host addr %s not listed for host %s",
+                                           naddr, res0->ai_canonname
+                                                   ? res0->ai_canonname
+                                                   : saddr);
+                                       errorstr =
+                                           "Host address mismatch for %s\n";
+                                       hostname = naddr;
+                               }
+                       }
+               }
+               (void)strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf));
+               hostname = hostnamebuf;
+               if (res0)
+                       freeaddrinfo(res0);
+       } else {
+               (void)strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf));
+               errorhost = hostname = hostnamebuf;
+       }
+
+       (void)alarm(60);
+       getstr(remuser, sizeof(remuser), "remuser");
+       getstr(locuser, sizeof(locuser), "locuser");
+       getstr(cmdbuf, sizeof(cmdbuf), "command");
+       (void)alarm(0);
+
+#ifdef USE_PAM
+       pam_err = pam_start("rsh", locuser, &pamc, &pamh);
+       if (pam_err != PAM_SUCCESS) {
+               syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
+                   pam_strerror(pamh, pam_err));
+               rshd_errx(EXIT_FAILURE, incorrect);
+       }
+
+       if ((pam_err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS ||
+           (pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS){
+               syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
+                   pam_strerror(pamh, pam_err));
+               rshd_errx(EXIT_FAILURE, incorrect);
+       }
+
+       pam_err = pam_authenticate(pamh, 0);
+       if (pam_err == PAM_SUCCESS) {
+               if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
+                       (void)strlcpy(locuser, cp, sizeof(locuser));
+                       /* XXX truncation! */
+               }
+               pam_err = pam_acct_mgmt(pamh, 0);
+       }
+       if (pam_err != PAM_SUCCESS) {
+               errorstr = incorrect;
+               errormsg = pam_strerror(pamh, pam_err);
+               goto badlogin;
+       }
+#endif /* USE_PAM */
+       setpwent();
+       if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
+           pwd == NULL) {
+               syslog(LOG_INFO|LOG_AUTH,
+                   "%s@%s as %s: unknown login. cmd='%.80s'",
+                   remuser, hostname, locuser, cmdbuf);
+               if (errorstr == NULL)
+                       errorstr = "Permission denied.";
+               rshd_errx(EXIT_FAILURE, errorstr, errorhost);
+       }
+#ifdef LOGIN_CAP
+       lc = login_getclass(pwd ? pwd->pw_class : NULL);
+#endif 
+
+       if (chdir(pwd->pw_dir) < 0) {
+               if (chdir("/") < 0
+#ifdef LOGIN_CAP
+                   || login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0)
+#endif
+               ) {
+                       syslog(LOG_INFO|LOG_AUTH,
+                           "%s@%s as %s: no home directory. cmd='%.80s'",
+                           remuser, hostname, locuser, cmdbuf);
+                       rshd_errx(EXIT_SUCCESS, "No remote home directory.");
+               }
+       }
+
+#ifndef USE_PAM
+       if (errorstr ||
+           (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
+               iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser,
+                       locuser) < 0)) {
+               errormsg = __rcmd_errstr ? __rcmd_errstr : "unknown error";
+               if (errorstr == NULL)
+                       errorstr = "Permission denied.";
+               goto badlogin;
+       }
+
+       if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK))
+               rshd_errx(EXIT_FAILURE, "Logins currently disabled.");
+#endif
+
+#ifdef LOGIN_CAP
+       /*
+        * PAM modules might add supplementary groups in
+        * pam_setcred(), so initialize them first.
+        * But we need to open the session as root.
+        */
+       if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
+               syslog(LOG_ERR, "setusercontext: %m");
+               exit(EXIT_FAILURE);
+       }
+#else
+       initgroups(pwd->pw_name, pwd->pw_gid);
+#endif
+
+#ifdef USE_PAM
+       if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_open_session: %s",
+                   pam_strerror(pamh, pam_err));
+       } else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED))
+           != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err));
+       }
+#endif
+
+       (void)write(STDERR_FILENO, "\0", 1);
+       sent_null = 1;
+
+       if (port) {
+               if (pipe(pv) < 0)
+                       rshd_errx(EXIT_FAILURE, "Can't make pipe. (%s)",
+                           strerror(errno));
+               pid = fork();
+               if (pid == -1)
+                       rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
+                           strerror(errno));
+               if (pid) {
+                       (void)close(STDIN_FILENO);
+                       (void)close(STDOUT_FILENO);
+                       (void)close(STDERR_FILENO);
+                       (void)close(pv[1]);
+
+                       set[0].fd = s;
+                       set[0].events = POLLIN;
+                       set[1].fd = pv[0];
+                       set[1].events = POLLIN;
+                       ioctl(pv[0], FIONBIO, (char *)&one);
+
+                       /* should set s nbio! */
+                       do {
+#ifdef __minix
+                               if (set[0].events == 0 && set[1].events == 0)
+                                       break;
+#endif /* __minix */
+                               if (poll(set, 2, INFTIM) < 0)
+                                       break;
+                               if (set[0].revents & POLLIN) {
+                                       int     ret;
+
+                                       ret = read(s, &sig, 1);
+                                       if (ret <= 0)
+                                               set[0].events = 0;
+                                       else
+                                               killpg(pid, sig);
+                               }
+                               if (set[1].revents & POLLIN) {
+                                       errno = 0;
+                                       cc = read(pv[0], buf, sizeof(buf));
+                                       if (cc <= 0) {
+                                               shutdown(s, SHUT_RDWR);
+                                               set[1].events = 0;
+                                       } else {
+                                               (void)write(s, buf, cc);
+                                       }
+                               }
+
+                       } while ((set[0].revents | set[1].revents) & POLLIN);
+                       PAM_END;
+                       exit(EXIT_SUCCESS);
+               }
+               (void)close(s);
+               (void)close(pv[0]);
+               (void)dup2(pv[1], STDERR_FILENO);
+               close(pv[1]);
+       }
+#ifdef USE_PAM
+       else {
+               pid = fork();
+               if (pid == -1)
+                       rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
+                           strerror(errno));
+               if (pid) {
+                       pid_t xpid;
+                       int status;
+                       if ((xpid = waitpid(pid, &status, 0)) != pid) {
+                               pam_err = pam_close_session(pamh, 0);
+                               if (pam_err != PAM_SUCCESS) {
+                                       syslog(LOG_ERR,
+                                           "pam_close_session: %s",
+                                           pam_strerror(pamh, pam_err));
+                               }
+                               PAM_END;
+                               if (xpid != -1)
+                                       syslog(LOG_WARNING,
+                                           "wrong PID: %d != %d", pid, xpid);
+                               else
+                                       syslog(LOG_WARNING,
+                                           "wait pid=%d failed %m", pid);
+                               exit(EXIT_FAILURE);
+                       }
+                       exit(EXIT_SUCCESS);
+               }
+       }
+#endif
+
+#ifdef F_CLOSEM
+       (void)fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);
+#else
+       for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
+               (void)close(fd);
+#endif
+       if (setsid() == -1)
+               syslog(LOG_ERR, "setsid() failed: %m");
+#ifdef USE_PAM
+       if (setlogin(pwd->pw_name) < 0)
+               syslog(LOG_ERR, "setlogin() failed: %m");
+
+       if (*pwd->pw_shell == '\0')
+               pwd->pw_shell = __UNCONST(_PATH_BSHELL);
+
+       (void)pam_setenv(pamh, "HOME", pwd->pw_dir, 1);
+       (void)pam_setenv(pamh, "SHELL", pwd->pw_shell, 1);
+       (void)pam_setenv(pamh, "USER", pwd->pw_name, 1);
+       (void)pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1);
+       environ = pam_getenvlist(pamh);
+       (void)pam_end(pamh, pam_err);
+#else
+#ifdef LOGIN_CAP
+       {
+               char *sh;
+               if ((sh = login_getcapstr(lc, "shell", NULL, NULL))) {
+                       if(!(sh = strdup(sh))) {
+                               syslog(LOG_ERR, "Cannot alloc mem");
+                               exit(EXIT_FAILURE);
+                       }
+                       pwd->pw_shell = sh;
+               }
+       }
+#endif
+{
+       static char *envinit[] = { NULL };
+       environ = envinit;
+}
+       setenv("PATH", _PATH_DEFPATH, 1);
+       setenv("HOME", pwd->pw_dir, 1);
+       setenv("SHELL", pwd->pw_shell, 1);
+       setenv("USER", pwd->pw_name, 1);
+#endif
+
+       cp = strrchr(pwd->pw_shell, '/');
+       if (cp)
+               cp++;
+       else
+               cp = pwd->pw_shell;
+
+#ifdef LOGIN_CAP
+       if (setusercontext(lc, pwd, pwd->pw_uid,
+               LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
+               syslog(LOG_ERR, "setusercontext(): %m");
+               exit(EXIT_FAILURE);
+       }
+       login_close(lc);
+#else
+       (void)setgid((gid_t)pwd->pw_gid);
+       (void)setuid((uid_t)pwd->pw_uid);
+#endif
+       endpwent();
+       if (log_success || pwd->pw_uid == 0) {
+               syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
+                   remuser, hostname, locuser, cmdbuf);
+       }
+       (void)execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL);
+       rshd_errx(EXIT_FAILURE, "%s: %s", pwd->pw_shell, strerror(errno));
+badlogin:
+       syslog(LOG_INFO|LOG_AUTH,
+           "%s@%s as %s: permission denied (%s). cmd='%.80s'",
+           remuser, hostname, locuser, errormsg, cmdbuf);
+       rshd_errx(EXIT_FAILURE, errorstr, errorhost);
+}
+
+/*
+ * Report error to client.  Note: can't be used until second socket has
+ * connected to client, or older clients will hang waiting for that
+ * connection first.
+ */
+
+#include <stdarg.h>
+
+static void
+rshd_errx(int error, const char *fmt, ...)
+{
+       va_list ap;
+       int len, rv;
+       char *bp, buf[BUFSIZ];
+       va_start(ap, fmt);
+       bp = buf;
+       if (sent_null == 0) {
+               *bp++ = 1;
+               len = 1;
+       } else
+               len = 0;
+       rv = vsnprintf(bp, sizeof(buf) - 2, fmt, ap);
+       bp[rv++] = '\n';
+       (void)write(STDERR_FILENO, buf, len + rv);
+       va_end(ap);
+       exit(error);
+}
+
+static void
+getstr(char *buf, int cnt, const char *err)
+{
+       char c;
+
+       do {
+               if (read(STDIN_FILENO, &c, 1) != 1)
+                       exit(EXIT_FAILURE);
+               *buf++ = c;
+               if (--cnt == 0)
+                       rshd_errx(EXIT_FAILURE, "%s too long", err);
+       } while (c != 0);
+}
+
+/*
+ * Check whether host h is in our local domain,
+ * defined as sharing the last two components of the domain part,
+ * or the entire domain part if the local domain has only one component.
+ * If either name is unqualified (contains no '.'),
+ * assume that the host is local, as it will be
+ * interpreted as such.
+ */
+static int
+local_domain(char *h)
+{
+       char localhost[MAXHOSTNAMELEN + 1];
+       char *p1, *p2;
+
+       localhost[0] = 0;
+       (void)gethostname(localhost, sizeof(localhost));
+       localhost[sizeof(localhost) - 1] = '\0';
+       p1 = topdomain(localhost);
+       p2 = topdomain(h);
+       if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
+               return (1);
+       return (0);
+}
+
+static char *
+topdomain(char *h)
+{
+       char *p, *maybe = NULL;
+       int dots = 0;
+
+       for (p = h + strlen(h); p >= h; p--) {
+               if (*p == '.') {
+                       if (++dots == 2)
+                               return (p);
+                       maybe = p;
+               }
+       }
+       return (maybe);
+}
+
+static void
+usage(void)
+{
+
+       syslog(LOG_ERR, "Usage: %s [-%s]", getprogname(), OPTIONS);
+       exit(EXIT_FAILURE);
+}
index 55b2a8393e1f8f06ae31cdecad815f99242b4eb0..032930ae455c171364de6462aa8828307fe7879a 100644 (file)
@@ -19,9 +19,9 @@ SUBDIR=       add_route arp at backup btrace \
        nonamed \
        postinstall prep printroot \
        profile progressbar pr_routes ps pwdauth \
-       ramdisk rarpd rawspeed rcp readclock \
+       ramdisk rarpd rawspeed readclock \
        remsync rget rlogin \
-       rotate rsh rshd service setup \
+       rotate service setup \
        slip spell sprofalyze sprofdiff srccrc \
        svclog svrctl swifi synctree sysenv \
        tcpd tcpdp tcpstat telnet \
diff --git a/minix/commands/rcp/Makefile b/minix/commands/rcp/Makefile
deleted file mode 100644 (file)
index 4286e51..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-PROG=  rcp
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/minix/commands/rcp/rcp.c b/minix/commands/rcp/rcp.c
deleted file mode 100644 (file)
index 3b0318e..0000000
+++ /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 <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <utime.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include <netdb.h>
-#include <net/netlib.h>
-
-#if __STDC__
-#define PROTO(func, args)      func args
-#else
-#define PROTO(func, args)      func ()
-#endif /* __STDC__ */
-
-PROTO (int main, (int argc, char *argv[]));
-PROTO (void lostconn, (int sig));
-PROTO (void error, (char *fmt, ...) );
-PROTO (int response, (void) );
-PROTO (void source, (int argc, char *argv[]) );
-PROTO (void sink, (int argc, char *argv[]) );
-PROTO (void usage, (void) );
-PROTO (char *colon, (char *cp) );
-PROTO (int okname, (char *cp0) );
-PROTO (int susystem, (char *s) );
-PROTO (void verifydir, (char *cp) );
-PROTO (void rsource, (char *name, struct stat *statp) );
-PROTO (struct buffer *allocbuf, (struct buffer *bp, int fd, int blksize) );
-
-#define vfork  fork
-
-int    rem;
-int    errs;
-int    errno;
-int    iamremote, targetshouldbedirectory;
-int    iamrecursive;
-int    myuid;          /* uid of invoker */
-int    pflag;
-struct passwd *pwd;
-int    userid;
-int    port;
-
-struct buffer {
-       int     cnt;
-       char    *buf;
-};
-
-
-#define        ga()            (void) write(rem, "", 1)
-
-int main(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *targ, *host, *src;
-#ifndef NAMESERVER
-       char *suser, *tuser;
-#else /* NAMESERVER */
-       char *suser, *tuser, *thost;
-#endif /* NAMESERVER */
-       int i;
-       char buf[BUFSIZ], cmd[16];
-       struct servent *sp;
-
-       sp = getservbyname("shell", "tcp");
-       if (sp == NULL) {
-               fprintf(stderr, "rcp: shell/tcp: unknown service\n");
-               exit(1);
-       }
-       port = sp->s_port;
-       pwd = getpwuid(userid = getuid());
-       if (pwd == 0) {
-               fprintf(stderr, "who are you?\n");
-               exit(1);
-       }
-
-#ifdef NOT_DEF
-       /*
-        * This is a kludge to allow seteuid to user before touching
-        * files and seteuid root before doing rcmd so we can open
-        * the socket.
-        */
-       myuid = getuid();
-       if (setruid(0) < 0) {
-               perror("setruid root");
-               exit(1);
-       }
-       seteuid(myuid);
-#endif
-
-       for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
-               (*argv)++;
-               while (**argv) switch (*(*argv)++) {
-
-                   case 'r':
-                       iamrecursive++;
-                       break;
-
-                   case 'p':           /* preserve mtimes and atimes */
-                       pflag++;
-                       break;
-
-                   /* The rest of these are not for users. */
-                   case 'd':
-                       targetshouldbedirectory = 1;
-                       break;
-
-                   case 'f':           /* "from" */
-                       iamremote = 1;
-                       (void) response();
-                       source(--argc, ++argv);
-                       exit(errs);
-
-                   case 't':           /* "to" */
-                       iamremote = 1;
-                       sink(--argc, ++argv);
-                       exit(errs);
-
-                   default:
-                       usage();
-                       exit(1);
-               }
-       }
-if (iamremote)
-{
-       close(2);
-       open("/dev/tty", 2);
-}
-
-       if (argc < 2) {
-               usage();
-               exit(1);
-       }
-       rem = -1;
-       if (argc > 2)
-               targetshouldbedirectory = 1;
-       (void) sprintf(cmd, "rcp%s%s%s",
-           iamrecursive ? " -r" : "", pflag ? " -p" : "", 
-           targetshouldbedirectory ? " -d" : "");
-       (void) signal(SIGPIPE, lostconn);
-       targ = colon(argv[argc - 1]);
-       if (targ) {                             /* ... to remote */
-               *targ++ = 0;
-               if (*targ == 0)
-                       targ = ".";
-#ifndef NAMESERVER
-               tuser = strrchr(argv[argc - 1], '.');
-               if (tuser) {
-                       *tuser++ = 0;
-                       if (!okname(tuser))
-                               exit(1);
-               } else
-                       tuser = pwd->pw_name;
-#else /* NAMESERVER */
-               thost = strchr(argv[argc - 1], '@');
-               if (thost) {
-                       *thost++ = 0;
-                       tuser = argv[argc - 1];
-                       if (*tuser == '\0')
-                               tuser = pwd->pw_name;
-                       else if (!okname(tuser))
-                               exit(1);
-               } else {
-                       thost = argv[argc - 1];
-                       tuser = pwd->pw_name;
-               }
-#endif /* NAMESERVER */
-               for (i = 0; i < argc - 1; i++) {
-                       src = colon(argv[i]);
-                       if (src) {              /* remote to remote */
-                               *src++ = 0;
-                               if (*src == 0)
-                                       src = ".";
-#ifndef NAMESERVER
-                               suser = strrchr(argv[i], '.');
-                               if (suser) {
-                                       *suser++ = 0;
-                                       if (!okname(suser))
-#else /* NAMESERVER */
-                               host = strchr(argv[i], '@');
-                               if (host) {
-                                       *host++ = 0;
-                                       suser = argv[i];
-                                       if (*suser == '\0')
-                                               suser = pwd->pw_name;
-                                       else if (!okname(suser))
-#endif /* NAMESERVER */
-                                               continue;
-#ifndef NAMESERVER
-               (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s.%s:%s'",
-                                           argv[i], suser, cmd, src,
-                                           argv[argc - 1], tuser, targ);
-                               } else
-               (void) sprintf(buf, "rsh %s -n %s %s '%s.%s:%s'",
-                                           argv[i], cmd, src,
-                                           argv[argc - 1], tuser, targ);
-#else /* NAMESERVER */
-               (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s@%s:%s'",
-                                           host, suser, cmd, src,
-                                           tuser, thost, targ);
-                               } else
-               (void) sprintf(buf, "rsh %s -n %s %s '%s@%s:%s'",
-                                           argv[i], cmd, src,
-                                           tuser, thost, targ);
-#endif /* NAMESERVER */
-                               (void) susystem(buf);
-                       } else {                /* local to remote */
-                               if (rem == -1) {
-                                       (void) sprintf(buf, "%s -t %s",
-                                           cmd, targ);
-#ifndef NAMESERVER
-                                       host = argv[argc - 1];
-#else /* NAMESERVER */
-                                       host = thost;
-#endif /* NAMESERVER */
-#ifdef NOT_DEF
-                                       if (seteuid(0) < 0) {
-                                               perror("seteuid root");
-                                               exit(1);
-                                       }
-#endif
-                                       rem = rcmd(&host, port, pwd->pw_name,
-                                           tuser, buf, 0);
-#ifdef NO_DEF
-                                       seteuid(myuid);
-#endif
-                                       if (rem < 0)
-                                               exit(1);
-                                       if (response() < 0)
-                                               exit(1);
-                               }
-                               source(1, argv+i);
-                       }
-               }
-       } else {                                /* ... to local */
-               if (targetshouldbedirectory)
-                       verifydir(argv[argc - 1]);
-               for (i = 0; i < argc - 1; i++) {
-                       src = colon(argv[i]);
-                       if (src == 0) {         /* local to local */
-                               (void) sprintf(buf, "cp%s%s %s %s",
-                                   iamrecursive ? " -r" : "",
-                                   pflag ? " -p" : "",
-                                   argv[i], argv[argc - 1]);
-                               (void) susystem(buf);
-                       } else {                /* remote to local */
-                               *src++ = 0;
-                               if (*src == 0)
-                                       src = ".";
-#ifndef NAMESERVER
-                               suser = strrchr(argv[i], '.');
-                               if (suser) {
-                                       *suser++ = 0;
-                                       if (!okname(suser))
-#else /* NAMESERVER */
-                               host = strchr(argv[i], '@');
-                               if (host) {
-                                       *host++ = 0;
-                                       suser = argv[i];
-                                       if (*suser == '\0')
-                                               suser = pwd->pw_name;
-                                       else if (!okname(suser))
-#endif /* NAMESERVER */
-                                               continue;
-#ifndef NAMESERVER
-                               } else
-#else /* NAMESERVER */
-                               } else {
-                                       host = argv[i];
-#endif /* NAMESERVER */
-                                       suser = pwd->pw_name;
-#ifdef NAMESERVER
-                               }
-#endif /* NAMESERVER */
-                               (void) sprintf(buf, "%s -f %s", cmd, src);
-#ifndef NAMESERVER
-                               host = argv[i];
-#endif /* NAMESERVER */
-#ifdef NOT_DEF
-                               if (seteuid(0) < 0) {
-                                       perror("seteuid root");
-                                       exit(1);
-                               }
-#endif
-                               rem = rcmd(&host, port, pwd->pw_name, suser,
-                                   buf, 0);
-#ifdef NOT_DEF
-                               seteuid(myuid);
-#endif
-                               if (rem < 0) {
-                                       errs++;
-                                       continue;
-                               }
-                               sink(1, argv+argc-1);
-                               (void) close(rem);
-                               rem = -1;
-                       }
-               }
-       }
-       exit(errs);
-}
-
-void
-verifydir(cp)
-       char *cp;
-{
-       struct stat stb;
-
-       if (stat(cp, &stb) >= 0) {
-               if ((stb.st_mode & S_IFMT) == S_IFDIR)
-                       return;
-               errno = ENOTDIR;
-       }
-       error("rcp: %s: %s.\n", cp, strerror(errno));
-       exit(1);
-}
-
-char *
-colon(cp)
-       char *cp;
-{
-
-       while (*cp) {
-               if (*cp == ':')
-                       return (cp);
-               if (*cp == '/')
-                       return (0);
-               cp++;
-       }
-       return (0);
-}
-
-
-int
-okname(cp0)
-       char *cp0;
-{
-       register char *cp = cp0;
-       register int c;
-
-       do {
-               c = *cp;
-               if (c & 0200)
-                       goto bad;
-               if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
-                       goto bad;
-               cp++;
-       } while (*cp);
-       return (1);
-bad:
-       fprintf(stderr, "rcp: invalid user name %s\n", cp0);
-       return (0);
-}
-
-int
-susystem(s)
-       char *s;
-{
-       int status, pid, w;
-       register void PROTO ((*istat), (int) ), PROTO ((*qstat), (int) );
-
-       if ((pid = vfork()) == 0) {
-#ifdef NOT_DEF
-               (void) setruid(myuid);
-#endif
-               execl("/bin/sh", "sh", "-c", s, (char *)0);
-               _exit(127);
-       }
-       istat = signal(SIGINT, SIG_IGN);
-       qstat = signal(SIGQUIT, SIG_IGN);
-       while ((w = wait(&status)) != pid && w != -1)
-               ;
-       if (w == -1)
-               status = -1;
-       (void) signal(SIGINT, istat);
-       (void) signal(SIGQUIT, qstat);
-       return (status);
-}
-
-void
-source(argc, argv)
-       int argc;
-       char **argv;
-{
-       char *last, *name;
-       struct stat stb;
-       static struct buffer buffer;
-       struct buffer *bp;
-       int x, sizerr, f, amt;
-       off_t i;
-       char buf[BUFSIZ];
-
-       for (x = 0; x < argc; x++) {
-               name = argv[x];
-               if ((f = open(name, 0)) < 0) {
-                       error("rcp: %s: %s\n", name, strerror(errno));
-                       continue;
-               }
-               if (fstat(f, &stb) < 0)
-                       goto notreg;
-               switch (stb.st_mode&S_IFMT) {
-
-               case S_IFREG:
-                       break;
-
-               case S_IFDIR:
-                       if (iamrecursive) {
-                               (void) close(f);
-                               rsource(name, &stb);
-                               continue;
-                       }
-                       /* fall into ... */
-               default:
-notreg:
-                       (void) close(f);
-                       error("rcp: %s: not a plain file\n", name);
-                       continue;
-               }
-               last = strrchr(name, '/');
-               if (last == 0)
-                       last = name;
-               else
-                       last++;
-               if (pflag) {
-                       /*
-                        * Make it compatible with possible future
-                        * versions expecting microseconds.
-                        */
-                       (void) sprintf(buf, "T%d 0 %d 0\n",
-                           stb.st_mtime, stb.st_atime);
-                       (void) write(rem, buf, strlen(buf));
-                       if (response() < 0) {
-                               (void) close(f);
-                               continue;
-                       }
-               }
-               (void) sprintf(buf, "C%04o %lld %s\n",
-                   stb.st_mode&07777, stb.st_size, last);
-               (void) write(rem, buf, strlen(buf));
-               if (response() < 0) {
-                       (void) close(f);
-                       continue;
-               }
-               if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
-                       (void) close(f);
-                       continue;
-               }
-               sizerr = 0;
-               for (i = 0; i < stb.st_size; i += bp->cnt) {
-                       amt = bp->cnt;
-                       if (i + amt > stb.st_size)
-                               amt = stb.st_size - i;
-                       if (sizerr == 0 && read(f, bp->buf, amt) != amt)
-                               sizerr = 1;
-                       (void) write(rem, bp->buf, amt);
-               }
-               (void) close(f);
-               if (sizerr == 0)
-                       ga();
-               else
-                       error("rcp: %s: file changed size\n", name);
-               (void) response();
-       }
-}
-
-
-void
-rsource(name, statp)
-       char *name;
-       struct stat *statp;
-{
-       DIR *d = opendir(name);
-       char *last;
-       struct dirent *dp;
-       char buf[BUFSIZ];
-       char *bufv[1];
-
-       if (d == 0) {
-               error("rcp: %s: %s\n", name, strerror(errno));
-               return;
-       }
-       last = strrchr(name, '/');
-       if (last == 0)
-               last = name;
-       else
-               last++;
-       if (pflag) {
-               (void) sprintf(buf, "T%d 0 %d 0\n",
-                   statp->st_mtime, statp->st_atime);
-               (void) write(rem, buf, strlen(buf));
-               if (response() < 0) {
-                       closedir(d);
-                       return;
-               }
-       }
-       (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
-       (void) write(rem, buf, strlen(buf));
-       if (response() < 0) {
-               closedir(d);
-               return;
-       }
-       while ((dp = readdir(d))) {
-               if (dp->d_ino == 0)
-                       continue;
-               if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
-                       continue;
-               if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
-                       error("%s/%s: Name too long.\n", name, dp->d_name);
-                       continue;
-               }
-               (void) sprintf(buf, "%s/%s", name, dp->d_name);
-               bufv[0] = buf;
-               source(1, bufv);
-       }
-       closedir(d);
-       (void) write(rem, "E\n", 2);
-       (void) response();
-}
-
-int
-response()
-{
-       char resp, c, rbuf[BUFSIZ], *cp = rbuf;
-
-       if (read(rem, &resp, 1) != 1)
-               lostconn(0);
-       switch (resp) {
-
-       case 0:                         /* ok */
-               return (0);
-
-       default:
-               *cp++ = resp;
-               /* fall into... */
-       case 1:                         /* error, followed by err msg */
-       case 2:                         /* fatal error, "" */
-               do {
-                       if (read(rem, &c, 1) != 1)
-                               lostconn(0);
-                       *cp++ = c;
-               } while (cp < &rbuf[BUFSIZ] && c != '\n');
-               if (iamremote == 0)
-                       (void) write(2, rbuf, cp - rbuf);
-               errs++;
-               if (resp == 1)
-                       return (-1);
-               exit(1);
-       }
-       /*NOTREACHED*/
-}
-
-void
-lostconn(sig)
-int sig;
-{
-
-       if (iamremote == 0)
-               fprintf(stderr, "rcp: lost connection\n");
-       exit(1);
-}
-
-void
-sink(argc, argv)
-       int argc;
-       char **argv;
-{
-       off_t i, j, size;
-       char *targ, *whopp, *cp;
-       int of, mode, wrerr, exists, first, count, amt;
-       struct buffer *bp;
-       static struct buffer buffer;
-       struct stat stb;
-       int targisdir = 0;
-       int mask = umask(0);
-       char *myargv[1];
-       char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
-       int setimes = 0;
-       struct utimbuf utimbuf;
-#define atime  utimbuf.actime
-#define mtime  utimbuf.modtime
-       time_t dummy;
-#define        SCREWUP(str)    { whopp = str; goto screwup; }
-
-#ifdef NOT_DEF
-       seteuid(pwd->pw_uid);
-#endif
-       if (!pflag)
-               (void) umask(mask);
-       if (argc != 1) {
-               error("rcp: ambiguous target\n");
-               exit(1);
-       }
-       targ = *argv;
-       if (targetshouldbedirectory)
-               verifydir(targ);
-       ga();
-       if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
-               targisdir = 1;
-       for (first = 1; ; first = 0) {
-               cp = cmdbuf;
-               if (read(rem, cp, 1) <= 0)
-                       return;
-               if (*cp++ == '\n')
-                       SCREWUP("unexpected '\\n'");
-               do {
-                       if (read(rem, cp, 1) != 1)
-                               SCREWUP("lost connection");
-               } while (*cp++ != '\n');
-               *cp = 0;
-               if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
-                       if (iamremote == 0)
-                               (void) write(2, cmdbuf+1, strlen(cmdbuf+1));
-                       if (cmdbuf[0] == '\02')
-                               exit(1);
-                       errs++;
-                       continue;
-               }
-               *--cp = 0;
-               cp = cmdbuf;
-               if (*cp == 'E') {
-                       ga();
-                       return;
-               }
-
-#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
-               if (*cp == 'T') {
-                       setimes++;
-                       cp++;
-                       getnum(mtime);
-                       if (*cp++ != ' ')
-                               SCREWUP("mtime.sec not delimited");
-                       getnum(dummy);
-                       if (*cp++ != ' ')
-                               SCREWUP("mtime.usec not delimited");
-                       getnum(atime);
-                       if (*cp++ != ' ')
-                               SCREWUP("atime.sec not delimited");
-                       getnum(dummy);
-                       if (*cp++ != '\0')
-                               SCREWUP("atime.usec not delimited");
-                       ga();
-                       continue;
-               }
-               if (*cp != 'C' && *cp != 'D') {
-                       /*
-                        * Check for the case "rcp remote:foo\* local:bar".
-                        * In this case, the line "No match." can be returned
-                        * by the shell before the rcp command on the remote is
-                        * executed so the ^Aerror_message convention isn't
-                        * followed.
-                        */
-                       if (first) {
-                               error("%s\n", cp);
-                               exit(1);
-                       }
-                       SCREWUP("expected control record");
-               }
-               cp++;
-               mode = 0;
-               for (; cp < cmdbuf+5; cp++) {
-                       if (*cp < '0' || *cp > '7')
-                               SCREWUP("bad mode");
-                       mode = (mode << 3) | (*cp - '0');
-               }
-               if (*cp++ != ' ')
-                       SCREWUP("mode not delimited");
-               size = 0;
-               while (isdigit(*cp))
-                       size = size * 10 + (*cp++ - '0');
-               if (*cp++ != ' ')
-                       SCREWUP("size not delimited");
-               if (targisdir)
-                       (void) sprintf(nambuf, "%s%s%s", targ,
-                           *targ ? "/" : "", cp);
-               else
-                       (void) strcpy(nambuf, targ);
-               exists = stat(nambuf, &stb) == 0;
-               if (cmdbuf[0] == 'D') {
-                       if (exists) {
-                               if ((stb.st_mode&S_IFMT) != S_IFDIR) {
-                                       errno = ENOTDIR;
-                                       goto bad;
-                               }
-                               if (pflag)
-                                       (void) chmod(nambuf, mode);
-                       } else if (mkdir(nambuf, mode) < 0)
-                               goto bad;
-                       myargv[0] = nambuf;
-                       sink(1, myargv);
-                       if (setimes) {
-                               setimes = 0;
-                               if (utime(nambuf, &utimbuf) < 0)
-                                       error("rcp: can't set times on %s: %s\n",
-                                           nambuf, strerror(errno));
-                       }
-                       continue;
-               }
-               if ((of = creat(nambuf, mode)) < 0) {
-       bad:
-                       error("rcp: %s: %s\n", nambuf, strerror(errno));
-                       continue;
-               }
-               if (exists && pflag)
-                       (void) chmod(nambuf, mode);
-               ga();
-               if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) {
-                       (void) close(of);
-                       continue;
-               }
-               cp = bp->buf;
-               count = 0;
-               wrerr = 0;
-               for (i = 0; i < size; i += BUFSIZ) {
-                       amt = BUFSIZ;
-                       if (i + amt > size)
-                               amt = size - i;
-                       count += amt;
-                       do {
-                               j = read(rem, cp, amt);
-                               if (j <= 0)
-                                       exit(1);
-                               amt -= j;
-                               cp += j;
-                       } while (amt > 0);
-                       if (count == bp->cnt) {
-                               if (wrerr == 0 &&
-                                   write(of, bp->buf, count) != count)
-                                       wrerr++;
-                               count = 0;
-                               cp = bp->buf;
-                       }
-               }
-               if (count != 0 && wrerr == 0 &&
-                   write(of, bp->buf, count) != count)
-                       wrerr++;
-               (void) close(of);
-               (void) response();
-               if (setimes) {
-                       setimes = 0;
-                       if (utime(nambuf, &utimbuf) < 0)
-                               error("rcp: can't set times on %s: %s\n",
-                                   nambuf, strerror(errno));
-               }                                  
-               if (wrerr)
-                       error("rcp: %s: %s\n", nambuf, strerror(errno));
-               else
-                       ga();
-       }
-screwup:
-       error("rcp: protocol screwup: %s\n", whopp);
-       exit(1);
-}
-
-struct buffer *
-allocbuf(bp, fd, blksize)
-       struct buffer *bp;
-       int fd, blksize;
-{
-       struct stat stb;
-       int size;
-
-       if (fstat(fd, &stb) < 0) {
-               error("rcp: fstat: %s\n", strerror(errno));
-               return ((struct buffer *)0);
-       }
-       size= 0;
-#if NOT_DEF
-       size = roundup(stb.st_blksize, blksize);
-#endif
-       if (size == 0)
-               size = blksize;
-       if (bp->cnt < size) {
-               if (bp->buf != 0)
-                       free(bp->buf);
-               bp->buf = (char *)malloc((unsigned) size);
-               if (bp->buf == 0) {
-                       error("rcp: malloc: out of memory\n");
-                       return ((struct buffer *)0);
-               }
-       }
-       bp->cnt = size;
-       return (bp);
-}
-
-/*VARARGS1*/
-#if __STDC__
-void
-error (char *fmt, ...)
-#else
-error(fmt)
-char *fmt;
-#endif
-{
-       char buf[BUFSIZ], *cp = buf;
-       va_list ap;
-
-       va_start(ap, fmt);
-
-       errs++;
-       *cp++ = 1;
-       (void) vsprintf(cp, fmt, ap);
-       va_end(ap);
-       (void) write(rem, buf, strlen(buf));
-       if (iamremote == 0)
-               (void) write(2, buf+1, strlen(buf+1));
-}
-
-void
-usage()
-{
-       fprintf(stderr, "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n");
-}
diff --git a/minix/commands/rsh/Makefile b/minix/commands/rsh/Makefile
deleted file mode 100644 (file)
index cfcddfa..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-PROG=  rsh
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/minix/commands/rsh/rsh.c b/minix/commands/rsh/rsh.c
deleted file mode 100644 (file)
index 230068c..0000000
+++ /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 <sys/types.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <net/netlib.h>
-#include <netdb.h>
-int main( int argc, char *argv[] );
-void usage( void );
-char *copyargs( char **argv );
-void sendsig( int signo );
-void talk( int nflag, long omask, int pid, int rem );
-
-#define _PATH_RLOGIN1  "/bin/rlogin"
-#define _PATH_RLOGIN2  "/usr/bin/rlogin"
-
-#else
-#include <sys/types.h>
-#include <sys/signal.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/file.h>
-
-#include <netinet/in.h>
-#include <netdb.h>
-
-#include <pwd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <varargs.h>
-#include "pathnames.h"
-#endif
-
-#ifdef KERBEROS
-#include <kerberosIV/des.h>
-#include <kerberosIV/krb.h>
-
-CREDENTIALS cred;
-Key_schedule schedule;
-int use_kerberos = 1, doencrypt;
-char dst_realm_buf[REALM_SZ], *dest_realm;
-extern char *krb_realmofhost();
-#endif
-
-/*
- * rsh - remote shell
- */
-extern int errno;
-int rfd2;
-
-int
-main(argc, argv)
-       int argc;
-       char **argv;
-{
-       extern char *optarg;
-       extern int optind;
-       struct passwd *pw;
-       struct servent *sp;
-       long omask;
-       int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
-       register char *p;
-       char *args, *host, *user;
-#if !defined(__minix)
-       char *copyargs();
-       void sendsig();
-#endif
-
-       argoff = asrsh = dflag = nflag = 0;
-       one = 1;
-       host = user = NULL;
-
-       /* if called as something other than "rsh", use it as the host name */
-       if ((p = rindex(argv[0], '/')))
-               ++p;
-       else
-               p = argv[0];
-       if (strcmp(p, "rsh"))
-               host = p;
-       else
-               asrsh = 1;
-
-       /* handle "rsh host flags" */
-       if (!host && argc > 2 && argv[1][0] != '-') {
-               host = argv[1];
-               argoff = 1;
-       }
-
-#ifdef KERBEROS
-#ifdef CRYPT
-#define        OPTIONS "8KLdek:l:nwx"
-#else
-#define        OPTIONS "8KLdek:l:nw"
-#endif
-#else
-#define        OPTIONS "8KLdel:nw"
-#endif
-       while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
-               switch(ch) {
-               case 'K':
-#ifdef KERBEROS
-                       use_kerberos = 0;
-#endif
-                       break;
-               case 'L':       /* -8Lew are ignored to allow rlogin aliases */
-               case 'e':
-               case 'w':
-               case '8':
-                       break;
-               case 'd':
-                       dflag = 1;
-                       break;
-               case 'l':
-                       user = optarg;
-                       break;
-#ifdef KERBEROS
-               case 'k':
-                       dest_realm = dst_realm_buf;
-                       strncpy(dest_realm, optarg, REALM_SZ);
-                       break;
-#endif
-               case 'n':
-                       nflag = 1;
-                       break;
-#ifdef KERBEROS
-#ifdef CRYPT
-               case 'x':
-                       doencrypt = 1;
-                       des_set_key(cred.session, schedule);
-                       break;
-#endif
-#endif
-               case '?':
-               default:
-                       usage();
-               }
-       optind += argoff;
-
-       /* if haven't gotten a host yet, do so */
-       if (!host && !(host = argv[optind++]))
-               usage();
-
-       /* if no further arguments, must have been called as rlogin. */
-       if (!argv[optind]) {
-               if (asrsh)
-                       *argv = "rlogin";
-               execv(_PATH_RLOGIN1, argv);
-               execv(_PATH_RLOGIN2, argv);
-               (void)fprintf(stderr, "rsh: can't exec rlogin\n");
-               exit(1);
-       }
-
-       argc -= optind;
-       argv += optind;
-
-       if (!(pw = getpwuid(uid = getuid()))) {
-               (void)fprintf(stderr, "rsh: unknown user id.\n");
-               exit(1);
-       }
-       if (!user)
-               user = pw->pw_name;
-
-#ifdef KERBEROS
-#ifdef CRYPT
-       /* -x turns off -n */
-       if (doencrypt)
-               nflag = 0;
-#endif
-#endif
-
-       args = copyargs(argv);
-
-       sp = NULL;
-#ifdef KERBEROS
-       if (use_kerberos) {
-               sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
-               if (sp == NULL) {
-                       use_kerberos = 0;
-                       warning("can't get entry for %s/tcp service",
-                           doencrypt ? "ekshell" : "kshell");
-               }
-       }
-#endif
-       if (sp == NULL)
-               sp = getservbyname("shell", "tcp");
-       if (sp == NULL) {
-               (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
-               exit(1);
-       }
-
-#ifdef KERBEROS
-try_connect:
-       if (use_kerberos) {
-               rem = KSUCCESS;
-               errno = 0;
-               if (dest_realm == NULL)
-                       dest_realm = krb_realmofhost(host);
-
-#ifdef CRYPT
-               if (doencrypt)
-                       rem = krcmd_mutual(&host, sp->s_port, user, args,
-                           &rfd2, dest_realm, &cred, schedule);
-               else
-#endif
-                       rem = krcmd(&host, sp->s_port, user, args, &rfd2,
-                           dest_realm);
-               if (rem < 0) {
-                       use_kerberos = 0;
-                       sp = getservbyname("shell", "tcp");
-                       if (sp == NULL) {
-                               (void)fprintf(stderr,
-                                   "rsh: unknown service shell/tcp.\n");
-                               exit(1);
-                       }
-                       if (errno == ECONNREFUSED)
-                               warning("remote host doesn't support Kerberos");
-                       if (errno == ENOENT)
-                               warning("can't provide Kerberos auth data");
-                       goto try_connect;
-               }
-       } else {
-               if (doencrypt) {
-                       (void)fprintf(stderr,
-                           "rsh: the -x flag requires Kerberos authentication.\n");
-                       exit(1);
-               }
-               rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
-       }
-#else
-       rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
-#endif
-
-       if (rem < 0)
-               exit(1);
-
-       if (rfd2 < 0) {
-               (void)fprintf(stderr, "rsh: can't establish stderr.\n");
-               exit(1);
-       }
-#if !defined(__minix)
-       if (dflag) {
-               if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
-                   sizeof(one)) < 0)
-                       (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
-                           strerror(errno));
-               if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
-                   sizeof(one)) < 0)
-                       (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
-                           strerror(errno));
-       }
-#endif
-
-       (void)setuid(uid);
-#if !defined(__minix)
-       omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
-#endif
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
-               (void)signal(SIGINT, sendsig);
-       if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
-               (void)signal(SIGQUIT, sendsig);
-       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
-               (void)signal(SIGTERM, sendsig);
-
-       if (!nflag) {
-               pid = fork();
-               if (pid < 0) {
-                       (void)fprintf(stderr,
-                           "rsh: fork: %s.\n", strerror(errno));
-                       exit(1);
-               }
-       }
-
-#ifdef KERBEROS
-#ifdef CRYPT
-       if (!doencrypt)
-#endif
-#endif
-       {
-#if defined(__minix)
-               ;
-#else
-               (void)ioctl(rfd2, FIONBIO, &one);
-               (void)ioctl(rem, FIONBIO, &one);
-#endif
-       }
-
-       talk(nflag, omask, pid, rem);
-
-       if (!nflag && pid)
-       {
-#if DEBUG
-               printf("killing %d with %d\n", pid, SIGKILL);
-#endif
-               (void)kill(pid, SIGKILL);
-       }
-       exit(0);
-}
-
-void
-talk(nflag, omask, pid, rem)
-       int nflag, pid;
-       long omask;
-       register int rem;
-{
-       register int cc, wc;
-       register char *bp;
-#if !defined(__minix)
-       int readfrom, ready, rembits;
-#endif
-       char buf[BUFSIZ];
-#if defined(__minix)
-       int pid1;
-#endif
-
-       if (!nflag && pid == 0) {
-               (void)close(rfd2);
-
-reread:                errno = 0;
-               if ((cc = read(0, buf, sizeof buf)) <= 0)
-                       goto done;
-               bp = buf;
-
-rewrite:
-#if !defined(__minix)
-               rembits = 1 << rem;
-               if (select(16, 0, &rembits, 0, 0) < 0) {
-                       if (errno != EINTR) {
-                               (void)fprintf(stderr,
-                                   "rsh: select: %s.\n", strerror(errno));
-                               exit(1);
-                       }
-                       goto rewrite;
-               }
-               if ((rembits & (1 << rem)) == 0)
-                       goto rewrite;
-#endif
-#ifdef KERBEROS
-#ifdef CRYPT
-               if (doencrypt)
-                       wc = des_write(rem, bp, cc);
-               else
-#endif
-#endif
-                       wc = write(rem, bp, cc);
-               if (wc < 0) {
-#if !defined(__minix)
-                       if (errno == EWOULDBLOCK)
-                               goto rewrite;
-#endif
-                       goto done;
-               }
-               bp += wc;
-               cc -= wc;
-               if (cc == 0)
-                       goto reread;
-               goto rewrite;
-done:
-#if defined(__minix)
-               ioctl(rem, NWIOTCPSHUTDOWN, NULL);
-#else
-               (void)shutdown(rem, 1);
-#endif
-               exit(0);
-       }
-
-#if defined(__minix)
-       pid1= fork();
-       if (pid1 == -1)
-       {
-               (void)fprintf(stderr, "rsh: fork: %s.\n", strerror(errno));
-               exit(1);
-       }
-       close (pid1 ? rfd2 : rem);
-       for(;;)
-       {
-               errno = 0;
-               cc = read(pid1 ? rem : rfd2, buf, sizeof buf);
-               if (cc <= 0)
-               {
-                       if (pid1)
-                       {
-#if DEBUG
-                               printf("killing %d with %d\n", pid1, SIGKILL);
-#endif
-                               kill(pid1, SIGKILL);
-                               return;
-                       }
-                       exit(0);
-               }
-               (void)write(pid1 ? 1 : 2, buf, cc);
-       }
-#else
-       (void)sigsetmask(omask);
-       readfrom = (1 << rfd2) | (1 << rem);
-       do {
-               ready = readfrom;
-               if (select(16, &ready, 0, 0, 0) < 0) {
-                       if (errno != EINTR) {
-                               (void)fprintf(stderr,
-                                   "rsh: select: %s.\n", strerror(errno));
-                               exit(1);
-                       }
-                       continue;
-               }
-               if (ready & (1 << rfd2)) {
-                       errno = 0;
-#ifdef KERBEROS
-#ifdef CRYPT
-                       if (doencrypt)
-                               cc = des_read(rfd2, buf, sizeof buf);
-                       else
-#endif
-#endif
-                               cc = read(rfd2, buf, sizeof buf);
-                       if (cc <= 0) {
-                               if (errno != EWOULDBLOCK)
-                                       readfrom &= ~(1 << rfd2);
-                       } else
-                               (void)write(2, buf, cc);
-               }
-               if (ready & (1 << rem)) {
-                       errno = 0;
-#ifdef KERBEROS
-#ifdef CRYPT
-                       if (doencrypt)
-                               cc = des_read(rem, buf, sizeof buf);
-                       else
-#endif
-#endif
-                               cc = read(rem, buf, sizeof buf);
-                       if (cc <= 0) {
-                               if (errno != EWOULDBLOCK)
-                                       readfrom &= ~(1 << rem);
-                       } else
-                               (void)write(1, buf, cc);
-               }
-       } while (readfrom);
-#endif
-}
-
-void
-sendsig(signo)
-       char signo;
-{
-#ifdef KERBEROS
-#ifdef CRYPT
-       if (doencrypt)
-               (void)des_write(rfd2, &signo, 1);
-       else
-#endif
-#endif
-               (void)write(rfd2, &signo, 1);
-}
-
-#ifdef KERBEROS
-/* VARARGS */
-warning(va_alist)
-va_dcl
-{
-       va_list ap;
-       char *fmt;
-
-       (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       (void)fprintf(stderr, ".\n");
-}
-#endif
-
-char *
-copyargs(argv)
-       char **argv;
-{
-       register int cc;
-       register char **ap, *p;
-       char *args;
-#if !defined(__minix)
-       char *malloc();
-#endif
-
-       cc = 0;
-       for (ap = argv; *ap; ++ap)
-               cc += strlen(*ap) + 1;
-       if (!(args = malloc((u_int)cc))) {
-               (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
-               exit(1);
-       }
-       for (p = args, ap = argv; *ap; ++ap) {
-               (void)strcpy(p, *ap);
-               for (p = strcpy(p, *ap); *p; ++p);
-               if (ap[1])
-                       *p++ = ' ';
-       }
-       return(args);
-}
-
-void
-usage()
-{
-       (void)fprintf(stderr,
-           "usage: rsh [-nd%s]%s[-l login] host [command]\n",
-#ifdef KERBEROS
-#ifdef CRYPT
-           "x", " [-k realm] ");
-#else
-           "", " [-k realm] ");
-#endif
-#else
-           "", " ");
-#endif
-       exit(1);
-}
diff --git a/minix/commands/rshd/Makefile b/minix/commands/rshd/Makefile
deleted file mode 100644 (file)
index cb47a3d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-PROG=  in.rshd
-SRCS=  rshd.c
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/minix/commands/rshd/rshd.c b/minix/commands/rshd/rshd.c
deleted file mode 100644 (file)
index cc2bdde..0000000
+++ /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 <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <pwd.h>
-#include <grp.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <net/gen/in.h>
-#include <net/gen/inet.h>
-#include <netdb.h>
-#include <net/gen/socket.h>
-#include <net/gen/tcp.h>
-#include <net/gen/tcp_io.h>
-#include <net/hton.h>
-#include <net/netlib.h>
-
-#define DEBUG 0
-
-#if DEBUG
-#define where() fprintf(stderr, "%s, %d: ", __FILE__, __LINE__)
-#endif
-
-char cmdbuf[_POSIX_ARG_MAX+1], locuser[16], remuser[16];
-extern char **environ;
-char username[20]="USER=";
-char homedir[64]="HOME=";
-char shell[64]="SHELL=";
-char tz[1024]="TZ=";
-char *envinit[]= {homedir, shell, username, tz, "PATH=:/bin:/usr/bin", 0};
-char *prog_name;
-char buffer[PIPE_BUF];
-
-#if __STDC__
-#define PROTO(func, args) func args
-#else
-#define PROTO(func, args) func ()
-#endif
-
-PROTO (int main, (int argc, char *argv[]));
-PROTO (void getstr, (char*buf, int cnt, char *err));
-PROTO (void close_on_exec, (int fd));
-
-int main(argc, argv)
-int argc;
-char *argv[];
-{
-       int result, result1;
-       nwio_tcpconf_t tcpconf, err_tcpconf;
-       nwio_tcpcl_t tcpconnopt;
-       nwio_tcpatt_t tcpattachopt;
-       tcpport_t tcpport;
-       tcpport_t err_port;
-       int err_fd, pds[2];
-       pid_t pid, pid1, new_pg;
-#if USEATTACH
-       int err2_fd;
-#endif
-       struct passwd *pwent;
-       char *cp, *buff_ptr, *TZ;
-       char sig;
-
-       prog_name= argv[0];
-       if (argc != 1)
-       {
-               fprintf(stderr, "%s: wrong number of arguments (%d)\n",
-                       prog_name, argc);
-               exit(1);
-       }
-
-       signal(SIGINT, SIG_DFL);
-       signal(SIGQUIT, SIG_DFL);
-       signal(SIGTERM, SIG_DFL);
-
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-       result= ioctl (0, NWIOGTCPCONF, &tcpconf);
-       if (result<0)
-       {
-               fprintf(stderr, "%s: ioctl(NWIOGTCPCONF)= %d : %s\n", 
-                       prog_name, errno, strerror(errno));
-               exit(1);
-       }
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-
-       tcpport= ntohs(tcpconf.nwtc_remport);
-       if (tcpport >= TCPPORT_RESERVED || tcpport < TCPPORT_RESERVED/2)
-       {
-               printf("\1%s: unprotected port (%d)\n", prog_name, tcpport);
-               exit(1);
-       }
-       alarm(60);
-       err_port= 0;
-       for (;;)
-       {
-               char c;
-               result= read(0, &c, 1);
-               if (result <0)
-               {
-                       fprintf(stderr, "%s: read= %d : %s\n", prog_name, 
-                               errno, strerror(errno));
-               }
-               if (result<1)
-                       exit(1);
-               if (c == 0)
-                       break;
-               err_port= err_port*10 + c - '0';
-       }
-       alarm(0);
-       if (err_port != 0)
-       {
-               int n, pid, lport;
-
-               pid= getpid();
-               lport= 1;
-               do {
-                       lport= (lport << 1) | (pid & 1);
-                       pid >>= 1;
-               } while (lport < TCPPORT_RESERVED/2);
-
-               n= TCPPORT_RESERVED/2;
-               do
-               {
-                       if (--lport < TCPPORT_RESERVED/2)
-                               lport= TCPPORT_RESERVED-1;
-                       err_fd= open ("/dev/tcp", O_RDWR);
-                       if (err_fd<0)
-                       {
-                               fprintf(stderr, "%s: open= %d : %s\n", 
-                                       prog_name, errno, strerror(errno));
-                               exit(1);
-                       }
-                       close_on_exec(err_fd);
-                       err_tcpconf.nwtc_flags= NWTC_LP_SET | NWTC_SET_RA |
-                               NWTC_SET_RP | NWTC_EXCL;
-                       err_tcpconf.nwtc_locport= htons(lport);
-                       err_tcpconf.nwtc_remport= htons(err_port);
-                       err_tcpconf.nwtc_remaddr= tcpconf.nwtc_remaddr;
-
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-                       result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
-                       if (result == 0) break;
-                       if (errno != EADDRINUSE)
-                       {
-                               fprintf(stderr, 
-                                       "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
-                                       prog_name, errno, strerror(errno));
-                               exit(1);
-                       }
-                       close(err_fd);
-               } while (--n > 0);
-               if (n == 0)
-               {
-                       printf("\1can't get stderr port\n");
-                       exit(1);
-               }
-
-               err_tcpconf.nwtc_flags= NWTC_SHARED;
-#if DEBUG
-{ where(); fprintf(stderr, "\n"); }
-#endif
-               result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
-               if (result<0)
-               {
-                       fprintf(stderr, 
-                               "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
-                               prog_name, errno, strerror(errno));
-                       exit(1);
-               }
-#if DEBUG
-{ where(); fprintf(stderr, "\n"); }
-#endif
-               tcpconnopt.nwtcl_flags= 0;
-
-               n= 20;
-               for (;;)
-               {
-#if DEBUG
-{ where(); fprintf(stderr, "\n"); }
-#endif
-                       result= ioctl (err_fd, NWIOTCPCONN, &tcpconnopt);
-                       if (result == 0) break;
-                       if (errno != EAGAIN && errno != ECONNREFUSED)
-                       {
-                               fprintf(stderr,
-                                       "%s: ioctl(NWIOTCPCONN)= %d : %s\n",
-                                       prog_name, errno, strerror(errno));
-                               exit(1);
-                       }
-                       if (--n == 0) break;
-                       sleep(1);
-#if DEBUG
-{ where(); fprintf(stderr, "\n"); }
-#endif
-               }
-#if USEATTACH
-               err2_fd= open ("/dev/tcp", O_RDWR);
-               close_on_exec(err2_fd);
-               if (err2_fd<0)
-               {
-                       fprintf(stderr, "%s: open= %d : %s\n", errno,
-                               prog_name, strerror(errno));
-                       exit(1);
-               }
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-               result= ioctl (err2_fd, NWIOSTCPCONF, &err_tcpconf);
-               if (result<0)
-               {
-                       fprintf(stderr, "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
-                               prog_name, errno, strerror(errno));
-                       exit(1);
-               }
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-               tcpattachopt.nwta_flags= 0;
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-               result= ioctl (err2_fd, NWIOTCPATTACH, &tcpattachopt);
-               if (result<0)
-               {
-                       fprintf(stderr, "%s: ioctl(NWIOTCPATTACH)= %d : %s\n",
-                               prog_name, errno, strerror(errno));
-                       exit(1);
-               }
-#if DEBUG
- { where(); fprintf(stderr, "\n"); }
-#endif
-#endif
-       }
-       getstr(remuser, sizeof(remuser), "remuser");
-       getstr(locuser, sizeof(locuser), "locuser");
-       getstr(cmdbuf, sizeof(cmdbuf), "cmdbuf");
-       setpwent();
-       pwent= getpwnam(locuser);
-       if (!pwent)
-       {
-               printf("\1Login incorrect.\n");
-               exit(1);
-       }
-       endpwent();
-       if (chdir(pwent->pw_dir) < 0)
-       {
-               chdir("/");
-       }
-#if DEBUG
- { where(); fprintf(stderr, "calling iruserok(%s, %d, %s, %s)\n", 
-       inet_ntoa(tcpconf.nwtc_remaddr), 0, remuser, locuser); }
-#endif
-       if (iruserok(tcpconf.nwtc_remaddr, 0, remuser, locuser) < 0)
-       {
-               printf("\1Permission denied.\n");
-               exit(1);
-       }
-       if (err_port)
-       {
-               /* Let's go to a different process group. */
-               new_pg= setsid();
-               pid= fork();
-               if (pid<0)
-               {
-                       if (errno != EAGAIN)
-                       {
-                               fprintf(stderr, "%s: fork()= %d : %s\n",
-                                       prog_name, errno, strerror(errno));
-                       }
-                       printf("\1Try again.\n");
-                       exit(1);
-               }
-               if (pid)
-               {
-                       close(0);       /* stdin */
-                       close(1);       /* stdout */
-#if USEATTACH
-                       close(err_fd);  /* stderr for shell */
-#endif
-                       dup2(2,0);
-                       dup2(2,1);
-                       for (;;)
-                       {
-#if !USEATTACH
-                               if (read(err_fd, &sig, 1) <= 0)
-#else
-                               if (read(err2_fd, &sig, 1) <= 0)
-#endif
-                               {
-#if 0
-                                       printf("read failed: %d\n", errno);
-#endif
-                                       exit(0);
-                               }
-                               pid= 0;
-#if 0
-                               printf("killing %d with %d\n", -new_pg, sig);
-#endif
-                               kill(-new_pg, sig);
-                       }
-               }
-#if USEATTACH
-               close(err2_fd); /* signal channel for parent */
-#endif
-               result= pipe(pds);
-               if (result<0)
-               {
-                       printf("\1Can't make pipe\n");
-                       kill(getppid(), SIGTERM);
-                       exit(1);
-               }
-               pid1= fork();
-               if (pid1<0)
-               {
-                       if (errno != EAGAIN)
-                       {
-                               fprintf(stderr, "%s: fork()= %d : %s\n",
-                                       prog_name, errno, strerror(errno));
-                       }
-                       printf("\1Try again.\n");
-                       kill(-new_pg, SIGTERM);
-                       exit(1);
-               }
-               if (pid1)
-               {
-                       close(pds[1]);  /* write side of pipe */
-                       for (;;)
-                       {
-                               result= read(pds[0], buffer, sizeof(buffer));
-                               if (result<=0)
-                               {
-                                       kill(pid, SIGTERM);
-                                       exit(0);
-                               }
-                               buff_ptr= buffer;
-                               while (result>0)
-                               {
-                                       result1= write (err_fd, buff_ptr,
-                                               result);
-                                       if (result1 <= 0)
-                                       {
-                                               fprintf(stderr, 
-                                               "%s: write()= %d : %s\n",
-                                                       prog_name, errno,
-                                                       strerror(errno));
-                                               kill(-new_pg, SIGTERM);
-                                               exit(1);
-                                       }
-                                       result -= result1;
-                               }
-                       }
-               }
-               close(err_fd);  /* file descriptor for error channel */
-               close (pds[0]); /* read side of pipe */
-               dup2(pds[1], 2);
-               close (pds[1]); /* write side of pipe */
-       }
-       if (*pwent->pw_shell == '\0')
-               pwent->pw_shell= "/bin/sh";
-#if __minix_vmd
-       initgroups(pwent->pw_name, pwent->pw_gid);
-#endif
-       setgid(pwent->pw_gid);
-       setuid(pwent->pw_uid);
-       TZ=getenv("TZ");
-       environ= envinit;
-       strncat(homedir, pwent->pw_dir, sizeof(homedir)-6);
-       strncat(shell, pwent->pw_shell, sizeof(shell)-7);
-       strncat(username, pwent->pw_name, sizeof(username)-6);
-       if (TZ)
-               strncat(tz, TZ, sizeof(tz)-4);
-       else
-               envinit[3]= NULL;
-
-       cp= strrchr(pwent->pw_shell, '/');
-       if (cp)
-               cp++;
-       else
-               cp= pwent->pw_shell;
-
-       if (!err_port)
-               dup2(1, 2);
-       write(1, "\0", 1);
-
-       execl(pwent->pw_shell, cp, "-c", cmdbuf, 0);
-       close(2);
-       open("/dev/tty", O_RDWR);
-       fprintf(stderr, "%s: execl(%s, %s, .., %s)= %d : %s\n", prog_name,
-               pwent->pw_shell, cp, cmdbuf, errno, strerror(errno));
-       kill(getppid(), SIGTERM);
-       exit(1);
-}
-
-void getstr(buf, cnt, err)
-char *buf;
-int cnt;
-char *err;
-{
-       char c;
-
-       do
-       {
-               if (read(0, &c, 1) != 1)
-                       exit(1);
-               *buf++ = c;
-               if (--cnt == 0)
-               {
-                       printf("\1%s too long", err);
-                       exit(1);
-               }
-       } while (c != 0);
-}
-
-void close_on_exec(fd)
-int fd;
-{
-       (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
-}
index 0d7679cfd05e627714f88b2f16774c9c2b74ff6a..ad7d3785a9f009af204bfd01f8ff08dc169774bf 100644 (file)
@@ -242,6 +242,7 @@ int main(int argc, char **argv)
                sigprocmask(SIG_SETMASK, &oldmask, NULL);
                dup2(client_fd, 0);
                dup2(client_fd, 1);
+               dup2(client_fd, 2);
                close(client_fd);
                execvp(progv[0], progv);
                report(progv[0]);
index 48d0af70606ac684dc211808a752a63ec97f3f41..d34eec4a3caa641e1e291ceb36d321f92138ca87 100644 (file)
@@ -12,8 +12,8 @@ MAN=  at.1 \
        mixer.1 \
        mkproto.1 mount.1 mt.1 \
        playwave.1 prep.1 \
-       profile.1 ps.1 rcp.1 recwave.1 \
-       remsync.1 rget.1 rlogin.1 rsh.1 rz.1 \
+       profile.1 ps.1 recwave.1 \
+       remsync.1 rget.1 rlogin.1 rz.1 \
        spell.1 svc.1 svrctl.1 \
        synctree.1 sysenv.1 sz.1 telnet.1 template.1 \
        term.1 termcap.1 tget.1 time.1 \
diff --git a/minix/man/man1/rcp.1 b/minix/man/man1/rcp.1
deleted file mode 100644 (file)
index e7100d8..0000000
+++ /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 (file)
index 65e36be..0000000
+++ /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).
index 2441f56cc5ce92237b4fbcaef2770aacb029cc47..38d8d5cbd6a787827e6776bdf71773ef3a3a06e9 100644 (file)
@@ -7,7 +7,7 @@ MAN=    add_route.8 backup.8 boot.8 btrace.8 \
        ossdevlinks.8 part.8 partition.8 \
        printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
        readclock.8 repartition.8 \
-       rshd.8  screendump.8 serial-ip.8 \
+       screendump.8 serial-ip.8 \
        setup.8 shutdown.8 slip.8 srccrc.8 tcpd.8 \
        unix.8 update.8 usage.8 vbfs.8
 
diff --git a/minix/man/man8/rshd.8 b/minix/man/man8/rshd.8
deleted file mode 100644 (file)
index b550c3b..0000000
+++ /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 ``<shellname>: ...''
-.br
-The user's login shell could not be started.  This message is returned
-on the connection associated with the
-.BR stderr ,
-and is not preceded by a flag byte.
-.SH SEE ALSO
-.BR rsh (1),
-.BR rcmd (3).
-.SH BUGS
-The authentication procedure used here assumes the integrity
-of each client machine and the connecting medium.  This is
-insecure, but is useful in an ``open'' environment.
-.PP
-A facility to allow all data exchanges to be encrypted should be
-present.
-.PP
-A more extensible protocol should be used.
index 792ba7e783436dc5beaf9c12e94a3319cfe752e0..680001480ecf61bef41dee28c54a7b556c5e6756 100644 (file)
@@ -21,7 +21,7 @@ SUBDIR= asa \
        nbperf newgrp nice nl nohup \
        passwd paste patch pathchk pr \
        printenv printf pwhash \
-       renice rev \
+       renice rev rsh \
        \
        sdiff sed seq shar shlock \
        shuffle  sort split stat su \
diff --git a/usr.bin/rsh/Makefile b/usr.bin/rsh/Makefile
new file mode 100644 (file)
index 0000000..a3be62d
--- /dev/null
@@ -0,0 +1,13 @@
+#      $NetBSD: Makefile,v 1.20 2009/04/14 22:15:25 lukem Exp $
+#      from: @(#)Makefile      8.1 (Berkeley) 7/19/93
+
+.include <bsd.own.mk>
+
+USE_FORT?=yes  # network client
+
+PROG=  rsh
+SRCS=  rsh.c getport.c
+
+.PATH: ${NETBSDSRCDIR}/usr.bin/rlogin
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/rsh/getport.c b/usr.bin/rsh/getport.c
new file mode 100644 (file)
index 0000000..739a9e4
--- /dev/null
@@ -0,0 +1,66 @@
+/*     $NetBSD: getport.c,v 1.2 2008/04/28 20:24:14 martin Exp $       */
+
+/*-
+ * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: getport.c,v 1.2 2008/04/28 20:24:14 martin Exp $");
+
+#include <stdlib.h>
+#include <err.h>
+#include <netdb.h>
+#include <limits.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include "getport.h"
+
+struct servent *
+getport(const char *service, const char *protocol)
+{
+       long port;
+       char *ep;
+       struct servent *sp = getservbyname(service, protocol);
+       if (sp != NULL)
+               return sp;
+
+       if ((sp = calloc(1, sizeof(*sp))) == NULL)
+               err(1, "malloc");
+       sp->s_name = __UNCONST(service);
+       sp->s_proto = __UNCONST(protocol);
+       port = strtol(service, &ep, 0);
+       if ((service[0] != '\0' && *ep != '\0') ||
+           (errno == ERANGE &&
+           (port == LONG_MAX || port == LONG_MIN)) ||
+           (port <= 0 || port >= IPPORT_ANONMAX))
+               errx(1,"port must be between 1 and %d",
+                   IPPORT_ANONMAX);
+       sp->s_port = htons((uint16_t)port);
+       return sp;
+}
diff --git a/usr.bin/rsh/getport.h b/usr.bin/rsh/getport.h
new file mode 100644 (file)
index 0000000..66ac4aa
--- /dev/null
@@ -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 (file)
index 0000000..3168b38
--- /dev/null
@@ -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 (file)
index 0000000..c029f81
--- /dev/null
@@ -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 (file)
index 0000000..ad3bf70
--- /dev/null
@@ -0,0 +1,474 @@
+/*     $NetBSD: rsh.c,v 1.33 2011/08/29 14:22:46 joerg Exp $   */
+
+/*-
+ * Copyright (c) 1983, 1990, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1990, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rsh.c      8.4 (Berkeley) 4/29/95";
+#else
+__RCSID("$NetBSD: rsh.c,v 1.33 2011/08/29 14:22:46 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <poll.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+#include "getport.h"
+
+
+/*
+ * rsh - remote shell
+ */
+int    remerr;
+
+static int sigs[] = { SIGINT, SIGTERM, SIGQUIT };
+
+static char   *copyargs(char **);
+static void    sendsig(int);
+static int     checkfd(struct pollfd *, int);
+static void    talk(int, sigset_t *, pid_t, int);
+__dead static void     usage(void);
+#ifdef IN_RCMD
+int     orcmd(char **, int, const char *,
+    const char *, const char *, int *);
+int     orcmd_af(char **, int, const char *,
+    const char *, const char *, int *, int);
+#endif
+
+int
+main(int argc, char **argv)
+{
+       struct passwd *pw;
+       struct servent *sp;
+       sigset_t oset, nset;
+       struct protoent *proto;
+
+#ifdef IN_RCMD
+       char    *locuser = 0, *loop;
+#endif /* IN_RCMD */
+       int argoff, asrsh, ch, dflag, nflag, one, rem;
+       size_t i;
+       int family = AF_UNSPEC;
+       pid_t pid;
+       uid_t uid;
+       char *args, *host, *p, *user, *name;
+
+       argoff = asrsh = dflag = nflag = 0;
+       one = 1;
+       host = user = NULL;
+       sp = NULL;
+
+#ifndef IN_RCMD
+       /*
+        * If called as something other than "rsh" use it as the host name,
+        * only for rsh.
+        */
+       if (strcmp(getprogname(), "rsh") == 0)
+               asrsh = 1;
+       else {
+               host = strdup(getprogname());
+               if (host == NULL)
+                       err(1, NULL);
+       }
+#endif /* IN_RCMD */
+
+       /* handle "rsh host flags" */
+       if (!host && argc > 2 && argv[1][0] != '-') {
+               host = argv[1];
+               argoff = 1;
+       }
+
+#ifdef IN_RCMD
+       if ((loop = getenv("RCMD_LOOP")) && strcmp(loop, "YES") == 0)
+               warnx("rcmd appears to be looping!");
+
+       setenv("RCMD_LOOP", "YES", 1);
+
+#  define      OPTIONS "468KLdel:np:u:w"
+
+#else /* IN_RCMD */
+
+#  define      OPTIONS "468KLdel:np:w"
+
+#endif /* IN_RCMD */
+
+       if (!(pw = getpwuid(uid = getuid())))
+               errx(1, "unknown user id");
+
+       if ((name = strdup(pw->pw_name)) == NULL)
+               err(1, "malloc");
+       while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
+               switch(ch) {
+               case '4':
+                       family = AF_INET;
+                       break;
+               case '6':
+                       family = AF_INET6;
+                       break;
+               case 'K':
+                       break;
+               case 'L':       /* -8Lew are ignored to allow rlogin aliases */
+               case 'e':
+               case 'w':
+               case '8':
+                       break;
+               case 'd':
+                       dflag = 1;
+                       break;
+               case 'l':
+                       user = optarg;
+                       break;
+               case 'n':
+                       nflag = 1;
+                       break;
+               case 'p':
+                       sp = getport(optarg, "tcp");
+                       break;
+#ifdef IN_RCMD
+               case 'u':
+                       if (getuid() != 0 && optarg && name &&
+                           strcmp(name, optarg) != 0)
+                               errx(1,"only super user can use the -u option");
+                       locuser = optarg;
+                       break;
+#endif /* IN_RCMD */
+               case '?':
+               default:
+                       usage();
+               }
+       optind += argoff;
+
+       /* if haven't gotten a host yet, do so */
+       if (!host && !(host = argv[optind++]))
+               usage();
+
+       /* if no further arguments, must have been called as rlogin. */
+       if (!argv[optind]) {
+#ifdef IN_RCMD
+               usage();
+#else
+               if (asrsh)
+                       *argv = __UNCONST("rlogin");
+               execv(_PATH_RLOGIN, argv);
+               err(1, "can't exec %s", _PATH_RLOGIN);
+#endif
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* Accept user1@host format, though "-l user2" overrides user1 */
+       p = strchr(host, '@');
+       if (p) {
+               *p = '\0';
+               if (!user && p > host)
+                       user = host;
+               host = p + 1;
+               if (*host == '\0')
+                       usage();
+       }
+       if (!user)
+               user = name;
+
+
+       args = copyargs(argv);
+
+       if (sp == NULL)
+               sp = getservbyname("shell", "tcp");
+       if (sp == NULL)
+               errx(1, "shell/tcp: unknown service");
+
+
+#ifdef IN_RCMD
+       rem = orcmd_af(&host, sp->s_port, locuser ? locuser :
+#else
+       rem = rcmd_af(&host, sp->s_port,
+#endif
+           name, user, args, &remerr, family);
+       (void)free(name);
+
+       if (rem < 0)
+               exit(1);
+
+       if (remerr < 0)
+               errx(1, "can't establish stderr");
+       if (dflag) {
+               if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
+                   sizeof(one)) < 0)
+                       warn("setsockopt remote");
+               if (setsockopt(remerr, SOL_SOCKET, SO_DEBUG, &one,
+                   sizeof(one)) < 0)
+                       warn("setsockopt stderr");
+       }
+       proto = getprotobyname("tcp");
+       setsockopt(rem, proto->p_proto, TCP_NODELAY, &one, sizeof(one));
+       setsockopt(remerr, proto->p_proto, TCP_NODELAY, &one, sizeof(one));
+
+
+       (void)setuid(uid);
+
+       (void)sigemptyset(&nset);
+       for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
+               (void)sigaddset(&nset, sigs[i]);
+
+       (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+
+       for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) {
+               struct sigaction sa;
+
+               if (sa.sa_handler != SIG_IGN) {
+                       sa.sa_handler = sendsig;
+                       (void)sigaction(sigs[i], &sa, NULL);
+               }
+       }
+
+       if (!nflag) {
+               pid = fork();
+               if (pid < 0)
+                       err(1, "fork");
+       }
+       else
+               pid = -1;
+
+#if defined(KERBEROS) && defined(CRYPT)
+       if (!doencrypt)
+#endif
+       {
+               (void)ioctl(remerr, FIONBIO, &one);
+               (void)ioctl(rem, FIONBIO, &one);
+       }
+
+       talk(nflag, &oset, pid, rem);
+
+       if (!nflag)
+               (void)kill(pid, SIGKILL);
+       exit(0);
+}
+
+static int
+checkfd(struct pollfd *fdp, int outfd)
+{
+       int nr, nw;
+       char buf[BUFSIZ];
+
+       if (fdp->revents & (POLLNVAL|POLLERR|POLLHUP))
+               return -1;
+          
+       if ((fdp->revents & POLLIN) == 0)
+               return 0;
+
+       errno = 0;
+#if defined(KERBEROS) && defined(CRYPT)
+       if (doencrypt)
+               nr = des_read(fdp->fd, buf, sizeof buf);
+       else
+#endif
+               nr = read(fdp->fd, buf, sizeof buf);
+
+       if (nr <= 0) {
+               if (errno != EAGAIN)
+                       return -1;
+               else
+                       return 0;
+       }
+       else {
+               char *bc = buf;
+               while (nr) {
+                       if ((nw = write(outfd, bc, nr)) <= 0)
+                               return -1;
+                       nr -= nw;
+                       bc += nw;
+               }
+               return 0;
+       }
+}
+
+static void
+talk(int nflag, sigset_t *oset, __pid_t pid, int rem)
+{
+       int nr, nw, nfds;
+       struct pollfd fds[2], *fdp = &fds[0];
+       char *bp, buf[BUFSIZ];
+
+       if (!nflag && pid == 0) {
+               (void)close(remerr);
+
+               fdp->events = POLLOUT|POLLNVAL|POLLERR|POLLHUP;
+               fdp->fd = rem;
+               nr = 0;
+               bp = buf;
+
+               for (;;) {
+                       errno = 0;
+
+                       if (nr == 0) {
+                               if ((nr = read(0, buf, sizeof buf)) == 0)
+                                       goto done;
+                               if (nr == -1) {
+                                       if (errno == EIO)
+                                               goto done;
+                                       if (errno == EINTR) {
+                                               nr = 0;
+                                               continue;
+                                       }
+                                       err(1, "read");
+                               }
+                               bp = buf;
+                       }
+
+rewrite:               if (poll(fdp, 1, INFTIM) == -1) {
+                               if (errno != EINTR)
+                                       err(1, "poll");
+                               goto rewrite;
+                       }
+
+                       if (fdp->revents & (POLLNVAL|POLLERR|POLLHUP))
+                               err(1, "poll");
+
+                       if ((fdp->revents & POLLOUT) == 0)
+                               goto rewrite;
+
+#if defined(KERBEROS) && defined(CRYPT)
+                       if (doencrypt)
+                               nw = des_write(rem, bp, nr);
+                       else
+#endif
+                               nw = write(rem, bp, nr);
+
+                       if (nw < 0) {
+                               if (errno == EAGAIN)
+                                       continue;
+                               err(1, "write");
+                       }
+                       bp += nw;
+                       nr -= nw;
+               }
+done:
+               (void)shutdown(rem, 1);
+               exit(0);
+       }
+
+       (void)sigprocmask(SIG_SETMASK, oset, NULL);
+       fds[0].events = fds[1].events = POLLIN|POLLNVAL|POLLERR|POLLHUP;
+       fds[0].fd = remerr;
+       fds[1].fd = rem;
+       fdp = &fds[0];
+       nfds = 2;
+       do {
+               if (poll(fdp, nfds, INFTIM) == -1) {
+                       if (errno != EINTR)
+                               err(1, "poll");
+                       continue;
+               }
+               if (fds[0].events != 0 && checkfd(&fds[0], 2) == -1) {
+                       nfds--;
+                       fds[0].events = 0;
+                       fdp = &fds[1];
+               }
+               if (fds[1].events != 0 && checkfd(&fds[1], 1) == -1) {
+                       nfds--;
+                       fds[1].events = 0;
+               }
+       }
+       while (nfds);
+}
+
+static void
+sendsig(int sig)
+{
+       char signo;
+
+       signo = sig;
+               (void)write(remerr, &signo, 1);
+}
+
+
+static char *
+copyargs(char **argv)
+{
+       int cc;
+       char **ap, *args, *p, *ep;
+
+       cc = 0;
+       for (ap = argv; *ap; ++ap)
+               cc += strlen(*ap) + 1;
+       if (!(args = malloc((u_int)cc)))
+               err(1, "malloc");
+       ep = args + cc;
+       for (p = args, *p = '\0', ap = argv; *ap; ++ap) {
+               (void)strlcpy(p, *ap, ep - p);
+               p += strlen(p);
+               if (ap[1])
+                       *p++ = ' ';
+       }
+       *p = '\0';
+       return (args);
+}
+
+static void
+usage(void)
+{
+
+       (void)fprintf(stderr,
+           "usage: %s [-46dn] [-l login] [-p port]%s [login@]host command\n",
+           getprogname(),
+#ifdef IN_RCMD
+           " [-u locuser]"
+#else
+           ""
+#endif
+           );
+       exit(1);
+}