~ubuntu-branches/ubuntu/precise/libssh/precise

« back to all changes in this revision

Viewing changes to libssh/sftp.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2011-06-15 15:48:07 UTC
  • mfrom: (1.1.10 upstream) (4.1.12 sid)
  • Revision ID: james.westby@ubuntu.com-20110615154807-3muklcqfftr1vtch
Tags: 0.5.0-2
* debian/patches/0002-Check-for-NULL-pointers-in-string-c.patch:
  Consolidate patch (Should fix previous REJECT)
* Support multiarch spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * sftp.c - Secure FTP functions
3
 
 *
4
 
 * This file is part of the SSH Library
5
 
 *
6
 
 * Copyright (c) 2005-2008 by Aris Adamantiadis
7
 
 * Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
8
 
 *
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.
13
 
 *
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.
18
 
 *
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,
22
 
 * MA 02111-1307, USA.
23
 
 */
24
 
 
25
 
/* This file contains code written by Nick Zitzmann */
26
 
 
27
 
#include <errno.h>
28
 
#include <ctype.h>
29
 
#include <fcntl.h>
30
 
#include <stdlib.h>
31
 
#include <string.h>
32
 
#include <stdio.h>
33
 
#include <sys/types.h>
34
 
#include <sys/stat.h>
35
 
 
36
 
#ifndef _WIN32
37
 
#include <arpa/inet.h>
38
 
#else
39
 
#define S_IFSOCK 0140000
40
 
#define S_IFLNK  0120000
41
 
 
42
 
#ifdef _MSC_VER
43
 
#define S_IFBLK  0060000
44
 
#define S_IFIFO  0010000
45
 
#endif
46
 
#endif
47
 
 
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"
55
 
 
56
 
#ifdef WITH_SFTP
57
 
 
58
 
#define sftp_enter_function() _enter_function(sftp->channel->session)
59
 
#define sftp_leave_function() _leave_function(sftp->channel->session)
60
 
 
61
 
struct sftp_ext_struct {
62
 
  unsigned int count;
63
 
  char **name;
64
 
  char **data;
65
 
};
66
 
 
67
 
/* functions */
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);
72
 
 
73
 
static sftp_ext sftp_ext_new(void) {
74
 
  sftp_ext ext;
75
 
 
76
 
  ext = malloc(sizeof(struct sftp_ext_struct));
77
 
  if (ext == NULL) {
78
 
    return NULL;
79
 
  }
80
 
  ZERO_STRUCTP(ext);
81
 
 
82
 
  return ext;
83
 
}
84
 
 
85
 
static void sftp_ext_free(sftp_ext ext) {
86
 
  unsigned int i;
87
 
 
88
 
  if (ext == NULL) {
89
 
    return;
90
 
  }
91
 
 
92
 
  if (ext->count) {
93
 
    for (i = 0; i < ext->count; i++) {
94
 
      SAFE_FREE(ext->name[i]);
95
 
      SAFE_FREE(ext->data[i]);
96
 
    }
97
 
    SAFE_FREE(ext->name);
98
 
    SAFE_FREE(ext->data);
99
 
  }
100
 
 
101
 
  SAFE_FREE(ext);
102
 
}
103
 
 
104
 
sftp_session sftp_new(ssh_session session){
105
 
  sftp_session sftp;
106
 
 
107
 
  enter_function();
108
 
 
109
 
  if (session == NULL) {
110
 
    leave_function();
111
 
    return NULL;
112
 
  }
113
 
 
114
 
  sftp = malloc(sizeof(struct sftp_session_struct));
115
 
  if (sftp == NULL) {
116
 
    ssh_set_error_oom(session);
117
 
    leave_function();
118
 
    return NULL;
119
 
  }
120
 
  ZERO_STRUCTP(sftp);
121
 
 
122
 
  sftp->ext = sftp_ext_new();
123
 
  if (sftp->ext == NULL) {
124
 
    ssh_set_error_oom(session);
125
 
    SAFE_FREE(sftp);
126
 
    sftp_leave_function();
127
 
    return NULL;
128
 
  }
129
 
 
130
 
  sftp->session = session;
131
 
  sftp->channel = channel_new(session);
132
 
  if (sftp->channel == NULL) {
133
 
    SAFE_FREE(sftp);
134
 
    leave_function();
135
 
    return NULL;
136
 
  }
137
 
 
138
 
  if (channel_open_session(sftp->channel)) {
139
 
    channel_free(sftp->channel);
140
 
    SAFE_FREE(sftp);
141
 
    leave_function();
142
 
    return NULL;
143
 
  }
144
 
 
145
 
  if (channel_request_sftp(sftp->channel)) {
146
 
    sftp_free(sftp);
147
 
    leave_function();
148
 
    return NULL;
149
 
  }
150
 
 
151
 
  leave_function();
152
 
  return sftp;
153
 
}
154
 
 
155
 
#ifdef WITH_SERVER
156
 
sftp_session sftp_server_new(ssh_session session, ssh_channel chan){
157
 
  sftp_session sftp = NULL;
158
 
 
159
 
  sftp = malloc(sizeof(struct sftp_session_struct));
160
 
  if (sftp == NULL) {
161
 
    ssh_set_error_oom(session);
162
 
    return NULL;
163
 
  }
164
 
  ZERO_STRUCTP(sftp);
165
 
 
166
 
  sftp->session = session;
167
 
  sftp->channel = chan;
168
 
 
169
 
  return sftp;
170
 
}
171
 
 
172
 
int sftp_server_init(sftp_session sftp){
173
 
  ssh_session session = sftp->session;
174
 
  sftp_packet packet = NULL;
175
 
  ssh_buffer reply = NULL;
176
 
  uint32_t version;
177
 
 
178
 
  sftp_enter_function();
179
 
 
180
 
  packet = sftp_packet_read(sftp);
181
 
  if (packet == NULL) {
182
 
    sftp_leave_function();
183
 
    return -1;
184
 
  }
185
 
 
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",
189
 
        packet->type);
190
 
 
191
 
    sftp_packet_free(packet);
192
 
    sftp_leave_function();
193
 
    return -1;
194
 
  }
195
 
 
196
 
  ssh_log(session, SSH_LOG_PACKET, "Received SSH_FXP_INIT");
197
 
 
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;
202
 
 
203
 
  sftp_packet_free(packet);
204
 
 
205
 
  reply = buffer_new();
206
 
  if (reply == NULL) {
207
 
    ssh_set_error_oom(session);
208
 
    sftp_leave_function();
209
 
    return -1;
210
 
  }
211
 
 
212
 
  if (buffer_add_u32(reply, ntohl(LIBSFTP_VERSION)) < 0) {
213
 
    ssh_set_error_oom(session);
214
 
    buffer_free(reply);
215
 
    sftp_leave_function();
216
 
    return -1;
217
 
  }
218
 
 
219
 
  if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) {
220
 
    buffer_free(reply);
221
 
    sftp_leave_function();
222
 
    return -1;
223
 
  }
224
 
  buffer_free(reply);
225
 
 
226
 
  ssh_log(session, SSH_LOG_RARE, "Server version sent");
227
 
 
228
 
  if (version > LIBSFTP_VERSION) {
229
 
    sftp->version = LIBSFTP_VERSION;
230
 
  } else {
231
 
    sftp->version=version;
232
 
  }
233
 
 
234
 
  sftp_leave_function();
235
 
  return 0;
236
 
}
237
 
#endif /* WITH_SERVER */
238
 
 
239
 
void sftp_free(sftp_session sftp){
240
 
  sftp_request_queue ptr;
241
 
 
242
 
  if (sftp == NULL) {
243
 
    return;
244
 
  }
245
 
 
246
 
  channel_send_eof(sftp->channel);
247
 
  ptr = sftp->queue;
248
 
  while(ptr) {
249
 
    sftp_request_queue old;
250
 
    sftp_message_free(ptr->message);
251
 
    old = ptr->next;
252
 
    SAFE_FREE(ptr);
253
 
    ptr = old;
254
 
  }
255
 
 
256
 
  channel_free(sftp->channel);
257
 
  sftp_ext_free(sftp->ext);
258
 
  ZERO_STRUCTP(sftp);
259
 
 
260
 
  SAFE_FREE(sftp);
261
 
}
262
 
 
263
 
int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
264
 
  int size;
265
 
 
266
 
  if (buffer_prepend_data(payload, &type, sizeof(uint8_t)) < 0) {
267
 
    ssh_set_error_oom(sftp->session);
268
 
    return -1;
269
 
  }
270
 
 
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);
274
 
    return -1;
275
 
  }
276
 
 
277
 
  size = channel_write(sftp->channel, buffer_get(payload),
278
 
      buffer_get_len(payload));
279
 
  if (size < 0) {
280
 
    return -1;
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),
285
 
        size);
286
 
  }
287
 
 
288
 
  return size;
289
 
}
290
 
 
291
 
sftp_packet sftp_packet_read(sftp_session sftp) {
292
 
  sftp_packet packet = NULL;
293
 
  uint32_t size;
294
 
 
295
 
  sftp_enter_function();
296
 
 
297
 
  packet = malloc(sizeof(struct sftp_packet_struct));
298
 
  if (packet == NULL) {
299
 
    ssh_set_error_oom(sftp->session);
300
 
    return NULL;
301
 
  }
302
 
  packet->sftp = sftp;
303
 
  packet->payload = buffer_new();
304
 
  if (packet->payload == NULL) {
305
 
    ssh_set_error_oom(sftp->session);
306
 
    SAFE_FREE(packet);
307
 
    return NULL;
308
 
  }
309
 
 
310
 
  if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
311
 
    buffer_free(packet->payload);
312
 
    SAFE_FREE(packet);
313
 
    sftp_leave_function();
314
 
    return NULL;
315
 
  }
316
 
 
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);
320
 
    SAFE_FREE(packet);
321
 
    sftp_leave_function();
322
 
    return NULL;
323
 
  }
324
 
 
325
 
  size = ntohl(size);
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);
329
 
    SAFE_FREE(packet);
330
 
    sftp_leave_function();
331
 
    return NULL;
332
 
  }
333
 
 
334
 
  buffer_get_u8(packet->payload, &packet->type);
335
 
  if (size > 1) {
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);
339
 
      SAFE_FREE(packet);
340
 
      sftp_leave_function();
341
 
      return NULL;
342
 
    }
343
 
  }
344
 
 
345
 
  sftp_leave_function();
346
 
  return packet;
347
 
}
348
 
 
349
 
static void sftp_set_error(sftp_session sftp, int errnum) {
350
 
  if (sftp != NULL) {
351
 
    sftp->errnum = errnum;
352
 
  }
353
 
}
354
 
 
355
 
/* Get the last sftp error */
356
 
int sftp_get_error(sftp_session sftp) {
357
 
  if (sftp == NULL) {
358
 
    return -1;
359
 
  }
360
 
 
361
 
  return sftp->errnum;
362
 
}
363
 
 
364
 
static sftp_message sftp_message_new(sftp_session sftp){
365
 
  sftp_message msg = NULL;
366
 
 
367
 
  sftp_enter_function();
368
 
 
369
 
  msg = malloc(sizeof(struct sftp_message_struct));
370
 
  if (msg == NULL) {
371
 
    ssh_set_error_oom(sftp->session);
372
 
    return NULL;
373
 
  }
374
 
  ZERO_STRUCTP(msg);
375
 
 
376
 
  msg->payload = buffer_new();
377
 
  if (msg->payload == NULL) {
378
 
    ssh_set_error_oom(sftp->session);
379
 
    SAFE_FREE(msg);
380
 
    return NULL;
381
 
  }
382
 
  msg->sftp = sftp;
383
 
 
384
 
  sftp_leave_function();
385
 
  return msg;
386
 
}
387
 
 
388
 
