Blame src/sftpserver.c

Packit Service 31306d
/*
Packit Service 31306d
 * sftpserver.c - server based function for the sftp protocol
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2005      by Aris Adamantiadis
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
#include <netinet/in.h>
Packit Service 31306d
#include <arpa/inet.h>
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#include "libssh/libssh.h"
Packit Service 31306d
#include "libssh/sftp.h"
Packit Service 31306d
#include "libssh/sftp_priv.h"
Packit Service 31306d
#include "libssh/ssh2.h"
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
Packit Service 31306d
#define SFTP_HANDLES 256
Packit Service 31306d
Packit Service 31306d
sftp_client_message sftp_get_client_message(sftp_session sftp) {
Packit Service 31306d
  ssh_session session = sftp->session;
Packit Service 31306d
  sftp_packet packet;
Packit Service 31306d
  sftp_client_message msg;
Packit Service 31306d
  ssh_buffer payload;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  msg = malloc(sizeof (struct sftp_client_message_struct));
Packit Service 31306d
  if (msg == NULL) {
Packit Service 31306d
    ssh_set_error_oom(session);
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
  ZERO_STRUCTP(msg);
Packit Service 31306d
Packit Service 31306d
  packet = sftp_packet_read(sftp);
Packit Service 31306d
  if (packet == NULL) {
Packit Service 31306d
    ssh_set_error_oom(session);
Packit Service 31306d
    sftp_client_message_free(msg);
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  payload = packet->payload;
Packit Service 31306d
  msg->type = packet->type;
Packit Service 31306d
  msg->sftp = sftp;
Packit Service 31306d
Packit Service 31306d
  /* take a copy of the whole packet */
Packit Service 31306d
  msg->complete_message = ssh_buffer_new();
Packit Service 31306d
  ssh_buffer_add_data(msg->complete_message,
Packit Service 31306d
                      ssh_buffer_get(payload),
Packit Service 31306d
                      ssh_buffer_get_len(payload));
Packit Service 31306d
Packit Service 31306d
  ssh_buffer_get_u32(payload, &msg->id);
Packit Service 31306d
Packit Service 31306d
  switch(msg->type) {
Packit Service 31306d
    case SSH_FXP_CLOSE:
Packit Service 31306d
    case SSH_FXP_READDIR:
Packit Service 31306d
      msg->handle = ssh_buffer_get_ssh_string(payload);
Packit Service 31306d
      if (msg->handle == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_READ:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "Sqd",
Packit Service 31306d
                             &msg->handle,
Packit Service 31306d
                             &msg->offset,
Packit Service 31306d
                             &msg->len);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_WRITE:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "SqS",
Packit Service 31306d
                             &msg->handle,
Packit Service 31306d
                             &msg->offset,
Packit Service 31306d
                             &msg->data);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_REMOVE:
Packit Service 31306d
    case SSH_FXP_RMDIR:
Packit Service 31306d
    case SSH_FXP_OPENDIR:
Packit Service 31306d
    case SSH_FXP_READLINK:
Packit Service 31306d
    case SSH_FXP_REALPATH:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "s",
Packit Service 31306d
                             &msg->filename);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_RENAME:
Packit Service 31306d
    case SSH_FXP_SYMLINK:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "sS",
Packit Service 31306d
                             &msg->filename,
Packit Service 31306d
                             &msg->data);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_MKDIR:
Packit Service 31306d
    case SSH_FXP_SETSTAT:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "s",
Packit Service 31306d
                             &msg->filename);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      msg->attr = sftp_parse_attr(sftp, payload, 0);
