[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.48.2.2 and 1.49

version 1.48.2.2, 2006/10/06 03:19:33 version 1.49, 2005/09/13 23:40:07
Line 1 
Line 1 
 /* $OpenBSD$ */  
 /*  /*
  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.   * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
  *   *
Line 14 
Line 13 
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */   */
   #include "includes.h"
   RCSID("$OpenBSD$");
   
 #include <sys/types.h>  
 #include <sys/stat.h>  
 #include <sys/time.h>  
 #include <sys/param.h>  
   
 #include <dirent.h>  
 #include <errno.h>  
 #include <fcntl.h>  
 #include <stdlib.h>  
 #include <stdio.h>  
 #include <string.h>  
 #include <pwd.h>  
 #include <time.h>  
 #include <unistd.h>  
 #include <stdarg.h>  
   
 #include "xmalloc.h"  
 #include "buffer.h"  #include "buffer.h"
   #include "bufaux.h"
   #include "getput.h"
 #include "log.h"  #include "log.h"
   #include "xmalloc.h"
 #include "misc.h"  #include "misc.h"
 #include "uidswap.h"  
   
 #include "sftp.h"  #include "sftp.h"
 #include "sftp-common.h"  #include "sftp-common.h"
Line 44 
Line 30 
 #define get_int64()                     buffer_get_int64(&iqueue);  #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
   
 /* Our verbosity */  
 LogLevel log_level = SYSLOG_LEVEL_ERROR;  
   
 /* Our client */  
 struct passwd *pw = NULL;  
 char *client_addr = NULL;  
   
 /* input and output queue */  /* input and output queue */
 Buffer iqueue;  Buffer iqueue;
 Buffer oqueue;  Buffer oqueue;
Line 122 
Line 102 
         return flags;          return flags;
 }  }
   
 static const char *  
 string_from_portable(int pflags)  
 {  
         static char ret[128];  
   
         *ret = '\0';  
   
 #define PAPPEND(str)    {                               \  
                 if (*ret != '\0')                       \  
                         strlcat(ret, ",", sizeof(ret)); \  
                 strlcat(ret, str, sizeof(ret));         \  
         }  
   
         if (pflags & SSH2_FXF_READ)  
                 PAPPEND("READ")  
         if (pflags & SSH2_FXF_WRITE)  
                 PAPPEND("WRITE")  
         if (pflags & SSH2_FXF_CREAT)  
                 PAPPEND("CREATE")  
         if (pflags & SSH2_FXF_TRUNC)  
                 PAPPEND("TRUNCATE")  
         if (pflags & SSH2_FXF_EXCL)  
                 PAPPEND("EXCL")  
   
         return ret;  
 }  
   
 static Attrib *  static Attrib *
 get_attrib(void)  get_attrib(void)
 {  {
Line 163 
Line 116 
         DIR *dirp;          DIR *dirp;
         int fd;          int fd;
         char *name;          char *name;
         u_int64_t bytes_read, bytes_write;  
 };  };
   
 enum {  enum {
Line 194 
Line 146 
                         handles[i].dirp = dirp;                          handles[i].dirp = dirp;
                         handles[i].fd = fd;                          handles[i].fd = fd;
                         handles[i].name = xstrdup(name);                          handles[i].name = xstrdup(name);
                         handles[i].bytes_read = handles[i].bytes_write = 0;  
                         return i;                          return i;
                 }                  }
         }          }
Line 214 
Line 165 
         if (stringp == NULL || hlenp == NULL)          if (stringp == NULL || hlenp == NULL)
                 return -1;                  return -1;
         *stringp = xmalloc(sizeof(int32_t));          *stringp = xmalloc(sizeof(int32_t));
         put_u32(*stringp, handle);          PUT_32BIT(*stringp, handle);
         *hlenp = sizeof(int32_t);          *hlenp = sizeof(int32_t);
         return 0;          return 0;
 }  }
Line 226 
Line 177 
   
         if (hlen != sizeof(int32_t))          if (hlen != sizeof(int32_t))
                 return -1;                  return -1;
         val = get_u32(handle);          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 258 
