~ubuntu-branches/ubuntu/lucid/openssh/lucid

« back to all changes in this revision

Viewing changes to sftp-client.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2008-09-30 23:09:58 UTC
  • mfrom: (1.13.3 upstream) (29 hardy)
  • mto: This revision was merged to the branch mainline in revision 43.
  • Revision ID: james.westby@ubuntu.com-20080930230958-o6vsgn8c4mm959s0
Tags: 1:5.1p1-3
* Remove unnecessary ssh-vulnkey output in non-verbose mode when no
  compromised or unknown keys were found (closes: #496495).
* Configure with --disable-strip; dh_strip will deal with stripping
  binaries and will honour DEB_BUILD_OPTIONS (thanks, Bernhard R. Link;
  closes: #498681).
* Fix handling of zero-length server banners (thanks, Tomas Mraz; closes:
  #497026).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $OpenBSD: sftp-client.c,v 1.76 2007/01/22 11:32:50 djm Exp $ */
 
1
/* $OpenBSD: sftp-client.c,v 1.86 2008/06/26 06:10:09 djm Exp $ */
2
2
/*
3
3
 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4
4
 *
24
24
 
25
25
#include <sys/types.h>
26
26
#include <sys/param.h>
 
27
#ifdef HAVE_SYS_STATVFS_H
 
28
#include <sys/statvfs.h>
 
29
#endif
27
30
#include "openbsd-compat/sys-queue.h"
28
31
#ifdef HAVE_SYS_STAT_H
29
32
# include <sys/stat.h>
65
68
        u_int num_requests;
66
69
        u_int version;
67
70
        u_int msg_id;
 
71
#define SFTP_EXT_POSIX_RENAME   0x00000001
 
72
#define SFTP_EXT_STATVFS        0x00000002
 
73
#define SFTP_EXT_FSTATVFS       0x00000004
 
74
        u_int exts;
68
75
};
69
76
 
70
77
static void
236
243
        return(a);
237
244
}
238
245
 
 
246
static int
 
247
get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id,
 
248
    int quiet)
 
249
{
 
250
        Buffer msg;
 
251
        u_int type, id, flag;
 
252
 
 
253
        buffer_init(&msg);
 
254
        get_msg(fd, &msg);
 
255
 
 
256
        type = buffer_get_char(&msg);
 
257
        id = buffer_get_int(&msg);
 
258
 
 
259
        debug3("Received statvfs reply T:%u I:%u", type, id);
 
260
        if (id != expected_id)
 
261
                fatal("ID mismatch (%u != %u)", id, expected_id);
 
262
        if (type == SSH2_FXP_STATUS) {
 
263
                int status = buffer_get_int(&msg);
 
264
 
 
265
                if (quiet)
 
266
                        debug("Couldn't statvfs: %s", fx2txt(status));
 
267
                else
 
268
                        error("Couldn't statvfs: %s", fx2txt(status));
 
269
                buffer_free(&msg);
 
270
                return -1;
 
271
        } else if (type != SSH2_FXP_EXTENDED_REPLY) {
 
272
                fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
 
273
                    SSH2_FXP_EXTENDED_REPLY, type);
 
274
        }
 
275
 
 
276
        bzero(st, sizeof(*st));
 
277
        st->f_bsize = buffer_get_int64(&msg);
 
278
        st->f_frsize = buffer_get_int64(&msg);
 
279
        st->f_blocks = buffer_get_int64(&msg);
 
280
        st->f_bfree = buffer_get_int64(&msg);
 
281
        st->f_bavail = buffer_get_int64(&msg);
 
282
        st->f_files = buffer_get_int64(&msg);
 
283
        st->f_ffree = buffer_get_int64(&msg);
 
284
        st->f_favail = buffer_get_int64(&msg);
 
285
        st->f_fsid = buffer_get_int64(&msg);
 
286
        flag = buffer_get_int64(&msg);
 
287
        st->f_namemax = buffer_get_int64(&msg);
 
288
 
 
289
        st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
 
290
        st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
 
291
 
 
292
        buffer_free(&msg);
 
293
 
 
294
        return 0;
 
295
}
 
296
 
239
297
struct sftp_conn *
240
298
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
241
299
{
242
 
        u_int type;
 
300
        u_int type, exts = 0;
243
301
        int version;
244
302
        Buffer msg;
245
303
        struct sftp_conn *ret;
268
326
        while (buffer_len(&msg) > 0) {
269
327
                char *name = buffer_get_string(&msg, NULL);
270
328
                char *value = buffer_get_string(&msg, NULL);
 
329
                int known = 0;
271
330
 
272
 
                debug2("Init extension: \"%s\"", name);
 
331
                if (strcmp(name, "posix-rename@openssh.com") == 0 &&
 
332
                    strcmp(value, "1") == 0) {
 
333
                        exts |= SFTP_EXT_POSIX_RENAME;
 
334
                        known = 1;
 
335
                } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
 
336
                    strcmp(value, "2") == 0) {
 
337
                        exts |= SFTP_EXT_STATVFS;
 
338
                        known = 1;
 
339
                } if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
 
340
                    strcmp(value, "2") == 0) {
 
341
                        exts |= SFTP_EXT_FSTATVFS;
 
342
                        known = 1;
 
343
                }
 
344
                if (known) {
 
345
                        debug2("Server supports extension \"%s\" revision %s",
 
346
                            name, value);
 
347
                } else {
 
348
                        debug2("Unrecognised server extension \"%s\"", name);
 
349
                }
273
350
                xfree(name);
274
351
                xfree(value);
275
352
        }
283
360
        ret->num_requests = num_requests;
284
361
        ret->version = version;
285
362
        ret->msg_id = 1;
 
363
        ret->exts = exts;
286
364
 
287
365
        /* Some filexfer v.0 servers don't support large packets */
288
366
        if (version == 0)
534
612
        return(get_decode_stat(conn->fd_in, id, quiet));
535
613
}
536
614
 
 
615
#ifdef notyet
537
616
Attrib *
538
617
do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
539
618
{
545
624
 
546
625
        return(get_decode_stat(conn->fd_in, id, quiet));
547
626
}
 
627
#endif
548
628
 
549
629
int
550
630
do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
637
717
 
638
718
        /* Send rename request */
639
719
        id = conn->msg_id++;
640
 
        buffer_put_char(&msg, SSH2_FXP_RENAME);
641
 
        buffer_put_int(&msg, id);
 
720
        if ((conn->exts & SFTP_EXT_POSIX_RENAME)) {
 
721
                buffer_put_char(&msg, SSH2_FXP_EXTENDED);
 
722
                buffer_put_int(&msg, id);
 
723
                buffer_put_cstring(&msg, "posix-rename@openssh.com");
 
724
        } else {
 
725
                buffer_put_char(&msg, SSH2_FXP_RENAME);
 
726
                buffer_put_int(&msg, id);
 
727
        }
642
728
        buffer_put_cstring(&msg, oldpath);
643
729
        buffer_put_cstring(&msg, newpath);
644
730
        send_msg(conn->fd_out, &msg);
645
 
        debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
646
 
            newpath);
 
731
        debug3("Sent message %s \"%s\" -> \"%s\"",
 
732
            (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" :
 
733
            "SSH2_FXP_RENAME", oldpath, newpath);
647
734
        buffer_free(&msg);
648
735
 
649
736
        status = get_status(conn->fd_in, id);
686
773
        return(status);
687
774
}
688
775
 
 
776
#ifdef notyet
689
777
char *
690
778
do_readlink(struct sftp_conn *conn, char *path)
691
779
{
732
820
 
733
821
        return(filename);
734
822
}
 
823
#endif
 
824
 
 
825
int
 
826
do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
 
827
    int quiet)
 
