summaryrefslogtreecommitdiffstats
path: root/usr.bin/rdist
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1996-08-10 07:54:17 +0000
committerpeter <peter@FreeBSD.org>1996-08-10 07:54:17 +0000
commiteda223150ae28327a1899db37fe184b8b8942e70 (patch)
treea7f69e16c74cc884e69d51027b64a2371b6f57ac /usr.bin/rdist
parentd6987f0ce13738a30ff52bb78cd8ff1fe6a63b23 (diff)
downloadFreeBSD-src-eda223150ae28327a1899db37fe184b8b8942e70.zip
FreeBSD-src-eda223150ae28327a1899db37fe184b8b8942e70.tar.gz
Remove the need for rdist(1) to run setuid, thus completely closing any
possibility of a security hole. It now does what rdist-6 does, and calls /usr/bin/rsh if not running as root. There are NO protocol changes, this is 100% compatable with the old rdist, except that it does not need setuid root privs. However, there are some minor differences to the base rdist-6 code in that if it is being run by root, it will call rcmd(3) directly rather than piping everything through rsh(1). This is a little more efficient as it doesn't involve context switching on pipe reads/writes. Also, the -P option was added from rdist-6.1.2, which allows an alternative rsh program to be specified, such as ssh. Note that it requires the fixes to the ssh port to disable the unconditional USE_PIPES option that was recently added. The rcmd(3) optimisation is disabled if a non-rsh program is speficied.
Diffstat (limited to 'usr.bin/rdist')
-rw-r--r--usr.bin/rdist/Makefile12
-rw-r--r--usr.bin/rdist/defs.h9
-rw-r--r--usr.bin/rdist/docmd.c65
-rw-r--r--usr.bin/rdist/expand.c16
-rw-r--r--usr.bin/rdist/gram.y6
-rw-r--r--usr.bin/rdist/lookup.c4
-rw-r--r--usr.bin/rdist/main.c14
-rw-r--r--usr.bin/rdist/pathnames.h1
-rw-r--r--usr.bin/rdist/rdist.112
-rw-r--r--usr.bin/rdist/rshrcmd.c124
-rw-r--r--usr.bin/rdist/server.c30
11 files changed, 250 insertions, 43 deletions
diff --git a/usr.bin/rdist/Makefile b/usr.bin/rdist/Makefile
index 853439c..83582e0 100644
--- a/usr.bin/rdist/Makefile
+++ b/usr.bin/rdist/Makefile
@@ -2,11 +2,15 @@
PROG= rdist
CFLAGS+=-I${.CURDIR}
-SRCS= docmd.c expand.c lookup.c main.c server.c
+SRCS= docmd.c expand.c lookup.c main.c rshrcmd.c server.c
OBJS+= gram.o
-BINOWN= root
-BINMODE=4555
-INSTALLFLAGS=-fschg
CLEANFILES=y.tab.h
+# To use the old method, which requires setuid-root and all the baggage and
+# security holes that goes with it, uncomment:
+# CFLAGS+= -DDIRECT_RCMD
+# BINOWN= root
+# BINMODE=4555
+# INSTALLFLAGS=-fschg
+
.include <bsd.prog.mk>
diff --git a/usr.bin/rdist/defs.h b/usr.bin/rdist/defs.h
index c99ddd6..e23ae6f 100644
--- a/usr.bin/rdist/defs.h
+++ b/usr.bin/rdist/defs.h
@@ -105,6 +105,13 @@
#define ALLOC(x) (struct x *) malloc(sizeof(struct x))
+/*
+ * RSH Time Out interval (in seconds).
+ * Should be long enough to allow rsh to even the slowest hosts.
+ */
+#define RTIMEOUT 180
+
+
struct namelist { /* for making lists of strings */
char *n_name;
struct namelist *n_next;
@@ -150,6 +157,7 @@ extern struct passwd *pw; /* pointer to static area used by getpwent */
extern struct group *gr; /* pointer to static area used by getgrent */
extern char host[]; /* host name of master copy */
extern char buf[BUFSIZ]; /* general purpose buffer */
+extern char *path_rsh; /* rsh command to use */
int any __P((int, char *));
char *colon __P((char *));
@@ -178,3 +186,4 @@ void prnames __P((struct namelist *));
void server __P((void));
void yyerror __P((char *));
int yyparse __P((void));
+int rshrcmd __P((char **, u_short, char *, char *, char *, int *));
diff --git a/usr.bin/rdist/docmd.c b/usr.bin/rdist/docmd.c
index 7b3219d..e941d78 100644
--- a/usr.bin/rdist/docmd.c
+++ b/usr.bin/rdist/docmd.c
@@ -34,7 +34,7 @@
#ifndef lint
/*static char sccsid[] = "From: @(#)docmd.c 8.1 (Berkeley) 6/9/93";*/
static const char rcsid[] =
- "$Id: docmd.c,v 1.3 1995/05/30 06:33:02 rgrimes Exp $";
+ "$Id: docmd.c,v 1.4 1996/07/12 04:00:13 nate Exp $";
#endif /* not lint */
#include "defs.h"
@@ -56,6 +56,7 @@ static void dodcolon __P((char **,
struct namelist *, char *, struct subcmd *));
static void notify __P((char *, char *, struct namelist *, time_t));
static void rcmptime __P((struct stat *));
+static int remotecmd __P((char *, char *, char *, char *));
/*
* Do the commands in cmds (initialized by yyparse).
@@ -129,7 +130,7 @@ doarrow(filev, files, rhost, cmds)
int n, ddir, opts = options;
if (debug)
- printf("doarrow(%x, %s, %x)\n", files, rhost, cmds);
+ printf("doarrow(%p, %s, %p)\n", files, rhost, cmds);
if (files == NULL) {
error("no files to be updated\n");
@@ -194,6 +195,54 @@ done:
}
}
+static int remotecmd(rhost, luser, ruser, cmd)
+ char *rhost;
+ char *luser, *ruser;
+ char *cmd;
+{
+ int desc;
+ static int port = -1;
+
+ if (debug) {
+ printf("local user = %s remote user = %s\n", luser, ruser);
+ printf("Remote command = '%s'\n", cmd);
+ }
+
+ (void) fflush(stdout);
+ (void) fflush(stderr);
+ (void) signal(SIGALRM, cleanup);
+ (void) alarm(RTIMEOUT);
+
+ if (geteuid() == 0 && strcmp(path_rsh, _PATH_RSH) == 0) {
+ if (debug)
+ printf("I am root, therefore direct rcmd\n");
+
+ (void) signal(SIGPIPE, cleanup);
+
+ if (port < 0) {
+ struct servent *sp;
+
+ if ((sp = getservbyname("shell", "tcp")) == NULL)
+ fatal("shell/tcp: unknown service");
+ port = sp->s_port;
+ }
+
+ desc = rcmd(&rhost, port, luser, ruser, cmd, 0);
+ } else {
+ if (debug)
+ printf("Remote shell command = '%s'\n", path_rsh);
+ (void) signal(SIGPIPE, SIG_IGN);
+ desc = rshrcmd(&rhost, -1, luser, ruser, cmd, 0);
+ if (desc > 0)
+ (void) signal(SIGPIPE, cleanup);
+ }
+
+ (void) alarm(0);
+
+ return(desc);
+}
+
+
/*
* Create a connection to the rdist server on the machine rhost.
*/
@@ -207,7 +256,9 @@ makeconn(rhost)
char tuser[20];
int n;
extern char user[];
+#if defined(DIRECT_RCMD)
extern int userid;
+#endif
if (debug)
printf("makeconn(%s)\n", rhost);
@@ -251,9 +302,13 @@ makeconn(rhost)
}
fflush(stdout);
+#if defined(DIRECT_RCMD)
seteuid(0);
rem = rcmd(&rhost, port, user, ruser, buf, 0);
seteuid(userid);
+#else
+ rem = remotecmd(rhost, user, ruser, buf);
+#endif
if (rem < 0)
return(0);
cp = buf;
@@ -463,7 +518,7 @@ rcmptime(st)
int len;
if (debug)
- printf("rcmptime(%x)\n", st);
+ printf("rcmptime(%p)\n", st);
if ((d = opendir(target)) == NULL) {
error("%s: %s\n", target, strerror(errno));
@@ -471,7 +526,7 @@ rcmptime(st)
}
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
@@ -481,7 +536,7 @@ rcmptime(st)
tp = otp;
*tp++ = '/';
cp = dp->d_name;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
cmptime(target);
diff --git a/usr.bin/rdist/expand.c b/usr.bin/rdist/expand.c
index 555dbf1..4d1819b 100644
--- a/usr.bin/rdist/expand.c
+++ b/usr.bin/rdist/expand.c
@@ -91,7 +91,7 @@ expand(list, wh)
char *argvbuf[GAVSIZ];
if (debug) {
- printf("expand(%x, %d)\nlist = ", list, wh);
+ printf("expand(%p, %d)\nlist = ", list, wh);
prnames(list);
}
@@ -217,7 +217,7 @@ expstr(s)
cp1 = pw->pw_dir;
s = cp;
}
- for (cp = path; *cp++ = *cp1++; )
+ for (cp = path; (*cp++ = *cp1++); )
;
tpathp = pathp = cp - 1;
} else {
@@ -451,7 +451,7 @@ amatch(s, p)
case '[':
ok = 0;
lc = 077777;
- while (cc = *p++) {
+ while ((cc = *p++)) {
if (cc == ']') {
if (ok)
break;
@@ -534,7 +534,7 @@ smatch(s, p)
case '[':
ok = 0;
lc = 077777;
- while (cc = *p++) {
+ while ((cc = *p++)) {
if (cc == ']') {
if (ok)
break;
@@ -592,10 +592,10 @@ Cat(s1, s2)
eargv[eargc - 1] = s = malloc(len);
if (s == NULL)
fatal("ran out of memory\n");
- while (*s++ = *s1++ & TRIM)
+ while ((*s++ = *s1++ & TRIM))
;
s--;
- while (*s++ = *s2++ & TRIM)
+ while ((*s++ = *s2++ & TRIM))
;
}
@@ -655,12 +655,12 @@ exptilde(buf, file)
*s3 = '/';
s2 = pw->pw_dir;
}
- for (s1 = buf; *s1++ = *s2++; )
+ for (s1 = buf; (*s1++ = *s2++); )
;
s2 = --s1;
if (s3 != NULL) {
s2++;
- while (*s1++ = *s3++)
+ while ((*s1++ = *s3++))
;
}
return(s2);
diff --git a/usr.bin/rdist/gram.y b/usr.bin/rdist/gram.y
index 6e54911..22d0ee8 100644
--- a/usr.bin/rdist/gram.y
+++ b/usr.bin/rdist/gram.y
@@ -171,8 +171,8 @@ cmd: INSTALL options opt_namelist SM = {
char errbuf[_POSIX2_LINE_MAX];
for (nl = $2; nl != NULL; nl = nl->n_next) {
- if (val = regcomp(&rx, nl->n_name,
- REG_EXTENDED)) {
+ if ((val = regcomp(&rx, nl->n_name,
+ REG_EXTENDED))) {
regerror(val, &rx, errbuf,
sizeof errbuf);
yyerror(errbuf);
@@ -477,7 +477,7 @@ makestr(str)
str = cp = malloc(strlen(s = str) + 1);
if (cp == NULL)
fatal("ran out of memory\n");
- while (*cp++ = *s++)
+ while ((*cp++ = *s++))
;
return(str);
}
diff --git a/usr.bin/rdist/lookup.c b/usr.bin/rdist/lookup.c
index 8b55afc..dc2f134 100644
--- a/usr.bin/rdist/lookup.c
+++ b/usr.bin/rdist/lookup.c
@@ -59,7 +59,7 @@ define(name)
{
register char *cp, *s;
register struct namelist *nl;
- struct namelist *value;
+ struct namelist *value = NULL;
if (debug)
printf("define(%s)\n", name);
@@ -129,7 +129,7 @@ lookup(name, action, value)
char buf[256];
if (debug)
- printf("lookup(%s, %d, %x)\n", name, action, value);
+ printf("lookup(%s, %d, %p)\n", name, action, value);
n = 0;
for (cp = name; *cp; )
diff --git a/usr.bin/rdist/main.c b/usr.bin/rdist/main.c
index 44b3279a..3badde7 100644
--- a/usr.bin/rdist/main.c
+++ b/usr.bin/rdist/main.c
@@ -68,6 +68,7 @@ char user[10]; /* user's name */
char homedir[128]; /* user's home directory */
int userid; /* user's user ID */
int groupid; /* user's group ID */
+char *path_rsh = _PATH_RSH; /* rsh (or equiv command) path */
struct passwd *pw; /* pointer to static area used by getpwent */
struct group *gr; /* pointer to static area used by getgrent */
@@ -107,6 +108,12 @@ main(argc, argv)
iamremote++;
else while (*++arg)
switch (*arg) {
+ case 'P':
+ if (--argc <= 0)
+ usage();
+ path_rsh = *++argv;
+ break;
+
case 'f':
if (--argc <= 0)
usage();
@@ -222,8 +229,9 @@ main(argc, argv)
static void
usage()
{
- printf("Usage: rdist [-nqbhirvwyD] [-f distfile] [-d var=value] [-m host] [file ...]\n");
- printf("or: rdist [-nqbhirvwyD] -c source [...] machine[:dest]\n");
+ printf("Usage: rdist [-nqbhirvwyD] [-P /path/to/rsh ] [-f distfile] [-d var=value]\n");
+ printf(" [-m host] [file ...]\n");
+ printf("or: rdist [-nqbhirvwyD] [-P /path/to/rsh ] -c source [...] machine[:dest]\n");
exit(1);
}
@@ -237,7 +245,7 @@ docmdargs(nargs, args)
{
register struct namelist *nl, *prev;
register char *cp;
- struct namelist *files, *hosts;
+ struct namelist *files = NULL, *hosts;
struct subcmd *cmds;
char *dest;
static struct namelist tnl = { NULL, NULL };
diff --git a/usr.bin/rdist/pathnames.h b/usr.bin/rdist/pathnames.h
index 2e1b067..c772539 100644
--- a/usr.bin/rdist/pathnames.h
+++ b/usr.bin/rdist/pathnames.h
@@ -36,3 +36,4 @@
#include <paths.h>
#define _PATH_RDIST "rdist"
+#define _PATH_RSH "/usr/bin/rsh"
diff --git a/usr.bin/rdist/rdist.1 b/usr.bin/rdist/rdist.1
index 00a3339..72ab587 100644
--- a/usr.bin/rdist/rdist.1
+++ b/usr.bin/rdist/rdist.1
@@ -40,12 +40,14 @@
.Sh SYNOPSIS
.Nm rdist
.Op Fl nqbRhivwy
+.Op Fl P Ar rshcmd
.Op Fl f Ar distfile
.Op Fl d Ar var=value
.Op Fl m Ar host
.Op Ar name ...
.Nm rdist
.Op Fl nqbRhivwy
+.Op Fl P Ar rshcmd
.Fl c
.Ar name ...
.Oo login@ Oc Ns Ar host Ns Op :dest
@@ -118,9 +120,13 @@ The equivalent distfile is as follows.
Options common to both forms:
.Pp
.Bl -tag -width Ic
-.It Fl b
-Binary comparison. Perform a binary comparison and update files if they differ
-rather than comparing dates and sizes.
+.It Fl P Ar rshcmd
+Alternative program to provide
+.Xr rsh 1 -like
+transport to the remote server. It must provide a binary-transparent path
+to the remote server, and must have a command argument syntax that is
+compatable with
+.Xr rsh 1 .
.It Fl d Ar var=value
Define
.Ar var
diff --git a/usr.bin/rdist/rshrcmd.c b/usr.bin/rdist/rshrcmd.c
new file mode 100644
index 0000000..2cb8ef2
--- /dev/null
+++ b/usr.bin/rdist/rshrcmd.c
@@ -0,0 +1,124 @@
+
+/*
+ * This is an rcmd() replacement originally by
+ * Chris Siebenmann <cks@utcc.utoronto.ca>.
+ */
+
+#ifndef lint
+static char RCSid[] =
+"$Id: rshrcmd.c,v 1.7 1995/12/12 00:20:55 mcooper Exp $";
+#endif
+
+#include "defs.h"
+
+#if !defined(DIRECT_RCMD)
+
+#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 <unistd.h>
+#include <stdlib.h>
+
+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) {
+ error("%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) {
+ error("socketpair(AF_UNIX, SOCK_STREAM, 0) failed: %s.",
+ strerror(errno));
+ return -1;
+ }
+
+ cpid = fork();
+ if (cpid < 0) {
+ error("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 || dup2(0, 2) < 0) {
+ error("dup2 failed: %s.", strerror(errno));
+ _exit(255);
+ }
+ /* fork again to lose parent. */
+ cpid = fork();
+ if (cpid < 0) {
+ error("fork to lose parent failed: %s.", strerror(errno));
+ _exit(255);
+ }
+ if (cpid > 0)
+ _exit(0);
+ /* in grandchild here. */
+
+ /*
+ * If we are rdist'ing to "localhost" as the same user
+ * as we are, then avoid running remote shell for efficiency.
+ */
+ if (strcmp(*ahost, "localhost") == 0 &&
+ strcmp(luser, ruser) == 0) {
+ execlp(_PATH_BSHELL, xbasename(_PATH_BSHELL), "-c",
+ cmd, (char *) NULL);
+ error("execlp %s failed: %s.", _PATH_BSHELL, strerror(errno));
+ } else {
+ execlp(path_rsh, xbasename(path_rsh),
+ *ahost, "-l", ruser, cmd, (char *) NULL);
+ error("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);
+}
+
+#endif /* !DIRECT_RCMD */
diff --git a/usr.bin/rdist/server.c b/usr.bin/rdist/server.c
index 46f3ea4..a511174 100644
--- a/usr.bin/rdist/server.c
+++ b/usr.bin/rdist/server.c
@@ -371,7 +371,7 @@ sendf(rname, opts)
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") ||
!strcmp(dp->d_name, ".."))
continue;
@@ -383,7 +383,7 @@ sendf(rname, opts)
tp = otp;
*tp++ = '/';
cp = dp->d_name;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
sendf(dp->d_name, opts);
@@ -498,7 +498,7 @@ done:
} else
ack();
f = response();
- if (f < 0 || f == 0 && (opts & COMPARE))
+ if (f < 0 || (f == 0 && (opts & COMPARE)))
return;
dospecial:
for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
@@ -564,7 +564,7 @@ update(rname, opts, stp)
register time_t mtime;
if (debug)
- printf("update(%s, %x, %x)\n", rname, opts, stp);
+ printf("update(%s, %x, %p)\n", rname, opts, stp);
/*
* Check to see if the file exists on the remote machine.
@@ -697,7 +697,7 @@ recvf(cmd, type)
int type;
{
register char *cp;
- int f, mode, opts, wrerr, olderrno;
+ int f = -1, mode, opts, wrerr, olderrno;
off_t i, size;
time_t mtime;
struct stat stb;
@@ -761,7 +761,7 @@ recvf(cmd, type)
stp[catname] = tp;
if (catname++) {
*tp++ = '/';
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
}
@@ -783,8 +783,8 @@ recvf(cmd, type)
return;
}
errno = ENOTDIR;
- } else if (errno == ENOENT && (mkdir(target, mode) == 0 ||
- chkparent(target) == 0 && mkdir(target, mode) == 0)) {
+ } else if ((errno == ENOENT && mkdir(target, mode) == 0) ||
+ (chkparent(target) == 0 && mkdir(target, mode) == 0)) {
if (fchog(-1, target, owner, group, mode) == 0)
ack();
return;
@@ -922,7 +922,7 @@ differ: buf[0] = '\0';
note("%s: utimes failed %s: %s\n", host, new, strerror(errno));
if (fchog(f, new, owner, group, mode) < 0) {
-badnew2: (void) close(f);
+badnew2: if (f != -1) (void) close(f);
(void) unlink(new);
return;
}
@@ -1084,10 +1084,10 @@ fchog(fd, file, owner, group, mode)
mode &= ~02000;
gid = -1;
}
-ok: if (fd != -1 && fchown(fd, uid, gid) < 0 || chown(file, uid, gid) < 0)
+ok: if ((fd != -1 && fchown(fd, uid, gid) < 0) || chown(file, uid, gid) < 0)
note("%s: %s chown: %s", host, file, strerror(errno));
else if (mode & 07000 &&
- (fd != -1 && fchmod(fd, mode) < 0 || chmod(file, mode) < 0))
+ ((fd != -1 && fchmod(fd, mode) < 0) || chmod(file, mode) < 0))
note("%s: %s chmod: %s", host, file, strerror(errno));
return(0);
}
@@ -1204,7 +1204,7 @@ clean(cp)
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
@@ -1215,7 +1215,7 @@ clean(cp)
tp = otp;
*tp++ = '/';
cp = dp->d_name;;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
if (lstat(target, &stb) < 0) {
@@ -1284,7 +1284,7 @@ removeit(stp)
otp = tp;
len = tp - target;
- while (dp = readdir(d)) {
+ while ((dp = readdir(d))) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
@@ -1295,7 +1295,7 @@ removeit(stp)
tp = otp;
*tp++ = '/';
cp = dp->d_name;;
- while (*tp++ = *cp++)
+ while ((*tp++ = *cp++))
;
tp--;
if (lstat(target, &stb) < 0) {
OpenPOWER on IntegriCloud