sftp.c   sftp.c 
skipping to change at line 36 skipping to change at line 36
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifndef _WIN32 #ifndef _WIN32
#include <arpa/inet.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 #endif
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/ssh2.h" #include "libssh/ssh2.h"
#include "libssh/sftp.h" #include "libssh/sftp.h"
#include "libssh/buffer.h"
#include "libssh/channels.h"
#include "libssh/session.h"
#include "libssh/misc.h"
#ifdef WITH_SFTP #ifdef WITH_SFTP
#define sftp_enter_function() _enter_function(sftp->channel->session) #define sftp_enter_function() _enter_function(sftp->channel->session)
#define sftp_leave_function() _leave_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 */ /* functions */
static int sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg); static int sftp_enqueue(sftp_session session, sftp_message msg);
static void sftp_message_free(SFTP_MESSAGE *msg); static void sftp_message_free(sftp_message msg);
static void sftp_set_error(SFTP_SESSION *sftp, int errnum); static void sftp_set_error(sftp_session sftp, int errnum);
static void status_msg_free(STATUS_MESSAGE *status); 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);
SFTP_SESSION *sftp_new(SSH_SESSION *session){ return ext;
SFTP_SESSION *sftp; }
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;
enter_function(); enter_function();
if (session == NULL) { if (session == NULL) {
leave_function(); leave_function();
return NULL; return NULL;
} }
sftp = malloc(sizeof(SFTP_SESSION)); sftp = malloc(sizeof(struct sftp_session_struct));
if (sftp == NULL) { if (sftp == NULL) {
ssh_set_error_oom(session);
leave_function(); leave_function();
return NULL; return NULL;
} }
memset(sftp,0,sizeof(SFTP_SESSION)); ZERO_STRUCTP(sftp);
sftp->ext = sftp_ext_new();
if (sftp->ext == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(sftp);
sftp_leave_function();
return NULL;
}
sftp->session = session; sftp->session = session;
sftp->channel = channel_new(session); sftp->channel = channel_new(session);
if (sftp->channel == NULL) { if (sftp->channel == NULL) {
SAFE_FREE(sftp); SAFE_FREE(sftp);
leave_function(); leave_function();
return NULL; return NULL;
} }
if (channel_open_session(sftp->channel)) { if (channel_open_session(sftp->channel)) {
skipping to change at line 96 skipping to change at line 154
sftp_free(sftp); sftp_free(sftp);
leave_function(); leave_function();
return NULL; return NULL;
} }
leave_function(); leave_function();
return sftp; return sftp;
} }
#ifdef WITH_SERVER #ifdef WITH_SERVER
SFTP_SESSION *sftp_server_new(SSH_SESSION *session, CHANNEL *chan){ sftp_session sftp_server_new(ssh_session session, ssh_channel chan){
SFTP_SESSION *sftp = NULL; sftp_session sftp = NULL;
sftp = malloc(sizeof(SFTP_SESSION)); sftp = malloc(sizeof(struct sftp_session_struct));
if (sftp == NULL) { if (sftp == NULL) {
ssh_set_error_oom(session);
return NULL; return NULL;
} }
ZERO_STRUCTP(sftp); ZERO_STRUCTP(sftp);
sftp->session = session; sftp->session = session;
sftp->channel = chan; sftp->channel = chan;
return sftp; return sftp;
} }
int sftp_server_init(SFTP_SESSION *sftp){ int sftp_server_init(sftp_session sftp){
struct ssh_session *session = sftp->session; ssh_session session = sftp->session;
SFTP_PACKET *packet = NULL; sftp_packet packet = NULL;
BUFFER *reply = NULL; ssh_buffer reply = NULL;
u32 version; uint32_t version;
sftp_enter_function(); sftp_enter_function();
packet = sftp_packet_read(sftp); packet = sftp_packet_read(sftp);
if (packet == NULL) { if (packet == NULL) {
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
if (packet->type != SSH_FXP_INIT) { if (packet->type != SSH_FXP_INIT) {
skipping to change at line 146 skipping to change at line 205
buffer_get_u32(packet->payload, &version); buffer_get_u32(packet->payload, &version);
version = ntohl(version); version = ntohl(version);
ssh_log(session, SSH_LOG_PACKET, "Client version: %d", version); ssh_log(session, SSH_LOG_PACKET, "Client version: %d", version);
sftp->client_version = version; sftp->client_version = version;
sftp_packet_free(packet); sftp_packet_free(packet);
reply = buffer_new(); reply = buffer_new();
if (reply == NULL) { if (reply == NULL) {
ssh_set_error_oom(session);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) { if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) {
ssh_set_error_oom(session);
buffer_free(reply); buffer_free(reply);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) { if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
buffer_free(reply); buffer_free(reply);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
skipping to change at line 176 skipping to change at line 237
sftp->version = LIBSFTP_VERSION; sftp->version = LIBSFTP_VERSION;
} else { } else {
sftp->version=version; sftp->version=version;
} }
sftp_leave_function(); sftp_leave_function();
return 0; return 0;
} }
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */
void sftp_free(SFTP_SESSION *sftp){ void sftp_free(sftp_session sftp){
struct request_queue *ptr; sftp_request_queue ptr;
if (sftp == NULL) { if (sftp == NULL) {
return; return;
} }
channel_send_eof(sftp->channel); channel_send_eof(sftp->channel);
ptr = sftp->queue; ptr = sftp->queue;
while(ptr) { while(ptr) {
struct request_queue *old; sftp_request_queue old;
sftp_message_free(ptr->message); sftp_message_free(ptr->message);
old = ptr->next; old = ptr->next;
SAFE_FREE(ptr); SAFE_FREE(ptr);
ptr = old; ptr = old;
} }
channel_free(sftp->channel); channel_free(sftp->channel);
memset(sftp, 0, sizeof(*sftp)); sftp_ext_free(sftp->ext);
ZERO_STRUCTP(sftp);
SAFE_FREE(sftp); SAFE_FREE(sftp);
} }
int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload){ int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
int size; int size;
if (buffer_prepend_data(payload, &type, sizeof(u8)) < 0) { if (buffer_prepend_data(payload, &type, sizeof(uint8_t)) < 0) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
size = htonl(buffer_get_len(payload)); size = htonl(buffer_get_len(payload));
if (buffer_prepend_data(payload, &size, sizeof(u32)) < 0) { if (buffer_prepend_data(payload, &size, sizeof(uint32_t)) < 0) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
size = channel_write(sftp->channel, buffer_get(payload), size = channel_write(sftp->channel, buffer_get(payload),
buffer_get_len(payload)); buffer_get_len(payload));
if (size < 0) { if (size < 0) {
return -1; return -1;
} else if((u32) size != buffer_get_len(payload)) { } else if((uint32_t) size != buffer_get_len(payload)) {
ssh_log(sftp->session, SSH_LOG_PACKET, ssh_log(sftp->session, SSH_LOG_PACKET,
"Had to write %d bytes, wrote only %d", "Had to write %d bytes, wrote only %d",
buffer_get_len(payload), buffer_get_len(payload),
size); size);
} }
return size; return size;
} }
SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) { sftp_packet sftp_packet_read(sftp_session sftp) {
SFTP_PACKET *packet = NULL; sftp_packet packet = NULL;
u32 size; uint32_t size;
sftp_enter_function(); sftp_enter_function();
packet = malloc(sizeof(SFTP_PACKET)); packet = malloc(sizeof(struct sftp_packet_struct));
if (packet == NULL) { if (packet == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
packet->sftp = sftp; packet->sftp = sftp;
packet->payload = buffer_new(); packet->payload = buffer_new();
if (packet->payload == NULL) { if (packet->payload == NULL) {
ssh_set_error_oom(sftp->session);
SAFE_FREE(packet); SAFE_FREE(packet);
return NULL; return NULL;
} }
if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) { if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
buffer_free(packet->payload); buffer_free(packet->payload);
SAFE_FREE(packet); SAFE_FREE(packet);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
if (buffer_get_u32(packet->payload, &size) < 0) { if (buffer_get_u32(packet->payload, &size) != sizeof(uint32_t)) {
ssh_set_error(sftp->session, SSH_FATAL, "Short sftp packet!");
buffer_free(packet->payload); buffer_free(packet->payload);
SAFE_FREE(packet); SAFE_FREE(packet);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
size = ntohl(size); size = ntohl(size);
if (channel_read_buffer(sftp->channel, packet->payload, 1, 0) <= 0) { 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 * /
buffer_free(packet->payload); buffer_free(packet->payload);
SAFE_FREE(packet); SAFE_FREE(packet);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
buffer_get_u8(packet->payload, &packet->type); buffer_get_u8(packet->payload, &packet->type);
if (size > 1) { if (size > 1) {
if (channel_read_buffer(sftp->channel, packet->payload, size - 1, 0) <= 0) { 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 */
buffer_free(packet->payload); buffer_free(packet->payload);
SAFE_FREE(packet); SAFE_FREE(packet);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
} }
sftp_leave_function(); sftp_leave_function();
return packet; return packet;
} }
static void sftp_set_error(SFTP_SESSION *sftp, int errnum) { static void sftp_set_error(sftp_session sftp, int errnum) {
if (sftp != NULL) { if (sftp != NULL) {
sftp->errnum = errnum; sftp->errnum = errnum;
} }
} }
/* Get the last sftp error */ /* Get the last sftp error */
int sftp_get_error(SFTP_SESSION *sftp) { int sftp_get_error(sftp_session sftp) {
if (sftp == NULL) { if (sftp == NULL) {
return -1; return -1;
} }
return sftp->errnum; return sftp->errnum;
} }
static SFTP_MESSAGE *sftp_message_new(SFTP_SESSION *sftp){ static sftp_message sftp_message_new(sftp_session sftp){
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
sftp_enter_function(); sftp_enter_function();
msg = malloc(sizeof(SFTP_MESSAGE)); msg = malloc(sizeof(struct sftp_message_struct));
if (msg == NULL) { if (msg == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(msg); ZERO_STRUCTP(msg);
msg->payload = buffer_new(); msg->payload = buffer_new();
if (msg->payload == NULL) { if (msg->payload == NULL) {
ssh_set_error_oom(sftp->session);
SAFE_FREE(msg); SAFE_FREE(msg);
return NULL; return NULL;
} }
msg->sftp = sftp; msg->sftp = sftp;
sftp_leave_function(); sftp_leave_function();
return msg; return msg;
} }
static void sftp_message_free(SFTP_MESSAGE *msg) { static void sftp_message_free(sftp_message msg) {
SFTP_SESSION *sftp; sftp_session sftp;
if (msg == NULL) { if (msg == NULL) {
return; return;
} }
sftp = msg->sftp; sftp = msg->sftp;
sftp_enter_function(); sftp_enter_function();
buffer_free(msg->payload); buffer_free(msg->payload);
SAFE_FREE(msg); SAFE_FREE(msg);
sftp_leave_function(); sftp_leave_function();
} }
static SFTP_MESSAGE *sftp_get_message(SFTP_PACKET *packet) { static sftp_message sftp_get_message(sftp_packet packet) {
SFTP_SESSION *sftp = packet->sftp; sftp_session sftp = packet->sftp;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
sftp_enter_function(); sftp_enter_function();
msg = sftp_message_new(sftp); msg = sftp_message_new(sftp);
if (msg == NULL) { if (msg == NULL) {
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
msg->sftp = packet->sftp; msg->sftp = packet->sftp;
msg->packet_type = packet->type; msg->packet_type = packet->type;
if ((packet->type != SSH_FXP_STATUS) && (packet->type!=SSH_FXP_HANDLE) && 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_DATA) && (packet->type != SSH_FXP_ATTRS) &&
(packet->type != SSH_FXP_NAME)) { (packet->type != SSH_FXP_NAME) && (packet->type != SSH_FXP_EXTENDED_R EPLY)) {
ssh_set_error(packet->sftp->session, SSH_FATAL, ssh_set_error(packet->sftp->session, SSH_FATAL,
"Unknown packet type %d", packet->type); "Unknown packet type %d", packet->type);
sftp_message_free(msg); sftp_message_free(msg);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
if (buffer_get_u32(packet->payload, &msg->id) != sizeof(u32)) { if (buffer_get_u32(packet->payload, &msg->id) != sizeof(uint32_t)) {
ssh_set_error(packet->sftp->session, SSH_FATAL, ssh_set_error(packet->sftp->session, SSH_FATAL,
"Invalid packet %d: no ID", packet->type); "Invalid packet %d: no ID", packet->type);
sftp_message_free(msg); sftp_message_free(msg);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
ssh_log(packet->sftp->session, SSH_LOG_PACKET, ssh_log(packet->sftp->session, SSH_LOG_PACKET,
"Packet with id %d type %d", "Packet with id %d type %d",
msg->id, msg->id,
msg->packet_type); msg->packet_type);
if (buffer_add_data(msg->payload, buffer_get_rest(packet->payload), if (buffer_add_data(msg->payload, buffer_get_rest(packet->payload),
buffer_get_rest_len(packet->payload)) < 0) { buffer_get_rest_len(packet->payload)) < 0) {
ssh_set_error_oom(sftp->session);
sftp_message_free(msg); sftp_message_free(msg);
sftp_leave_function(); sftp_leave_function();
return NULL; return NULL;
} }
sftp_leave_function(); sftp_leave_function();
return msg; return msg;
} }
static int sftp_read_and_dispatch(SFTP_SESSION *sftp) { static int sftp_read_and_dispatch(sftp_session sftp) {
SFTP_PACKET *packet = NULL; sftp_packet packet = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
sftp_enter_function(); sftp_enter_function();
packet = sftp_packet_read(sftp); packet = sftp_packet_read(sftp);
if (packet == NULL) { if (packet == NULL) {
sftp_leave_function(); sftp_leave_function();
return -1; /* something nasty happened reading the packet */ return -1; /* something nasty happened reading the packet */
} }
msg = sftp_get_message(packet); msg = sftp_get_message(packet);
skipping to change at line 409 skipping to change at line 481
if (sftp_enqueue(sftp, msg) < 0) { if (sftp_enqueue(sftp, msg) < 0) {
sftp_message_free(msg); sftp_message_free(msg);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
sftp_leave_function(); sftp_leave_function();
return 0; return 0;
} }
void sftp_packet_free(SFTP_PACKET *packet) { void sftp_packet_free(sftp_packet packet) {
if (packet == NULL) { if (packet == NULL) {
return; return;
} }
buffer_free(packet->payload); buffer_free(packet->payload);
free(packet); free(packet);
} }
/* Initialize the sftp session with the server. */ /* Initialize the sftp session with the server. */
int sftp_init(SFTP_SESSION *sftp) { int sftp_init(sftp_session sftp) {
SFTP_PACKET *packet = NULL; sftp_packet packet = NULL;
BUFFER *buffer = NULL; ssh_buffer buffer = NULL;
STRING *ext_name_s = NULL; ssh_string ext_name_s = NULL;
STRING *ext_data_s = NULL; ssh_string ext_data_s = NULL;
char *ext_name = NULL; char *ext_name = NULL;
char *ext_data = NULL; char *ext_data = NULL;
u32 version = htonl(LIBSFTP_VERSION); uint32_t version = htonl(LIBSFTP_VERSION);
sftp_enter_function(); sftp_enter_function();
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
if ((buffer_add_u32(buffer, version) < 0) || if (buffer_add_u32(buffer, version) < 0) {
sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
sftp_leave_function();
return -1;
}
if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
packet = sftp_packet_read(sftp); packet = sftp_packet_read(sftp);
if (packet == NULL) { if (packet == NULL) {
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
if (packet->type != SSH_FXP_VERSION) { if (packet->type != SSH_FXP_VERSION) {
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received a %d messages instead of SSH_FXP_VERSION", packet->type); "Received a %d messages instead of SSH_FXP_VERSION", packet->type);
sftp_packet_free(packet); sftp_packet_free(packet);
sftp_leave_function(); sftp_leave_function();
return -1; return -1;
} }
buffer_get_u32(packet->payload,&version); /* TODO: are we sure there are 4 bytes ready? */
buffer_get_u32(packet->payload, &version);
version = ntohl(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); ext_name_s = buffer_get_ssh_string(packet->payload);
ext_data_s = buffer_get_ssh_string(packet->payload); while (ext_name_s != NULL) {
if (ext_name_s == NULL || (ext_data_s == NULL)) { int count = sftp->ext->count;
string_free(ext_name_s); char **tmp;
string_free(ext_data_s);
ssh_log(sftp->session, SSH_LOG_RARE, ext_data_s = buffer_get_ssh_string(packet->payload);
"SFTP server version %d", version); if (ext_data_s == NULL) {
} else { string_free(ext_name_s);
break;
}
ext_name = string_to_char(ext_name_s); ext_name = string_to_char(ext_name_s);
ext_data = string_to_char(ext_data_s); ext_data = 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);
string_free(ext_name_s);
string_free(ext_data_s);
return -1;
}
ssh_log(sftp->session, SSH_LOG_RARE,
"SFTP server extension: %s, version: %s",
ext_name, ext_data);
if (ext_name != NULL || ext_data != NULL) { count++;
ssh_log(sftp->session, SSH_LOG_RARE, tmp = realloc(sftp->ext->name, count * sizeof(char *));
"SFTP server version %d (%s,%s)", if (tmp == NULL) {
version, ext_name, ext_data); ssh_set_error_oom(sftp->session);
} else { SAFE_FREE(ext_name);
ssh_log(sftp->session, SSH_LOG_RARE, SAFE_FREE(ext_data);
"SFTP server version %d", version); string_free(ext_name_s);
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);
string_free(ext_name_s);
string_free(ext_data_s);
return -1;
} }
SAFE_FREE(ext_name); tmp[count - 1] = ext_data;
SAFE_FREE(ext_data); sftp->ext->data = tmp;
sftp->ext->count = count;
string_free(ext_name_s);
string_free(ext_data_s);
ext_name_s = buffer_get_ssh_string(packet->payload);
} }
string_free(ext_name_s);
string_free(ext_data_s);
sftp_packet_free(packet); sftp_packet_free(packet);
sftp->version = sftp->server_version = version; sftp->version = sftp->server_version = version;
sftp_leave_function(); sftp_leave_function();
return 0; return 0;
} }
static REQUEST_QUEUE *request_queue_new(SFTP_MESSAGE *msg) { unsigned int sftp_extensions_get_count(sftp_session sftp) {
REQUEST_QUEUE *queue = NULL; if (sftp == NULL || sftp->ext == NULL) {
return 0;
}
return sftp->ext->count;
}
queue = malloc(sizeof(REQUEST_QUEUE)); 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) { if (queue == NULL) {
ssh_set_error_oom(msg->sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(queue); ZERO_STRUCTP(queue);
queue->message = msg; queue->message = msg;
return queue; return queue;
} }
static void request_queue_free(REQUEST_QUEUE *queue) { static void request_queue_free(sftp_request_queue queue) {
if (queue == NULL) { if (queue == NULL) {
return; return;
} }
ZERO_STRUCTP(queue); ZERO_STRUCTP(queue);
SAFE_FREE(queue); SAFE_FREE(queue);
} }
static int sftp_enqueue(SFTP_SESSION *sftp, SFTP_MESSAGE *msg) { static int sftp_enqueue(sftp_session sftp, sftp_message msg) {
REQUEST_QUEUE *queue = NULL; sftp_request_queue queue = NULL;
REQUEST_QUEUE *ptr; sftp_request_queue ptr;
queue = request_queue_new(msg); queue = request_queue_new(msg);
if (queue == NULL) { if (queue == NULL) {
return -1; return -1;
} }
ssh_log(sftp->session, SSH_LOG_PACKET, ssh_log(sftp->session, SSH_LOG_PACKET,
"Queued msg type %d id %d", "Queued msg type %d id %d",
msg->id, msg->packet_type); msg->id, msg->packet_type);
skipping to change at line 547 skipping to change at line 719
ptr->next = queue; /* add it on bottom */ ptr->next = queue; /* add it on bottom */
} }
return 0; return 0;
} }
/* /*
* Pulls of a message from the queue based on the ID. * Pulls of a message from the queue based on the ID.
* Returns NULL if no message has been found. * Returns NULL if no message has been found.
*/ */
static SFTP_MESSAGE *sftp_dequeue(SFTP_SESSION *sftp, u32 id){ static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){
REQUEST_QUEUE *prev = NULL; sftp_request_queue prev = NULL;
REQUEST_QUEUE *queue; sftp_request_queue queue;
SFTP_MESSAGE *msg; sftp_message msg;
if(sftp->queue == NULL) { if(sftp->queue == NULL) {
return NULL; return NULL;
} }
queue = sftp->queue; queue = sftp->queue;
while (queue) { while (queue) {
if(queue->message->id == id) { if(queue->message->id == id) {
/* remove from queue */ /* remove from queue */
if (prev == NULL) { if (prev == NULL) {
skipping to change at line 585 skipping to change at line 757
} }
return NULL; return NULL;
} }
/* /*
* Assigns a new SFTP ID for new requests and assures there is no collision * Assigns a new SFTP ID for new requests and assures there is no collision
* between them. * between them.
* Returns a new ID ready to use in a request * Returns a new ID ready to use in a request
*/ */
static inline u32 sftp_get_new_id(SFTP_SESSION *session) { static inline uint32_t sftp_get_new_id(sftp_session session) {
return ++session->id_counter; return ++session->id_counter;
} }
static STATUS_MESSAGE *parse_status_msg(SFTP_MESSAGE *msg){ static sftp_status_message parse_status_msg(sftp_message msg){
STATUS_MESSAGE *status; sftp_status_message status;
if (msg->packet_type != SSH_FXP_STATUS) { if (msg->packet_type != SSH_FXP_STATUS) {
ssh_set_error(msg->sftp->session, SSH_FATAL, ssh_set_error(msg->sftp->session, SSH_FATAL,
"Not a ssh_fxp_status message passed in!"); "Not a ssh_fxp_status message passed in!");
return NULL; return NULL;
} }
status = malloc(sizeof(STATUS_MESSAGE)); status = malloc(sizeof(struct sftp_status_message_struct));
if (status == NULL) { if (status == NULL) {
ssh_set_error_oom(msg->sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(status); ZERO_STRUCTP(status);
status->id = msg->id; status->id = msg->id;
if ((buffer_get_u32(msg->payload,&status->status) != 4) || if (buffer_get_u32(msg->payload,&status->status) != 4){
(status->error = buffer_get_ssh_string(msg->payload)) == NULL ||
(status->lang = buffer_get_ssh_string(msg->payload)) == NULL) {
string_free(status->error);
/* status->lang never get allocated if something failed */
SAFE_FREE(status); SAFE_FREE(status);
ssh_set_error(msg->sftp->session, SSH_FATAL, ssh_set_error(msg->sftp->session, SSH_FATAL,
"Invalid SSH_FXP_STATUS message"); "Invalid SSH_FXP_STATUS message");
return NULL; 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 */
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); status->status = ntohl(status->status);
status->errormsg = string_to_char(status->error); if(status->error)
status->langmsg = string_to_char(status->lang); status->errormsg = string_to_char(status->error);
else
status->errormsg = strdup("No error message in packet");
if(status->lang)
status->langmsg = string_to_char(status->lang);
else
status->langmsg = strdup("");
if (status->errormsg == NULL || status->langmsg == NULL) { if (status->errormsg == NULL || status->langmsg == NULL) {
ssh_set_error_oom(msg->sftp->session);
status_msg_free(status); status_msg_free(status);
return NULL; return NULL;
} }
return status; return status;
} }
static void status_msg_free(STATUS_MESSAGE *status){ static void status_msg_free(sftp_status_message status){
if (status == NULL) { if (status == NULL) {
return; return;
} }
string_free(status->error); string_free(status->error);
string_free(status->lang); string_free(status->lang);
SAFE_FREE(status->errormsg); SAFE_FREE(status->errormsg);
SAFE_FREE(status->langmsg); SAFE_FREE(status->langmsg);
SAFE_FREE(status); SAFE_FREE(status);
} }
static SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){ static sftp_file parse_handle_msg(sftp_message msg){
SFTP_FILE *file; sftp_file file;
if(msg->packet_type != SSH_FXP_HANDLE) { if(msg->packet_type != SSH_FXP_HANDLE) {
ssh_set_error(msg->sftp->session, SSH_FATAL, ssh_set_error(msg->sftp->session, SSH_FATAL,
"Not a ssh_fxp_handle message passed in!"); "Not a ssh_fxp_handle message passed in!");
return NULL; return NULL;
} }
file = malloc(sizeof(SFTP_FILE)); file = malloc(sizeof(struct sftp_file_struct));
if (file == NULL) { if (file == NULL) {
ssh_set_error_oom(msg->sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(file); ZERO_STRUCTP(file);
file->handle = buffer_get_ssh_string(msg->payload); file->handle = buffer_get_ssh_string(msg->payload);
if (file->handle == NULL) { if (file->handle == NULL) {
ssh_set_error(msg->sftp->session, SSH_FATAL, ssh_set_error(msg->sftp->session, SSH_FATAL,
"Invalid SSH_FXP_HANDLE message"); "Invalid SSH_FXP_HANDLE message");
SAFE_FREE(file); SAFE_FREE(file);
return NULL; return NULL;
} }
file->sftp = msg->sftp; file->sftp = msg->sftp;
file->offset = 0; file->offset = 0;
file->eof = 0; file->eof = 0;
return file; return file;
} }
/* Open a directory */ /* Open a directory */
SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, const char *path){ sftp_dir sftp_opendir(sftp_session sftp, const char *path){
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
SFTP_FILE *file = NULL; sftp_file file = NULL;
SFTP_DIR *dir = NULL; sftp_dir dir = NULL;
STATUS_MESSAGE *status; sftp_status_message status;
STRING *path_s; ssh_string path_s;
BUFFER *payload; ssh_buffer payload;
u32 id; uint32_t id;
payload = buffer_new(); payload = buffer_new();
if (payload == NULL) { if (payload == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
path_s = string_from_char(path); path_s = string_from_char(path);
if (path_s == NULL) { if (path_s == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(payload); buffer_free(payload);
return NULL; return NULL;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(payload, id) < 0 || if (buffer_add_u32(payload, id) < 0 ||
buffer_add_ssh_string(payload, path_s) < 0) { buffer_add_ssh_string(payload, path_s) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(payload); buffer_free(payload);
string_free(path_s); string_free(path_s);
return NULL; return NULL;
} }
string_free(path_s); string_free(path_s);
if (sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload) < 0) { if (sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload) < 0) {
buffer_free(payload); buffer_free(payload);
return NULL; return NULL;
} }
skipping to change at line 729 skipping to change at line 922
} }
sftp_set_error(sftp, status->status); sftp_set_error(sftp, status->status);
ssh_set_error(sftp->session, SSH_REQUEST_DENIED, ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
"SFTP server: %s", status->errormsg); "SFTP server: %s", status->errormsg);
status_msg_free(status); status_msg_free(status);
return NULL; return NULL;
case SSH_FXP_HANDLE: case SSH_FXP_HANDLE:
file = parse_handle_msg(msg); file = parse_handle_msg(msg);
sftp_message_free(msg); sftp_message_free(msg);
if (file != NULL) { if (file != NULL) {
dir = malloc(sizeof(SFTP_DIR)); dir = malloc(sizeof(struct sftp_dir_struct));
if (dir == NULL) { if (dir == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(dir); ZERO_STRUCTP(dir);
dir->sftp = sftp; dir->sftp = sftp;
dir->name = strdup(path); dir->name = strdup(path);
if (dir->name == NULL) { if (dir->name == NULL) {
SAFE_FREE(dir); SAFE_FREE(dir);
SAFE_FREE(file); SAFE_FREE(file);
return NULL; return NULL;
skipping to change at line 760 skipping to change at line 954
} }
return NULL; return NULL;
} }
/* /*
* Parse the attributes from a payload from some messages. It is coded on * Parse the attributes from a payload from some messages. It is coded on
* baselines from the protocol version 4. * baselines from the protocol version 4.
* This code is more or less dead but maybe we need it in future. * This code is more or less dead but maybe we need it in future.
*/ */
static SFTP_ATTRIBUTES *sftp_parse_attr_4(SFTP_SESSION *sftp, BUFFER *buf, static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
int expectnames) { int expectnames) {
SFTP_ATTRIBUTES *attr; sftp_attributes attr;
STRING *owner = NULL; ssh_string owner = NULL;
STRING *group = NULL; ssh_string group = NULL;
u32 flags = 0; uint32_t flags = 0;
int ok = 0; int ok = 0;
/* unused member variable */ /* unused member variable */
(void) expectnames; (void) expectnames;
attr = malloc(sizeof(SFTP_ATTRIBUTES)); attr = malloc(sizeof(struct sftp_attributes_struct));
if (attr == NULL) { if (attr == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(attr); ZERO_STRUCTP(attr);
/* This isn't really a loop, but it is like a try..catch.. */ /* This isn't really a loop, but it is like a try..catch.. */
do { do {
if (buffer_get_u32(buf, &flags) != 4) { if (buffer_get_u32(buf, &flags) != 4) {
break; break;
} }
skipping to change at line 810 skipping to change at line 1005
break; break;
} }
} }
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) { if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
if (buffer_get_u32(buf, &attr->permissions) != 4) { if (buffer_get_u32(buf, &attr->permissions) != 4) {
break; break;
} }
attr->permissions = ntohl(attr->permissions); attr->permissions = ntohl(attr->permissions);
#ifndef _WIN32
/* FIXME on windows! */ /* FIXME on windows! */
switch (attr->permissions & S_IFMT) { switch (attr->permissions & S_IFMT) {
case S_IFSOCK: case S_IFSOCK:
case S_IFBLK: case S_IFBLK:
case S_IFCHR: case S_IFCHR:
case S_IFIFO: case S_IFIFO:
attr->type = SSH_FILEXFER_TYPE_SPECIAL; attr->type = SSH_FILEXFER_TYPE_SPECIAL;
break; break;
case S_IFLNK: case S_IFLNK:
attr->type = SSH_FILEXFER_TYPE_SYMLINK; attr->type = SSH_FILEXFER_TYPE_SYMLINK;
skipping to change at line 832 skipping to change at line 1026
case S_IFREG: case S_IFREG:
attr->type = SSH_FILEXFER_TYPE_REGULAR; attr->type = SSH_FILEXFER_TYPE_REGULAR;
break; break;
case S_IFDIR: case S_IFDIR:
attr->type = SSH_FILEXFER_TYPE_DIRECTORY; attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
break; break;
default: default:
attr->type = SSH_FILEXFER_TYPE_UNKNOWN; attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
break; break;
} }
#endif /* _WIN32 */
} }
if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) { if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
if (buffer_get_u64(buf, &attr->atime64) != 8) { if (buffer_get_u64(buf, &attr->atime64) != 8) {
break; break;
} }
attr->atime64 = ntohll(attr->atime64); attr->atime64 = ntohll(attr->atime64);
} }
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) { if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
skipping to change at line 921 skipping to change at line 1114
SAFE_FREE(attr); SAFE_FREE(attr);
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure"); ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
return NULL; return NULL;
} }
return attr; return attr;
} }
/* Version 3 code. it is the only one really supported (the draft for the 4 misses clarifications) */ /* sftp version 0-3 code. It is different from the v4 */
/* maybe a paste of the draft is better than the code */ /* maybe a paste of the draft is better than the code */
/* /*
uint32 flags uint32 flags
uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDG ID uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDG ID
uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDG ID uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDG ID
uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERM ISSIONS uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERM ISSIONS
uint32 atime present only if flag SSH_FILEXFER_ACMODTIME uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
uint32 mtime 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_EXTE NDED uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTE NDED
string extended_type string extended_type
string extended_data string extended_data
... more extended data (extended_type - extended_data pairs), ... more extended data (extended_type - extended_data pairs),
so that number of pairs equals extended_count */ so that number of pairs equals extended_count */
static SFTP_ATTRIBUTES *sftp_parse_attr_3(SFTP_SESSION *sftp, BUFFER *buf, static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
int expectname) { int expectname) {
STRING *longname = NULL; ssh_string longname = NULL;
STRING *name = NULL; ssh_string name = NULL;
SFTP_ATTRIBUTES *attr; sftp_attributes attr;
u32 flags = 0; uint32_t flags = 0;
int ok = 0; int ok = 0;
attr = malloc(sizeof(SFTP_ATTRIBUTES)); attr = malloc(sizeof(struct sftp_attributes_struct));
if (attr == NULL) { if (attr == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
ZERO_STRUCTP(attr); ZERO_STRUCTP(attr);
/* This isn't really a loop, but it is like a try..catch.. */ /* This isn't really a loop, but it is like a try..catch.. */
do { do {
if (expectname) { if (expectname) {
if ((name = buffer_get_ssh_string(buf)) == NULL || if ((name = buffer_get_ssh_string(buf)) == NULL ||
(attr->name = string_to_char(name)) == NULL) { (attr->name = string_to_char(name)) == NULL) {
break; break;
skipping to change at line 968 skipping to change at line 1162
ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name); ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
if ((longname=buffer_get_ssh_string(buf)) == NULL || if ((longname=buffer_get_ssh_string(buf)) == NULL ||
(attr->longname=string_to_char(longname)) == NULL) { (attr->longname=string_to_char(longname)) == NULL) {
break; break;
} }
string_free(longname); string_free(longname);
} }
if (buffer_get_u32(buf, &flags) != sizeof(u32)) { if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
break; break;
} }
flags = ntohl(flags); flags = ntohl(flags);
attr->flags = flags; attr->flags = flags;
ssh_log(sftp->session, SSH_LOG_RARE, ssh_log(sftp->session, SSH_LOG_RARE,
"Flags: %.8lx\n", (long unsigned int) flags); "Flags: %.8lx\n", (long unsigned int) flags);
if (flags & SSH_FILEXFER_ATTR_SIZE) { if (flags & SSH_FILEXFER_ATTR_SIZE) {
if(buffer_get_u64(buf, &attr->size) != sizeof(u64)) { if(buffer_get_u64(buf, &attr->size) != sizeof(uint64_t)) {
break; break;
} }
attr->size = ntohll(attr->size); attr->size = ntohll(attr->size);
ssh_log(sftp->session, SSH_LOG_RARE, ssh_log(sftp->session, SSH_LOG_RARE,
"Size: %llu\n", "Size: %llu\n",
(long long unsigned int) attr->size); (long long unsigned int) attr->size);
} }
if (flags & SSH_FILEXFER_ATTR_UIDGID) { if (flags & SSH_FILEXFER_ATTR_UIDGID) {
if (buffer_get_u32(buf, &attr->uid) != sizeof(u32)) { if (buffer_get_u32(buf, &attr->uid) != sizeof(uint32_t)) {
break; break;
} }
if (buffer_get_u32(buf, &attr->gid) != sizeof(u32)) { if (buffer_get_u32(buf, &attr->gid) != sizeof(uint32_t)) {
break; break;
} }
attr->uid = ntohl(attr->uid); attr->uid = ntohl(attr->uid);
attr->gid = ntohl(attr->gid); attr->gid = ntohl(attr->gid);
} }
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) { if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
if (buffer_get_u32(buf, &attr->permissions) != sizeof(u32)) { if (buffer_get_u32(buf, &attr->permissions) != sizeof(uint32_t)) {
break; break;
} }
attr->permissions = ntohl(attr->permissions); attr->permissions = ntohl(attr->permissions);
#ifndef _WIN32
/* FIXME on windows */
switch (attr->permissions & S_IFMT) { switch (attr->permissions & S_IFMT) {
case S_IFSOCK: case S_IFSOCK:
case S_IFBLK: case S_IFBLK:
case S_IFCHR: case S_IFCHR:
case S_IFIFO: case S_IFIFO:
attr->type = SSH_FILEXFER_TYPE_SPECIAL; attr->type = SSH_FILEXFER_TYPE_SPECIAL;
break; break;
case S_IFLNK: case S_IFLNK:
attr->type = SSH_FILEXFER_TYPE_SYMLINK; attr->type = SSH_FILEXFER_TYPE_SYMLINK;
break; break;
case S_IFREG: case S_IFREG:
attr->type = SSH_FILEXFER_TYPE_REGULAR; attr->type = SSH_FILEXFER_TYPE_REGULAR;
break; break;
case S_IFDIR: case S_IFDIR:
attr->type = SSH_FILEXFER_TYPE_DIRECTORY; attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
break; break;
default: default:
attr->type = SSH_FILEXFER_TYPE_UNKNOWN; attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
break; break;
} }
#endif /* _WIN32 */
} }
if (flags & SSH_FILEXFER_ATTR_ACMODTIME) { if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
if (buffer_get_u32(buf, &attr->atime) != sizeof(u32)) { if (buffer_get_u32(buf, &attr->atime) != sizeof(uint32_t)) {
break; break;
} }
attr->atime = ntohl(attr->atime); attr->atime = ntohl(attr->atime);
if (buffer_get_u32(buf, &attr->mtime) != sizeof(u32)) { if (buffer_get_u32(buf, &attr->mtime) != sizeof(uint32_t)) {
break; break;
} }
attr->mtime = ntohl(attr->mtime); attr->mtime = ntohl(attr->mtime);
} }
if (flags & SSH_FILEXFER_ATTR_EXTENDED) { if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
if (buffer_get_u32(buf, &attr->extended_count) != sizeof(u32)) { if (buffer_get_u32(buf, &attr->extended_count) != sizeof(uint32_t)) {
break; break;
} }
attr->extended_count = ntohl(attr->extended_count); attr->extended_count = ntohl(attr->extended_count);
while (attr->extended_count && while (attr->extended_count &&
(attr->extended_type = buffer_get_ssh_string(buf)) (attr->extended_type = buffer_get_ssh_string(buf))
&& (attr->extended_data = buffer_get_ssh_string(buf))) { && (attr->extended_data = buffer_get_ssh_string(buf))) {
attr->extended_count--; attr->extended_count--;
} }
skipping to change at line 1078 skipping to change at line 1269
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure"); ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
return NULL; return NULL;
} }
/* everything went smoothly */ /* everything went smoothly */
return attr; return attr;
} }
/* FIXME is this really needed as a public function? */ /* FIXME is this really needed as a public function? */
int buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr) { int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr) {
u32 flags = (attr ? attr->flags : 0); uint32_t flags = (attr ? attr->flags : 0);
flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID |
SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME); SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
if (buffer_add_u32(buffer, htonl(flags)) < 0) { if (buffer_add_u32(buffer, htonl(flags)) < 0) {
return -1; return -1;
} }
if (attr) { if (attr) {
if (flags & SSH_FILEXFER_ATTR_SIZE) { if (flags & SSH_FILEXFER_ATTR_SIZE) {
skipping to change at line 1119 skipping to change at line 1310
if (buffer_add_u32(buffer, htonl(attr->atime)) < 0 || if (buffer_add_u32(buffer, htonl(attr->atime)) < 0 ||
buffer_add_u32(buffer, htonl(attr->mtime)) < 0) { buffer_add_u32(buffer, htonl(attr->mtime)) < 0) {
return -1; return -1;
} }
} }
} }
return 0; return 0;
} }
SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf, sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,
int expectname) { int expectname) {
switch(session->version) { switch(session->version) {
case 4: case 4:
return sftp_parse_attr_4(session, buf, expectname); return sftp_parse_attr_4(session, buf, expectname);
case 3: case 3:
case 2:
case 1:
case 0:
return sftp_parse_attr_3(session, buf, expectname); return sftp_parse_attr_3(session, buf, expectname);
default: default:
ssh_set_error(session->session, SSH_FATAL, ssh_set_error(session->session, SSH_FATAL,
"Version %d unsupported by client", session->server_version); "Version %d unsupported by client", session->server_version);
return NULL; return NULL;
} }
return NULL; return NULL;
} }
/* Get the version of the SFTP protocol supported by the server */ /* Get the version of the SFTP protocol supported by the server */
int sftp_server_version(SFTP_SESSION *sftp) { int sftp_server_version(sftp_session sftp) {
return sftp->server_version; return sftp->server_version;
} }
/* Get a single file attributes structure of a directory. */ /* Get a single file attributes structure of a directory. */
SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir) { sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) {
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STATUS_MESSAGE *status; sftp_status_message status;
SFTP_ATTRIBUTES *attr; sftp_attributes attr;
BUFFER *payload; ssh_buffer payload;
u32 id; uint32_t id;
if (dir->buffer == NULL) { if (dir->buffer == NULL) {
payload = buffer_new(); payload = buffer_new();
if (payload == NULL) { if (payload == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(payload, id) < 0 || if (buffer_add_u32(payload, id) < 0 ||
buffer_add_ssh_string(payload, dir->handle) < 0) { buffer_add_ssh_string(payload, dir->handle) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(payload); buffer_free(payload);
return NULL; return NULL;
} }
if (sftp_packet_write(sftp, SSH_FXP_READDIR, payload) < 0) { if (sftp_packet_write(sftp, SSH_FXP_READDIR, payload) < 0) {
buffer_free(payload); buffer_free(payload);
return NULL; return NULL;
} }
buffer_free(payload); buffer_free(payload);
skipping to change at line 1243 skipping to change at line 1439
dir->count--; dir->count--;
if (dir->count == 0) { if (dir->count == 0) {
buffer_free(dir->buffer); buffer_free(dir->buffer);
dir->buffer = NULL; dir->buffer = NULL;
} }
return attr; return attr;
} }
/* Tell if the directory has reached EOF (End Of File). */ /* Tell if the directory has reached EOF (End Of File). */
int sftp_dir_eof(SFTP_DIR *dir) { int sftp_dir_eof(sftp_dir dir) {
return dir->eof; return dir->eof;
} }
/* Free a SFTP_ATTRIBUTE handle */ /* Free a SFTP_ATTRIBUTE handle */
void sftp_attributes_free(SFTP_ATTRIBUTES *file){ void sftp_attributes_free(sftp_attributes file){
if (file == NULL) { if (file == NULL) {
return; return;
} }
string_free(file->acl); string_free(file->acl);
string_free(file->extended_data); string_free(file->extended_data);
string_free(file->extended_type); string_free(file->extended_type);
SAFE_FREE(file->name); SAFE_FREE(file->name);
SAFE_FREE(file->longname); SAFE_FREE(file->longname);
SAFE_FREE(file->group); SAFE_FREE(file->group);
SAFE_FREE(file->owner); SAFE_FREE(file->owner);
SAFE_FREE(file); SAFE_FREE(file);
} }
static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle) { static int sftp_handle_close(sftp_session sftp, ssh_string handle) {
STATUS_MESSAGE *status; sftp_status_message status;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
BUFFER *buffer = NULL; ssh_buffer buffer = NULL;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, handle) < 0 || buffer_add_ssh_string(buffer, handle) < 0) {
sftp_packet_write(sftp, SSH_FXP_CLOSE ,buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
return -1;
}
if (sftp_packet_write(sftp, SSH_FXP_CLOSE ,buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
/* something nasty has happened */ /* something nasty has happened */
return -1; return -1;
} }
skipping to change at line 1322 skipping to change at line 1523
return -1; return -1;
default: default:
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d during sftp_handle_close!", msg->packet_type ); "Received message %d during sftp_handle_close!", msg->packet_type );
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
int sftp_file_close(SFTP_FILE *file) {
return sftp_close(file);
}
/* Close an open file handle. */ /* Close an open file handle. */
int sftp_close(SFTP_FILE *file){ int sftp_close(sftp_file file){
int err = SSH_NO_ERROR; int err = SSH_NO_ERROR;
SAFE_FREE(file->name); SAFE_FREE(file->name);
if (file->handle){ if (file->handle){
err = sftp_handle_close(file->sftp,file->handle); err = sftp_handle_close(file->sftp,file->handle);
string_free(file->handle); string_free(file->handle);
} }
/* FIXME: check server response and implement errno */ /* FIXME: check server response and implement errno */
SAFE_FREE(file); SAFE_FREE(file);
return err; return err;
} }
int sftp_dir_close(SFTP_DIR *dir) {
return sftp_closedir(dir);
}
/* Close an open directory. */ /* Close an open directory. */
int sftp_closedir(SFTP_DIR *dir){ int sftp_closedir(sftp_dir dir){
int err = SSH_NO_ERROR; int err = SSH_NO_ERROR;
SAFE_FREE(dir->name); SAFE_FREE(dir->name);
if (dir->handle) { if (dir->handle) {
err = sftp_handle_close(dir->sftp, dir->handle); err = sftp_handle_close(dir->sftp, dir->handle);
string_free(dir->handle); string_free(dir->handle);
} }
/* FIXME: check server response and implement errno */ /* FIXME: check server response and implement errno */
buffer_free(dir->buffer); buffer_free(dir->buffer);
SAFE_FREE(dir); SAFE_FREE(dir);
return err; return err;
} }
/* Open a file on the server. */ /* Open a file on the server. */
SFTP_FILE *sftp_open(SFTP_SESSION *sftp, const char *file, int flags, sftp_file sftp_open(sftp_session sftp, const char *file, int flags,
mode_t mode) { mode_t mode) {
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STATUS_MESSAGE *status; sftp_status_message status;
SFTP_ATTRIBUTES attr; struct sftp_attributes_struct attr;
SFTP_FILE *handle; sftp_file handle;
STRING *filename; ssh_string filename;
BUFFER *buffer; ssh_buffer buffer;
u32 sftp_flags = 0; uint32_t sftp_flags = 0;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
filename = string_from_char(file); filename = string_from_char(file);
if (filename == NULL) { if (filename == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return NULL; return NULL;
} }
ZERO_STRUCT(attr); ZERO_STRUCT(attr);
attr.permissions = mode; attr.permissions = mode;
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
if (flags == O_RDONLY) if (flags == O_RDONLY)
sftp_flags |= SSH_FXF_READ; /* if any of the other flag is set, sftp_flags |= SSH_FXF_READ; /* if any of the other flag is set,
skipping to change at line 1401 skipping to change at line 1596
if (flags & O_WRONLY) if (flags & O_WRONLY)
sftp_flags |= SSH_FXF_WRITE; sftp_flags |= SSH_FXF_WRITE;
if (flags & O_RDWR) if (flags & O_RDWR)
sftp_flags |= (SSH_FXF_WRITE | SSH_FXF_READ); sftp_flags |= (SSH_FXF_WRITE | SSH_FXF_READ);
if (flags & O_CREAT) if (flags & O_CREAT)
sftp_flags |= SSH_FXF_CREAT; sftp_flags |= SSH_FXF_CREAT;
if (flags & O_TRUNC) if (flags & O_TRUNC)
sftp_flags |= SSH_FXF_TRUNC; sftp_flags |= SSH_FXF_TRUNC;
if (flags & O_EXCL) if (flags & O_EXCL)
sftp_flags |= SSH_FXF_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); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, filename) < 0) { buffer_add_ssh_string(buffer, filename) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
string_free(filename); string_free(filename);
return NULL; return NULL;
} }
string_free(filename); string_free(filename);
if (buffer_add_u32(buffer, htonl(sftp_flags)) < 0 || if (buffer_add_u32(buffer, htonl(sftp_flags)) < 0 ||
buffer_add_attributes(buffer, &attr) < 0 || buffer_add_attributes(buffer, &attr) < 0) {
sftp_packet_write(sftp, SSH_FXP_OPEN, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
return NULL;
}
if (sftp_packet_write(sftp, SSH_FXP_OPEN, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
return NULL; return NULL;
} }
buffer_free(buffer); buffer_free(buffer);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
/* something nasty has happened */ /* something nasty has happened */
return NULL; return NULL;
} }
skipping to change at line 1453 skipping to change at line 1653
return handle; return handle;
default: default:
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d during open!", msg->packet_type); "Received message %d during open!", msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
} }
return NULL; return NULL;
} }
void sftp_file_set_nonblocking(SFTP_FILE *handle){ void sftp_file_set_nonblocking(sftp_file handle){
handle->nonblocking=1; handle->nonblocking=1;
} }
void sftp_file_set_blocking(SFTP_FILE *handle){ void sftp_file_set_blocking(sftp_file handle){
handle->nonblocking=0; handle->nonblocking=0;
} }
/* Read from a file using an opened sftp file handle. */ /* Read from a file using an opened sftp file handle. */
ssize_t sftp_read(SFTP_FILE *handle, void *buf, size_t count) { ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
SFTP_SESSION *sftp = handle->sftp; sftp_session sftp = handle->sftp;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STATUS_MESSAGE *status; sftp_status_message status;
STRING *datastring; ssh_string datastring;
BUFFER *buffer; ssh_buffer buffer;
int id; int id;
if (handle->eof) { if (handle->eof) {
return 0; return 0;
} }
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
id = sftp_get_new_id(handle->sftp); id = sftp_get_new_id(handle->sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, handle->handle) < 0 || buffer_add_ssh_string(buffer, handle->handle) < 0 ||
buffer_add_u64(buffer, htonll(handle->offset)) < 0 || buffer_add_u64(buffer, htonll(handle->offset)) < 0 ||
buffer_add_u32(buffer,htonl(count)) < 0 || buffer_add_u32(buffer,htonl(count)) < 0) {
sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
return -1;
}
if (sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
while (msg == NULL) { while (msg == NULL) {
if (handle->nonblocking) { if (handle->nonblocking) {
if (channel_poll(handle->sftp->channel, 0) == 0) { if (channel_poll(handle->sftp->channel, 0) == 0) {
/* we cannot block */ /* we cannot block */
return 0; return 0;
skipping to change at line 1541 skipping to change at line 1746
if (string_len(datastring) > count) { if (string_len(datastring) > count) {
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received a too big DATA packet from sftp server: " "Received a too big DATA packet from sftp server: "
"%zu and asked for %zu", "%zu and asked for %zu",
string_len(datastring), count); string_len(datastring), count);
string_free(datastring); string_free(datastring);
return -1; return -1;
} }
count = string_len(datastring); count = string_len(datastring);
handle->offset += count; handle->offset += count;
memcpy(buf, datastring->string, count); memcpy(buf, string_data(datastring), count);
string_free(datastring); string_free(datastring);
return count; return count;
default: default:
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d during read!", msg->packet_type); "Received message %d during read!", msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
return -1; return -1;
} }
return -1; /* not reached */ return -1; /* not reached */
} }
/* Start an asynchronous read from a file using an opened sftp file handle. */ /* Start an asynchronous read from a file using an opened sftp file handle. */
int sftp_async_read_begin(SFTP_FILE *file, u32 len){ int sftp_async_read_begin(sftp_file file, uint32_t len){
SFTP_SESSION *sftp = file->sftp; sftp_session sftp = file->sftp;
BUFFER *buffer; ssh_buffer buffer;
u32 id; uint32_t id;
sftp_enter_function(); sftp_enter_function();
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0 || buffer_add_ssh_string(buffer, file->handle) < 0 ||
buffer_add_u64(buffer, htonll(file->offset)) < 0 || buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
buffer_add_u32(buffer, htonl(len)) < 0 || buffer_add_u32(buffer, htonl(len)) < 0) {
sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
return -1;
}
if (sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
file->offset += len; /* assume we'll read len bytes */ file->offset += len; /* assume we'll read len bytes */
sftp_leave_function(); sftp_leave_function();
return id; return id;
} }
/* Wait for an asynchronous read to complete and save the data. */ /* Wait for an asynchronous read to complete and save the data. */
int sftp_async_read(SFTP_FILE *file, void *data, u32 size, u32 id){ 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_session sftp = file->sftp;
STATUS_MESSAGE *status; sftp_message msg = NULL;
STRING *datastring; sftp_status_message status;
ssh_string datastring;
int err = SSH_OK; int err = SSH_OK;
u32 len; uint32_t len;
sftp_enter_function(); sftp_enter_function();
if (file->eof) { if (file->eof) {
sftp_leave_function(); sftp_leave_function();
return 0; return 0;
} }
/* handle an existing request */ /* handle an existing request */
while (msg == NULL) { while (msg == NULL) {
skipping to change at line 1660 skipping to change at line 1870
"%zu and asked for %u", "%zu and asked for %u",
string_len(datastring), size); string_len(datastring), size);
string_free(datastring); string_free(datastring);
sftp_leave_function(); sftp_leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
len = string_len(datastring); len = string_len(datastring);
//handle->offset+=len; //handle->offset+=len;
/* We already have set the offset previously. All we can do is warn t hat the expected len /* We already have set the offset previously. All we can do is warn t hat the expected len
* and effective lengths are different */ * and effective lengths are different */
memcpy(data, datastring->string, len); memcpy(data, string_data(datastring), len);
string_free(datastring); string_free(datastring);
sftp_leave_function(); sftp_leave_function();
return len; return len;
default: default:
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during rea d!",msg->packet_type); ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during rea d!",msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
sftp_leave_function(); sftp_leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
sftp_leave_function(); sftp_leave_function();
return SSH_ERROR; return SSH_ERROR;
} }
ssize_t sftp_write(SFTP_FILE *file, const void *buf, size_t count) { ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
SFTP_SESSION *sftp = file->sftp; sftp_session sftp = file->sftp;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STATUS_MESSAGE *status; sftp_status_message status;
STRING *datastring; ssh_string datastring;
BUFFER *buffer; ssh_buffer buffer;
u32 id; uint32_t id;
int len; int len;
int packetlen; int packetlen;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
datastring = string_new(count); datastring = string_new(count);
if (datastring == NULL) { if (datastring == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
string_fill(datastring, buf, count); string_fill(datastring, buf, count);
id = sftp_get_new_id(file->sftp); id = sftp_get_new_id(file->sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0 || buffer_add_ssh_string(buffer, file->handle) < 0 ||
buffer_add_u64(buffer, htonll(file->offset)) < 0 || buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
buffer_add_ssh_string(buffer, datastring) < 0) { buffer_add_ssh_string(buffer, datastring) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
string_free(datastring); string_free(datastring);
return -1; return -1;
} }
string_free(datastring); string_free(datastring);
len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer); len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer);
packetlen=buffer_get_len(buffer); packetlen=buffer_get_len(buffer);
buffer_free(buffer); buffer_free(buffer);
if (len < 0) { if (len < 0) {
return -1; return -1;
skipping to change at line 1757 skipping to change at line 1970
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d during write!", msg->packet_type); "Received message %d during write!", msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
return -1; return -1;
} }
return -1; /* not reached */ return -1; /* not reached */
} }
/* Seek to a specific location in a file. */ /* Seek to a specific location in a file. */
int sftp_seek(SFTP_FILE *file, u32 new_offset) { int sftp_seek(sftp_file file, uint32_t new_offset) {
if (file == NULL) { if (file == NULL) {
return -1; return -1;
} }
file->offset = new_offset; file->offset = new_offset;
return 0; return 0;
} }
int sftp_seek64(SFTP_FILE *file, u64 new_offset) { int sftp_seek64(sftp_file file, uint64_t new_offset) {
if (file == NULL) { if (file == NULL) {
return -1; return -1;
} }
file->offset = new_offset; file->offset = new_offset;
return 0; return 0;
} }
/* Report current byte position in file. */ /* Report current byte position in file. */
unsigned long sftp_tell(SFTP_FILE *file) { unsigned long sftp_tell(sftp_file file) {
return (unsigned long)file->offset; return (unsigned long)file->offset;
} }
/* Report current byte position in file. */ /* Report current byte position in file. */
u64 sftp_tell64(SFTP_FILE *file) { uint64_t sftp_tell64(sftp_file file) {
return (u64)file->offset; return (uint64_t) file->offset;
} }
/* Rewinds the position of the file pointer to the beginning of the file.*/ /* Rewinds the position of the file pointer to the beginning of the file.*/
void sftp_rewind(SFTP_FILE *file) { void sftp_rewind(sftp_file file) {
file->offset = 0; file->offset = 0;
} }
/* deprecated */
int sftp_rm(SFTP_SESSION *sftp, const char *file) {
return sftp_unlink(sftp, file);
}
/* code written by Nick */ /* code written by Nick */
int sftp_unlink(SFTP_SESSION *sftp, const char *file) { int sftp_unlink(sftp_session sftp, const char *file) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STRING *filename; ssh_string filename;
BUFFER *buffer; ssh_buffer buffer;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
filename = string_from_char(file); filename = string_from_char(file);
if (filename == NULL) { if (filename == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, filename) < 0 || buffer_add_ssh_string(buffer, filename) < 0) {
sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(filename);
}
if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(filename); string_free(filename);
} }
string_free(filename); string_free(filename);
buffer_free(buffer); buffer_free(buffer);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp)) { if (sftp_read_and_dispatch(sftp)) {
return -1; return -1;
} }
skipping to change at line 1866 skipping to change at line 2080
} else { } else {
ssh_set_error(sftp->session,SSH_FATAL, ssh_set_error(sftp->session,SSH_FATAL,
"Received message %d when attempting to remove file", msg->packet_t ype); "Received message %d when attempting to remove file", msg->packet_t ype);
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
/* code written by Nick */ /* code written by Nick */
int sftp_rmdir(SFTP_SESSION *sftp, const char *directory) { int sftp_rmdir(sftp_session sftp, const char *directory) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STRING *filename; ssh_string filename;
BUFFER *buffer; ssh_buffer buffer;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
filename = string_from_char(directory); filename = string_from_char(directory);
if (filename == NULL) { if (filename == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, filename) < 0 || buffer_add_ssh_string(buffer, filename) < 0) {
sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(filename);
return -1;
}
if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(filename); string_free(filename);
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
string_free(filename); string_free(filename);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
return -1; return -1;
skipping to change at line 1933 skipping to change at line 2154
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d when attempting to remove directory", "Received message %d when attempting to remove directory",
msg->packet_type); msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
/* Code written by Nick */ /* Code written by Nick */
int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, mode_t mode) { int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
SFTP_ATTRIBUTES *errno_attr = NULL; sftp_attributes errno_attr = NULL;
SFTP_ATTRIBUTES attr; struct sftp_attributes_struct attr;
BUFFER *buffer; ssh_buffer buffer;
STRING *path; ssh_string path;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
path = string_from_char(directory); path = string_from_char(directory);
if (path == NULL) { if (path == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
ZERO_STRUCT(attr); ZERO_STRUCT(attr);
attr.permissions = mode; attr.permissions = mode;
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
skipping to change at line 2022 skipping to change at line 2245
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d when attempting to make directory", "Received message %d when attempting to make directory",
msg->packet_type); msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
/* code written by nick */ /* code written by nick */
int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newna int sftp_rename(sftp_session sftp, const char *original, const char *newnam
me) { e) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
BUFFER *buffer; ssh_buffer buffer;
STRING *oldpath; ssh_string oldpath;
STRING *newpath; ssh_string newpath;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
oldpath = string_from_char(original); oldpath = string_from_char(original);
if (oldpath == NULL) { if (oldpath == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
newpath = string_from_char(newname); newpath = string_from_char(newname);
if (newpath == NULL) { if (newpath == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
string_free(oldpath); string_free(oldpath);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, oldpath) < 0 || buffer_add_ssh_string(buffer, oldpath) < 0 ||
buffer_add_ssh_string(buffer, newpath) < 0 || buffer_add_ssh_string(buffer, newpath) < 0 ||
/* POSIX rename atomically replaces newpath, we should do the same */ /* POSIX rename atomically replaces newpath, we should do the same */
buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0 || buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0) {
sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(oldpath);
string_free(newpath);
return -1;
}
if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(oldpath); string_free(oldpath);
string_free(newpath); string_free(newpath);
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
string_free(oldpath); string_free(oldpath);
string_free(newpath); string_free(newpath);
while (msg == NULL) { while (msg == NULL) {
skipping to change at line 2106 skipping to change at line 2338
"Received message %d when attempting to rename", "Received message %d when attempting to rename",
msg->packet_type); msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
/* Code written by Nick */ /* Code written by Nick */
/* Set file attributes on a file, directory or symbolic link. */ /* Set file attributes on a file, directory or symbolic link. */
int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *att int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr)
r) { {
u32 id = sftp_get_new_id(sftp); uint32_t id = sftp_get_new_id(sftp);
BUFFER *buffer = buffer_new(); ssh_buffer buffer = buffer_new();
STRING *path = string_from_char(file); ssh_string path = string_from_char(file);
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
path = string_from_char(file); path = string_from_char(file);
if (path == NULL) { if (path == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, path) < 0 || buffer_add_ssh_string(buffer, path) < 0 ||
buffer_add_attributes(buffer, attr) < 0 || buffer_add_attributes(buffer, attr) < 0) {
sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(path);
return -1;
}
if (sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(path); string_free(path);
return -1; return -1;
} }
buffer_free(buffer); buffer_free(buffer);
string_free(path); string_free(path);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
return -1; return -1;
skipping to change at line 2176 skipping to change at line 2415
} else { } else {
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d when attempting to set stats", msg->packet_typ e); "Received message %d when attempting to set stats", msg->packet_typ e);
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
/* Change the file owner and group */ /* Change the file owner and group */
int sftp_chown(SFTP_SESSION *sftp, const char *file, uid_t owner, gid_t gro int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t grou
up) { p) {
SFTP_ATTRIBUTES attr; struct sftp_attributes_struct attr;
ZERO_STRUCT(attr); ZERO_STRUCT(attr);
attr.uid = owner; attr.uid = owner;
attr.gid = group; attr.gid = group;
attr.flags = SSH_FILEXFER_ATTR_OWNERGROUP; attr.flags = SSH_FILEXFER_ATTR_OWNERGROUP;
return sftp_setstat(sftp, file, &attr); return sftp_setstat(sftp, file, &attr);
} }
/* Change permissions of a file */ /* Change permissions of a file */
int sftp_chmod(SFTP_SESSION *sftp, const char *file, mode_t mode) { int sftp_chmod(sftp_session sftp, const char *file, mode_t mode) {
SFTP_ATTRIBUTES attr; struct sftp_attributes_struct attr;
ZERO_STRUCT(attr); ZERO_STRUCT(attr);
attr.permissions = mode; attr.permissions = mode;
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
return sftp_setstat(sftp, file, &attr); return sftp_setstat(sftp, file, &attr);
} }
/* Change the last modification and access time of a file. */ /* Change the last modification and access time of a file. */
int sftp_utimes(SFTP_SESSION *sftp, const char *file, int sftp_utimes(sftp_session sftp, const char *file,
const struct timeval *times) { const struct timeval *times) {
SFTP_ATTRIBUTES attr; struct sftp_attributes_struct attr;
ZERO_STRUCT(attr); ZERO_STRUCT(attr);
attr.atime = times[0].tv_sec; attr.atime = times[0].tv_sec;
attr.atime_nseconds = times[0].tv_usec; attr.atime_nseconds = times[0].tv_usec;
attr.mtime = times[1].tv_sec; attr.mtime = times[1].tv_sec;
attr.mtime_nseconds = times[1].tv_usec; attr.mtime_nseconds = times[1].tv_usec;
attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME | attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME |
SSH_FILEXFER_ATTR_SUBSECOND_TIMES; SSH_FILEXFER_ATTR_SUBSECOND_TIMES;
return sftp_setstat(sftp, file, &attr); return sftp_setstat(sftp, file, &attr);
} }
int sftp_symlink(SFTP_SESSION *sftp, const char *target, const char *dest) int sftp_symlink(sftp_session sftp, const char *target, const char *dest) {
{ sftp_status_message status = NULL;
STATUS_MESSAGE *status = NULL; sftp_message msg = NULL;
SFTP_MESSAGE *msg = NULL; ssh_string target_s;
STRING *target_s; ssh_string dest_s;
STRING *dest_s; ssh_buffer buffer;
BUFFER *buffer; uint32_t id;
u32 id;
if (sftp == NULL || target == NULL || dest == NULL) { if (sftp == NULL)
return -1;
if (target == NULL || dest == NULL) {
ssh_set_error_invalid(sftp->session, __FUNCTION__);
return -1; return -1;
} }
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return -1; return -1;
} }
target_s = string_from_char(target); target_s = string_from_char(target);
if (target_s == NULL) { if (target_s == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
dest_s = string_from_char(dest); dest_s = string_from_char(dest);
if (dest_s == NULL) { if (dest_s == NULL) {
ssh_set_error_oom(sftp->session);
string_free(target_s); string_free(target_s);
buffer_free(buffer); buffer_free(buffer);
return -1; return -1;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0) { if (buffer_add_u32(buffer, id) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
string_free(dest_s); string_free(dest_s);
string_free(target_s); string_free(target_s);
return -1; return -1;
} }
if (ssh_get_openssh_version(sftp->session)) { if (ssh_get_openssh_version(sftp->session)) {
/* TODO check for version number if they ever fix it. */ /* TODO check for version number if they ever fix it. */
if (buffer_add_ssh_string(buffer, target_s) < 0 || if (buffer_add_ssh_string(buffer, target_s) < 0 ||
buffer_add_ssh_string(buffer, dest_s) < 0) { buffer_add_ssh_string(buffer, dest_s) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
string_free(dest_s); string_free(dest_s);
string_free(target_s); string_free(target_s);
return -1; return -1;
} }
} else { } else {
if (buffer_add_ssh_string(buffer, dest_s) < 0 || if (buffer_add_ssh_string(buffer, dest_s) < 0 ||
buffer_add_ssh_string(buffer, target_s) < 0) { buffer_add_ssh_string(buffer, target_s) < 0) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
string_free(dest_s); string_free(dest_s);
string_free(target_s); string_free(target_s);
return -1; return -1;
} }
} }
if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) { if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(dest_s); string_free(dest_s);
skipping to change at line 2323 skipping to change at line 2568
return -1; return -1;
} else { } else {
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d when attempting to set stats", msg->packet_typ e); "Received message %d when attempting to set stats", msg->packet_typ e);
sftp_message_free(msg); sftp_message_free(msg);
} }
return -1; return -1;
} }
char *sftp_readlink(SFTP_SESSION *sftp, const char *path) { char *sftp_readlink(sftp_session sftp, const char *path) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STRING *path_s = NULL; ssh_string path_s = NULL;
STRING *link_s = NULL; ssh_string link_s = NULL;
BUFFER *buffer; ssh_buffer buffer;
char *link; char *lnk;
u32 ignored; uint32_t ignored;
u32 id; uint32_t id;
if (sftp == NULL || path == NULL) { 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; return NULL;
} }
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
path_s = string_from_char(path); path_s = string_from_char(path);
if (path_s == NULL) { if (path_s == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return NULL; return NULL;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, path_s) < 0 || buffer_add_ssh_string(buffer, path_s) < 0) {
sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(path_s);
return NULL;
}
if (sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(path_s); string_free(path_s);
return NULL; return NULL;
} }
buffer_free(buffer); buffer_free(buffer);
string_free(path_s); string_free(path_s);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
return NULL; return NULL;
skipping to change at line 2373 skipping to change at line 2631
msg = sftp_dequeue(sftp, id); msg = sftp_dequeue(sftp, id);
} }
if (msg->packet_type == SSH_FXP_NAME) { if (msg->packet_type == SSH_FXP_NAME) {
/* we don't care about "count" */ /* we don't care about "count" */
buffer_get_u32(msg->payload, &ignored); buffer_get_u32(msg->payload, &ignored);
/* we only care about the file name string */ /* we only care about the file name string */
link_s = buffer_get_ssh_string(msg->payload); link_s = buffer_get_ssh_string(msg->payload);
sftp_message_free(msg); sftp_message_free(msg);
if (link_s == NULL) { if (link_s == NULL) {
/* TODO: what error to set here? */
return NULL; return NULL;
} }
link = string_to_char(link_s); lnk = string_to_char(link_s);
string_free(link_s); string_free(link_s);
return link; return lnk;
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */ } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
status = parse_status_msg(msg); status = parse_status_msg(msg);
sftp_message_free(msg); sftp_message_free(msg);
if (status == NULL) { if (status == NULL) {
return NULL; return NULL;
} }
ssh_set_error(sftp->session, SSH_REQUEST_DENIED, ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
"SFTP server: %s", status->errormsg); "SFTP server: %s", status->errormsg);
status_msg_free(status); status_msg_free(status);
} else { /* this shouldn't happen */ } else { /* this shouldn't happen */
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d when attempting to set stats", msg->packet_typ e); "Received message %d when attempting to set stats", msg->packet_typ e);
sftp_message_free(msg); sftp_message_free(msg);
} }
return NULL; 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 = buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return NULL;
}
ext = string_from_char("statvfs@openssh.com");
if (ext == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer);
return NULL;
}
pathstr = string_from_char(path);
if (pathstr == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer);
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);
buffer_free(buffer);
string_free(ext);
string_free(pathstr);
return NULL;
}
if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
buffer_free(buffer);
string_free(ext);
string_free(pathstr);
return NULL;
}
buffer_free(buffer);
string_free(ext);
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_t
ype);
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 = buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return NULL;
}
ext = string_from_char("fstatvfs@openssh.com");
if (ext == NULL) {
ssh_set_error_oom(sftp->session);
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);
buffer_free(buffer);
string_free(ext);
return NULL;
}
if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
buffer_free(buffer);
string_free(ext);
return NULL;
}
buffer_free(buffer);
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_typ
e);
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 */ /* another code written by Nick */
char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path) { char *sftp_canonicalize_path(sftp_session sftp, const char *path) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STRING *name = NULL; ssh_string name = NULL;
STRING *pathstr; ssh_string pathstr;
BUFFER *buffer; ssh_buffer buffer;
char *cname; char *cname;
u32 ignored; uint32_t ignored;
u32 id; uint32_t id;
if (sftp == NULL)
return NULL;
if (path == NULL) {
ssh_set_error_invalid(sftp->session, __FUNCTION__);
return NULL;
}
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
pathstr = string_from_char(path); pathstr = string_from_char(path);
if (pathstr == NULL) { if (pathstr == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return NULL; return NULL;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, pathstr) < 0 || buffer_add_ssh_string(buffer, pathstr) < 0) {
sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(pathstr);
return NULL;
}
if (sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(pathstr); string_free(pathstr);
return NULL; return NULL;
} }
buffer_free(buffer); buffer_free(buffer);
string_free(pathstr); string_free(pathstr);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
return NULL; return NULL;
skipping to change at line 2444 skipping to change at line 2986
msg = sftp_dequeue(sftp, id); msg = sftp_dequeue(sftp, id);
} }
if (msg->packet_type == SSH_FXP_NAME) { if (msg->packet_type == SSH_FXP_NAME) {
/* we don't care about "count" */ /* we don't care about "count" */
buffer_get_u32(msg->payload, &ignored); buffer_get_u32(msg->payload, &ignored);
/* we only care about the file name string */ /* we only care about the file name string */
name = buffer_get_ssh_string(msg->payload); name = buffer_get_ssh_string(msg->payload);
sftp_message_free(msg); sftp_message_free(msg);
if (name == NULL) { if (name == NULL) {
/* TODO: error message? */
return NULL; return NULL;
} }
cname = string_to_char(name); cname = string_to_char(name);
string_free(name); string_free(name);
if (cname == NULL) {
ssh_set_error_oom(sftp->session);
}
return cname; return cname;
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */ } else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
status = parse_status_msg(msg); status = parse_status_msg(msg);
sftp_message_free(msg); sftp_message_free(msg);
if (status == NULL) { if (status == NULL) {
return NULL; return NULL;
} }
ssh_set_error(sftp->session, SSH_REQUEST_DENIED, ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
"SFTP server: %s", status->errormsg); "SFTP server: %s", status->errormsg);
status_msg_free(status); status_msg_free(status);
} else { /* this shouldn't happen */ } else { /* this shouldn't happen */
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d when attempting to set stats", msg->packet_typ e); "Received message %d when attempting to set stats", msg->packet_typ e);
sftp_message_free(msg); sftp_message_free(msg);
} }
return NULL; return NULL;
} }
static SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, const char *path, static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
int param) { int param) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
STRING *pathstr; ssh_string pathstr;
BUFFER *buffer; ssh_buffer buffer;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(sftp->session);
return NULL; return NULL;
} }
pathstr = string_from_char(path); pathstr = string_from_char(path);
if (pathstr == NULL) { if (pathstr == NULL) {
ssh_set_error_oom(sftp->session);
buffer_free(buffer); buffer_free(buffer);
return NULL; return NULL;
} }
id = sftp_get_new_id(sftp); id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, pathstr) < 0 || buffer_add_ssh_string(buffer, pathstr) < 0) {
sftp_packet_write(sftp, param, buffer) < 0) { ssh_set_error_oom(sftp->session);
buffer_free(buffer);
string_free(pathstr);
return NULL;
}
if (sftp_packet_write(sftp, param, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
string_free(pathstr); string_free(pathstr);
return NULL; return NULL;
} }
buffer_free(buffer); buffer_free(buffer);
string_free(pathstr); string_free(pathstr);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) { if (sftp_read_and_dispatch(sftp) < 0) {
return NULL; return NULL;
skipping to change at line 2526 skipping to change at line 3078
status_msg_free(status); status_msg_free(status);
return NULL; return NULL;
} }
ssh_set_error(sftp->session, SSH_FATAL, ssh_set_error(sftp->session, SSH_FATAL,
"Received mesg %d during stat()", msg->packet_type); "Received mesg %d during stat()", msg->packet_type);
sftp_message_free(msg); sftp_message_free(msg);
return NULL; return NULL;
} }
SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, const char *path) { sftp_attributes sftp_stat(sftp_session session, const char *path) {
return sftp_xstat(session, path, SSH_FXP_STAT); return sftp_xstat(session, path, SSH_FXP_STAT);
} }
SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, const char *path) { sftp_attributes sftp_lstat(sftp_session session, const char *path) {
return sftp_xstat(session, path, SSH_FXP_LSTAT); return sftp_xstat(session, path, SSH_FXP_LSTAT);
} }
SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file) { sftp_attributes sftp_fstat(sftp_file file) {
STATUS_MESSAGE *status = NULL; sftp_status_message status = NULL;
SFTP_MESSAGE *msg = NULL; sftp_message msg = NULL;
BUFFER *buffer; ssh_buffer buffer;
u32 id; uint32_t id;
buffer = buffer_new(); buffer = buffer_new();
if (buffer == NULL) { if (buffer == NULL) {
ssh_set_error_oom(file->sftp->session);
return NULL; return NULL;
} }
id = sftp_get_new_id(file->sftp); id = sftp_get_new_id(file->sftp);
if (buffer_add_u32(buffer, id) < 0 || if (buffer_add_u32(buffer, id) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0 || buffer_add_ssh_string(buffer, file->handle) < 0) {
sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer) < 0) { ssh_set_error_oom(file->sftp->session);
buffer_free(buffer);
return NULL;
}
if (sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer) < 0) {
buffer_free(buffer); buffer_free(buffer);
return NULL; return NULL;
} }
buffer_free(buffer); buffer_free(buffer);
while (msg == NULL) { while (msg == NULL) {
if (sftp_read_and_dispatch(file->sftp) < 0) { if (sftp_read_and_dispatch(file->sftp) < 0) {
return NULL; return NULL;
} }
msg = sftp_dequeue(file->sftp, id); msg = sftp_dequeue(file->sftp, id);
 End of changes. 202 change blocks. 
321 lines changed or deleted 885 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/