828
{
 
829
        Buffer msg;
 
830
        u_int id;
 
831
 
 
832
        if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
 
833
                error("Server does not support statvfs@openssh.com extension");
 
834
                return -1;
 
835
        }
 
836
 
 
837
        id = conn->msg_id++;
 
838
 
 
839
        buffer_init(&msg);
 
840
        buffer_clear(&msg);
 
841
        buffer_put_char(&msg, SSH2_FXP_EXTENDED);
 
842
        buffer_put_int(&msg, id);
 
843
        buffer_put_cstring(&msg, "statvfs@openssh.com");
 
844
        buffer_put_cstring(&msg, path);
 
845
        send_msg(conn->fd_out, &msg);
 
846
        buffer_free(&msg);
 
847
 
 
848
        return get_decode_statvfs(conn->fd_in, st, id, quiet);
 
849
}
 
850
 
 
851
#ifdef notyet
 
852
int
 
853
do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
 
854
    struct sftp_statvfs *st, int quiet)
 
855
{
 
856
        Buffer msg;
 
857
        u_int id;
 
858
 
 
859
        if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
 
860
                error("Server does not support fstatvfs@openssh.com extension");
 
861
                return -1;
 
862
        }
 
863
 
 
864
        id = conn->msg_id++;
 
865
 
 
866
        buffer_init(&msg);
 
867
        buffer_clear(&msg);
 
868
        buffer_put_char(&msg, SSH2_FXP_EXTENDED);
 
869
        buffer_put_int(&msg, id);
 
870
        buffer_put_cstring(&msg, "fstatvfs@openssh.com");
 
871
        buffer_put_string(&msg, handle, handle_len);
 
872
        send_msg(conn->fd_out, &msg);
 
873
        buffer_free(&msg);
 
874
 
 
875
        return get_decode_statvfs(conn->fd_in, st, id, quiet);
 
876
}
 
877
#endif
735
878
 
736
879
static void
737
880
send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
777
920
        if (a == NULL)
778
921
                return(-1);
