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

📄 sftp-server.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2000, 2001, 2002 Markus Friedl.  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 "includes.h"RCSID("$OpenBSD: sftp-server.c,v 1.35 2002/06/06 17:30:11 markus Exp $");#include "buffer.h"#include "bufaux.h"#include "getput.h"#include "log.h"#include "xmalloc.h"#include "sftp.h"#include "sftp-common.h"/* helper */#define get_int64()			buffer_get_int64(&iqueue);#define get_int()			buffer_get_int(&iqueue);#define get_string(lenp)		buffer_get_string(&iqueue, lenp);#define TRACE				debug#ifdef HAVE___PROGNAMEextern char *__progname;#elsechar *__progname;#endif/* input and output queue */Buffer iqueue;Buffer oqueue;/* Version of client */int version;/* portable attibutes, etc. */typedef struct Stat Stat;struct Stat {	char *name;	char *long_name;	Attrib attrib;};static interrno_to_portable(int unixerrno){	int ret = 0;	switch (unixerrno) {	case 0:		ret = SSH2_FX_OK;		break;	case ENOENT:	case ENOTDIR:	case EBADF:	case ELOOP:		ret = SSH2_FX_NO_SUCH_FILE;		break;	case EPERM:	case EACCES:	case EFAULT:		ret = SSH2_FX_PERMISSION_DENIED;		break;	case ENAMETOOLONG:	case EINVAL:		ret = SSH2_FX_BAD_MESSAGE;		break;	default:		ret = SSH2_FX_FAILURE;		break;	}	return ret;}static intflags_from_portable(int pflags){	int flags = 0;	if ((pflags & SSH2_FXF_READ) &&	    (pflags & SSH2_FXF_WRITE)) {		flags = O_RDWR;	} else if (pflags & SSH2_FXF_READ) {		flags = O_RDONLY;	} else if (pflags & SSH2_FXF_WRITE) {		flags = O_WRONLY;	}	if (pflags & SSH2_FXF_CREAT)		flags |= O_CREAT;	if (pflags & SSH2_FXF_TRUNC)		flags |= O_TRUNC;	if (pflags & SSH2_FXF_EXCL)		flags |= O_EXCL;	return flags;}static Attrib *get_attrib(void){	return decode_attrib(&iqueue);}/* handle handles */typedef struct Handle Handle;struct Handle {	int use;	DIR *dirp;	int fd;	char *name;};enum {	HANDLE_UNUSED,	HANDLE_DIR,	HANDLE_FILE};Handle	handles[100];static voidhandle_init(void){	int i;	for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)		handles[i].use = HANDLE_UNUSED;}static inthandle_new(int use, char *name, int fd, DIR *dirp){	int i;	for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {		if (handles[i].use == HANDLE_UNUSED) {			handles[i].use = use;			handles[i].dirp = dirp;			handles[i].fd = fd;			handles[i].name = name;			return i;		}	}	return -1;}static inthandle_is_ok(int i, int type){	return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&	    handles[i].use == type;}static inthandle_to_string(int handle, char **stringp, int *hlenp){	if (stringp == NULL || hlenp == NULL)		return -1;	*stringp = xmalloc(sizeof(int32_t));	PUT_32BIT(*stringp, handle);	*hlenp = sizeof(int32_t);	return 0;}static inthandle_from_string(char *handle, u_int hlen){	int val;	if (hlen != sizeof(int32_t))		return -1;	val = GET_32BIT(handle);	if (handle_is_ok(val, HANDLE_FILE) ||	    handle_is_ok(val, HANDLE_DIR))		return val;	return -1;}static char *handle_to_name(int handle){	if (handle_is_ok(handle, HANDLE_DIR)||	    handle_is_ok(handle, HANDLE_FILE))		return handles[handle].name;	return NULL;}static DIR *handle_to_dir(int handle){	if (handle_is_ok(handle, HANDLE_DIR))		return handles[handle].dirp;	return NULL;}static inthandle_to_fd(int handle){	if (handle_is_ok(handle, HANDLE_FILE))		return handles[handle].fd;	return -1;}static inthandle_close(int handle){	int ret = -1;	if (handle_is_ok(handle, HANDLE_FILE)) {		ret = close(handles[handle].fd);		handles[handle].use = HANDLE_UNUSED;	} else if (handle_is_ok(handle, HANDLE_DIR)) {		ret = closedir(handles[handle].dirp);		handles[handle].use = HANDLE_UNUSED;	} else {		errno = ENOENT;	}	return ret;}static intget_handle(void){	char *handle;	int val = -1;	u_int hlen;	handle = get_string(&hlen);	if (hlen < 256)		val = handle_from_string(handle, hlen);	xfree(handle);	return val;}/* send replies */static voidsend_msg(Buffer *m){	int mlen = buffer_len(m);	buffer_put_int(&oqueue, mlen);	buffer_append(&oqueue, buffer_ptr(m), mlen);	buffer_consume(m, mlen);}static voidsend_status(u_int32_t id, u_int32_t error){	Buffer msg;	const char *status_messages[] = {		"Success",			/* SSH_FX_OK */		"End of file",			/* SSH_FX_EOF */		"No such file",			/* SSH_FX_NO_SUCH_FILE */		"Permission denied",		/* SSH_FX_PERMISSION_DENIED */		"Failure",			/* SSH_FX_FAILURE */		"Bad message",			/* SSH_FX_BAD_MESSAGE */		"No connection",		/* SSH_FX_NO_CONNECTION */		"Connection lost",		/* SSH_FX_CONNECTION_LOST */		"Operation unsupported",	/* SSH_FX_OP_UNSUPPORTED */		"Unknown error"			/* Others */	};	TRACE("sent status id %d error %d", id, error);	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_STATUS);	buffer_put_int(&msg, id);	buffer_put_int(&msg, error);	if (version >= 3) {		buffer_put_cstring(&msg,		    status_messages[MIN(error,SSH2_FX_MAX)]);		buffer_put_cstring(&msg, "");	}	send_msg(&msg);	buffer_free(&msg);}static voidsend_data_or_handle(char type, u_int32_t id, char *data, int dlen){	Buffer msg;	buffer_init(&msg);	buffer_put_char(&msg, type);	buffer_put_int(&msg, id);	buffer_put_string(&msg, data, dlen);	send_msg(&msg);	buffer_free(&msg);}static voidsend_data(u_int32_t id, char *data, int dlen){	TRACE("sent data id %d len %d", id, dlen);	send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);}static voidsend_handle(u_int32_t id, int handle){	char *string;	int hlen;	handle_to_string(handle, &string, &hlen);	TRACE("sent handle id %d handle %d", id, handle);	send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);	xfree(string);}static voidsend_names(u_int32_t id, int count, Stat *stats){	Buffer msg;	int i;	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_NAME);	buffer_put_int(&msg, id);	buffer_put_int(&msg, count);	TRACE("sent names id %d count %d", id, count);	for (i = 0; i < count; i++) {		buffer_put_cstring(&msg, stats[i].name);		buffer_put_cstring(&msg, stats[i].long_name);		encode_attrib(&msg, &stats[i].attrib);	}	send_msg(&msg);	buffer_free(&msg);}static voidsend_attrib(u_int32_t id, Attrib *a){	Buffer msg;	TRACE("sent attrib id %d have 0x%x", id, a->flags);	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_ATTRS);	buffer_put_int(&msg, id);	encode_attrib(&msg, a);	send_msg(&msg);	buffer_free(&msg);}/* parse incoming */static voidprocess_init(void){	Buffer msg;	version = get_int();	TRACE("client version %d", version);	buffer_init(&msg);	buffer_put_char(&msg, SSH2_FXP_VERSION);	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);	send_msg(&msg);	buffer_free(&msg);}static voidprocess_open(void){	u_int32_t id, pflags;	Attrib *a;	char *name;	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;	id = get_int();	name = get_string(NULL);	pflags = get_int();		/* portable flags */	a = get_attrib();	flags = flags_from_portable(pflags);	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;	TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);	fd = open(name, flags, mode);	if (fd < 0) {		status = errno_to_portable(errno);	} else {		handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);		if (handle < 0) {			close(fd);		} else {			send_handle(id, handle);			status = SSH2_FX_OK;		}	}	if (status != SSH2_FX_OK)		send_status(id, status);	xfree(name);}static voidprocess_close(void){	u_int32_t id;	int handle, ret, status = SSH2_FX_FAILURE;	id = get_int();	handle = get_handle();	TRACE("close id %d handle %d", id, handle);	ret = handle_close(handle);	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;	send_status(id, status);}static voidprocess_read(void){	char buf[64*1024];	u_int32_t id, len;	int handle, fd, ret, status = SSH2_FX_FAILURE;	u_int64_t off;	id = get_int();	handle = get_handle();	off = get_int64();	len = get_int();	TRACE("read id %d handle %d off %llu len %d", id, handle,	    (u_int64_t)off, len);	if (len > sizeof buf) {		len = sizeof buf;		log("read change len %d", len);	}	fd = handle_to_fd(handle);	if (fd >= 0) {		if (lseek(fd, off, SEEK_SET) < 0) {			error("process_read: seek failed");			status = errno_to_portable(errno);		} else {			ret = read(fd, buf, len);			if (ret < 0) {				status = errno_to_portable(errno);			} else if (ret == 0) {				status = SSH2_FX_EOF;			} else {				send_data(id, buf, ret);				status = SSH2_FX_OK;			}		}	}	if (status != SSH2_FX_OK)		send_status(id, status);}static voidprocess_write(void){	u_int32_t id;	u_int64_t off;	u_int len;	int handle, fd, ret, status = SSH2_FX_FAILURE;	char *data;	id = get_int();	handle = get_handle();	off = get_int64();	data = get_string(&len);	TRACE("write id %d handle %d off %llu len %d", id, handle,	    (u_int64_t)off, len);	fd = handle_to_fd(handle);	if (fd >= 0) {		if (lseek(fd, off, SEEK_SET) < 0) {			status = errno_to_portable(errno);			error("process_write: seek failed");		} else {/* XXX ATOMICIO ? */			ret = write(fd, data, len);			if (ret == -1) {				error("process_write: write failed");				status = errno_to_portable(errno);			} else if (ret == len) {				status = SSH2_FX_OK;			} else {				log("nothing at all written");			}		}	}	send_status(id, status);	xfree(data);}static voidprocess_do_stat(int do_lstat){	Attrib a;	struct stat st;	u_int32_t id;	char *name;	int ret, status = SSH2_FX_FAILURE;	id = get_int();	name = get_string(NULL);	TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);	ret = do_lstat ? lstat(name, &st) : stat(name, &st);	if (ret < 0) {		status = errno_to_portable(errno);	} else {		stat_to_attrib(&st, &a);		send_attrib(id, &a);		status = SSH2_FX_OK;	}	if (status != SSH2_FX_OK)		send_status(id, status);	xfree(name);}static voidprocess_stat(void){	process_do_stat(0);}static voidprocess_lstat(void){	process_do_stat(1);}static voidprocess_fstat(void){	Attrib a;	struct stat st;	u_int32_t id;	int fd, ret, handle, status = SSH2_FX_FAILURE;	id = get_int();	handle = get_handle();	TRACE("fstat id %d handle %d", id, handle);	fd = handle_to_fd(handle);	if (fd  >= 0) {		ret = fstat(fd, &st);		if (ret < 0) {			status = errno_to_portable(errno);		} else {			stat_to_attrib(&st, &a);			send_attrib(id, &a);			status = SSH2_FX_OK;		}	}	if (status != SSH2_FX_OK)		send_status(id, status);}static struct timeval *

⌨️ 快捷键说明

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