aboutsummaryrefslogtreecommitdiff
path: root/libssh/sftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/sftp.c')
-rw-r--r--libssh/sftp.c3207
1 files changed, 0 insertions, 3207 deletions
diff --git a/libssh/sftp.c b/libssh/sftp.c
deleted file mode 100644
index e5c91af..0000000
--- a/libssh/sftp.c
+++ /dev/null
@@ -1,3207 +0,0 @@
-/*
- * sftp.c - Secure FTP functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005-2008 by Aris Adamantiadis
- * Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-/* This file contains code written by Nick Zitzmann */
-
-#include <errno.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#else
-#define S_IFSOCK 0140000
-#define S_IFLNK 0120000
-
-#ifdef _MSC_VER
-#define S_IFBLK 0060000
-#define S_IFIFO 0010000
-#endif
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/sftp.h"
-#include "libssh/buffer.h"
-#include "libssh/channels.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-
-#ifdef WITH_SFTP
-
-#define sftp_enter_function() _enter_function(sftp->channel->session)
-#define sftp_leave_function() _leave_function(sftp->channel->session)
-
-struct sftp_ext_struct {
- unsigned int count;
- char **name;
- char **data;
-};
-
-/* functions */
-static int sftp_enqueue(sftp_session session, sftp_message msg);
-static void sftp_message_free(sftp_message msg);
-static void sftp_set_error(sftp_session sftp, int errnum);
-static void status_msg_free(sftp_status_message status);
-
-static sftp_ext sftp_ext_new(void) {
- sftp_ext ext;
-
- ext = malloc(sizeof(struct sftp_ext_struct));
- if (ext == NULL) {
- return NULL;
- }
- ZERO_STRUCTP(ext);
-
- return ext;
-}
-
-static void sftp_ext_free(sftp_ext ext) {
- unsigned int i;
-
- if (ext == NULL) {
- return;
- }
-
- if (ext->count) {
- for (i = 0; i < ext->count; i++) {
- SAFE_FREE(ext->name[i]);
- SAFE_FREE(ext->data[i]);
- }
- SAFE_FREE(ext->name);
- SAFE_FREE(ext->data);
- }
-
- SAFE_FREE(ext);
-}
-
-sftp_session sftp_new(ssh_session session){
- sftp_session sftp;
-
- if (session == NULL) {
- return NULL;
- }
- enter_function();
-
- sftp = malloc(sizeof(struct sftp_session_struct));
- if (sftp == NULL) {
- ssh_set_error_oom(session);
- leave_function();
- return NULL;
- }
- ZERO_STRUCTP(sftp);
-
- sftp->ext = sftp_ext_new();
- if (sftp->ext == NULL) {
- ssh_set_error_oom(session);
- SAFE_FREE(sftp);
- leave_function();
- return NULL;
- }
-
- sftp->session = session;
- sftp->channel = ssh_channel_new(session);
- if (sftp->channel == NULL) {
- SAFE_FREE(sftp);
- leave_function();
- return NULL;
- }
-
- if (ssh_channel_open_session(sftp->channel)) {
- ssh_channel_free(sftp->channel);
- SAFE_FREE(sftp);
- leave_function();
- return NULL;
- }
-
- if (ssh_channel_request_sftp(sftp->channel)) {
- sftp_free(sftp);
- leave_function();
- return NULL;
- }
-
- leave_function();
- return sftp;
-}
-
-#ifdef WITH_SERVER
-sftp_session sftp_server_new(ssh_session session, ssh_channel chan){
- sftp_session sftp = NULL;
-
- sftp = malloc(sizeof(struct sftp_session_struct));
- if (sftp == NULL) {
- ssh_set_error_oom(session);
- return NULL;
- }
- ZERO_STRUCTP(sftp);
-
- sftp->session = session;
- sftp->channel = chan;
-
- return sftp;
-}
-
-int sftp_server_init(sftp_session sftp){
- ssh_session session = sftp->session;
- sftp_packet packet = NULL;
- ssh_buffer reply = NULL;
- uint32_t version;
-
- sftp_enter_function();
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_leave_function();
- return -1;
- }
-
- if (packet->type != SSH_FXP_INIT) {
- ssh_set_error(session, SSH_FATAL,
- "Packet read of type %d instead of SSH_FXP_INIT",
- packet->type);
-
- sftp_packet_free(packet);
- sftp_leave_function();
- return -1;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Received SSH_FXP_INIT");
-
- buffer_get_u32(packet->payload, &version);
- version = ntohl(version);
- ssh_log(session, SSH_LOG_PACKET, "Client version: %d", version);
- sftp->client_version = version;
-
- sftp_packet_free(packet);
-
- reply = ssh_buffer_new();
- if (reply == NULL) {
- ssh_set_error_oom(session);
- sftp_leave_function();
- return -1;
- }
-
- if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) {
- ssh_set_error_oom(session);
- ssh_buffer_free(reply);
- sftp_leave_function();
- return -1;
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
- ssh_buffer_free(reply);
- sftp_leave_function();
- return -1;
- }
- ssh_buffer_free(reply);
-
- ssh_log(session, SSH_LOG_RARE, "Server version sent");
-
- if (version > LIBSFTP_VERSION) {
- sftp->version = LIBSFTP_VERSION;
- } else {
- sftp->version=version;
- }
-
- sftp_leave_function();
- return 0;
-}
-#endif /* WITH_SERVER */
-
-void sftp_free(sftp_session sftp){
- sftp_request_queue ptr;
-
- if (sftp == NULL) {
- return;
- }
-
- ssh_channel_send_eof(sftp->channel);
- ptr = sftp->queue;
- while(ptr) {
- sftp_request_queue old;
- sftp_message_free(ptr->message);
- old = ptr->next;
- SAFE_FREE(ptr);
- ptr = old;
- }
-
- ssh_channel_free(sftp->channel);
- sftp_ext_free(sftp->ext);
- ZERO_STRUCTP(sftp);
-
- SAFE_FREE(sftp);
-}
-
-int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
- int size;
-
- if (buffer_prepend_data(payload, &type, sizeof(uint8_t)) < 0) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- size = htonl(ssh_buffer_get_len(payload));
- if (buffer_prepend_data(payload, &size, sizeof(uint32_t)) < 0) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- size = ssh_channel_write(sftp->channel, ssh_buffer_get_begin(payload),
- ssh_buffer_get_len(payload));
- if (size < 0) {
- return -1;
- } else if((uint32_t) size != ssh_buffer_get_len(payload)) {
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Had to write %d bytes, wrote only %d",
- ssh_buffer_get_len(payload),
- size);
- }
-
- return size;
-}
-
-sftp_packet sftp_packet_read(sftp_session sftp) {
- sftp_packet packet = NULL;
- uint32_t size;
-
- sftp_enter_function();
-
- packet = malloc(sizeof(struct sftp_packet_struct));
- if (packet == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- packet->sftp = sftp;
- packet->payload = ssh_buffer_new();
- if (packet->payload == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(packet);
- return NULL;
- }
-
- if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
-
- if (buffer_get_u32(packet->payload, &size) != sizeof(uint32_t)) {
- ssh_set_error(sftp->session, SSH_FATAL, "Short sftp packet!");
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
-
- size = ntohl(size);
- if (channel_read_buffer(sftp->channel, packet->payload, 1, 0) <= 0) {
- /* TODO: check if there are cases where an error needs to be set here */
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
-
- buffer_get_u8(packet->payload, &packet->type);
- if (size > 1) {
- if (channel_read_buffer(sftp->channel, packet->payload, size - 1, 0) <= 0) {
- /* TODO: check if there are cases where an error needs to be set here */
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- sftp_leave_function();
- return NULL;
- }
- }
-
- sftp_leave_function();
- return packet;
-}
-
-static void sftp_set_error(sftp_session sftp, int errnum) {
- if (sftp != NULL) {
- sftp->errnum = errnum;
- }
-}
-
-/* Get the last sftp error */
-int sftp_get_error(sftp_session sftp) {
- if (sftp == NULL) {
- return -1;
- }
-
- return sftp->errnum;
-}
-
-static sftp_message sftp_message_new(sftp_session sftp){
- sftp_message msg = NULL;
-
- sftp_enter_function();
-
- msg = malloc(sizeof(struct sftp_message_struct));
- if (msg == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(msg);
-
- msg->payload = ssh_buffer_new();
- if (msg->payload == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(msg);
- return NULL;
- }
- msg->sftp = sftp;
-
- sftp_leave_function();
- return msg;
-}
-
-static void sftp_message_free(sftp_message msg) {
- sftp_session sftp;
-
- if (msg == NULL) {
- return;
- }
-
- sftp = msg->sftp;
- sftp_enter_function();
-
- ssh_buffer_free(msg->payload);
- SAFE_FREE(msg);
-
- sftp_leave_function();
-}
-
-static sftp_message sftp_get_message(sftp_packet packet) {
- sftp_session sftp = packet->sftp;
- sftp_message msg = NULL;
-
- sftp_enter_function();
-
- msg = sftp_message_new(sftp);
- if (msg == NULL) {
- sftp_leave_function();
- return NULL;
- }
-
- msg->sftp = packet->sftp;
- msg->packet_type = packet->type;
-
- if ((packet->type != SSH_FXP_STATUS) && (packet->type!=SSH_FXP_HANDLE) &&
- (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS) &&
- (packet->type != SSH_FXP_NAME) && (packet->type != SSH_FXP_EXTENDED_REPLY)) {
- ssh_set_error(packet->sftp->session, SSH_FATAL,
- "Unknown packet type %d", packet->type);
- sftp_message_free(msg);
- sftp_leave_function();
- return NULL;
- }
-
- if (buffer_get_u32(packet->payload, &msg->id) != sizeof(uint32_t)) {
- ssh_set_error(packet->sftp->session, SSH_FATAL,
- "Invalid packet %d: no ID", packet->type);
- sftp_message_free(msg);
- sftp_leave_function();
- return NULL;
- }
-
- ssh_log(packet->sftp->session, SSH_LOG_PACKET,
- "Packet with id %d type %d",
- msg->id,
- msg->packet_type);
-
- if (buffer_add_data(msg->payload, buffer_get_rest(packet->payload),
- buffer_get_rest_len(packet->payload)) < 0) {
- ssh_set_error_oom(sftp->session);
- sftp_message_free(msg);
- sftp_leave_function();
- return NULL;
- }
-
- sftp_leave_function();
- return msg;
-}
-
-static int sftp_read_and_dispatch(sftp_session sftp) {
- sftp_packet packet = NULL;
- sftp_message msg = NULL;
-
- sftp_enter_function();
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_leave_function();
- return -1; /* something nasty happened reading the packet */
- }
-
- msg = sftp_get_message(packet);
- sftp_packet_free(packet);
- if (msg == NULL) {
- sftp_leave_function();
- return -1;
- }
-
- if (sftp_enqueue(sftp, msg) < 0) {
- sftp_message_free(msg);
- sftp_leave_function();
- return -1;
- }
-
- sftp_leave_function();
- return 0;
-}
-
-void sftp_packet_free(sftp_packet packet) {
- if (packet == NULL) {
- return;
- }
-
- ssh_buffer_free(packet->payload);
- free(packet);
-}
-
-/* Initialize the sftp session with the server. */
-int sftp_init(sftp_session sftp) {
- sftp_packet packet = NULL;
- ssh_buffer buffer = NULL;
- ssh_string ext_name_s = NULL;
- ssh_string ext_data_s = NULL;
- char *ext_name = NULL;
- char *ext_data = NULL;
- uint32_t version = htonl(LIBSFTP_VERSION);
-
- sftp_enter_function();
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- sftp_leave_function();
- return -1;
- }
-
- if (buffer_add_u32(buffer, version) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- sftp_leave_function();
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
- ssh_buffer_free(buffer);
- sftp_leave_function();
- return -1;
- }
- ssh_buffer_free(buffer);
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- sftp_leave_function();
- return -1;
- }
-
- if (packet->type != SSH_FXP_VERSION) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received a %d messages instead of SSH_FXP_VERSION", packet->type);
- sftp_packet_free(packet);
- sftp_leave_function();
- return -1;
- }
-
- /* TODO: are we sure there are 4 bytes ready? */
- buffer_get_u32(packet->payload, &version);
- version = ntohl(version);
- ssh_log(sftp->session, SSH_LOG_RARE,
- "SFTP server version %d",
- version);
-
- ext_name_s = buffer_get_ssh_string(packet->payload);
- while (ext_name_s != NULL) {
- int count = sftp->ext->count;
- char **tmp;
-
- ext_data_s = buffer_get_ssh_string(packet->payload);
- if (ext_data_s == NULL) {
- ssh_string_free(ext_name_s);
- break;
- }
-
- ext_name = ssh_string_to_char(ext_name_s);
- ext_data = ssh_string_to_char(ext_data_s);
- if (ext_name == NULL || ext_data == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
- return -1;
- }
- ssh_log(sftp->session, SSH_LOG_RARE,
- "SFTP server extension: %s, version: %s",
- ext_name, ext_data);
-
- count++;
- tmp = realloc(sftp->ext->name, count * sizeof(char *));
- if (tmp == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
- return -1;
- }
- tmp[count - 1] = ext_name;
- sftp->ext->name = tmp;
-
- tmp = realloc(sftp->ext->data, count * sizeof(char *));
- if (tmp == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
- return -1;
- }
- tmp[count - 1] = ext_data;
- sftp->ext->data = tmp;
-
- sftp->ext->count = count;
-
- ssh_string_free(ext_name_s);
- ssh_string_free(ext_data_s);
-
- ext_name_s = buffer_get_ssh_string(packet->payload);
- }
-
- sftp_packet_free(packet);
-
- sftp->version = sftp->server_version = version;
-
- sftp_leave_function();
-
- return 0;
-}
-
-unsigned int sftp_extensions_get_count(sftp_session sftp) {
- if (sftp == NULL || sftp->ext == NULL) {
- return 0;
- }
-
- return sftp->ext->count;
-}
-
-const char *sftp_extensions_get_name(sftp_session sftp, unsigned int idx) {
- if (sftp == NULL)
- return NULL;
- if (sftp->ext == NULL || sftp->ext->name == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- if (idx > sftp->ext->count) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- return sftp->ext->name[idx];
-}
-
-const char *sftp_extensions_get_data(sftp_session sftp, unsigned int idx) {
- if (sftp == NULL)
- return NULL;
- if (sftp->ext == NULL || sftp->ext->name == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- if (idx > sftp->ext->count) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- return sftp->ext->data[idx];
-}
-
-int sftp_extension_supported(sftp_session sftp, const char *name,
- const char *data) {
- int i, n;
-
- n = sftp_extensions_get_count(sftp);
- for (i = 0; i < n; i++) {
- if (strcmp(sftp_extensions_get_name(sftp, i), name) == 0 &&
- strcmp(sftp_extensions_get_data(sftp, i), data) == 0) {
- return 1;
- }
- }
-
- return 0;
-}
-
-static sftp_request_queue request_queue_new(sftp_message msg) {
- sftp_request_queue queue = NULL;
-
- queue = malloc(sizeof(struct sftp_request_queue_struct));
- if (queue == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(queue);
-
- queue->message = msg;
-
- return queue;
-}
-
-static void request_queue_free(sftp_request_queue queue) {
- if (queue == NULL) {
- return;
- }
-
- ZERO_STRUCTP(queue);
- SAFE_FREE(queue);
-}
-
-static int sftp_enqueue(sftp_session sftp, sftp_message msg) {
- sftp_request_queue queue = NULL;
- sftp_request_queue ptr;
-
- queue = request_queue_new(msg);
- if (queue == NULL) {
- return -1;
- }
-
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Queued msg type %d id %d",
- msg->id, msg->packet_type);
-
- if(sftp->queue == NULL) {
- sftp->queue = queue;
- } else {
- ptr = sftp->queue;
- while(ptr->next) {
- ptr=ptr->next; /* find end of linked list */
- }
- ptr->next = queue; /* add it on bottom */
- }
-
- return 0;
-}
-
-/*
- * Pulls of a message from the queue based on the ID.
- * Returns NULL if no message has been found.
- */
-static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){
- sftp_request_queue prev = NULL;
- sftp_request_queue queue;
- sftp_message msg;
-
- if(sftp->queue == NULL) {
- return NULL;
- }
-
- queue = sftp->queue;
- while (queue) {
- if(queue->message->id == id) {
- /* remove from queue */
- if (prev == NULL) {
- sftp->queue = queue->next;
- } else {
- prev->next = queue->next;
- }
- msg = queue->message;
- request_queue_free(queue);
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Dequeued msg id %d type %d",
- msg->id,
- msg->packet_type);
- return msg;
- }
- prev = queue;
- queue = queue->next;
- }
-
- return NULL;
-}
-
-/*
- * Assigns a new SFTP ID for new requests and assures there is no collision
- * between them.
- * Returns a new ID ready to use in a request
- */
-static inline uint32_t sftp_get_new_id(sftp_session session) {
- return ++session->id_counter;
-}
-
-static sftp_status_message parse_status_msg(sftp_message msg){
- sftp_status_message status;
-
- if (msg->packet_type != SSH_FXP_STATUS) {
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Not a ssh_fxp_status message passed in!");
- return NULL;
- }
-
- status = malloc(sizeof(struct sftp_status_message_struct));
- if (status == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(status);
-
- status->id = msg->id;
- if (buffer_get_u32(msg->payload,&status->status) != 4){
- SAFE_FREE(status);
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_STATUS message");
- return NULL;
- }
- status->error = buffer_get_ssh_string(msg->payload);
- status->lang = buffer_get_ssh_string(msg->payload);
- if(status->error == NULL || status->lang == NULL){
- if(msg->sftp->version >=3){
- /* These are mandatory from version 3 */
- ssh_string_free(status->error);
- /* status->lang never get allocated if something failed */
- SAFE_FREE(status);
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_STATUS message");
- return NULL;
- }
- }
-
- status->status = ntohl(status->status);
- if(status->error)
- status->errormsg = ssh_string_to_char(status->error);
- else
- status->errormsg = strdup("No error message in packet");
- if(status->lang)
- status->langmsg = ssh_string_to_char(status->lang);
- else
- status->langmsg = strdup("");
- if (status->errormsg == NULL || status->langmsg == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- status_msg_free(status);
- return NULL;
- }
-
- return status;
-}
-
-static void status_msg_free(sftp_status_message status){
- if (status == NULL) {
- return;
- }
-
- ssh_string_free(status->error);
- ssh_string_free(status->lang);
- SAFE_FREE(status->errormsg);
- SAFE_FREE(status->langmsg);
- SAFE_FREE(status);
-}
-
-static sftp_file parse_handle_msg(sftp_message msg){
- sftp_file file;
-
- if(msg->packet_type != SSH_FXP_HANDLE) {
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Not a ssh_fxp_handle message passed in!");
- return NULL;
- }
-
- file = malloc(sizeof(struct sftp_file_struct));
- if (file == NULL) {
- ssh_set_error_oom(msg->sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(file);
-
- file->handle = buffer_get_ssh_string(msg->payload);
- if (file->handle == NULL) {
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_HANDLE message");
- SAFE_FREE(file);
- return NULL;
- }
-
- file->sftp = msg->sftp;
- file->offset = 0;
- file->eof = 0;
-
- return file;
-}
-
-/* Open a directory */
-sftp_dir sftp_opendir(sftp_session sftp, const char *path){
- sftp_message msg = NULL;
- sftp_file file = NULL;
- sftp_dir dir = NULL;
- sftp_status_message status;
- ssh_string path_s;
- ssh_buffer payload;
- uint32_t id;
-
- payload = ssh_buffer_new();
- if (payload == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- path_s = ssh_string_from_char(path);
- if (path_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(payload);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(payload, id) < 0 ||
- buffer_add_ssh_string(payload, path_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(payload);
- ssh_string_free(path_s);
- return NULL;
- }
- ssh_string_free(path_s);
-
- if (sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload) < 0) {
- ssh_buffer_free(payload);
- return NULL;
- }
- ssh_buffer_free(payload);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return NULL;
- case SSH_FXP_HANDLE:
- file = parse_handle_msg(msg);
- sftp_message_free(msg);
- if (file != NULL) {
- dir = malloc(sizeof(struct sftp_dir_struct));
- if (dir == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(dir);
-
- dir->sftp = sftp;
- dir->name = strdup(path);
- if (dir->name == NULL) {
- SAFE_FREE(dir);
- SAFE_FREE(file);
- return NULL;
- }
- dir->handle = file->handle;
- SAFE_FREE(file);
- }
- return dir;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during opendir!", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-/*
- * Parse the attributes from a payload from some messages. It is coded on
- * baselines from the protocol version 4.
- * This code is more or less dead but maybe we need it in future.
- */
-static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
- int expectnames) {
- sftp_attributes attr;
- ssh_string owner = NULL;
- ssh_string group = NULL;
- uint32_t flags = 0;
- int ok = 0;
-
- /* unused member variable */
- (void) expectnames;
-
- attr = malloc(sizeof(struct sftp_attributes_struct));
- if (attr == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(attr);
-
- /* This isn't really a loop, but it is like a try..catch.. */
- do {
- if (buffer_get_u32(buf, &flags) != 4) {
- break;
- }
-
- flags = ntohl(flags);
- attr->flags = flags;
-
- if (flags & SSH_FILEXFER_ATTR_SIZE) {
- if (buffer_get_u64(buf, &attr->size) != 8) {
- break;
- }
- attr->size = ntohll(attr->size);
- }
-
- if (flags & SSH_FILEXFER_ATTR_OWNERGROUP) {
- if((owner = buffer_get_ssh_string(buf)) == NULL ||
- (attr->owner = ssh_string_to_char(owner)) == NULL) {
- break;
- }
- if ((group = buffer_get_ssh_string(buf)) == NULL ||
- (attr->group = ssh_string_to_char(group)) == NULL) {
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- if (buffer_get_u32(buf, &attr->permissions) != 4) {
- break;
- }
- attr->permissions = ntohl(attr->permissions);
-
- /* FIXME on windows! */
- switch (attr->permissions & S_IFMT) {
- case S_IFSOCK:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- attr->type = SSH_FILEXFER_TYPE_SPECIAL;
- break;
- case S_IFLNK:
- attr->type = SSH_FILEXFER_TYPE_SYMLINK;
- break;
- case S_IFREG:
- attr->type = SSH_FILEXFER_TYPE_REGULAR;
- break;
- case S_IFDIR:
- attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
- break;
- default:
- attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
- if (buffer_get_u64(buf, &attr->atime64) != 8) {
- break;
- }
- attr->atime64 = ntohll(attr->atime64);
- }
-
- if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
- if (buffer_get_u32(buf, &attr->atime_nseconds) != 4) {
- break;
- }
- attr->atime_nseconds = ntohl(attr->atime_nseconds);
- }
-
- if (flags & SSH_FILEXFER_ATTR_CREATETIME) {
- if (buffer_get_u64(buf, &attr->createtime) != 8) {
- break;
- }
- attr->createtime = ntohll(attr->createtime);
- }
-
- if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
- if (buffer_get_u32(buf, &attr->createtime_nseconds) != 4) {
- break;
- }
- attr->createtime_nseconds = ntohl(attr->createtime_nseconds);
- }
-
- if (flags & SSH_FILEXFER_ATTR_MODIFYTIME) {
- if (buffer_get_u64(buf, &attr->mtime64) != 8) {
- break;
- }
- attr->mtime64 = ntohll(attr->mtime64);
- }
-
- if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
- if (buffer_get_u32(buf, &attr->mtime_nseconds) != 4) {
- break;
- }
- attr->mtime_nseconds = ntohl(attr->mtime_nseconds);
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACL) {
- if ((attr->acl = buffer_get_ssh_string(buf)) == NULL) {
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
- if (buffer_get_u32(buf,&attr->extended_count) != 4) {
- break;
- }
- attr->extended_count = ntohl(attr->extended_count);
-
- while(attr->extended_count &&
- (attr->extended_type = buffer_get_ssh_string(buf)) &&
- (attr->extended_data = buffer_get_ssh_string(buf))){
- attr->extended_count--;
- }
-
- if (attr->extended_count) {
- break;
- }
- }
- ok = 1;
- } while (0);
-
- if (ok == 0) {
- /* break issued somewhere */
- ssh_string_free(owner);
- ssh_string_free(group);
- ssh_string_free(attr->acl);
- ssh_string_free(attr->extended_type);
- ssh_string_free(attr->extended_data);
- SAFE_FREE(attr->owner);
- SAFE_FREE(attr->group);
- SAFE_FREE(attr);
-
- ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
-
- return NULL;
- }
-
- return attr;
-}
-
-enum sftp_longname_field_e {
- SFTP_LONGNAME_PERM = 0,
- SFTP_LONGNAME_FIXME,
- SFTP_LONGNAME_OWNER,
- SFTP_LONGNAME_GROUP,
- SFTP_LONGNAME_SIZE,
- SFTP_LONGNAME_DATE,
- SFTP_LONGNAME_TIME,
- SFTP_LONGNAME_NAME,
-};
-
-static char *sftp_parse_longname(const char *longname,
- enum sftp_longname_field_e longname_field) {
- const char *p, *q;
- size_t len, field = 0;
- char *x;
-
- p = longname;
- /* Find the beginning of the field which is specified by sftp_longanme_field_e. */
- while(field != longname_field) {
- if(isspace(*p)) {
- field++;
- p++;
- while(*p && isspace(*p)) {
- p++;
- }
- } else {
- p++;
- }
- }
-
- q = p;
- while (! isspace(*q)) {
- q++;
- }
-
- /* There is no strndup on windows */
- len = q - p + 1;
- x = malloc(len);
- if (x == NULL) {
- return NULL;
- }
-
- snprintf(x, len, "%s", p);
-
- return x;
-}
-
-/* sftp version 0-3 code. It is different from the v4 */
-/* maybe a paste of the draft is better than the code */
-/*
- uint32 flags
- uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
- uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
- uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
- uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
- uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
- uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
- uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
- string extended_type
- string extended_data
- ... more extended data (extended_type - extended_data pairs),
- so that number of pairs equals extended_count */
-static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
- int expectname) {
- ssh_string longname = NULL;
- ssh_string name = NULL;
- sftp_attributes attr;
- uint32_t flags = 0;
- int ok = 0;
-
- attr = malloc(sizeof(struct sftp_attributes_struct));
- if (attr == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(attr);
-
- /* This isn't really a loop, but it is like a try..catch.. */
- do {
- if (expectname) {
- if ((name = buffer_get_ssh_string(buf)) == NULL ||
- (attr->name = ssh_string_to_char(name)) == NULL) {
- break;
- }
- ssh_string_free(name);
-
- ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
-
- if ((longname=buffer_get_ssh_string(buf)) == NULL ||
- (attr->longname=ssh_string_to_char(longname)) == NULL) {
- break;
- }
- ssh_string_free(longname);
-
- /* Set owner and group if we talk to openssh and have the longname */
- if (ssh_get_openssh_version(sftp->session)) {
- attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER);
- if (attr->owner == NULL) {
- break;
- }
-
- attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
- if (attr->group == NULL) {
- break;
- }
- }
- }
-
- if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
- break;
- }
- flags = ntohl(flags);
- attr->flags = flags;
- ssh_log(sftp->session, SSH_LOG_RARE,
- "Flags: %.8lx\n", (long unsigned int) flags);
-
- if (flags & SSH_FILEXFER_ATTR_SIZE) {
- if(buffer_get_u64(buf, &attr->size) != sizeof(uint64_t)) {
- break;
- }
- attr->size = ntohll(attr->size);
- ssh_log(sftp->session, SSH_LOG_RARE,
- "Size: %llu\n",
- (long long unsigned int) attr->size);
- }
-
- if (flags & SSH_FILEXFER_ATTR_UIDGID) {
- if (buffer_get_u32(buf, &attr->uid) != sizeof(uint32_t)) {
- break;
- }
- if (buffer_get_u32(buf, &attr->gid) != sizeof(uint32_t)) {
- break;
- }
- attr->uid = ntohl(attr->uid);
- attr->gid = ntohl(attr->gid);
- }
-
- if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- if (buffer_get_u32(buf, &attr->permissions) != sizeof(uint32_t)) {
- break;
- }
- attr->permissions = ntohl(attr->permissions);
-
- switch (attr->permissions & S_IFMT) {
- case S_IFSOCK:
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- attr->type = SSH_FILEXFER_TYPE_SPECIAL;
- break;
- case S_IFLNK:
- attr->type = SSH_FILEXFER_TYPE_SYMLINK;
- break;
- case S_IFREG:
- attr->type = SSH_FILEXFER_TYPE_REGULAR;
- break;
- case S_IFDIR:
- attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
- break;
- default:
- attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
- break;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
- if (buffer_get_u32(buf, &attr->atime) != sizeof(uint32_t)) {
- break;
- }
- attr->atime = ntohl(attr->atime);
- if (buffer_get_u32(buf, &attr->mtime) != sizeof(uint32_t)) {
- break;
- }
- attr->mtime = ntohl(attr->mtime);
- }
-
- if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
- if (buffer_get_u32(buf, &attr->extended_count) != sizeof(uint32_t)) {
- break;
- }
-
- attr->extended_count = ntohl(attr->extended_count);
- while (attr->extended_count &&
- (attr->extended_type = buffer_get_ssh_string(buf))
- && (attr->extended_data = buffer_get_ssh_string(buf))) {
- attr->extended_count--;
- }
-
- if (attr->extended_count) {
- break;
- }
- }
- ok = 1;
- } while (0);
-
- if (!ok) {
- /* break issued somewhere */
- ssh_string_free(name);
- ssh_string_free(longname);
- ssh_string_free(attr->extended_type);
- ssh_string_free(attr->extended_data);
- SAFE_FREE(attr->name);
- SAFE_FREE(attr->longname);
- SAFE_FREE(attr->owner);
- SAFE_FREE(attr->group);
- SAFE_FREE(attr);
-
- ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
-
- return NULL;
- }
-
- /* everything went smoothly */
- return attr;
-}
-
-/* FIXME is this really needed as a public function? */
-int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr) {
- uint32_t flags = (attr ? attr->flags : 0);
-
- flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID |
- SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
-
- if (buffer_add_u32(buffer, htonl(flags)) < 0) {
- return -1;
- }
-
- if (attr) {
- if (flags & SSH_FILEXFER_ATTR_SIZE) {
- if (buffer_add_u64(buffer, htonll(attr->size)) < 0) {
- return -1;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_UIDGID) {
- if (buffer_add_u32(buffer,htonl(attr->uid)) < 0 ||
- buffer_add_u32(buffer,htonl(attr->gid)) < 0) {
- return -1;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- if (buffer_add_u32(buffer, htonl(attr->permissions)) < 0) {
- return -1;
- }
- }
-
- if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
- if (buffer_add_u32(buffer, htonl(attr->atime)) < 0 ||
- buffer_add_u32(buffer, htonl(attr->mtime)) < 0) {
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-
-sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,
- int expectname) {
- switch(session->version) {
- case 4:
- return sftp_parse_attr_4(session, buf, expectname);
- case 3:
- case 2:
- case 1:
- case 0:
- return sftp_parse_attr_3(session, buf, expectname);
- default:
- ssh_set_error(session->session, SSH_FATAL,
- "Version %d unsupported by client", session->server_version);
- return NULL;
- }
-
- return NULL;
-}
-
-/* Get the version of the SFTP protocol supported by the server */
-int sftp_server_version(sftp_session sftp) {
- return sftp->server_version;
-}
-
-/* Get a single file attributes structure of a directory. */
-sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) {
- sftp_message msg = NULL;
- sftp_status_message status;
- sftp_attributes attr;
- ssh_buffer payload;
- uint32_t id;
-
- if (dir->buffer == NULL) {
- payload = ssh_buffer_new();
- if (payload == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(payload, id) < 0 ||
- buffer_add_ssh_string(payload, dir->handle) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(payload);
- return NULL;
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_READDIR, payload) < 0) {
- ssh_buffer_free(payload);
- return NULL;
- }
- ssh_buffer_free(payload);
-
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Sent a ssh_fxp_readdir with id %d", id);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- switch (msg->packet_type){
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_EOF:
- dir->eof = 1;
- status_msg_free(status);
- return NULL;
- default:
- break;
- }
-
- ssh_set_error(sftp->session, SSH_FATAL,
- "Unknown error status: %d", status->status);
- status_msg_free(status);
-
- return NULL;
- case SSH_FXP_NAME:
- buffer_get_u32(msg->payload, &dir->count);
- dir->count = ntohl(dir->count);
- dir->buffer = msg->payload;
- msg->payload = NULL;
- sftp_message_free(msg);
- break;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Unsupported message back %d", msg->packet_type);
- sftp_message_free(msg);
-
- return NULL;
- }
- }
-
- /* now dir->buffer contains a buffer and dir->count != 0 */
- if (dir->count == 0) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Count of files sent by the server is zero, which is invalid, or "
- "libsftp bug");
- return NULL;
- }
-
- ssh_log(sftp->session, SSH_LOG_RARE, "Count is %d", dir->count);
-
- attr = sftp_parse_attr(sftp, dir->buffer, 1);
- if (attr == NULL) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Couldn't parse the SFTP attributes");
- return NULL;
- }
-
- dir->count--;
- if (dir->count == 0) {
- ssh_buffer_free(dir->buffer);
- dir->buffer = NULL;
- }
-
- return attr;
-}
-
-/* Tell if the directory has reached EOF (End Of File). */
-int sftp_dir_eof(sftp_dir dir) {
- return dir->eof;
-}
-
-/* Free a SFTP_ATTRIBUTE handle */
-void sftp_attributes_free(sftp_attributes file){
- if (file == NULL) {
- return;
- }
-
- ssh_string_free(file->acl);
- ssh_string_free(file->extended_data);
- ssh_string_free(file->extended_type);
-
- SAFE_FREE(file->name);
- SAFE_FREE(file->longname);
- SAFE_FREE(file->group);
- SAFE_FREE(file->owner);
-
- SAFE_FREE(file);
-}
-
-static int sftp_handle_close(sftp_session sftp, ssh_string handle) {
- sftp_status_message status;
- sftp_message msg = NULL;
- ssh_buffer buffer = NULL;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, handle) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_CLOSE ,buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return -1;
- }
- msg = sftp_dequeue(sftp,id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if(status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- break;
- default:
- break;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during sftp_handle_close!", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Close an open file handle. */
-int sftp_close(sftp_file file){
- int err = SSH_NO_ERROR;
-
- SAFE_FREE(file->name);
- if (file->handle){
- err = sftp_handle_close(file->sftp,file->handle);
- ssh_string_free(file->handle);
- }
- /* FIXME: check server response and implement errno */
- SAFE_FREE(file);
-
- return err;
-}
-
-/* Close an open directory. */
-int sftp_closedir(sftp_dir dir){
- int err = SSH_NO_ERROR;
-
- SAFE_FREE(dir->name);
- if (dir->handle) {
- err = sftp_handle_close(dir->sftp, dir->handle);
- ssh_string_free(dir->handle);
- }
- /* FIXME: check server response and implement errno */
- ssh_buffer_free(dir->buffer);
- SAFE_FREE(dir);
-
- return err;
-}
-
-/* Open a file on the server. */
-sftp_file sftp_open(sftp_session sftp, const char *file, int flags,
- mode_t mode) {
- sftp_message msg = NULL;
- sftp_status_message status;
- struct sftp_attributes_struct attr;
- sftp_file handle;
- ssh_string filename;
- ssh_buffer buffer;
- uint32_t sftp_flags = 0;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- filename = ssh_string_from_char(file);
- if (filename == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- ZERO_STRUCT(attr);
- attr.permissions = mode;
- attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
-
- if (flags == O_RDONLY)
- sftp_flags |= SSH_FXF_READ; /* if any of the other flag is set,
- READ should not be set initialy */
- if (flags & O_WRONLY)
- sftp_flags |= SSH_FXF_WRITE;
- if (flags & O_RDWR)
- sftp_flags |= (SSH_FXF_WRITE | SSH_FXF_READ);
- if (flags & O_CREAT)
- sftp_flags |= SSH_FXF_CREAT;
- if (flags & O_TRUNC)
- sftp_flags |= SSH_FXF_TRUNC;
- if (flags & O_EXCL)
- sftp_flags |= SSH_FXF_EXCL;
- ssh_log(sftp->session,SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags);
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, filename) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- return NULL;
- }
- ssh_string_free(filename);
-
- if (buffer_add_u32(buffer, htonl(sftp_flags)) < 0 ||
- buffer_add_attributes(buffer, &attr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_OPEN, buffer) < 0) {
- ssh_buffer_free(buffer);
- return NULL;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
-
- return NULL;
- case SSH_FXP_HANDLE:
- handle = parse_handle_msg(msg);
- sftp_message_free(msg);
- return handle;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during open!", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-void sftp_file_set_nonblocking(sftp_file handle){
- handle->nonblocking=1;
-}
-void sftp_file_set_blocking(sftp_file handle){
- handle->nonblocking=0;
-}
-
-/* Read from a file using an opened sftp file handle. */
-ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
- sftp_session sftp = handle->sftp;
- sftp_message msg = NULL;
- sftp_status_message status;
- ssh_string datastring;
- ssh_buffer buffer;
- int id;
-
- if (handle->eof) {
- return 0;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
- id = sftp_get_new_id(handle->sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, handle->handle) < 0 ||
- buffer_add_u64(buffer, htonll(handle->offset)) < 0 ||
- buffer_add_u32(buffer,htonl(count)) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (handle->nonblocking) {
- if (ssh_channel_poll(handle->sftp->channel, 0) == 0) {
- /* we cannot block */
- return 0;
- }
- }
- if (sftp_read_and_dispatch(handle->sftp) < 0) {
- /* something nasty has happened */
- return -1;
- }
- msg = sftp_dequeue(handle->sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_EOF:
- handle->eof = 1;
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- ssh_set_error(sftp->session,SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- case SSH_FXP_DATA:
- datastring = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (datastring == NULL) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received invalid DATA packet from sftp server");
- return -1;
- }
-
- if (ssh_string_len(datastring) > count) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received a too big DATA packet from sftp server: "
- "%zu and asked for %zu",
- ssh_string_len(datastring), count);
- ssh_string_free(datastring);
- return -1;
- }
- count = ssh_string_len(datastring);
- handle->offset += count;
- memcpy(buf, ssh_string_data(datastring), count);
- ssh_string_free(datastring);
- return count;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during read!", msg->packet_type);
- sftp_message_free(msg);
- return -1;
- }
-
- return -1; /* not reached */
-}
-
-/* Start an asynchronous read from a file using an opened sftp file handle. */
-int sftp_async_read_begin(sftp_file file, uint32_t len){
- sftp_session sftp = file->sftp;
- ssh_buffer buffer;
- uint32_t id;
-
- sftp_enter_function();
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0 ||
- buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
- buffer_add_u32(buffer, htonl(len)) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- file->offset += len; /* assume we'll read len bytes */
-
- sftp_leave_function();
- return id;
-}
-
-/* Wait for an asynchronous read to complete and save the data. */
-int sftp_async_read(sftp_file file, void *data, uint32_t size, uint32_t id){
- sftp_session sftp = file->sftp;
- sftp_message msg = NULL;
- sftp_status_message status;
- ssh_string datastring;
- int err = SSH_OK;
- uint32_t len;
-
- sftp_enter_function();
-
- if (file->eof) {
- sftp_leave_function();
- return 0;
- }
-
- /* handle an existing request */
- while (msg == NULL) {
- if (file->nonblocking){
- if (ssh_channel_poll(sftp->channel, 0) == 0) {
- /* we cannot block */
- return SSH_AGAIN;
- }
- }
-
- if (sftp_read_and_dispatch(sftp) < 0) {
- /* something nasty has happened */
- sftp_leave_function();
- return SSH_ERROR;
- }
-
- msg = sftp_dequeue(sftp,id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- sftp_leave_function();
- return -1;
- }
- sftp_set_error(sftp, status->status);
- if (status->status != SSH_FX_EOF) {
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server : %s", status->errormsg);
- sftp_leave_function();
- err = SSH_ERROR;
- } else {
- file->eof = 1;
- }
- status_msg_free(status);
- sftp_leave_function();
- return err;
- case SSH_FXP_DATA:
- datastring = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (datastring == NULL) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received invalid DATA packet from sftp server");
- sftp_leave_function();
- return SSH_ERROR;
- }
- if (ssh_string_len(datastring) > size) {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received a too big DATA packet from sftp server: "
- "%zu and asked for %u",
- ssh_string_len(datastring), size);
- ssh_string_free(datastring);
- sftp_leave_function();
- return SSH_ERROR;
- }
- len = ssh_string_len(datastring);
- //handle->offset+=len;
- /* We already have set the offset previously. All we can do is warn that the expected len
- * and effective lengths are different */
- memcpy(data, ssh_string_data(datastring), len);
- ssh_string_free(datastring);
- sftp_leave_function();
- return len;
- default:
- ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type);
- sftp_message_free(msg);
- sftp_leave_function();
- return SSH_ERROR;
- }
-
- sftp_leave_function();
- return SSH_ERROR;
-}
-
-ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
- sftp_session sftp = file->sftp;
- sftp_message msg = NULL;
- sftp_status_message status;
- ssh_string datastring;
- ssh_buffer buffer;
- uint32_t id;
- int len;
- int packetlen;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- datastring = ssh_string_new(count);
- if (datastring == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_string_fill(datastring, buf, count);
-
- id = sftp_get_new_id(file->sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0 ||
- buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
- buffer_add_ssh_string(buffer, datastring) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(datastring);
- return -1;
- }
- ssh_string_free(datastring);
- len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer);
- packetlen=ssh_buffer_get_len(buffer);
- ssh_buffer_free(buffer);
- if (len < 0) {
- return -1;
- } else if (len != packetlen) {
- ssh_log(sftp->session, SSH_LOG_PACKET,
- "Could not write as much data as expected");
- }
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(file->sftp) < 0) {
- /* something nasty has happened */
- return -1;
- }
- msg = sftp_dequeue(file->sftp, id);
- }
-
- switch (msg->packet_type) {
- case SSH_FXP_STATUS:
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- file->offset += count;
- status_msg_free(status);
- return count;
- default:
- break;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- file->offset += count;
- status_msg_free(status);
- return -1;
- default:
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d during write!", msg->packet_type);
- sftp_message_free(msg);
- return -1;
- }
-
- return -1; /* not reached */
-}
-
-/* Seek to a specific location in a file. */
-int sftp_seek(sftp_file file, uint32_t new_offset) {
- if (file == NULL) {
- return -1;
- }
-
- file->offset = new_offset;
-
- return 0;
-}
-
-int sftp_seek64(sftp_file file, uint64_t new_offset) {
- if (file == NULL) {
- return -1;
- }
-
- file->offset = new_offset;
-
- return 0;
-}
-
-/* Report current byte position in file. */
-unsigned long sftp_tell(sftp_file file) {
- return (unsigned long)file->offset;
-}
-/* Report current byte position in file. */
-uint64_t sftp_tell64(sftp_file file) {
- return (uint64_t) file->offset;
-}
-
-/* Rewinds the position of the file pointer to the beginning of the file.*/
-void sftp_rewind(sftp_file file) {
- file->offset = 0;
-}
-
-/* code written by Nick */
-int sftp_unlink(sftp_session sftp, const char *file) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string filename;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- filename = ssh_string_from_char(file);
- if (filename == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, filename) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- }
- if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- }
- ssh_string_free(filename);
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp)) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_STATUS) {
- /* by specification, this command's only supposed to return SSH_FXP_STATUS */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
-
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session,SSH_FATAL,
- "Received message %d when attempting to remove file", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* code written by Nick */
-int sftp_rmdir(sftp_session sftp, const char *directory) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string filename;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- filename = ssh_string_from_char(directory);
- if (filename == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, filename) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(filename);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- break;
- default:
- break;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to remove directory",
- msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Code written by Nick */
-int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- sftp_attributes errno_attr = NULL;
- struct sftp_attributes_struct attr;
- ssh_buffer buffer;
- ssh_string path;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- path = ssh_string_from_char(directory);
- if (path == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- ZERO_STRUCT(attr);
- attr.permissions = mode;
- attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, path) < 0 ||
- buffer_add_attributes(buffer, &attr) < 0 ||
- sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(path);
- }
- ssh_buffer_free(buffer);
- ssh_string_free(path);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_FAILURE:
- /*
- * mkdir always returns a failure, even if the path already exists.
- * To be POSIX conform and to be able to map it to EEXIST a stat
- * call is needed here.
- */
- errno_attr = sftp_lstat(sftp, directory);
- if (errno_attr != NULL) {
- SAFE_FREE(errno_attr);
- sftp_set_error(sftp, SSH_FX_FILE_ALREADY_EXISTS);
- }
- break;
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- break;
- default:
- break;
- }
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to make directory",
- msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* code written by nick */
-int sftp_rename(sftp_session sftp, const char *original, const char *newname) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_buffer buffer;
- ssh_string oldpath;
- ssh_string newpath;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- oldpath = ssh_string_from_char(original);
- if (oldpath == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- newpath = ssh_string_from_char(newname);
- if (newpath == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, oldpath) < 0 ||
- buffer_add_ssh_string(buffer, newpath) < 0 ||
- /* POSIX rename atomically replaces newpath, we should do the same
- * only available on >=v4 */
- sftp->version>=4 ? (buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0):0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- ssh_string_free(newpath);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- ssh_string_free(newpath);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(oldpath);
- ssh_string_free(newpath);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- /*
- * Status should be SSH_FX_OK if the command was successful, if it didn't,
- * then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to rename",
- msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Code written by Nick */
-/* Set file attributes on a file, directory or symbolic link. */
-int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr) {
- uint32_t id;
- ssh_buffer buffer;
- ssh_string path;
- sftp_message msg = NULL;
- sftp_status_message status = NULL;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- path = ssh_string_from_char(file);
- if (path == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, path) < 0 ||
- buffer_add_attributes(buffer, attr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(path);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(path);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(path);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-/* Change the file owner and group */
-int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t group) {
- struct sftp_attributes_struct attr;
- ZERO_STRUCT(attr);
-
- attr.uid = owner;
- attr.gid = group;
-
- attr.flags = SSH_FILEXFER_ATTR_UIDGID;
-
- return sftp_setstat(sftp, file, &attr);
-}
-
-/* Change permissions of a file */
-int sftp_chmod(sftp_session sftp, const char *file, mode_t mode) {
- struct sftp_attributes_struct attr;
- ZERO_STRUCT(attr);
- attr.permissions = mode;
- attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
-
- return sftp_setstat(sftp, file, &attr);
-}
-
-/* Change the last modification and access time of a file. */
-int sftp_utimes(sftp_session sftp, const char *file,
- const struct timeval *times) {
- struct sftp_attributes_struct attr;
- ZERO_STRUCT(attr);
-
- attr.atime = times[0].tv_sec;
- attr.atime_nseconds = times[0].tv_usec;
-
- attr.mtime = times[1].tv_sec;
- attr.mtime_nseconds = times[1].tv_usec;
-
- attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME |
- SSH_FILEXFER_ATTR_SUBSECOND_TIMES;
-
- return sftp_setstat(sftp, file, &attr);
-}
-
-int sftp_symlink(sftp_session sftp, const char *target, const char *dest) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string target_s;
- ssh_string dest_s;
- ssh_buffer buffer;
- uint32_t id;
-
- if (sftp == NULL)
- return -1;
- if (target == NULL || dest == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return -1;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- target_s = ssh_string_from_char(target);
- if (target_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- dest_s = ssh_string_from_char(dest);
- if (dest_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_string_free(target_s);
- ssh_buffer_free(buffer);
- return -1;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- if (ssh_get_openssh_version(sftp->session)) {
- /* TODO check for version number if they ever fix it. */
- if (buffer_add_ssh_string(buffer, target_s) < 0 ||
- buffer_add_ssh_string(buffer, dest_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- } else {
- if (buffer_add_ssh_string(buffer, dest_s) < 0 ||
- buffer_add_ssh_string(buffer, target_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
- return -1;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(dest_s);
- ssh_string_free(target_s);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return -1;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- /* By specification, this command only returns SSH_FXP_STATUS */
- if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return -1;
- }
- sftp_set_error(sftp, status->status);
- switch (status->status) {
- case SSH_FX_OK:
- status_msg_free(status);
- return 0;
- default:
- break;
- }
- /*
- * The status should be SSH_FX_OK if the command was successful, if it
- * didn't, then there was an error
- */
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return -1;
- } else {
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return -1;
-}
-
-char *sftp_readlink(sftp_session sftp, const char *path) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string path_s = NULL;
- ssh_string link_s = NULL;
- ssh_buffer buffer;
- char *lnk;
- uint32_t ignored;
- uint32_t id;
-
- if (sftp == NULL)
- return NULL;
- if (path == NULL) {
- ssh_set_error_invalid(sftp, __FUNCTION__);
- return NULL;
- }
- if (sftp->version < 3){
- ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_readlink",sftp->version);
- return NULL;
- }
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- path_s = ssh_string_from_char(path);
- if (path_s == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, path_s) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(path_s);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(path_s);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(path_s);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_NAME) {
- /* we don't care about "count" */
- buffer_get_u32(msg->payload, &ignored);
- /* we only care about the file name string */
- link_s = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (link_s == NULL) {
- /* TODO: what error to set here? */
- return NULL;
- }
- lnk = ssh_string_to_char(link_s);
- ssh_string_free(link_s);
-
- return lnk;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) {
- sftp_statvfs_t statvfs;
- uint64_t tmp;
- int ok = 0;
-
- statvfs = malloc(sizeof(struct sftp_statvfs_struct));
- if (statvfs == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(statvfs);
-
- /* try .. catch */
- do {
- /* file system block size */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_bsize = ntohll(tmp);
-
- /* fundamental fs block size */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_frsize = ntohll(tmp);
-
- /* number of blocks (unit f_frsize) */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_blocks = ntohll(tmp);
-
- /* free blocks in file system */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_bfree = ntohll(tmp);
-
- /* free blocks for non-root */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_bavail = ntohll(tmp);
-
- /* total file inodes */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_files = ntohll(tmp);
-
- /* free file inodes */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_ffree = ntohll(tmp);
-
- /* free file inodes for to non-root */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_favail = ntohll(tmp);
-
- /* file system id */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_fsid = ntohll(tmp);
-
- /* bit mask of f_flag values */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_flag = ntohll(tmp);
-
- /* maximum filename length */
- if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
- break;
- }
- statvfs->f_namemax = ntohll(tmp);
-
- ok = 1;
- } while(0);
-
- if (!ok) {
- SAFE_FREE(statvfs);
- ssh_set_error(sftp->session, SSH_FATAL, "Invalid statvfs structure");
- return NULL;
- }
-
- return statvfs;
-}
-
-sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string pathstr;
- ssh_string ext;
- ssh_buffer buffer;
- uint32_t id;
-
- if (sftp == NULL)
- return NULL;
- if (path == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
- if (sftp->version < 3){
- ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_statvfs",sftp->version);
- return NULL;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- ext = ssh_string_from_char("statvfs@openssh.com");
- if (ext == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- pathstr = ssh_string_from_char(path);
- if (pathstr == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, ext) < 0 ||
- buffer_add_ssh_string(buffer, pathstr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- ssh_string_free(pathstr);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- ssh_string_free(pathstr);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- ssh_string_free(pathstr);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
- sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
- sftp_message_free(msg);
- if (buf == NULL) {
- return NULL;
- }
-
- return buf;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to get statvfs", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-sftp_statvfs_t sftp_fstatvfs(sftp_file file) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- sftp_session sftp;
- ssh_string ext;
- ssh_buffer buffer;
- uint32_t id;
-
- if (file == NULL) {
- return NULL;
- }
- sftp = file->sftp;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- ext = ssh_string_from_char("fstatvfs@openssh.com");
- if (ext == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, ext) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(ext);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
- sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
- sftp_message_free(msg);
- if (buf == NULL) {
- return NULL;
- }
-
- return buf;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-void sftp_statvfs_free(sftp_statvfs_t statvfs) {
- if (statvfs == NULL) {
- return;
- }
-
- SAFE_FREE(statvfs);
-}
-
-/* another code written by Nick */
-char *sftp_canonicalize_path(sftp_session sftp, const char *path) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string name = NULL;
- ssh_string pathstr;
- ssh_buffer buffer;
- char *cname;
- uint32_t ignored;
- uint32_t id;
-
- if (sftp == NULL)
- return NULL;
- if (path == NULL) {
- ssh_set_error_invalid(sftp->session, __FUNCTION__);
- return NULL;
- }
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- pathstr = ssh_string_from_char(path);
- if (pathstr == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, pathstr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- if (sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_NAME) {
- /* we don't care about "count" */
- buffer_get_u32(msg->payload, &ignored);
- /* we only care about the file name string */
- name = buffer_get_ssh_string(msg->payload);
- sftp_message_free(msg);
- if (name == NULL) {
- /* TODO: error message? */
- return NULL;
- }
- cname = ssh_string_to_char(name);
- ssh_string_free(name);
- if (cname == NULL) {
- ssh_set_error_oom(sftp->session);
- }
- return cname;
- } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- } else { /* this shouldn't happen */
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received message %d when attempting to set stats", msg->packet_type);
- sftp_message_free(msg);
- }
-
- return NULL;
-}
-
-static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
- int param) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_string pathstr;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
-
- pathstr = ssh_string_from_char(path);
- if (pathstr == NULL) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
-
- id = sftp_get_new_id(sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, pathstr) < 0) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- if (sftp_packet_write(sftp, param, buffer) < 0) {
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
- return NULL;
- }
- ssh_buffer_free(buffer);
- ssh_string_free(pathstr);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_ATTRS) {
- return sftp_parse_attr(sftp, msg->payload, 0);
- } else if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- sftp_set_error(sftp, status->status);
- ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
- return NULL;
- }
- ssh_set_error(sftp->session, SSH_FATAL,
- "Received mesg %d during stat()", msg->packet_type);
- sftp_message_free(msg);
-
- return NULL;
-}
-
-sftp_attributes sftp_stat(sftp_session session, const char *path) {
- return sftp_xstat(session, path, SSH_FXP_STAT);
-}
-
-sftp_attributes sftp_lstat(sftp_session session, const char *path) {
- return sftp_xstat(session, path, SSH_FXP_LSTAT);
-}
-
-sftp_attributes sftp_fstat(sftp_file file) {
- sftp_status_message status = NULL;
- sftp_message msg = NULL;
- ssh_buffer buffer;
- uint32_t id;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(file->sftp->session);
- return NULL;
- }
-
- id = sftp_get_new_id(file->sftp);
- if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, file->handle) < 0) {
- ssh_set_error_oom(file->sftp->session);
- ssh_buffer_free(buffer);
- return NULL;
- }
- if (sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer) < 0) {
- ssh_buffer_free(buffer);
- return NULL;
- }
- ssh_buffer_free(buffer);
-
- while (msg == NULL) {
- if (sftp_read_and_dispatch(file->sftp) < 0) {
- return NULL;
- }
- msg = sftp_dequeue(file->sftp, id);
- }
-
- if (msg->packet_type == SSH_FXP_ATTRS){
- return sftp_parse_attr(file->sftp, msg->payload, 0);
- } else if (msg->packet_type == SSH_FXP_STATUS) {
- status = parse_status_msg(msg);
- sftp_message_free(msg);
- if (status == NULL) {
- return NULL;
- }
- ssh_set_error(file->sftp->session, SSH_REQUEST_DENIED,
- "SFTP server: %s", status->errormsg);
- status_msg_free(status);
-
- return NULL;
- }
- ssh_set_error(file->sftp->session, SSH_FATAL,
- "Received msg %d during fstat()", msg->packet_type);
- sftp_message_free(msg);
-
- return NULL;
-}
-
-#endif /* WITH_SFTP */
-/* vim: set ts=2 sw=2 et cindent: */