]> andersk Git - openssh.git/blobdiff - sftp-server.c
- markus@cvs.openbsd.org 2001/04/05 10:42:57
[openssh.git] / sftp-server.c
index c8daeea1e700587933b55817333b7134735ab30a..0695a9824dce3b7ca3e396f30b12a0c98a008e48 100644 (file)
@@ -22,7 +22,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "includes.h"
-RCSID("$OpenBSD: sftp-server.c,v 1.20 2001/02/21 09:12:56 deraadt Exp $");
+RCSID("$OpenBSD: sftp-server.c,v 1.25 2001/04/05 10:42:53 markus Exp $");
 
 #include "buffer.h"
 #include "bufaux.h"
@@ -49,6 +49,9 @@ char *__progname;
 Buffer iqueue;
 Buffer oqueue;
 
+/* Version of client */
+int version;
+
 /* portable attibutes, etc. */
 
 typedef struct Stat Stat;
@@ -63,6 +66,7 @@ int
 errno_to_portable(int unixerrno)
 {
        int ret = 0;
+
        switch (unixerrno) {
        case 0:
                ret = SSH2_FX_OK;
@@ -93,6 +97,7 @@ int
 flags_from_portable(int pflags)
 {
        int flags = 0;
+
        if ((pflags & SSH2_FXF_READ) &&
            (pflags & SSH2_FXF_WRITE)) {
                flags = O_RDWR;
@@ -125,17 +130,20 @@ struct Handle {
        int fd;
        char *name;
 };
+
 enum {
        HANDLE_UNUSED,
        HANDLE_DIR,
        HANDLE_FILE
 };
+
 Handle handles[100];
 
 void
 handle_init(void)
 {
        int i;
+
        for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
                handles[i].use = HANDLE_UNUSED;
 }
@@ -144,6 +152,7 @@ int
 handle_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;
@@ -178,6 +187,7 @@ int
 handle_from_string(char *handle, u_int hlen)
 {
        int val;
+
        if (hlen != sizeof(int32_t))
                return -1;
        val = GET_32BIT(handle);
@@ -216,6 +226,7 @@ int
 handle_close(int handle)
 {
        int ret = -1;
+
        if (handle_is_ok(handle, HANDLE_FILE)) {
                ret = close(handles[handle].fd);
                handles[handle].use = HANDLE_UNUSED;
@@ -234,6 +245,7 @@ get_handle(void)
        char *handle;
        int val = -1;
        u_int hlen;
+
        handle = get_string(&hlen);
        if (hlen < 256)
                val = handle_from_string(handle, hlen);
@@ -247,6 +259,7 @@ void
 send_msg(Buffer *m)
 {
        int mlen = buffer_len(m);
+
        buffer_put_int(&oqueue, mlen);
        buffer_append(&oqueue, buffer_ptr(m), mlen);
        buffer_consume(m, mlen);
@@ -256,11 +269,29 @@ void
 send_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);
 }
@@ -268,6 +299,7 @@ void
 send_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);
@@ -288,6 +320,7 @@ send_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);
@@ -299,6 +332,7 @@ send_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);
@@ -317,6 +351,7 @@ void
 send_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);
@@ -332,8 +367,8 @@ void
 process_init(void)
 {
        Buffer msg;
-       int version = buffer_get_int(&iqueue);
 
+       version = buffer_get_int(&iqueue);
        TRACE("client version %d", version);
        buffer_init(&msg);
        buffer_put_char(&msg, SSH2_FXP_VERSION);
@@ -533,6 +568,7 @@ struct timeval *
 attrib_to_tv(Attrib *a)
 {
        static struct timeval tv[2];
+
        tv[0].tv_sec = a->atime;
        tv[0].tv_usec = 0;
        tv[1].tv_sec = a->mtime;
@@ -843,6 +879,51 @@ process_rename(void)
        xfree(newpath);
 }
 
+void
+process_readlink(void)
+{
+       u_int32_t id;
+       char link[MAXPATHLEN];
+       char *path;
+
+       id = get_int();
+       path = get_string(NULL);
+       TRACE("readlink id %d path %s", id, path);
+       if (readlink(path, link, sizeof(link) - 1) == -1)
+               send_status(id, errno_to_portable(errno));
+       else {
+               Stat s;
+               
+               link[sizeof(link) - 1] = '\0';
+               attrib_clear(&s.attrib);
+               s.name = s.long_name = link;
+               send_names(id, 1, &s);
+       }
+       xfree(path);
+}
+
+void
+process_symlink(void)
+{
+       u_int32_t id;
+       struct stat st;
+       char *oldpath, *newpath;
+       int ret, status = SSH2_FX_FAILURE;
+
+       id = get_int();
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
+       /* fail if 'newpath' exists */
+       if (stat(newpath, &st) == -1) {
+               ret = symlink(oldpath, newpath);
+               status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+       }
+       send_status(id, status);
+       xfree(oldpath);
+       xfree(newpath);
+}
+
 void
 process_extended(void)
 {
@@ -928,6 +1009,12 @@ process(void)
        case SSH2_FXP_RENAME:
                process_rename();
                break;
+       case SSH2_FXP_READLINK:
+               process_readlink();
+               break;
+       case SSH2_FXP_SYMLINK:
+               process_symlink();
+               break;
        case SSH2_FXP_EXTENDED:
                process_extended();
                break;
@@ -940,9 +1027,11 @@ process(void)
 int
 main(int ac, char **av)
 {
-       fd_set rset, wset;
+       fd_set *rset, *wset;
        int in, out, max;
-       ssize_t len, olen;
+       ssize_t len, olen, set_size;
+
+       /* XXX should use getopt */
 
        __progname = get_progname(av[0]);
        handle_init();
@@ -963,23 +1052,27 @@ main(int ac, char **av)
        buffer_init(&iqueue);
        buffer_init(&oqueue);
 
+       set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
+       rset = (fd_set *)xmalloc(set_size);
+       wset = (fd_set *)xmalloc(set_size);
+
        for (;;) {
-               FD_ZERO(&rset);
-               FD_ZERO(&wset);
+               memset(rset, 0, set_size);
+               memset(wset, 0, set_size);
 
-               FD_SET(in, &rset);
+               FD_SET(in, rset);
                olen = buffer_len(&oqueue);
                if (olen > 0)
-                       FD_SET(out, &wset);
+                       FD_SET(out, wset);
 
-               if (select(max+1, &rset, &wset, NULL, NULL) < 0) {
+               if (select(max+1, rset, wset, NULL, NULL) < 0) {
                        if (errno == EINTR)
                                continue;
                        exit(2);
                }
 
                /* copy stdin to iqueue */
-               if (FD_ISSET(in, &rset)) {
+               if (FD_ISSET(in, rset)) {
                        char buf[4*4096];
                        len = read(in, buf, sizeof buf);
                        if (len == 0) {
@@ -993,7 +1086,7 @@ main(int ac, char **av)
                        }
                }
                /* send oqueue to stdout */
-               if (FD_ISSET(out, &wset)) {
+               if (FD_ISSET(out, wset)) {
                        len = write(out, buffer_ptr(&oqueue), olen);
                        if (len < 0) {
                                error("write error");
This page took 0.680357 seconds and 4 git commands to generate.