]> andersk Git - openssh.git/blobdiff - sftp-server.c
- markus@cvs.openbsd.org 2001/04/22 23:58:36
[openssh.git] / sftp-server.c
index 2b1a7e3e5afe6cb78554f52c2bd6bf002760ee76..75c19c8a63e1892cd6a4acaf59b0b062c5cb066f 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.21 2001/03/03 21:40:30 millert 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;
@@ -944,6 +1031,8 @@ main(int ac, char **av)
        int in, out, max;
        ssize_t len, olen, set_size;
 
+       /* XXX should use getopt */
+
        __progname = get_progname(av[0]);
        handle_init();
 
@@ -954,6 +1043,11 @@ main(int ac, char **av)
        in = dup(STDIN_FILENO);
        out = dup(STDOUT_FILENO);
 
+#ifdef HAVE_CYGWIN
+       setmode(in, O_BINARY);
+       setmode(out, O_BINARY);
+#endif
+
        max = 0;
        if (in > max)
                max = in;
This page took 0.100372 seconds and 4 git commands to generate.