|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* sftp.c - Secure FTP functions
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* This file is part of the SSH Library
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* Copyright (c) 2005-2008 by Aris Adamantiadis
|
|
Packit Service |
31306d |
* Copyright (c) 2008-2018 by Andreas Schneider <asn@cryptomilk.org>
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is free software; you can redistribute it and/or modify
|
|
Packit Service |
31306d |
* it under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
31306d |
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
|
Packit Service |
31306d |
* option) any later version.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is distributed in the hope that it will be useful, but
|
|
Packit Service |
31306d |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit Service |
31306d |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
Packit Service |
31306d |
* License for more details.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
31306d |
* along with the SSH Library; see the file COPYING. If not, write to
|
|
Packit Service |
31306d |
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
Packit Service |
31306d |
* MA 02111-1307, USA.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* This file contains code written by Nick Zitzmann */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "config.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include <stdbool.h>
|
|
Packit Service |
31306d |
#include <errno.h>
|
|
Packit Service |
31306d |
#include <ctype.h>
|
|
Packit Service |
31306d |
#include <fcntl.h>
|
|
Packit Service |
31306d |
#include <stdio.h>
|
|
Packit Service |
31306d |
#include <stdint.h>
|
|
Packit Service |
31306d |
#include <sys/types.h>
|
|
Packit Service |
31306d |
#include <sys/stat.h>
|
|
Packit Service |
31306d |
#include <limits.h>
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#ifndef _WIN32
|
|
Packit Service |
31306d |
#include <netinet/in.h>
|
|
Packit Service |
31306d |
#include <arpa/inet.h>
|
|
Packit Service |
31306d |
#endif
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "libssh/priv.h"
|
|
Packit Service |
31306d |
#include "libssh/ssh2.h"
|
|
Packit Service |
31306d |
#include "libssh/sftp.h"
|
|
Packit Service |
31306d |
#include "libssh/sftp_priv.h"
|
|
Packit Service |
31306d |
#include "libssh/buffer.h"
|
|
Packit Service |
31306d |
#include "libssh/channels.h"
|
|
Packit Service |
31306d |
#include "libssh/session.h"
|
|
Packit Service |
31306d |
#include "libssh/misc.h"
|
|
Packit Service |
31306d |
#include "libssh/bytearray.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#ifdef WITH_SFTP
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Buffer size maximum is 256M */
|
|
Packit Service |
31306d |
#define SFTP_PACKET_SIZE_MAX 0x10000000
|
|
Packit Service |
31306d |
#define SFTP_BUFFER_SIZE_MAX 16384
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
struct sftp_ext_struct {
|
|
Packit Service |
31306d |
uint32_t count;
|
|
Packit Service |
31306d |
char **name;
|
|
Packit Service |
31306d |
char **data;
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* functions */
|
|
Packit Service |
31306d |
static int sftp_enqueue(sftp_session session, sftp_message msg);
|
|
Packit Service |
31306d |
static void sftp_message_free(sftp_message msg);
|
|
Packit Service |
31306d |
static void sftp_set_error(sftp_session sftp, int errnum);
|
|
Packit Service |
31306d |
static void status_msg_free(sftp_status_message status);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_ext sftp_ext_new(void) {
|
|
Packit Service |
31306d |
sftp_ext ext;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ext = calloc(1, sizeof(struct sftp_ext_struct));
|
|
Packit Service |
31306d |
if (ext == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return ext;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static void sftp_ext_free(sftp_ext ext)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
size_t i;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ext == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ext->count > 0) {
|
|
Packit Service |
31306d |
if (ext->name != NULL) {
|
|
Packit Service |
31306d |
for (i = 0; i < ext->count; i++) {
|
|
Packit Service |
31306d |
SAFE_FREE(ext->name[i]);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(ext->name);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ext->data != NULL) {
|
|
Packit Service |
31306d |
for (i = 0; i < ext->count; i++) {
|
|
Packit Service |
31306d |
SAFE_FREE(ext->data[i]);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(ext->data);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(ext);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_session sftp_new(ssh_session session)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_session sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp = calloc(1, sizeof(struct sftp_session_struct));
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->ext = sftp_ext_new();
|
|
Packit Service |
31306d |
if (sftp->ext == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->read_packet = calloc(1, sizeof(struct sftp_packet_struct));
|
|
Packit Service |
31306d |
if (sftp->read_packet == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->read_packet->payload = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (sftp->read_packet->payload == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->session = session;
|
|
Packit Service |
31306d |
sftp->channel = ssh_channel_new(session);
|
|
Packit Service |
31306d |
if (sftp->channel == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ssh_channel_open_session(sftp->channel)) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ssh_channel_request_sftp(sftp->channel)) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp;
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
if (sftp->ext != NULL) {
|
|
Packit Service |
31306d |
sftp_ext_free(sftp->ext);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp->channel != NULL) {
|
|
Packit Service |
31306d |
ssh_channel_free(sftp->channel);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp->read_packet != NULL) {
|
|
Packit Service |
31306d |
if (sftp->read_packet->payload != NULL) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(sftp->read_packet->payload);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(sftp->read_packet);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(sftp);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_session sftp_new_channel(ssh_session session, ssh_channel channel){
|
|
Packit Service |
31306d |
sftp_session sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp = calloc(1, sizeof(struct sftp_session_struct));
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->ext = sftp_ext_new();
|
|
Packit Service |
31306d |
if (sftp->ext == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
SAFE_FREE(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->session = session;
|
|
Packit Service |
31306d |
sftp->channel = channel;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#ifdef WITH_SERVER
|
|
Packit Service |
31306d |
sftp_session sftp_server_new(ssh_session session, ssh_channel chan){
|
|
Packit Service |
31306d |
sftp_session sftp = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp = calloc(1, sizeof(struct sftp_session_struct));
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->read_packet = calloc(1, sizeof(struct sftp_packet_struct));
|
|
Packit Service |
31306d |
if (sftp->read_packet == NULL) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->read_packet->payload = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (sftp->read_packet->payload == NULL) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->session = session;
|
|
Packit Service |
31306d |
sftp->channel = chan;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
if (sftp->read_packet != NULL) {
|
|
Packit Service |
31306d |
if (sftp->read_packet->payload != NULL) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(sftp->read_packet->payload);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(sftp->read_packet);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(sftp);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int sftp_server_init(sftp_session sftp){
|
|
Packit Service |
31306d |
ssh_session session = sftp->session;
|
|
Packit Service |
31306d |
sftp_packet packet = NULL;
|
|
Packit Service |
31306d |
ssh_buffer reply = NULL;
|
|
Packit Service |
31306d |
uint32_t version;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
packet = sftp_packet_read(sftp);
|
|
Packit Service |
31306d |
if (packet == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (packet->type != SSH_FXP_INIT) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Packet read of type %d instead of SSH_FXP_INIT",
|
|
Packit Service |
31306d |
packet->type);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET, "Received SSH_FXP_INIT");
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_buffer_get_u32(packet->payload, &version);
|
|
Packit Service |
31306d |
version = ntohl(version);
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET, "Client version: %d", version);
|
|
Packit Service |
31306d |
sftp->client_version = (int)version;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
reply = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (reply == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(reply, "dssss",
|
|
Packit Service |
31306d |
LIBSFTP_VERSION,
|
|
Packit Service |
31306d |
"posix-rename@openssh.com",
|
|
Packit Service |
31306d |
"1",
|
|
Packit Service |
31306d |
"hardlink@openssh.com",
|
|
Packit Service |
31306d |
"1");
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(reply);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(reply);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(reply);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL, "Server version sent");
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (version > LIBSFTP_VERSION) {
|
|
Packit Service |
31306d |
sftp->version = LIBSFTP_VERSION;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
sftp->version = (int)version;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void sftp_server_free(sftp_session sftp)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_request_queue ptr;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ptr = sftp->queue;
|
|
Packit Service |
31306d |
while(ptr) {
|
|
Packit Service |
31306d |
sftp_request_queue old;
|
|
Packit Service |
31306d |
sftp_message_free(ptr->message);
|
|
Packit Service |
31306d |
old = ptr->next;
|
|
Packit Service |
31306d |
SAFE_FREE(ptr);
|
|
Packit Service |
31306d |
ptr = old;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(sftp->handles);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(sftp->read_packet->payload);
|
|
Packit Service |
31306d |
SAFE_FREE(sftp->read_packet);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_ext_free(sftp->ext);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(sftp);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
#endif /* WITH_SERVER */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void sftp_free(sftp_session sftp)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_request_queue ptr;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp->channel != NULL) {
|
|
Packit Service |
31306d |
ssh_channel_send_eof(sftp->channel);
|
|
Packit Service |
31306d |
ptr = sftp->queue;
|
|
Packit Service |
31306d |
while(ptr) {
|
|
Packit Service |
31306d |
sftp_request_queue old;
|
|
Packit Service |
31306d |
sftp_message_free(ptr->message);
|
|
Packit Service |
31306d |
old = ptr->next;
|
|
Packit Service |
31306d |
SAFE_FREE(ptr);
|
|
Packit Service |
31306d |
ptr = old;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_channel_free(sftp->channel);
|
|
Packit Service |
31306d |
sftp->channel = NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(sftp->handles);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(sftp->read_packet->payload);
|
|
Packit Service |
31306d |
SAFE_FREE(sftp->read_packet);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_ext_free(sftp->ext);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(sftp);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssize_t sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
uint8_t header[5] = {0};
|
|
Packit Service |
31306d |
uint32_t payload_size;
|
|
Packit Service |
31306d |
ssize_t size;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Add size of type */
|
|
Packit Service |
31306d |
payload_size = ssh_buffer_get_len(payload) + sizeof(uint8_t);
|
|
Packit Service |
31306d |
PUSH_BE_U32(header, 0, payload_size);
|
|
Packit Service |
31306d |
PUSH_BE_U8(header, 4, type);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_prepend_data(payload, header, sizeof(header));
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
size = ssh_channel_write(sftp->channel,
|
|
Packit Service |
31306d |
ssh_buffer_get(payload),
|
|
Packit Service |
31306d |
ssh_buffer_get_len(payload));
|
|
Packit Service |
31306d |
if (size < 0) {
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if ((uint32_t)size != ssh_buffer_get_len(payload)) {
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Had to write %d bytes, wrote only %zd",
|
|
Packit Service |
31306d |
ssh_buffer_get_len(payload),
|
|
Packit Service |
31306d |
size);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return size;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_packet sftp_packet_read(sftp_session sftp)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
uint8_t buffer[SFTP_BUFFER_SIZE_MAX];
|
|
Packit Service |
31306d |
sftp_packet packet = sftp->read_packet;
|
|
Packit Service |
31306d |
uint32_t size;
|
|
Packit Service |
31306d |
int nread;
|
|
Packit Service |
31306d |
bool is_eof;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
packet->sftp = sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* If the packet has a payload, then just reinit the buffer, otherwise
|
|
Packit Service |
31306d |
* allocate a new one.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
if (packet->payload != NULL) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_reinit(packet->payload);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
packet->payload = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (packet->payload == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
nread = 0;
|
|
Packit Service |
31306d |
do {
|
|
Packit Service |
31306d |
int s;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
// read from channel until 4 bytes have been read or an error occurs
|
|
Packit Service |
31306d |
s = ssh_channel_read(sftp->channel, buffer + nread, 4 - nread, 0);
|
|
Packit Service |
31306d |
if (s < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
} else if (s == 0) {
|
|
Packit Service |
31306d |
is_eof = ssh_channel_is_eof(sftp->channel);
|
|
Packit Service |
31306d |
if (is_eof) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_FATAL,
|
|
Packit Service |
31306d |
"Received EOF while reading sftp packet size");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_EOF);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
nread += s;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} while (nread < 4);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
size = PULL_BE_U32(buffer, 0);
|
|
Packit Service |
31306d |
if (size == 0 || size > SFTP_PACKET_SIZE_MAX) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL, "Invalid sftp packet size!");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
do {
|
|
Packit Service |
31306d |
nread = ssh_channel_read(sftp->channel, buffer, 1, 0);
|
|
Packit Service |
31306d |
if (nread < 0) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
} else if (nread == 0) {
|
|
Packit Service |
31306d |
is_eof = ssh_channel_is_eof(sftp->channel);
|
|
Packit Service |
31306d |
if (is_eof) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_FATAL,
|
|
Packit Service |
31306d |
"Received EOF while reading sftp packet type");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_EOF);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} while (nread < 1);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
packet->type = buffer[0];
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Remove the packet type size */
|
|
Packit Service |
31306d |
size -= sizeof(uint8_t);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
nread = ssh_buffer_allocate_size(packet->payload, size);
|
|
Packit Service |
31306d |
if (nread < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
while (size > 0 && size < SFTP_PACKET_SIZE_MAX) {
|
|
Packit Service |
31306d |
nread = ssh_channel_read(sftp->channel,
|
|
Packit Service |
31306d |
buffer,
|
|
Packit Service |
31306d |
sizeof(buffer) > size ? size : sizeof(buffer),
|
|
Packit Service |
31306d |
0);
|
|
Packit Service |
31306d |
if (nread < 0) {
|
|
Packit Service |
31306d |
/* TODO: check if there are cases where an error needs to be set here */
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (nread > 0) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_add_data(packet->payload, buffer, nread);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else { /* nread == 0 */
|
|
Packit Service |
31306d |
/* Retry the reading unless the remote was closed */
|
|
Packit Service |
31306d |
is_eof = ssh_channel_is_eof(sftp->channel);
|
|
Packit Service |
31306d |
if (is_eof) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"Received EOF while reading sftp packet");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_EOF);
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
size -= nread;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return packet;
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
ssh_buffer_reinit(packet->payload);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static void sftp_set_error(sftp_session sftp, int errnum) {
|
|
Packit Service |
31306d |
if (sftp != NULL) {
|
|
Packit Service |
31306d |
sftp->errnum = errnum;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Get the last sftp error */
|
|
Packit Service |
31306d |
int sftp_get_error(sftp_session sftp) {
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp->errnum;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static void sftp_message_free(sftp_message msg)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
if (msg == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(msg->payload);
|
|
Packit Service |
31306d |
SAFE_FREE(msg);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_message sftp_get_message(sftp_packet packet)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_session sftp = packet->sftp;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch(packet->type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
case SSH_FXP_HANDLE:
|
|
Packit Service |
31306d |
case SSH_FXP_DATA:
|
|
Packit Service |
31306d |
case SSH_FXP_ATTRS:
|
|
Packit Service |
31306d |
case SSH_FXP_NAME:
|
|
Packit Service |
31306d |
case SSH_FXP_EXTENDED_REPLY:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(packet->sftp->session,
|
|
Packit Service |
31306d |
SSH_FATAL,
|
|
Packit Service |
31306d |
"Unknown packet type %d",
|
|
Packit Service |
31306d |
packet->type);
|
|
Packit Service |
31306d |
sftp_set_error(packet->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
msg = calloc(1, sizeof(struct sftp_message_struct));
|
|
Packit Service |
31306d |
if (msg == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(packet->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
msg->sftp = packet->sftp;
|
|
Packit Service |
31306d |
msg->packet_type = packet->type;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Move the payload from the packet to the message */
|
|
Packit Service |
31306d |
msg->payload = packet->payload;
|
|
Packit Service |
31306d |
packet->payload = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(msg->payload, "d", &msg->id);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error(packet->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Invalid packet %d: no ID", packet->type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(packet->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Packet with id %d type %d",
|
|
Packit Service |
31306d |
msg->id,
|
|
Packit Service |
31306d |
msg->packet_type);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return msg;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static int sftp_read_and_dispatch(sftp_session sftp)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_packet packet = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
packet = sftp_packet_read(sftp);
|
|
Packit Service |
31306d |
if (packet == NULL) {
|
|
Packit Service |
31306d |
/* something nasty happened reading the packet */
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
msg = sftp_get_message(packet);
|
|
Packit Service |
31306d |
if (msg == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp_enqueue(sftp, msg) < 0) {
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void sftp_packet_free(sftp_packet packet)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
if (packet == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(packet->payload);
|
|
Packit Service |
31306d |
free(packet);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Initialize the sftp session with the server. */
|
|
Packit Service |
31306d |
int sftp_init(sftp_session sftp) {
|
|
Packit Service |
31306d |
sftp_packet packet = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer = NULL;
|
|
Packit Service |
31306d |
char *ext_name = NULL;
|
|
Packit Service |
31306d |
char *ext_data = NULL;
|
|
Packit Service |
31306d |
uint32_t version;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer, "d", LIBSFTP_VERSION);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
packet = sftp_packet_read(sftp);
|
|
Packit Service |
31306d |
if (packet == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (packet->type != SSH_FXP_VERSION) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received a %d messages instead of SSH_FXP_VERSION", packet->type);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* TODO: are we sure there are 4 bytes ready? */
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(packet->payload, "d", &version);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL,
|
|
Packit Service |
31306d |
"SFTP server version %d",
|
|
Packit Service |
31306d |
version);
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(packet->payload, "s", &ext_name);
|
|
Packit Service |
31306d |
while (rc == SSH_OK) {
|
|
Packit Service |
31306d |
uint32_t count = sftp->ext->count;
|
|
Packit Service |
31306d |
char **tmp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(packet->payload, "s", &ext_data);
|
|
Packit Service |
31306d |
if (rc == SSH_ERROR) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL,
|
|
Packit Service |
31306d |
"SFTP server extension: %s, version: %s",
|
|
Packit Service |
31306d |
ext_name, ext_data);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
count++;
|
|
Packit Service |
31306d |
tmp = realloc(sftp->ext->name, count * sizeof(char *));
|
|
Packit Service |
31306d |
if (tmp == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SAFE_FREE(ext_name);
|
|
Packit Service |
31306d |
SAFE_FREE(ext_data);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
tmp[count - 1] = ext_name;
|
|
Packit Service |
31306d |
sftp->ext->name = tmp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
tmp = realloc(sftp->ext->data, count * sizeof(char *));
|
|
Packit Service |
31306d |
if (tmp == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SAFE_FREE(ext_name);
|
|
Packit Service |
31306d |
SAFE_FREE(ext_data);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
tmp[count - 1] = ext_data;
|
|
Packit Service |
31306d |
sftp->ext->data = tmp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->ext->count = count;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(packet->payload, "s", &ext_name);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp->version = sftp->server_version = (int)version;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
unsigned int sftp_extensions_get_count(sftp_session sftp) {
|
|
Packit Service |
31306d |
if (sftp == NULL || sftp->ext == NULL) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp->ext->count;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
const char *sftp_extensions_get_name(sftp_session sftp, unsigned int idx) {
|
|
Packit Service |
31306d |
if (sftp == NULL)
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
if (sftp->ext == NULL || sftp->ext->name == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (idx > sftp->ext->count) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp->ext->name[idx];
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
const char *sftp_extensions_get_data(sftp_session sftp, unsigned int idx) {
|
|
Packit Service |
31306d |
if (sftp == NULL)
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
if (sftp->ext == NULL || sftp->ext->name == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (idx > sftp->ext->count) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp->ext->data[idx];
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int sftp_extension_supported(sftp_session sftp, const char *name,
|
|
Packit Service |
31306d |
const char *data) {
|
|
Packit Service |
31306d |
size_t i, n;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL || name == NULL || data == NULL) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
n = sftp_extensions_get_count(sftp);
|
|
Packit Service |
31306d |
for (i = 0; i < n; i++) {
|
|
Packit Service |
31306d |
const char *ext_name = sftp_extensions_get_name(sftp, i);
|
|
Packit Service |
31306d |
const char *ext_data = sftp_extensions_get_data(sftp, i);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ext_name != NULL && ext_data != NULL &&
|
|
Packit Service |
31306d |
strcmp(ext_name, name) == 0 &&
|
|
Packit Service |
31306d |
strcmp(ext_data, data) == 0) {
|
|
Packit Service |
31306d |
return 1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_request_queue request_queue_new(sftp_message msg) {
|
|
Packit Service |
31306d |
sftp_request_queue queue = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
queue = calloc(1, sizeof(struct sftp_request_queue_struct));
|
|
Packit Service |
31306d |
if (queue == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(msg->sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
queue->message = msg;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return queue;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static void request_queue_free(sftp_request_queue queue) {
|
|
Packit Service |
31306d |
if (queue == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ZERO_STRUCTP(queue);
|
|
Packit Service |
31306d |
SAFE_FREE(queue);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static int sftp_enqueue(sftp_session sftp, sftp_message msg) {
|
|
Packit Service |
31306d |
sftp_request_queue queue = NULL;
|
|
Packit Service |
31306d |
sftp_request_queue ptr;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
queue = request_queue_new(msg);
|
|
Packit Service |
31306d |
if (queue == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Queued msg id %d type %d",
|
|
Packit Service |
31306d |
msg->id, msg->packet_type);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if(sftp->queue == NULL) {
|
|
Packit Service |
31306d |
sftp->queue = queue;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ptr = sftp->queue;
|
|
Packit Service |
31306d |
while(ptr->next) {
|
|
Packit Service |
31306d |
ptr=ptr->next; /* find end of linked list */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ptr->next = queue; /* add it on bottom */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Pulls of a message from the queue based on the ID.
|
|
Packit Service |
31306d |
* Returns NULL if no message has been found.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){
|
|
Packit Service |
31306d |
sftp_request_queue prev = NULL;
|
|
Packit Service |
31306d |
sftp_request_queue queue;
|
|
Packit Service |
31306d |
sftp_message msg;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if(sftp->queue == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
queue = sftp->queue;
|
|
Packit Service |
31306d |
while (queue) {
|
|
Packit Service |
31306d |
if(queue->message->id == id) {
|
|
Packit Service |
31306d |
/* remove from queue */
|
|
Packit Service |
31306d |
if (prev == NULL) {
|
|
Packit Service |
31306d |
sftp->queue = queue->next;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
prev->next = queue->next;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = queue->message;
|
|
Packit Service |
31306d |
request_queue_free(queue);
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Dequeued msg id %d type %d",
|
|
Packit Service |
31306d |
msg->id,
|
|
Packit Service |
31306d |
msg->packet_type);
|
|
Packit Service |
31306d |
return msg;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
prev = queue;
|
|
Packit Service |
31306d |
queue = queue->next;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Assigns a new SFTP ID for new requests and assures there is no collision
|
|
Packit Service |
31306d |
* between them.
|
|
Packit Service |
31306d |
* Returns a new ID ready to use in a request
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static inline uint32_t sftp_get_new_id(sftp_session session) {
|
|
Packit Service |
31306d |
return ++session->id_counter;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_status_message parse_status_msg(sftp_message msg){
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type != SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
ssh_set_error(msg->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Not a ssh_fxp_status message passed in!");
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
status = calloc(1, sizeof(struct sftp_status_message_struct));
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(msg->sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
status->id = msg->id;
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(msg->payload, "d",
|
|
Packit Service |
31306d |
&status->status);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
SAFE_FREE(status);
|
|
Packit Service |
31306d |
ssh_set_error(msg->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Invalid SSH_FXP_STATUS message");
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(msg->payload, "ss",
|
|
Packit Service |
31306d |
&status->errormsg,
|
|
Packit Service |
31306d |
&status->langmsg);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if(rc != SSH_OK && msg->sftp->version >=3){
|
|
Packit Service |
31306d |
/* These are mandatory from version 3 */
|
|
Packit Service |
31306d |
SAFE_FREE(status);
|
|
Packit Service |
31306d |
ssh_set_error(msg->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Invalid SSH_FXP_STATUS message");
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (status->errormsg == NULL)
|
|
Packit Service |
31306d |
status->errormsg = strdup("No error message in packet");
|
|
Packit Service |
31306d |
if (status->langmsg == NULL)
|
|
Packit Service |
31306d |
status->langmsg = strdup("");
|
|
Packit Service |
31306d |
if (status->errormsg == NULL || status->langmsg == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(msg->sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return status;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static void status_msg_free(sftp_status_message status){
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(status->errormsg);
|
|
Packit Service |
31306d |
SAFE_FREE(status->langmsg);
|
|
Packit Service |
31306d |
SAFE_FREE(status);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_file parse_handle_msg(sftp_message msg){
|
|
Packit Service |
31306d |
sftp_file file;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if(msg->packet_type != SSH_FXP_HANDLE) {
|
|
Packit Service |
31306d |
ssh_set_error(msg->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Not a ssh_fxp_handle message passed in!");
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
file = calloc(1, sizeof(struct sftp_file_struct));
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(msg->sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
file->handle = ssh_buffer_get_ssh_string(msg->payload);
|
|
Packit Service |
31306d |
if (file->handle == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(msg->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Invalid SSH_FXP_HANDLE message");
|
|
Packit Service |
31306d |
SAFE_FREE(file);
|
|
Packit Service |
31306d |
sftp_set_error(msg->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
file->sftp = msg->sftp;
|
|
Packit Service |
31306d |
file->offset = 0;
|
|
Packit Service |
31306d |
file->eof = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return file;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Open a directory */
|
|
Packit Service |
31306d |
sftp_dir sftp_opendir(sftp_session sftp, const char *path)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_file file = NULL;
|
|
Packit Service |
31306d |
sftp_dir dir = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
ssh_buffer payload;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
payload = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (payload == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(payload,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
path);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(payload);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(payload);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
case SSH_FXP_HANDLE:
|
|
Packit Service |
31306d |
file = parse_handle_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (file != NULL) {
|
|
Packit Service |
31306d |
dir = calloc(1, sizeof(struct sftp_dir_struct));
|
|
Packit Service |
31306d |
if (dir == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
free(file);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
dir->sftp = sftp;
|
|
Packit Service |
31306d |
dir->name = strdup(path);
|
|
Packit Service |
31306d |
if (dir->name == NULL) {
|
|
Packit Service |
31306d |
SAFE_FREE(dir);
|
|
Packit Service |
31306d |
SAFE_FREE(file);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
dir->handle = file->handle;
|
|
Packit Service |
31306d |
SAFE_FREE(file);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
return dir;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d during opendir!", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Parse the attributes from a payload from some messages. It is coded on
|
|
Packit Service |
31306d |
* baselines from the protocol version 4.
|
|
Packit Service |
31306d |
* This code is more or less dead but maybe we need it in future.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
|
|
Packit Service |
31306d |
int expectnames) {
|
|
Packit Service |
31306d |
sftp_attributes attr;
|
|
Packit Service |
31306d |
ssh_string owner = NULL;
|
|
Packit Service |
31306d |
ssh_string group = NULL;
|
|
Packit Service |
31306d |
uint32_t flags = 0;
|
|
Packit Service |
31306d |
int ok = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* unused member variable */
|
|
Packit Service |
31306d |
(void) expectnames;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr = calloc(1, sizeof(struct sftp_attributes_struct));
|
|
Packit Service |
31306d |
if (attr == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* This isn't really a loop, but it is like a try..catch.. */
|
|
Packit Service |
31306d |
do {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u32(buf, &flags) != 4) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
flags = ntohl(flags);
|
|
Packit Service |
31306d |
attr->flags = flags;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_SIZE) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u64(buf, &attr->size) != 8) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->size = ntohll(attr->size);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_OWNERGROUP) {
|
|
Packit Service |
31306d |
owner = ssh_buffer_get_ssh_string(buf);
|
|
Packit Service |
31306d |
if (owner == NULL) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->owner = ssh_string_to_char(owner);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(owner);
|
|
Packit Service |
31306d |
if (attr->owner == NULL) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
group = ssh_buffer_get_ssh_string(buf);
|
|
Packit Service |
31306d |
if (group == NULL) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->group = ssh_string_to_char(group);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(group);
|
|
Packit Service |
31306d |
if (attr->group == NULL) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u32(buf, &attr->permissions) != 4) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->permissions = ntohl(attr->permissions);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* FIXME on windows! */
|
|
Packit Service |
31306d |
switch (attr->permissions & SSH_S_IFMT) {
|
|
Packit Service |
31306d |
case SSH_S_IFSOCK:
|
|
Packit Service |
31306d |
case SSH_S_IFBLK:
|
|
Packit Service |
31306d |
case SSH_S_IFCHR:
|
|
Packit Service |
31306d |
case SSH_S_IFIFO:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_SPECIAL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_S_IFLNK:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_SYMLINK;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_S_IFREG:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_REGULAR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_S_IFDIR:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u64(buf, &attr->atime64) != 8) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->atime64 = ntohll(attr->atime64);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u32(buf, &attr->atime_nseconds) != 4) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->atime_nseconds = ntohl(attr->atime_nseconds);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_CREATETIME) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u64(buf, &attr->createtime) != 8) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->createtime = ntohll(attr->createtime);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u32(buf, &attr->createtime_nseconds) != 4) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->createtime_nseconds = ntohl(attr->createtime_nseconds);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_MODIFYTIME) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u64(buf, &attr->mtime64) != 8) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->mtime64 = ntohll(attr->mtime64);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u32(buf, &attr->mtime_nseconds) != 4) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->mtime_nseconds = ntohl(attr->mtime_nseconds);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_ACL) {
|
|
Packit Service |
31306d |
if ((attr->acl = ssh_buffer_get_ssh_string(buf)) == NULL) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
|
|
Packit Service |
31306d |
if (ssh_buffer_get_u32(buf,&attr->extended_count) != 4) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->extended_count = ntohl(attr->extended_count);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while(attr->extended_count &&
|
|
Packit Service |
31306d |
(attr->extended_type = ssh_buffer_get_ssh_string(buf)) &&
|
|
Packit Service |
31306d |
(attr->extended_data = ssh_buffer_get_ssh_string(buf))){
|
|
Packit Service |
31306d |
attr->extended_count--;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->extended_count) {
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ok = 1;
|
|
Packit Service |
31306d |
} while (0);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ok == 0) {
|
|
Packit Service |
31306d |
/* break issued somewhere */
|
|
Packit Service |
31306d |
SSH_STRING_FREE(attr->acl);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(attr->extended_type);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(attr->extended_data);
|
|
Packit Service |
31306d |
SAFE_FREE(attr->owner);
|
|
Packit Service |
31306d |
SAFE_FREE(attr->group);
|
|
Packit Service |
31306d |
SAFE_FREE(attr);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return attr;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
enum sftp_longname_field_e {
|
|
Packit Service |
31306d |
SFTP_LONGNAME_PERM = 0,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_FIXME,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_OWNER,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_GROUP,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_SIZE,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_DATE,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_TIME,
|
|
Packit Service |
31306d |
SFTP_LONGNAME_NAME,
|
|
Packit Service |
31306d |
};
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static char *sftp_parse_longname(const char *longname,
|
|
Packit Service |
31306d |
enum sftp_longname_field_e longname_field) {
|
|
Packit Service |
31306d |
const char *p, *q;
|
|
Packit Service |
31306d |
size_t len, field = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
p = longname;
|
|
Packit Service |
31306d |
/* Find the beginning of the field which is specified by sftp_longanme_field_e. */
|
|
Packit Service |
31306d |
while(field != longname_field) {
|
|
Packit Service |
31306d |
if(isspace(*p)) {
|
|
Packit Service |
31306d |
field++;
|
|
Packit Service |
31306d |
p++;
|
|
Packit Service |
31306d |
while(*p && isspace(*p)) {
|
|
Packit Service |
31306d |
p++;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
p++;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
q = p;
|
|
Packit Service |
31306d |
while (! isspace(*q)) {
|
|
Packit Service |
31306d |
q++;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
len = q - p;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return strndup(p, len);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* sftp version 0-3 code. It is different from the v4 */
|
|
Packit Service |
31306d |
/* maybe a paste of the draft is better than the code */
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
uint32 flags
|
|
Packit Service |
31306d |
uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
|
|
Packit Service |
31306d |
uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
|
|
Packit Service |
31306d |
uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
|
|
Packit Service |
31306d |
uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
|
|
Packit Service |
31306d |
uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
|
|
Packit Service |
31306d |
uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
|
|
Packit Service |
31306d |
uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
|
|
Packit Service |
31306d |
string extended_type
|
|
Packit Service |
31306d |
string extended_data
|
|
Packit Service |
31306d |
... more extended data (extended_type - extended_data pairs),
|
|
Packit Service |
31306d |
so that number of pairs equals extended_count */
|
|
Packit Service |
31306d |
static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
|
|
Packit Service |
31306d |
int expectname) {
|
|
Packit Service |
31306d |
sftp_attributes attr;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr = calloc(1, sizeof(struct sftp_attributes_struct));
|
|
Packit Service |
31306d |
if (attr == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (expectname) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "ss",
|
|
Packit Service |
31306d |
&attr->name,
|
|
Packit Service |
31306d |
&attr->longname);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL, "Name: %s", attr->name);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Set owner and group if we talk to openssh and have the longname */
|
|
Packit Service |
31306d |
if (ssh_get_openssh_version(sftp->session)) {
|
|
Packit Service |
31306d |
attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER);
|
|
Packit Service |
31306d |
if (attr->owner == NULL) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
|
|
Packit Service |
31306d |
if (attr->group == NULL) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "d", &attr->flags);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL,
|
|
Packit Service |
31306d |
"Flags: %.8"PRIx32"\n", (uint32_t) attr->flags);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->flags & SSH_FILEXFER_ATTR_SIZE) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "q", &attr->size);
|
|
Packit Service |
31306d |
if(rc != SSH_OK) {
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL,
|
|
Packit Service |
31306d |
"Size: %"PRIu64"\n",
|
|
Packit Service |
31306d |
(uint64_t) attr->size);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->flags & SSH_FILEXFER_ATTR_UIDGID) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "dd",
|
|
Packit Service |
31306d |
&attr->uid,
|
|
Packit Service |
31306d |
&attr->gid);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "d", &attr->permissions);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (attr->permissions & SSH_S_IFMT) {
|
|
Packit Service |
31306d |
case SSH_S_IFSOCK:
|
|
Packit Service |
31306d |
case SSH_S_IFBLK:
|
|
Packit Service |
31306d |
case SSH_S_IFCHR:
|
|
Packit Service |
31306d |
case SSH_S_IFIFO:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_SPECIAL;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_S_IFLNK:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_SYMLINK;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_S_IFREG:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_REGULAR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_S_IFDIR:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->flags & SSH_FILEXFER_ATTR_ACMODTIME) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "dd",
|
|
Packit Service |
31306d |
&attr->atime,
|
|
Packit Service |
31306d |
&attr->mtime);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->flags & SSH_FILEXFER_ATTR_EXTENDED) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "d", &attr->extended_count);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr->extended_count > 0){
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "ss",
|
|
Packit Service |
31306d |
&attr->extended_type,
|
|
Packit Service |
31306d |
&attr->extended_data);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
attr->extended_count--;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* just ignore the remaining extensions */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (attr->extended_count > 0){
|
|
Packit Service |
31306d |
ssh_string tmp1,tmp2;
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "SS", &tmp1, &tmp2);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
goto error;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(tmp1);
|
|
Packit Service |
31306d |
SAFE_FREE(tmp2);
|
|
Packit Service |
31306d |
attr->extended_count--;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return attr;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
error:
|
|
Packit Service |
31306d |
SSH_STRING_FREE(attr->extended_type);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(attr->extended_data);
|
|
Packit Service |
31306d |
SAFE_FREE(attr->name);
|
|
Packit Service |
31306d |
SAFE_FREE(attr->longname);
|
|
Packit Service |
31306d |
SAFE_FREE(attr->owner);
|
|
Packit Service |
31306d |
SAFE_FREE(attr->group);
|
|
Packit Service |
31306d |
SAFE_FREE(attr);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
uint32_t flags = (attr ? attr->flags : 0);
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID |
|
|
Packit Service |
31306d |
SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer, "d", flags);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (attr != NULL) {
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_SIZE) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer, "q", attr->size);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_UIDGID) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer, "dd", attr->uid, attr->gid);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer, "d", attr->permissions);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer, "dd", attr->atime, attr->mtime);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_attributes sftp_parse_attr(sftp_session session,
|
|
Packit Service |
31306d |
ssh_buffer buf,
|
|
Packit Service |
31306d |
int expectname)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
switch(session->version) {
|
|
Packit Service |
31306d |
case 4:
|
|
Packit Service |
31306d |
return sftp_parse_attr_4(session, buf, expectname);
|
|
Packit Service |
31306d |
case 3:
|
|
Packit Service |
31306d |
case 2:
|
|
Packit Service |
31306d |
case 1:
|
|
Packit Service |
31306d |
case 0:
|
|
Packit Service |
31306d |
return sftp_parse_attr_3(session, buf, expectname);
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(session->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Version %d unsupported by client", session->server_version);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Get the version of the SFTP protocol supported by the server */
|
|
Packit Service |
31306d |
int sftp_server_version(sftp_session sftp) {
|
|
Packit Service |
31306d |
return sftp->server_version;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Get a single file attributes structure of a directory. */
|
|
Packit Service |
31306d |
sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
sftp_attributes attr;
|
|
Packit Service |
31306d |
ssh_buffer payload;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (dir->buffer == NULL) {
|
|
Packit Service |
31306d |
payload = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (payload == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(payload,
|
|
Packit Service |
31306d |
"dS",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
dir->handle);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(payload);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_READDIR, payload);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(payload);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Sent a ssh_fxp_readdir with id %d", id);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type){
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_EOF:
|
|
Packit Service |
31306d |
dir->eof = 1;
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Unknown error status: %d", status->status);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
case SSH_FXP_NAME:
|
|
Packit Service |
31306d |
ssh_buffer_get_u32(msg->payload, &dir->count);
|
|
Packit Service |
31306d |
dir->count = ntohl(dir->count);
|
|
Packit Service |
31306d |
dir->buffer = msg->payload;
|
|
Packit Service |
31306d |
msg->payload = NULL;
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Unsupported message back %d", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* now dir->buffer contains a buffer and dir->count != 0 */
|
|
Packit Service |
31306d |
if (dir->count == 0) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Count of files sent by the server is zero, which is invalid, or "
|
|
Packit Service |
31306d |
"libsftp bug");
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PROTOCOL, "Count is %d", dir->count);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr = sftp_parse_attr(sftp, dir->buffer, 1);
|
|
Packit Service |
31306d |
if (attr == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Couldn't parse the SFTP attributes");
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
dir->count--;
|
|
Packit Service |
31306d |
if (dir->count == 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(dir->buffer);
|
|
Packit Service |
31306d |
dir->buffer = NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return attr;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Tell if the directory has reached EOF (End Of File). */
|
|
Packit Service |
31306d |
int sftp_dir_eof(sftp_dir dir) {
|
|
Packit Service |
31306d |
return dir->eof;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Free a SFTP_ATTRIBUTE handle */
|
|
Packit Service |
31306d |
void sftp_attributes_free(sftp_attributes file){
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_STRING_FREE(file->acl);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(file->extended_data);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(file->extended_type);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(file->name);
|
|
Packit Service |
31306d |
SAFE_FREE(file->longname);
|
|
Packit Service |
31306d |
SAFE_FREE(file->group);
|
|
Packit Service |
31306d |
SAFE_FREE(file->owner);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(file);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static int sftp_handle_close(sftp_session sftp, ssh_string handle)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer = NULL;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dS",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
handle);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_CLOSE, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp,id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if(status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d during sftp_handle_close!", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Close an open file handle. */
|
|
Packit Service |
31306d |
int sftp_close(sftp_file file){
|
|
Packit Service |
31306d |
int err = SSH_NO_ERROR;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(file->name);
|
|
Packit Service |
31306d |
if (file->handle){
|
|
Packit Service |
31306d |
err = sftp_handle_close(file->sftp,file->handle);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(file->handle);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* FIXME: check server response and implement errno */
|
|
Packit Service |
31306d |
SAFE_FREE(file);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return err;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Close an open directory. */
|
|
Packit Service |
31306d |
int sftp_closedir(sftp_dir dir){
|
|
Packit Service |
31306d |
int err = SSH_NO_ERROR;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(dir->name);
|
|
Packit Service |
31306d |
if (dir->handle) {
|
|
Packit Service |
31306d |
err = sftp_handle_close(dir->sftp, dir->handle);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(dir->handle);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* FIXME: check server response and implement errno */
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(dir->buffer);
|
|
Packit Service |
31306d |
SAFE_FREE(dir);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return err;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Open a file on the server. */
|
|
Packit Service |
31306d |
sftp_file sftp_open(sftp_session sftp,
|
|
Packit Service |
31306d |
const char *file,
|
|
Packit Service |
31306d |
int flags,
|
|
Packit Service |
31306d |
mode_t mode)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
struct sftp_attributes_struct attr;
|
|
Packit Service |
31306d |
sftp_file handle;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
sftp_attributes stat_data;
|
|
Packit Service |
31306d |
uint32_t sftp_flags = 0;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ZERO_STRUCT(attr);
|
|
Packit Service |
31306d |
attr.permissions = mode;
|
|
Packit Service |
31306d |
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if ((flags & O_RDWR) == O_RDWR) {
|
|
Packit Service |
31306d |
sftp_flags |= (SSH_FXF_WRITE | SSH_FXF_READ);
|
|
Packit Service |
31306d |
} else if ((flags & O_WRONLY) == O_WRONLY) {
|
|
Packit Service |
31306d |
sftp_flags |= SSH_FXF_WRITE;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
sftp_flags |= SSH_FXF_READ;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if ((flags & O_CREAT) == O_CREAT)
|
|
Packit Service |
31306d |
sftp_flags |= SSH_FXF_CREAT;
|
|
Packit Service |
31306d |
if ((flags & O_TRUNC) == O_TRUNC)
|
|
Packit Service |
31306d |
sftp_flags |= SSH_FXF_TRUNC;
|
|
Packit Service |
31306d |
if ((flags & O_EXCL) == O_EXCL)
|
|
Packit Service |
31306d |
sftp_flags |= SSH_FXF_EXCL;
|
|
Packit Service |
31306d |
if ((flags & O_APPEND) == O_APPEND) {
|
|
Packit Service |
31306d |
sftp_flags |= SSH_FXF_APPEND;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags);
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dsd",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
file,
|
|
Packit Service |
31306d |
sftp_flags);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = buffer_add_attributes(buffer, &attr);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_OPEN, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
case SSH_FXP_HANDLE:
|
|
Packit Service |
31306d |
handle = parse_handle_msg(msg);
|
|
Packit Service |
31306d |
if (handle == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if ((flags & O_APPEND) == O_APPEND) {
|
|
Packit Service |
31306d |
stat_data = sftp_stat(sftp, file);
|
|
Packit Service |
31306d |
if (stat_data == NULL) {
|
|
Packit Service |
31306d |
sftp_close(handle);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if ((stat_data->flags & SSH_FILEXFER_ATTR_SIZE) != SSH_FILEXFER_ATTR_SIZE) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_FATAL,
|
|
Packit Service |
31306d |
"Cannot open in append mode. Unknown file size.");
|
|
Packit Service |
31306d |
sftp_close(handle);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
handle->offset = stat_data->size;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
return handle;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d during open!", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void sftp_file_set_nonblocking(sftp_file handle){
|
|
Packit Service |
31306d |
handle->nonblocking=1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
void sftp_file_set_blocking(sftp_file handle){
|
|
Packit Service |
31306d |
handle->nonblocking=0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Read from a file using an opened sftp file handle. */
|
|
Packit Service |
31306d |
ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
|
|
Packit Service |
31306d |
sftp_session sftp = handle->sftp;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
ssh_string datastring;
|
|
Packit Service |
31306d |
size_t datalen;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (handle->eof) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(handle->sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dSqd",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
handle->handle,
|
|
Packit Service |
31306d |
handle->offset,
|
|
Packit Service |
31306d |
count);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (handle->nonblocking) {
|
|
Packit Service |
31306d |
if (ssh_channel_poll(handle->sftp->channel, 0) == 0) {
|
|
Packit Service |
31306d |
/* we cannot block */
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(handle->sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(handle->sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_EOF:
|
|
Packit Service |
31306d |
handle->eof = 1;
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
case SSH_FXP_DATA:
|
|
Packit Service |
31306d |
datastring = ssh_buffer_get_ssh_string(msg->payload);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (datastring == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received invalid DATA packet from sftp server");
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
datalen = ssh_string_len(datastring);
|
|
Packit Service |
31306d |
if (datalen > count) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received a too big DATA packet from sftp server: "
|
|
Packit Service |
31306d |
"%" PRIdS " and asked for %" PRIdS,
|
|
Packit Service |
31306d |
datalen, count);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(datastring);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
handle->offset += (uint64_t)datalen;
|
|
Packit Service |
31306d |
memcpy(buf, ssh_string_data(datastring), datalen);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(datastring);
|
|
Packit Service |
31306d |
return datalen;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d during read!", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1; /* not reached */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Start an asynchronous read from a file using an opened sftp file handle. */
|
|
Packit Service |
31306d |
int sftp_async_read_begin(sftp_file file, uint32_t len){
|
|
Packit Service |
31306d |
sftp_session sftp = file->sftp;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dSqd",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
file->handle,
|
|
Packit Service |
31306d |
file->offset,
|
|
Packit Service |
31306d |
len);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
file->offset += len; /* assume we'll read len bytes */
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return id;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Wait for an asynchronous read to complete and save the data. */
|
|
Packit Service |
31306d |
int sftp_async_read(sftp_file file, void *data, uint32_t size, uint32_t id){
|
|
Packit Service |
31306d |
sftp_session sftp;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
ssh_string datastring;
|
|
Packit Service |
31306d |
int err = SSH_OK;
|
|
Packit Service |
31306d |
uint32_t len;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp = file->sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (file->eof) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* handle an existing request */
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (file->nonblocking){
|
|
Packit Service |
31306d |
if (ssh_channel_poll(sftp->channel, 0) == 0) {
|
|
Packit Service |
31306d |
/* we cannot block */
|
|
Packit Service |
31306d |
return SSH_AGAIN;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp,id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
if (status->status != SSH_FX_EOF) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server : %s", status->errormsg);
|
|
Packit Service |
31306d |
err = SSH_ERROR;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
file->eof = 1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return err;
|
|
Packit Service |
31306d |
case SSH_FXP_DATA:
|
|
Packit Service |
31306d |
datastring = ssh_buffer_get_ssh_string(msg->payload);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (datastring == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received invalid DATA packet from sftp server");
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (ssh_string_len(datastring) > size) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received a too big DATA packet from sftp server: "
|
|
Packit Service |
31306d |
"%" PRIdS " and asked for %u",
|
|
Packit Service |
31306d |
ssh_string_len(datastring), size);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(datastring);
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
len = ssh_string_len(datastring);
|
|
Packit Service |
31306d |
/* Update the offset with the correct value */
|
|
Packit Service |
31306d |
file->offset = file->offset - (size - len);
|
|
Packit Service |
31306d |
memcpy(data, ssh_string_data(datastring), len);
|
|
Packit Service |
31306d |
SSH_STRING_FREE(datastring);
|
|
Packit Service |
31306d |
return len;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
|
|
Packit Service |
31306d |
sftp_session sftp = file->sftp;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
ssize_t len;
|
|
Packit Service |
31306d |
size_t packetlen;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(file->sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dSqdP",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
file->handle,
|
|
Packit Service |
31306d |
file->offset,
|
|
Packit Service |
31306d |
count, /* len of datastring */
|
|
Packit Service |
31306d |
(size_t)count, buf);
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
packetlen=ssh_buffer_get_len(buffer);
|
|
Packit Service |
31306d |
len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (len < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else if ((size_t)len != packetlen) {
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Could not write as much data as expected");
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(file->sftp) < 0) {
|
|
Packit Service |
31306d |
/* something nasty has happened */
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(file->sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
switch (msg->packet_type) {
|
|
Packit Service |
31306d |
case SSH_FXP_STATUS:
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
file->offset += count;
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return count;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
file->offset += count;
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d during write!", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1; /* not reached */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Seek to a specific location in a file. */
|
|
Packit Service |
31306d |
int sftp_seek(sftp_file file, uint32_t new_offset) {
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
file->offset = new_offset;
|
|
Packit Service |
31306d |
file->eof = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int sftp_seek64(sftp_file file, uint64_t new_offset) {
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
file->offset = new_offset;
|
|
Packit Service |
31306d |
file->eof = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Report current byte position in file. */
|
|
Packit Service |
31306d |
unsigned long sftp_tell(sftp_file file) {
|
|
Packit Service |
31306d |
return (unsigned long)file->offset;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* Report current byte position in file. */
|
|
Packit Service |
31306d |
uint64_t sftp_tell64(sftp_file file) {
|
|
Packit Service |
31306d |
return (uint64_t) file->offset;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Rewinds the position of the file pointer to the beginning of the file.*/
|
|
Packit Service |
31306d |
void sftp_rewind(sftp_file file) {
|
|
Packit Service |
31306d |
file->offset = 0;
|
|
Packit Service |
31306d |
file->eof = 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* code written by Nick */
|
|
Packit Service |
31306d |
int sftp_unlink(sftp_session sftp, const char *file) {
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
file);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp)) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
/* by specification, this command's only supposed to return SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* The status should be SSH_FX_OK if the command was successful, if it
|
|
Packit Service |
31306d |
* didn't, then there was an error
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to remove file", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* code written by Nick */
|
|
Packit Service |
31306d |
int sftp_rmdir(sftp_session sftp, const char *directory) {
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
directory);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* By specification, this command returns SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to remove directory",
|
|
Packit Service |
31306d |
msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Code written by Nick */
|
|
Packit Service |
31306d |
int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_attributes errno_attr = NULL;
|
|
Packit Service |
31306d |
struct sftp_attributes_struct attr;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ZERO_STRUCT(attr);
|
|
Packit Service |
31306d |
attr.permissions = mode;
|
|
Packit Service |
31306d |
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
directory);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = buffer_add_attributes(buffer, &attr);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* By specification, this command only returns SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_FAILURE:
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* mkdir always returns a failure, even if the path already exists.
|
|
Packit Service |
31306d |
* To be POSIX conform and to be able to map it to EEXIST a stat
|
|
Packit Service |
31306d |
* call is needed here.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
errno_attr = sftp_lstat(sftp, directory);
|
|
Packit Service |
31306d |
if (errno_attr != NULL) {
|
|
Packit Service |
31306d |
SAFE_FREE(errno_attr);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FILE_ALREADY_EXISTS);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* The status should be SSH_FX_OK if the command was successful, if it
|
|
Packit Service |
31306d |
* didn't, then there was an error
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to make directory",
|
|
Packit Service |
31306d |
msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* code written by nick */
|
|
Packit Service |
31306d |
int sftp_rename(sftp_session sftp, const char *original, const char *newname) {
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dss",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
original,
|
|
Packit Service |
31306d |
newname);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp->version >= 4){
|
|
Packit Service |
31306d |
/* POSIX rename atomically replaces newpath, we should do the same
|
|
Packit Service |
31306d |
* only available on >=v4 */
|
|
Packit Service |
31306d |
ssh_buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* By specification, this command only returns SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* Status should be SSH_FX_OK if the command was successful, if it didn't,
|
|
Packit Service |
31306d |
* then there was an error
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to rename",
|
|
Packit Service |
31306d |
msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Code written by Nick */
|
|
Packit Service |
31306d |
/* Set file attributes on a file, directory or symbolic link. */
|
|
Packit Service |
31306d |
int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
file);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = buffer_add_attributes(buffer, attr);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* By specification, this command only returns SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* The status should be SSH_FX_OK if the command was successful, if it
|
|
Packit Service |
31306d |
* didn't, then there was an error
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to set stats", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Change the file owner and group */
|
|
Packit Service |
31306d |
int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t group) {
|
|
Packit Service |
31306d |
struct sftp_attributes_struct attr;
|
|
Packit Service |
31306d |
ZERO_STRUCT(attr);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr.uid = owner;
|
|
Packit Service |
31306d |
attr.gid = group;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr.flags = SSH_FILEXFER_ATTR_UIDGID;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp_setstat(sftp, file, &attr);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Change permissions of a file */
|
|
Packit Service |
31306d |
int sftp_chmod(sftp_session sftp, const char *file, mode_t mode) {
|
|
Packit Service |
31306d |
struct sftp_attributes_struct attr;
|
|
Packit Service |
31306d |
ZERO_STRUCT(attr);
|
|
Packit Service |
31306d |
attr.permissions = mode;
|
|
Packit Service |
31306d |
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp_setstat(sftp, file, &attr);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Change the last modification and access time of a file. */
|
|
Packit Service |
31306d |
int sftp_utimes(sftp_session sftp, const char *file,
|
|
Packit Service |
31306d |
const struct timeval *times) {
|
|
Packit Service |
31306d |
struct sftp_attributes_struct attr;
|
|
Packit Service |
31306d |
ZERO_STRUCT(attr);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr.atime = times[0].tv_sec;
|
|
Packit Service |
31306d |
attr.atime_nseconds = times[0].tv_usec;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr.mtime = times[1].tv_sec;
|
|
Packit Service |
31306d |
attr.mtime_nseconds = times[1].tv_usec;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME |
|
|
Packit Service |
31306d |
SSH_FILEXFER_ATTR_SUBSECOND_TIMES;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return sftp_setstat(sftp, file, &attr);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int sftp_symlink(sftp_session sftp, const char *target, const char *dest) {
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL)
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
if (target == NULL || dest == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* TODO check for version number if they ever fix it. */
|
|
Packit Service |
31306d |
if (ssh_get_openssh_version(sftp->session)) {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dss",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
target,
|
|
Packit Service |
31306d |
dest);
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dss",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
dest,
|
|
Packit Service |
31306d |
target);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (rc != SSH_OK){
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) {
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* By specification, this command only returns SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* The status should be SSH_FX_OK if the command was successful, if it
|
|
Packit Service |
31306d |
* didn't, then there was an error
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to set stats", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
char *sftp_readlink(sftp_session sftp, const char *path)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (path == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp->version < 3){
|
|
Packit Service |
31306d |
ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_readlink",sftp->version);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
path);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_READLINK, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_NAME) {
|
|
Packit Service |
31306d |
uint32_t ignored = 0;
|
|
Packit Service |
31306d |
char *lnk = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(msg->payload,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
&ignored,
|
|
Packit Service |
31306d |
&lnk;;
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_ERROR,
|
|
Packit Service |
31306d |
"Failed to retrieve link");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return lnk;
|
|
Packit Service |
31306d |
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
} else { /* this shouldn't happen */
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to set stats", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) {
|
|
Packit Service |
31306d |
sftp_statvfs_t statvfs;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
statvfs = calloc(1, sizeof(struct sftp_statvfs_struct));
|
|
Packit Service |
31306d |
if (statvfs == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(buf, "qqqqqqqqqqq",
|
|
Packit Service |
31306d |
&statvfs->f_bsize, /* file system block size */
|
|
Packit Service |
31306d |
&statvfs->f_frsize, /* fundamental fs block size */
|
|
Packit Service |
31306d |
&statvfs->f_blocks, /* number of blocks (unit f_frsize) */
|
|
Packit Service |
31306d |
&statvfs->f_bfree, /* free blocks in file system */
|
|
Packit Service |
31306d |
&statvfs->f_bavail, /* free blocks for non-root */
|
|
Packit Service |
31306d |
&statvfs->f_files, /* total file inodes */
|
|
Packit Service |
31306d |
&statvfs->f_ffree, /* free file inodes */
|
|
Packit Service |
31306d |
&statvfs->f_favail, /* free file inodes for to non-root */
|
|
Packit Service |
31306d |
&statvfs->f_fsid, /* file system id */
|
|
Packit Service |
31306d |
&statvfs->f_flag, /* bit mask of f_flag values */
|
|
Packit Service |
31306d |
&statvfs->f_namemax/* maximum filename length */
|
|
Packit Service |
31306d |
);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
SAFE_FREE(statvfs);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL, "Invalid statvfs structure");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return statvfs;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL)
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
if (path == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (sftp->version < 3){
|
|
Packit Service |
31306d |
ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_statvfs",sftp->version);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dss",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
"statvfs@openssh.com",
|
|
Packit Service |
31306d |
path);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
|
|
Packit Service |
31306d |
sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (buf == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return buf;
|
|
Packit Service |
31306d |
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
} else { /* this shouldn't happen */
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to get statvfs", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int sftp_fsync(sftp_file file)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_session sftp;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp = file->sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dsS",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
"fsync@openssh.com",
|
|
Packit Service |
31306d |
file->handle);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
goto done;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
goto done;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
do {
|
|
Packit Service |
31306d |
rc = sftp_read_and_dispatch(sftp);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
rc = -1;
|
|
Packit Service |
31306d |
goto done;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
} while (msg == NULL);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* By specification, this command only returns SSH_FXP_STATUS */
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
sftp_status_message status;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
rc = -1;
|
|
Packit Service |
31306d |
goto done;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
switch (status->status) {
|
|
Packit Service |
31306d |
case SSH_FX_OK:
|
|
Packit Service |
31306d |
/* SUCCESS, LEAVE */
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
rc = 0;
|
|
Packit Service |
31306d |
goto done;
|
|
Packit Service |
31306d |
default:
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* The status should be SSH_FX_OK if the command was successful, if it
|
|
Packit Service |
31306d |
* didn't, then there was an error
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s",
|
|
Packit Service |
31306d |
status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = -1;
|
|
Packit Service |
31306d |
goto done;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to set stats",
|
|
Packit Service |
31306d |
msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = -1;
|
|
Packit Service |
31306d |
done:
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return rc;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_statvfs_t sftp_fstatvfs(sftp_file file)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
sftp_session sftp;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp = file->sftp;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dsS",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
"fstatvfs@openssh.com",
|
|
Packit Service |
31306d |
file->handle);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
|
|
Packit Service |
31306d |
sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (buf == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return buf;
|
|
Packit Service |
31306d |
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
} else { /* this shouldn't happen */
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to set stats", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
void sftp_statvfs_free(sftp_statvfs_t statvfs) {
|
|
Packit Service |
31306d |
if (statvfs == NULL) {
|
|
Packit Service |
31306d |
return;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(statvfs);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* another code written by Nick */
|
|
Packit Service |
31306d |
char *sftp_canonicalize_path(sftp_session sftp, const char *path)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL)
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
if (path == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
path);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_NAME) {
|
|
Packit Service |
31306d |
uint32_t ignored = 0;
|
|
Packit Service |
31306d |
char *cname = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_unpack(msg->payload,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
&ignored,
|
|
Packit Service |
31306d |
&cname);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session,
|
|
Packit Service |
31306d |
SSH_ERROR,
|
|
Packit Service |
31306d |
"Failed to parse canonicalized path");
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return cname;
|
|
Packit Service |
31306d |
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
} else { /* this shouldn't happen */
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received message %d when attempting to set stats", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
static sftp_attributes sftp_xstat(sftp_session sftp,
|
|
Packit Service |
31306d |
const char *path,
|
|
Packit Service |
31306d |
int param)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (sftp == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (path == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_invalid(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"ds",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
path);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(sftp, param, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(sftp) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_ATTRS) {
|
|
Packit Service |
31306d |
sftp_attributes attr = sftp_parse_attr(sftp, msg->payload, 0);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return attr;
|
|
Packit Service |
31306d |
} else if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ssh_set_error(sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received mesg %d during stat()", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_attributes sftp_stat(sftp_session session, const char *path) {
|
|
Packit Service |
31306d |
return sftp_xstat(session, path, SSH_FXP_STAT);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_attributes sftp_lstat(sftp_session session, const char *path) {
|
|
Packit Service |
31306d |
return sftp_xstat(session, path, SSH_FXP_LSTAT);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
sftp_attributes sftp_fstat(sftp_file file)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
sftp_status_message status = NULL;
|
|
Packit Service |
31306d |
sftp_message msg = NULL;
|
|
Packit Service |
31306d |
ssh_buffer buffer;
|
|
Packit Service |
31306d |
uint32_t id;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = ssh_buffer_new();
|
|
Packit Service |
31306d |
if (buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(file->sftp->session);
|
|
Packit Service |
31306d |
sftp_set_error(file->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
id = sftp_get_new_id(file->sftp);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_buffer_pack(buffer,
|
|
Packit Service |
31306d |
"dS",
|
|
Packit Service |
31306d |
id,
|
|
Packit Service |
31306d |
file->handle);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(file->sftp->session);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
sftp_set_error(file->sftp, SSH_FX_FAILURE);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer);
|
|
Packit Service |
31306d |
SSH_BUFFER_FREE(buffer);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (msg == NULL) {
|
|
Packit Service |
31306d |
if (sftp_read_and_dispatch(file->sftp) < 0) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
msg = sftp_dequeue(file->sftp, id);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (msg->packet_type == SSH_FXP_ATTRS){
|
|
Packit Service |
31306d |
sftp_attributes attr = sftp_parse_attr(file->sftp, msg->payload, 0);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return attr;
|
|
Packit Service |
31306d |
} else if (msg->packet_type == SSH_FXP_STATUS) {
|
|
Packit Service |
31306d |
status = parse_status_msg(msg);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
if (status == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
sftp_set_error(file->sftp, status->status);
|
|
Packit Service |
31306d |
ssh_set_error(file->sftp->session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"SFTP server: %s", status->errormsg);
|
|
Packit Service |
31306d |
status_msg_free(status);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
ssh_set_error(file->sftp->session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Received msg %d during fstat()", msg->packet_type);
|
|
Packit Service |
31306d |
sftp_message_free(msg);
|
|
Packit Service |
31306d |
sftp_set_error(file->sftp, SSH_FX_BAD_MESSAGE);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#endif /* WITH_SFTP */
|