sftp-server.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* 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
*
* 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.38 2002/09/11 22:41:50 djm Exp $");
#pragma ident "%Z%%M% %I% %E% SMI"
#include "buffer.h"
#include "bufaux.h"
#include "getput.h"
#include "log.h"
#include "xmalloc.h"
#include "sftp.h"
#include "sftp-common.h"
/* helper */
#ifdef HAVE___PROGNAME
extern char *__progname;
#else
char *__progname;
#endif
/* input and output queue */
/* Version of client */
int version;
/* portable attibutes, etc. */
struct Stat {
char *name;
char *long_name;
};
static int
{
int ret = 0;
switch (unixerrno) {
case 0:
ret = SSH2_FX_OK;
break;
case ENOENT:
case ENOTDIR:
case EBADF:
case ELOOP:
break;
case EPERM:
case EACCES:
case EFAULT:
break;
case ENAMETOOLONG:
case EINVAL:
break;
default:
break;
}
return ret;
}
static int
{
int flags = 0;
if ((pflags & SSH2_FXF_READ) &&
(pflags & SSH2_FXF_WRITE)) {
} else if (pflags & SSH2_FXF_READ) {
} else if (pflags & SSH2_FXF_WRITE) {
}
if (pflags & SSH2_FXF_CREAT)
if (pflags & SSH2_FXF_TRUNC)
if (pflags & SSH2_FXF_EXCL)
return flags;
}
static Attrib *
get_attrib(void)
{
return decode_attrib(&iqueue);
}
/* handle handles */
struct Handle {
int use;
int fd;
char *name;
};
enum {
};
static void
handle_init(void)
{
int i;
}
static int
{
int i;
return i;
}
}
return -1;
}
static int
handle_is_ok(int i, int type)
{
}
static int
{
return -1;
return 0;
}
static int
{
int val;
return -1;
return val;
return -1;
}
static char *
handle_to_name(int handle)
{
return NULL;
}
static DIR *
handle_to_dir(int handle)
{
return NULL;
}
static int
handle_to_fd(int handle)
{
return -1;
}
static int
handle_close(int handle)
{
int ret = -1;
} else {
}
return ret;
}
static int
get_handle(void)
{
char *handle;
int val = -1;
if (hlen < 256)
return val;
}
/* send replies */
static void
{
int mlen = buffer_len(m);
buffer_consume(m, mlen);
}
static void
{
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 */
};
buffer_init(&msg);
if (version >= 3) {
}
buffer_free(&msg);
}
static void
{
buffer_init(&msg);
buffer_free(&msg);
}
static void
{
}
static void
{
char *string;
int hlen;
}
static void
{
int i;
buffer_init(&msg);
for (i = 0; i < count; i++) {
}
buffer_free(&msg);
}
static void
{
buffer_init(&msg);
encode_attrib(&msg, a);
buffer_free(&msg);
}
/* parse incoming */
static void
process_init(void)
{
buffer_init(&msg);
buffer_free(&msg);
}
static void
process_open(void)
{
Attrib *a;
char *name;
a = get_attrib();
if (fd < 0) {
} else {
if (handle < 0) {
} else {
status = SSH2_FX_OK;
}
}
if (status != SSH2_FX_OK)
}
static void
process_close(void)
{
handle = get_handle();
}
static void
process_read(void)
{
handle = get_handle();
}
if (fd >= 0) {
error("process_read: seek failed");
} else {
if (ret < 0) {
} else if (ret == 0) {
} else {
status = SSH2_FX_OK;
}
}
}
if (status != SSH2_FX_OK)
}
static void
process_write(void)
{
char *data;
handle = get_handle();
if (fd >= 0) {
error("process_write: seek failed");
} else {
/* XXX ATOMICIO ? */
if (ret == -1) {
error("process_write: write failed");
status = SSH2_FX_OK;
} else {
log("nothing at all written");
}
}
}
}
static void
process_do_stat(int do_lstat)
{
Attrib a;
char *name;
if (ret < 0) {
} else {
stat_to_attrib(&st, &a);
send_attrib(id, &a);
status = SSH2_FX_OK;
}
if (status != SSH2_FX_OK)
}
static void
process_stat(void)
{
process_do_stat(0);
}
static void
process_lstat(void)
{
process_do_stat(1);
}
static void
process_fstat(void)
{
Attrib a;
handle = get_handle();
if (fd >= 0) {
if (ret < 0) {
} else {
stat_to_attrib(&st, &a);
send_attrib(id, &a);
status = SSH2_FX_OK;
}
}
if (status != SSH2_FX_OK)
}
static struct timeval *
attrib_to_tv(Attrib *a)
{
return tv;
}
static void
process_setstat(void)
{
Attrib *a;
char *name;
a = get_attrib();
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
if (ret == -1)
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
if (ret == -1)
}
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
if (ret == -1)
}
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
if (ret == -1)
}
}
static void
process_fsetstat(void)
{
Attrib *a;
int status = SSH2_FX_OK;
char *name;
handle = get_handle();
a = get_attrib();
} else {
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
if (ret == -1)
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
#ifdef HAVE_FCHMOD
#else
#endif
if (ret == -1)
}
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
#ifdef HAVE_FUTIMES
#else
#endif
if (ret == -1)
}
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
#ifdef HAVE_FCHOWN
#else
#endif
if (ret == -1)
}
}
}
static void
process_opendir(void)
{
char *path;
} else {
if (handle < 0) {
} else {
status = SSH2_FX_OK;
}
}
if (status != SSH2_FX_OK)
}
static void
process_readdir(void)
{
char *path;
int handle;
handle = get_handle();
} else {
char pathname[1024];
nstats *= 2;
}
/* XXX OVERFLOW ? */
continue;
count++;
/* send up to 100 entries in one message */
/* XXX check packet size instead */
if (count == 100)
break;
}
if (count > 0) {
for (i = 0; i < count; i++) {
}
} else {
}
}
}
static void
process_remove(void)
{
char *name;
int status = SSH2_FX_FAILURE;
int ret;
}
static void
process_mkdir(void)
{
Attrib *a;
char *name;
a = get_attrib();
}
static void
process_rmdir(void)
{
char *name;
}
static void
process_realpath(void)
{
char resolvedname[MAXPATHLEN];
char *path;
if (path[0] == '\0') {
}
} else {
Stat s;
attrib_clear(&s.attrib);
}
}
static void
process_rename(void)
{
/* fail if 'newpath' exists */
}
}
static void
process_readlink(void)
{
int len;
char link[MAXPATHLEN];
char *path;
else {
Stat s;
attrib_clear(&s.attrib);
}
}
static void
process_symlink(void)
{
/* fail if 'newpath' exists */
}
}
static void
process_extended(void)
{
char *request;
}
/* stolen from ssh-agent */
static void
process(void)
{
if (buf_len < 5)
return; /* Incomplete message. */
error("bad message ");
exit(11);
}
return;
buf_len -= 4;
switch (type) {
case SSH2_FXP_INIT:
process_init();
break;
case SSH2_FXP_OPEN:
process_open();
break;
case SSH2_FXP_CLOSE:
break;
case SSH2_FXP_READ:
process_read();
break;
case SSH2_FXP_WRITE:
break;
case SSH2_FXP_LSTAT:
break;
case SSH2_FXP_FSTAT:
break;
case SSH2_FXP_SETSTAT:
break;
case SSH2_FXP_FSETSTAT:
break;
case SSH2_FXP_OPENDIR:
break;
case SSH2_FXP_READDIR:
break;
case SSH2_FXP_REMOVE:
break;
case SSH2_FXP_MKDIR:
break;
case SSH2_FXP_RMDIR:
break;
case SSH2_FXP_REALPATH:
break;
case SSH2_FXP_STAT:
process_stat();
break;
case SSH2_FXP_RENAME:
break;
case SSH2_FXP_READLINK:
break;
case SSH2_FXP_SYMLINK:
break;
case SSH2_FXP_EXTENDED:
break;
default:
break;
}
/* discard the remaining bytes from the current packet */
fatal("iqueue grows");
}
int
{
/* XXX should use getopt */
handle_init();
#ifdef DEBUG_SFTP_SERVER
#endif
#ifdef HAVE_CYGWIN
#endif
max = 0;
for (;;) {
if (olen > 0)
continue;
return (2);
}
/* copy stdin to iqueue */
if (len == 0) {
debug("read eof");
return (0);
} else if (len < 0) {
error("read error");
return (1);
} else {
}
}
/* send oqueue to stdout */
if (len < 0) {
error("write error");
return (1);
} else {
}
}
/* process requests from client */
process();
}
}