static void sftp_message_free(sftp_message msg) {
389
 
  sftp_session sftp;
390
 
 
391
 
  if (msg == NULL) {
392
 
    return;
393
 
  }
394
 
 
395
 
  sftp = msg->sftp;
396
 
  sftp_enter_function();
397
 
 
398
 
  buffer_free(msg->payload);
399
 
  SAFE_FREE(msg);
400
 
 
401
 
  sftp_leave_function();
402
 
}
403
 
 
404
 
static sftp_message sftp_get_message(sftp_packet packet) {
405
 
  sftp_session sftp = packet->sftp;
406
 
  sftp_message msg = NULL;
407
 
 
408
 
  sftp_enter_function();
409
 
 
410
 
  msg = sftp_message_new(sftp);
411
 
  if (msg == NULL) {
412
 
    sftp_leave_function();
413
 
    return NULL;
414
 
  }
415
 
 
416
 
  msg->sftp = packet->sftp;
417
 
  msg->packet_type = packet->type;
418
 
 
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();
426
 
    return NULL;
427
 
  }
428
 
 
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();
434
 
    return NULL;
435
 
  }
436
 
 
437
 
  ssh_log(packet->sftp->session, SSH_LOG_PACKET,
438
 
      "Packet with id %d type %d",
439
 
      msg->id,
440
 
      msg->packet_type);
441
 
 
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();
447
 
    return NULL;
448
 
  }
449
 
 
450
 
  sftp_leave_function();
451
 
  return msg;
452
 
}
453
 
 
454
 
static int sftp_read_and_dispatch(sftp_session sftp) {
455
 
  sftp_packet packet = NULL;
456
 
  sftp_message msg = NULL;
457
 
 
458
 
  sftp_enter_function();
459
 
 
460
 
  packet = sftp_packet_read(sftp);
461
 
  if (packet == NULL) {
462
 
    sftp_leave_function();
463
 
    return -1; /* something nasty happened reading the packet */
464
 
  }
465
 
 
466
 
  msg = sftp_get_message(packet);
467
 
  sftp_packet_free(packet);
468
 
  if (msg == NULL) {
469
 
    sftp_leave_function();
470
 
    return -1;
471
 
  }
472
 
 
473
 
  if (sftp_enqueue(sftp, msg) < 0) {
474
 
    sftp_message_free(msg);
475
 
    sftp_leave_function();
476
 
    return -1;
477
 
  }
478
 
 
479
 
  sftp_leave_function();
480
 
  return 0;
481
 
}
482
 
 
483
 
void sftp_packet_free(sftp_packet packet) {
484
 
  if (packet == NULL) {
485
 
    return;
486
 
  }
487
 
 
488
 
  buffer_free(packet->payload);
489
 
  free(packet);
490
 
}
491
 
 
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);
501
 
 
502
 
  sftp_enter_function();
503
 
 
504
 
  buffer = buffer_new();
505
 
  if (buffer == NULL) {
506
 
    ssh_set_error_oom(sftp->session);
507
 
    sftp_leave_function();
508
 
    return -1;
509
 
  }
510
 
 
511
 
  if (buffer_add_u32(buffer, version) < 0) {
512
 
    ssh_set_error_oom(sftp->session);
513
 
    buffer_free(buffer);
514
 
    sftp_leave_function();
515
 
    return -1;
516
 
  }
517
 
  if (sftp_packet_write(sftp, SSH_FXP_INIT, buffer) < 0) {
518
 
    buffer_free(buffer);
519
 
    sftp_leave_function();
520
 
    return -1;
521
 
  }
522
 
  buffer_free(buffer);
523
 
 
524
 
  packet = sftp_packet_read(sftp);
525
 
  if (packet == NULL) {
526
 
    sftp_leave_function();
527
 
    return -1;
528
 
  }
529
 
 
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();
535
 
    return -1;
536
 
  }
537
 
 
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",
543
 
      version);
544
 
 
545
 
  ext_name_s = buffer_get_ssh_string(packet->payload);
546
 
  while (ext_name_s != NULL) {
547
 
    int count = sftp->ext->count;
548
 
    char **tmp;
549
 
 
550
 
    ext_data_s = buffer_get_ssh_string(packet->payload);
551
 
    if (ext_data_s == NULL) {
552
 
      string_free(ext_name_s);
553
 
      break;
554
 
    }
555
 
 
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);
560
 
      SAFE_FREE(ext_name);
561
 
      SAFE_FREE(ext_data);
562
 
      string_free(ext_name_s);
563
 
      string_free(ext_data_s);
564
 
      return -1;
565
 
    }
566
 
    ssh_log(sftp->session, SSH_LOG_RARE,
567
 
        "SFTP server extension: %s, version: %s",
568
 
        ext_name, ext_data);
569
 
 
570
 
    count++;
571
 
    tmp = realloc(sftp->ext->name, count * sizeof(char *));
572
 
    if (tmp == NULL) {
573
 
      ssh_set_error_oom(sftp->session);
574
 
      SAFE_FREE(ext_name);
575
 
      SAFE_FREE(ext_data);
576
 
      string_free(ext_name_s);
577
 
      string_free(ext_data_s);
578
 
      return -1;
579
 
    }
580
 
    tmp[count - 1] = ext_name;
581
 
    sftp->ext->name = tmp;
582
 
 
583
 
    tmp = realloc(sftp->ext->data, count * sizeof(char *));
584
 
    if (tmp == NULL) {
585
 
      ssh_set_error_oom(sftp->session);
586
 
      SAFE_FREE(ext_name);
587
 
      SAFE_FREE(ext_data);
588
 
      string_free(ext_name_s);
589
 
      string_free(ext_data_s);
590
 
      return -1;
591
 
    }
592
 
    tmp[count - 1] = ext_data;
593
 
    sftp->ext->data = tmp;
594
 
 
595
 
    sftp->ext->count = count;
596
 
 
597
 
    string_free(ext_name_s);
598
 
    string_free(ext_data_s);
599
 
 
600
 
    ext_name_s = buffer_get_ssh_string(packet->payload);
601
 
  }
602
 
 
603
 
  sftp_packet_free(packet);
604
 
 
605
 
  sftp->version = sftp->server_version = version;
606
 
 
607
 
  sftp_leave_function();
608
 
 
609
 
  return 0;
610
 
}
611
 
 
612
 
unsigned int sftp_extensions_get_count(sftp_session sftp) {
613
 
  if (sftp == NULL || sftp->ext == NULL) {
614
 
    return 0;
615
 
  }
616
 
 
617
 
  return sftp->ext->count;
618
 
}
619
 
 
620
 
const char *sftp_extensions_get_name(sftp_session sftp, unsigned int idx) {
621
 
  if (sftp == NULL)
622
 
    return NULL;
623
 
  if (sftp->ext == NULL || sftp->ext->name == NULL) {
624
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
625
 
    return NULL;
626
 
  }
627
 
 
628
 
  if (idx > sftp->ext->count) {
629
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
630
 
    return NULL;
631
 
  }
632
 
 
633
 
  return sftp->ext->name[idx];
634
 
}
635
 
 
636
 
const char *sftp_extensions_get_data(sftp_session sftp, unsigned int idx) {
637
 
  if (sftp == NULL)
638
 
    return NULL;
639
 
  if (sftp->ext == NULL || sftp->ext->name == NULL) {
640
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
641
 
    return NULL;
642
 
  }
643
 
 
644
 
  if (idx > sftp->ext->count) {
645
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
646
 
    return NULL;
647
 
  }
648
 
 
649
 
  return sftp->ext->data[idx];
650
 
}
651
 
 
652
 
int sftp_extension_supported(sftp_session sftp, const char *name,
653
 
    const char *data) {
654
 
  int i, n;
655
 
 
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) {
660
 
      return 1;
661
 
    }
662
 
  }
663
 
 
664
 
  return 0;
665
 
}
666
 
 
667
 
static sftp_request_queue request_queue_new(sftp_message msg) {
668
 
  sftp_request_queue queue = NULL;
669
 
 
670
 
  queue = malloc(sizeof(struct sftp_request_queue_struct));
671
 
  if (queue == NULL) {
672
 
    ssh_set_error_oom(msg->sftp->session);
673
 
    return NULL;
674
 
  }
675
 
  ZERO_STRUCTP(queue);
676
 
 
677
 
  queue->message = msg;
678
 
 
679
 
  return queue;
680
 
}
681
 
 
682
 
static void request_queue_free(sftp_request_queue queue) {
683
 
  if (queue == NULL) {
684
 
    return;
685
 
  }
686
 
 
687
 
  ZERO_STRUCTP(queue);
688
 
  SAFE_FREE(queue);
689
 
}
690
 
 
691
 
static int sftp_enqueue(sftp_session sftp, sftp_message msg) {
692
 
  sftp_request_queue queue = NULL;
693
 
  sftp_request_queue ptr;
694
 
 
695
 
  queue = request_queue_new(msg);
696
 
  if (queue == NULL) {
697
 
    return -1;
698
 
  }
699
 
 
700
 
  ssh_log(sftp->session, SSH_LOG_PACKET,
701
 
      "Queued msg type %d id %d",
702
 
      msg->id, msg->packet_type);
703
 
 
704
 
  if(sftp->queue == NULL) {
705
 
    sftp->queue = queue;
706
 
  } else {
707
 
    ptr = sftp->queue;
708
 
    while(ptr->next) {
709
 
      ptr=ptr->next; /* find end of linked list */
710
 
    }
711
 
    ptr->next = queue; /* add it on bottom */
712
 
  }
713
 
 
714
 
  return 0;
715
 
}
716
 
 
717
 
/*
718
 
 * Pulls of a message from the queue based on the ID.
719
 
 * Returns NULL if no message has been found.
720
 
 */
721
 
static sftp_message sftp_dequeue(sftp_session sftp, uint32_t id){
722
 
  sftp_request_queue prev = NULL;
723
 
  sftp_request_queue queue;
724
 
  sftp_message msg;
725
 
 
726
 
  if(sftp->queue == NULL) {
727
 
    return NULL;
728
 
  }
729
 
 
730
 
  queue = sftp->queue;
731
 
  while (queue) {
732
 
    if(queue->message->id == id) {
733
 
      /* remove from queue */
734
 
      if (prev == NULL) {
735
 
        sftp->queue = queue->next;
736
 
      } else {
737
 
        prev->next = queue->next;
738
 
      }
739
 
      msg = queue->message;
740
 
      request_queue_free(queue);
741
 
      ssh_log(sftp->session, SSH_LOG_PACKET,
742
 
          "Dequeued msg id %d type %d",
743
 
          msg->id,
744
 
          msg->packet_type);
745
 
      return msg;
746
 
    }
747
 
    prev = queue;
748
 
    queue = queue->next;
749
 
  }
750
 
 
751
 
  return NULL;
752
 
}
753
 
 
754
 
/*
755
 
 * Assigns a new SFTP ID for new requests and assures there is no collision
756
 
 * between them.
757
 
 * Returns a new ID ready to use in a request
758
 
 */
