Skip to content
Snippets Groups Projects
Select Git revision
  • abc7b852f2873d5cb6edc10628adc95af0dac4cf
  • master default protected
  • 9.0
  • marcus/wix3
  • 8.0
  • nt-tools
  • 7.8
  • 7.6
  • 7.4
  • 7.2
  • 7.0
  • 0.6
  • rosuav/latex-markdown-renderer
  • rxnpatch/rxnpatch
  • marcus/gobject-introspection
  • rxnpatch/8.0
  • rosuav/pre-listening-ports
  • rosuav/async-annotations
  • rosuav/pgsql-ssl
  • rxnpatch/rxnpatch-broken/2023-10-06T094250
  • grubba/fdlib
  • v8.0.2020
  • v8.0.2018
  • v8.0.2016
  • v8.0.2014
  • v8.0.2012
  • v8.0.2008
  • v8.0.2006
  • v8.0.2004
  • v8.0.2002
  • v8.0.2000
  • v8.0.1998
  • v8.0.1996
  • v8.0.1994
  • v8.0.1992
  • v8.0.1990
  • v8.0.1988
  • v8.0.1986
  • rxnpatch/clusters/8.0/2025-04-29T124414
  • rxnpatch/2025-04-29T124414
  • v8.0.1984
41 results

git_export_autodoc.pike