Line 209 
         return -1;          return -1;
 }  }
   
 static void  
 handle_update_read(int handle, ssize_t bytes)  
 {  
         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)  
                 handles[handle].bytes_read += bytes;  
 }  
   
 static void  
 handle_update_write(int handle, ssize_t bytes)  
 {  
         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)  
                 handles[handle].bytes_write += bytes;  
 }  
   
 static u_int64_t  
 handle_bytes_read(int handle)  
 {  
         if (handle_is_ok(handle, HANDLE_FILE))  
                 return (handles[handle].bytes_read);  
         return 0;  
 }  
   
 static u_int64_t  
 handle_bytes_write(int handle)  
 {  
         if (handle_is_ok(handle, HANDLE_FILE))  
                 return (handles[handle].bytes_write);  
         return 0;  
 }  
   
 static int  static int
 handle_close(int handle)  handle_close(int handle)
 {  {
Line 307 
Line 228 
         return ret;          return ret;
 }  }
   
 static void  
 handle_log_close(int handle, char *emsg)  
 {  
         if (handle_is_ok(handle, HANDLE_FILE)) {  
                 logit("%s%sclose \"%s\" bytes read %llu written %llu",  
                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",  
                     handle_to_name(handle),  
                     handle_bytes_read(handle), handle_bytes_write(handle));  
         } else {  
                 logit("%s%sclosedir \"%s\"",  
                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",  
                     handle_to_name(handle));  
         }  
 }  
   
 static void  
 handle_log_exit(void)  
 {  
         u_int i;  
   
         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)  
                 if (handles[i].use != HANDLE_UNUSED)  
                         handle_log_close(i, "forced");  
 }  
   
 static int  static int
 get_handle(void)  get_handle(void)
 {  {
Line 358 
Line 254 
         buffer_consume(m, mlen);          buffer_consume(m, mlen);
 }  }
   
 static const char *  static void
 status_to_message(u_int32_t status)  send_status(u_int32_t id, u_int32_t status)
 {  {
           Buffer msg;
         const char *status_messages[] = {          const char *status_messages[] = {
                 "Success",                      /* SSH_FX_OK */                  "Success",                      /* SSH_FX_OK */
                 "End of file",                  /* SSH_FX_EOF */                  "End of file",                  /* SSH_FX_EOF */
Line 373 
Line 270 
                 "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */                  "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
                 "Unknown error"                 /* Others */                  "Unknown error"                 /* Others */
         };          };
         return (status_messages[MIN(status,SSH2_FX_MAX)]);  
 }  
   
 static void          TRACE("sent status id %u error %u", id, status);
 send_status(u_int32_t id, u_int32_t status)  
 {  
         Buffer msg;  
   
         debug3("request %u: sent status %u", id, status);  
         if (log_level > SYSLOG_LEVEL_VERBOSE ||  
             (status != SSH2_FX_OK && status != SSH2_FX_EOF))  
                 logit("sent status %s", status_to_message(status));  
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_STATUS);          buffer_put_char(&msg, SSH2_FXP_STATUS);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_int(&msg, status);          buffer_put_int(&msg, status);
         if (version >= 3) {          if (version >= 3) {
                 buffer_put_cstring(&msg, status_to_message(status));                  buffer_put_cstring(&msg,
                       status_messages[MIN(status,SSH2_FX_MAX)]);
                 buffer_put_cstring(&msg, "");                  buffer_put_cstring(&msg, "");
         }          }
         send_msg(&msg);          send_msg(&msg);
Line 412 
Line 300 
 static void  static void
 send_data(u_int32_t id, const char *data, int dlen)  send_data(u_int32_t id, const char *data, int dlen)
 {  {
         debug("request %u: sent data len %d", id, dlen);          TRACE("sent data id %u len %d", id, dlen);
         send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);          send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
 }  }
   
Line 423 
Line 311 
         int hlen;          int hlen;
   
         handle_to_string(handle, &string, &hlen);          handle_to_string(handle, &string, &hlen);
         debug("request %u: sent handle handle %d", id, handle);          TRACE("sent handle id %u handle %d", id, handle);
         send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);          send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
         xfree(string);          xfree(string);
 }  }