759
 
static inline uint32_t sftp_get_new_id(sftp_session session) {
760
 
  return ++session->id_counter;
761
 
}
762
 
 
763
 
static sftp_status_message parse_status_msg(sftp_message msg){
764
 
  sftp_status_message status;
765
 
 
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!");
769
 
    return NULL;
770
 
  }
771
 
 
772
 
  status = malloc(sizeof(struct sftp_status_message_struct));
773
 
  if (status == NULL) {
774
 
    ssh_set_error_oom(msg->sftp->session);
775
 
    return NULL;
776
 
  }
777
 
  ZERO_STRUCTP(status);
778
 
 
779
 
  status->id = msg->id;
780
 
  if (buffer_get_u32(msg->payload,&status->status) != 4){
781
 
    SAFE_FREE(status);
782
 
    ssh_set_error(msg->sftp->session, SSH_FATAL,
783
 
        "Invalid SSH_FXP_STATUS message");
784
 
    return NULL;
785
 
  }
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 */
793
 
      SAFE_FREE(status);
794
 
      ssh_set_error(msg->sftp->session, SSH_FATAL,
795
 
        "Invalid SSH_FXP_STATUS message");
796
 
      return NULL;
797
 
    }
798
 
  }
799
 
 
800
 
  status->status = ntohl(status->status);
801
 
  if(status->error)
802
 
    status->errormsg = string_to_char(status->error);
803
 
  else
804
 
    status->errormsg = strdup("No error message in packet");
805
 
  if(status->lang)
806
 
    status->langmsg = string_to_char(status->lang);
807
 
  else
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);
812
 
    return NULL;
813
 
  }
814
 
 
815
 
  return status;
816
 
}
817
 
 
818
 
static void status_msg_free(sftp_status_message status){
819
 
  if (status == NULL) {
820
 
    return;
821
 
  }
822
 
 
823
 
  string_free(status->error);
824
 
  string_free(status->lang);
825
 
  SAFE_FREE(status->errormsg);
826
 
  SAFE_FREE(status->langmsg);
827
 
  SAFE_FREE(status);
828
 
}
829
 
 
830
 
static sftp_file parse_handle_msg(sftp_message msg){
831
 
  sftp_file file;
832
 
 
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!");
836
 
    return NULL;
837
 
  }
838
 
 
839
 
  file = malloc(sizeof(struct sftp_file_struct));
840
 
  if (file == NULL) {
841
 
    ssh_set_error_oom(msg->sftp->session);
842
 
    return NULL;
843
 
  }
844
 
  ZERO_STRUCTP(file);
845
 
 
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");
850
 
    SAFE_FREE(file);
851
 
    return NULL;
852
 
  }
853
 
 
854
 
  file->sftp = msg->sftp;
855
 
  file->offset = 0;
856
 
  file->eof = 0;
857
 
 
858
 
  return file;
859
 
}
860
 
 
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;
865
 
  sftp_dir dir = NULL;
866
 
  sftp_status_message status;
867
 
  ssh_string path_s;
868
 
  ssh_buffer payload;
869
 
  uint32_t id;
870
 
 
871
 
  payload = buffer_new();
872
 
  if (payload == NULL) {
873
 
    ssh_set_error_oom(sftp->session);
874
 
    return NULL;
875
 
  }
876
 
 
877
 
  path_s = string_from_char(path);
878
 
  if (path_s == NULL) {
879
 
    ssh_set_error_oom(sftp->session);
880
 
    buffer_free(payload);
881
 
    return NULL;
882
 
  }
883
 
 
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);
889
 
    string_free(path_s);
890
 
    return NULL;
891
 
  }
892
 
  string_free(path_s);
893
 
 
894
 
  if (sftp_packet_write(sftp, SSH_FXP_OPENDIR, payload) < 0) {
895
 
    buffer_free(payload);
896
 
    return NULL;
897
 
  }
898
 
  buffer_free(payload);
899
 
 
900
 
  while (msg == NULL) {
901
 
    if (sftp_read_and_dispatch(sftp) < 0) {
902
 
      /* something nasty has happened */
903
 
      return NULL;
904
 
    }
905
 
    msg = sftp_dequeue(sftp, id);
906
 
  }
907
 
 
908
 
  switch (msg->packet_type) {
909
 
    case SSH_FXP_STATUS:
910
 
      status = parse_status_msg(msg);
911
 
      sftp_message_free(msg);
912
 
      if (status == NULL) {
913
 
        return NULL;
914
 
      }
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);
919
 
      return NULL;
920
 
    case SSH_FXP_HANDLE:
921
 
      file = parse_handle_msg(msg);
922
 
      sftp_message_free(msg);
923
 
      if (file != NULL) {
924
 
        dir = malloc(sizeof(struct sftp_dir_struct));
925
 
        if (dir == NULL) {
926
 
          ssh_set_error_oom(sftp->session);
927
 
          return NULL;
928
 
        }
929
 
        ZERO_STRUCTP(dir);
930
 
 
931
 
        dir->sftp = sftp;
932
 
        dir->name = strdup(path);
933
 
        if (dir->name == NULL) {
934
 
          SAFE_FREE(dir);
935
 
          SAFE_FREE(file);
936
 
          return NULL;
937
 
        }
938
 
        dir->handle = file->handle;
939
 
        SAFE_FREE(file);
940
 
      }
941
 
      return dir;
942
 
    default:
943
 
      ssh_set_error(sftp->session, SSH_FATAL,
944
 
          "Received message %d during opendir!", msg->packet_type);
945
 
      sftp_message_free(msg);
946
 
  }
947
 
 
948
 
  return NULL;
949
 
}
950
 
 
951
 
/*
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.
955
 
 */
956
 
static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
957
 
    int expectnames) {
958
 
  sftp_attributes attr;
959
 
  ssh_string owner = NULL;
960
 
  ssh_string group = NULL;
961
 
  uint32_t flags = 0;
962
 
  int ok = 0;
963
 
 
964
 
  /* unused member variable */
965
 
  (void) expectnames;
966
 
 
967
 
  attr = malloc(sizeof(struct sftp_attributes_struct));
968
 
  if (attr == NULL) {
969
 
    ssh_set_error_oom(sftp->session);
970
 
    return NULL;
971
 
  }
972
 
  ZERO_STRUCTP(attr);
973
 
 
974
 
  /* This isn't really a loop, but it is like a try..catch.. */
975
 
  do {
976
 
    if (buffer_get_u32(buf, &flags) != 4) {
977
 
      break;
978
 
    }
979
 
 
980
 
    flags = ntohl(flags);
981
 
    attr->flags = flags;
982
 
 
983
 
    if (flags & SSH_FILEXFER_ATTR_SIZE) {
984
 
      if (buffer_get_u64(buf, &attr->size) != 8) {
985
 
        break;
986
 
      }
987
 
      attr->size = ntohll(attr->size);
988
 
    }
989
 
 
990
 
    if (flags & SSH_FILEXFER_ATTR_OWNERGROUP) {
991
 
      if((owner = buffer_get_ssh_string(buf)) == NULL ||
992
 
        (attr->owner = string_to_char(owner)) == NULL) {
993
 
        break;
994
 
      }
995
 
      if ((group = buffer_get_ssh_string(buf)) == NULL ||
996
 
        (attr->group = string_to_char(group)) == NULL) {
997
 
        break;
998
 
      }
999
 
    }
1000
 
 
1001
 
    if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
1002
 
      if (buffer_get_u32(buf, &attr->permissions) != 4) {
1003
 
        break;
1004
 
      }
1005
 
      attr->permissions = ntohl(attr->permissions);
1006
 
 
1007
 
      /* FIXME on windows! */
1008
 
      switch (attr->permissions & S_IFMT) {
1009
 
        case S_IFSOCK:
1010
 
        case S_IFBLK:
1011
 
        case S_IFCHR:
1012
 
        case S_IFIFO:
1013
 
          attr->type = SSH_FILEXFER_TYPE_SPECIAL;
1014
 
          break;
1015
 
        case S_IFLNK:
1016
 
          attr->type = SSH_FILEXFER_TYPE_SYMLINK;
1017
 
          break;
1018
 
        case S_IFREG:
1019
 
          attr->type = SSH_FILEXFER_TYPE_REGULAR;
1020
 
          break;
1021
 
        case S_IFDIR:
1022
 
          attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
1023
 
          break;
1024
 
        default:
1025
 
          attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
1026
 
          break;
1027
 
      }
1028
 
    }
1029
 
 
1030
 
    if (flags & SSH_FILEXFER_ATTR_ACCESSTIME) {
1031
 
      if (buffer_get_u64(buf, &attr->atime64) != 8) {
1032
 
        break;
1033
 
      }
1034
 
      attr->atime64 = ntohll(attr->atime64);
1035
 
    }
1036
 
 
1037
 
    if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
1038
 
      if (buffer_get_u32(buf, &attr->atime_nseconds) != 4) {
1039
 
        break;
1040
 
      }
1041
 
      attr->atime_nseconds = ntohl(attr->atime_nseconds);
1042
 
    }
1043
 
 
1044
 
    if (flags & SSH_FILEXFER_ATTR_CREATETIME) {
1045
 
      if (buffer_get_u64(buf, &attr->createtime) != 8) {
1046
 
        break;
1047
 
      }
1048
 
      attr->createtime = ntohll(attr->createtime);
1049
 
    }
1050
 
 
1051
 
    if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
1052
 
      if (buffer_get_u32(buf, &attr->createtime_nseconds) != 4) {
1053
 
        break;
1054
 
      }
1055
 
      attr->createtime_nseconds = ntohl(attr->createtime_nseconds);
1056
 
    }
1057
 
 
1058
 
    if (flags & SSH_FILEXFER_ATTR_MODIFYTIME) {
1059
 
      if (buffer_get_u64(buf, &attr->mtime64) != 8) {
1060
 
        break;
1061
 
      }
1062
 
      attr->mtime64 = ntohll(attr->mtime64);
1063
 
    }
1064
 
 
1065
 
    if (flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) {
1066
 
      if (buffer_get_u32(buf, &attr->mtime_nseconds) != 4) {
1067
 
        break;
1068
 
      }
1069
 
      attr->mtime_nseconds = ntohl(attr->mtime_nseconds);
1070
 
    }
1071
 
 
1072
 
    if (flags & SSH_FILEXFER_ATTR_ACL) {
1073
 
      if ((attr->acl = buffer_get_ssh_string(buf)) == NULL) {
1074
 
        break;
1075
 
      }
1076
 
    }
1077
 
 
1078
 
    if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
1079
 
      if (buffer_get_u32(buf,&attr->extended_count) != 4) {
1080
 
        break;
1081
 
      }
1082
 
      attr->extended_count = ntohl(attr->extended_count);
1083
 
 
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--;
1088
 
      }
1089
 
 
1090
 
      if (attr->extended_count) {
1091
 
        break;
1092
 
      }
1093
 
    }
1094
 
    ok = 1;
1095
 
  } while (0);
1096
 
 
1097
 
  if (ok == 0) {
1098
 
    /* break issued somewhere */
1099
 
    string_free(owner);
1100
 
    string_free(group);
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);
1106
 
    SAFE_FREE(attr);
1107
 
 
1108
 
    ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
1109
 
 
1110
 
    return NULL;
1111
 
  }
1112
 
 
1113
 
  return attr;