Blame
  • buffer.c 9.80 KiB
    /* buffer.c
     *
     * $Id$
     *
     * Buffering for sftp.
     */
    
    #include "buffer.h"
    
    #include "sftp.h"
    
    #include <assert.h>
    #include <stdarg.h>
    
    #define FATAL(x) do { fputs("sftp-server: " x "\n", stderr); exit(EXIT_FAILURE); } while (0)
    
    #include <stdlib.h>
    
    /* Reads a 32-bit integer, in network byte order */
    #define READ_UINT32(p)				\
    (  (((UINT32) (p)[0]) << 24)			\
     | (((UINT32) (p)[1]) << 16)			\
     | (((UINT32) (p)[2]) << 8)			\
     |  ((UINT32) (p)[3]))
    
    #define WRITE_UINT32(p, i)			\
    do {						\
      (p)[0] = ((i) >> 24) & 0xff;			\
      (p)[1] = ((i) >> 16) & 0xff;			\
      (p)[2] = ((i) >> 8) & 0xff;			\
      (p)[3] = (i) & 0xff;				\
    } while(0)
    
    #define SFTP_MAX_STRINGS 2
    
    struct sftp_input
    {
      FILE *f;
      UINT32 left;
    
      /* Strings that we own */
      UINT8 *strings[SFTP_MAX_STRINGS];
      unsigned used_strings;
    };
    
    struct sftp_output
    {
      FILE *f;
    
      /* The message type is the first byte of a message, after the
       * length. */
      UINT8 msg;
    
      /* The next word is either the id, or the version. */
      UINT32 first;
    
      /* The rest of the packet is variable length. */
      UINT8 *data;
      UINT32 size;
      UINT32 i;
    };
    
    /* Input */
    
    static int
    sftp_check_input(struct sftp_input *input, UINT32 length)
    {
      if (input->left < length)
        return 0;
    
      input->left -= length;
      return 1;
    }
    
    int
    sftp_get_data(struct sftp_input *i, UINT32 length, UINT8 *data)
    {
      return sftp_check_input(i, length)
        && (fread(data, 1, length, i->f) == length);
    }
    
    #define GET_DATA(i, buf) \
    (sftp_get_data((i), sizeof((buf)), (buf)))
    
    int
    sftp_get_uint8(struct sftp_input *i, UINT8 *value)
    {
      return sftp_get_data(i, 1, value);    
    }
    
    int
    sftp_get_uint32(struct sftp_input *i, UINT32 *value)
    {
      UINT8 buf[4];
      if (!GET_DATA(i, buf))
        return 0;
    
      *value = READ_UINT32(buf);
      return 1;
    }
    
    UINT8 *
    sftp_get_string(struct sftp_input *i, UINT32 *length)
    {
      UINT8 *data;
    
      assert(i->used_strings < SFTP_MAX_STRINGS);
      
      if (!(sftp_get_uint32(i, length) && sftp_check_input(i, *length)))
        return NULL;
    
      data = malloc(*length + 1);
      if (!data)
        return NULL;
    
      if (!sftp_get_data(i, *length, data))
        {
          free(data);
          return NULL;
        }
    
      /* NUL-terminate, for convenience */
      data[*length] = '\0';
    
      /* Remember the string. */
      i->strings[i->used_strings++] = data;
      return data;
    }
    
    int
    sftp_get_eod(struct sftp_input *i)
    {
      return !i->left;
    }
    
    /* Input */
    struct sftp_input *
    sftp_make_input(FILE *f)
    {
      struct sftp_input *i = malloc(sizeof(struct sftp_input));
      if (i)
        {
          i->f = f;
          i->left = 0;
          i->used_strings = 0;
        }
      return i;
    }
    
    static void
    sftp_input_clear_strings(struct sftp_input *i)
    {
      unsigned k;
    
      for (k = 0; k < i->used_strings; k++)
        free(i->strings[k]);
    
      i->used_strings = 0;
    }
    
    /* Returns 1 of all was well, 0 on error, and -1 on EOF */
    int
    sftp_read_packet(struct sftp_input *i)
    {
      UINT8 buf[4];
      int done;
    
      assert(i->left == 0);
    
      /* First, deallocate the strings. */
      sftp_input_clear_strings(i);
      
      done = fread(buf, 1, sizeof(buf), i->f);
    
      switch (done)
        {
        case 0:
          return feof(i->f) ? -1 : 0;
        case 4:
          i->left = READ_UINT32(buf);
          return 1;
        default:
          return 0;
        }
    }
    
    /* Output */
    
    static void
    sftp_check_output(struct sftp_output *o, UINT32 length)
    {
      UINT32 needed = o->i + length;
      if (!o->data || (needed > o->size))
      {
        UINT8 *p;
        UINT32 size = 2 * needed + 40;
        p = realloc(o->data, size);
        if (!p)
          FATAL("Virtual memory exhausted");
    
        o->data = p;
        o->size = size;
      }
    }
    
    void
    sftp_put_data(struct sftp_output *o, UINT32 length, const UINT8 *data)
    {
      sftp_check_output(o, length);
    
      memcpy(o->data + o->i, data, length);
      o->i += length;
    }
    
    #define PUT_DATA(o, buf) \
    (sftp_put_data((o), sizeof((buf)), (buf)))
    
    void
    sftp_put_uint8(struct sftp_output *o, UINT8 value)
    {
      sftp_check_output(o, 1);
    
      o->data[o->i++] = value;
    }
    
    void
    sftp_put_uint32(struct sftp_output *o, UINT32 value)
    {
      UINT8 buf[4];
    
      WRITE_UINT32(buf, value);
      PUT_DATA(o, buf);
    }
    
    void
    sftp_put_string(struct sftp_output *o, UINT32 length, const UINT8 *data)
    {
      sftp_put_uint32(o, length);
      sftp_put_data(o, length, data);
    }
    
    UINT32
    sftp_put_reserve_length(struct sftp_output *o)
    {
      UINT32 index;
      sftp_check_output(o, 4);
    
      index = o->i;
      o->i += 4;
    
      return index;
    }
    
    void
    sftp_put_length(struct sftp_output *o,
    		UINT32 index,
    		UINT32 length)
    {
      assert( (index + 4) < o->i);
      WRITE_UINT32(o->data + index, length);
    }
    
    void
    sftp_put_final_length(struct sftp_output *o,
    		      UINT32 index)
    {
      sftp_put_length(o, index, o->i - index);
    }
    
    void
    sftp_put_reset(struct sftp_output *o,
    	       UINT32 index)
    {
      assert(index >= o->i);
      assert(index <= o->size);
      o->i = index;
    }
    
    UINT32
    sftp_put_printf(struct sftp_output *o, const char *format, ...)
    {
      /* Initial buffer space */
      int needed;
      int length;
      
      for (needed = 100;; needed *= 2)
        {
          va_list args;
          
          va_start(args, format);
    
          sftp_check_output(o, needed);
          length = vsnprintf(o->data + o->i, needed, format, args);
          
          va_end(args);
    
          if ( (length >= 0) && (length < needed))
    	break;
        }
      o->i += length;
      
      return length;
    }
    
    /* If SIZE > 0 it is the desired field length, and
     * smaller output is padded with blanks. */
    UINT32
    sftp_put_strftime(struct sftp_output *o, UINT32 size, const char *format,
    		  const struct tm *tm)
    {
      /* Initial buffer space */
      size_t needed;
      size_t length;
      
      for (needed = size ? size : 100;; needed *= 2)
        {
          sftp_check_output(o, needed);
          length = strftime(o->data + o->i, needed, format, tm);
    
          if ( (length > 0) && (length < needed))
    	break;
        }
    
      while (length < size)
        o->data[o->i + length++] = ' ';
    
      o->i += length;
      
      return length;
    }
    
    
    /* 64-bit stuff */
    #if SIZEOF_OFF_T > 4
    #define READ_UINT64(p)				\
    (  (((UINT64) (p)[0]) << 56)			\
     | (((UINT64) (p)[1]) << 48)			\
     | (((UINT64) (p)[2]) << 40)			\
     | (((UINT64) (p)[3]) << 32)			\
     | (((UINT64) (p)[4]) << 24)			\
     | (((UINT64) (p)[5]) << 16)			\
     | (((UINT64) (p)[6]) << 8)			\
     |  ((UINT64) (p)[7]))
    
    
    int
    sftp_get_uint64(struct sftp_input *i, off_t *value)
    {
      UINT8 buf[8];
      if (!GET_DATA(i, buf))
        return 0;
    
      *value = READ_UINT64(buf);
      return 1;
    }
    
    #define WRITE_UINT64(p, i)			\
    do {						\
      (p)[0] = ((i) >> 56) & 0xff;			\
      (p)[1] = ((i) >> 48) & 0xff;			\
      (p)[2] = ((i) >> 40) & 0xff;			\
      (p)[3] = ((i) >> 32) & 0xff;			\
      (p)[4] = ((i) >> 24) & 0xff;			\
      (p)[5] = ((i) >> 16) & 0xff;			\
      (p)[6] = ((i) >> 8) & 0xff;			\
      (p)[7] = (i) & 0xff;				\
    } while(0)
    
    void
    sftp_put_uint64(struct sftp_output *o, off_t value)
    {
      UINT8 buf[8];
    
      WRITE_UINT64(buf, value);
      PUT_DATA(o, buf);
    }
    
    #else /* SIZEOF_OFF_T <= 4 */
    
    /* Fail for too large numbers. */
    int
    sftp_get_uint64(struct sftp_input *i, off_t *value)
    {
      UINT32 high;
      UINT32 low;
    
      if (sftp_get_uint32(i, &high)
          && !high
          && sftp_get_uint32(i, &low))
        {
          *value = low;
          return 1;
        }
      else
        return 0;
    }
    
    void
    sftp_put_uint64(struct sftp_output *o, off_t value)
    {
      sftp_put_uint32(o, 0);
      sftp_put_uint32(o, value);
    }
    
    #endif /* SIZEOF_OFF_T <= 4 */
    
    /* The first part of the buffer is always
     *
     * uint32 length
     * uint8  msg
     * uint32 id/version
     */
    
    struct sftp_output *
    sftp_make_output(FILE *f)
    {
      struct sftp_output *o = malloc(sizeof(struct sftp_output));
      if (o)
        {
          o->f = f;
          o->data = NULL;
          o->size = 0;
          o->i = 0;
        }
      return o;
    }
    
    void
    sftp_set_msg(struct sftp_output *o, UINT8 msg)
    {
      o->msg = msg;
    }
    
    void
    sftp_set_id(struct sftp_output *o, UINT32 id)
    {
      o->first = id;
    }
    
    int
    sftp_write_packet(struct sftp_output *o)
    {
      UINT32 length = o->i + 5;
      UINT8 buf[9];
    
      WRITE_UINT32(buf, length);
      buf[4] = o->msg;
      WRITE_UINT32(buf + 5, o->first);
    
      if (fwrite(buf, 1, 9, o->f) != 9)
        return 0;
      if (fwrite(o->data, 1, o->i, o->f) != o->i)
        return 0;
    
      o->i = 0;
    
      /* FIXME: Flushing after each packet is sub-optimal. */
      if (fflush(o->f))
        return 0;
    
      return 1;
    }
    
    /* General functions */
    
    void
    sftp_clear_attrib(struct sftp_attrib *a)
    {
      a->flags = 0;
      a->size = 0;
      a->uid = 0;
      a->gid = 0;
      a->permissions = 0;
      a->atime = 0;
      a->mtime = 0;
    };
    
    int
    sftp_skip_extension(struct sftp_input *i)
    {
      UINT32 length;
      UINT8 *data;
      unsigned j;
      
      /* Skip name and value*/
      for (j = 0; j<2; j++)
        {
          if (!(data = sftp_get_string(i, &length)))
    	return 0;
        }
      sftp_input_clear_strings(i);
      
      return 1;
    }
    
    int
    sftp_get_attrib(struct sftp_input *i, struct sftp_attrib *a)
    {
      sftp_clear_attrib(a);
      
      if (!sftp_get_uint32(i, &a->flags))
        return 0;
    
      if (a->flags & SSH_FILEXFER_ATTR_SIZE)
        {
          if (!sftp_get_uint64(i, &a->size))
    	return 0;
        }
    
      if (a->flags & SSH_FILEXFER_ATTR_UIDGID)
        {
          if (!sftp_get_uint32(i, &a->uid))
    	return 0;
    
          if (!sftp_get_uint32(i, &a->gid))
    	return 0;
        }
    
      if (a->flags & SSH_FILEXFER_ATTR_PERMISSIONS)
        {
          if (!sftp_get_uint32(i, &a->permissions))
    	return 0;
        }
    
      if (a->flags & SSH_FILEXFER_ATTR_ACMODTIME)
        {
          if (!sftp_get_uint32(i, &a->atime))
    	return 0;
    
          if (!sftp_get_uint32(i, &a->mtime))
    	return 0;
        }
    
      if (a->flags & SSH_FILEXFER_ATTR_EXTENDED)
        {
          UINT32 count;
          UINT32 n;
    
          if (!sftp_get_uint32(i, &count))
    	return 0;
    
          /* Just skip the extensions */
          for (n = 0; n < count; n++)
    	if (!sftp_skip_extension(i))
    	  return 0;
        }
      return 1;
    }
    
    void
    sftp_put_attrib(struct sftp_output *o, const struct sftp_attrib *a)
    {
      assert(!a->flags & SSH_FILEXFER_ATTR_EXTENDED);
      
      sftp_put_uint32(o, a->flags);
    
      if (a->flags & SSH_FILEXFER_ATTR_SIZE)
        sftp_put_uint64(o, a->size);
    
      if (a->flags & SSH_FILEXFER_ATTR_UIDGID)
        {
          sftp_put_uint32(o, a->uid);
          sftp_put_uint32(o, a->gid);
        }
    
      if (a->flags & SSH_FILEXFER_ATTR_PERMISSIONS)
        sftp_put_uint32(o, a->permissions);
    
      if (a->flags & SSH_FILEXFER_ATTR_ACMODTIME)
        {
          sftp_put_uint32(o, a->atime);
          sftp_put_uint32(o, a->mtime);
        }
    }