Line 438 
Line 326 
         buffer_put_char(&msg, SSH2_FXP_NAME);          buffer_put_char(&msg, SSH2_FXP_NAME);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_int(&msg, count);          buffer_put_int(&msg, count);
         debug("request %u: sent names count %d", id, count);          TRACE("sent names id %u count %d", id, count);
         for (i = 0; i < count; i++) {          for (i = 0; i < count; i++) {
                 buffer_put_cstring(&msg, stats[i].name);                  buffer_put_cstring(&msg, stats[i].name);
                 buffer_put_cstring(&msg, stats[i].long_name);                  buffer_put_cstring(&msg, stats[i].long_name);
Line 453 
Line 341 
 {  {
         Buffer msg;          Buffer msg;
   
         debug("request %u: sent attrib have 0x%x", id, a->flags);          TRACE("sent attrib id %u have 0x%x", id, a->flags);
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_ATTRS);          buffer_put_char(&msg, SSH2_FXP_ATTRS);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
Line 470 
Line 358 
         Buffer msg;          Buffer msg;
   
         version = get_int();          version = get_int();
         verbose("received 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, SSH2_FXP_VERSION);
         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);          buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
Line 489 
Line 377 
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         pflags = get_int();             /* portable flags */          pflags = get_int();             /* portable flags */
         debug3("request %u: open flags %d", id, pflags);  
         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 & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
         logit("open \"%s\" flags %s mode 0%o",          TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
             name, string_from_portable(pflags), mode);  
         fd = open(name, flags, mode);          fd = open(name, flags, mode);
         if (fd < 0) {          if (fd < 0) {
                 status = errno_to_portable(errno);                  status = errno_to_portable(errno);
Line 520 
Line 406 
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         debug3("request %u: close handle %u", id, handle);          TRACE("close id %u handle %d", id, handle);
         handle_log_close(handle, NULL);  
         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) : SSH2_FX_OK;
         send_status(id, status);          send_status(id, status);
Line 540 
Line 425 
         off = get_int64();          off = get_int64();
         len = get_int();          len = get_int();
   
         debug("request %u: read \"%s\" (handle %d) off %llu len %d",          TRACE("read id %u handle %d off %llu len %d", id, handle,
             id, handle_to_name(handle), handle, (unsigned long long)off, len);              (unsigned long long)off, len);
         if (len > sizeof buf) {          if (len > sizeof buf) {
                 len = sizeof buf;                  len = sizeof buf;
                 debug2("read change len %d", len);                  logit("read change len %d", len);
         }          }
         fd = handle_to_fd(handle);          fd = handle_to_fd(handle);
         if (fd >= 0) {          if (fd >= 0) {
Line 560 
Line 445 
                         } else {                          } else {
                                 send_data(id, buf, ret);                                  send_data(id, buf, ret);
                                 status = SSH2_FX_OK;                                  status = SSH2_FX_OK;
                                 handle_update_read(handle, ret);  
                         }                          }
                 }                  }
         }          }
Line 582 
Line 466 
         off = get_int64();          off = get_int64();
         data = get_string(&len);          data = get_string(&len);
   
         debug("request %u: write \"%s\" (handle %d) off %llu len %d",          TRACE("write id %u handle %d off %llu len %d", id, handle,
             id, handle_to_name(handle), handle, (unsigned long long)off, len);              (unsigned long long)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 597 
Line 481 
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
                         } else if ((size_t)ret == len) {                          } else if ((size_t)ret == len) {
                                 status = SSH2_FX_OK;                                  status = SSH2_FX_OK;
                                 handle_update_write(handle, ret);  
                         } else {                          } else {
                                 debug2("nothing at all written");                                  logit("nothing at all written");
                         }                          }
                 }                  }
         }          }