1114
 
}
1115
 
 
1116
 
enum sftp_longname_field_e {
1117
 
  SFTP_LONGNAME_PERM = 0,
1118
 
  SFTP_LONGNAME_FIXME,
1119
 
  SFTP_LONGNAME_OWNER,
1120
 
  SFTP_LONGNAME_GROUP,
1121
 
  SFTP_LONGNAME_SIZE,
1122
 
  SFTP_LONGNAME_DATE,
1123
 
  SFTP_LONGNAME_TIME,
1124
 
  SFTP_LONGNAME_NAME,
1125
 
};
1126
 
 
1127
 
static char *sftp_parse_longname(const char *longname,
1128
 
        enum sftp_longname_field_e longname_field) {
1129
 
    const char *p, *q;
1130
 
    size_t len, field = 0;
1131
 
    char *x;
1132
 
 
1133
 
    p = longname;
1134
 
    /* Find the beginning of the field which is specified by sftp_longanme_field_e. */
1135
 
    while(field != longname_field) {
1136
 
        if(isspace(*p)) {
1137
 
            field++;
1138
 
            p++;
1139
 
            while(*p && isspace(*p)) {
1140
 
                p++;
1141
 
            }
1142
 
        } else {
1143
 
            p++;
1144
 
        }
1145
 
    }
1146
 
 
1147
 
    q = p;
1148
 
    while (! isspace(*q)) {
1149
 
        q++;
1150
 
    }
1151
 
 
1152
 
    /* There is no strndup on windows */
1153
 
    len = q - p + 1;
1154
 
    x = malloc(len);
1155
 
    if (x == NULL) {
1156
 
      return NULL;
1157
 
    }
1158
 
 
1159
 
    snprintf(x, len, "%s", p);
1160
 
 
1161
 
    return x;
1162
 
}
1163
 
 
1164
 
/* sftp version 0-3 code. It is different from the v4 */
1165
 
/* maybe a paste of the draft is better than the code */
1166
 
/*
1167
 
        uint32   flags
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,
1180
 
    int expectname) {
1181
 
  ssh_string longname = NULL;
1182
 
  ssh_string name = NULL;
1183
 
  sftp_attributes attr;
1184
 
  uint32_t flags = 0;
1185
 
  int ok = 0;
1186
 
 
1187
 
  attr = malloc(sizeof(struct sftp_attributes_struct));
1188
 
  if (attr == NULL) {
1189
 
    ssh_set_error_oom(sftp->session);
1190
 
    return NULL;
1191
 
  }
1192
 
  ZERO_STRUCTP(attr);
1193
 
 
1194
 
  /* This isn't really a loop, but it is like a try..catch.. */
1195
 
  do {
1196
 
    if (expectname) {
1197
 
      if ((name = buffer_get_ssh_string(buf)) == NULL ||
1198
 
          (attr->name = string_to_char(name)) == NULL) {
1199
 
        break;
1200
 
      }
1201
 
      string_free(name);
1202
 
 
1203
 
      ssh_log(sftp->session, SSH_LOG_RARE, "Name: %s", attr->name);
1204
 
 
1205
 
      if ((longname=buffer_get_ssh_string(buf)) == NULL ||
1206
 
          (attr->longname=string_to_char(longname)) == NULL) {
1207
 
        break;
1208
 
      }
1209
 
      string_free(longname);
1210
 
 
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) {
1215
 
          break;
1216
 
        }
1217
 
 
1218
 
        attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
1219
 
        if (attr->group == NULL) {
1220
 
          break;
1221
 
        }
1222
 
      }
1223
 
    }
1224
 
 
1225
 
    if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
1226
 
      break;
1227
 
    }
1228
 
    flags = ntohl(flags);
1229
 
    attr->flags = flags;
1230
 
    ssh_log(sftp->session, SSH_LOG_RARE,
1231
 
        "Flags: %.8lx\n", (long unsigned int) flags);
1232
 
 
1233
 
    if (flags & SSH_FILEXFER_ATTR_SIZE) {
1234
 
      if(buffer_get_u64(buf, &attr->size) != sizeof(uint64_t)) {
1235
 
        break;
1236
 
      }
1237
 
      attr->size = ntohll(attr->size);
1238
 
      ssh_log(sftp->session, SSH_LOG_RARE,
1239
 
          "Size: %llu\n",
1240
 
          (long long unsigned int) attr->size);
1241
 
    }
1242
 
 
1243
 
    if (flags & SSH_FILEXFER_ATTR_UIDGID) {
1244
 
      if (buffer_get_u32(buf, &attr->uid) != sizeof(uint32_t)) {
1245
 
        break;
1246
 
      }
1247
 
      if (buffer_get_u32(buf, &attr->gid) != sizeof(uint32_t)) {
1248
 
        break;
1249
 
      }
1250
 
      attr->uid = ntohl(attr->uid);
1251
 
      attr->gid = ntohl(attr->gid);
1252
 
    }
1253
 
 
1254
 
    if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
1255
 
      if (buffer_get_u32(buf, &attr->permissions) != sizeof(uint32_t)) {
1256
 
        break;
1257
 
      }
1258
 
      attr->permissions = ntohl(attr->permissions);
1259
 
 
1260
 
      switch (attr->permissions & S_IFMT) {
1261
 
        case S_IFSOCK:
1262
 
        case S_IFBLK:
1263
 
        case S_IFCHR:
1264
 
        case S_IFIFO:
1265
 
          attr->type = SSH_FILEXFER_TYPE_SPECIAL;
1266
 
          break;
1267
 
        case S_IFLNK:
1268
 
          attr->type = SSH_FILEXFER_TYPE_SYMLINK;
1269
 
          break;
1270
 
        case S_IFREG:
1271
 
          attr->type = SSH_FILEXFER_TYPE_REGULAR;
1272
 
          break;
1273
 
        case S_IFDIR:
1274
 
          attr->type = SSH_FILEXFER_TYPE_DIRECTORY;
1275
 
          break;
1276
 
        default:
1277
 
          attr->type = SSH_FILEXFER_TYPE_UNKNOWN;
1278
 
          break;
1279
 
      }
1280
 
    }
1281
 
 
1282
 
    if (flags & SSH_FILEXFER_ATTR_ACMODTIME) {
1283
 
      if (buffer_get_u32(buf, &attr->atime) != sizeof(uint32_t)) {
1284
 
        break;
1285
 
      }
1286
 
      attr->atime = ntohl(attr->atime);
1287
 
      if (buffer_get_u32(buf, &attr->mtime) != sizeof(uint32_t)) {
1288
 
        break;
1289
 
      }
1290
 
      attr->mtime = ntohl(attr->mtime);
1291
 
    }
1292
 
 
1293
 
    if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
1294
 
      if (buffer_get_u32(buf, &attr->extended_count) != sizeof(uint32_t)) {
1295
 
        break;
1296
 
      }
1297
 
 
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--;
1303
 
      }
1304
 
 
1305
 
      if (attr->extended_count) {
1306
 
        break;
1307
 
      }
1308
 
    }
1309
 
    ok = 1;
1310
 
  } while (0);
1311
 
 
1312
 
  if (!ok) {
1313
 
    /* break issued somewhere */
1314
 
    string_free(name);
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);
1322
 
    SAFE_FREE(attr);
1323
 
 
1324
 
    ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
1325
 
 
1326
 
    return NULL;
1327
 
  }
1328
 
 
1329
 
  /* everything went smoothly */
1330
 
  return attr;
1331
 
}
1332
 
 
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);
1336
 
 
1337
 
  flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID |
1338
 
      SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
1339
 
 
1340
 
  if (buffer_add_u32(buffer, htonl(flags)) < 0) {
1341
 
    return -1;
1342
 
  }
1343
 
 
1344
 
  if (attr) {
1345
 
    if (flags & SSH_FILEXFER_ATTR_SIZE) {
1346
 
      if (buffer_add_u64(buffer, htonll(attr->size)) < 0) {
1347
 
        return -1;
1348
 
      }
1349
 
    }
1350
 
 
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) {
1354
 
        return -1;
1355
 
      }
1356
 
    }
1357
 
 
1358
 
    if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
1359
 
      if (buffer_add_u32(buffer, htonl(attr->permissions)) < 0) {
1360
 
        return -1;
1361
 
      }
1362
 
    }
1363
 
 
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) {
1367
 
        return -1;
1368
 
      }
1369
 
    }
1370
 
  }
1371
 
 
1372
 
  return 0;
1373
 
}
1374
 
 
1375
 
 
1376
 
sftp_attributes sftp_parse_attr(sftp_session session, ssh_buffer buf,
1377
 
    int expectname) {
1378
 
  switch(session->version) {
1379
 
    case 4:
1380
 
      return sftp_parse_attr_4(session, buf, expectname);
1381
 
    case 3:
1382
 
    case 2:
1383
 
    case 1:
1384
 
    case 0:
1385
 
      return sftp_parse_attr_3(session, buf, expectname);
1386
 
    default:
1387
 
      ssh_set_error(session->session, SSH_FATAL,
1388
 
          "Version %d unsupported by client", session->server_version);
1389
 
      return NULL;
1390
 
  }
1391
 
 
1392
 
  return NULL;
1393
 
}
1394
 
 
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;
1398
 
}
1399
 
 
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;
1405
 
  ssh_buffer payload;
1406
 
  uint32_t id;
1407
 
 
1408
 
  if (dir->buffer == NULL) {
1409
 
    payload = buffer_new();
1410
 
    if (payload == NULL) {
1411
 
      ssh_set_error_oom(sftp->session);
1412
 
      return NULL;
1413
 
    }
1414
 
 
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);
1420
 
      return NULL;
1421
 
    }
1422
 
 
1423
 
    if (sftp_packet_write(sftp, SSH_FXP_READDIR, payload) < 0) {
1424
 
      buffer_free(payload);
1425
 
      return NULL;
1426
 
    }
1427
 
    buffer_free(payload);
1428
 
 
1429
 
    ssh_log(sftp->session, SSH_LOG_PACKET,
1430
 
        "Sent a ssh_fxp_readdir with id %d", id);
1431
 
 
1432
 
    while (msg == NULL) {
1433
 
      if (sftp_read_and_dispatch(sftp) < 0) {
1434
 
        /* something nasty has happened */
1435
 
        return NULL;
1436
 
      }
1437
 
      msg = sftp_dequeue(sftp, id);
1438
 
    }
1439
 
 
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) {
1445
 
          return NULL;
1446
 
        }
1447
 
        sftp_set_error(sftp, status->status);
1448
 
        switch (status->status) {
1449
 
          case SSH_FX_EOF:
1450
 
            dir->eof = 1;
1451
 
            status_msg_free(status);
1452
 
            return NULL;
1453
 
          default:
1454
 
            break;
1455
 
        }
1456
 
 
1457
 
        ssh_set_error(sftp->session, SSH_FATAL,
1458
 
            "Unknown error status: %d", status->status);
1459
 
        status_msg_free(status);
1460
 
 
1461
 
        return NULL;
1462
 
      case SSH_FXP_NAME:
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);
1468
 
        break;
1469
 
      default:
1470
 
        ssh_set_error(sftp->session, SSH_FATAL,
1471
 
            "Unsupported message back %d", msg->packet_type);
1472
 
        sftp_message_free(msg);
1473
 
 
1474
 
        return NULL;
1475
 
    }
1476
 
  }