779
922
 
780
 
        /* XXX: should we preserve set[ug]id? */
 
923
        /* Do not preserve set[ug]id here, as we do not preserve ownership */
781
924
        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
782
925
                mode = a->perm & 0777;
783
926
        else
819
962
        if (local_fd == -1) {
820
963
                error("Couldn't open local file \"%s\" for writing: %s",
821
964
                    local_path, strerror(errno));
 
965
                do_close(conn, handle, handle_len);
822
966
                buffer_free(&msg);
823
967
                xfree(handle);
824
968
                return(-1);
992
1136
do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
993
1137
    int pflag)
994
1138
{
995
 
        int local_fd, status;
 
1139
        int local_fd;
 
1140
        int status = SSH2_FX_OK;
996
1141
        u_int handle_len, id, type;
997
 
        u_int64_t offset;
 
1142
        off_t offset;
998
1143
        char *handle, *data;
999
1144
        Buffer msg;
1000
1145
        struct stat sb;
1004
1149
        struct outstanding_ack {
1005
1150
                u_int id;
1006
1151
                u_int len;
1007
 
                u_int64_t offset;
 
1152
                off_t offset;
1008
1153
                TAILQ_ENTRY(outstanding_ack) tq;
1009
1154
        };
1010
1155
        TAILQ_HEAD(ackhead, outstanding_ack) acks;
1054
1199
        if (handle == NULL) {
1055
1200
                close(local_fd);
1056
1201
                buffer_free(&msg);
1057
 
                return(-1);
 
1202
                return -1;
1058
1203
        }
1059
1204
 
1060
1205
        startid = ackid = id + 1;
1074
1219
                 * Simulate an EOF on interrupt, allowing ACKs from the
1075
1220
                 * server to drain.
1076
1221
                 */
1077
 
                if (interrupted)
 
1222
                if (interrupted || status != SSH2_FX_OK)
1078
1223
                        len = 0;
1079
1224
                else do
1080
1225
                        len = read(local_fd, data, conn->transfer_buflen);
1081
 
                while ((len == -1) && (errno == EINTR || errno == EAGAIN));
 
1226
                while ((len == -1) &&
 
1227
                    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
1082
1228
 
1083
1229
                if (len == -1)
1084
1230
                        fatal("Couldn't read from \"%s\": %s", local_path,
1130
1276
                        if (ack == NULL)
1131
1277
                                fatal("Can't find request for ID %u", r_id);
1132
1278
                        TAILQ_REMOVE(&acks, ack, tq);
1133
 
 
1134
 
                        if (status != SSH2_FX_OK) {
1135
 
                                error("Couldn't write to remote file \"%s\": %s",
1136
 
                                    remote_path, fx2txt(status));
1137
 
                                if (showprogress)
1138
 
                                        stop_progress_meter();
1139
 
                                do_close(conn, handle, handle_len);
1140
 
                                close(local_fd);
1141
 
                                xfree(data);
1142
 
                                xfree(ack);
1143
 
                                status = -1;
1144
 
                                goto done;
1145
 
                        }
1146
 
                        debug3("In write loop, ack for %u %u bytes at %llu",
1147
 
                            ack->id, ack->len, (unsigned long long)ack->offset);
 
1279
                        debug3("In write loop, ack for %u %u bytes at %lld",
 
1280
                            ack->id, ack->len, (long long)ack->offset);
1148
1281
                        ++ackid;
1149
1282
                        xfree(ack);
1150
1283
                }
1151
1284
                offset += len;
 
1285
                if (offset < 0)
 
1286
                        fatal("%s: offset < 0", __func__);
1152
1287
        }
 
1288
        buffer_free(&msg);
 
1289
 
1153
1290
        if (showprogress)
1154
1291
                stop_progress_meter();
1155
1292
        xfree(data);
1156
1293
 
 
1294
        if (status != SSH2_FX_OK) {
 
1295
                error("Couldn't write to remote file \"%s\": %s",
 
1296
                    remote_path, fx2txt(status));
 
1297
                status = -1;
 
1298
        }
 
1299
 
1157
1300
        if (close(local_fd) == -1) {
1158
1301
                error("Couldn't close local file \"%s\": %s", local_path,
1159
1302
                    strerror(errno));
1160
 
                do_close(conn, handle, handle_len);
1161
1303
                status = -1;
1162
 
                goto done;
1163
1304
        }
1164
1305
 
1165
1306
        /* Override umask and utimes if asked */
1166
1307
        if (pflag)
1167
1308
                do_fsetstat(conn, handle, handle_len, &a);
1168
1309
 
1169
 
        status = do_close(conn, handle, handle_len);
1170
 
 
1171
 
done:
 
1310
        if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
 
1311
                status = -1;
1172
1312
        xfree(handle);
1173
 
        buffer_free(&msg);
1174
 
        return(status);
 
1313
 
 
1314
        return status;
1175
1315
}