⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scp.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * scp - secure remote copy.  This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). * * NOTE: This version should NOT be suid root.  (This uses ssh to * do the transfer and ssh has the necessary privileges.) * * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose.  Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". *//* * Copyright (c) 1999 Theo de Raadt.  All rights reserved. * Copyright (c) 1999 Aaron Campbell.  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. *//* * Parts from: * * Copyright (c) 1983, 1990, 1992, 1993, 1995 *	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. * */#include "includes.h"RCSID("$OpenBSD: scp.c,v 1.91 2002/06/19 00:27:55 deraadt Exp $");#include "xmalloc.h"#include "atomicio.h"#include "pathnames.h"#include "log.h"#include "misc.h"#ifdef HAVE___PROGNAMEextern char *__progname;#elsechar *__progname;#endif/* For progressmeter() -- number of seconds before xfer considered "stalled" */#define STALLTIME	5/* alarm() interval for updating progress meter */#define PROGRESSTIME	1/* Visual statistics about files as they are transferred. */void progressmeter(int);/* Returns width of the terminal (for progress meter calculations). */int getttywidth(void);int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);/* Struct for addargs */arglist args;/* Time a transfer started. */static struct timeval start;/* Number of bytes of current file transferred so far. */volatile off_t statbytes;/* Total size of current file. */off_t totalbytes = 0;/* Name of current file being transferred. */char *curfile;/* This is set to non-zero to enable verbose mode. */int verbose_mode = 0;/* This is set to zero if the progressmeter is not desired. */int showprogress = 1;/* This is the program to execute for the secured connection. ("ssh" or -S) */char *ssh_program = _PATH_SSH_PROGRAM;/* * This function executes the given command as the specified user on the * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This * assigns the input and output file descriptors on success. */intdo_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc){	int pin[2], pout[2], reserved[2];	if (verbose_mode)		fprintf(stderr,		    "Executing: program %s host %s, user %s, command %s\n",		    ssh_program, host,		    remuser ? remuser : "(unspecified)", cmd);	/*	 * Reserve two descriptors so that the real pipes won't get	 * descriptors 0 and 1 because that will screw up dup2 below.	 */	pipe(reserved);	/* Create a socket pair for communicating with ssh. */	if (pipe(pin) < 0)		fatal("pipe: %s", strerror(errno));	if (pipe(pout) < 0)		fatal("pipe: %s", strerror(errno));	/* Free the reserved descriptors. */	close(reserved[0]);	close(reserved[1]);	/* For a child to execute the command on the remote host using ssh. */	if (fork() == 0)  {		/* Child. */		close(pin[1]);		close(pout[0]);		dup2(pin[0], 0);		dup2(pout[1], 1);		close(pin[0]);		close(pout[1]);		args.list[0] = ssh_program;		if (remuser != NULL)			addargs(&args, "-l%s", remuser);		addargs(&args, "%s", host);		addargs(&args, "%s", cmd);		execvp(ssh_program, args.list);		perror(ssh_program);		exit(1);	}	/* Parent.  Close the other side, and return the local side. */	close(pin[0]);	*fdout = pin[1];	close(pout[1]);	*fdin = pout[0];	return 0;}typedef struct {	int cnt;	char *buf;} BUF;BUF *allocbuf(BUF *, int, int);void lostconn(int);void nospace(void);int okname(char *);void run_err(const char *,...);void verifydir(char *);struct passwd *pwd;uid_t userid;int errs, remin, remout;int pflag, iamremote, iamrecursive, targetshouldbedirectory;#define	CMDNEEDS	64char 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);intmain(argc, argv)	int argc;	char *argv[];{	int ch, fflag, tflag;	char *targ;	extern char *optarg;	extern int optind;	__progname = get_progname(argv[0]);	args.list = NULL;	addargs(&args, "ssh");		/* overwritten with ssh_program */	addargs(&args, "-x");	addargs(&args, "-oForwardAgent no");	addargs(&args, "-oClearAllForwardings yes");	fflag = tflag = 0;	while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:F:")) != -1)		switch (ch) {		/* User-visible flags. */		case '4':		case '6':		case 'C':			addargs(&args, "-%c", ch);			break;		case 'o':		case 'c':		case 'i':		case 'F':			addargs(&args, "-%c%s", ch, optarg);			break;		case 'P':			addargs(&args, "-p%s", optarg);			break;		case 'B':			addargs(&args, "-oBatchmode yes");			break;		case 'p':			pflag = 1;			break;		case 'r':			iamrecursive = 1;			break;		case 'S':			ssh_program = xstrdup(optarg);			break;		case 'v':			addargs(&args, "-v");			verbose_mode = 1;			break;		case 'q':			showprogress = 0;			break;		/* Server options. */		case 'd':			targetshouldbedirectory = 1;			break;		case 'f':	/* "from" */			iamremote = 1;			fflag = 1;			break;		case 't':	/* "to" */			iamremote = 1;			tflag = 1;#ifdef HAVE_CYGWIN			setmode(0, O_BINARY);#endif			break;		default:			usage();		}	argc -= optind;	argv += optind;	if ((pwd = getpwuid(userid = getuid())) == NULL)		fatal("unknown user %d", (int) userid);	if (!isatty(STDERR_FILENO))		showprogress = 0;	remin = STDIN_FILENO;	remout = STDOUT_FILENO;	if (fflag) {		/* Follow "protocol", send data. */		(void) response();		source(argc, argv);		exit(errs != 0);	}	if (tflag) {		/* Receive data. */		sink(argc, argv);		exit(errs != 0);	}	if (argc < 2)		usage();	if (argc > 2)		targetshouldbedirectory = 1;	remin = remout = -1;	/* Command to be executed on remote system using "ssh". */	(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",	    verbose_mode ? " -v" : "",	    iamrecursive ? " -r" : "", pflag ? " -p" : "",	    targetshouldbedirectory ? " -d" : "");	(void) signal(SIGPIPE, lostconn);	if ((targ = colon(argv[argc - 1])))	/* Dest is remote host. */		toremote(targ, argc, argv);	else {		tolocal(argc, argv);	/* Dest is local host. */		if (targetshouldbedirectory)			verifydir(argv[argc - 1]);	}	exit(errs != 0);}voidtoremote(targ, argc, argv)	char *targ, *argv[];	int argc;{	int i, len;	char *bp, *host, *src, *suser, *thost, *tuser;	*targ++ = 0;	if (*targ == 0)		targ = ".";	if ((thost = strchr(argv[argc - 1], '@'))) {		/* 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;	}	for (i = 0; i < argc - 1; i++) {		src = colon(argv[i]);		if (src) {	/* remote to remote */			static char *ssh_options =			    "-x -o'ClearAllForwardings yes'";			*src++ = 0;			if (*src == 0)				src = ".";			host = strchr(argv[i], '@');			len = strlen(ssh_program) + strlen(argv[i]) +			    strlen(src) + (tuser ? strlen(tuser) : 0) +			    strlen(thost) + strlen(targ) +			    strlen(ssh_options) + CMDNEEDS + 20;			bp = xmalloc(len);			if (host) {				*host++ = 0;				host = cleanhostname(host);				suser = argv[i];				if (*suser == '\0')					suser = pwd->pw_name;				else if (!okname(suser))					continue;				snprintf(bp, len,				    "%s%s %s -n "				    "-l %s %s %s %s '%s%s%s:%s'",				    ssh_program, verbose_mode ? " -v" : "",				    ssh_options, suser, host, cmd, src,				    tuser ? tuser : "", tuser ? "@" : "",				    thost, targ);			} else {				host = cleanhostname(argv[i]);				snprintf(bp, len,				    "exec %s%s %s -n %s "				    "%s %s '%s%s%s:%s'",				    ssh_program, verbose_mode ? " -v" : "",				    ssh_options, host, cmd, src,				    tuser ? tuser : "", tuser ? "@" : "",				    thost, targ);			}			if (verbose_mode)				fprintf(stderr, "Executing: %s\n", bp);			(void) system(bp);			(void) xfree(bp);		} else {	/* local to remote */			if (remin == -1) {				len = strlen(targ) + CMDNEEDS + 20;				bp = xmalloc(len);				(void) snprintf(bp, len, "%s -t %s", cmd, targ);				host = cleanhostname(thost);				if (do_cmd(host, tuser, bp, &remin,				    &remout, argc) < 0)					exit(1);				if (response() < 0)					exit(1);				(void) xfree(bp);			}			source(1, argv + i);		}	}}voidtolocal(argc, argv)	int argc;	char *argv[];{	int i, 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;			bp = xmalloc(len);			(void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,			    iamrecursive ? " -r" : "", pflag ? " -p" : "",			    argv[i], argv[argc - 1]);			if (verbose_mode)				fprintf(stderr, "Executing: %s\n", bp);			if (system(bp))				++errs;			(void) xfree(bp);			continue;		}		*src++ = 0;		if (*src == 0)			src = ".";		if ((host = strchr(argv[i], '@')) == NULL) {			host = argv[i];			suser = NULL;		} else {			*host++ = 0;			suser = argv[i];			if (*suser == '\0')				suser = pwd->pw_name;			else if (!okname(suser))				continue;		}		host = cleanhostname(host);		len = strlen(src) + CMDNEEDS + 20;		bp = xmalloc(len);		(void) snprintf(bp, len, "%s -f %s", cmd, src);		if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) {			(void) xfree(bp);			++errs;			continue;		}		xfree(bp);		sink(1, argv + argc - 1);		(void) close(remin);		remin = remout = -1;	}}voidsource(argc, argv)	int argc;	char *argv[];{	struct stat stb;	static BUF buffer;	BUF *bp;	off_t i, amt, result;	int fd, haderr, indx;	char *last, *name, buf[2048];	int len;	for (indx = 0; indx < argc; ++indx) {		name = argv[indx];		statbytes = 0;		len = strlen(name);		while (len > 1 && name[len-1] == '/')			name[--len] = '\0';		if (strchr(name, '\n') != NULL) {			run_err("%s: skipping, filename contains a newline",			    name);			goto next;		}		if ((fd = open(name, O_RDONLY, 0)) < 0)			goto syserr;		if (fstat(fd, &stb) < 0) {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;		curfile = last;		if (pflag) {			/*			 * Make it compatible with possible future			 * versions expecting microseconds.			 */			(void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",			    (u_long) stb.st_mtime,			    (u_long) stb.st_atime);			(void) atomicio(write, remout, buf, strlen(buf));			if (response() < 0)				goto next;		}#define	FILEMODEMASK	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)#ifdef HAVE_LONG_LONG_INT		snprintf(buf, sizeof buf, "C%04o %lld %s\n",		    (u_int) (stb.st_mode & FILEMODEMASK),		    (long long)stb.st_size, last);#else		/* XXX: Handle integer overflow? */		snprintf(buf, sizeof buf, "C%04o %lu %s\n",		    (u_int) (stb.st_mode & FILEMODEMASK),		    (u_long) stb.st_size, last);#endif		if (verbose_mode) {			fprintf(stderr, "Sending file modes: %s", buf);			fflush(stderr);		}		(void) atomicio(write, remout, buf, strlen(buf));		if (response() < 0)			goto next;		if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {next:			(void) close(fd);			continue;		}		if (showprogress) {			totalbytes = stb.st_size;			progressmeter(-1);		}		/* Keep writing after an error so that we stay sync'd up. */		for (haderr = 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 = atomicio(read, fd, bp->buf, amt);				if (result != amt)					haderr = result >= 0 ? EIO : errno;			}			if (haderr)				(void) atomicio(write, remout, bp->buf, amt);			else {				result = atomicio(write, remout, bp->buf, amt);				if (result != amt)					haderr = result >= 0 ? EIO : errno;				statbytes += result;			}		}		if (showprogress)			progressmeter(1);		if (close(fd) < 0 && !haderr)			haderr = errno;		if (!haderr)			(void) atomicio(write, remout, "", 1);		else			run_err("%s: %s", name, strerror(haderr));		(void) response();	}}voidrsource(name, statp)	char *name;	struct stat *statp;{	DIR *dirp;	struct dirent *dp;	char *last, *vect[1], path[1100];	if (!(dirp = opendir(name))) {		run_err("%s: %s", name, strerror(errno));		return;	}	last = strrchr(name, '/');

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -