summaryrefslogtreecommitdiffstats
path: root/libssh/src/sftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/src/sftp.c')
-rw-r--r--libssh/src/sftp.c3081
1 files changed, 0 insertions, 3081 deletions
diff --git a/libssh/src/sftp.c b/libssh/src/sftp.c
deleted file mode 100644
index b57da645..00000000
--- a/libssh/src/sftp.c
+++ /dev/null
@@ -1,3081 +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 <asn@cryptomilk.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 <netinet/in.h>
-#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
-
-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;
- }
-
- sftp = malloc(sizeof(struct sftp_session_struct));
- if (sftp == NULL) {
- ssh_set_error_oom(session);
-
- return NULL;
- }
- ZERO_STRUCTP(sftp);
-
- sftp->ext = sftp_ext_new();
- if (sftp->ext == NULL) {
- ssh_set_error_oom(session);
- SAFE_FREE(sftp);
-
- return NULL;
- }
-
- sftp->session = session;
- sftp->channel = ssh_channel_new(session);
- if (sftp->channel == NULL) {
- SAFE_FREE(sftp);
-
- return NULL;
- }
-
- if (ssh_channel_open_session(sftp->channel)) {
- ssh_channel_free(sftp->channel);
- SAFE_FREE(sftp);
-
- return NULL;
- }
-
- if (ssh_channel_request_sftp(sftp->channel)) {
- sftp_free(sftp);
-
- return NULL;
- }
-
- return sftp;
-}
-
-sftp_session sftp_new_channel(ssh_session session, ssh_channel channel){
- sftp_session sftp;
-
- if (session == NULL) {
- return NULL;
- }
-
- sftp = malloc(sizeof(struct sftp_session_struct));
- if (sftp == NULL) {
- ssh_set_error_oom(session);
-
- return NULL;
- }
- ZERO_STRUCTP(sftp);
-
- sftp->ext = sftp_ext_new();
- if (sftp->ext == NULL) {
- ssh_set_error_oom(session);
- SAFE_FREE(sftp);
-
- return NULL;
- }
-
- sftp->session = session;
- sftp->channel = channel;
-
- 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;
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- 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);
- return -1;
- }
-
- SSH_LOG(SSH_LOG_PACKET, "Received SSH_FXP_INIT");
-
- buffer_get_u32(packet->payload, &version);
- version = ntohl(version);
- SSH_LOG(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);
- return -1;
- }
-
- if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) {
- ssh_set_error_oom(session);
- ssh_buffer_free(reply);
- return -1;
- }
-
- if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
- ssh_buffer_free(reply);
- return -1;
- }
- ssh_buffer_free(reply);
-
- SSH_LOG(SSH_LOG_RARE, "Server version sent");
-
- if (version > LIBSFTP_VERSION) {
- sftp->version = LIBSFTP_VERSION;
- } else {
- sftp->version=version;
- }
-
- 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);
-
- SAFE_FREE(sftp->handles);
-
- 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(buffer_get_rest_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, buffer_get_rest(payload),
- buffer_get_rest_len(payload));
- if (size < 0) {
- return -1;
- } else if((uint32_t) size != buffer_get_rest_len(payload)) {
- SSH_LOG(SSH_LOG_PACKET,
- "Had to write %d bytes, wrote only %d",
- buffer_get_rest_len(payload),
- size);
- }
-
- return size;
-}
-
-sftp_packet sftp_packet_read(sftp_session sftp) {
- unsigned char buffer[MAX_BUF_SIZE];
- sftp_packet packet = NULL;
- uint32_t size;
- int r;
-
- 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;
- }
-
- r=ssh_channel_read(sftp->channel, buffer, 4, 0);
- if (r < 0) {
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- return NULL;
- }
- ssh_buffer_add_data(packet->payload, buffer, r);
- 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);
- return NULL;
- }
-
- size = ntohl(size);
- r=ssh_channel_read(sftp->channel, buffer, 1, 0);
- if (r <= 0) {
- /* TODO: check if there are cases where an error needs to be set here */
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- return NULL;
- }
- ssh_buffer_add_data(packet->payload, buffer, r);
- buffer_get_u8(packet->payload, &packet->type);
- size=size-1;
- while (size>0){
- r=ssh_channel_read(sftp->channel,buffer,
- sizeof(buffer)>size ? size:sizeof(buffer),0);
-
- if(r <= 0) {
- /* TODO: check if there are cases where an error needs to be set here */
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- return NULL;
- }
- if (ssh_buffer_add_data(packet->payload, buffer, r) == SSH_ERROR) {
- ssh_buffer_free(packet->payload);
- SAFE_FREE(packet);
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- size -= r;
- }
-
- 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;
-
- 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;
-
- return msg;
-}
-
-static void sftp_message_free(sftp_message msg) {
- if (msg == NULL) {
- return;
- }
-
- ssh_buffer_free(msg->payload);
- SAFE_FREE(msg);
-}
-
-static sftp_message sftp_get_message(sftp_packet packet) {
- sftp_session sftp = packet->sftp;
- sftp_message msg = NULL;
- int rc;
-
- msg = sftp_message_new(sftp);
- if (msg == NULL) {
- 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);
- return NULL;
- }
-
- rc = ssh_buffer_unpack(packet->payload, "d", &msg->id);
- if (rc != SSH_OK) {
- ssh_set_error(packet->sftp->session, SSH_FATAL,
- "Invalid packet %d: no ID", packet->type);
- sftp_message_free(msg);
- return NULL;
- }
-
- SSH_LOG(SSH_LOG_PACKET,
- "Packet with id %d type %d",
- msg->id,
- msg->packet_type);
-
- if (ssh_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);
- return NULL;
- }
-
- return msg;
-}
-
-static int sftp_read_and_dispatch(sftp_session sftp) {
- sftp_packet packet = NULL;
- sftp_message msg = NULL;
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- return -1; /* something nasty happened reading the packet */
- }
-
- msg = sftp_get_message(packet);
- sftp_packet_free(packet);
- if (msg == NULL) {
- return -1;
- }
-
- if (sftp_enqueue(sftp, msg) < 0) {
- sftp_message_free(msg);
- return -1;
- }
-
- 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;
- char *ext_name = NULL;
- char *ext_data = NULL;
- uint32_t version;
- int rc;
-
- buffer = ssh_buffer_new();
- if (buffer == NULL) {
- ssh_set_error_oom(sftp->session);
- return -1;
- }
-
- rc = ssh_buffer_pack(buffer, "d", LIBSFTP_VERSION);
- if (rc != SSH_OK) {
- ssh_set_error_oom(sftp->session);
- ssh_buffer_free(buffer);
- return -1;
- }
- if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
- ssh_buffer_free(buffer);
- return -1;
- }
- ssh_buffer_free(buffer);
-
- packet = sftp_packet_read(sftp);
- if (packet == NULL) {
- 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);
- return -1;
- }
-
- /* TODO: are we sure there are 4 bytes ready? */
- rc = ssh_buffer_unpack(packet->payload, "d", &version);
- if (rc != SSH_OK){
- return -1;
- }
- SSH_LOG(SSH_LOG_RARE,
- "SFTP server version %d",
- version);
- rc = ssh_buffer_unpack(packet->payload, "s", &ext_name);
- while (rc == SSH_OK) {
- int count = sftp->ext->count;
-
- rc = ssh_buffer_unpack(packet->payload, "s", &ext_data);
- if (rc == SSH_ERROR) {
- break;
- }
-
- SSH_LOG(SSH_LOG_RARE,
- "SFTP server extension: %s, version: %s",
- ext_name, ext_data);
-
- count++;
- sftp->ext->name = realloc(sftp->ext->name, count * sizeof(char *));
- if (sftp->ext->name == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- return -1;
- }
- sftp->ext->name[count - 1] = ext_name;
-
- sftp->ext->data = realloc(sftp->ext->data, count * sizeof(char *));
- if (sftp->ext->data == NULL) {
- ssh_set_error_oom(sftp->session);
- SAFE_FREE(ext_name);
- SAFE_FREE(ext_data);
- return -1;
- }
- sftp->ext->data[count - 1] = ext_data;
-
- sftp->ext->count = count;
-
- rc = ssh_buffer_unpack(packet->payload, "s", &ext_name);
- }
-
- sftp_packet_free(packet);
-
- sftp->version = sftp->server_version = version;
-
-
- 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);
- return NULL;
- }
-
- if (idx > sftp->ext->count) {
- ssh_set_error_invalid(sftp->session);
- 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);
- return NULL;
- }
-
- if (idx > sftp->ext->count) {
- ssh_set_error_invalid(sftp->session);
- return NULL;
- }
-
- return sftp->ext->data[idx];
-}
-
-int sftp_extension_supported(sftp_session sftp, const char *name,
- const char *data) {
- int i, n;
-
- if (sftp == NULL || name == NULL || data == NULL) {
- return 0;
- }
-
- n = sftp_extensions_get_count(sftp);
- for (i = 0; i < n; i++) {
- const char *ext_name = sftp_extensions_get_name(sftp, i);
- const char *ext_data = sftp_extensions_get_data(sftp, i);
-
- if (ext_name != NULL && ext_data != NULL &&
- strcmp(ext_name, name) == 0 &&
- strcmp(ext_data, 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(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(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;
- int rc;
-
- 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;
- rc = ssh_buffer_unpack(msg->payload, "d",
- &status->status);
- if (rc != SSH_OK){
- SAFE_FREE(status);
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_STATUS message");
- return NULL;
- }
- rc = ssh_buffer_unpack(msg->payload, "ss",
- &status->errormsg,
- &status->langmsg);
-
- if(rc != SSH_OK && msg->sftp->version >=3){
- /* These are mandatory from version 3 */
- SAFE_FREE(status);
- ssh_set_error(msg->sftp->session, SSH_FATAL,
- "Invalid SSH_FXP_STATUS message");
- return NULL;
- }
- if (status->errormsg == NULL)
- status->errormsg = strdup("No error message in packet");
- if (status->langmsg == NULL)
- 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;
- }
-
- 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, htonl(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);
- free(file);
- 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) {
- owner = buffer_get_ssh_string(buf);
- if (owner == NULL) {
- break;
- }
- attr->owner = ssh_string_to_char(owner);
- ssh_string_free(owner);
- if (attr->owner == NULL) {
- break;
- }
-
- group = buffer_get_ssh_string(buf);
- if (group == NULL) {
- break;
- }
- attr->group = ssh_string_to_char(group);
- ssh_string_free(group);
- if (attr->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(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) {
- sftp_attributes attr;
- int rc;
-
- attr = malloc(sizeof(struct sftp_attributes_struct));
- if (attr == NULL) {
- ssh_set_error_oom(sftp->session);
- return NULL;
- }
- ZERO_STRUCTP(attr);
-
- if (expectname) {
- rc = ssh_buffer_unpack(buf, "ss",
- &attr->name,
- &attr->longname);
- if (rc != SSH_OK){
- goto error;
- }
- SSH_LOG(SSH_LOG_RARE, "Name: %s", attr->name);
-
- /* 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) {
- goto error;
- }
-
- attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
- if (attr->group == NULL) {
- goto error;
- }
- }
- }
-
- rc = ssh_buffer_unpack(buf, "d", &attr->flags);
- if (rc != SSH_OK){
- goto error;
- }
- SSH_LOG(SSH_LOG_RARE,
- "Flags: %.8lx\n", (long unsigned int) attr->flags);
-
- if (attr->flags & SSH_FILEXFER_ATTR_SIZE) {
- rc = ssh_buffer_unpack(buf, "q", &attr->size);
- if(rc != SSH_OK) {
- goto error;
- }
- SSH_LOG(SSH_LOG_RARE,
- "Size: %llu\n",
- (long long unsigned int) attr->size);
- }
-
- if (attr->flags & SSH_FILEXFER_ATTR_UIDGID) {
- rc = ssh_buffer_unpack(buf, "dd",
- &attr->uid,
- &attr->gid);
- if (rc != SSH_OK){
- goto error;
- }
- }
-
- if (attr->flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
- rc = ssh_buffer_unpack(buf, "d", &attr->permissions);
- if (rc != SSH_OK){
- goto error;
- }
-
- 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;
- }