1477
 
 
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 "
1482
 
        "libsftp bug");
1483
 
    return NULL;
1484
 
  }
1485
 
 
1486
 
  ssh_log(sftp->session, SSH_LOG_RARE, "Count is %d", dir->count);
1487
 
 
1488
 
  attr = sftp_parse_attr(sftp, dir->buffer, 1);
1489
 
  if (attr == NULL) {
1490
 
    ssh_set_error(sftp->session, SSH_FATAL,
1491
 
        "Couldn't parse the SFTP attributes");
1492
 
    return NULL;
1493
 
  }
1494
 
 
1495
 
  dir->count--;
1496
 
  if (dir->count == 0) {
1497
 
    buffer_free(dir->buffer);
1498
 
    dir->buffer = NULL;
1499
 
  }
1500
 
 
1501
 
  return attr;
1502
 
}
1503
 
 
1504
 
/* Tell if the directory has reached EOF (End Of File). */
1505
 
int sftp_dir_eof(sftp_dir dir) {
1506
 
  return dir->eof;
1507
 
}
1508
 
 
1509
 
/* Free a SFTP_ATTRIBUTE handle */
1510
 
void sftp_attributes_free(sftp_attributes file){
1511
 
  if (file == NULL) {
1512
 
    return;
1513
 
  }
1514
 
 
1515
 
  string_free(file->acl);
1516
 
  string_free(file->extended_data);
1517
 
  string_free(file->extended_type);
1518
 
 
1519
 
  SAFE_FREE(file->name);
1520
 
  SAFE_FREE(file->longname);
1521
 
  SAFE_FREE(file->group);
1522
 
  SAFE_FREE(file->owner);
1523
 
 
1524
 
  SAFE_FREE(file);
1525
 
}
1526
 
 
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;
1531
 
  uint32_t id;
1532
 
 
1533
 
  buffer = buffer_new();
1534
 
  if (buffer == NULL) {
1535
 
    ssh_set_error_oom(sftp->session);
1536
 
    return -1;
1537
 
  }
1538
 
 
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);
1544
 
    return -1;
1545
 
  }
1546
 
  if (sftp_packet_write(sftp, SSH_FXP_CLOSE ,buffer) < 0) {
1547
 
    buffer_free(buffer);
1548
 
    return -1;
1549
 
  }
1550
 
  buffer_free(buffer);
1551
 
 
1552
 
  while (msg == NULL) {
1553
 
    if (sftp_read_and_dispatch(sftp) < 0) {
1554
 
      /* something nasty has happened */
1555
 
      return -1;
1556
 
    }
1557
 
    msg = sftp_dequeue(sftp,id);
1558
 
  }
1559
 
 
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) {
1565
 
        return -1;
1566
 
      }
1567
 
      sftp_set_error(sftp, status->status);
1568
 
      switch (status->status) {
1569
 
        case SSH_FX_OK:
1570
 
          status_msg_free(status);
1571
 
          return 0;
1572
 
          break;
1573
 
        default:
1574
 
          break;
1575
 
      }
1576
 
      ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
1577
 
          "SFTP server: %s", status->errormsg);
1578
 
      status_msg_free(status);
1579
 
      return -1;
1580
 
    default:
1581
 
      ssh_set_error(sftp->session, SSH_FATAL,
1582
 
          "Received message %d during sftp_handle_close!", msg->packet_type);
1583
 
      sftp_message_free(msg);
1584
 
  }
1585
 
 
1586
 
  return -1;
1587
 
}
1588
 
 
1589
 
/* Close an open file handle. */
1590
 
int sftp_close(sftp_file file){
1591
 
  int err = SSH_NO_ERROR;
1592
 
 
1593
 
  SAFE_FREE(file->name);
1594
 
  if (file->handle){
1595
 
    err = sftp_handle_close(file->sftp,file->handle);
1596
 
    string_free(file->handle);
1597
 
  }
1598
 
  /* FIXME: check server response and implement errno */
1599
 
  SAFE_FREE(file);
1600
 
 
1601
 
  return err;
1602
 
}
1603
 
 
1604
 
/* Close an open directory. */
1605
 
int sftp_closedir(sftp_dir dir){
1606
 
  int err = SSH_NO_ERROR;
1607
 
 
1608
 
  SAFE_FREE(dir->name);
1609
 
  if (dir->handle) {
1610
 
    err = sftp_handle_close(dir->sftp, dir->handle);
1611
 
    string_free(dir->handle);
1612
 
  }
1613
 
  /* FIXME: check server response and implement errno */
1614
 
  buffer_free(dir->buffer);
1615
 
  SAFE_FREE(dir);
1616
 
 
1617
 
  return err;
1618
 
}
1619
 
 
1620
 
/* Open a file on the server. */
1621
 
sftp_file sftp_open(sftp_session sftp, const char *file, int flags,
1622
 
    mode_t mode) {
1623
 
  sftp_message msg = NULL;
1624
 
  sftp_status_message status;
1625
 
  struct sftp_attributes_struct attr;
1626
 
  sftp_file handle;
1627
 
  ssh_string filename;
1628
 
  ssh_buffer buffer;
1629
 
  uint32_t sftp_flags = 0;
1630
 
  uint32_t id;
1631
 
 
1632
 
  buffer = buffer_new();
1633
 
  if (buffer == NULL) {
1634
 
    ssh_set_error_oom(sftp->session);
1635
 
    return NULL;
1636
 
  }
1637
 
 
1638
 
  filename = string_from_char(file);
1639
 
  if (filename == NULL) {
1640
 
    ssh_set_error_oom(sftp->session);
1641
 
    buffer_free(buffer);
1642
 
    return NULL;
1643
 
  }
1644
 
 
1645
 
  ZERO_STRUCT(attr);
1646
 
  attr.permissions = mode;
1647
 
  attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
1648
 
 
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;
1654
 
  if (flags & O_RDWR)
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;
1660
 
  if (flags & O_EXCL)
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);
1669
 
    return NULL;
1670
 
  }
1671
 
  string_free(filename);
1672
 
 
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);
1677
 
    return NULL;
1678
 
  }
1679
 
  if (sftp_packet_write(sftp, SSH_FXP_OPEN, buffer) < 0) {
1680
 
    buffer_free(buffer);
1681
 
    return NULL;
1682
 
  }
1683
 
  buffer_free(buffer);
1684
 
 
1685
 
  while (msg == NULL) {
1686
 
    if (sftp_read_and_dispatch(sftp) < 0) {
1687
 
      /* something nasty has happened */
1688
 
      return NULL;
1689
 
    }
1690
 
    msg = sftp_dequeue(sftp, id);
1691
 
  }
1692
 
 
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) {
1698
 
        return NULL;
1699
 
      }
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);
1704
 
 
1705
 
      return NULL;
1706
 
    case SSH_FXP_HANDLE:
1707
 
      handle = parse_handle_msg(msg);
1708
 
      sftp_message_free(msg);
1709
 
      return handle;
1710
 
    default:
1711
 
      ssh_set_error(sftp->session, SSH_FATAL,
1712
 
          "Received message %d during open!", msg->packet_type);
1713
 
      sftp_message_free(msg);
1714
 
  }
1715
 
 
1716
 
  return NULL;
1717
 
}
1718
 
 
1719
 
void sftp_file_set_nonblocking(sftp_file handle){
1720
 
    handle->nonblocking=1;
1721
 
}
1722
 
void sftp_file_set_blocking(sftp_file handle){
1723
 
    handle->nonblocking=0;
1724
 
}
1725
 
 
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;
1732
 
  ssh_buffer buffer;
1733
 
  int id;
1734
 
 
1735
 
  if (handle->eof) {
1736
 
    return 0;
1737
 
  }
1738
 
 
1739
 
  buffer = buffer_new();
1740
 
  if (buffer == NULL) {
1741
 
    ssh_set_error_oom(sftp->session);
1742
 
    return -1;
1743
 
  }
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);
1751
 
    return -1;
1752
 
  }
1753
 
  if (sftp_packet_write(handle->sftp, SSH_FXP_READ, buffer) < 0) {
1754
 
    buffer_free(buffer);
1755
 
    return -1;
1756
 
  }
1757
 
  buffer_free(buffer);
1758
 
 
1759
 
  while (msg == NULL) {
1760
 
    if (handle->nonblocking) {
1761
 
      if (channel_poll(handle->sftp->channel, 0) == 0) {
1762
 
        /* we cannot block */
1763
 
        return 0;
1764
 
      }
1765
 
    }
1766
 
    if (sftp_read_and_dispatch(handle->sftp) < 0) {
1767
 
      /* something nasty has happened */
1768
 
      return -1;
1769
 
    }
1770
 
    msg = sftp_dequeue(handle->sftp, id);
1771
 
  }
1772
 
 
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) {
1778
 
        return -1;
1779
 
      }
1780
 
      sftp_set_error(sftp, status->status);
1781
 
      switch (status->status) {
1782
 
        case SSH_FX_EOF:
1783
 
          handle->eof = 1;
1784
 
          status_msg_free(status);
1785
 
          return 0;
1786
 
        default:
1787
 
          break;
1788
 
      }
1789
 
      ssh_set_error(sftp->session,SSH_REQUEST_DENIED,
1790
 
          "SFTP server: %s", status->errormsg);
1791
 
      status_msg_free(status);
1792
 
      return -1;
1793
 
    case SSH_FXP_DATA:
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");
1799
 
        return -1;
1800
 
      }
1801
 
 
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);
1808
 
        return -1;
1809
 
      }
1810
 
      count = string_len(datastring);
1811
 
      handle->offset += count;
1812
 
      memcpy(buf, string_data(datastring), count);
1813
 
      string_free(datastring);
1814
 
      return count;
1815
 
    default:
1816
 
      ssh_set_error(sftp->session, SSH_FATAL,
1817
 
          "Received message %d during read!", msg->packet_type);
1818
 
      sftp_message_free(msg);
1819
 
      return -1;
1820
 
  }
1821
 
 
1822
 
  return -1; /* not reached */
1823
 
}
1824
 
 
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;
1828
 
  ssh_buffer buffer;
1829
 
  uint32_t id;
1830
 
 
1831
 
  sftp_enter_function();
1832
 
 
1833
 
  buffer = buffer_new();
1834
 
  if (buffer == NULL) {
1835
 
    ssh_set_error_oom(sftp->session);
1836
 
    return -1;
1837
 
  }
1838
 
 
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);
1846
 
    return -1;
1847
 
  }
1848
 
  if (sftp_packet_write(sftp, SSH_FXP_READ, buffer) < 0) {
1849
 
    buffer_free(buffer);
1850
 
    return -1;
1851
 
  }
1852
 
  buffer_free(buffer);
1853
 
 
1854
 
  file->offset += len; /* assume we'll read len bytes */
1855
 
 
1856
 
  sftp_leave_function();
1857
 
  return id;
1858
 
}
1859
 
 
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;
1866
 
  int err = SSH_OK;
1867
 
  uint32_t len;
1868
 
 
1869
 
  sftp_enter_function();
1870
 
 
1871
 
  if (file->eof) {
1872
 
    sftp_leave_function();
1873
 
    return 0;
1874
 
  }
1875
 
 
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 */
1881
 
        return SSH_AGAIN;
1882
 
      }
1883
 
    }
1884
 
 
1885
 
    if (sftp_read_and_dispatch(sftp) < 0) {
1886
 
      /* something nasty has happened */
1887
 
      sftp_leave_function();
1888
 
      return SSH_ERROR;
1889
 
    }
1890
 
 
1891
 
    msg = sftp_dequeue(sftp,id);
1892
 
  }
1893
 
 
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();
1900
 
        return -1;
1901
 
      }
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();
1907
 
        err = SSH_ERROR;
1908
 
      } else {
1909
 
        file->eof = 1;
1910
 
      }
1911
 
      status_msg_free(status);
1912
 
      sftp_leave_function();
1913
 
      return err;
1914
 
    case SSH_FXP_DATA:
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();
1921
 
        return SSH_ERROR;
1922
 
      }
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();
1930
 
        return SSH_ERROR;
1931
 
      }
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();
1939
 
      return len;
1940
 
    default:
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();
1944
 
      return SSH_ERROR;
1945
 
  }
1946
 
 
1947
 
  sftp_leave_function();
1948
 
  return SSH_ERROR;
1949
 
}
1950
 
 
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;
1956
 
  ssh_buffer buffer;
1957
 
  uint32_t id;
1958
 
  int len;
1959
 
  int packetlen;
1960
 
 
1961
 
  buffer = buffer_new();
1962
 
  if (buffer == NULL) {
1963
 
    ssh_set_error_oom(sftp->session);
1964
 
    return -1;
1965
 
  }
1966
 
 
1967
 
  datastring = string_new(count);
1968
 
  if (datastring == NULL) {
1969
 
    ssh_set_error_oom(sftp->session);
1970
 
    buffer_free(buffer);
1971
 
    return -1;
1972
 
  }
1973
 
  string_fill(datastring, buf, count);
1974
 
 
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);
1983
 
    return -1;
1984
 
  }
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);
1989
 
  if (len < 0) {
1990
 
    return -1;
1991
 
  } else  if (len != packetlen) {
1992
 
    ssh_log(sftp->session, SSH_LOG_PACKET,
1993
 
        "Could not write as much data as expected");
1994
 
  }
1995
 
 
1996
 
  while (msg == NULL) {
1997
 
    if (sftp_read_and_dispatch(file->sftp) < 0) {
1998
 
      /* something nasty has happened */
1999
 
      return -1;
2000
 
    }
2001
 
    msg = sftp_dequeue(file->sftp, id);
2002
 
  }
2003
 
 
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) {
2009
 
        return -1;
2010
 
      }
2011
 
      sftp_set_error(sftp, status->status);
2012
 
      switch (status->status) {
2013
 
        case SSH_FX_OK:
2014
 
          file->offset += count;
2015
 
          status_msg_free(status);
2016
 
          return count;
2017
 
        default:
2018
 
          break;
2019
 
      }
2020
 
      ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2021
 
          "SFTP server: %s", status->errormsg);
2022
 
      file->offset += count;
2023
 
      status_msg_free(status);
2024
 
      return -1;
2025
 
    default:
2026
 
      ssh_set_error(sftp->session, SSH_FATAL,
2027
 
          "Received message %d during write!", msg->packet_type);
2028
 
      sftp_message_free(msg);
2029
 
      return -1;
2030
 
  }
2031
 
 
2032
 
  return -1; /* not reached */
2033
 
}
2034
 
 
2035
 
/* Seek to a specific location in a file. */
2036
 
int sftp_seek(sftp_file file, uint32_t new_offset) {
2037
 
  if (file == NULL) {
2038
 
    return -1;
2039
 
  }
2040
 
 
2041
 
  file->offset = new_offset;
2042
 
 
2043
 
  return 0;
2044
 
}
2045
 
 
2046
 
int sftp_seek64(sftp_file file, uint64_t new_offset) {
2047
 
  if (file == NULL) {
2048
 
    return -1;
2049
 
  }
2050
 
 
2051
 
  file->offset = new_offset;
2052
 
 
2053
 
  return 0;
2054
 
}
2055
 
 
2056
 
/* Report current byte position in file. */
2057
 
unsigned long sftp_tell(sftp_file file) {
2058
 
  return (unsigned long)file->offset;
2059
 
}
2060
 
/* Report current byte position in file. */
2061
 
uint64_t sftp_tell64(sftp_file file) {
2062
 
  return (uint64_t) file->offset;
2063
 
}
2064
 
 
2065
 
/* Rewinds the position of the file pointer to the beginning of the file.*/
2066
 
void sftp_rewind(sftp_file file) {
2067
 
  file->offset = 0;
2068
 
}
2069
 
 
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;
2075
 
  ssh_buffer buffer;
2076
 
  uint32_t id;
2077
 
 
2078
 
  buffer = buffer_new();
2079
 
  if (buffer == NULL) {
2080
 
    ssh_set_error_oom(sftp->session);
2081
 
    return -1;
2082
 
  }
2083
 
 
2084
 
  filename = string_from_char(file);
2085
 
  if (filename == NULL) {
2086
 
    ssh_set_error_oom(sftp->session);
2087
 
    buffer_free(buffer);
2088
 
    return -1;
2089
 
  }
2090
 
 
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);
2097
 
  }
2098
 
  if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) {
2099
 
    buffer_free(buffer);
2100
 
    string_free(filename);
2101
 
  }
2102
 
  string_free(filename);
2103
 
  buffer_free(buffer);
2104
 
 
2105
 
  while (msg == NULL) {
2106
 
    if (sftp_read_and_dispatch(sftp)) {
2107
 
      return -1;
2108
 
    }
2109
 
    msg = sftp_dequeue(sftp, id);
2110
 
  }
2111
 
 
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) {
2117
 
      return -1;
2118
 
    }
2119
 
    sftp_set_error(sftp, status->status);
2120
 
    switch (status->status) {
2121
 
      case SSH_FX_OK:
2122
 
        status_msg_free(status);
2123
 
        return 0;
2124
 
      default:
2125
 
        break;
2126
 
    }
2127
 
 
2128
 
    /*
2129
 
     * The status should be SSH_FX_OK if the command was successful, if it
2130
 
     * didn't, then there was an error
2131
 
     */
2132
 
    ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2133
 
        "SFTP server: %s", status->errormsg);
2134
 
    status_msg_free(status);
2135
 
    return -1;
2136
 
  } else {
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);
2140
 
  }
2141
 
 
2142
 
  return -1;
2143
 
}
2144
 
 
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;
2150
 
  ssh_buffer buffer;
2151
 
  uint32_t id;
2152
 
 
2153
 
  buffer = buffer_new();
2154
 
  if (buffer == NULL) {
2155
 
    ssh_set_error_oom(sftp->session);
2156
 
    return -1;
2157
 
  }
2158
 
 
2159
 
  filename = string_from_char(directory);
2160
 
  if (filename == NULL) {
2161
 
    ssh_set_error_oom(sftp->session);
2162
 
    buffer_free(buffer);
2163
 
    return -1;
2164
 
  }
2165
 
 
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);
2172
 
    return -1;
2173
 
  }
2174
 
  if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) {
2175
 
    buffer_free(buffer);
2176
 
    string_free(filename);
2177
 
    return -1;
2178
 
  }
2179
 
  buffer_free(buffer);
2180
 
  string_free(filename);
2181
 
 
2182
 
  while (msg == NULL) {
2183
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2184
 
      return -1;
2185
 
    }
2186
 
    msg = sftp_dequeue(sftp, id);
2187
 
  }
2188
 
 
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) {
2194
 
      return -1;
2195
 
    }
2196
 
    sftp_set_error(sftp, status->status);
2197
 
    switch (status->status) {
2198
 
      case SSH_FX_OK:
2199
 
        status_msg_free(status);
2200
 
        return 0;
2201
 
        break;
2202
 
      default:
2203
 
        break;
2204
 
    }
2205
 
    ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2206
 
        "SFTP server: %s", status->errormsg);
2207
 
    status_msg_free(status);
2208
 
    return -1;
2209
 
  } else {
2210
 
    ssh_set_error(sftp->session, SSH_FATAL,
2211
 
        "Received message %d when attempting to remove directory",
2212
 
        msg->packet_type);
2213
 
    sftp_message_free(msg);
2214
 
  }
2215
 
 
2216
 
  return -1;
2217
 
}
2218
 
 
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;
2225
 
  ssh_buffer buffer;
2226
 
  ssh_string path;
2227
 
  uint32_t id;
2228
 
 
2229
 
  buffer = buffer_new();
2230
 
  if (buffer == NULL) {
2231
 
    ssh_set_error_oom(sftp->session);
2232
 
    return -1;
2233
 
  }
2234
 
 
2235
 
  path = string_from_char(directory);
2236
 
  if (path == NULL) {
2237
 
    ssh_set_error_oom(sftp->session);
2238
 
    buffer_free(buffer);
2239
 
    return -1;
2240
 
  }
2241
 
 
2242
 
  ZERO_STRUCT(attr);
2243
 
  attr.permissions = mode;
2244
 
  attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
2245
 
 
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);
2252
 
    string_free(path);
2253
 
  }
2254
 
  buffer_free(buffer);
2255
 
  string_free(path);
2256
 
 
2257
 
  while (msg == NULL) {
2258
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2259
 
      return -1;
2260
 
    }
2261
 
    msg = sftp_dequeue(sftp, id);
2262
 
  }
2263
 
 
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) {
2269
 
      return -1;
2270
 
    }
2271
 
    sftp_set_error(sftp, status->status);
2272
 
    switch (status->status) {
2273
 
      case SSH_FX_FAILURE:
2274
 
        /*
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.
2278
 
         */
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);
2283
 
        }
2284
 
        break;
2285
 
      case SSH_FX_OK:
2286
 
        status_msg_free(status);
2287
 
        return 0;
2288
 
        break;
2289
 
      default:
2290
 
        break;
2291
 
    }
2292
 
    /*
2293
 
     * The status should be SSH_FX_OK if the command was successful, if it
2294
 
     * didn't, then there was an error
2295
 
     */
2296
 
    ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2297
 
        "SFTP server: %s", status->errormsg);
2298
 
    status_msg_free(status);
2299
 
    return -1;
2300
 
  } else {
2301
 
    ssh_set_error(sftp->session, SSH_FATAL,
2302
 
        "Received message %d when attempting to make directory",
2303
 
        msg->packet_type);
2304
 
    sftp_message_free(msg);
2305
 
  }
2306
 
 
2307
 
  return -1;
2308
 
}
2309
 
 
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;
2314
 
  ssh_buffer buffer;
2315
 
  ssh_string oldpath;
2316
 
  ssh_string newpath;
2317
 
  uint32_t id;
2318
 
 
2319
 
  buffer = buffer_new();
2320
 
  if (buffer == NULL) {
2321
 
    ssh_set_error_oom(sftp->session);
2322
 
    return -1;
2323
 
  }
2324
 
 
2325
 
  oldpath = string_from_char(original);
2326
 
  if (oldpath == NULL) {
2327
 
    ssh_set_error_oom(sftp->session);
2328
 
    buffer_free(buffer);
2329
 
    return -1;
2330
 
  }
2331
 
 
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);
2337
 
    return -1;
2338
 
  }
2339
 
 
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);
2351
 
    return -1;
2352
 
  }
2353
 
  if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) {
2354
 
    buffer_free(buffer);
2355
 
    string_free(oldpath);
2356
 
    string_free(newpath);
2357
 
    return -1;
2358
 
  }
2359
 
  buffer_free(buffer);
2360
 
  string_free(oldpath);
2361
 
  string_free(newpath);
2362
 
 
2363
 
  while (msg == NULL) {
2364
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2365
 
      return -1;
2366
 
    }
2367
 
    msg = sftp_dequeue(sftp, id);
2368
 
  }
2369
 
 
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) {
2375
 
      return -1;
2376
 
    }
2377
 
    sftp_set_error(sftp, status->status);
2378
 
    switch (status->status) {
2379
 
      case SSH_FX_OK:
2380
 
        status_msg_free(status);
2381
 
        return 0;
2382
 
      default:
2383
 
        break;
2384
 
    }
2385
 
    /*
2386
 
     * Status should be SSH_FX_OK if the command was successful, if it didn't,
2387
 
     * then there was an error
2388
 
     */
2389
 
    ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2390
 
        "SFTP server: %s", status->errormsg);
2391
 
    status_msg_free(status);
2392
 
    return -1;
2393
 
  } else {
2394
 
    ssh_set_error(sftp->session, SSH_FATAL,
2395
 
        "Received message %d when attempting to rename",
2396
 
        msg->packet_type);
2397
 
    sftp_message_free(msg);
2398
 
  }
2399
 
 
2400
 
  return -1;
2401
 
}
2402
 
 
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;
2411
 
 
2412
 
  buffer = buffer_new();
2413
 
  if (buffer == NULL) {
2414
 
    ssh_set_error_oom(sftp->session);
2415
 
    return -1;
2416
 
  }
2417
 
 
2418
 
  path = string_from_char(file);
2419
 
  if (path == NULL) {
2420
 
    ssh_set_error_oom(sftp->session);
2421
 
    buffer_free(buffer);
2422
 
    return -1;
2423
 
  }
2424
 
 
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);
2431
 
    string_free(path);
2432
 
    return -1;
2433
 
  }
2434
 
  if (sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer) < 0) {
2435
 
    buffer_free(buffer);
2436
 
    string_free(path);
2437
 
    return -1;
2438
 
  }
2439
 
  buffer_free(buffer);
2440
 
  string_free(path);
2441
 
 
2442
 
  while (msg == NULL) {
2443
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2444
 
      return -1;
2445
 
    }
2446
 
    msg = sftp_dequeue(sftp, id);
2447
 
  }
2448
 
 
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) {
2454
 
      return -1;
2455
 
    }
2456
 
    sftp_set_error(sftp, status->status);
2457
 
    switch (status->status) {
2458
 
      case SSH_FX_OK:
2459
 
        status_msg_free(status);
2460
 
        return 0;
2461
 
      default:
2462
 
        break;
2463
 
    }
2464
 
    /*
2465
 
     * The status should be SSH_FX_OK if the command was successful, if it
2466
 
     * didn't, then there was an error
2467
 
     */
2468
 
    ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2469
 
        "SFTP server: %s", status->errormsg);
2470
 
    status_msg_free(status);
2471
 
    return -1;
2472
 
  } else {
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);
2476
 
  }
2477
 
 
2478
 
  return -1;
2479
 
}
2480
 
 
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;
2484
 
  ZERO_STRUCT(attr);
2485
 
 
2486
 
  attr.uid = owner;
2487
 
  attr.gid = group;
2488
 
 
2489
 
  attr.flags = SSH_FILEXFER_ATTR_UIDGID;
2490
 
 
2491
 
  return sftp_setstat(sftp, file, &attr);
2492
 
}
2493
 
 
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;
2497
 
  ZERO_STRUCT(attr);
2498
 
  attr.permissions = mode;
2499
 
  attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
2500
 
 
2501
 
  return sftp_setstat(sftp, file, &attr);
2502
 
}
2503
 
 
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;
2508
 
  ZERO_STRUCT(attr);
2509
 
 
2510
 
  attr.atime = times[0].tv_sec;
2511
 
  attr.atime_nseconds = times[0].tv_usec;
2512
 
 
2513
 
  attr.mtime = times[1].tv_sec;
2514
 
  attr.mtime_nseconds = times[1].tv_usec;
2515
 
 
2516
 
  attr.flags |= SSH_FILEXFER_ATTR_ACCESSTIME | SSH_FILEXFER_ATTR_MODIFYTIME |
2517
 
    SSH_FILEXFER_ATTR_SUBSECOND_TIMES;
2518
 
 
2519
 
  return sftp_setstat(sftp, file, &attr);
2520
 
}
2521
 
 
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;
2526
 
  ssh_string dest_s;
2527
 
  ssh_buffer buffer;
2528
 
  uint32_t id;
2529
 
 
2530
 
  if (sftp == NULL)
2531
 
    return -1;
2532
 
  if (target == NULL || dest == NULL) {
2533
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
2534
 
    return -1;
2535
 
  }
2536
 
 
2537
 
  buffer = buffer_new();
2538
 
  if (buffer == NULL) {
2539
 
    ssh_set_error_oom(sftp->session);
2540
 
    return -1;
2541
 
  }
2542
 
 
2543
 
  target_s = string_from_char(target);
2544
 
  if (target_s == NULL) {
2545
 
    ssh_set_error_oom(sftp->session);
2546
 
    buffer_free(buffer);
2547
 
    return -1;
2548
 
  }
2549
 
 
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);
2555
 
    return -1;
2556
 
  }
2557
 
 
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);
2564
 
    return -1;
2565
 
  }
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);
2574
 
      return -1;
2575
 
    }
2576
 
  } else {
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);
2583
 
      return -1;
2584
 
    }
2585
 
  }
2586
 
 
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);
2591
 
    return -1;
2592
 
  }
2593
 
  buffer_free(buffer);
2594
 
  string_free(dest_s);
2595
 
  string_free(target_s);
2596
 
 
2597
 
  while (msg == NULL) {
2598
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2599
 
      return -1;
2600
 
    }
2601
 
    msg = sftp_dequeue(sftp, id);
2602
 
  }
2603
 
 
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) {
2609
 
      return -1;
2610
 
    }
2611
 
    sftp_set_error(sftp, status->status);
2612
 
    switch (status->status) {
2613
 
      case SSH_FX_OK:
2614
 
        status_msg_free(status);
2615
 
        return 0;
2616
 
      default:
2617
 
        break;
2618
 
    }
2619
 
    /*
2620
 
     * The status should be SSH_FX_OK if the command was successful, if it
2621
 
     * didn't, then there was an error
2622
 
     */
2623
 
    ssh_set_error(sftp->session, SSH_REQUEST_DENIED,
2624
 
        "SFTP server: %s", status->errormsg);
2625
 
    status_msg_free(status);
2626
 
    return -1;
2627
 
  } else {
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);
2631
 
  }
2632
 
 
2633
 
  return -1;
2634
 
}
2635
 
 
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;
2641
 
  ssh_buffer buffer;
2642
 
  char *lnk;
2643
 
  uint32_t ignored;
2644
 
  uint32_t id;
2645
 
 
2646
 
  if (sftp == NULL)
2647
 
    return NULL;
2648
 
  if (path == NULL) {
2649
 
    ssh_set_error_invalid(sftp, __FUNCTION__);
2650
 
    return NULL;
2651
 
  }
2652
 
  if (sftp->version < 3){
2653
 
    ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_readlink",sftp->version);
2654
 
    return NULL;
2655
 
  }
2656
 
  buffer = buffer_new();
2657
 
  if (buffer == NULL) {
2658
 
    ssh_set_error_oom(sftp->session);
2659
 
    return NULL;
2660
 
  }
2661
 
 
2662
 
  path_s = string_from_char(path);
2663
 
  if (path_s == NULL) {
2664
 
    ssh_set_error_oom(sftp->session);
2665
 
    buffer_free(buffer);
2666
 
    return NULL;
2667
 
  }
2668
 
 
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);
2675
 
    return NULL;
2676
 
  }
2677
 
  if (sftp_packet_write(sftp, SSH_FXP_READLINK, buffer) < 0) {
2678
 
    buffer_free(buffer);
2679
 
    string_free(path_s);
2680
 
    return NULL;
2681
 
  }
2682
 
  buffer_free(buffer);
2683
 
  string_free(path_s);
2684
 
 
2685
 
  while (msg == NULL) {
2686
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2687
 
      return NULL;
2688
 
    }
2689
 
    msg = sftp_dequeue(sftp, id);
2690
 
  }
2691
 
 
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? */
2700
 
      return NULL;
2701
 
    }
2702
 
    lnk = string_to_char(link_s);
2703
 
    string_free(link_s);
2704
 
 
2705
 
    return lnk;
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) {
2710
 
      return NULL;
2711
 
    }
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);
2719
 
  }
2720
 
 
2721
 
  return NULL;
2722
 
}
2723
 
 
2724
 
static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) {
2725
 
        sftp_statvfs_t  statvfs;
2726
 
  uint64_t tmp;
2727
 
  int ok = 0;
2728
 
 
2729
 
  statvfs = malloc(sizeof(struct sftp_statvfs_struct));
2730
 
  if (statvfs == NULL) {
2731
 
    ssh_set_error_oom(sftp->session);
2732
 
    return NULL;
2733
 
  }
2734
 
  ZERO_STRUCTP(statvfs);
2735
 
 
2736
 
  /* try .. catch */
2737
 
  do {
2738
 
    /* file system block size */
2739
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2740
 
      break;
2741
 
    }
2742
 
    statvfs->f_bsize = ntohll(tmp);
2743
 
 
2744
 
    /* fundamental fs block size */
2745
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2746
 
      break;
2747
 
    }
2748
 
    statvfs->f_frsize = ntohll(tmp);
2749
 
 
2750
 
    /* number of blocks (unit f_frsize) */
2751
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2752
 
      break;
2753
 
    }
2754
 
    statvfs->f_blocks = ntohll(tmp);
2755
 
 
2756
 
    /* free blocks in file system */
2757
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2758
 
      break;
2759
 
    }
2760
 
    statvfs->f_bfree = ntohll(tmp);
2761
 
 
2762
 
    /* free blocks for non-root */
2763
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2764
 
      break;
2765
 
    }
2766
 
    statvfs->f_bavail = ntohll(tmp);
2767
 
 
2768
 
    /* total file inodes */
2769
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2770
 
      break;
2771
 
    }
2772
 
    statvfs->f_files = ntohll(tmp);
2773
 
 
2774
 
    /* free file inodes */
2775
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2776
 
      break;
2777
 
    }
2778
 
    statvfs->f_ffree = ntohll(tmp);
2779
 
 
2780
 
    /* free file inodes for to non-root */
2781
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2782
 
      break;
2783
 
    }
2784
 
    statvfs->f_favail = ntohll(tmp);
2785
 
 
2786
 
    /* file system id */
2787
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2788
 
      break;
2789
 
    }
2790
 
    statvfs->f_fsid = ntohll(tmp);
2791
 
 
2792
 
    /* bit mask of f_flag values */
2793
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2794
 
      break;
2795
 
    }
2796
 
    statvfs->f_flag = ntohll(tmp);
2797
 
 
2798
 
    /* maximum filename length */
2799
 
    if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) {
2800
 
      break;
2801
 
    }
2802
 
    statvfs->f_namemax = ntohll(tmp);
2803
 
 
2804
 
    ok = 1;
2805
 
  } while(0);
2806
 
 
2807
 
  if (!ok) {
2808
 
    SAFE_FREE(statvfs);
2809
 
    ssh_set_error(sftp->session, SSH_FATAL, "Invalid statvfs structure");
2810
 
    return NULL;
2811
 
  }
2812
 
 
2813
 
  return statvfs;
2814
 
}
2815
 
 
2816
 
sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path) {
2817
 
  sftp_status_message status = NULL;
2818
 
  sftp_message msg = NULL;
2819
 
  ssh_string pathstr;
2820
 
  ssh_string ext;
2821
 
  ssh_buffer buffer;
2822
 
  uint32_t id;
2823
 
 
2824
 
  if (sftp == NULL)
2825
 
    return NULL;
2826
 
  if (path == NULL) {
2827
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
2828
 
    return NULL;
2829
 
  }
2830
 
  if (sftp->version < 3){
2831
 
    ssh_set_error(sftp,SSH_REQUEST_DENIED,"sftp version %d does not support sftp_statvfs",sftp->version);
2832
 
    return NULL;
2833
 
  }
2834
 
 
2835
 
  buffer = buffer_new();
2836
 
  if (buffer == NULL) {
2837
 
    ssh_set_error_oom(sftp->session);
2838
 
    return NULL;
2839
 
  }
2840
 
 
2841
 
  ext = string_from_char("statvfs@openssh.com");
2842
 
  if (ext == NULL) {
2843
 
    ssh_set_error_oom(sftp->session);
2844
 
    buffer_free(buffer);
2845
 
    return NULL;
2846
 
  }
2847
 
 
2848
 
  pathstr = string_from_char(path);
2849
 
  if (pathstr == NULL) {
2850
 
    ssh_set_error_oom(sftp->session);
2851
 
    buffer_free(buffer);
2852
 
    string_free(ext);
2853
 
    return NULL;
2854
 
  }
2855
 
 
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);
2862
 
    string_free(ext);
2863
 
    string_free(pathstr);
2864
 
    return NULL;
2865
 
  }
2866
 
  if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
2867
 
    buffer_free(buffer);
2868
 
    string_free(ext);
2869
 
    string_free(pathstr);
2870
 
    return NULL;
2871
 
  }
2872
 
  buffer_free(buffer);
2873
 
  string_free(ext);
2874
 
  string_free(pathstr);
2875
 
 
2876
 
  while (msg == NULL) {
2877
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2878
 
      return NULL;
2879
 
    }
2880
 
    msg = sftp_dequeue(sftp, id);
2881
 
  }
2882
 
 
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);
2886
 
    if (buf == NULL) {
2887
 
      return NULL;
2888
 
    }
2889
 
 
2890
 
    return buf;
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) {
2895
 
      return NULL;
2896
 
    }
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);
2904
 
  }
2905
 
 
2906
 
  return NULL;
2907
 
}
2908
 
 
2909
 
sftp_statvfs_t sftp_fstatvfs(sftp_file file) {
2910
 
  sftp_status_message status = NULL;
2911
 
  sftp_message msg = NULL;
2912
 
  sftp_session sftp;
2913
 
  ssh_string ext;
2914
 
  ssh_buffer buffer;
2915
 
  uint32_t id;
2916
 
 
2917
 
  if (file == NULL) {
2918
 
    return NULL;
2919
 
  }
2920
 
  sftp = file->sftp;
2921
 
 
2922
 
  buffer = buffer_new();
2923
 
  if (buffer == NULL) {
2924
 
    ssh_set_error_oom(sftp->session);
2925
 
    return NULL;
2926
 
  }
2927
 
 
2928
 
  ext = string_from_char("fstatvfs@openssh.com");
2929
 
  if (ext == NULL) {
2930
 
    ssh_set_error_oom(sftp->session);
2931
 
    buffer_free(buffer);
2932
 
    return NULL;
2933
 
  }
2934
 
 
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);
2941
 
    string_free(ext);
2942
 
    return NULL;
2943
 
  }
2944
 
  if (sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
2945
 
    buffer_free(buffer);
2946
 
    string_free(ext);
2947
 
    return NULL;
2948
 
  }
2949
 
  buffer_free(buffer);
2950
 
  string_free(ext);
2951
 
 
2952
 
  while (msg == NULL) {
2953
 
    if (sftp_read_and_dispatch(sftp) < 0) {
2954
 
      return NULL;
2955
 
    }
2956
 
    msg = sftp_dequeue(sftp, id);
2957
 
  }
2958
 
 
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);
2962
 
    if (buf == NULL) {
2963
 
      return NULL;
2964
 
    }
2965
 
 
2966
 
    return buf;
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) {
2971
 
      return NULL;
2972
 
    }
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);
2980
 
  }
2981
 
 
2982
 
  return NULL;
2983
 
}
2984
 
 
2985
 
void sftp_statvfs_free(sftp_statvfs_t statvfs) {
2986
 
  if (statvfs == NULL) {
2987
 
    return;
2988
 
  }
2989
 
 
2990
 
  SAFE_FREE(statvfs);
2991
 
}
2992
 
 
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;
2998
 
  ssh_string pathstr;
2999
 
  ssh_buffer buffer;
3000
 
  char *cname;
3001
 
  uint32_t ignored;
3002
 
  uint32_t id;
3003
 
 
3004
 
  if (sftp == NULL)
3005
 
    return NULL;
3006
 
  if (path == NULL) {
3007
 
    ssh_set_error_invalid(sftp->session, __FUNCTION__);
3008
 
    return NULL;
3009
 
  }
3010
 
 
3011
 
  buffer = buffer_new();
3012
 
  if (buffer == NULL) {
3013
 
    ssh_set_error_oom(sftp->session);
3014
 
    return NULL;
3015
 
  }
3016
 
 
3017
 
  pathstr = string_from_char(path);
3018
 
  if (pathstr == NULL) {
3019
 
    ssh_set_error_oom(sftp->session);
3020
 
    buffer_free(buffer);
3021
 
    return NULL;
3022
 
  }
3023
 
 
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);
3030
 
    return NULL;
3031
 
  }
3032
 
  if (sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer) < 0) {
3033
 
    buffer_free(buffer);
3034
 
    string_free(pathstr);
3035
 
    return NULL;
3036
 
  }
3037
 
  buffer_free(buffer);
3038
 
  string_free(pathstr);
3039
 
 
3040
 
  while (msg == NULL) {
3041
 
    if (sftp_read_and_dispatch(sftp) < 0) {
3042
 
      return NULL;
3043
 
    }
3044
 
    msg = sftp_dequeue(sftp, id);
3045
 
  }
3046
 
 
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);
3053
 
    if (name == NULL) {
3054
 
      /* TODO: error message? */
3055
 
      return NULL;
3056
 
    }
3057
 
    cname = string_to_char(name);
3058
 
    string_free(name);
3059
 
    if (cname == NULL) {
3060
 
      ssh_set_error_oom(sftp->session);
3061
 
    }
3062
 
    return cname;
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) {
3067
 
      return NULL;
3068
 
    }
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);
3076
 
  }
3077
 
 
3078
 
  return NULL;
3079
 
}
3080
 
 
3081
 
static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
3082
 
    int param) {
3083
 
  sftp_status_message status = NULL;
3084
 
  sftp_message msg = NULL;
3085
 
  ssh_string pathstr;
3086
 
  ssh_buffer buffer;
3087
 
  uint32_t id;
3088
 
 
3089
 
  buffer = buffer_new();
3090
 
  if (buffer == NULL) {
3091
 
    ssh_set_error_oom(sftp->session);
3092
 
    return NULL;
3093
 
  }
3094
 
 
3095
 
  pathstr = string_from_char(path);
3096
 
  if (pathstr == NULL) {
3097
 
    ssh_set_error_oom(sftp->session);
3098
 
    buffer_free(buffer);
3099
 
    return NULL;
3100
 
  }
3101
 
 
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);
3108
 
    return NULL;
3109
 
  }
3110
 
  if (sftp_packet_write(sftp, param, buffer) < 0) {
3111
 
    buffer_free(buffer);
3112
 
    string_free(pathstr);
3113
 
    return NULL;
3114
 
  }
3115
 
  buffer_free(buffer);
3116
 
  string_free(pathstr);
3117
 
 
3118
 
  while (msg == NULL) {
3119
 
    if (sftp_read_and_dispatch(sftp) < 0) {
3120
 
      return NULL;
3121
 
    }
3122
 
    msg = sftp_dequeue(sftp, id);
3123
 
  }
3124
 
 
3125
 
  if (msg->packet_type == SSH_FXP_ATTRS) {
3126
 
    sftp_attributes attr = sftp_parse_attr(sftp, msg->payload, 0);
3127
 
    sftp_message_free(msg);
3128
 
 
3129
 
    return attr;
3130
 
  } else if (msg->packet_type == SSH_FXP_STATUS) {
3131
 
    status = parse_status_msg(msg);
3132
 
    sftp_message_free(msg);
3133
 
    if (status == NULL) {
3134
 
      return NULL;
3135
 
    }
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);
3140
 
    return NULL;
3141
 
  }
3142
 
  ssh_set_error(sftp->session, SSH_FATAL,
3143
 
      "Received mesg %d during stat()", msg->packet_type);
3144
 
  sftp_message_free(msg);
3145
 
 
3146
 
  return NULL;
3147
 
}
3148
 
 
3149
 
sftp_attributes sftp_stat(sftp_session session, const char *path) {
3150
 
  return sftp_xstat(session, path, SSH_FXP_STAT);
3151
 
}
3152
 
 
3153
 
sftp_attributes sftp_lstat(sftp_session session, const char *path) {
3154
 
  return sftp_xstat(session, path, SSH_FXP_LSTAT);
3155
 
}
3156
 
 
3157
 
sftp_attributes sftp_fstat(sftp_file file) {
3158
 
  sftp_status_message status = NULL;
3159
 
  sftp_message msg = NULL;
3160
 
  ssh_buffer buffer;
3161
 
  uint32_t id;
3162
 
 
3163
 
  buffer = buffer_new();
3164
 
  if (buffer == NULL) {
3165
 
    ssh_set_error_oom(file->sftp->session);
3166
 
    return NULL;
3167
 
  }
3168
 
 
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);
3174
 
    return NULL;
3175
 
  }
3176
 
  if (sftp_packet_write(file->sftp, SSH_FXP_FSTAT, buffer) < 0) {
3177
 
    buffer_free(buffer);
3178
 
    return NULL;
3179
 
  }
3180
 
  buffer_free(buffer);
3181
 
 
3182
 
  while (msg == NULL) {
3183
 
    if (sftp_read_and_dispatch(file->sftp) < 0) {
3184
 
      return NULL;
3185
 
    }
3186
 
    msg = sftp_dequeue(file->sftp, id);
3187
 
  }
3188
 
 
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) {
3195
 
      return NULL;
3196
 
    }
3197
 
    ssh_set_error(file->sftp->session, SSH_REQUEST_DENIED,
3198
 
        "SFTP server: %s", status->errormsg);
3199
 
    status_msg_free(status);
3200
 
 
3201
 
    return NULL;
3202
 
  }
3203
 
  ssh_set_error(file->sftp->session, SSH_FATAL,
3204
 
      "Received msg %d during fstat()", msg->packet_type);
3205
 
  sftp_message_free(msg);
3206
 
 
3207
 
  return NULL;
3208
 
}
3209
 
 
3210
 
#endif /* WITH_SFTP */
3211
 
/* vim: set ts=2 sw=2 et cindent: */