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

📄 ssh_ftp.c

📁 UNIX环境下命令行FTP/SFTP工具源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Modified for use in Yafc by Martin Hedenfalk <mhe@stacken.kth.se> * * Original copyright: * * Copyright (c) 2001 Damien Miller.  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. */#include "syshdr.h"#include "ftp.h"#include "ssh_ftp.h"#include "buffer.h"#include "bufaux.h"#include "getput.h"#include "atomicio.h"#include "gvars.h"int use_ssh1 = 0;#define COPY_SIZE 8192int ssh_connect(char **args, int *in, int *out, pid_t *sshpid){	int c_in, c_out;#ifdef USE_PIPES	int pin[2], pout[2];	if ((pipe(pin) == -1) || (pipe(pout) == -1)) {		ftp_err("pipe: %s\n", strerror(errno));		return -1;	}	*in = pin[0];	*out = pout[1];	c_in = pout[0];	c_out = pin[1];#else /* USE_PIPES */	int inout[2];	if(socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) {		ftp_err("socketpair: %s\n", strerror(errno));		return -1;	}	*in = *out = inout[0];	c_in = c_out = inout[1];#endif /* USE_PIPES */	if ((*sshpid = fork()) == -1) {		ftp_err("fork: %s\n", strerror(errno));		return -1;	} else if (*sshpid == 0) {		if ((dup2(c_in, /*STDIN_FILENO*/ 0) == -1) ||		    (dup2(c_out, /*STDOUT_FILENO*/ 1) == -1)) {			ftp_err("dup2: %s\n", strerror(errno));			exit(1);		}		close(*in);		close(*out);		close(c_in);		close(c_out);		execv(gvSSHProgram, args);		ftp_err("exec: %s: %s\n", gvSSHProgram, strerror(errno));		exit(1);	}	close(c_in);	close(c_out);	return 0;}static const char *ssh_cmd2txt(int code){	static const char *strings[] = {		"",		"SSH2_FXP_INIT", /* 1 */		"",		"SSH2_FXP_OPEN", /* 3 */		"SSH2_FXP_CLOSE",		"SSH2_FXP_READ",		"SSH2_FXP_WRITE",		"SSH2_FXP_LSTAT",		"SSH2_FXP_FSTAT",		"SSH2_FXP_SETSTAT",		"SSH2_FXP_FSETSTAT", /* 10 */		"SSH2_FXP_OPENDIR",		"SSH2_FXP_READDIR",		"SSH2_FXP_REMOVE",		"SSH2_FXP_MKDIR",		"SSH2_FXP_RMDIR",		"SSH2_FXP_REALPATH",		"SSH2_FXP_STAT",		"SSH2_FXP_RENAME",		"SSH2_FXP_READLINK",		"SSH2_FXP_SYMLINK" /* 20 */	};	if(code >= 1 && code <= 20)		return strings[code];	return "unknown command";}static void ssh_print_cmd(Buffer *cmd){	char code;	void (*pfunc)(const char *fmt, ...);	char *e;	code = buffer_ptr(cmd)[4];	if(ftp_get_verbosity() == vbDebug)		pfunc = ftp_err;	else		pfunc = ftp_trace;	pfunc("--> [%s] ", ftp->url ? ftp->url->hostname : "?");	pfunc("%s", ssh_cmd2txt(code));	switch(code) {		case SSH2_FXP_OPEN:			cmd->offset = 9;			e = buffer_get_string(cmd, 0);			pfunc("(%s)", e);			free(e);			break;		case SSH2_FXP_WRITE:			cmd->offset = 9;			buffer_consume(cmd, buffer_get_int(cmd));			pfunc("(offset %ld)", buffer_get_int64(cmd));			break;	}	pfunc("\n");}/* sends an SSH command on the control channel * returns 0 on success or -1 on error */int ssh_cmd(Buffer *m){	int mlen = buffer_len(m);	int len;	Buffer oqueue;	buffer_init(&oqueue);	buffer_put_int(&oqueue, mlen);	buffer_append(&oqueue, buffer_ptr(m), mlen);	buffer_consume(m, mlen);	len = atomicio(write, ftp->ssh_out, buffer_ptr(&oqueue),				   buffer_len(&oqueue));	ssh_print_cmd(&oqueue);	buffer_free(&oqueue);	if(len <= 0) {		ftp_err("Couldn't send packet: %s\n", strerror(errno));		return -1;	}	return 0;}static const char *ssh_reply2txt(int code){	static const char *strings[] = {		"SSH2_FXP_VERSION", /* 2 */		"SSH2_FXP_STATUS",  /* 101 */		"SSH2_FXP_HANDLE",  /* 102 */		"SSH2_FXP_DATA",    /* 103 */		"SSH2_FXP_NAME",    /* 104 */		"SSH2_FXP_ATTRS",   /* 105 */	};	if(code == 2)		return strings[0];	else if(code >= 101 && code <= 105)		return strings[code - 100];	return "unknown reply";}static void ssh_print_reply(int code){	verbose_t v = ftp_get_verbosity();	ftp_trace("<-- [%s] %s\n",			  ftp->url ? ftp->url->hostname : ftp->host->hostname,			  ssh_reply2txt(code));	if(v >= vbCommand || (ftp->code >= ctTransient && v == vbError)) {		if(v == vbDebug)			fprintf(stderr, "<-- [%s] %s\n",					ftp->url ? ftp->url->hostname : ftp->host->hostname,					ssh_reply2txt(code));		else			fprintf(stderr, "%s\n", ssh_reply2txt(code));	}}int ssh_reply(Buffer *m){	u_int len, msg_len;	char buf[4096];	bool reply_printed = false;	len = atomicio(read, ftp->ssh_in, buf, 4);	if(len == 0) {		ftp_err("Connection closed\n");		return -1;	} else if(len == -1) {		ftp_err("Couldn't read packet: %s\n", strerror(errno));		return -1;	}	msg_len = GET_32BIT(buf);	if(msg_len > 256 * 1024) {		ftp_err("Received message too long %d\n", msg_len);		return -1;	}	while(msg_len) {		len = atomicio(read, ftp->ssh_in, buf, min(msg_len, sizeof(buf)));		if(len == 0) {			ftp_err("Connection closed\n");			return -1;		} else if (len == -1) {			ftp_err("Couldn't read packet: %s\n", strerror(errno));			return -1;		}		if(!reply_printed) {			ssh_print_reply(buf[0]);			reply_printed = true;		}		msg_len -= len;		buffer_append(m, buf, len);	}	ftp->fullcode = 200;	ftp->code = ctComplete;	return 0;}/* returns SSH version on success, -1 on failure */int ssh_init(void){	int type, version;	Buffer msg;	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_INIT);	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);	if(ssh_cmd(&msg) == -1)		return -1;	buffer_clear(&msg);	if(ssh_reply(&msg) == -1)		return -1;	/* Expecting a VERSION reply */	if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {		ftp_err("Invalid packet back from SSH2_FXP_INIT (type %d)\n", type);		buffer_free(&msg);		return -1;	}	version = buffer_get_int(&msg);	/* Check for extensions */	while(buffer_len(&msg) > 0) {		char *name = buffer_get_string(&msg, NULL);		char *value = buffer_get_string(&msg, NULL);		ftp_err("Init extension: \"%s\"\n", name);		free(name);		free(value);	}	buffer_free(&msg);	return version;}char *ssh_realpath(char *path){	Buffer msg;	u_int type, expected_id, count, id;	char *filename, *longname;	Attrib *a;	expected_id = id = ftp->ssh_id++;	ssh_send_string_request(id, SSH2_FXP_REALPATH, path, strlen(path));	buffer_init(&msg);	if(ssh_reply(&msg) == -1)		return 0;	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	if(id != expected_id) {		ftp_err("ID mismatch (%d != %d)\n", id, expected_id);		return 0;	}	if(type == SSH2_FXP_STATUS) {		u_int status = buffer_get_int(&msg);		ftp_err("Couldn't canonicalise: %s\n", fx2txt(status));		return 0;	} else if(type != SSH2_FXP_NAME) {		ftp_err("Expected SSH2_FXP_NAME(%d) packet, got %s (%d)\n",				SSH2_FXP_NAME, ssh_reply2txt(type), type);		return 0;	}	count = buffer_get_int(&msg);	if(count != 1) {		ftp_err("Got multiple names (%d) from SSH_FXP_REALPATH\n", count);		return 0;	}	filename = buffer_get_string(&msg, NULL);	longname = buffer_get_string(&msg, NULL);	a = decode_attrib(&msg);	free(longname);	buffer_free(&msg);	return filename;}Attrib *ssh_stat(const char *path){	u_int id;	id = ftp->ssh_id++;	ssh_send_string_request(id, SSH2_FXP_STAT, path, strlen(path));	return ssh_get_decode_stat(id);}Attrib *do_lstat(const char *path){	u_int id;	id = ftp->ssh_id++;	ssh_send_string_request(id, SSH2_FXP_LSTAT, path, strlen(path));	return ssh_get_decode_stat(id);}Attrib *do_fstat(char *handle, u_int handle_len){	u_int id;	id = ftp->ssh_id++;	ssh_send_string_request(id, SSH2_FXP_FSTAT, handle, handle_len);	return ssh_get_decode_stat(id);}int ssh_setstat(const char *path, Attrib *a){	u_int status, id;	id = ftp->ssh_id++;	ssh_send_string_attrs_request(id, SSH2_FXP_SETSTAT, path,								  strlen(path), a);	status = ssh_get_status(id);	if(status != SSH2_FX_OK) {		ftp_err("Couldn't setstat on \"%s\": %s\n", path,				fx2txt(status));		return -1;	}	return 0;}char *ssh_get_handle(u_int expected_id, u_int *len){	Buffer msg;	u_int type, id;	char *handle;	buffer_init(&msg);	if(ssh_reply(&msg) == -1)		return 0;	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	if(id != expected_id) {		ftp_err("ID mismatch (%d != %d)\n", id, expected_id);		return 0;	}	if(type == SSH2_FXP_STATUS) {		int status = buffer_get_int(&msg);		ftp_err("Couldn't get handle: %s\n", fx2txt(status));		return NULL;	} else if (type != SSH2_FXP_HANDLE) {		ftp_err("Expected SSH2_FXP_HANDLE(%d) packet, got %s (%d)\n",				SSH2_FXP_HANDLE, ssh_reply2txt(type), type);		return 0;	}	handle = buffer_get_string(&msg, len);	buffer_free(&msg);	return handle;}int ssh_readdir(char *path, SFTP_DIRENT ***dir){	Buffer msg;	u_int type, id, handle_len, i, expected_id, ents = 0;	char *handle;	id = ftp->ssh_id++;	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_OPENDIR);	buffer_put_int(&msg, id);	buffer_put_cstring(&msg, path);	if(ssh_cmd(&msg) == -1)		return -1;	buffer_clear(&msg);	handle = ssh_get_handle(id, &handle_len);	if(handle == 0)		return -1;	if(dir) {		ents = 0;		*dir = xmalloc(sizeof(**dir));		(*dir)[0] = NULL;	}	while(true) {		int count;		id = expected_id = ftp->ssh_id++;		buffer_clear(&msg);		buffer_put_char(&msg, SSH2_FXP_READDIR);		buffer_put_int(&msg, id);		buffer_put_string(&msg, handle, handle_len);		if(ssh_cmd(&msg) == -1)			return -1;		buffer_clear(&msg);		if(ssh_reply(&msg) == -1)			return -1;		type = buffer_get_char(&msg);		id = buffer_get_int(&msg);

⌨️ 快捷键说明

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