From naddy@bigeye.rhein-neckar.de  Sat Jan  1 18:00:44 2000
Return-Path: <naddy@bigeye.rhein-neckar.de>
Received: from news-ma.rhein-neckar.de (news-ma.rhein-neckar.de [193.197.90.3])
	by hub.freebsd.org (Postfix) with ESMTP id 9F5E114DB6
	for <FreeBSD-gnats-submit@freebsd.org>; Sat,  1 Jan 2000 18:00:42 -0800 (PST)
	(envelope-from naddy@bigeye.rhein-neckar.de)
Received: from bigeye.rhein-neckar.de (uucp@localhost)
	by news-ma.rhein-neckar.de (8.8.8/8.8.8) with bsmtp id DAA10310
	for FreeBSD-gnats-submit@freebsd.org; Sun, 2 Jan 2000 03:00:41 +0100 (CET)
	(envelope-from naddy@bigeye.rhein-neckar.de)
Received: (from naddy@localhost)
	by bigeye.rhein-neckar.de (8.9.3/8.9.3) id CAA88226;
	Sun, 2 Jan 2000 02:59:34 +0100 (CET)
	(envelope-from naddy)
Message-Id: <200001020159.CAA88226@bigeye.rhein-neckar.de>
Date: Sun, 2 Jan 2000 02:59:34 +0100 (CET)
From: Christian Weisgerber <naddy@mips.rhein-neckar.de>
Sender: naddy@bigeye.rhein-neckar.de
Reply-To: naddy@mips.rhein-neckar.de
To: FreeBSD-gnats-submit@freebsd.org
Subject: PATCH: rdump over ssh
X-Send-Pr-Version: 3.2

>Number:         15830
>Category:       bin
>Synopsis:       PATCH: rdump over ssh
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    imp
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jan  1 18:10:01 PST 2000
>Closed-Date:    Tue Oct 23 00:26:56 MDT 2001
>Last-Modified:  Tue Oct 23 00:28:20 MDT 2001
>Originator:     Christian Weisgerber
>Release:        FreeBSD 4.0-CURRENT i386
>Organization:
>Environment:

>Description:

The included patch adds to dump/restore the capability to access
tape devices on remote hosts over an arbitrary rsh-like program.
In particular, this is intended to allow the use of ssh.

Currently, dump/restore offer remote tape access using rcmd(3) to
call rmt on the remote host. This patch adds a flag "-P <rshcmd>"
to spawn a coprocess using <rshcmd>, in lieu of rcmd(3). "-P" was
chosen because it is used for the same purpose by rdist(1). Most
of the actual code has been taken from rdist, too.

Issues:

* The biggest chunk of the patch is the addition of a dump/rshrcmd.c
  module, which is almost literally copied from rdist/rshrcmd.c.
  Alas, the latter can't be used directly. The module adds the
  function rshrcmd(), which is mostly a drop-in replacement for
  rcmd(), transparently calling a rsh-like program.

  - rdist uses a local function error() to display error messages,
    dump uses msg(). This could be handled by compiling with
    -Derror=msg or by adding error() as wrapper for msg(). Both
    solutions appear questionable to me.

  - If the operator presses the interrupt character (^C), SIGINT
    is delivered to all processes in the foreground process group.
    The five processes spawned by the dump command variously catch
    or ignore SIGINT. The operator is offered a choice of aborting
    or continuing the dump run. Alas, the coprocess also receives
    the SIGINT, and ssh apparently installs a handler and terminates
    on SIGINT, so the whole dump run would always abort on interrupt.

    Diverging from the rdist code, I solved this by putting the
    coprocess in its own process group. I'm not sure I fully
    understand all the consequences of this, but it works. An
    interrupt doesn't kill the dump run, and if I forcefully
    terminate dump, the coprocess dies along with it.

* rshrcmd() doesn't really handle rcmd()'s final "fd2p" argument.
  Adding this appears to be rather complex, judging by the rcmd
  code. Considering the limited use (added post 4.4Lite) this sees
  in dump, I think it is a negligible omission.

* I didn't add "#ifdef RDUMP" around the changes, since I couldn't
  decide whether this is appropriate.

>How-To-Repeat:

Usage example:
$ dump 0aPf ssh host:/dev/nrsa0 /

>Fix:

diff -u -uNr /usr/src/sbin/dump/Makefile dump/Makefile
--- /usr/src/sbin/dump/Makefile	Tue Oct 26 21:47:56 1999
+++ dump/Makefile	Sat Jan  1 20:06:13 2000
@@ -17,7 +17,8 @@
 LINKS=	${BINDIR}/dump ${BINDIR}/rdump
 CFLAGS+=-DRDUMP
 CFLAGS+=-I${.CURDIR}/../../libexec/rlogind
-SRCS=	itime.c main.c optr.c dumprmt.c tape.c traverse.c unctime.c
+SRCS=	itime.c main.c optr.c dumprmt.c tape.c traverse.c unctime.c \
+	rshrcmd.c
 BINGRP=	tty
 BINMODE=2555
 MAN8=	dump.8
diff -u -uNr /usr/src/sbin/dump/dump.8 dump/dump.8
--- /usr/src/sbin/dump/dump.8	Sat Sep 11 03:51:55 1999
+++ dump/dump.8	Sat Jan  1 22:18:54 2000
@@ -47,6 +47,7 @@
 .Op Fl d Ar density
 .Op Fl f Ar file
 .Op Fl h Ar level
+.Op Fl P Ar rshcmd
 .Op Fl s Ar feet
 .Op Fl T Ar date
 .Ar filesystem
@@ -177,6 +178,13 @@
 .Dq operator
 by means similar to a
 .Xr wall 1 .
+.It Fl P Ar rshcmd
+Program to provide
+.Xr rsh 1 -like Ns
+transport to the remote tape server.
+It must provide a binary-transparent path to the remote host
+and must have a command argument syntax that is compatible with
+.Xr rsh 1 .
 .It Fl s Ar feet
 Attempt to calculate the amount of tape needed
 at a particular density.
diff -u -uNr /usr/src/sbin/dump/dump.h dump/dump.h
--- /usr/src/sbin/dump/dump.h	Tue Jul 14 11:19:45 1998
+++ dump/dump.h	Sat Jan  1 20:42:34 2000
@@ -102,7 +102,7 @@
 void	timeest __P((void));
 time_t	unctime __P((char *str));
 
-/* mapping rouintes */
+/* mapping routines */
 struct	dinode;
 long	blockest __P((struct dinode *dp));
 int	mapfiles __P((ino_t maxino, long *tapesize));
@@ -137,6 +137,8 @@
 int	rmtopen __P((char *tape, int mode));
 int	rmtwrite __P((char *buf, int count));
 #endif /* RDUMP */
+int	rshrcmd __P((char **ahost, u_short port, char *luser, char *ruser,
+		     char *cmd, int *fd2p));
 
 void	interrupt __P((int signo));	/* in case operator bangs on console */
 
diff -u -uNr /usr/src/sbin/dump/dumprmt.c dump/dumprmt.c
--- /usr/src/sbin/dump/dumprmt.c	Sat Sep 11 03:51:55 1999
+++ dump/dumprmt.c	Sat Jan  1 20:36:52 2000
@@ -92,6 +92,7 @@
 static	int errfd = -1;
 extern	int dokerberos;
 extern	int ntrec;		/* blocking factor on tape */
+extern	char *path_rsh;
 
 int
 rmthost(host)
@@ -141,7 +142,7 @@
 rmtgetconn()
 {
 	register char *cp;
-	register const char *rmt;
+	register char *rmt;
 	static struct servent *sp = NULL;
 	static struct passwd *pwd = NULL;
 	char *tuser;
@@ -173,6 +174,10 @@
 	if ((rmt = getenv("RMT")) == NULL)
 		rmt = _PATH_RMT;
 	msg("");
+	if (path_rsh)
+		rmtape = rshrcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name,
+				 tuser, rmt, 0);
+	else
 #ifdef KERBEROS
 	if (dokerberos)
 		rmtape = krcmd(&rmtpeer, sp->s_port, tuser, rmt, &errfd,
@@ -186,6 +191,8 @@
 		return;
 	}
 	(void)fprintf(stderr, "Connection to %s established.\n", rmtpeer);
+	if (path_rsh)
+		return;
 	size = ntrec * TP_BSIZE;
 	if (size > 60 * 1024)		/* XXX */
 		size = 60 * 1024;
diff -u -uNr /usr/src/sbin/dump/main.c dump/main.c
--- /usr/src/sbin/dump/main.c	Sat Sep 11 03:51:55 1999
+++ dump/main.c	Sat Jan  1 22:11:40 2000
@@ -86,6 +86,7 @@
 long	dev_bsize = 1;	/* recalculated below */
 long	blocksperfile;	/* output blocks per file */
 char	*host = NULL;	/* remote host (if any) */
+char	*path_rsh = NULL;	/* rsh (or equiv command) path */
 
 static long numarg __P((char *, long, long));
 static void obsolete __P((int *, char **[]));
@@ -122,9 +123,9 @@
 
 	obsolete(&argc, &argv);
 #ifdef KERBEROS
-#define optstring "0123456789aB:b:cd:f:h:kns:T:uWw"
+#define optstring "0123456789aB:b:cd:f:h:knP:s:T:uWw"
 #else
-#define optstring "0123456789aB:b:cd:f:h:ns:T:uWw"
+#define optstring "0123456789aB:b:cd:f:h:nP:s:T:uWw"
 #endif
 	while ((ch = getopt(argc, argv, optstring)) != -1)
 #undef optstring
@@ -177,6 +178,10 @@
 			notify = 1;
 			break;
 
+		case 'P':
+			path_rsh = optarg;
+			break;
+
 		case 's':		/* tape size, feet */
 			tsize = numarg("tape size", 1L, 0L) * 12 * 10;
 			break;
@@ -491,7 +496,8 @@
 		"k"
 #endif
 		"nu] [-B records] [-b blocksize] [-d density] [-f file]\n"
-		"            [-h level] [-s feet] [-T date] filesystem\n"
+		"            [-h level] [-P rshcmd] [-s feet] [-T date] "
+		"filesystem\n"
 		"       dump [-W | -w]\n");
 	exit(X_STARTUP);
 }
@@ -598,6 +604,7 @@
 		case 'd':
 		case 'f':
 		case 'h':
+		case 'P':
 		case 's':
 		case 'T':
 			if (*argv == NULL) {
diff -u -uNr /usr/src/sbin/dump/rshrcmd.c dump/rshrcmd.c
--- /usr/src/sbin/dump/rshrcmd.c	Thu Jan  1 01:00:00 1970
+++ dump/rshrcmd.c	Sat Jan  1 22:05:35 2000
@@ -0,0 +1,110 @@
+
+/*
+ * This is an rcmd() replacement originally by 
+ * Chris Siebenmann <cks@utcc.utoronto.ca>.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dump.h"
+
+extern	char *path_rsh;
+
+static char *
+xbasename(s)
+	char *s;
+{
+	char *ret;
+
+	ret = strrchr(s, '/');
+	if (ret && ret[1])
+		return (ret + 1);
+	return s;
+}
+
+
+/*
+ * This is a replacement rcmd() function that uses the rsh(1c)
+ * program in place of a direct rcmd() function call so as to
+ * avoid having to be root.
+ */
+int
+rshrcmd(ahost, port, luser, ruser, cmd, fd2p)
+	char  	**ahost;
+	u_short	port;
+	char	*luser, *ruser, *cmd;
+	int	*fd2p;
+{
+	int             cpid;
+	struct hostent  *hp;
+	int             sp[2];
+
+	/* insure that we are indeed being used as we thought. */
+	if (fd2p != 0)
+		return -1;
+	/* validate remote hostname. */
+	hp = gethostbyname(*ahost);
+	if (hp == 0) {
+		msg("%s: unknown host", *ahost);
+		return -1;
+	}
+	*ahost = hp->h_name;	/* This makes me nervous. */
+
+	/* get a socketpair we'll use for stdin and stdout. */
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+		msg("socketpair(AF_UNIX, SOCK_STREAM, 0) failed: %s.", 
+		    strerror(errno));
+		return -1;
+	}
+
+	cpid = fork();
+	if (cpid < 0) {
+		msg("fork failed: %s.", strerror(errno));
+		return -1;      /* error. */
+	}
+	if (cpid == 0) {
+		/* child. we use sp[1] to be stdin/stdout, and close
+		   sp[0]. */
+		(void) close(sp[0]);
+		if (dup2(sp[1], 0) < 0 || dup2(0,1) < 0) {
+			msg("dup2 failed: %s.", strerror(errno));
+			_exit(255);
+		}
+		/* fork again to lose parent. */
+		cpid = fork();
+		if (cpid < 0) {
+			msg("fork to lose parent failed: %s.", strerror(errno));
+			_exit(255);
+		}
+		if (cpid > 0)
+			_exit(0);
+		/* in grandchild here. */
+		setpgid(0, getpid());	/* run in background */
+		execlp(path_rsh, xbasename(path_rsh), 
+		       *ahost, "-l", ruser, cmd, (char *) NULL);
+		msg("execlp %s failed: %s.", path_rsh, strerror(errno));
+		_exit(255);
+	}
+	if (cpid > 0) {
+		/* parent. close sp[1], return sp[0]. */
+		(void) close(sp[1]);
+		/* reap child. */
+		(void) wait(0);
+		return sp[0];
+	}
+	/*NOTREACHED*/
+	return (-1);
+}
diff -u -uNr /usr/src/sbin/restore/Makefile restore/Makefile
--- /usr/src/sbin/restore/Makefile	Tue Oct 26 21:48:16 1999
+++ restore/Makefile	Sat Jan  1 22:06:28 2000
@@ -6,7 +6,7 @@
 CFLAGS+=-DRRESTORE
 CFLAGS+=-I${.CURDIR}/../../libexec/rlogind
 SRCS=	main.c interactive.c restore.c dirs.c symtab.c tape.c utilities.c \