Packit Service 31306d
      if (msg->attr == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_FSETSTAT:
Packit Service 31306d
      msg->handle = ssh_buffer_get_ssh_string(payload);
Packit Service 31306d
      if (msg->handle == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      msg->attr = sftp_parse_attr(sftp, payload, 0);
Packit Service 31306d
      if (msg->attr == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_LSTAT:
Packit Service 31306d
    case SSH_FXP_STAT:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "s",
Packit Service 31306d
                             &msg->filename);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      if(sftp->version > 3) {
Packit Service 31306d
        ssh_buffer_unpack(payload, "d", &msg->flags);
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_OPEN:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "sd",
Packit Service 31306d
                             &msg->filename,
Packit Service 31306d
                             &msg->flags);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      msg->attr = sftp_parse_attr(sftp, payload, 0);
Packit Service 31306d
      if (msg->attr == NULL) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_FSTAT:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "S",
Packit Service 31306d
                             &msg->handle);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    case SSH_FXP_EXTENDED:
Packit Service 31306d
      rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                             "s",
Packit Service 31306d
                             &msg->submessage);
Packit Service 31306d
      if (rc != SSH_OK) {
Packit Service 31306d
        ssh_set_error_oom(session);
Packit Service 31306d
        sftp_client_message_free(msg);
Packit Service 31306d
        return NULL;
Packit Service 31306d
      }
Packit Service 31306d
Packit Service 31306d
      if (strcmp(msg->submessage, "hardlink@openssh.com") == 0 ||
Packit Service 31306d
          strcmp(msg->submessage, "posix-rename@openssh.com") == 0) {
Packit Service 31306d
        rc = ssh_buffer_unpack(payload,
Packit Service 31306d
                               "sS",
Packit Service 31306d
                               &msg->filename,
Packit Service 31306d
                               &msg->data);
Packit Service 31306d
        if (rc != SSH_OK) {
Packit Service 31306d
          ssh_set_error_oom(session);
Packit Service 31306d
          sftp_client_message_free(msg);
Packit Service 31306d
          return NULL;
Packit Service 31306d
        }
Packit Service 31306d
      }
Packit Service 31306d
      break;
Packit Service 31306d
    default:
Packit Service 31306d
      ssh_set_error(sftp->session, SSH_FATAL,
Packit Service 31306d
                    "Received unhandled sftp message %d", msg->type);
Packit Service 31306d
      sftp_client_message_free(msg);
Packit Service 31306d
      return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return msg;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* Send an sftp client message. Can be used in cas of proxying */