Line 618 
Line 501 
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         debug3("request %u: %sstat", id, do_lstat ? "l" : "");          TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
         verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);  
         ret = do_lstat ? lstat(name, &st) : stat(name, &st);          ret = do_lstat ? lstat(name, &st) : stat(name, &st);
         if (ret < 0) {          if (ret < 0) {
                 status = errno_to_portable(errno);                  status = errno_to_portable(errno);
Line 655 
Line 537 
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         debug("request %u: fstat \"%s\" (handle %u)",          TRACE("fstat id %u handle %d", id, handle);
             id, handle_to_name(handle), handle);  
         fd = handle_to_fd(handle);          fd = handle_to_fd(handle);
         if (fd  >= 0) {          if (fd  >= 0) {
                 ret = fstat(fd, &st);                  ret = fstat(fd, &st);
Line 695 
Line 576 
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         a = get_attrib();          a = get_attrib();
         debug("request %u: setstat name \"%s\"", id, name);          TRACE("setstat id %u name %s", id, name);
         if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {          if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
                 logit("set \"%s\" size %llu", name, a->size);  
                 ret = truncate(name, a->size);                  ret = truncate(name, a->size);
                 if (ret == -1)                  if (ret == -1)
                         status = errno_to_portable(errno);                          status = errno_to_portable(errno);
         }          }
         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {          if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
                 logit("set \"%s\" mode %04o", name, a->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 & SSH2_FILEXFER_ATTR_ACMODTIME) {
                 char buf[64];  
                 time_t t = a->mtime;  
   
                 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",  
                     localtime(&t));  
                 logit("set \"%s\" modtime %s", name, buf);  
                 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) {          if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
                 logit("set \"%s\" owner %lu group %lu", name,  
                     (u_long)a->uid, (u_long)a->gid);  
                 ret = chown(name, a->uid, a->gid);                  ret = chown(name, a->uid, a->gid);
                 if (ret == -1)                  if (ret == -1)
                         status = errno_to_portable(errno);                          status = errno_to_portable(errno);
Line 741 
Line 612 
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         a = get_attrib();          a = get_attrib();
         debug("request %u: fsetstat handle %d", id, handle);          TRACE("fsetstat id %u 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 = SSH2_FX_FAILURE;
         } else {          } else {
                 char *name = handle_to_name(handle);  
   
                 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {                  if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
                         logit("set \"%s\" size %llu", name, a->size);  
                         ret = ftruncate(fd, a->size);                          ret = ftruncate(fd, a->size);
                         if (ret == -1)                          if (ret == -1)
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
                 }                  }
                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {                  if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
                         logit("set \"%s\" mode %04o", name, a->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 & SSH2_FILEXFER_ATTR_ACMODTIME) {
                         char buf[64];  
                         time_t t = a->mtime;  
   
                         strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",  
                             localtime(&t));  
                         logit("set \"%s\" modtime %s", name, buf);  
                         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) {                  if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
                         logit("set \"%s\" owner %lu group %lu", name,  
                             (u_long)a->uid, (u_long)a->gid);  
                         ret = fchown(fd, a->uid, a->gid);                          ret = fchown(fd, a->uid, a->gid);
                         if (ret == -1)                          if (ret == -1)
                                 status = errno_to_portable(errno);                                  status = errno_to_portable(errno);
Line 792 
Line 651 
   
         id = get_int();          id = get_int();
         path = get_string(NULL);          path = get_string(NULL);
         debug3("request %u: opendir", id);          TRACE("opendir id %u path %s", id, path);
         logit("opendir \"%s\"", path);  
         dirp = opendir(path);          dirp = opendir(path);
         if (dirp == NULL) {          if (dirp == NULL) {
                 status = errno_to_portable(errno);                  status = errno_to_portable(errno);
Line 823 
Line 681 
   
         id = get_int();          id = get_int();
         handle = get_handle();          handle = get_handle();
         debug("request %u: readdir \"%s\" (handle %d)", id,          TRACE("readdir id %u handle %d", id, handle);
             handle_to_name(handle), handle);  
         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, SSH2_FX_FAILURE);
         } else {          } else {
                 struct stat st;                  struct stat st;
                 char pathname[MAXPATHLEN];                  char pathname[1024];
                 Stat *stats;                  Stat *stats;
                 int nstats = 10, count = 0, i;                  int nstats = 10, count = 0, i;
   
                 stats = xcalloc(nstats, sizeof(Stat));                  stats = xmalloc(nstats * sizeof(Stat));
                 while ((dp = readdir(dirp)) != NULL) {                  while ((dp = readdir(dirp)) != NULL) {
                         if (count >= nstats) {                          if (count >= nstats) {
                                 nstats *= 2;                                  nstats *= 2;
                                 stats = xrealloc(stats, nstats, sizeof(Stat));                                  stats = xrealloc(stats, nstats * sizeof(Stat));
                         }                          }
 /* XXX OVERFLOW ? */  /* XXX OVERFLOW ? */
                         snprintf(pathname, sizeof pathname, "%s%s%s", path,                          snprintf(pathname, sizeof pathname, "%s%s%s", path,
Line 878 
Line 735 
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         debug3("request %u: remove", id);          TRACE("remove id %u name %s", id, name);
         logit("remove name \"%s\"", name);  
         ret = unlink(name);          ret = unlink(name);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
         send_status(id, status);          send_status(id, status);
Line 899 
Line 755 
         a = get_attrib();          a = get_attrib();
         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?          mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
             a->perm & 0777 : 0777;              a->perm & 0777 : 0777;
         debug3("request %u: mkdir", id);          TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
         logit("mkdir name \"%s\" mode 0%o", 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) : SSH2_FX_OK;
         send_status(id, status);          send_status(id, status);
Line 916 
Line 771 
   
         id = get_int();          id = get_int();
         name = get_string(NULL);          name = get_string(NULL);
         debug3("request %u: rmdir", id);          TRACE("rmdir id %u name %s", id, name);
         logit("rmdir name \"%s\"", name);  
         ret = rmdir(name);          ret = rmdir(name);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
         send_status(id, status);          send_status(id, status);
Line 937 
Line 791 
                 xfree(path);                  xfree(path);
                 path = xstrdup(".");                  path = xstrdup(".");
         }          }
         debug3("request %u: realpath", id);          TRACE("realpath id %u path %s", id, path);
         verbose("realpath \"%s\"", path);  
         if (realpath(path, resolvedname) == NULL) {          if (realpath(path, resolvedname) == NULL) {
                 send_status(id, errno_to_portable(errno));                  send_status(id, errno_to_portable(errno));
         } else {          } else {
Line 961 
Line 814 
         id = get_int();          id = get_int();
         oldpath = get_string(NULL);          oldpath = get_string(NULL);
         newpath = get_string(NULL);          newpath = get_string(NULL);
         debug3("request %u: rename", id);          TRACE("rename id %u old %s new %s", id, oldpath, newpath);
         logit("rename old \"%s\" new \"%s\"", oldpath, newpath);  
         status = SSH2_FX_FAILURE;          status = SSH2_FX_FAILURE;
         if (lstat(oldpath, &sb) == -1)          if (lstat(oldpath, &sb) == -1)
                 status = errno_to_portable(errno);                  status = errno_to_portable(errno);
Line 1013 
Line 865 
   
         id = get_int();          id = get_int();
         path = get_string(NULL);          path = get_string(NULL);
         debug3("request %u: readlink", id);          TRACE("readlink id %u path %s", id, path);
         verbose("readlink \"%s\"", path);  
         if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)          if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
                 send_status(id, errno_to_portable(errno));                  send_status(id, errno_to_portable(errno));
         else {          else {
Line 1038 
Line 889 
         id = get_int();          id = get_int();
         oldpath = get_string(NULL);          oldpath = get_string(NULL);
         newpath = get_string(NULL);          newpath = get_string(NULL);
         debug3("request %u: symlink", id);          TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
         logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);  
         /* this will fail if 'newpath' exists */          /* this will fail if 'newpath' exists */
         ret = symlink(oldpath, newpath);          ret = symlink(oldpath, newpath);
         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;          status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
Line 1075 
Line 925 
         if (buf_len < 5)          if (buf_len < 5)
                 return;         /* Incomplete message. */                  return;         /* Incomplete message. */
         cp = buffer_ptr(&iqueue);          cp = buffer_ptr(&iqueue);
         msg_len = get_u32(cp);          msg_len = GET_32BIT(cp);
         if (msg_len > SFTP_MAX_MSG_LENGTH) {          if (msg_len > 256 * 1024) {
                 error("bad message from %s local user %s",                  error("bad message ");
                     client_addr, pw->pw_name);                  exit(11);
                 cleanup_exit(11);  
         }          }
         if (buf_len < msg_len + 4)          if (buf_len < msg_len + 4)
                 return;                  return;
Line 1153 
Line 1002 
         }          }
         /* discard the remaining bytes from the current packet */          /* discard the remaining bytes from the current packet */
         if (buf_len < buffer_len(&iqueue))          if (buf_len < buffer_len(&iqueue))
                 fatal("iqueue grew unexpectedly");                  fatal("iqueue grows");
         consumed = buf_len - buffer_len(&iqueue);          consumed = buf_len - buffer_len(&iqueue);
         if (msg_len < consumed)          if (msg_len < consumed)
                 fatal("msg_len %d < consumed %d", msg_len, consumed);                  fatal("msg_len %d < consumed %d", msg_len, consumed);
Line 1161 
Line 1010 
                 buffer_consume(&iqueue, msg_len - consumed);                  buffer_consume(&iqueue, msg_len - consumed);
 }  }
   
 /* Cleanup handler that logs active handles upon normal exit */  
 void  
 cleanup_exit(int i)  
 {  
         if (pw != NULL && client_addr != NULL) {  
                 handle_log_exit();  
                 logit("session closed for local user %s from [%s]",  
                     pw->pw_name, client_addr);  
         }  
         _exit(i);  
 }  
   
 static void  
 usage(void)  
 {  
         extern char *__progname;  
   
         fprintf(stderr,  
             "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);  
         exit(1);  
 }  
   
 int  int
 main(int argc, char **argv)  main(int ac, char **av)
 {  {
         fd_set *rset, *wset;          fd_set *rset, *wset;
         int in, out, max, ch, skipargs = 0, log_stderr = 0;          int in, out, max;
         ssize_t len, olen, set_size;          ssize_t len, olen, set_size;
         SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;  
         char *cp;  
   
         extern char *optarg;  
         extern char *__progname;  
   
         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */          /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
         sanitise_stdfd();          sanitise_stdfd();
   
         log_init(__progname, log_level, log_facility, log_stderr);          /* XXX should use getopt */
   
         while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {  
                 switch (ch) {  
                 case 'c':  
                         /*  
                          * Ignore all arguments if we are invoked as a  
                          * shell using "sftp-server -c command"  
                          */  
                         skipargs = 1;  
                         break;  
                 case 'e':  
                         log_stderr = 1;  
                         break;  
                 case 'l':  
                         log_level = log_level_number(optarg);  
                         if (log_level == SYSLOG_LEVEL_NOT_SET)  
                                 error("Invalid log level \"%s\"", optarg);  
                         break;  
                 case 'f':  
                         log_facility = log_facility_number(optarg);  
                         if (log_level == SYSLOG_FACILITY_NOT_SET)  
                                 error("Invalid log facility \"%s\"", optarg);  
                         break;  
                 case 'h':  
                 default:  
                         usage();  
                 }  
         }  
   
         log_init(__progname, log_level, log_facility, log_stderr);  
   
         if ((cp = getenv("SSH_CONNECTION")) != NULL) {  
                 client_addr = xstrdup(cp);  
                 if ((cp = strchr(client_addr, ' ')) == NULL)  
                         fatal("Malformed SSH_CONNECTION variable: \"%s\"",  
                             getenv("SSH_CONNECTION"));  
                 *cp = '\0';  
         } else  
                 client_addr = xstrdup("UNKNOWN");  
   
         if ((pw = getpwuid(getuid())) == NULL)  
                 fatal("No user found for uid %lu", (u_long)getuid());  
         pw = pwcopy(pw);  
   
         logit("session opened for local user %s from [%s]",  
             pw->pw_name, client_addr);  
   
         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 1276 
Line 1056 
                 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;
                         error("select: %s", strerror(errno));                          exit(2);
                         cleanup_exit(2);  
                 }                  }
   
                 /* copy stdin to iqueue */                  /* copy stdin to iqueue */
Line 1286 
Line 1065 
                         len = read(in, buf, sizeof buf);                          len = read(in, buf, sizeof buf);
                         if (len == 0) {                          if (len == 0) {
                                 debug("read eof");                                  debug("read eof");
                                 cleanup_exit(0);                                  exit(0);
                         } else if (len < 0) {                          } else if (len < 0) {
                                 error("read: %s", strerror(errno));                                  error("read error");
                                 cleanup_exit(1);                                  exit(1);
                         } else {                          } else {
                                 buffer_append(&iqueue, buf, len);                                  buffer_append(&iqueue, buf, len);
                         }                          }
Line 1298 
Line 1077 
                 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: %s", strerror(errno));                                  error("write error");
                                 cleanup_exit(1);                                  exit(1);
                         } else {                          } else {
                                 buffer_consume(&oqueue, len);                                  buffer_consume(&oqueue, len);
                         }                          }

Legend:
Removed from v.1.48.2.2  
changed lines
  Added in v.1.49