-	dumprmt.c
+	dumprmt.c rshrcmd.c
 BINGRP=	tty
 BINMODE=2555
 MAN8=	restore.8
diff -u -uNr /usr/src/sbin/restore/main.c restore/main.c
--- /usr/src/sbin/restore/main.c	Sat Sep 11 03:52:25 1999
+++ restore/main.c	Sat Jan  1 22:12:13 2000
@@ -74,6 +74,7 @@
 time_t	dumptime;
 time_t	dumpdate;
 FILE 	*terminal;
+char	*path_rsh = NULL;
 
 static void obsolete __P((int *, char **[]));
 static void usage __P((void));
@@ -99,9 +100,9 @@
 		inputdev = _PATH_DEFTAPE;
 	obsolete(&argc, &argv);
 #ifdef KERBEROS
-#define	optlist "b:cdf:hikmNRrs:tuvxy"
+#define	optlist "b:cdf:hikmNP:Rrs:tuvxy"
 #else
-#define	optlist "b:cdf:himNRrs:tuvxy"
+#define	optlist "b:cdf:himNP:Rrs:tuvxy"
 #endif
 	while ((ch = getopt(argc, argv, optlist)) != -1)
 		switch(ch) {
@@ -148,6 +149,9 @@
 		case 'N':
 			Nflag = 1;
 			break;
+		case 'P':
+			path_rsh = optarg;
+			break;
 		case 's':
 			/* Dumpnum (skip to) for multifile dump tapes. */
 			dumpnum = strtol(optarg, &p, 10);
@@ -292,12 +296,14 @@
 static void
 usage()
 {
-	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
-	  "restore -i [-chkmuvy] [-b blocksize] [-f file] [-s fileno]",
-	  "restore -r [-ckuvy] [-b blocksize] [-f file] [-s fileno]",
-	  "restore -R [-ckuvy] [-b blocksize] [-f file] [-s fileno]",
-	  "restore -x [-chkmuvy] [-b blocksize] [-f file] [-s fileno] [file ...]",
-	  "restore -t [-chkuvy] [-b blocksize] [-f file] [-s fileno] [file ...]");
+	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
+	  "restore -i [-chkmuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+	  "restore -r [-ckuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+	  "restore -R [-ckuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+	  "restore -x [-chkmuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+          "        [file ...]",
+	  "restore -t [-chkuvy] [-b blocksize] [-f file] [-P rshcmd] [-s fileno]",
+          "        [file ...]");
 	done(1);
 }
 
@@ -335,6 +341,7 @@
 		switch (*ap) {
 		case 'b':
 		case 'f':
+		case 'P':
 		case 's':
 			if (*argv == NULL) {
 				warnx("option requires an argument -- %c", *ap);
diff -u -uNr /usr/src/sbin/restore/restore.8 restore/restore.8
--- /usr/src/sbin/restore/restore.8	Sat Sep 11 03:52:25 1999
+++ restore/restore.8	Sat Jan  1 22:19:10 2000
@@ -44,24 +44,28 @@
 .Op Fl chkmuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Nm restore
 .Fl R
 .Op Fl ckuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Nm restore
 .Fl r
 .Op Fl ckuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Nm restore
 .Fl t
 .Op Fl chkuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Op file ...
 .Nm restore
@@ -69,6 +73,7 @@
 .Op Fl chkmuvy
 .Op Fl b Ar blocksize
 .Op Fl f Ar file
+.Op Fl P Ar rshcmd
 .Op Fl s Ar fileno
 .Op file ...
 .Pp
@@ -311,6 +316,13 @@
 This is useful if only a few files are being extracted,
 and one wants to avoid regenerating the complete pathname
 to the file.
+.It Fl P Ar rshcmd
+Program to provide
+.Xr rsh 1 -like Ns
+transport to the remote tape server.
+It must provide a binary-transparent path to the remote host
+and must have a command argument syntax that is compatible with
+.Xr rsh 1 .
 .It Fl s Ar fileno
 Read from the specified
 .Ar fileno

>Release-Note:
>Audit-Trail:

From: Warner Losh <imp@village.org>
To: freebsd-gnats-submit@FreeBSD.org
Cc: naddy@mips.rhein-neckar.de
Subject: Re: bin/15830: PATCH: rdump over ssh
Date: Thu, 24 Aug 2000 21:29:59 -0600

 I don't like this at all.  It is too specific to dump.  Why not take a
 page from OpenBSD and do the following?
 
 Warner
 
 Index: net/Makefile.inc
 ===================================================================
 RCS file: /home/imp/FreeBSD/CVS/src/lib/libc/net/Makefile.inc,v
 retrieving revision 1.37
 diff -u -r1.37 Makefile.inc
 --- net/Makefile.inc	2000/07/05 02:13:14	1.37
 +++ net/Makefile.inc	2000/08/25 03:21:51
 @@ -16,7 +16,7 @@
  	inet_pton.c ip6opt.c linkaddr.c map_v4v6.c name6.c ns_addr.c \
  	ns_name.c ns_netint.c \
  	ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
 -	rcmd.c recv.c res_comp.c res_data.c res_debug.c \
 +	rcmd.c rcmdsh.c recv.c res_comp.c res_data.c res_debug.c \
  	res_init.c res_mkquery.c res_mkupdate.c res_query.c res_send.c \
  	res_update.c rthdr.c send.c vars.c
  # not supported: iso_addr.c 
 Index: net/rcmd.c
 ===================================================================
 RCS file: /home/imp/FreeBSD/CVS/src/lib/libc/net/rcmd.c,v
 retrieving revision 1.29
 diff -u -r1.29 rcmd.c
 --- net/rcmd.c	2000/08/10 17:10:57	1.29
 +++ net/rcmd.c	2000/08/25 03:21:54
 @@ -47,6 +47,7 @@
  #include <signal.h>
  #include <fcntl.h>
  #include <netdb.h>
 +#include <stdlib.h>
  #include <unistd.h>
  #include <pwd.h>
  #include <errno.h>
 @@ -99,9 +100,27 @@
  	long oldmask;
  	pid_t pid;
  	int s, aport, lport, timo, error;
 -	char c;
 +	char c, *p;
  	char num[8];
  	static char canonnamebuf[MAXDNAME];	/* is it proper here? */
 +
 +	/* call rcmdsh() with specified remote shell if appropriate. */
 +	if (!issetugid() && (p = getenv("RSH"))) {
 +		struct servent *sp = getservbyname("shell", "tcp");
 +
 +		if (sp && sp->s_port == rport)
 +			return (rcmdsh(ahost, rport, locuser, remuser,
 +			    cmd, p));
 +	}
 +
 +	/* use rsh(1) if non-root and remote port is shell. */
 +	if (geteuid()) {
 +		struct servent *sp = getservbyname("shell", "tcp");
 +
 +		if (sp && sp->s_port == rport)
 +			return (rcmdsh(ahost, rport, locuser, remuser,
 +			    cmd, NULL));
 +	}
  
  	pid = getpid();
  
 Index: net/rcmdsh.3
 ===================================================================
 RCS file: rcmdsh.3
 diff -N rcmdsh.3
 --- /dev/null	Thu Aug 24 20:04:33 2000
 +++ rcmdsh.3	Thu Aug 24 20:21:54 2000
 @@ -0,0 +1,103 @@
 +.\"	$OpenBSD: rcmdsh.3,v 1.6 1999/07/05 04:41:00 aaron Exp $
 +.\"
 +.\" Copyright (c) 1983, 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. 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.
 +.\"
 +.Dd September 1, 1996
 +.Dt RCMDSH 3
 +.Os
 +.Sh NAME
 +.Nm rcmdsh
 +.Nd return a stream to a remote command without superuser
 +.Sh SYNOPSIS
 +.Fd #include <unistd.h>
 +.Ft int
 +.Fn rcmdsh "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "char *rshprog"
 +.Sh DESCRIPTION
 +The
 +.Fn rcmdsh
 +function
 +is used by normal users to execute a command on
 +a remote machine using an authentication scheme based
 +on reserved port numbers using
 +.Xr rshd 8
 +or the value of
 +.Fa rshprog
 +(if non-null).
 +.Pp
 +The
 +.Fn rcmdsh
 +function
 +looks up the host
 +.Fa *ahost
 +using
 +.Xr gethostbyname 3 ,
 +returning \-1 if the host does not exist.
 +Otherwise
 +.Fa *ahost
 +is set to the standard name of the host
 +and a connection is established to a server
 +residing at the well-known Internet port
 +.Li shell/tcp
 +(or whatever port is used by
 +.Fa rshprog
 +).  The parameter
 +.Fa inport
 +is ignored; it is only included to provide an interface similar to
 +.Xr rcmd 3 .
 +.Pp
 +If the connection succeeds,
 +a socket in the
 +.Tn UNIX
 +domain of type
 +.Dv SOCK_STREAM
 +is returned to the caller, and given to the remote
 +command as stdin and stdout, and stderr.
 +.Sh DIAGNOSTICS
 +The
 +.Fn rcmdsh
 +function
 +returns a valid socket descriptor on success.
 +It returns \-1 on error and prints a diagnostic message on the standard error.
 +.Sh SEE ALSO
 +.Xr rsh 1 ,
 +.Xr socketpair 2 ,
 +.Xr rcmd 3 ,
 +.Xr rshd 8
 +.Sh BUGS
 +If
 +.Xr rsh 1
 +gets an error a file descriptor is still returned instead of \-1.
 +.Sh HISTORY
 +The
 +.Fn rcmdsh
 +function first appeared in
 +.Ox 2.0 .
 Index: net/rcmdsh.c
 ===================================================================
 RCS file: rcmdsh.c
 diff -N rcmdsh.c
 --- /dev/null	Thu Aug 24 20:04:33 2000
 +++ rcmdsh.c	Thu Aug 24 20:21:54 2000
 @@ -0,0 +1,128 @@
 +/*	$OpenBSD: rcmdsh.c,v 1.5 1998/04/25 16:23:58 millert Exp $	*/ 
 +
 +/*
 + * This is an rcmd() replacement originally by 
 + * Chris Siebenmann <cks@utcc.utoronto.ca>.
 + */
 +
 +#if defined(LIBC_SCCS) && !defined(lint)
 +static char *rcsid = "$OpenBSD: rcmdsh.c,v 1.5 1998/04/25 16:23:58 millert Exp $";
 +#endif /* LIBC_SCCS and not lint */
 +
 +#include      <sys/types.h>
 +#include      <sys/socket.h>
 +#include      <sys/wait.h>
 +#include      <signal.h>
 +#include      <errno.h>
 +#include      <netdb.h>
 +#include      <stdio.h>
 +#include      <string.h>
 +#include      <pwd.h>
 +#include      <paths.h>
 +#include      <unistd.h>
 +
 +#ifndef _PATH_RSH
 +#define _PATH_RSH "/usr/bin/rsh"
 +#endif
 +
 +/*
 + * This is a replacement rcmd() function that uses the rsh(1)
 + * program in place of a direct rcmd(3) function call so as to
 + * avoid having to be root.  Note that rport is ignored.
 + */
 +/* ARGSUSED */
 +int
 +rcmdsh(ahost, rport, locuser, remuser, cmd, rshprog)
 +	char **ahost;
 +	int rport;
 +	const char *locuser, *remuser, *cmd;
 +	char *rshprog;
 +{
 +	struct hostent *hp;
 +	int cpid, sp[2];
 +	char *p;
 +	struct passwd *pw;
 +
 +	/* What rsh/shell to use. */
 +	if (rshprog == NULL)
 +		rshprog = _PATH_RSH;
 +
 +	/* locuser must exist on this host. */
 +	if ((pw = getpwnam(locuser)) == NULL) {
 +		(void) fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser);
 +		return(-1);
 +	}
 +
 +	/* Validate remote hostname. */
 +	if (strcmp(*ahost, "localhost") != 0) {
 +		if ((hp = gethostbyname(*ahost)) == NULL) {
 +			herror(*ahost);
 +			return(-1);
 +		}
 +		*ahost = hp->h_name;
 +	}
 +
 +	/* Get a socketpair we'll use for stdin and stdout. */
 +	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) < 0) {
 +		perror("rcmdsh: socketpair");
 +		return(-1);
 +	}
 +
 +	cpid = fork();
 +	if (cpid < 0) {
 +		perror("rcmdsh: fork failed");
 +		return(-1);
 +	} else if (cpid == 0) {
 +		/*
 +		 * Child.  We use sp[1] to be stdin/stdout, and close sp[0].
 +		 */
 +		(void) close(sp[0]);
 +		if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) {
 +			perror("rcmdsh: dup2 failed");
 +			_exit(255);
 +		}
 +		/* Fork again to lose parent. */
 +		cpid = fork();
 +		if (cpid < 0) {
 +			perror("rcmdsh: fork to lose parent failed");
 +			_exit(255);
 +		}
 +		if (cpid > 0)
 +			_exit(0);
 +
 +		/* In grandchild here.  Become local user for rshprog. */
 +		if (setuid(pw->pw_uid)) {
 +			(void) fprintf(stderr, "rcmdsh: setuid(%u): %s\n",
 +				       pw->pw_uid, strerror(errno));
 +			_exit(255);
 +		}
 +
 +		/*
 +		 * If remote host is "localhost" and local and remote user
 +		 * are the same, avoid running remote shell for efficiency.
 +		 */
 +		if (!strcmp(*ahost, "localhost") && !strcmp(locuser, remuser)) {
 +			if (pw->pw_shell[0] == '\0')
 +				rshprog = _PATH_BSHELL;
 +			else
 +				rshprog = pw->pw_shell;
 +			p = strrchr(rshprog, '/');
 +			execlp(rshprog, p ? p+1 : rshprog, "-c", cmd,
 +			       (char *) NULL);
 +		} else {
 +			p = strrchr(rshprog, '/');
 +			execlp(rshprog, p ? p+1 : rshprog, *ahost, "-l",
 +			       remuser, cmd, (char *) NULL);
 +		}
 +		(void) fprintf(stderr, "rcmdsh: execlp %s failed: %s\n",
 +			       rshprog, strerror(errno));
 +		_exit(255);
 +	} else {
 +		/* Parent. close sp[1], return sp[0]. */
 +		(void) close(sp[1]);
 +		/* Reap child. */
 +		(void) wait(NULL);
 +		return(sp[0]);
 +	}
 +	/* NOTREACHED */
 +}
 Index: net/res_query.c
 ===================================================================
 RCS file: /home/imp/FreeBSD/CVS/src/lib/libc/net/res_query.c,v
 retrieving revision 1.19
 diff -u -r1.19 res_query.c
 --- net/res_query.c	1999/11/04 04:30:44	1.19
 +++ net/res_query.c	2000/08/25 03:21:55
 @@ -76,6 +76,7 @@
  
  #include <sys/types.h>
  #include <sys/param.h>
 +#include <sys/stat.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <arpa/nameser.h>
 @@ -376,14 +377,23 @@
  	char *file;
  	char buf[BUFSIZ];
  	static char abuf[MAXDNAME];
 +	struct stat sb;
  
  	if (_res.options & RES_NOALIASES)
  		return (NULL);
 -	if (issetugid())
 -		return (NULL);
  	file = getenv("HOSTALIASES");
  	if (file == NULL || (fp = fopen(file, "r")) == NULL)
  		return (NULL);
 +	if (issetugid()) {
 +		if (fstat(fileno(fp), &sb)) {
 +			fclose(fp);
 +			return (NULL);
 +		}
 +		if ((sb.st_mode & 0444) != 0444) {
 +			fclose(fp);
 +			return (NULL);
 +		}
 +	}
  	setbuf(fp, NULL);
  	buf[sizeof(buf) - 1] = '\0';
  	while (fgets(buf, sizeof(buf), fp)) {
 
State-Changed-From-To: open->feedback 
State-Changed-By: sheldonh 
State-Changed-When: Fri Aug 25 02:22:18 PDT 2000 
State-Changed-Why:  
Need feedback from Christian, regarding Warner's alternative. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=15830 
State-Changed-From-To: feedback->open 
State-Changed-By: sheldonh 
State-Changed-When: Mon Aug 28 08:58:16 PDT 2000 
State-Changed-Why:  
The originator's address bounces, so leaving this in the 
feedback state isn't going to score us much. 


Responsible-Changed-From-To: freebsd-bugs->imp 
Responsible-Changed-By: sheldonh 
Responsible-Changed-When: Mon Aug 28 08:58:16 PDT 2000 
Responsible-Changed-Why:  
This is a reminder for Warner to commit the stuff he got 
from OpenBSD. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=15830 

From: Peter Johnson <freebsd@bilogic.org>
To: freebsd-gnats-submit@freebsd.org
Cc: freebsd-bugs@freebsd.org
Subject: Re: bin/15830: PATCH: rdump over ssh
Date: Fri, 12 Oct 2001 18:16:09 -0500

 Is there a reason this hasn't been committed yet?  I successfully applied
 and built Warner's patch with 4.4-STABLE, with the following change to the
 patchset for Makefile.in (so it builds and installs the manpage).  The
 result is perfect for using dump over ssh (just "setenv RSH ssh" before
 running dump with -f username@hostname:/dev/device).
 
 --- orig/Makefile.inc	Thu Sep 13 17:12:39 2001
 +++ Makefile.inc	Tue Oct  9 18:46:25 2001
 @@ -16,7 +16,7 @@
  	inet_pton.c ip6opt.c linkaddr.c map_v4v6.c name6.c ns_addr.c \
  	ns_name.c ns_netint.c \
  	ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
 -	rcmd.c recv.c res_comp.c res_data.c res_debug.c \
 +	rcmd.c rcmdsh.c recv.c res_comp.c res_data.c res_debug.c \
  	res_init.c res_mkquery.c res_mkupdate.c res_query.c res_send.c \
  	res_update.c rthdr.c send.c vars.c
  # not supported: iso_addr.c 
 @@ -32,7 +32,7 @@
  	getnameinfo.3 getnetent.3 getprotoent.3 getservent.3
 if_indextoname.3 \
  	inet.3 inet_net.3 \
  	inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
 -	rcmd.3 resolver.3
 +	rcmd.3 rcmdsh.3 resolver.3
  # not installed: iso_addr.3 ns.3
  
  MLINKS+=addr2ascii.3 ascii2addr.3
 
State-Changed-From-To: open->closed 
State-Changed-By: imp 
State-Changed-When: Tue Oct 23 00:26:56 MDT 2001 
State-Changed-Why:  
I fixed this. 


http://www.FreeBSD.org/cgi/query-pr.cgi?pr=15830 
>Unformatted:
