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

📄 sftp-client.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2001,2002 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. *//* XXX: memleaks *//* XXX: signed vs unsigned *//* XXX: remove all logging, only return status codes *//* XXX: copy between two remote sites */#include "includes.h"RCSID("$OpenBSD: sftp-client.c,v 1.32 2002/06/09 13:32:01 markus Exp $");#include "openbsd-compat/fake-queue.h"#include "buffer.h"#include "bufaux.h"#include "getput.h"#include "xmalloc.h"#include "log.h"#include "atomicio.h"#include "sftp.h"#include "sftp-common.h"#include "sftp-client.h"/* Minimum amount of data to read at at time */#define MIN_READ_SIZE	512struct sftp_conn {	int fd_in;	int fd_out;	u_int transfer_buflen;	u_int num_requests;	u_int version;	u_int msg_id;};static voidsend_msg(int fd, 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, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));	if (len <= 0)		fatal("Couldn't send packet: %s", strerror(errno));	buffer_free(&oqueue);}static voidget_msg(int fd, Buffer *m){	u_int len, msg_len;	unsigned char buf[4096];	len = atomicio(read, fd, buf, 4);	if (len == 0)		fatal("Connection closed");	else if (len == -1)		fatal("Couldn't read packet: %s", strerror(errno));	msg_len = GET_32BIT(buf);	if (msg_len > 256 * 1024)		fatal("Received message too long %d", msg_len);	while (msg_len) {		len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));		if (len == 0)			fatal("Connection closed");		else if (len == -1)			fatal("Couldn't read packet: %s", strerror(errno));		msg_len -= len;		buffer_append(m, buf, len);	}}static voidsend_string_request(int fd, u_int id, u_int code, char *s,    u_int len){	Buffer msg;	buffer_init(&msg);	buffer_put_char(&msg, code);	buffer_put_int(&msg, id);	buffer_put_string(&msg, s, len);	send_msg(fd, &msg);	debug3("Sent message fd %d T:%d I:%d", fd, code, id);	buffer_free(&msg);}static voidsend_string_attrs_request(int fd, u_int id, u_int code, char *s,    u_int len, Attrib *a){	Buffer msg;	buffer_init(&msg);	buffer_put_char(&msg, code);	buffer_put_int(&msg, id);	buffer_put_string(&msg, s, len);	encode_attrib(&msg, a);	send_msg(fd, &msg);	debug3("Sent message fd %d T:%d I:%d", fd, code, id);	buffer_free(&msg);}static u_intget_status(int fd, int expected_id){	Buffer msg;	u_int type, id, status;	buffer_init(&msg);	get_msg(fd, &msg);	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	if (id != expected_id)		fatal("ID mismatch (%d != %d)", id, expected_id);	if (type != SSH2_FXP_STATUS)		fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",		    SSH2_FXP_STATUS, type);	status = buffer_get_int(&msg);	buffer_free(&msg);	debug3("SSH2_FXP_STATUS %d", status);	return(status);}static char *get_handle(int fd, u_int expected_id, u_int *len){	Buffer msg;	u_int type, id;	char *handle;	buffer_init(&msg);	get_msg(fd, &msg);	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	if (id != expected_id)		fatal("ID mismatch (%d != %d)", id, expected_id);	if (type == SSH2_FXP_STATUS) {		int status = buffer_get_int(&msg);		error("Couldn't get handle: %s", fx2txt(status));		return(NULL);	} else if (type != SSH2_FXP_HANDLE)		fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",		    SSH2_FXP_HANDLE, type);	handle = buffer_get_string(&msg, len);	buffer_free(&msg);	return(handle);}static Attrib *get_decode_stat(int fd, u_int expected_id, int quiet){	Buffer msg;	u_int type, id;	Attrib *a;	buffer_init(&msg);	get_msg(fd, &msg);	type = buffer_get_char(&msg);	id = buffer_get_int(&msg);	debug3("Received stat reply T:%d I:%d", type, id);	if (id != expected_id)		fatal("ID mismatch (%d != %d)", id, expected_id);	if (type == SSH2_FXP_STATUS) {		int status = buffer_get_int(&msg);		if (quiet)			debug("Couldn't stat remote file: %s", fx2txt(status));		else			error("Couldn't stat remote file: %s", fx2txt(status));		return(NULL);	} else if (type != SSH2_FXP_ATTRS) {		fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",		    SSH2_FXP_ATTRS, type);	}	a = decode_attrib(&msg);	buffer_free(&msg);	return(a);}struct sftp_conn *do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests){	int type, version;	Buffer msg;	struct sftp_conn *ret;	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_INIT);	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);	send_msg(fd_out, &msg);	buffer_clear(&msg);	get_msg(fd_in, &msg);	/* Expecting a VERSION reply */	if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {		error("Invalid packet back from SSH2_FXP_INIT (type %d)",		    type);		buffer_free(&msg);		return(NULL);	}	version = buffer_get_int(&msg);	debug2("Remote version: %d", version);	/* Check for extensions */	while (buffer_len(&msg) > 0) {		char *name = buffer_get_string(&msg, NULL);		char *value = buffer_get_string(&msg, NULL);		debug2("Init extension: \"%s\"", name);		xfree(name);		xfree(value);	}	buffer_free(&msg);	ret = xmalloc(sizeof(*ret));	ret->fd_in = fd_in;	ret->fd_out = fd_out;	ret->transfer_buflen = transfer_buflen;	ret->num_requests = num_requests;	ret->version = version;	ret->msg_id = 1;	/* Some filexfer v.0 servers don't support large packets */	if (version == 0)		ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);	return(ret);}u_intsftp_proto_version(struct sftp_conn *conn){	return(conn->version);}intdo_close(struct sftp_conn *conn, char *handle, u_int handle_len){	u_int id, status;	Buffer msg;	buffer_init(&msg);	id = conn->msg_id++;	buffer_put_char(&msg, SSH2_FXP_CLOSE);	buffer_put_int(&msg, id);	buffer_put_string(&msg, handle, handle_len);	send_msg(conn->fd_out, &msg);	debug3("Sent message SSH2_FXP_CLOSE I:%d", id);	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't close file: %s", fx2txt(status));	buffer_free(&msg);	return(status);}static intdo_lsreaddir(struct sftp_conn *conn, char *path, int printflag,    SFTP_DIRENT ***dir){	Buffer msg;	u_int type, id, handle_len, i, expected_id, ents = 0;	char *handle;	id = conn->msg_id++;	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_OPENDIR);	buffer_put_int(&msg, id);	buffer_put_cstring(&msg, path);	send_msg(conn->fd_out, &msg);	buffer_clear(&msg);	handle = get_handle(conn->fd_in, id, &handle_len);	if (handle == NULL)		return(-1);	if (dir) {		ents = 0;		*dir = xmalloc(sizeof(**dir));		(*dir)[0] = NULL;	}	for (;;) {		int count;		id = expected_id = conn->msg_id++;		debug3("Sending SSH2_FXP_READDIR I:%d", id);		buffer_clear(&msg);		buffer_put_char(&msg, SSH2_FXP_READDIR);		buffer_put_int(&msg, id);		buffer_put_string(&msg, handle, handle_len);		send_msg(conn->fd_out, &msg);		buffer_clear(&msg);		get_msg(conn->fd_in, &msg);		type = buffer_get_char(&msg);		id = buffer_get_int(&msg);		debug3("Received reply T:%d I:%d", type, id);		if (id != expected_id)			fatal("ID mismatch (%d != %d)", id, expected_id);		if (type == SSH2_FXP_STATUS) {			int status = buffer_get_int(&msg);			debug3("Received SSH2_FXP_STATUS %d", status);			if (status == SSH2_FX_EOF) {				break;			} else {				error("Couldn't read directory: %s",				    fx2txt(status));				do_close(conn, handle, handle_len);				return(status);			}		} else if (type != SSH2_FXP_NAME)			fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",			    SSH2_FXP_NAME, type);		count = buffer_get_int(&msg);		if (count == 0)			break;		debug3("Received %d SSH2_FXP_NAME responses", count);		for (i = 0; i < count; i++) {			char *filename, *longname;			Attrib *a;			filename = buffer_get_string(&msg, NULL);			longname = buffer_get_string(&msg, NULL);			a = decode_attrib(&msg);			if (printflag)				printf("%s\n", longname);			if (dir) {				*dir = xrealloc(*dir, sizeof(**dir) *				    (ents + 2));				(*dir)[ents] = xmalloc(sizeof(***dir));				(*dir)[ents]->filename = xstrdup(filename);				(*dir)[ents]->longname = xstrdup(longname);				memcpy(&(*dir)[ents]->a, a, sizeof(*a));				(*dir)[++ents] = NULL;			}			xfree(filename);			xfree(longname);		}	}	buffer_free(&msg);	do_close(conn, handle, handle_len);	xfree(handle);	return(0);}intdo_ls(struct sftp_conn *conn, char *path){	return(do_lsreaddir(conn, path, 1, NULL));}intdo_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir){	return(do_lsreaddir(conn, path, 0, dir));}void free_sftp_dirents(SFTP_DIRENT **s){	int i;	for (i = 0; s[i]; i++) {		xfree(s[i]->filename);		xfree(s[i]->longname);		xfree(s[i]);	}	xfree(s);}intdo_rm(struct sftp_conn *conn, char *path){	u_int status, id;	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);	id = conn->msg_id++;	send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,	    strlen(path));	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't delete file: %s", fx2txt(status));	return(status);}intdo_mkdir(struct sftp_conn *conn, char *path, Attrib *a){	u_int status, id;	id = conn->msg_id++;	send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,	    strlen(path), a);	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't create directory: %s", fx2txt(status));	return(status);}intdo_rmdir(struct sftp_conn *conn, char *path){	u_int status, id;	id = conn->msg_id++;	send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,	    strlen(path));	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't remove directory: %s", fx2txt(status));	return(status);}Attrib *do_stat(struct sftp_conn *conn, char *path, int quiet){	u_int id;	id = conn->msg_id++;	send_string_request(conn->fd_out, id,	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,	    path, strlen(path));	return(get_decode_stat(conn->fd_in, id, quiet));}Attrib *do_lstat(struct sftp_conn *conn, char *path, int quiet){	u_int id;	if (conn->version == 0) {		if (quiet)			debug("Server version does not support lstat operation");		else			log("Server version does not support lstat operation");		return(do_stat(conn, path, quiet));	}	id = conn->msg_id++;	send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path,	    strlen(path));	return(get_decode_stat(conn->fd_in, id, quiet));}Attrib *do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet){	u_int id;	id = conn->msg_id++;	send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,	    handle_len);	return(get_decode_stat(conn->fd_in, id, quiet));}intdo_setstat(struct sftp_conn *conn, char *path, Attrib *a){	u_int status, id;	id = conn->msg_id++;	send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,	    strlen(path), a);	status = get_status(conn->fd_in, id);	if (status != SSH2_FX_OK)		error("Couldn't setstat on \"%s\": %s", path,		    fx2txt(status));	return(status);}intdo_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,    Attrib *a){	u_int status, id;	id = conn->msg_id++;	send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,	    handle_len, a);	status = get_status(conn->fd_in, id);

⌨️ 快捷键说明

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