Packit Service 31306d
int sftp_send_client_message(sftp_session sftp, sftp_client_message msg){
Packit Service 31306d
	return sftp_packet_write(sftp, msg->type, msg->complete_message);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
uint8_t sftp_client_message_get_type(sftp_client_message msg){
Packit Service 31306d
	return msg->type;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *sftp_client_message_get_filename(sftp_client_message msg){
Packit Service 31306d
	return msg->filename;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void sftp_client_message_set_filename(sftp_client_message msg, const char *newname){
Packit Service 31306d
	free(msg->filename);
Packit Service 31306d
	msg->filename = strdup(newname);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *sftp_client_message_get_data(sftp_client_message msg){
Packit Service 31306d
	if (msg->str_data == NULL)
Packit Service 31306d
		msg->str_data = ssh_string_to_char(msg->data);
Packit Service 31306d
	return msg->str_data;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
uint32_t sftp_client_message_get_flags(sftp_client_message msg){
Packit Service 31306d
	return msg->flags;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
const char *sftp_client_message_get_submessage(sftp_client_message msg){
Packit Service 31306d
        return msg->submessage;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void sftp_client_message_free(sftp_client_message msg) {
Packit Service 31306d
  if (msg == NULL) {
Packit Service 31306d
    return;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SAFE_FREE(msg->filename);
Packit Service 31306d
  SAFE_FREE(msg->submessage);
Packit Service 31306d
  SSH_STRING_FREE(msg->data);
Packit Service 31306d
  SSH_STRING_FREE(msg->handle);
Packit Service 31306d
  sftp_attributes_free(msg->attr);
Packit Service 31306d
  SSH_BUFFER_FREE(msg->complete_message);
Packit Service 31306d
  SAFE_FREE(msg->str_data);
Packit Service 31306d
  ZERO_STRUCTP(msg);
Packit Service 31306d
  SAFE_FREE(msg);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_name(sftp_client_message msg, const char *name,
Packit Service 31306d
    sftp_attributes attr) {
Packit Service 31306d
  ssh_buffer out;
Packit Service 31306d
  ssh_string file;
Packit Service 31306d
Packit Service 31306d
  out = ssh_buffer_new();
Packit Service 31306d
  if (out == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  file = ssh_string_from_char(name);
Packit Service 31306d
  if (file == NULL) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
Packit Service 31306d
      ssh_buffer_add_u32(out, htonl(1)) < 0 ||
Packit Service 31306d
      ssh_buffer_add_ssh_string(out, file) < 0 ||
Packit Service 31306d
      ssh_buffer_add_ssh_string(out, file) < 0 || /* The protocol is broken here between 3 & 4 */
Packit Service 31306d
      buffer_add_attributes(out, attr) < 0 ||
Packit Service 31306d
      sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    SSH_STRING_FREE(file);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
  SSH_BUFFER_FREE(out);
Packit Service 31306d
  SSH_STRING_FREE(file);
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_handle(sftp_client_message msg, ssh_string handle){
Packit Service 31306d
  ssh_buffer out;
Packit Service 31306d
Packit Service 31306d
  out = ssh_buffer_new();
Packit Service 31306d
  if (out == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
Packit Service 31306d
      ssh_buffer_add_ssh_string(out, handle) < 0 ||
Packit Service 31306d
      sftp_packet_write(msg->sftp, SSH_FXP_HANDLE, out) < 0) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
  SSH_BUFFER_FREE(out);
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr) {
Packit Service 31306d
  ssh_buffer out;
Packit Service 31306d
Packit Service 31306d
  out = ssh_buffer_new();
Packit Service 31306d
  if (out == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
Packit Service 31306d
      buffer_add_attributes(out, attr) < 0 ||
Packit Service 31306d
      sftp_packet_write(msg->sftp, SSH_FXP_ATTRS, out) < 0) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
  SSH_BUFFER_FREE(out);
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_names_add(sftp_client_message msg, const char *file,
Packit Service 31306d
    const char *longname, sftp_attributes attr) {
Packit Service 31306d
  ssh_string name;
Packit Service 31306d
Packit Service 31306d
  name = ssh_string_from_char(file);
Packit Service 31306d
  if (name == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (msg->attrbuf == NULL) {
Packit Service 31306d
    msg->attrbuf = ssh_buffer_new();
Packit Service 31306d
    if (msg->attrbuf == NULL) {
Packit Service 31306d
      SSH_STRING_FREE(name);
Packit Service 31306d
      return -1;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_ssh_string(msg->attrbuf, name) < 0) {
Packit Service 31306d
    SSH_STRING_FREE(name);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SSH_STRING_FREE(name);
Packit Service 31306d
  name = ssh_string_from_char(longname);
Packit Service 31306d
  if (name == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
  if (ssh_buffer_add_ssh_string(msg->attrbuf,name) < 0 ||
Packit Service 31306d
      buffer_add_attributes(msg->attrbuf,attr) < 0) {
Packit Service 31306d
    SSH_STRING_FREE(name);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
  SSH_STRING_FREE(name);
Packit Service 31306d
  msg->attr_num++;
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_names(sftp_client_message msg) {
Packit Service 31306d
  ssh_buffer out;
Packit Service 31306d
Packit Service 31306d
  out = ssh_buffer_new();
Packit Service 31306d
  if (out == NULL) {
Packit Service 31306d
    SSH_BUFFER_FREE(msg->attrbuf);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
Packit Service 31306d
      ssh_buffer_add_u32(out, htonl(msg->attr_num)) < 0 ||
Packit Service 31306d
      ssh_buffer_add_data(out, ssh_buffer_get(msg->attrbuf),
Packit Service 31306d
        ssh_buffer_get_len(msg->attrbuf)) < 0 ||
Packit Service 31306d
      sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    SSH_BUFFER_FREE(msg->attrbuf);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SSH_BUFFER_FREE(out);
Packit Service 31306d
  SSH_BUFFER_FREE(msg->attrbuf);
Packit Service 31306d
Packit Service 31306d
  msg->attr_num = 0;
Packit Service 31306d
  msg->attrbuf = NULL;
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_status(sftp_client_message msg, uint32_t status,
Packit Service 31306d
    const char *message) {
Packit Service 31306d
  ssh_buffer out;
Packit Service 31306d
  ssh_string s;
Packit Service 31306d
Packit Service 31306d
  out = ssh_buffer_new();
Packit Service 31306d
  if (out == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  s = ssh_string_from_char(message ? message : "");
Packit Service 31306d
  if (s == NULL) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
Packit Service 31306d
      ssh_buffer_add_u32(out, htonl(status)) < 0 ||
Packit Service 31306d
      ssh_buffer_add_ssh_string(out, s) < 0 ||
Packit Service 31306d
      ssh_buffer_add_u32(out, 0) < 0 || /* language string */
Packit Service 31306d
      sftp_packet_write(msg->sftp, SSH_FXP_STATUS, out) < 0) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    SSH_STRING_FREE(s);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  SSH_BUFFER_FREE(out);
Packit Service 31306d
  SSH_STRING_FREE(s);
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int sftp_reply_data(sftp_client_message msg, const void *data, int len) {
Packit Service 31306d
  ssh_buffer out;
Packit Service 31306d
Packit Service 31306d
  out = ssh_buffer_new();
Packit Service 31306d
  if (out == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_add_u32(out, msg->id) < 0 ||
Packit Service 31306d
      ssh_buffer_add_u32(out, ntohl(len)) < 0 ||
Packit Service 31306d
      ssh_buffer_add_data(out, data, len) < 0 ||
Packit Service 31306d
      sftp_packet_write(msg->sftp, SSH_FXP_DATA, out) < 0) {
Packit Service 31306d
    SSH_BUFFER_FREE(out);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
  SSH_BUFFER_FREE(out);
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * This function will return you a new handle to give the client.
Packit Service 31306d
 * the function accepts an info that can be retrieved later with
Packit Service 31306d
 * the handle. Care is given that a corrupted handle won't give a
Packit Service 31306d
 * valid info (or worse).
Packit Service 31306d
 */
Packit Service 31306d
ssh_string sftp_handle_alloc(sftp_session sftp, void *info) {
Packit Service 31306d
  ssh_string ret;
Packit Service 31306d
  uint32_t val;
Packit Service 31306d
  uint32_t i;
Packit Service 31306d
Packit Service 31306d
  if (sftp->handles == NULL) {
Packit Service 31306d
    sftp->handles = calloc(SFTP_HANDLES, sizeof(void *));
Packit Service 31306d
    if (sftp->handles == NULL) {
Packit Service 31306d
      return NULL;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  for (i = 0; i < SFTP_HANDLES; i++) {
Packit Service 31306d
    if (sftp->handles[i] == NULL) {
Packit Service 31306d
      break;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (i == SFTP_HANDLES) {
Packit Service 31306d
    return NULL; /* no handle available */
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  val = i;
Packit Service 31306d
  ret = ssh_string_new(4);
Packit Service 31306d
  if (ret == NULL) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  memcpy(ssh_string_data(ret), &val, sizeof(uint32_t));
Packit Service 31306d
  sftp->handles[i] = info;
Packit Service 31306d
Packit Service 31306d
  return ret;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void *sftp_handle(sftp_session sftp, ssh_string handle){
Packit Service 31306d
  uint32_t val;
Packit Service 31306d
Packit Service 31306d
  if (sftp->handles == NULL) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_string_len(handle) != sizeof(uint32_t)) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  memcpy(&val, ssh_string_data(handle), sizeof(uint32_t));
Packit Service 31306d
Packit Service 31306d
  if (val > SFTP_HANDLES) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return sftp->handles[val];
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void sftp_handle_remove(sftp_session sftp, void *handle) {
Packit Service 31306d
  int i;
Packit Service 31306d
Packit Service 31306d
  for (i = 0; i < SFTP_HANDLES; i++) {
Packit Service 31306d
    if (sftp->handles[i] == handle) {
Packit Service 31306d
      sftp->handles[i] = NULL;
Packit Service 31306d
      break;
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
}