2
* sftp.c - Secure FTP functions
4
* This file is part of the SSH Library
6
* Copyright (c) 2005-2008 by Aris Adamantiadis
7
* Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
9
* The SSH Library is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU Lesser General Public License as published by
11
* the Free Software Foundation; either version 2.1 of the License, or (at your
12
* option) any later version.
14
* The SSH Library is distributed in the hope that it will be useful, but
15
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17
* License for more details.
19
* You should have received a copy of the GNU Lesser General Public License
20
* along with the SSH Library; see the file COPYING. If not, write to
21
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25
/* This file contains code written by Nick Zitzmann */
33
#include <sys/types.h>
37
#include <arpa/inet.h>
39
#define S_IFSOCK 0140000
40
#define S_IFLNK 0120000
43
#define S_IFBLK 0060000
44
#define S_IFIFO 0010000
48
#include "libssh/priv.h"
49
#include "libssh/ssh2.h"
50
#include "libssh/sftp.h"
51
#include "libssh/buffer.h"
52
#include "libssh/channels.h"
53
#include "libssh/session.h"
54
#include "libssh/misc.h"
58
#define sftp_enter_function() _enter_function(sftp->channel->session)
59
#define sftp_leave_function() _leave_function(sftp->channel->session)
61
struct sftp_ext_struct {
68
static int sftp_enqueue(sftp_session session, sftp_message msg);
69
static void sftp_message_free(sftp_message msg);
70
static void sftp_set_error(sftp_session sftp, int errnum);
71
static void status_msg_free(sftp_status_message status);
73
static sftp_ext sftp_ext_new(void) {
76
ext = malloc(sizeof(struct sftp_ext_struct));
85
static void sftp_ext_free(sftp_ext ext) {
93
for (i = 0; i < ext->count; i++) {
94
SAFE_FREE(ext->name[i]);
95
SAFE_FREE(ext->data[i]);
104
sftp_session sftp_new(ssh_session session){
109
if (session == NULL) {
114
sftp = malloc(sizeof(struct sftp_session_struct));
116
ssh_set_error_oom(session);
122
sftp->ext = sftp_ext_new();
123
if (sftp->ext == NULL) {
124
ssh_set_error_oom(session);
126
sftp_leave_function();
130
sftp->session = session;
131
sftp->channel = channel_new(session);
132
if (sftp->channel == NULL) {
138
if (channel_open_session(sftp->channel)) {
139
channel_free(sftp->channel);
145
if (channel_request_sftp(sftp->channel)) {
156
sftp_session sftp_server_new(ssh_session session, ssh_channel chan){
157
sftp_session sftp = NULL;
159
sftp = malloc(sizeof(struct sftp_session_struct));
161
ssh_set_error_oom(session);
166
sftp->session = session;
167
sftp->channel = chan;
172
int sftp_server_init(sftp_session sftp){
173
ssh_session session = sftp->session;
174
sftp_packet packet = NULL;
175
ssh_buffer reply = NULL;
178
sftp_enter_function();
180
packet = sftp_packet_read(sftp);
181
if (packet == NULL) {
182
sftp_leave_function();
186
if (packet->type != SSH_FXP_INIT) {
187
ssh_set_error(session, SSH_FATAL,
188
"Packet read of type %d instead of SSH_FXP_INIT",
191
sftp_packet_free(packet);
192
sftp_leave_function();
196
ssh_log(session, SSH_LOG_PACKET, "Received SSH_FXP_INIT");
198
buffer_get_u32(packet->payload, &version);
199
version = ntohl(version);
200
ssh_log(session, SSH_LOG_PACKET, "Client version: %d", version);
201
sftp->client_version = version;
203
sftp_packet_free(packet);
205
reply = buffer_new();
207
ssh_set_error_oom(session);
208
sftp_leave_function();
212
if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) {
213
ssh_set_error_oom(session);
215
sftp_leave_function();
219
if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
221
sftp_leave_function();
226
ssh_log(session, SSH_LOG_RARE, "Server version sent");
228
if (version > LIBSFTP_VERSION) {
229
sftp->version = LIBSFTP_VERSION;
231
sftp->version=version;
234
sftp_leave_function();
237
#endif /* WITH_SERVER */
239
void sftp_free(sftp_session sftp){
240
sftp_request_queue ptr;
246
channel_send_eof(sftp->channel);
249
sftp_request_queue old;
250
sftp_message_free(ptr->message);
256
channel_free(sftp->channel);
257
sftp_ext_free(sftp->ext);
263
int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
266
if (buffer_prepend_data(payload, &type, sizeof(uint8_t)) < 0) {
267
ssh_set_error_oom(sftp->session);
271
size = htonl(buffer_get_len(payload));
272
if (buffer_prepend_data(payload, &size, sizeof(uint32_t)) < 0) {
273
ssh_set_error_oom(sftp->session);
277
size = channel_write(sftp->channel, buffer_get(payload),
278
buffer_get_len(payload));
281
} else if((uint32_t) size != buffer_get_len(payload)) {
282
ssh_log(sftp->session, SSH_LOG_PACKET,
283
"Had to write %d bytes, wrote only %d",
284
buffer_get_len(payload),
291
sftp_packet sftp_packet_read(sftp_session sftp) {
292
sftp_packet packet = NULL;
295
sftp_enter_function();
297
packet = malloc(sizeof(struct sftp_packet_struct));
298
if (packet == NULL) {
299
ssh_set_error_oom(sftp->session);
303
packet->payload = buffer_new();
304
if (packet->payload == NULL) {
305
ssh_set_error_oom(sftp->session);
310
if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
311
buffer_free(packet->payload);
313
sftp_leave_function();
317
if (buffer_get_u32(packet->payload, &size) != sizeof(uint32_t)) {
318
ssh_set_error(sftp->session, SSH_FATAL, "Short sftp packet!");
319
buffer_free(packet->payload);
321
sftp_leave_function();
326
if (channel_read_buffer(sftp->channel, packet->payload, 1, 0) <= 0) {
327
/* TODO: check if there are cases where an error needs to be set here */
328
buffer_free(packet->payload);
330
sftp_leave_function();
334
buffer_get_u8(packet->payload, &packet->type);
336
if (channel_read_buffer(sftp->channel, packet->payload, size - 1, 0) <= 0) {
337
/* TODO: check if there are cases where an error needs to be set here */
338
buffer_free(packet->payload);
340
sftp_leave_function();
345
sftp_leave_function();
349
static void sftp_set_error(sftp_session sftp, int errnum) {
351
sftp->errnum = errnum;
355
/* Get the last sftp error */
356
int sftp_get_error(sftp_session sftp) {
364
static sftp_message sftp_message_new(sftp_session sftp){
365
sftp_message msg = NULL;
367
sftp_enter_function();
369
msg = malloc(sizeof(struct sftp_message_struct));
371
ssh_set_error_oom(sftp->session);
376
msg->payload = buffer_new();
377
if (msg->payload == NULL) {
378
ssh_set_error_oom(sftp->session);
384
sftp_leave_function();
388
static void sftp_message_free(sftp_message msg) {
396
sftp_enter_function();
398
buffer_free(msg->payload);
401
sftp_leave_function();
404
static sftp_message sftp_get_message(sftp_packet packet) {
405
sftp_session sftp = packet->sftp;
406
sftp_message msg = NULL;
408
sftp_enter_function();
410
msg = sftp_message_new(sftp);
412
sftp_leave_function();
416
msg->sftp = packet->sftp;
417
msg->packet_type = packet->type;
419
if ((packet->type != SSH_FXP_STATUS) && (packet->type!=SSH_FXP_HANDLE) &&
420
(packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS) &&
421
(packet->type != SSH_FXP_NAME) && (packet->type != SSH_FXP_EXTENDED_REPLY)) {
422
ssh_set_error(packet->sftp->session, SSH_FATAL,
423
"Unknown packet type %d", packet->type);
424
sftp_message_free(msg);
425
sftp_leave_function();
429
if (buffer_get_u32(packet->payload, &msg->id) != sizeof(uint32_t)) {
430
ssh_set_error(packet->sftp->session, SSH_FATAL,
431
"Invalid packet %d: no ID", packet->type);
432
sftp_message_free(msg);
433
sftp_leave_function();
437
ssh_log(packet->sftp->session, SSH_LOG_PACKET,
438
"Packet with id %d type %d",
442
if (buffer_add_data(msg->payload, buffer_get_rest(packet->payload),
443
buffer_get_rest_len(packet->payload)) < 0) {
444
ssh_set_error_oom(sftp->session);
445
sftp_message_free(msg);
446
sftp_leave_function();
450
sftp_leave_function();
454
static int sftp_read_and_dispatch(sftp_session sftp) {
455
sftp_packet packet = NULL;
456
sftp_message msg = NULL;
458
sftp_enter_function();
460
packet = sftp_packet_read(sftp);
461
if (packet == NULL) {
462
sftp_leave_function();
463
return -1; /* something nasty happened reading the packet */
466
msg = sftp_get_message(packet);
467
sftp_packet_free(packet);
469
sftp_leave_function();
473
if (sftp_enqueue(sftp, msg) < 0) {
474
sftp_message_free(msg);
475
sftp_leave_function();
479
sftp_leave_function();
483
void sftp_packet_free(sftp_packet packet) {
484
if (packet == NULL) {
488
buffer_free(packet->payload);
492
/* Initialize the sftp session with the server. */
493
int sftp_init(sftp_session sftp) {
494
sftp_packet packet = NULL;
495
ssh_buffer buffer = NULL;
496
ssh_string ext_name_s = NULL;
497
ssh_string ext_data_s = NULL;
498
char *ext_name = NULL;
499
char *ext_data = NULL;
500
uint32_t version = htonl(LIBSFTP_VERSION);
502
sftp_enter_function();
504
buffer = buffer_new();
505
if (buffer == NULL) {
506
ssh_set_error_oom(sftp->session);
507
sftp_leave_function();
511
if (buffer_add_u32(buffer, version) < 0) {
512
ssh_set_error_oom(sftp->session);
514
sftp_leave_function();
517
if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
519
sftp_leave_function();
524
packet = sftp_packet_read(sftp);
525
if (packet == NULL) {
526
sftp_leave_function();
530
if (packet->type != SSH_FXP_VERSION) {
531
ssh_set_error(sftp->session, SSH_FATAL,
532
"Received a %d messages instead of SSH_FXP_VERSION", packet->type);
533
sftp_packet_free(packet);
534
sftp_leave_function();
538
/* TODO: are we sure there are 4 bytes ready? */
539
buffer_get_u32(packet->payload, &version);
540
version = ntohl(version);
541
ssh_log(sftp->session, SSH_LOG_RARE,
542
"SFTP server version %d",
545
ext_name_s = buffer_get_ssh_string(packet->payload);
546
while (ext_name_s != NULL) {
547
int count = sftp->ext->count;
550
ext_data_s = buffer_get_ssh_string(packet->payload);
551
if (ext_data_s == NULL) {
552
string_free(ext_name_s);
556
ext_name = string_to_char(ext_name_s);
557
ext_data = string_to_char(ext_data_s);
558
if (ext_name == NULL || ext_data == NULL) {
559
ssh_set_error_oom(sftp->session);
562
string_free(ext_name_s);
563
string_free(ext_data_s);
566
ssh_log(sftp->session, SSH_LOG_RARE,
567
"SFTP server extension: %s, version: %s",
571
tmp = realloc(sftp->ext->name, count * sizeof(char *));
573
ssh_set_error_oom(sftp->session);
576
string_free(ext_name_s);
577
string_free(ext_data_s);
580
tmp[count - 1] = ext_name;
581
sftp->ext->name = tmp;
583
tmp = realloc(sftp->ext->data, count * sizeof(char *));
585
ssh_set_error_oom(sftp->session);
588
string_free(ext_name_s);
589
string_free(ext_data_s);
592
tmp[count - 1] = ext_data;
593
sftp->ext->data = tmp;
595
sftp->ext->count = count;
597
string_free(ext_name_s);
598
string_free(ext_data_s);
600
ext_name_s = buffer_get_ssh_string(packet->payload);
603
sftp_packet_free(packet);
605
sftp->version = sftp->server_version = version;
607
sftp_leave_function();
612
unsigned int sftp_extensions_get_count(sftp_session sftp) {
613
if (sftp == NULL || sftp->ext == NULL) {
617
return sftp->ext->count;
620
const char *sftp_extensions_get_name(sftp_session sftp, unsigned int idx) {
623
if (sftp->ext == NULL || sftp->ext->name == NULL) {
624
ssh_set_error_invalid(sftp->session, __FUNCTION__);
628
if (idx > sftp->ext->count) {
629
ssh_set_error_invalid(sftp->session, __FUNCTION__);
633
return sftp->ext->name[idx];
636
const char *sftp_extensions_get_data(sftp_session sftp, unsigned int idx) {
639
if (sftp->ext == NULL || sftp->ext->name == NULL) {
640
ssh_set_error_invalid(sftp->session, __FUNCTION__);
644
if (idx > sftp->ext->count) {
645
ssh_set_error_invalid(sftp->session, __FUNCTION__);
649
return sftp->ext->data[idx];
652
int sftp_extension_supported(sftp_session sftp, const char *name,
656
n = sftp_extensions_get_count(sftp);
657
for (i = 0; i < n; i++) {
658
if (strcmp(sftp_extensions_get_name(sftp, i), name) == 0 &&
659
strcmp(sftp_extensions_get_data(sftp, i), data) == 0) {
667
static sftp_request_queue request_queue_new(sftp_message msg) {
668
sftp_request_queue queue = NULL;
670
queue = malloc(sizeof(struct sftp_request_queue_struct));
672
ssh_set_error_oom(msg->sftp->session);
677
queue->message = msg;
682
static void request_queue_free(sftp_request_queue queue) {
691
static int sftp_enqueue(sftp_session sftp, sftp_message msg) {
692
sftp_request_queue queue = NULL;
693
sftp_request_queue ptr;
695
queue = request_queue_new(msg);
700
ssh_log(sftp->session, SSH_LOG_PACKET,
701
"Queued msg type %d id %d",
702
msg->id, msg->packet_type);
704
if(sftp->queue == NULL) {
709
ptr=ptr->next; /* find end of linked list */
711
ptr->next = queue; /* add it on bottom */
718
* Pulls of a message from the queue based on the ID.
719
* Returns NULL if no message has been found.
721
static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){
722
sftp_request_queue prev = NULL;
723
sftp_request_queue queue;
726
if(sftp->queue == NULL) {
732
if(queue->message->id == id) {
733
/* remove from queue */
735
sftp->queue = queue->next;
737
prev->next = queue->next;
739
msg = queue->message;
740
request_queue_free(queue);
741
ssh_log(sftp->session, SSH_LOG_PACKET,
742
"Dequeued msg id %d type %d",
755
* Assigns a new SFTP ID for new requests and assures there is no collision
757
* Returns a new ID ready to use in a request
759
static inline uint32_t sftp_get_new_id(sftp_session session) {
760
return ++session->id_counter;
763
static sftp_status_message parse_status_msg(sftp_message msg){
764
sftp_status_message status;
766
if (msg->packet_type != SSH_FXP_STATUS) {
767
ssh_set_error(msg->sftp->session, SSH_FATAL,
768
"Not a ssh_fxp_status message passed in!");
772
status = malloc(sizeof(struct sftp_status_message_struct));
773
if (status == NULL) {
774
ssh_set_error_oom(msg->sftp->session);
777
ZERO_STRUCTP(status);
779
status->id = msg->id;
780
if (buffer_get_u32(msg->payload,&status->status) != 4){
782
ssh_set_error(msg->sftp->session, SSH_FATAL,
783
"Invalid SSH_FXP_STATUS message");
786
status->error = buffer_get_ssh_string(msg->payload);
787
status->lang = buffer_get_ssh_string(msg->payload);
788
if(status->error == NULL || status->lang == NULL){
789
if(msg->sftp->version >=3){
790
/* These are mandatory from version 3 */
791
string_free(status->error);
792
/* status->lang never get allocated if something failed */
794
ssh_set_error(msg->sftp->session, SSH_FATAL,
795
"Invalid SSH_FXP_STATUS message");
800
status->status = ntohl(status->status);
802
status->errormsg = string_to_char(status->error);
804
status->errormsg = strdup("No error message in packet");
806
status->langmsg = string_to_char(status->lang);
808
status->langmsg = strdup("");
809
if (status->errormsg == NULL || status->langmsg == NULL) {
810
ssh_set_error_oom(msg->sftp->session);
811
status_msg_free(status);
818
static void status_msg_free(sftp_status_message status){
819
if (status == NULL) {
823
string_free(status->error);
824
string_free(status->lang);
825
SAFE_FREE(status->errormsg);
826
SAFE_FREE(status->langmsg);
830
static sftp_file parse_handle_msg(sftp_message msg){
833
if(msg->packet_type != SSH_FXP_HANDLE) {
834
ssh_set_error(msg->sftp->session, SSH_FATAL,
835
"Not a ssh_fxp_handle message passed in!");
839
file = malloc(sizeof(struct sftp_file_struct));
841
ssh_set_error_oom(msg->sftp->session);
846
file->handle = buffer_get_ssh_string(msg->payload);
847
if (file->handle == NULL) {
848
ssh_set_error(msg->sftp->session, SSH_FATAL,
849
"Invalid SSH_FXP_HANDLE message");
854
file->sftp = msg->sftp;
861
/* Open a directory */
862
sftp_dir sftp_opendir(sftp_session sftp, const char *path){
863
sftp_message msg = NULL;
864
sftp_file file = NULL;
866
sftp_status_message status;
871
payload = buffer_new();
872
if (payload == NULL) {
873
ssh_set_error_oom(sftp->session);
877
path_s = string_from_char(path);
878
if (path_s == NULL) {
879
ssh_set_error_oom(sftp->session);
880
buffer_free(payload);
884
id = sftp_get_new_id(sftp);
885
if (buffer_add_u32(payload, id) < 0 ||
886
buffer_add_ssh_string(payload, path_s) < 0) {
887
ssh_set_error_oom(sftp->session);
888
buffer_free(payload);
894
if (sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload) < 0) {
895
buffer_free(payload);
898
buffer_free(payload);
900
while (msg == NULL) {
901
if (sftp_read_and_dispatch(sftp) < 0) {
902
/* something nasty has happened */
905
msg = sftp_dequeue(sftp, id);
908
switch (msg->packet_type) {
910
status = parse_status_msg(msg);
911
sftp_message_free(msg);
912
if (status == NULL) {
915
sftp_set_error(sftp, status->status);
916
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
917
"SFTP server: %s", status->errormsg);
918
status_msg_free(status);
921
file = parse_handle_msg(msg);
922
sftp_message_free(msg);
924
dir = malloc(sizeof(struct sftp_dir_struct));
926
ssh_set_error_oom(sftp->session);
932
dir->name = strdup(path);
933
if (dir->name == NULL) {
938
dir->handle = file->handle;
943
ssh_set_error(sftp->session, SSH_FATAL,
944
"Received message %d during opendir!", msg->packet_type);
945
sftp_message_free(msg);
952
* Parse the attributes from a payload from some messages. It is coded on
953
* baselines from the protocol version 4.
954
* This code is more or less dead but maybe we need it in future.
956
static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
958
sftp_attributes attr;
959
ssh_string owner = NULL;
960
ssh_string group = NULL;
964
/* unused member variable */
967
attr = malloc(sizeof(struct sftp_attributes_struct));
969
ssh_set_error_oom(sftp->session);
974
/* This isn't really a loop, but it is like a try..catch.. */
976
if (buffer_get_u32(buf, &flags) != 4) {
980
flags = ntohl(flags);
983
if (flags & SSH_FILEXFER_ATTR_SIZE) {
984
if (buffer_get_u64(buf, &attr->size) != 8) {
987
attr->size = ntohll(attr->size);
990
if (flags & SSH_FILEXFER_ATTR_OWNERGROUP) {
991
if((owner = buffer_get_ssh_string(buf)) == NULL ||
992
(attr->owner = string_to_char(owner)) == NULL) {
995
if ((group = buffer_get_ssh_string(buf)) == NULL ||
996
(attr->group = string_to_char(group)) == NULL) {
1001
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
1002
if (buffer_get_u32(buf, &attr->permissions) != 4) {
1005
attr->permissions = ntohl(attr->permissions);
1007
/* FIXME on windows! */
1008
switch (attr->permissions & S_IFMT) {
1013
attr->type = SSH_FILEXFER_TYPE_SPECIAL;
1016
attr->type = SSH_FILEXFER_TYPE_SYMLINK;
1019
attr->type = SSH_FILEXFER_TYPE_REGULAR;
1022
attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
1025
attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
1030
if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
1031
if (buffer_get_u64(buf, &attr->atime64) != 8) {
1034
attr->atime64 = ntohll(attr->atime64);
1037
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
1038
if (buffer_get_u32(buf, &attr->atime_nseconds) != 4) {
1041
attr->atime_nseconds = ntohl(attr->atime_nseconds);
1044
if (flags & SSH_FILEXFER_ATTR_CREATETIME) {
1045
if (buffer_get_u64(buf, &attr->createtime) != 8) {
1048
attr->createtime = ntohll(attr->createtime);
1051
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
1052
if (buffer_get_u32(buf, &attr->createtime_nseconds) != 4) {
1055
attr->createtime_nseconds = ntohl(attr->createtime_nseconds);
1058
if (flags & SSH_FILEXFER_ATTR_MODIFYTIME) {
1059
if (buffer_get_u64(buf, &attr->mtime64) != 8) {
1062
attr->mtime64 = ntohll(attr->mtime64);
1065
if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
1066
if (buffer_get_u32(buf, &attr->mtime_nseconds) != 4) {
1069
attr->mtime_nseconds = ntohl(attr->mtime_nseconds);
1072
if (flags & SSH_FILEXFER_ATTR_ACL) {
1073
if ((attr->acl = buffer_get_ssh_string(buf)) == NULL) {
1078
if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
1079
if (buffer_get_u32(buf,&attr->extended_count) != 4) {
1082
attr->extended_count = ntohl(attr->extended_count);
1084
while(attr->extended_count &&
1085
(attr->extended_type = buffer_get_ssh_string(buf)) &&
1086
(attr->extended_data = buffer_get_ssh_string(buf))){
1087
attr->extended_count--;
1090
if (attr->extended_count) {
1098
/* break issued somewhere */
1101
string_free(attr->acl);
1102
string_free(attr->extended_type);
1103
string_free(attr->extended_data);
1104
SAFE_FREE(attr->owner);
1105
SAFE_FREE(attr->group);
1108
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
1116
enum sftp_longname_field_e {
1117
SFTP_LONGNAME_PERM = 0,
1118
SFTP_LONGNAME_FIXME,
1119
SFTP_LONGNAME_OWNER,
1120
SFTP_LONGNAME_GROUP,
1127
static char *sftp_parse_longname(const char *longname,
1128
enum sftp_longname_field_e longname_field) {
1130
size_t len, field = 0;
1134
/* Find the beginning of the field which is specified by sftp_longanme_field_e. */
1135
while(field != longname_field) {
1139
while(*p && isspace(*p)) {
1148
while (! isspace(*q)) {
1152
/* There is no strndup on windows */
1159
snprintf(x, len, "%s", p);
1164
/* sftp version 0-3 code. It is different from the v4 */
1165
/* maybe a paste of the draft is better than the code */
1168
uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
1169
uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
1170
uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
1171
uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
1172
uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
1173
uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
1174
uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
1175
string extended_type
1176
string extended_data
1177
... more extended data (extended_type - extended_data pairs),
1178
so that number of pairs equals extended_count */
1179
static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
1181
ssh_string longname = NULL;
1182
ssh_string name = NULL;
1183
sftp_attributes attr;
1187
attr = malloc(sizeof(struct sftp_attributes_struct));
1189
ssh_set_error_oom(sftp->session);
1194
/* This isn't really a loop, but it is like a try..catch.. */
1197
if ((name = buffer_get_ssh_string(buf)) == NULL ||
1198
(attr->name = string_to_char(name)) == NULL) {
1203
ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
1205
if ((longname=buffer_get_ssh_string(buf)) == NULL ||
1206
(attr->longname=string_to_char(longname)) == NULL) {
1209
string_free(longname);
1211
/* Set owner and group if we talk to openssh and have the longname */
1212
if (ssh_get_openssh_version(sftp->session)) {
1213
attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER);
1214
if (attr->owner == NULL) {
1218
attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
1219
if (attr->group == NULL) {
1225
if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
1228
flags = ntohl(flags);
1229
attr->flags = flags;
1230
ssh_log(sftp->session, SSH_LOG_RARE,
1231
"Flags: %.8lx\n", (long unsigned int) flags);
1233
if (flags & SSH_FILEXFER_ATTR_SIZE) {
1234
if(buffer_get_u64(buf, &attr->size) != sizeof(uint64_t)) {
1237
attr->size = ntohll(attr->size);
1238
ssh_log(sftp->session, SSH_LOG_RARE,
1240
(long long unsigned int) attr->size);
1243
if (flags & SSH_FILEXFER_ATTR_UIDGID) {
1244
if (buffer_get_u32(buf, &attr->uid) != sizeof(uint32_t)) {
1247
if (buffer_get_u32(buf, &attr->gid) != sizeof(uint32_t)) {
1250
attr->uid = ntohl(attr->uid);
1251
attr->gid = ntohl(attr->gid);
1254
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
1255
if (buffer_get_u32(buf, &attr->permissions) != sizeof(uint32_t)) {
1258
attr->permissions = ntohl(attr->permissions);
1260
switch (attr->permissions & S_IFMT) {
1265
attr->type = SSH_FILEXFER_TYPE_SPECIAL;
1268
attr->type = SSH_FILEXFER_TYPE_SYMLINK;
1271
attr->type = SSH_FILEXFER_TYPE_REGULAR;
1274
attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
1277
attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
1282
if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
1283
if (buffer_get_u32(buf, &attr->atime) != sizeof(uint32_t)) {
1286
attr->atime = ntohl(attr->atime);
1287
if (buffer_get_u32(buf, &attr->mtime) != sizeof(uint32_t)) {
1290
attr->mtime = ntohl(attr->mtime);
1293
if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
1294
if (buffer_get_u32(buf, &attr->extended_count) != sizeof(uint32_t)) {
1298
attr->extended_count = ntohl(attr->extended_count);
1299
while (attr->extended_count &&
1300
(attr->extended_type = buffer_get_ssh_string(buf))
1301
&& (attr->extended_data = buffer_get_ssh_string(buf))) {
1302
attr->extended_count--;
1305
if (attr->extended_count) {
1313
/* break issued somewhere */
1315
string_free(longname);
1316
string_free(attr->extended_type);
1317
string_free(attr->extended_data);
1318
SAFE_FREE(attr->name);
1319
SAFE_FREE(attr->longname);
1320
SAFE_FREE(attr->owner);
1321
SAFE_FREE(attr->group);
1324
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
1329
/* everything went smoothly */
1333
/* FIXME is this really needed as a public function? */
1334
int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr) {
1335
uint32_t flags = (attr ? attr->flags : 0);
1337
flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID |
1338
SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
1340
if (buffer_add_u32(buffer, htonl(flags)) < 0) {
1345
if (flags & SSH_FILEXFER_ATTR_SIZE) {
1346
if (buffer_add_u64(buffer, htonll(attr->size)) < 0) {
1351
if (flags & SSH_FILEXFER_ATTR_UIDGID) {
1352
if (buffer_add_u32(buffer,htonl(attr->uid)) < 0 ||
1353
buffer_add_u32(buffer,htonl(attr->gid)) < 0) {
1358
if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
1359
if (buffer_add_u32(buffer, htonl(attr->permissions)) < 0) {
1364
if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
1365
if (buffer_add_u32(buffer, htonl(attr->atime)) < 0 ||
1366
buffer_add_u32(buffer, htonl(attr->mtime)) < 0) {
1376
sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,
1378
switch(session->version) {
1380
return sftp_parse_attr_4(session, buf, expectname);
1385
return sftp_parse_attr_3(session, buf, expectname);
1387
ssh_set_error(session->session, SSH_FATAL,
1388
"Version %d unsupported by client", session->server_version);
1395
/* Get the version of the SFTP protocol supported by the server */
1396
int sftp_server_version(sftp_session sftp) {
1397
return sftp->server_version;
1400
/* Get a single file attributes structure of a directory. */
1401
sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) {
1402
sftp_message msg = NULL;
1403
sftp_status_message status;
1404
sftp_attributes attr;
1408
if (dir->buffer == NULL) {
1409
payload = buffer_new();
1410
if (payload == NULL) {
1411
ssh_set_error_oom(sftp->session);
1415
id = sftp_get_new_id(sftp);
1416
if (buffer_add_u32(payload, id) < 0 ||
1417
buffer_add_ssh_string(payload, dir->handle) < 0) {
1418
ssh_set_error_oom(sftp->session);
1419
buffer_free(payload);
1423
if (sftp_packet_write(sftp, SSH_FXP_READDIR, payload) < 0) {
1424
buffer_free(payload);
1427
buffer_free(payload);
1429
ssh_log(sftp->session, SSH_LOG_PACKET,
1430
"Sent a ssh_fxp_readdir with id %d", id);
1432
while (msg == NULL) {
1433
if (sftp_read_and_dispatch(sftp) < 0) {
1434
/* something nasty has happened */
1437
msg = sftp_dequeue(sftp, id);
1440
switch (msg->packet_type){
1441
case SSH_FXP_STATUS:
1442
status = parse_status_msg(msg);
1443
sftp_message_free(msg);
1444
if (status == NULL) {
1447
sftp_set_error(sftp, status->status);
1448
switch (status->status) {
1451
status_msg_free(status);
1457
ssh_set_error(sftp->session, SSH_FATAL,
1458
"Unknown error status: %d", status->status);
1459
status_msg_free(status);
1463
buffer_get_u32(msg->payload, &dir->count);
1464
dir->count = ntohl(dir->count);
1465
dir->buffer = msg->payload;
1466
msg->payload = NULL;
1467
sftp_message_free(msg);
1470
ssh_set_error(sftp->session, SSH_FATAL,
1471
"Unsupported message back %d", msg->packet_type);
1472
sftp_message_free(msg);
1478
/* now dir->buffer contains a buffer and dir->count != 0 */
1479
if (dir->count == 0) {
1480
ssh_set_error(sftp->session, SSH_FATAL,
1481
"Count of files sent by the server is zero, which is invalid, or "
1486
ssh_log(sftp->session, SSH_LOG_RARE, "Count is %d", dir->count);
1488
attr = sftp_parse_attr(sftp, dir->buffer, 1);
1490
ssh_set_error(sftp->session, SSH_FATAL,
1491
"Couldn't parse the SFTP attributes");
1496
if (dir->count == 0) {
1497
buffer_free(dir->buffer);
1504
/* Tell if the directory has reached EOF (End Of File). */
1505
int sftp_dir_eof(sftp_dir dir) {
1509
/* Free a SFTP_ATTRIBUTE handle */
1510
void sftp_attributes_free(sftp_attributes file){
1515
string_free(file->acl);
1516
string_free(file->extended_data);
1517
string_free(file->extended_type);
1519
SAFE_FREE(file->name);
1520
SAFE_FREE(file->longname);
1521
SAFE_FREE(file->group);
1522
SAFE_FREE(file->owner);
1527
static int sftp_handle_close(sftp_session sftp, ssh_string handle) {
1528
sftp_status_message status;
1529
sftp_message msg = NULL;
1530
ssh_buffer buffer = NULL;
1533
buffer = buffer_new();
1534
if (buffer == NULL) {
1535
ssh_set_error_oom(sftp->session);
1539
id = sftp_get_new_id(sftp);
1540
if (buffer_add_u32(buffer, id) < 0 ||
1541
buffer_add_ssh_string(buffer, handle) < 0) {
1542
ssh_set_error_oom(sftp->session);
1543
buffer_free(buffer);
1546
if (sftp_packet_write(sftp, SSH_FXP_CLOSE ,buffer) < 0) {
1547
buffer_free(buffer);
1550
buffer_free(buffer);
1552
while (msg == NULL) {
1553
if (sftp_read_and_dispatch(sftp) < 0) {
1554
/* something nasty has happened */
1557
msg = sftp_dequeue(sftp,id);
1560
switch (msg->packet_type) {
1561
case SSH_FXP_STATUS:
1562
status = parse_status_msg(msg);
1563
sftp_message_free(msg);
1564
if(status == NULL) {
1567
sftp_set_error(sftp, status->status);
1568
switch (status->status) {
1570
status_msg_free(status);
1576
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
1577
"SFTP server: %s", status->errormsg);
1578
status_msg_free(status);
1581
ssh_set_error(sftp->session, SSH_FATAL,
1582
"Received message %d during sftp_handle_close!", msg->packet_type);
1583
sftp_message_free(msg);
1589
/* Close an open file handle. */
1590
int sftp_close(sftp_file file){
1591
int err = SSH_NO_ERROR;
1593
SAFE_FREE(file->name);
1595
err = sftp_handle_close(file->sftp,file->handle);
1596
string_free(file->handle);
1598
/* FIXME: check server response and implement errno */
1604
/* Close an open directory. */
1605
int sftp_closedir(sftp_dir dir){
1606
int err = SSH_NO_ERROR;
1608
SAFE_FREE(dir->name);
1610
err = sftp_handle_close(dir->sftp, dir->handle);
1611
string_free(dir->handle);
1613
/* FIXME: check server response and implement errno */
1614
buffer_free(dir->buffer);
1620
/* Open a file on the server. */
1621
sftp_file sftp_open(sftp_session sftp, const char *file, int flags,
1623
sftp_message msg = NULL;
1624
sftp_status_message status;
1625
struct sftp_attributes_struct attr;
1627
ssh_string filename;
1629
uint32_t sftp_flags = 0;
1632
buffer = buffer_new();
1633
if (buffer == NULL) {
1634
ssh_set_error_oom(sftp->session);
1638
filename = string_from_char(file);
1639
if (filename == NULL) {
1640
ssh_set_error_oom(sftp->session);
1641
buffer_free(buffer);
1646
attr.permissions = mode;
1647
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
1649
if (flags == O_RDONLY)
1650
sftp_flags |= SSH_FXF_READ; /* if any of the other flag is set,
1651
READ should not be set initialy */
1652
if (flags & O_WRONLY)
1653
sftp_flags |= SSH_FXF_WRITE;
1655
sftp_flags |= (SSH_FXF_WRITE | SSH_FXF_READ);
1656
if (flags & O_CREAT)
1657
sftp_flags |= SSH_FXF_CREAT;
1658
if (flags & O_TRUNC)
1659
sftp_flags |= SSH_FXF_TRUNC;
1661
sftp_flags |= SSH_FXF_EXCL;
1662
ssh_log(sftp->session,SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags);
1663
id = sftp_get_new_id(sftp);
1664
if (buffer_add_u32(buffer, id) < 0 ||
1665
buffer_add_ssh_string(buffer, filename) < 0) {
1666
ssh_set_error_oom(sftp->session);
1667
buffer_free(buffer);
1668
string_free(filename);
1671
string_free(filename);
1673
if (buffer_add_u32(buffer, htonl(sftp_flags)) < 0 ||
1674
buffer_add_attributes(buffer, &attr) < 0) {
1675
ssh_set_error_oom(sftp->session);
1676
buffer_free(buffer);
1679
if (sftp_packet_write(sftp, SSH_FXP_OPEN, buffer) < 0) {
1680
buffer_free(buffer);
1683
buffer_free(buffer);
1685
while (msg == NULL) {
1686
if (sftp_read_and_dispatch(sftp) < 0) {
1687
/* something nasty has happened */
1690
msg = sftp_dequeue(sftp, id);
1693
switch (msg->packet_type) {
1694
case SSH_FXP_STATUS:
1695
status = parse_status_msg(msg);
1696
sftp_message_free(msg);
1697
if (status == NULL) {
1700
sftp_set_error(sftp, status->status);
1701
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
1702
"SFTP server: %s", status->errormsg);
1703
status_msg_free(status);
1706
case SSH_FXP_HANDLE:
1707
handle = parse_handle_msg(msg);
1708
sftp_message_free(msg);
1711
ssh_set_error(sftp->session, SSH_FATAL,
1712
"Received message %d during open!", msg->packet_type);
1713
sftp_message_free(msg);
1719
void sftp_file_set_nonblocking(sftp_file handle){
1720
handle->nonblocking=1;
1722
void sftp_file_set_blocking(sftp_file handle){
1723
handle->nonblocking=0;
1726
/* Read from a file using an opened sftp file handle. */
1727
ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
1728
sftp_session sftp = handle->sftp;
1729
sftp_message msg = NULL;
1730
sftp_status_message status;
1731
ssh_string datastring;
1739
buffer = buffer_new();
1740
if (buffer == NULL) {
1741
ssh_set_error_oom(sftp->session);
1744
id = sftp_get_new_id(handle->sftp);
1745
if (buffer_add_u32(buffer, id) < 0 ||
1746
buffer_add_ssh_string(buffer, handle->handle) < 0 ||
1747
buffer_add_u64(buffer, htonll(handle->offset)) < 0 ||
1748
buffer_add_u32(buffer,htonl(count)) < 0) {
1749
ssh_set_error_oom(sftp->session);
1750
buffer_free(buffer);
1753
if (sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) {
1754
buffer_free(buffer);
1757
buffer_free(buffer);
1759
while (msg == NULL) {
1760
if (handle->nonblocking) {
1761
if (channel_poll(handle->sftp->channel, 0) == 0) {
1762
/* we cannot block */
1766
if (sftp_read_and_dispatch(handle->sftp) < 0) {
1767
/* something nasty has happened */
1770
msg = sftp_dequeue(handle->sftp, id);
1773
switch (msg->packet_type) {
1774
case SSH_FXP_STATUS:
1775
status = parse_status_msg(msg);
1776
sftp_message_free(msg);
1777
if (status == NULL) {
1780
sftp_set_error(sftp, status->status);
1781
switch (status->status) {
1784
status_msg_free(status);
1789
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,
1790
"SFTP server: %s", status->errormsg);
1791
status_msg_free(status);
1794
datastring = buffer_get_ssh_string(msg->payload);
1795
sftp_message_free(msg);
1796
if (datastring == NULL) {
1797
ssh_set_error(sftp->session, SSH_FATAL,
1798
"Received invalid DATA packet from sftp server");
1802
if (string_len(datastring) > count) {
1803
ssh_set_error(sftp->session, SSH_FATAL,
1804
"Received a too big DATA packet from sftp server: "
1805
"%zu and asked for %zu",
1806
string_len(datastring), count);
1807
string_free(datastring);
1810
count = string_len(datastring);
1811
handle->offset += count;
1812
memcpy(buf, string_data(datastring), count);
1813
string_free(datastring);
1816
ssh_set_error(sftp->session, SSH_FATAL,
1817
"Received message %d during read!", msg->packet_type);
1818
sftp_message_free(msg);
1822
return -1; /* not reached */
1825
/* Start an asynchronous read from a file using an opened sftp file handle. */
1826
int sftp_async_read_begin(sftp_file file, uint32_t len){
1827
sftp_session sftp = file->sftp;
1831
sftp_enter_function();
1833
buffer = buffer_new();
1834
if (buffer == NULL) {
1835
ssh_set_error_oom(sftp->session);
1839
id = sftp_get_new_id(sftp);
1840
if (buffer_add_u32(buffer, id) < 0 ||
1841
buffer_add_ssh_string(buffer, file->handle) < 0 ||
1842
buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
1843
buffer_add_u32(buffer, htonl(len)) < 0) {
1844
ssh_set_error_oom(sftp->session);
1845
buffer_free(buffer);
1848
if (sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) {
1849
buffer_free(buffer);
1852
buffer_free(buffer);
1854
file->offset += len; /* assume we'll read len bytes */
1856
sftp_leave_function();
1860
/* Wait for an asynchronous read to complete and save the data. */
1861
int sftp_async_read(sftp_file file, void *data, uint32_t size, uint32_t id){
1862
sftp_session sftp = file->sftp;
1863
sftp_message msg = NULL;
1864
sftp_status_message status;
1865
ssh_string datastring;
1869
sftp_enter_function();
1872
sftp_leave_function();
1876
/* handle an existing request */
1877
while (msg == NULL) {
1878
if (file->nonblocking){
1879
if (channel_poll(sftp->channel, 0) == 0) {
1880
/* we cannot block */
1885
if (sftp_read_and_dispatch(sftp) < 0) {
1886
/* something nasty has happened */
1887
sftp_leave_function();
1891
msg = sftp_dequeue(sftp,id);
1894
switch (msg->packet_type) {
1895
case SSH_FXP_STATUS:
1896
status = parse_status_msg(msg);
1897
sftp_message_free(msg);
1898
if (status == NULL) {
1899
sftp_leave_function();
1902
sftp_set_error(sftp, status->status);
1903
if (status->status != SSH_FX_EOF) {
1904
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
1905
"SFTP server : %s", status->errormsg);
1906
sftp_leave_function();
1911
status_msg_free(status);
1912
sftp_leave_function();
1915
datastring = buffer_get_ssh_string(msg->payload);
1916
sftp_message_free(msg);
1917
if (datastring == NULL) {
1918
ssh_set_error(sftp->session, SSH_FATAL,
1919
"Received invalid DATA packet from sftp server");
1920
sftp_leave_function();
1923
if (string_len(datastring) > size) {
1924
ssh_set_error(sftp->session, SSH_FATAL,
1925
"Received a too big DATA packet from sftp server: "
1926
"%zu and asked for %u",
1927
string_len(datastring), size);
1928
string_free(datastring);
1929
sftp_leave_function();
1932
len = string_len(datastring);
1933
//handle->offset+=len;
1934
/* We already have set the offset previously. All we can do is warn that the expected len
1935
* and effective lengths are different */
1936
memcpy(data, string_data(datastring), len);
1937
string_free(datastring);
1938
sftp_leave_function();
1941
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during read!",msg->packet_type);
1942
sftp_message_free(msg);
1943
sftp_leave_function();
1947
sftp_leave_function();
1951
ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
1952
sftp_session sftp = file->sftp;
1953
sftp_message msg = NULL;
1954
sftp_status_message status;
1955
ssh_string datastring;
1961
buffer = buffer_new();
1962
if (buffer == NULL) {
1963
ssh_set_error_oom(sftp->session);
1967
datastring = string_new(count);
1968
if (datastring == NULL) {
1969
ssh_set_error_oom(sftp->session);
1970
buffer_free(buffer);
1973
string_fill(datastring, buf, count);
1975
id = sftp_get_new_id(file->sftp);
1976
if (buffer_add_u32(buffer, id) < 0 ||
1977
buffer_add_ssh_string(buffer, file->handle) < 0 ||
1978
buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
1979
buffer_add_ssh_string(buffer, datastring) < 0) {
1980
ssh_set_error_oom(sftp->session);
1981
buffer_free(buffer);
1982
string_free(datastring);
1985
string_free(datastring);
1986
len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer);
1987
packetlen=buffer_get_len(buffer);
1988
buffer_free(buffer);
1991
} else if (len != packetlen) {
1992
ssh_log(sftp->session, SSH_LOG_PACKET,
1993
"Could not write as much data as expected");
1996
while (msg == NULL) {
1997
if (sftp_read_and_dispatch(file->sftp) < 0) {
1998
/* something nasty has happened */
2001
msg = sftp_dequeue(file->sftp, id);
2004
switch (msg->packet_type) {
2005
case SSH_FXP_STATUS:
2006
status = parse_status_msg(msg);
2007
sftp_message_free(msg);
2008
if (status == NULL) {
2011
sftp_set_error(sftp, status->status);
2012
switch (status->status) {
2014
file->offset += count;
2015
status_msg_free(status);
2020
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2021
"SFTP server: %s", status->errormsg);
2022
file->offset += count;
2023
status_msg_free(status);
2026
ssh_set_error(sftp->session, SSH_FATAL,
2027
"Received message %d during write!", msg->packet_type);
2028
sftp_message_free(msg);
2032
return -1; /* not reached */
2035
/* Seek to a specific location in a file. */
2036
int sftp_seek(sftp_file file, uint32_t new_offset) {
2041
file->offset = new_offset;
2046
int sftp_seek64(sftp_file file, uint64_t new_offset) {
2051
file->offset = new_offset;
2056
/* Report current byte position in file. */
2057
unsigned long sftp_tell(sftp_file file) {
2058
return (unsigned long)file->offset;
2060
/* Report current byte position in file. */
2061
uint64_t sftp_tell64(sftp_file file) {
2062
return (uint64_t) file->offset;
2065
/* Rewinds the position of the file pointer to the beginning of the file.*/
2066
void sftp_rewind(sftp_file file) {
2070
/* code written by Nick */
2071
int sftp_unlink(sftp_session sftp, const char *file) {
2072
sftp_status_message status = NULL;
2073
sftp_message msg = NULL;
2074
ssh_string filename;
2078
buffer = buffer_new();
2079
if (buffer == NULL) {
2080
ssh_set_error_oom(sftp->session);
2084
filename = string_from_char(file);
2085
if (filename == NULL) {
2086
ssh_set_error_oom(sftp->session);
2087
buffer_free(buffer);
2091
id = sftp_get_new_id(sftp);
2092
if (buffer_add_u32(buffer, id) < 0 ||
2093
buffer_add_ssh_string(buffer, filename) < 0) {
2094
ssh_set_error_oom(sftp->session);
2095
buffer_free(buffer);
2096
string_free(filename);
2098
if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
2099
buffer_free(buffer);
2100
string_free(filename);
2102
string_free(filename);
2103
buffer_free(buffer);
2105
while (msg == NULL) {
2106
if (sftp_read_and_dispatch(sftp)) {
2109
msg = sftp_dequeue(sftp, id);
2112
if (msg->packet_type == SSH_FXP_STATUS) {
2113
/* by specification, this command's only supposed to return SSH_FXP_STATUS */
2114
status = parse_status_msg(msg);
2115
sftp_message_free(msg);
2116
if (status == NULL) {
2119
sftp_set_error(sftp, status->status);
2120
switch (status->status) {
2122
status_msg_free(status);
2129
* The status should be SSH_FX_OK if the command was successful, if it
2130
* didn't, then there was an error
2132
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2133
"SFTP server: %s", status->errormsg);
2134
status_msg_free(status);
2137
ssh_set_error(sftp->session,SSH_FATAL,
2138
"Received message %d when attempting to remove file", msg->packet_type);
2139
sftp_message_free(msg);
2145
/* code written by Nick */
2146
int sftp_rmdir(sftp_session sftp, const char *directory) {
2147
sftp_status_message status = NULL;
2148
sftp_message msg = NULL;
2149
ssh_string filename;
2153
buffer = buffer_new();
2154
if (buffer == NULL) {
2155
ssh_set_error_oom(sftp->session);
2159
filename = string_from_char(directory);
2160
if (filename == NULL) {
2161
ssh_set_error_oom(sftp->session);
2162
buffer_free(buffer);
2166
id = sftp_get_new_id(sftp);
2167
if (buffer_add_u32(buffer, id) < 0 ||
2168
buffer_add_ssh_string(buffer, filename) < 0) {
2169
ssh_set_error_oom(sftp->session);
2170
buffer_free(buffer);
2171
string_free(filename);
2174
if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) {
2175
buffer_free(buffer);
2176
string_free(filename);
2179
buffer_free(buffer);
2180
string_free(filename);
2182
while (msg == NULL) {
2183
if (sftp_read_and_dispatch(sftp) < 0) {
2186
msg = sftp_dequeue(sftp, id);
2189
/* By specification, this command returns SSH_FXP_STATUS */
2190
if (msg->packet_type == SSH_FXP_STATUS) {
2191
status = parse_status_msg(msg);
2192
sftp_message_free(msg);
2193
if (status == NULL) {
2196
sftp_set_error(sftp, status->status);
2197
switch (status->status) {
2199
status_msg_free(status);
2205
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2206
"SFTP server: %s", status->errormsg);
2207
status_msg_free(status);
2210
ssh_set_error(sftp->session, SSH_FATAL,
2211
"Received message %d when attempting to remove directory",
2213
sftp_message_free(msg);
2219
/* Code written by Nick */
2220
int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
2221
sftp_status_message status = NULL;
2222
sftp_message msg = NULL;
2223
sftp_attributes errno_attr = NULL;
2224
struct sftp_attributes_struct attr;
2229
buffer = buffer_new();
2230
if (buffer == NULL) {
2231
ssh_set_error_oom(sftp->session);
2235
path = string_from_char(directory);
2237
ssh_set_error_oom(sftp->session);
2238
buffer_free(buffer);
2243
attr.permissions = mode;
2244
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
2246
id = sftp_get_new_id(sftp);
2247
if (buffer_add_u32(buffer, id) < 0 ||
2248
buffer_add_ssh_string(buffer, path) < 0 ||
2249
buffer_add_attributes(buffer, &attr) < 0 ||
2250
sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) {
2251
buffer_free(buffer);
2254
buffer_free(buffer);
2257
while (msg == NULL) {
2258
if (sftp_read_and_dispatch(sftp) < 0) {
2261
msg = sftp_dequeue(sftp, id);
2264
/* By specification, this command only returns SSH_FXP_STATUS */
2265
if (msg->packet_type == SSH_FXP_STATUS) {
2266
status = parse_status_msg(msg);
2267
sftp_message_free(msg);
2268
if (status == NULL) {
2271
sftp_set_error(sftp, status->status);
2272
switch (status->status) {
2273
case SSH_FX_FAILURE:
2275
* mkdir always returns a failure, even if the path already exists.
2276
* To be POSIX conform and to be able to map it to EEXIST a stat
2277
* call is needed here.
2279
errno_attr = sftp_lstat(sftp, directory);
2280
if (errno_attr != NULL) {
2281
SAFE_FREE(errno_attr);
2282
sftp_set_error(sftp, SSH_FX_FILE_ALREADY_EXISTS);
2286
status_msg_free(status);
2293
* The status should be SSH_FX_OK if the command was successful, if it
2294
* didn't, then there was an error
2296
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2297
"SFTP server: %s", status->errormsg);
2298
status_msg_free(status);
2301
ssh_set_error(sftp->session, SSH_FATAL,
2302
"Received message %d when attempting to make directory",
2304
sftp_message_free(msg);
2310
/* code written by nick */
2311
int sftp_rename(sftp_session sftp, const char *original, const char *newname) {
2312
sftp_status_message status = NULL;
2313
sftp_message msg = NULL;
2319
buffer = buffer_new();
2320
if (buffer == NULL) {
2321
ssh_set_error_oom(sftp->session);
2325
oldpath = string_from_char(original);
2326
if (oldpath == NULL) {
2327
ssh_set_error_oom(sftp->session);
2328
buffer_free(buffer);
2332
newpath = string_from_char(newname);
2333
if (newpath == NULL) {
2334
ssh_set_error_oom(sftp->session);
2335
buffer_free(buffer);
2336
string_free(oldpath);
2340
id = sftp_get_new_id(sftp);
2341
if (buffer_add_u32(buffer, id) < 0 ||
2342
buffer_add_ssh_string(buffer, oldpath) < 0 ||
2343
buffer_add_ssh_string(buffer, newpath) < 0 ||
2344
/* POSIX rename atomically replaces newpath, we should do the same
2345
* only available on >=v4 */
2346
sftp->version>=4 ? (buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0):0) {
2347
ssh_set_error_oom(sftp->session);
2348
buffer_free(buffer);
2349
string_free(oldpath);
2350
string_free(newpath);
2353
if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) {
2354
buffer_free(buffer);
2355
string_free(oldpath);
2356
string_free(newpath);
2359
buffer_free(buffer);
2360
string_free(oldpath);
2361
string_free(newpath);
2363
while (msg == NULL) {
2364
if (sftp_read_and_dispatch(sftp) < 0) {
2367
msg = sftp_dequeue(sftp, id);
2370
/* By specification, this command only returns SSH_FXP_STATUS */
2371
if (msg->packet_type == SSH_FXP_STATUS) {
2372
status = parse_status_msg(msg);
2373
sftp_message_free(msg);
2374
if (status == NULL) {
2377
sftp_set_error(sftp, status->status);
2378
switch (status->status) {
2380
status_msg_free(status);
2386
* Status should be SSH_FX_OK if the command was successful, if it didn't,
2387
* then there was an error
2389
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2390
"SFTP server: %s", status->errormsg);
2391
status_msg_free(status);
2394
ssh_set_error(sftp->session, SSH_FATAL,
2395
"Received message %d when attempting to rename",
2397
sftp_message_free(msg);
2403
/* Code written by Nick */
2404
/* Set file attributes on a file, directory or symbolic link. */
2405
int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr) {
2406
uint32_t id = sftp_get_new_id(sftp);
2407
ssh_buffer buffer = buffer_new();
2408
ssh_string path = string_from_char(file);
2409
sftp_message msg = NULL;
2410
sftp_status_message status = NULL;
2412
buffer = buffer_new();
2413
if (buffer == NULL) {
2414
ssh_set_error_oom(sftp->session);
2418
path = string_from_char(file);
2420
ssh_set_error_oom(sftp->session);
2421
buffer_free(buffer);
2425
id = sftp_get_new_id(sftp);
2426
if (buffer_add_u32(buffer, id) < 0 ||
2427
buffer_add_ssh_string(buffer, path) < 0 ||
2428
buffer_add_attributes(buffer, attr) < 0) {
2429
ssh_set_error_oom(sftp->session);
2430
buffer_free(buffer);
2434
if (sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer) < 0) {
2435
buffer_free(buffer);
2439
buffer_free(buffer);
2442
while (msg == NULL) {
2443
if (sftp_read_and_dispatch(sftp) < 0) {
2446
msg = sftp_dequeue(sftp, id);
2449
/* By specification, this command only returns SSH_FXP_STATUS */
2450
if (msg->packet_type == SSH_FXP_STATUS) {
2451
status = parse_status_msg(msg);
2452
sftp_message_free(msg);
2453
if (status == NULL) {
2456
sftp_set_error(sftp, status->status);
2457
switch (status->status) {
2459
status_msg_free(status);
2465
* The status should be SSH_FX_OK if the command was successful, if it
2466
* didn't, then there was an error
2468
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2469
"SFTP server: %s", status->errormsg);
2470
status_msg_free(status);
2473
ssh_set_error(sftp->session, SSH_FATAL,
2474
"Received message %d when attempting to set stats", msg->packet_type);
2475
sftp_message_free(msg);
2481
/* Change the file owner and group */
2482
int sftp_chown(sftp_session sftp, const char *file, uid_t owner, gid_t group) {
2483
struct sftp_attributes_struct attr;
2489
attr.flags = SSH_FILEXFER_ATTR_UIDGID;
2491
return sftp_setstat(sftp, file, &attr);
2494
/* Change permissions of a file */
2495
int sftp_chmod(sftp_session sftp, const char *file, mode_t mode) {
2496
struct sftp_attributes_struct attr;
2498
attr.permissions = mode;
2499
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
2501
return sftp_setstat(sftp, file, &attr);
2504
/* Change the last modification and access time of a file. */
2505
int sftp_utimes(sftp_session sftp, const char *file,
2506
const struct timeval *times) {
2507
struct sftp_attributes_struct attr;
2510
attr.atime = times[0].tv_sec;
2511
attr.atime_nseconds = times[0].tv_usec;
2513
attr.mtime = times[1].tv_sec;
2514
attr.mtime_nseconds = times[1].tv_usec;
2516
attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME |
2517
SSH_FILEXFER_ATTR_SUBSECOND_TIMES;
2519
return sftp_setstat(sftp, file, &attr);
2522
int sftp_symlink(sftp_session sftp, const char *target, const char *dest) {
2523
sftp_status_message status = NULL;
2524
sftp_message msg = NULL;
2525
ssh_string target_s;
2532
if (target == NULL || dest == NULL) {
2533
ssh_set_error_invalid(sftp->session, __FUNCTION__);
2537
buffer = buffer_new();
2538
if (buffer == NULL) {
2539
ssh_set_error_oom(sftp->session);
2543
target_s = string_from_char(target);
2544
if (target_s == NULL) {
2545
ssh_set_error_oom(sftp->session);
2546
buffer_free(buffer);
2550
dest_s = string_from_char(dest);
2551
if (dest_s == NULL) {
2552
ssh_set_error_oom(sftp->session);
2553
string_free(target_s);
2554
buffer_free(buffer);
2558
id = sftp_get_new_id(sftp);
2559
if (buffer_add_u32(buffer, id) < 0) {
2560
ssh_set_error_oom(sftp->session);
2561
buffer_free(buffer);
2562
string_free(dest_s);
2563
string_free(target_s);
2566
if (ssh_get_openssh_version(sftp->session)) {
2567
/* TODO check for version number if they ever fix it. */
2568
if (buffer_add_ssh_string(buffer, target_s) < 0 ||
2569
buffer_add_ssh_string(buffer, dest_s) < 0) {
2570
ssh_set_error_oom(sftp->session);
2571
buffer_free(buffer);
2572
string_free(dest_s);
2573
string_free(target_s);
2577
if (buffer_add_ssh_string(buffer, dest_s) < 0 ||
2578
buffer_add_ssh_string(buffer, target_s) < 0) {
2579
ssh_set_error_oom(sftp->session);
2580
buffer_free(buffer);
2581
string_free(dest_s);
2582
string_free(target_s);
2587
if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) {
2588
buffer_free(buffer);
2589
string_free(dest_s);
2590
string_free(target_s);
2593
buffer_free(buffer);
2594
string_free(dest_s);
2595
string_free(target_s);
2597
while (msg == NULL) {
2598
if (sftp_read_and_dispatch(sftp) < 0) {
2601
msg = sftp_dequeue(sftp, id);
2604
/* By specification, this command only returns SSH_FXP_STATUS */
2605
if (msg->packet_type == SSH_FXP_STATUS) {
2606
status = parse_status_msg(msg);
2607
sftp_message_free(msg);
2608
if (status == NULL) {
2611
sftp_set_error(sftp, status->status);
2612
switch (status->status) {
2614
status_msg_free(status);
2620
* The status should be SSH_FX_OK if the command was successful, if it
2621
* didn't, then there was an error
2623
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2624
"SFTP server: %s", status->errormsg);
2625
status_msg_free(status);
2628
ssh_set_error(sftp->session, SSH_FATAL,
2629
"Received message %d when attempting to set stats", msg->packet_type);
2630
sftp_message_free(msg);
2636
char *sftp_readlink(sftp_session sftp, const char *path) {
2637
sftp_status_message status = NULL;
2638
sftp_message msg = NULL;
2639
ssh_string path_s = NULL;
2640
ssh_string link_s = NULL;
2649
ssh_set_error_invalid(sftp, __FUNCTION__);
2652
if (sftp->version < 3){
2653
ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_readlink",sftp->version);
2656
buffer = buffer_new();
2657
if (buffer == NULL) {
2658
ssh_set_error_oom(sftp->session);
2662
path_s = string_from_char(path);
2663
if (path_s == NULL) {
2664
ssh_set_error_oom(sftp->session);
2665
buffer_free(buffer);
2669
id = sftp_get_new_id(sftp);
2670
if (buffer_add_u32(buffer, id) < 0 ||
2671
buffer_add_ssh_string(buffer, path_s) < 0) {
2672
ssh_set_error_oom(sftp->session);
2673
buffer_free(buffer);
2674
string_free(path_s);
2677
if (sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) {
2678
buffer_free(buffer);
2679
string_free(path_s);
2682
buffer_free(buffer);
2683
string_free(path_s);
2685
while (msg == NULL) {
2686
if (sftp_read_and_dispatch(sftp) < 0) {
2689
msg = sftp_dequeue(sftp, id);
2692
if (msg->packet_type == SSH_FXP_NAME) {
2693
/* we don't care about "count" */
2694
buffer_get_u32(msg->payload, &ignored);
2695
/* we only care about the file name string */
2696
link_s = buffer_get_ssh_string(msg->payload);
2697
sftp_message_free(msg);
2698
if (link_s == NULL) {
2699
/* TODO: what error to set here? */
2702
lnk = string_to_char(link_s);
2703
string_free(link_s);
2706
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
2707
status = parse_status_msg(msg);
2708
sftp_message_free(msg);
2709
if (status == NULL) {
2712
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2713
"SFTP server: %s", status->errormsg);
2714
status_msg_free(status);
2715
} else { /* this shouldn't happen */
2716
ssh_set_error(sftp->session, SSH_FATAL,
2717
"Received message %d when attempting to set stats", msg->packet_type);
2718
sftp_message_free(msg);
2724
static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) {
2725
sftp_statvfs_t statvfs;
2729
statvfs = malloc(sizeof(struct sftp_statvfs_struct));
2730
if (statvfs == NULL) {
2731
ssh_set_error_oom(sftp->session);
2734
ZERO_STRUCTP(statvfs);
2738
/* file system block size */
2739
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2742
statvfs->f_bsize = ntohll(tmp);
2744
/* fundamental fs block size */
2745
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2748
statvfs->f_frsize = ntohll(tmp);
2750
/* number of blocks (unit f_frsize) */
2751
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2754
statvfs->f_blocks = ntohll(tmp);
2756
/* free blocks in file system */
2757
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2760
statvfs->f_bfree = ntohll(tmp);
2762
/* free blocks for non-root */
2763
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2766
statvfs->f_bavail = ntohll(tmp);
2768
/* total file inodes */
2769
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2772
statvfs->f_files = ntohll(tmp);
2774
/* free file inodes */
2775
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2778
statvfs->f_ffree = ntohll(tmp);
2780
/* free file inodes for to non-root */
2781
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2784
statvfs->f_favail = ntohll(tmp);
2786
/* file system id */
2787
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2790
statvfs->f_fsid = ntohll(tmp);
2792
/* bit mask of f_flag values */
2793
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2796
statvfs->f_flag = ntohll(tmp);
2798
/* maximum filename length */
2799
if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2802
statvfs->f_namemax = ntohll(tmp);
2809
ssh_set_error(sftp->session, SSH_FATAL, "Invalid statvfs structure");
2816
sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path) {
2817
sftp_status_message status = NULL;
2818
sftp_message msg = NULL;
2827
ssh_set_error_invalid(sftp->session, __FUNCTION__);
2830
if (sftp->version < 3){
2831
ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_statvfs",sftp->version);
2835
buffer = buffer_new();
2836
if (buffer == NULL) {
2837
ssh_set_error_oom(sftp->session);
2841
ext = string_from_char("statvfs@openssh.com");
2843
ssh_set_error_oom(sftp->session);
2844
buffer_free(buffer);
2848
pathstr = string_from_char(path);
2849
if (pathstr == NULL) {
2850
ssh_set_error_oom(sftp->session);
2851
buffer_free(buffer);
2856
id = sftp_get_new_id(sftp);
2857
if (buffer_add_u32(buffer, id) < 0 ||
2858
buffer_add_ssh_string(buffer, ext) < 0 ||
2859
buffer_add_ssh_string(buffer, pathstr) < 0) {
2860
ssh_set_error_oom(sftp->session);
2861
buffer_free(buffer);
2863
string_free(pathstr);
2866
if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
2867
buffer_free(buffer);
2869
string_free(pathstr);
2872
buffer_free(buffer);
2874
string_free(pathstr);
2876
while (msg == NULL) {
2877
if (sftp_read_and_dispatch(sftp) < 0) {
2880
msg = sftp_dequeue(sftp, id);
2883
if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
2884
sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
2885
sftp_message_free(msg);
2891
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
2892
status = parse_status_msg(msg);
2893
sftp_message_free(msg);
2894
if (status == NULL) {
2897
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2898
"SFTP server: %s", status->errormsg);
2899
status_msg_free(status);
2900
} else { /* this shouldn't happen */
2901
ssh_set_error(sftp->session, SSH_FATAL,
2902
"Received message %d when attempting to get statvfs", msg->packet_type);
2903
sftp_message_free(msg);
2909
sftp_statvfs_t sftp_fstatvfs(sftp_file file) {
2910
sftp_status_message status = NULL;
2911
sftp_message msg = NULL;
2922
buffer = buffer_new();
2923
if (buffer == NULL) {
2924
ssh_set_error_oom(sftp->session);
2928
ext = string_from_char("fstatvfs@openssh.com");
2930
ssh_set_error_oom(sftp->session);
2931
buffer_free(buffer);
2935
id = sftp_get_new_id(sftp);
2936
if (buffer_add_u32(buffer, id) < 0 ||
2937
buffer_add_ssh_string(buffer, ext) < 0 ||
2938
buffer_add_ssh_string(buffer, file->handle) < 0) {
2939
ssh_set_error_oom(sftp->session);
2940
buffer_free(buffer);
2944
if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
2945
buffer_free(buffer);
2949
buffer_free(buffer);
2952
while (msg == NULL) {
2953
if (sftp_read_and_dispatch(sftp) < 0) {
2956
msg = sftp_dequeue(sftp, id);
2959
if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
2960
sftp_statvfs_t buf = sftp_parse_statvfs(sftp, msg->payload);
2961
sftp_message_free(msg);
2967
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
2968
status = parse_status_msg(msg);
2969
sftp_message_free(msg);
2970
if (status == NULL) {
2973
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2974
"SFTP server: %s", status->errormsg);
2975
status_msg_free(status);
2976
} else { /* this shouldn't happen */
2977
ssh_set_error(sftp->session, SSH_FATAL,
2978
"Received message %d when attempting to set stats", msg->packet_type);
2979
sftp_message_free(msg);
2985
void sftp_statvfs_free(sftp_statvfs_t statvfs) {
2986
if (statvfs == NULL) {
2993
/* another code written by Nick */
2994
char *sftp_canonicalize_path(sftp_session sftp, const char *path) {
2995
sftp_status_message status = NULL;
2996
sftp_message msg = NULL;
2997
ssh_string name = NULL;
3007
ssh_set_error_invalid(sftp->session, __FUNCTION__);
3011
buffer = buffer_new();
3012
if (buffer == NULL) {
3013
ssh_set_error_oom(sftp->session);
3017
pathstr = string_from_char(path);
3018
if (pathstr == NULL) {
3019
ssh_set_error_oom(sftp->session);
3020
buffer_free(buffer);
3024
id = sftp_get_new_id(sftp);
3025
if (buffer_add_u32(buffer, id) < 0 ||
3026
buffer_add_ssh_string(buffer, pathstr) < 0) {
3027
ssh_set_error_oom(sftp->session);
3028
buffer_free(buffer);
3029
string_free(pathstr);
3032
if (sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer) < 0) {
3033
buffer_free(buffer);
3034
string_free(pathstr);
3037
buffer_free(buffer);
3038
string_free(pathstr);
3040
while (msg == NULL) {
3041
if (sftp_read_and_dispatch(sftp) < 0) {
3044
msg = sftp_dequeue(sftp, id);
3047
if (msg->packet_type == SSH_FXP_NAME) {
3048
/* we don't care about "count" */
3049
buffer_get_u32(msg->payload, &ignored);
3050
/* we only care about the file name string */
3051
name = buffer_get_ssh_string(msg->payload);
3052
sftp_message_free(msg);
3054
/* TODO: error message? */
3057
cname = string_to_char(name);
3059
if (cname == NULL) {
3060
ssh_set_error_oom(sftp->session);
3063
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
3064
status = parse_status_msg(msg);
3065
sftp_message_free(msg);
3066
if (status == NULL) {
3069
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
3070
"SFTP server: %s", status->errormsg);
3071
status_msg_free(status);
3072
} else { /* this shouldn't happen */
3073
ssh_set_error(sftp->session, SSH_FATAL,
3074
"Received message %d when attempting to set stats", msg->packet_type);
3075
sftp_message_free(msg);
3081
static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
3083
sftp_status_message status = NULL;
3084
sftp_message msg = NULL;
3089
buffer = buffer_new();
3090
if (buffer == NULL) {
3091
ssh_set_error_oom(sftp->session);
3095
pathstr = string_from_char(path);
3096
if (pathstr == NULL) {
3097
ssh_set_error_oom(sftp->session);
3098
buffer_free(buffer);
3102
id = sftp_get_new_id(sftp);
3103
if (buffer_add_u32(buffer, id) < 0 ||
3104
buffer_add_ssh_string(buffer, pathstr) < 0) {
3105
ssh_set_error_oom(sftp->session);
3106
buffer_free(buffer);
3107
string_free(pathstr);
3110
if (sftp_packet_write(sftp, param, buffer) < 0) {
3111
buffer_free(buffer);
3112
string_free(pathstr);
3115
buffer_free(buffer);
3116
string_free(pathstr);
3118
while (msg == NULL) {
3119
if (sftp_read_and_dispatch(sftp) < 0) {
3122
msg = sftp_dequeue(sftp, id);
3125
if (msg->packet_type == SSH_FXP_ATTRS) {
3126
sftp_attributes attr = sftp_parse_attr(sftp, msg->payload, 0);
3127
sftp_message_free(msg);
3130
} else if (msg->packet_type == SSH_FXP_STATUS) {
3131
status = parse_status_msg(msg);
3132
sftp_message_free(msg);
3133
if (status == NULL) {
3136
sftp_set_error(sftp, status->status);
3137
ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
3138
"SFTP server: %s", status->errormsg);
3139
status_msg_free(status);
3142
ssh_set_error(sftp->session, SSH_FATAL,
3143
"Received mesg %d during stat()", msg->packet_type);
3144
sftp_message_free(msg);
3149
sftp_attributes sftp_stat(sftp_session session, const char *path) {
3150
return sftp_xstat(session, path, SSH_FXP_STAT);
3153
sftp_attributes sftp_lstat(sftp_session session, const char *path) {
3154
return sftp_xstat(session, path, SSH_FXP_LSTAT);
3157
sftp_attributes sftp_fstat(sftp_file file) {
3158
sftp_status_message status = NULL;
3159
sftp_message msg = NULL;
3163
buffer = buffer_new();
3164
if (buffer == NULL) {
3165
ssh_set_error_oom(file->sftp->session);
3169
id = sftp_get_new_id(file->sftp);
3170
if (buffer_add_u32(buffer, id) < 0 ||
3171
buffer_add_ssh_string(buffer, file->handle) < 0) {
3172
ssh_set_error_oom(file->sftp->session);
3173
buffer_free(buffer);
3176
if (sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer) < 0) {
3177
buffer_free(buffer);
3180
buffer_free(buffer);
3182
while (msg == NULL) {
3183
if (sftp_read_and_dispatch(file->sftp) < 0) {
3186
msg = sftp_dequeue(file->sftp, id);
3189
if (msg->packet_type == SSH_FXP_ATTRS){
3190
return sftp_parse_attr(file->sftp, msg->payload, 0);
3191
} else if (msg->packet_type == SSH_FXP_STATUS) {
3192
status = parse_status_msg(msg);
3193
sftp_message_free(msg);
3194
if (status == NULL) {
3197
ssh_set_error(file->sftp->session, SSH_REQUEST_DENIED,
3198
"SFTP server: %s", status->errormsg);
3199
status_msg_free(status);
3203
ssh_set_error(file->sftp->session, SSH_FATAL,
3204
"Received msg %d during fstat()", msg->packet_type);
3205
sftp_message_free(msg);
3210
#endif /* WITH_SFTP */
3211
/* vim: set ts=2 sw=2 et cindent: */