diff options
Diffstat (limited to 'libssh/src/sftp.c')
-rw-r--r-- | libssh/src/sftp.c | 3081 |
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; - } |