[BACK]Return to sftp-server.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sftp-server.c between version 1.6.4.3 and 1.7

version 1.6.4.3, 2001/03/21 18:53:06 version 1.7, 2000/12/09 14:08:27
Line 24 
Line 24 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
   #include "ssh.h"
 #include "buffer.h"  #include "buffer.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "getput.h"  #include "getput.h"
 #include "log.h"  
 #include "xmalloc.h"  #include "xmalloc.h"
   
 #include "sftp.h"  /* version */
 #include "sftp-common.h"  #define SSH_FILEXFER_VERSION            2
   
   /* client to server */
   #define SSH_FXP_INIT                    1
   #define SSH_FXP_OPEN                    3
   #define SSH_FXP_CLOSE                   4
   #define SSH_FXP_READ                    5
   #define SSH_FXP_WRITE                   6
   #define SSH_FXP_LSTAT                   7
   #define SSH_FXP_FSTAT                   8
   #define SSH_FXP_SETSTAT                 9
   #define SSH_FXP_FSETSTAT                10
   #define SSH_FXP_OPENDIR                 11
   #define SSH_FXP_READDIR                 12
   #define SSH_FXP_REMOVE                  13
   #define SSH_FXP_MKDIR                   14
   #define SSH_FXP_RMDIR                   15
   #define SSH_FXP_REALPATH                16
   #define SSH_FXP_STAT                    17
   #define SSH_FXP_RENAME                  18
   
   /* server to client */
   #define SSH_FXP_VERSION                 2
   #define SSH_FXP_STATUS                  101
   #define SSH_FXP_HANDLE                  102
   #define SSH_FXP_DATA                    103
   #define SSH_FXP_NAME                    104
   #define SSH_FXP_ATTRS                   105
   
   /* portable open modes */
   #define SSH_FXF_READ                    0x01
   #define SSH_FXF_WRITE                   0x02
   #define SSH_FXF_APPEND                  0x04
   #define SSH_FXF_CREAT                   0x08
   #define SSH_FXF_TRUNC                   0x10
   #define SSH_FXF_EXCL                    0x20
   
   /* attributes */
   #define SSH_FXA_HAVE_SIZE               0x01
   #define SSH_FXA_HAVE_UGID               0x02
   #define SSH_FXA_HAVE_PERM               0x04
   #define SSH_FXA_HAVE_TIME               0x08
   
   /* status messages */
   #define SSH_FX_OK                       0x00
   #define SSH_FX_EOF                      0x01
   #define SSH_FX_NO_SUCH_FILE             0x02
   #define SSH_FX_PERMISSION_DENIED        0x03
   #define SSH_FX_FAILURE                  0x04
   #define SSH_FX_BAD_MESSAGE              0x05
   #define SSH_FX_NO_CONNECTION            0x06
   #define SSH_FX_CONNECTION_LOST          0x07
   
   
 /* helper */  /* helper */
 #define get_int64()                     buffer_get_int64(&iqueue);  
 #define get_int()                       buffer_get_int(&iqueue);  #define get_int()                       buffer_get_int(&iqueue);
 #define get_string(lenp)                buffer_get_string(&iqueue, lenp);  #define get_string(lenp)                buffer_get_string(&iqueue, lenp);
 #define TRACE                           debug  #define TRACE                           log
   
 /* input and output queue */  /* input and output queue */
 Buffer iqueue;  Buffer iqueue;
 Buffer oqueue;  Buffer oqueue;
   
 /* Version of client */  
 int version;  
   
 /* portable attibutes, etc. */  /* portable attibutes, etc. */
   
   typedef struct Attrib Attrib;
 typedef struct Stat Stat;  typedef struct Stat Stat;
   
 struct Stat {  struct Attrib
   {
           u_int32_t       flags;
           u_int32_t       size_high;
           u_int32_t       size_low;
           u_int64_t       size;
           u_int32_t       uid;
           u_int32_t       gid;
           u_int32_t       perm;
           u_int32_t       atime;
           u_int32_t       mtime;
   };
   
   struct Stat
   {
         char *name;          char *name;
         char *long_name;          char *long_name;
         Attrib attrib;          Attrib attrib;
Line 60 
Line 123 
 errno_to_portable(int unixerrno)  errno_to_portable(int unixerrno)
 {  {
         int ret = 0;          int ret = 0;
   
         switch (unixerrno) {          switch (unixerrno) {
         case 0:          case 0:
                 ret = SSH2_FX_OK;                  ret = SSH_FX_OK;
                 break;                  break;
         case ENOENT:          case ENOENT:
         case ENOTDIR:          case ENOTDIR:
         case EBADF:          case EBADF:
         case ELOOP:          case ELOOP:
                 ret = SSH2_FX_NO_SUCH_FILE;                  ret = SSH_FX_NO_SUCH_FILE;
                 break;                  break;
         case EPERM:          case EPERM:
         case EACCES:          case EACCES:
         case EFAULT:          case EFAULT:
                 ret = SSH2_FX_PERMISSION_DENIED;                  ret = SSH_FX_PERMISSION_DENIED;
                 break;                  break;
         case ENAMETOOLONG:          case ENAMETOOLONG:
         case EINVAL:          case EINVAL:
                 ret = SSH2_FX_BAD_MESSAGE;                  ret = SSH_FX_BAD_MESSAGE;
                 break;                  break;
         default:          default:
                 ret = SSH2_FX_FAILURE;                  ret = SSH_FX_FAILURE;
                 break;                  break;
         }          }
         return ret;          return ret;
Line 91 
Line 153 
 flags_from_portable(int pflags)  flags_from_portable(int pflags)
 {  {
         int flags = 0;          int flags = 0;
           if (pflags & SSH_FXF_READ &&
         if ((pflags & SSH2_FXF_READ) &&              pflags & SSH_FXF_WRITE) {
             (pflags & SSH2_FXF_WRITE)) {  
                 flags = O_RDWR;                  flags = O_RDWR;
         } else if (pflags & SSH2_FXF_READ) {          } else if (pflags & SSH_FXF_READ) {
                 flags = O_RDONLY;                  flags = O_RDONLY;
         } else if (pflags & SSH2_FXF_WRITE) {          } else if (pflags & SSH_FXF_WRITE) {
                 flags = O_WRONLY;                  flags = O_WRONLY;
         }          }
         if (pflags & SSH2_FXF_CREAT)          if (pflags & SSH_FXF_CREAT)
                 flags |= O_CREAT;                  flags |= O_CREAT;
         if (pflags & SSH2_FXF_TRUNC)          if (pflags & SSH_FXF_TRUNC)
                 flags |= O_TRUNC;                  flags |= O_TRUNC;
         if (pflags & SSH2_FXF_EXCL)          if (pflags & SSH_FXF_EXCL)
                 flags |= O_EXCL;                  flags |= O_EXCL;
         return flags;          return flags;
 }  }
   
   void
   attrib_clear(Attrib *a)
   {
           a->flags = 0;
           a->size_low = 0;
           a->size_high = 0;
           a->size = 0;
           a->uid = 0;
           a->gid = 0;
           a->perm = 0;
           a->atime = 0;
           a->mtime = 0;
   }
   
 Attrib *  Attrib *
   decode_attrib(Buffer *b)
   {
           static Attrib a;
           attrib_clear(&a);
           a.flags = buffer_get_int(b);
           if (a.flags & SSH_FXA_HAVE_SIZE) {
                   a.size_high = buffer_get_int(b);
                   a.size_low = buffer_get_int(b);
                   a.size = (((u_int64_t) a.size_high) << 32) + a.size_low;
           }
           if (a.flags & SSH_FXA_HAVE_UGID) {
                   a.uid = buffer_get_int(b);
                   a.gid = buffer_get_int(b);
           }
           if (a.flags & SSH_FXA_HAVE_PERM) {
                   a.perm = buffer_get_int(b);
           }
           if (a.flags & SSH_FXA_HAVE_TIME) {
                   a.atime = buffer_get_int(b);
                   a.mtime = buffer_get_int(b);
           }
           return &a;
   }
   
   void
   encode_attrib(Buffer *b, Attrib *a)
   {
           buffer_put_int(b, a->flags);
           if (a->flags & SSH_FXA_HAVE_SIZE) {
                   buffer_put_int(b, a->size_high);
                   buffer_put_int(b, a->size_low);
           }
           if (a->flags & SSH_FXA_HAVE_UGID) {
                   buffer_put_int(b, a->uid);
                   buffer_put_int(b, a->gid);
           }
           if (a->flags & SSH_FXA_HAVE_PERM) {
                   buffer_put_int(b, a->perm);
           }
           if (a->flags & SSH_FXA_HAVE_TIME) {
                   buffer_put_int(b, a->atime);
                   buffer_put_int(b, a->mtime);
           }
   }
   
   Attrib *
   stat_to_attrib(struct stat *st)
   {
           static Attrib a;
           attrib_clear(&a);
           a.flags = 0;
           a.flags |= SSH_FXA_HAVE_SIZE;
           a.size = st->st_size;
           a.size_low = a.size;
           a.size_high = (u_int32_t) (a.size >> 32);
           a.flags |= SSH_FXA_HAVE_UGID;
           a.uid = st->st_uid;
           a.gid = st->st_gid;
           a.flags |= SSH_FXA_HAVE_PERM;
           a.perm = st->st_mode;
           a.flags |= SSH_FXA_HAVE_TIME;
           a.atime = st->st_atime;
           a.mtime = st->st_mtime;
           return &a;
   }
   
   Attrib *
 get_attrib(void)  get_attrib(void)
 {  {
         return decode_attrib(&iqueue);          return decode_attrib(&iqueue);
Line 124 
Line 266 
         int fd;          int fd;
         char *name;          char *name;
 };  };
   
 enum {  enum {
         HANDLE_UNUSED,          HANDLE_UNUSED,
         HANDLE_DIR,          HANDLE_DIR,
         HANDLE_FILE          HANDLE_FILE
 };  };
   
 Handle  handles[100];  Handle  handles[100];
   
 void  void
 handle_init(void)  handle_init(void)
 {  {
         int i;          int i;
   
         for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)          for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
                 handles[i].use = HANDLE_UNUSED;                  handles[i].use = HANDLE_UNUSED;
 }  }
Line 146 
Line 285 
 handle_new(int use, char *name, int fd, DIR *dirp)  handle_new(int use, char *name, int fd, DIR *dirp)
 {  {
         int i;          int i;
   
         for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {          for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
                 if (handles[i].use == HANDLE_UNUSED) {                  if (handles[i].use == HANDLE_UNUSED) {
                         handles[i].use = use;                          handles[i].use = use;
Line 162 
Line 300 
 int  int
 handle_is_ok(int i, int type)  handle_is_ok(int i, int type)
 {  {
         return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&          return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type;
             handles[i].use == type;  
 }  }
   
 int  int
 handle_to_string(int handle, char **stringp, int *hlenp)  handle_to_string(int handle, char **stringp, int *hlenp)
 {  {
           char buf[1024];
         if (stringp == NULL || hlenp == NULL)          if (stringp == NULL || hlenp == NULL)
                 return -1;                  return -1;
         *stringp = xmalloc(sizeof(int32_t));          snprintf(buf, sizeof buf, "%d", handle);
         PUT_32BIT(*stringp, handle);          *stringp = xstrdup(buf);
         *hlenp = sizeof(int32_t);          *hlenp = strlen(*stringp);
         return 0;          return 0;
 }  }
   
 int  int
 handle_from_string(char *handle, u_int hlen)  handle_from_string(char *handle, u_int hlen)
 {  {
         int val;  /* XXX OVERFLOW ? */
           char *ep;
         if (hlen != sizeof(int32_t))          long lval = strtol(handle, &ep, 10);
           int val = lval;
           if (*ep != '\0')
                 return -1;                  return -1;
         val = GET_32BIT(handle);  
         if (handle_is_ok(val, HANDLE_FILE) ||          if (handle_is_ok(val, HANDLE_FILE) ||
             handle_is_ok(val, HANDLE_DIR))              handle_is_ok(val, HANDLE_DIR))
                 return val;                  return val;
Line 211 
Line 350 
 int  int
 handle_to_fd(int handle)  handle_to_fd(int handle)
 {  {
         if (handle_is_ok(handle, HANDLE_FILE))          if (handle_is_ok(handle, HANDLE_FILE))
                 return handles[handle].fd;                  return handles[handle].fd;
         return -1;          return -1;
 }  }
Line 220 
Line 359 
 handle_close(int handle)  handle_close(int handle)
 {  {
         int ret = -1;          int ret = -1;
   
         if (handle_is_ok(handle, HANDLE_FILE)) {          if (handle_is_ok(handle, HANDLE_FILE)) {
                 ret = close(handles[handle].fd);                  ret = close(handles[handle].fd);
                 handles[handle].use = HANDLE_UNUSED;                  handles[handle].use = HANDLE_UNUSED;
Line 237 
Line 375 
 get_handle(void)  get_handle(void)
 {  {
         char *handle;          char *handle;
         int val = -1;          int val;
         u_int hlen;          u_int hlen;
   
         handle = get_string(&hlen);          handle = get_string(&hlen);
         if (hlen < 256)          val = handle_from_string(handle, hlen);
                 val = handle_from_string(handle, hlen);  
         xfree(handle);          xfree(handle);
         return val;          return val;
 }  }
Line 253 
Line 389 
 send_msg(Buffer *m)  send_msg(Buffer *m)
 {  {
         int mlen = buffer_len(m);          int mlen = buffer_len(m);
   
         buffer_put_int(&oqueue, mlen);          buffer_put_int(&oqueue, mlen);
         buffer_append(&oqueue, buffer_ptr(m), mlen);          buffer_append(&oqueue, buffer_ptr(m), mlen);
         buffer_consume(m, mlen);          buffer_consume(m, mlen);
Line 263 
Line 398 
 send_status(u_int32_t id, u_int32_t error)  send_status(u_int32_t id, u_int32_t error)
 {  {
         Buffer msg;          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);          TRACE("sent status id %d error %d", id, error);
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_STATUS);          buffer_put_char(&msg, SSH_FXP_STATUS);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_int(&msg, error);          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);          send_msg(&msg);
         buffer_free(&msg);          buffer_free(&msg);
 }  }
Line 293 
Line 410 
 send_data_or_handle(char type, u_int32_t id, char *data, int dlen)  send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
 {  {
         Buffer msg;          Buffer msg;
   
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, type);          buffer_put_char(&msg, type);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
Line 306 
Line 422 
 send_data(u_int32_t id, char *data, int dlen)  send_data(u_int32_t id, char *data, int dlen)
 {  {
         TRACE("sent data id %d len %d", id, dlen);          TRACE("sent data id %d len %d", id, dlen);
         send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);          send_data_or_handle(SSH_FXP_DATA, id, data, dlen);
 }  }
   
 void  void
Line 314 
Line 430 
 {  {
         char *string;          char *string;
         int hlen;          int hlen;
   
         handle_to_string(handle, &string, &hlen);          handle_to_string(handle, &string, &hlen);
         TRACE("sent handle id %d handle %d", id, handle);          TRACE("sent handle id %d handle %d", id, handle);
         send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);          send_data_or_handle(SSH_FXP_HANDLE, id, string, hlen);
         xfree(string);          xfree(string);
 }  }
   
Line 326 
Line 441 
 {  {
         Buffer msg;          Buffer msg;
         int i;          int i;
   
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_NAME);          buffer_put_char(&msg, SSH_FXP_NAME);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_int(&msg, count);          buffer_put_int(&msg, count);
         TRACE("sent names id %d count %d", id, count);          TRACE("sent names id %d count %d", id, count);
Line 345 
Line 459 
 send_attrib(u_int32_t id, Attrib *a)  send_attrib(u_int32_t id, Attrib *a)
 {  {
         Buffer msg;          Buffer msg;
   
         TRACE("sent attrib id %d have 0x%x", id, a->flags);          TRACE("sent attrib id %d have 0x%x", id, a->flags);
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_ATTRS);          buffer_put_char(&msg, SSH_FXP_ATTRS);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         encode_attrib(&msg, a);          encode_attrib(&msg, a);
         send_msg(&msg);          send_msg(&msg);
Line 361 
Line 474 
 process_init(void)  process_init(void)
 {  {
         Buffer msg;          Buffer msg;
           int version = buffer_get_int(&iqueue);
   
         version = buffer_get_int(&iqueue);  
         TRACE("client version %d", version);          TRACE("client version %d", version);
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_VERSION);          buffer_put_char(&msg, SSH_FXP_VERSION);
         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);          buffer_put_int(&msg, SSH_FILEXFER_VERSION);
         send_msg(&msg);          send_msg(&msg);
         buffer_free(&msg);          buffer_free(&msg);
 }  }
Line 377 
Line 490 
         u_int32_t id, pflags;          u_int32_t id, pflags;
         Attrib *a;          Attrib *a;
         char *name;          char *name;
         int handle, fd, flags, mode, status = SSH2_FX_FAILURE;          int handle, fd, flags, mode, status = SSH_FX_FAILURE;
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         pflags = get_int();             /* portable flags */          pflags = get_int();
         a = get_attrib();          a = get_attrib();
         flags = flags_from_portable(pflags);          flags = flags_from_portable(pflags);
         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;          mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm : 0666;
         TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);          TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
         fd = open(name, flags, mode);          fd = open(name, flags, mode);
         if (fd < 0) {          if (fd < 0) {
Line 395 
Line 508 
                         close(fd);                          close(fd);
                 } else {                  } else {
                         send_handle(id, handle);                          send_handle(id, handle);
                         status = SSH2_FX_OK;                          status = SSH_FX_OK;
                 }                  }
         }          }
         if (status != SSH2_FX_OK)          if (status != SSH_FX_OK)
                 send_status(id, status);                  send_status(id, status);
         xfree(name);          xfree(name);
 }  }
Line 407 
Line 520 
 process_close(void)  process_close(void)
 {  {
         u_int32_t id;          u_int32_t id;
         int handle, ret, status = SSH2_FX_FAILURE;          int handle, ret, status = SSH_FX_FAILURE;
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         TRACE("close id %d handle %d", id, handle);          TRACE("close id %d handle %d", id, handle);
         ret = handle_close(handle);          ret = handle_close(handle);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
         send_status(id, status);          send_status(id, status);
 }  }
   
Line 421 
Line 534 
 process_read(void)  process_read(void)
 {  {
         char buf[64*1024];          char buf[64*1024];
         u_int32_t id, len;          u_int32_t id, off_high, off_low, len;
         int handle, fd, ret, status = SSH2_FX_FAILURE;          int handle, fd, ret, status = SSH_FX_FAILURE;
         u_int64_t off;          u_int64_t off;
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         off = get_int64();          off_high = get_int();
           off_low = get_int();
         len = get_int();          len = get_int();
   
         TRACE("read id %d handle %d off %llu len %d", id, handle,          off = (((u_int64_t) off_high) << 32) + off_low;
             (unsigned long long)off, len);          TRACE("read id %d handle %d off %qd len %d", id, handle, off, len);
         if (len > sizeof buf) {          if (len > sizeof buf) {
                 len = sizeof buf;                  len = sizeof buf;
                 log("read change len %d", len);                  log("read change len %d", len);
Line 446 
Line 560 
                         if (ret < 0) {                          if (ret < 0) {
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
                         } else if (ret == 0) {                          } else if (ret == 0) {
                                 status = SSH2_FX_EOF;                                  status = SSH_FX_EOF;
                         } else {                          } else {
                                 send_data(id, buf, ret);                                  send_data(id, buf, ret);
                                 status = SSH2_FX_OK;                                  status = SSH_FX_OK;
                         }                          }
                 }                  }
         }          }
         if (status != SSH2_FX_OK)          if (status != SSH_FX_OK)
                 send_status(id, status);                  send_status(id, status);
 }  }
   
 void  void
 process_write(void)  process_write(void)
 {  {
         u_int32_t id;          u_int32_t id, off_high, off_low;
         u_int64_t off;          u_int64_t off;
         u_int len;          u_int len;
         int handle, fd, ret, status = SSH2_FX_FAILURE;          int handle, fd, ret, status = SSH_FX_FAILURE;
         char *data;          char *data;
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         off = get_int64();          off_high = get_int();
           off_low = get_int();
         data = get_string(&len);          data = get_string(&len);
   
         TRACE("write id %d handle %d off %llu len %d", id, handle,          off = (((u_int64_t) off_high) << 32) + off_low;
             (unsigned long long)off, len);          TRACE("write id %d handle %d off %qd len %d", id, handle, off, len);
         fd = handle_to_fd(handle);          fd = handle_to_fd(handle);
         if (fd >= 0) {          if (fd >= 0) {
                 if (lseek(fd, off, SEEK_SET) < 0) {                  if (lseek(fd, off, SEEK_SET) < 0) {
Line 485 
Line 600 
                                 error("process_write: write failed");                                  error("process_write: write failed");
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
                         } else if (ret == len) {                          } else if (ret == len) {
                                 status = SSH2_FX_OK;                                  status = SSH_FX_OK;
                         } else {                          } else {
                                 log("nothing at all written");                                  log("nothing at all written");
                         }                          }
Line 498 
Line 613 
 void  void
 process_do_stat(int do_lstat)  process_do_stat(int do_lstat)
 {  {
         Attrib a;          Attrib *a;
         struct stat st;          struct stat st;
         u_int32_t id;          u_int32_t id;
         char *name;          char *name;
         int ret, status = SSH2_FX_FAILURE;          int ret, status = SSH_FX_FAILURE;
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
Line 511 
Line 626 
         if (ret < 0) {          if (ret < 0) {
                 status = errno_to_portable(errno);                  status = errno_to_portable(errno);
         } else {          } else {
                 stat_to_attrib(&st, &a);                  a = stat_to_attrib(&st);
                 send_attrib(id, &a);                  send_attrib(id, a);
                 status = SSH2_FX_OK;                  status = SSH_FX_OK;
         }          }
         if (status != SSH2_FX_OK)          if (status != SSH_FX_OK)
                 send_status(id, status);                  send_status(id, status);
         xfree(name);          xfree(name);
 }  }
Line 535 
Line 650 
 void  void
 process_fstat(void)  process_fstat(void)
 {  {
         Attrib a;          Attrib *a;
         struct stat st;          struct stat st;
         u_int32_t id;          u_int32_t id;
         int fd, ret, handle, status = SSH2_FX_FAILURE;          int fd, ret, handle, status = SSH_FX_FAILURE;
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
Line 549 
Line 664 
                 if (ret < 0) {                  if (ret < 0) {
                         status = errno_to_portable(errno);                          status = errno_to_portable(errno);
                 } else {                  } else {
                         stat_to_attrib(&st, &a);                          a = stat_to_attrib(&st);
                         send_attrib(id, &a);                          send_attrib(id, a);
                         status = SSH2_FX_OK;                          status = SSH_FX_OK;
                 }                  }
         }          }
         if (status != SSH2_FX_OK)          if (status != SSH_FX_OK)
                 send_status(id, status);                  send_status(id, status);
 }  }
   
Line 562 
Line 677 
 attrib_to_tv(Attrib *a)  attrib_to_tv(Attrib *a)
 {  {
         static struct timeval tv[2];          static struct timeval tv[2];
   
         tv[0].tv_sec = a->atime;          tv[0].tv_sec = a->atime;
         tv[0].tv_usec = 0;          tv[0].tv_usec = 0;
         tv[1].tv_sec = a->mtime;          tv[1].tv_sec = a->mtime;
Line 577 
Line 691 
         u_int32_t id;          u_int32_t id;
         char *name;          char *name;
         int ret;          int ret;
         int status = SSH2_FX_OK;          int status = SSH_FX_OK;
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         a = get_attrib();          a = get_attrib();
         TRACE("setstat id %d name %s", id, name);          TRACE("setstat id %d name %s", id, name);
         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {          if (a->flags & SSH_FXA_HAVE_PERM) {
                 ret = chmod(name, a->perm & 0777);                  ret = chmod(name, a->perm & 0777);
                 if (ret == -1)                  if (ret == -1)
                         status = errno_to_portable(errno);                          status = errno_to_portable(errno);
         }          }
         if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {          if (a->flags & SSH_FXA_HAVE_TIME) {
                 ret = utimes(name, attrib_to_tv(a));                  ret = utimes(name, attrib_to_tv(a));
                 if (ret == -1)                  if (ret == -1)
                         status = errno_to_portable(errno);                          status = errno_to_portable(errno);
         }          }
         if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {  
                 ret = chown(name, a->uid, a->gid);  
                 if (ret == -1)  
                         status = errno_to_portable(errno);  
         }  
         send_status(id, status);          send_status(id, status);
         xfree(name);          xfree(name);
 }  }
Line 608 
Line 717 
         Attrib *a;          Attrib *a;
         u_int32_t id;          u_int32_t id;
         int handle, fd, ret;          int handle, fd, ret;
         int status = SSH2_FX_OK;          int status = SSH_FX_OK;
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
Line 616 
Line 725 
         TRACE("fsetstat id %d handle %d", id, handle);          TRACE("fsetstat id %d handle %d", id, handle);
         fd = handle_to_fd(handle);          fd = handle_to_fd(handle);
         if (fd < 0) {          if (fd < 0) {
                 status = SSH2_FX_FAILURE;                  status = SSH_FX_FAILURE;
         } else {          } else {
                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {                  if (a->flags & SSH_FXA_HAVE_PERM) {
                         ret = fchmod(fd, a->perm & 0777);                          ret = fchmod(fd, a->perm & 0777);
                         if (ret == -1)                          if (ret == -1)
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
                 }                  }
                 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {                  if (a->flags & SSH_FXA_HAVE_TIME) {
                         ret = futimes(fd, attrib_to_tv(a));                          ret = futimes(fd, attrib_to_tv(a));
                         if (ret == -1)                          if (ret == -1)
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
                 }                  }
                 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {  
                         ret = fchown(fd, a->uid, a->gid);  
                         if (ret == -1)  
                                 status = errno_to_portable(errno);  
                 }  
         }          }
         send_status(id, status);          send_status(id, status);
 }  }
Line 642 
Line 746 
 {  {
         DIR *dirp = NULL;          DIR *dirp = NULL;
         char *path;          char *path;
         int handle, status = SSH2_FX_FAILURE;          int handle, status = SSH_FX_FAILURE;
         u_int32_t id;          u_int32_t id;
   
         id = get_int();          id = get_int();
         path = get_string(NULL);          path = get_string(NULL);
         TRACE("opendir id %d path %s", id, path);          TRACE("opendir id %d path %s", id, path);
         dirp = opendir(path);          dirp = opendir(path);
         if (dirp == NULL) {          if (dirp == NULL) {
                 status = errno_to_portable(errno);                  status = errno_to_portable(errno);
         } else {          } else {
Line 657 
Line 761 
                         closedir(dirp);                          closedir(dirp);
                 } else {                  } else {
                         send_handle(id, handle);                          send_handle(id, handle);
                         status = SSH2_FX_OK;                          status = SSH_FX_OK;
                 }                  }
   
         }          }
         if (status != SSH2_FX_OK)          if (status != SSH_FX_OK)
                 send_status(id, status);                  send_status(id, status);
         xfree(path);          xfree(path);
 }  }
   
 /*  
  * drwxr-xr-x    5 markus   markus       1024 Jan 13 18:39 .ssh  
  */  
 char *  char *
 ls_file(char *name, struct stat *st)  ls_file(char *name, struct stat *st)
 {  {
         int sz = 0;          char buf[1024];
         struct passwd *pw;          snprintf(buf, sizeof buf, "0%o %d %d %qd %d %s",
         struct group *gr;              st->st_mode, st->st_uid, st->st_gid, (long long)st->st_size,(int) st->st_mtime,
         struct tm *ltime = localtime(&st->st_mtime);              name);
         char *user, *group;  
         char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];  
   
         strmode(st->st_mode, mode);  
         if ((pw = getpwuid(st->st_uid)) != NULL) {  
                 user = pw->pw_name;  
         } else {  
                 snprintf(ubuf, sizeof ubuf, "%d", st->st_uid);  
                 user = ubuf;  
         }  
         if ((gr = getgrgid(st->st_gid)) != NULL) {  
                 group = gr->gr_name;  
         } else {  
                 snprintf(gbuf, sizeof gbuf, "%d", st->st_gid);  
                 group = gbuf;  
         }  
         if (ltime != NULL) {  
                 if (time(NULL) - st->st_mtime < (365*24*60*60)/2)  
                         sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);  
                 else  
                         sz = strftime(tbuf, sizeof tbuf, "%b %e  %Y", ltime);  
         }  
         if (sz == 0)  
                 tbuf[0] = '\0';  
         snprintf(buf, sizeof buf, "%s %3d %-8.8s %-8.8s %8llu %s %s", mode,  
             st->st_nlink, user, group, (unsigned long long)st->st_size, tbuf, name);  
         return xstrdup(buf);          return xstrdup(buf);
 }  }
   
Line 720 
Line 795 
         dirp = handle_to_dir(handle);          dirp = handle_to_dir(handle);
         path = handle_to_name(handle);          path = handle_to_name(handle);
         if (dirp == NULL || path == NULL) {          if (dirp == NULL || path == NULL) {
                 send_status(id, SSH2_FX_FAILURE);                  send_status(id, SSH_FX_FAILURE);
         } else {          } else {
                   Attrib *a;
                 struct stat st;                  struct stat st;
                 char pathname[1024];                  char pathname[1024];
                 Stat *stats;                  Stat *stats;
Line 737 
Line 813 
                             "%s/%s", path, dp->d_name);                              "%s/%s", path, dp->d_name);
                         if (lstat(pathname, &st) < 0)                          if (lstat(pathname, &st) < 0)
                                 continue;                                  continue;
                         stat_to_attrib(&st, &(stats[count].attrib));                          a = stat_to_attrib(&st);
                           stats[count].attrib = *a;
                         stats[count].name = xstrdup(dp->d_name);                          stats[count].name = xstrdup(dp->d_name);
                         stats[count].long_name = ls_file(dp->d_name, &st);                          stats[count].long_name = ls_file(dp->d_name, &st);
                         count++;                          count++;
                         /* send up to 100 entries in one message */                          /* send up to 100 entries in one message */
                         /* XXX check packet size instead */  
                         if (count == 100)                          if (count == 100)
                                 break;                                  break;
                 }                  }
                 if (count > 0) {                  send_names(id, count, stats);
                         send_names(id, count, stats);                  for(i = 0; i < count; i++) {
                         for(i = 0; i < count; i++) {                          xfree(stats[i].name);
                                 xfree(stats[i].name);                          xfree(stats[i].long_name);
                                 xfree(stats[i].long_name);  
                         }  
                 } else {  
                         send_status(id, SSH2_FX_EOF);  
                 }                  }
                 xfree(stats);                  xfree(stats);
         }          }
Line 764 
Line 836 
 {  {
         char *name;          char *name;
         u_int32_t id;          u_int32_t id;
         int status = SSH2_FX_FAILURE;          int status = SSH_FX_FAILURE;
         int ret;          int ret;
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         TRACE("remove id %d name %s", id, name);          TRACE("remove id %d name %s", id, name);
         ret = unlink(name);          ret = remove(name);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
         send_status(id, status);          send_status(id, status);
         xfree(name);          xfree(name);
 }  }
Line 782 
Line 854 
         Attrib *a;          Attrib *a;
         u_int32_t id;          u_int32_t id;
         char *name;          char *name;
         int ret, mode, status = SSH2_FX_FAILURE;          int ret, mode, status = SSH_FX_FAILURE;
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         a = get_attrib();          a = get_attrib();
         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?          mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm & 0777 : 0777;
             a->perm & 0777 : 0777;  
         TRACE("mkdir id %d name %s mode 0%o", id, name, mode);          TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
         ret = mkdir(name, mode);          ret = mkdir(name, mode);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
         send_status(id, status);          send_status(id, status);
         xfree(name);          xfree(name);
 }  }
Line 807 
Line 878 
         name = get_string(NULL);          name = get_string(NULL);
         TRACE("rmdir id %d name %s", id, name);          TRACE("rmdir id %d name %s", id, name);
         ret = rmdir(name);          ret = rmdir(name);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
         send_status(id, status);          send_status(id, status);
         xfree(name);          xfree(name);
 }  }
Line 841 
Line 912 
 process_rename(void)  process_rename(void)
 {  {
         u_int32_t id;          u_int32_t id;
         struct stat st;  
         char *oldpath, *newpath;          char *oldpath, *newpath;
         int ret, status = SSH2_FX_FAILURE;          int ret, status;
   
         id = get_int();          id = get_int();
         oldpath = get_string(NULL);          oldpath = get_string(NULL);
         newpath = get_string(NULL);          newpath = get_string(NULL);
         TRACE("rename id %d old %s new %s", id, oldpath, newpath);          TRACE("rename id %d old %s new %s", id, oldpath, newpath);
         /* fail if 'newpath' exists */          ret = rename(oldpath, newpath);
         if (stat(newpath, &st) == -1) {          status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
                 ret = rename(oldpath, newpath);  
                 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;  
         }  
         send_status(id, status);          send_status(id, status);
         xfree(oldpath);          xfree(oldpath);
         xfree(newpath);          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)  
 {  
         u_int32_t id;  
         char *request;  
   
         id = get_int();  
         request = get_string(NULL);  
         send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */  
         xfree(request);  
 }  
   
 /* stolen from ssh-agent */  /* stolen from ssh-agent */
   
 void  void
 process(void)  process(void)
 {  {
         u_int msg_len;          unsigned int msg_len;
         u_int type;          unsigned int type;
         u_char *cp;          unsigned char *cp;
   
         if (buffer_len(&iqueue) < 5)          if (buffer_len(&iqueue) < 5)
                 return;         /* Incomplete message. */                  return;         /* Incomplete message. */
         cp = (u_char *) buffer_ptr(&iqueue);          cp = (unsigned char *) buffer_ptr(&iqueue);
         msg_len = GET_32BIT(cp);          msg_len = GET_32BIT(cp);
         if (msg_len > 256 * 1024) {          if (msg_len > 256 * 1024) {
                 error("bad message ");                  error("bad message ");
Line 938 
Line 949 
         buffer_consume(&iqueue, 4);          buffer_consume(&iqueue, 4);
         type = buffer_get_char(&iqueue);          type = buffer_get_char(&iqueue);
         switch (type) {          switch (type) {
         case SSH2_FXP_INIT:          case SSH_FXP_INIT:
                 process_init();                  process_init();
                 break;                  break;
         case SSH2_FXP_OPEN:          case SSH_FXP_OPEN:
                 process_open();                  process_open();
                 break;                  break;
         case SSH2_FXP_CLOSE:          case SSH_FXP_CLOSE:
                 process_close();                  process_close();
                 break;                  break;
         case SSH2_FXP_READ:          case SSH_FXP_READ:
                 process_read();                  process_read();
                 break;                  break;
         case SSH2_FXP_WRITE:          case SSH_FXP_WRITE:
                 process_write();                  process_write();
                 break;                  break;
         case SSH2_FXP_LSTAT:          case SSH_FXP_LSTAT:
                 process_lstat();                  process_lstat();
                 break;                  break;
         case SSH2_FXP_FSTAT:          case SSH_FXP_FSTAT:
                 process_fstat();                  process_fstat();
                 break;                  break;
         case SSH2_FXP_SETSTAT:          case SSH_FXP_SETSTAT:
                 process_setstat();                  process_setstat();
                 break;                  break;
         case SSH2_FXP_FSETSTAT:          case SSH_FXP_FSETSTAT:
                 process_fsetstat();                  process_fsetstat();
                 break;                  break;
         case SSH2_FXP_OPENDIR:          case SSH_FXP_OPENDIR:
                 process_opendir();                  process_opendir();
                 break;                  break;
         case SSH2_FXP_READDIR:          case SSH_FXP_READDIR:
                 process_readdir();                  process_readdir();
                 break;                  break;
         case SSH2_FXP_REMOVE:          case SSH_FXP_REMOVE:
                 process_remove();                  process_remove();
                 break;                  break;
         case SSH2_FXP_MKDIR:          case SSH_FXP_MKDIR:
                 process_mkdir();                  process_mkdir();
                 break;                  break;
         case SSH2_FXP_RMDIR:          case SSH_FXP_RMDIR:
                 process_rmdir();                  process_rmdir();
                 break;                  break;
         case SSH2_FXP_REALPATH:          case SSH_FXP_REALPATH:
                 process_realpath();                  process_realpath();
                 break;                  break;
         case SSH2_FXP_STAT:          case SSH_FXP_STAT:
                 process_stat();                  process_stat();
                 break;                  break;
         case SSH2_FXP_RENAME:          case SSH_FXP_RENAME:
                 process_rename();                  process_rename();
                 break;                  break;
         case SSH2_FXP_READLINK:  
                 process_readlink();  
                 break;  
         case SSH2_FXP_SYMLINK:  
                 process_symlink();  
                 break;  
         case SSH2_FXP_EXTENDED:  
                 process_extended();  
                 break;  
         default:          default:
                 error("Unknown message %d", type);                  error("Unknown message %d", type);
                 break;                  break;
Line 1007 
Line 1009 
 int  int
 main(int ac, char **av)  main(int ac, char **av)
 {  {
         fd_set *rset, *wset;          fd_set rset, wset;
         int in, out, max;          int in, out, max;
         ssize_t len, olen, set_size;          ssize_t len, olen;
   
         /* XXX should use getopt */  
   
         handle_init();          handle_init();
   
 #ifdef DEBUG_SFTP_SERVER  
         log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);  
 #endif  
   
         in = dup(STDIN_FILENO);          in = dup(STDIN_FILENO);
         out = dup(STDOUT_FILENO);          out = dup(STDOUT_FILENO);
   
Line 1031 
Line 1027 
         buffer_init(&iqueue);          buffer_init(&iqueue);
         buffer_init(&oqueue);          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 (;;) {          for (;;) {
                 memset(rset, 0, set_size);                  FD_ZERO(&rset);
                 memset(wset, 0, set_size);                  FD_ZERO(&wset);
   
                 FD_SET(in, rset);                  FD_SET(in, &rset);
                 olen = buffer_len(&oqueue);                  olen = buffer_len(&oqueue);
                 if (olen > 0)                  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)                          if (errno == EINTR)
                                 continue;                                  continue;
                         exit(2);                          exit(2);
                 }                  }
   
                 /* copy stdin to iqueue */                  /* copy stdin to iqueue */
                 if (FD_ISSET(in, rset)) {                  if (FD_ISSET(in, &rset)) {
                         char buf[4*4096];                          char buf[4*4096];
                         len = read(in, buf, sizeof buf);                          len = read(in, buf, sizeof buf);
                         if (len == 0) {                          if (len == 0) {
Line 1065 
Line 1057 
                         }                          }
                 }                  }
                 /* send oqueue to stdout */                  /* send oqueue to stdout */
                 if (FD_ISSET(out, wset)) {                  if (FD_ISSET(out, &wset)) {
                         len = write(out, buffer_ptr(&oqueue), olen);                          len = write(out, buffer_ptr(&oqueue), olen);
                         if (len < 0) {                          if (len < 0) {
                                 error("write error");                                  error("write error");

Legend:
Removed from v.1.6.4.3  
changed lines
  Added in v.1.7