TUCoPS :: Unix :: General :: ciac-0~3.txt

Unix rcp Rdist


________________________________________________________________
		THE COMPUTER INCIDENT ADVISORY CAPABILITY

 				CIAC

			ADVISORY    NOTICE
________________________________________________________________


            NOTICE OF VULNERABILITY INVOLVING RCP AND RDIST

The DOE Computer Incident Advisory Capability (CIAC) has learned of a 
UNIX security problem involving rcp and rdist in 4.3BSD, 4.3BSD-tahoe, 
and all versions of UNIX using BSD networking code, as well as SunOS (all 
versions).  This vulnerability allows someone to overwrite system files 
without being detected. 

Because this problem has potentially serious consequences, CIAC recommends 
that you install a patch to correct the problems with rcp and rdist.  A patch 
is now available for BSD systems.  CIAC will send this patch to you via e-mail 
if you contact: 
 
     Gene Schultz, CIAC Manager
     gschultz%nsspa@icdc.llnl.gov
     (415) 422-8193 or (FTS) 532-8193

     or send e-mail to:

     ciac@tiger.llnl.gov

Although there are no SunOS workarounds currently available for rcp and rdist,
Sun is developing a patch.  If you would like to be notified when this patch 
is available, please contact CIAC.

------- Forwarded Message

Date: Thu, 25 May 89 15:33:48 GMT
>From: bostic@okeeffe.Berkeley.EDU (Keith Bostic)
Message-Id: <8905251533.AA15064@okeeffe.Berkeley.EDU>
To: cert@sei.cmu.edu
Subject: V1.82 (Rcp/rdist security patch)


Subject: Rcp/rdist security patch
Index: bin/rcp.c 4.3BSD
Index: ucb/rdist/server.c 4.3BSD

Description:
	There's a security problem associated with rcp and rdist
	in the 4.3BSD, 4.3BSD-tahoe, and first BSD networking
	distributions.
Fix:
	Replace your current bin/rcp.c with the attached rcp.c.
	Patch the server.c module in your current rdist with the
	attached patched.  Recompile and re-install.


# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	rcp.c
#	rdist.server.c.diff
#
echo x - rcp.c
sed 's/^X//' >rcp.c << 'END-of-rcp.c'
X/*
X * Copyright (c) 1983 The Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)rcp.c	5.20 (Berkeley) 5/23/89";
X#endif /* not lint */
X
X/*
X * rcp
X */
X#include <sys/param.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sys/ioctl.h>
X#include <sys/dir.h>
X#include <sys/signal.h>
X#include <netinet/in.h>
X#include <pwd.h>
X#include <netdb.h>
X#include <errno.h>
X#include <string.h>
X#include <stdio.h>
X#include <ctype.h>
X#include "pathnames.h"
X
X#ifdef KERBEROS
X#include <kerberos/krb.h>
X
Xchar krb_realm[REALM_SZ];
Xint use_kerberos = 1, encrypt = 0;
XCREDENTIALS cred;
XKey_schedule schedule;
X#endif
X
Xextern int errno;
Xextern char *sys_errlist[];
Xstruct passwd *pwd;
Xint errs, pflag, port, rem, userid;
Xint iamremote, iamrecursive, targetshouldbedirectory;
X
X#define	CMDNEEDS	20
Xchar cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
X
Xtypedef struct _buf {
X	int	cnt;
X	char	*buf;
X} BUF;
X
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	extern int optind;
X	struct servent *sp;
X	int ch, fflag, tflag;
X	char *targ, *colon();
X	struct passwd *getpwuid();
X	int lostconn();
X
X#ifdef KERBEROS
X	sp = getservbyname("kshell", "tcp");
X	if (sp == NULL) {
X		use_kerberos = 0;
X		old_warning("kshell service unknown");
X		sp = getservbyname("kshell", "tcp");
X	}
X#else
X	sp = getservbyname("shell", "tcp");
X#endif
X	if (!sp) {
X		(void)fprintf(stderr, "rcp: shell/tcp: unknown service\n");
X		exit(1);
X	}
X	port = sp->s_port;
X
X	if (!(pwd = getpwuid(userid = getuid()))) {
X		(void)fprintf(stderr, "rcp: unknown user %d.\n", userid);
X		exit(1);
X	}
X
X	fflag = tflag = 0;
X	while ((ch = getopt(argc, argv, "dfkprtx")) != EOF)
X		switch(ch) {
X		case 'd':
X			targetshouldbedirectory = 1;
X			break;
X		case 'f':			/* "from" */
X			fflag = 1;
X			break;
X#ifdef KERBEROS
X		case 'k':
X			strncpy(krb_realm, ++argv, REALM_SZ);
X			break;
X#endif
X		case 'p':			/* preserve access/mod times */
X			++pflag;
X			break;
X		case 'r':
X			++iamrecursive;
X			break;
X		case 't':			/* "to" */
X			tflag = 1;
X			break;
X#ifdef KERBEROS
X		case 'x':
X			encrypt = 1;
X			des_set_key(cred.session, schedule);
X			break;
X#endif
X		case '?':
X		default:
X			usage();
X		}
X	argc -= optind;
X	argv += optind;
X
X	if (fflag) {
X		iamremote = 1;
X		(void)response();
X		(void)setuid(userid);
X		source(argc, argv);
X		exit(errs);
X	}
X
X	if (tflag) {
X		iamremote = 1;
X		(void)setuid(userid);
X		sink(argc, argv);
X		exit(errs);
X	}
X
X	if (argc < 2)
X		usage();
X	if (argc > 2)
X		targetshouldbedirectory = 1;
X
X	rem = -1;
X	(void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "",
X	    pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
X
X	(void)signal(SIGPIPE, lostconn);
X
X	if (targ = colon(argv[argc - 1]))
X		toremote(targ, argc, argv);
X	else {
X		tolocal(argc, argv);
X		if (targetshouldbedirectory)
X			verifydir(argv[argc - 1]);
X	}
X	exit(errs);
X}
X
Xtoremote(targ, argc, argv)
X	char *targ;
X	int argc;
X	char **argv;
X{
X	int i;
X	char *bp, *host, *src, *suser, *thost, *tuser;
X	char *colon(), *malloc();
X
X	*targ++ = 0;
X	if (*targ == 0)
X		targ = ".";
X
X	if (thost = index(argv[argc - 1], '@')) {
X		*thost++ = 0;
X		tuser = argv[argc - 1];
X		if (*tuser == '\0')
X			tuser = NULL;
X		else if (!okname(tuser))
X			exit(1);
X	} else {
X		thost = argv[argc - 1];
X		tuser = NULL;
X	}
X
X	for (i = 0; i < argc - 1; i++) {
X		src = colon(argv[i]);
X		if (src) {			/* remote to remote */
X			*src++ = 0;
X			if (*src == 0)
X				src = ".";
X			host = index(argv[i], '@');
X			if (!(bp = malloc((u_int)(strlen(_PATH_RSH) +
X				    strlen(argv[i]) + strlen(src) +
X				    strlen(tuser) + strlen(thost) +
X				    strlen(targ)) + CMDNEEDS + 20)))
X					nospace();
X			if (host) {
X				*host++ = 0;
X				suser = argv[i];
X				if (*suser == '\0')
X					suser = pwd->pw_name;
X				else if (!okname(suser))
X					continue;
X				(void)sprintf(bp,
X				    "%s %s -l %s -n %s %s '%s%s%s:%s'",
X				    _PATH_RSH, host, suser, cmd, src,
X				    tuser ? tuser : "", tuser ? "@" : "",
X				    thost, targ);
X			} else
X				(void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'",
X				    _PATH_RSH, argv[i], cmd, src,
X				    tuser ? tuser : "", tuser ? "@" : "",
X				    thost, targ);
X			(void)susystem(bp);
X			(void)free(bp);
X		} else {			/* local to remote */
X			if (rem == -1) {
X				if (!(bp = malloc((u_int)strlen(targ) +
X				    CMDNEEDS + 20)))
X					nospace();
X				(void)sprintf(bp, "%s -t %s", cmd, targ);
X				host = thost;
X#ifdef KERBEROS
X				if (use_kerberos)
X					kerberos(bp,
X					    tuser ? tuser : pwd->pw_name);
X				else
X#endif
X					rem = rcmd(&host, port, pwd->pw_name,
X					    tuser ? tuser : pwd->pw_name,
X					    bp, 0);
X				if (rem < 0)
X					exit(1);
X				if (response() < 0)
X					exit(1);
X				(void)free(bp);
X				(void)setuid(userid);
X			}
X			source(1, argv+i);
X		}
X	}
X}
X
Xtolocal(argc, argv)
X	int argc;
X	char **argv;
X{
X	int i;
X	char *bp, *host, *src, *suser;
X	char *colon(), *malloc();
X
X	for (i = 0; i < argc - 1; i++) {
X		if (!(src = colon(argv[i]))) {	/* local to local */
X			if (!(bp = malloc((u_int)(strlen(_PATH_CP) +
X			    strlen(argv[i]) + strlen(argv[argc - 1])) + 20)))
X				nospace();
X			(void)sprintf(bp, "%s%s%s %s %s", _PATH_CP,
X			    iamrecursive ? " -r" : "", pflag ? " -p" : "",
X			    argv[i], argv[argc - 1]);
X			(void)susystem(bp);
X			(void)free(bp);
X			continue;
X		}
X		*src++ = 0;
X		if (*src == 0)
X			src = ".";
X		host = index(argv[i], '@');
X		if (host) {
X			*host++ = 0;
X			suser = argv[i];
X			if (*suser == '\0')
X				suser = pwd->pw_name;
X			else if (!okname(suser))
X				continue;
X		} else {
X			host = argv[i];
X			suser = pwd->pw_name;
X		}
X		if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20)))
X			nospace();
X		(void)sprintf(bp, "%s -f %s", cmd, src);
X#ifdef KERBEROS
X		if (use_kerberos)
X			kerberos(bp, suser);
X		else
X#endif
X			rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0);
X		(void)free(bp);
X		if (rem < 0)
X			continue;
X		(void)setreuid(0, userid);
X		sink(1, argv + argc - 1);
X		(void)setreuid(userid, 0);
X		(void)close(rem);
X		rem = -1;
X	}
X}
X
X#ifdef KERBEROS
Xkerberos(bp, user)
X	char *bp, *user;
X{
X	struct servent *sp;
X	char *host;
X
Xagain:	rem = KSUCCESS;
X	if (krb_realm[0] == '\0')
X		rem = krb_get_lrealm(krb_realm, 1);
X	if (rem == KSUCCESS) {
X		if (encrypt)
X			rem = krcmd_mutual(&host, port, user, bp, 0,
X			    krb_realm, &cred, schedule);
X		else
X			rem = krcmd(&host, port, user, bp, 0, krb_realm);
X	} else {
X		(void)fprintf(stderr,
X		    "rcp: error getting local realm %s\n", krb_err_txt[rem]);
X		exit(1);
X	}
X	if (rem < 0 && errno == ECONNREFUSED) {
X		use_kerberos = 0;
X		old_warning("remote host doesn't support Kerberos");
X		sp = getservbyname("shell", "tcp");
X		if (sp == NULL) {
X			(void)fprintf(stderr,
X			    "rcp: unknown service shell/tcp\n");
X			exit(1);
X		}
X		port = sp->s_port;
X		goto again;
X	}
X}
X#endif /* KERBEROS */
X
Xverifydir(cp)
X	char *cp;
X{
X	struct stat stb;
X
X	if (stat(cp, &stb) >= 0) {
X		if ((stb.st_mode & S_IFMT) == S_IFDIR)
X			return;
X		errno = ENOTDIR;
X	}
X	error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
X	exit(1);
X}
X
Xchar *
Xcolon(cp)
X	register char *cp;
X{
X	for (; *cp; ++cp) {
X		if (*cp == ':')
X			return(cp);
X		if (*cp == '/')
X			return(0);
X	}
X	return(0);
X}
X
Xokname(cp0)
X	char *cp0;
X{
X	register char *cp = cp0;
X	register int c;
X
X	do {
X		c = *cp;
X		if (c & 0200)
X			goto bad;
X		if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
X			goto bad;
X	} while (*++cp);
X	return(1);
Xbad:
X	(void)fprintf(stderr, "rcp: invalid user name %s\n", cp0);
X	return(0);
X}
X
Xsusystem(s)
X	char *s;
X{
X	int status, pid, w;
X	register int (*istat)(), (*qstat)();
X
X	if ((pid = vfork()) == 0) {
X		(void)setuid(userid);
X		execl(_PATH_BSHELL, "sh", "-c", s, (char *)0);
X		_exit(127);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X	if (w == -1)
X		status = -1;
X	(void)signal(SIGINT, istat);
X	(void)signal(SIGQUIT, qstat);
X	return(status);
X}
X
Xsource(argc, argv)
X	int argc;
X	char **argv;
X{
X	struct stat stb;
X	static BUF buffer;
X	BUF *bp;
X	off_t i;
X	int x, readerr, f, amt;
X	char *last, *name, buf[BUFSIZ];
X	BUF *allocbuf();
X
X	for (x = 0; x < argc; x++) {
X		name = argv[x];
X		if ((f = open(name, O_RDONLY, 0)) < 0) {
X			error("rcp: %s: %s\n", name, sys_errlist[errno]);
X			continue;
X		}
X		if (fstat(f, &stb) < 0)
X			goto notreg;
X		switch (stb.st_mode&S_IFMT) {
X
X		case S_IFREG:
X			break;
X
X		case S_IFDIR:
X			if (iamrecursive) {
X				(void)close(f);
X				rsource(name, &stb);
X				continue;
X			}
X			/* FALLTHROUGH */
X		default:
Xnotreg:			(void)close(f);
X			error("rcp: %s: not a plain file\n", name);
X			continue;
X		}
X		last = rindex(name, '/');
X		if (last == 0)
X			last = name;
X		else
X			last++;
X		if (pflag) {
X			/*
X			 * Make it compatible with possible future
X			 * versions expecting microseconds.
X			 */
X			(void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime,
X			    stb.st_atime);
X			(void)write(rem, buf, strlen(buf));
X			if (response() < 0) {
X				(void)close(f);
X				continue;
X			}
X		}
X		(void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777,
X		    stb.st_size, last);
X		(void)write(rem, buf, strlen(buf));
X		if (response() < 0) {
X			(void)close(f);
X			continue;
X		}
X		if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
X			(void)close(f);
X			continue;
X		}
X		readerr = 0;
X		for (i = 0; i < stb.st_size; i += bp->cnt) {
X			amt = bp->cnt;
X			if (i + amt > stb.st_size)
X				amt = stb.st_size - i;
X			if (readerr == 0 && read(f, bp->buf, amt) != amt)
X				readerr = errno;
X			(void)write(rem, bp->buf, amt);
X		}
X		(void)close(f);
X		if (readerr == 0)
X			(void)write(rem, "", 1);
X		else
X			error("rcp: %s: %s\n", name, sys_errlist[readerr]);
X		(void)response();
X	}
X}
X
Xrsource(name, statp)
X	char *name;
X	struct stat *statp;
X{
X	DIR *d;
X	struct direct *dp;
X	char *last, *vect[1], path[MAXPATHLEN];
X
X	if (!(d = opendir(name))) {
X		error("rcp: %s: %s\n", name, sys_errlist[errno]);
X		return;
X	}
X	last = rindex(name, '/');
X	if (last == 0)
X		last = name;
X	else
X		last++;
X	if (pflag) {
X		(void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime,
X		    statp->st_atime);
X		(void)write(rem, path, strlen(path));
X		if (response() < 0) {
X			closedir(d);
X			return;
X		}
X	}
X	(void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
X	(void)write(rem, path, strlen(path));
X	if (response() < 0) {
X		closedir(d);
X		return;
X	}
X	while (dp = readdir(d)) {
X		if (dp->d_ino == 0)
X			continue;
X		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
X			continue;
X		if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
X			error("%s/%s: name too long.\n", name, dp->d_name);
X			continue;
X		}
X		(void)sprintf(path, "%s/%s", name, dp->d_name);
X		vect[0] = path;
X		source(1, vect);
X	}
X	closedir(d);
X	(void)write(rem, "E\n", 2);
X	(void)response();
X}
X
Xresponse()
X{
X	register char *cp;
X	char ch, resp, rbuf[BUFSIZ];
X
X	if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
X		lostconn();
X
X	cp = rbuf;
X	switch(resp) {
X	case 0:				/* ok */
X		return(0);
X	default:
X		*cp++ = resp;
X		/* FALLTHROUGH */
X	case 1:				/* error, followed by err msg */
X	case 2:				/* fatal error, "" */
X		do {
X			if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
X				lostconn();
X			*cp++ = ch;
X		} while (cp < &rbuf[BUFSIZ] && ch != '\n');
X
X		if (!iamremote)
X			(void)write(2, rbuf, cp - rbuf);
X		++errs;
X		if (resp == 1)
X			return(-1);
X		exit(1);
X	}
X	/*NOTREACHED*/
X}
X
Xlostconn()
X{
X	if (!iamremote)
X		(void)fprintf(stderr, "rcp: lost connection\n");
X	exit(1);
X}
X
Xsink(argc, argv)
X	int argc;
X	char **argv;
X{
X	register char *cp;
X	static BUF buffer;
X	struct stat stb;
X	struct timeval tv[2];
X	BUF *bp, *allocbuf();
X	off_t i, j;
X	char ch, *targ, *why;
X	int amt, count, exists, first, mask, mode;
X	int ofd, setimes, size, targisdir, wrerr;
X	char *np, *vect[1], buf[BUFSIZ], *malloc();
X
X#define	atime	tv[0]
X#define	mtime	tv[1]
X#define	SCREWUP(str)	{ why = str; goto screwup; }
X
X	setimes = targisdir = 0;
X	mask = umask(0);
X	if (!pflag)
X		(void)umask(mask);
X	if (argc != 1) {
X		error("rcp: ambiguous target\n");
X		exit(1);
X	}
X	targ = *argv;
X	if (targetshouldbedirectory)
X		verifydir(targ);
X	(void)write(rem, "", 1);
X	if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
X		targisdir = 1;
X	for (first = 1;; first = 0) {
X		cp = buf;
X		if (read(rem, cp, 1) <= 0)
X			return;
X		if (*cp++ == '\n')
X			SCREWUP("unexpected <newline>");
X		do {
X			if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
X				SCREWUP("lost connection");
X			*cp++ = ch;
X		} while (cp < &buf[BUFSIZ - 1] && ch != '\n');
X		*cp = 0;
X
X		if (buf[0] == '\01' || buf[0] == '\02') {
X			if (iamremote == 0)
X				(void)write(2, buf + 1, strlen(buf + 1));
X			if (buf[0] == '\02')
X				exit(1);
X			errs++;
X			continue;
X		}
X		if (buf[0] == 'E') {
X			(void)write(rem, "", 1);
X			return;
X		}
X
X		if (ch == '\n')
X			*--cp = 0;
X
X#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
X		cp = buf;
X		if (*cp == 'T') {
X			setimes++;
X			cp++;
X			getnum(mtime.tv_sec);
X			if (*cp++ != ' ')
X				SCREWUP("mtime.sec not delimited");
X			getnum(mtime.tv_usec);
X			if (*cp++ != ' ')
X				SCREWUP("mtime.usec not delimited");
X			getnum(atime.tv_sec);
X			if (*cp++ != ' ')
X				SCREWUP("atime.sec not delimited");
X			getnum(atime.tv_usec);
X			if (*cp++ != '\0')
X				SCREWUP("atime.usec not delimited");
X			(void)write(rem, "", 1);
X			continue;
X		}
X		if (*cp != 'C' && *cp != 'D') {
X			/*
X			 * Check for the case "rcp remote:foo\* local:bar".
X			 * In this case, the line "No match." can be returned
X			 * by the shell before the rcp command on the remote is
X			 * executed so the ^Aerror_message convention isn't
X			 * followed.
X			 */
X			if (first) {
X				error("%s\n", cp);
X				exit(1);
X			}
X			SCREWUP("expected control record");
X		}
X		mode = 0;
X		for (++cp; cp < buf + 5; cp++) {
X			if (*cp < '0' || *cp > '7')
X				SCREWUP("bad mode");
X			mode = (mode << 3) | (*cp - '0');
X		}
X		if (*cp++ != ' ')
X			SCREWUP("mode not delimited");
X		size = 0;
X		while (isdigit(*cp))
X			size = size * 10 + (*cp++ - '0');
X		if (*cp++ != ' ')
X			SCREWUP("size not delimited");
X		if (targisdir) {
X			static char *namebuf;
X			static int cursize;
X			int need;
X
X			need = strlen(targ) + strlen(cp) + 250;
X			if (need > cursize) {
X				if (!(namebuf = malloc((u_int)need)))
X					error("out of memory\n");
X			}
X			(void)sprintf(namebuf, "%s%s%s", targ,
X			    *targ ? "/" : "", cp);
X			np = namebuf;
X		}
X		else
X			np = targ;
X		exists = stat(np, &stb) == 0;
X		if (buf[0] == 'D') {
X			if (exists) {
X				if ((stb.st_mode&S_IFMT) != S_IFDIR) {
X					errno = ENOTDIR;
X					goto bad;
X				}
X				if (pflag)
X					(void)chmod(np, mode);
X			} else if (mkdir(np, mode) < 0)
X				goto bad;
X			vect[0] = np;
X			sink(1, vect);
X			if (setimes) {
X				setimes = 0;
X				if (utimes(np, tv) < 0)
X				    error("rcp: can't set times on %s: %s\n",
X					np, sys_errlist[errno]);
X			}
X			continue;
X		}
X		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
Xbad:			error("rcp: %s: %s\n", np, sys_errlist[errno]);
X			continue;
X		}
X		if (exists && pflag)
X			(void)fchmod(ofd, mode);
X		(void)write(rem, "", 1);
X		if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) {
X			(void)close(ofd);
X			continue;
X		}
X		cp = bp->buf;
X		count = 0;
X		wrerr = 0;
X		for (i = 0; i < size; i += BUFSIZ) {
X			amt = BUFSIZ;
X			if (i + amt > size)
X				amt = size - i;
X			count += amt;
X			do {
X				j = read(rem, cp, amt);
X				if (j <= 0) {
X					error("rcp: %s\n",
X					    j ? sys_errlist[errno] :
X					    "dropped connection");
X					exit(1);
X				}
X				amt -= j;
X				cp += j;
X			} while (amt > 0);
X			if (count == bp->cnt) {
X				if (wrerr == 0 &&
X				    write(ofd, bp->buf, count) != count)
X					wrerr++;
X				count = 0;
X				cp = bp->buf;
X			}
X		}
X		if (count != 0 && wrerr == 0 &&
X		    write(ofd, bp->buf, count) != count)
X			wrerr++;
X		if (ftruncate(ofd, size))
X			error("rcp: can't truncate %s: %s\n", np,
X			    sys_errlist[errno]);
X		(void)close(ofd);
X		(void)response();
X		if (setimes) {
X			setimes = 0;
X			if (utimes(np, tv) < 0)
X				error("rcp: can't set times on %s: %s\n",
X				    np, sys_errlist[errno]);
X		}				   
X		if (wrerr)
X			error("rcp: %s: %s\n", np, sys_errlist[errno]);
X		else
X			(void)write(rem, "", 1);
X	}
Xscrewup:
X	error("rcp: protocol screwup: %s\n", why);
X	exit(1);
X}
X
XBUF *
Xallocbuf(bp, fd, blksize)
X	BUF *bp;
X	int fd, blksize;
X{
X	struct stat stb;
X	int size;
X	char *malloc();
X
X	if (fstat(fd, &stb) < 0) {
X		error("rcp: fstat: %s\n", sys_errlist[errno]);
X		return(0);
X	}
X	size = roundup(stb.st_blksize, blksize);
X	if (size == 0)
X		size = blksize;
X	if (bp->cnt < size) {
X		if (bp->buf != 0)
X			free(bp->buf);
X		bp->buf = (char *)malloc((u_int)size);
X		if (!bp->buf) {
X			error("rcp: malloc: out of memory\n");
X			return(0);
X		}
X	}
X	bp->cnt = size;
X	return(bp);
X}
X
X/* VARARGS1 */
Xerror(fmt, a1, a2, a3)
X	char *fmt;
X	int a1, a2, a3;
X{
X	static FILE *fp;
X
X	++errs;
X	if (!fp && !(fp = fdopen(rem, "w")))
X		return;
X	(void)fprintf(fp, "%c", 0x01);
X	(void)fprintf(fp, fmt, a1, a2, a3);
X	(void)fflush(fp);
X	if (!iamremote)
X		(void)fprintf(stderr, fmt, a1, a2, a3);
X}
X
Xnospace()
X{
X	(void)fprintf(stderr, "rcp: out of memory.\n");
X	exit(1);
X}
X
X#ifdef KERBEROS
Xold_warning(str)
X	char *str;
X{
X	(void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str);
X}
X#endif
X
Xusage()
X{
X#ifdef KERBEROS
X	(void)fprintf(stderr, "%s\n\t%s\n",
X	    "usage: rcp [-k realm] [-px] f1 f2",
X	    "or: rcp [-k realm] [-rpx] f1 ... fn directory");
X#else
X	(void)fprintf(stderr,
X	    "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n");
X#endif
X	exit(1);
X}
END-of-rcp.c
echo x - rdist.server.c.diff
sed 's/^X//' >rdist.server.c.diff << 'END-of-rdist.server.c.diff'
X*** old_server.c	Wed Jun 29 20:19:34 1988
X--- server.c	Wed May 24 20:17:51 1989
X***************
X*** 1369,1384 ****
X  	char *fmt;
X  	int a1, a2, a3;
X  {
X! 	nerrs++;
X! 	strcpy(buf, "\1rdist: ");
X! 	(void) sprintf(buf+8, fmt, a1, a2, a3);
X! 	if (!iamremote) {
X  		fflush(stdout);
X! 		(void) write(2, buf+1, strlen(buf+1));
X! 	} else
X! 		(void) write(rem, buf, strlen(buf));
X! 	if (lfp != NULL)
X! 		(void) fwrite(buf+1, 1, strlen(buf+1), lfp);
X  }
X  
X  /*VARARGS1*/
X--- 1369,1395 ----
X  	char *fmt;
X  	int a1, a2, a3;
X  {
X! 	static FILE *fp;
X! 
X! 	++nerrs;
X! 	if (!fp && !(fp = fdopen(rem, "w")))
X! 		return;
X! 	if (iamremote) {
X! 		(void)fprintf(fp, "%crdist: ", 0x01);
X! 		(void)fprintf(fp, fmt, a1, a2, a3);
X! 		fflush(fp);
X! 	}
X! 	else {
X  		fflush(stdout);
X! 		(void)fprintf(stderr, "rdist: ");
X! 		(void)fprintf(stderr, fmt, a1, a2, a3);
X! 		fflush(stderr);
X! 	}
X! 	if (lfp != NULL) {
X! 		(void)fprintf(lfp, "rdist: ");
X! 		(void)fprintf(lfp, fmt, a1, a2, a3);
X! 		fflush(lfp);
X! 	}
X  }
X  
X  /*VARARGS1*/
X***************
X*** 1386,1401 ****
X  	char *fmt;
X  	int a1, a2, a3;
X  {
X! 	nerrs++;
X! 	strcpy(buf, "\2rdist: ");
X! 	(void) sprintf(buf+8, fmt, a1, a2, a3);
X! 	if (!iamremote) {
X  		fflush(stdout);
X! 		(void) write(2, buf+1, strlen(buf+1));
X! 	} else
X! 		(void) write(rem, buf, strlen(buf));
X! 	if (lfp != NULL)
X! 		(void) fwrite(buf+1, 1, strlen(buf+1), lfp);
X  	cleanup();
X  }
X  
X--- 1397,1423 ----
X  	char *fmt;
X  	int a1, a2, a3;
X  {
X! 	static FILE *fp;
X! 
X! 	++nerrs;
X! 	if (!fp && !(fp = fdopen(rem, "w")))
X! 		return;
X! 	if (iamremote) {
X! 		(void)fprintf(fp, "%crdist: ", 0x02);
X! 		(void)fprintf(fp, fmt, a1, a2, a3);
X! 		fflush(fp);
X! 	}
X! 	else {
X  		fflush(stdout);
X! 		(void)fprintf(stderr, "rdist: ");
X! 		(void)fprintf(stderr, fmt, a1, a2, a3);
X! 		fflush(stderr);
X! 	}
X! 	if (lfp != NULL) {
X! 		(void)fprintf(lfp, "rdist: ");
X! 		(void)fprintf(lfp, fmt, a1, a2, a3);
X! 		fflush(lfp);
X! 	}
X  	cleanup();
X  }
X  
END-of-rdist.server.c.diff
exit


TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH