Statistics
| Branch: | Revision:

root / block / ssh.c @ f2e5dca4

History | View | Annotate | Download (29 kB)

1
/*
2
 * Secure Shell (ssh) backend for QEMU.
3
 *
4
 * Copyright (C) 2013 Red Hat Inc., Richard W.M. Jones <rjones@redhat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <stdarg.h>
28

    
29
#include <libssh2.h>
30
#include <libssh2_sftp.h>
31

    
32
#include "block/block_int.h"
33
#include "qemu/sockets.h"
34
#include "qemu/uri.h"
35
#include "qapi/qmp/qint.h"
36

    
37
/* DEBUG_SSH=1 enables the DPRINTF (debugging printf) statements in
38
 * this block driver code.
39
 *
40
 * TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself.  Note
41
 * that this requires that libssh2 was specially compiled with the
42
 * `./configure --enable-debug' option, so most likely you will have
43
 * to compile it yourself.  The meaning of <bitmask> is described
44
 * here: http://www.libssh2.org/libssh2_trace.html
45
 */
46
#define DEBUG_SSH     0
47
#define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
48

    
49
#define DPRINTF(fmt, ...)                           \
50
    do {                                            \
51
        if (DEBUG_SSH) {                            \
52
            fprintf(stderr, "ssh: %-15s " fmt "\n", \
53
                    __func__, ##__VA_ARGS__);       \
54
        }                                           \
55
    } while (0)
56

    
57
typedef struct BDRVSSHState {
58
    /* Coroutine. */
59
    CoMutex lock;
60

    
61
    /* SSH connection. */
62
    int sock;                         /* socket */
63
    LIBSSH2_SESSION *session;         /* ssh session */
64
    LIBSSH2_SFTP *sftp;               /* sftp session */
65
    LIBSSH2_SFTP_HANDLE *sftp_handle; /* sftp remote file handle */
66

    
67
    /* See ssh_seek() function below. */
68
    int64_t offset;
69
    bool offset_op_read;
70

    
71
    /* File attributes at open.  We try to keep the .filesize field
72
     * updated if it changes (eg by writing at the end of the file).
73
     */
74
    LIBSSH2_SFTP_ATTRIBUTES attrs;
75

    
76
    /* Used to warn if 'flush' is not supported. */
77
    char *hostport;
78
    bool unsafe_flush_warning;
79
} BDRVSSHState;
80

    
81
static void ssh_state_init(BDRVSSHState *s)
82
{
83
    memset(s, 0, sizeof *s);
84
    s->sock = -1;
85
    s->offset = -1;
86
    qemu_co_mutex_init(&s->lock);
87
}
88

    
89
static void ssh_state_free(BDRVSSHState *s)
90
{
91
    g_free(s->hostport);
92
    if (s->sftp_handle) {
93
        libssh2_sftp_close(s->sftp_handle);
94
    }
95
    if (s->sftp) {
96
        libssh2_sftp_shutdown(s->sftp);
97
    }
98
    if (s->session) {
99
        libssh2_session_disconnect(s->session,
100
                                   "from qemu ssh client: "
101
                                   "user closed the connection");
102
        libssh2_session_free(s->session);
103
    }
104
    if (s->sock >= 0) {
105
        close(s->sock);
106
    }
107
}
108

    
109
/* Wrappers around error_report which make sure to dump as much
110
 * information from libssh2 as possible.
111
 */
112
static void GCC_FMT_ATTR(2, 3)
113
session_error_report(BDRVSSHState *s, const char *fs, ...)
114
{
115
    va_list args;
116

    
117
    va_start(args, fs);
118
    error_vprintf(fs, args);
119

    
120
    if ((s)->session) {
121
        char *ssh_err;
122
        int ssh_err_code;
123

    
124
        libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
125
        /* This is not an errno.  See <libssh2.h>. */
126
        ssh_err_code = libssh2_session_last_errno((s)->session);
127

    
128
        error_printf(": %s (libssh2 error code: %d)", ssh_err, ssh_err_code);
129
    }
130

    
131
    va_end(args);
132
    error_printf("\n");
133
}
134

    
135
static void GCC_FMT_ATTR(2, 3)
136
sftp_error_report(BDRVSSHState *s, const char *fs, ...)
137
{
138
    va_list args;
139

    
140
    va_start(args, fs);
141
    error_vprintf(fs, args);
142

    
143
    if ((s)->sftp) {
144
        char *ssh_err;
145
        int ssh_err_code;
146
        unsigned long sftp_err_code;
147

    
148
        libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
149
        /* This is not an errno.  See <libssh2.h>. */
150
        ssh_err_code = libssh2_session_last_errno((s)->session);
151
        /* See <libssh2_sftp.h>. */
152
        sftp_err_code = libssh2_sftp_last_error((s)->sftp);
153

    
154
        error_printf(": %s (libssh2 error code: %d, sftp error code: %lu)",
155
                     ssh_err, ssh_err_code, sftp_err_code);
156
    }
157

    
158
    va_end(args);
159
    error_printf("\n");
160
}
161

    
162
static int parse_uri(const char *filename, QDict *options, Error **errp)
163
{
164
    URI *uri = NULL;
165
    QueryParams *qp = NULL;
166
    int i;
167

    
168
    uri = uri_parse(filename);
169
    if (!uri) {
170
        return -EINVAL;
171
    }
172

    
173
    if (strcmp(uri->scheme, "ssh") != 0) {
174
        error_setg(errp, "URI scheme must be 'ssh'");
175
        goto err;
176
    }
177

    
178
    if (!uri->server || strcmp(uri->server, "") == 0) {
179
        error_setg(errp, "missing hostname in URI");
180
        goto err;
181
    }
182

    
183
    if (!uri->path || strcmp(uri->path, "") == 0) {
184
        error_setg(errp, "missing remote path in URI");
185
        goto err;
186
    }
187

    
188
    qp = query_params_parse(uri->query);
189
    if (!qp) {
190
        error_setg(errp, "could not parse query parameters");
191
        goto err;
192
    }
193

    
194
    if(uri->user && strcmp(uri->user, "") != 0) {
195
        qdict_put(options, "user", qstring_from_str(uri->user));
196
    }
197

    
198
    qdict_put(options, "host", qstring_from_str(uri->server));
199

    
200
    if (uri->port) {
201
        qdict_put(options, "port", qint_from_int(uri->port));
202
    }
203

    
204
    qdict_put(options, "path", qstring_from_str(uri->path));
205

    
206
    /* Pick out any query parameters that we understand, and ignore
207
     * the rest.
208
     */
209
    for (i = 0; i < qp->n; ++i) {
210
        if (strcmp(qp->p[i].name, "host_key_check") == 0) {
211
            qdict_put(options, "host_key_check",
212
                      qstring_from_str(qp->p[i].value));
213
        }
214
    }
215

    
216
    query_params_free(qp);
217
    uri_free(uri);
218
    return 0;
219

    
220
 err:
221
    if (qp) {
222
      query_params_free(qp);
223
    }
224
    if (uri) {
225
      uri_free(uri);
226
    }
227
    return -EINVAL;
228
}
229

    
230
static void ssh_parse_filename(const char *filename, QDict *options,
231
                               Error **errp)
232
{
233
    if (qdict_haskey(options, "user") ||
234
        qdict_haskey(options, "host") ||
235
        qdict_haskey(options, "port") ||
236
        qdict_haskey(options, "path") ||
237
        qdict_haskey(options, "host_key_check")) {
238
        error_setg(errp, "user, host, port, path, host_key_check cannot be used at the same time as a file option");
239
        return;
240
    }
241

    
242
    parse_uri(filename, options, errp);
243
}
244

    
245
static int check_host_key_knownhosts(BDRVSSHState *s,
246
                                     const char *host, int port)
247
{
248
    const char *home;
249
    char *knh_file = NULL;
250
    LIBSSH2_KNOWNHOSTS *knh = NULL;
251
    struct libssh2_knownhost *found;
252
    int ret, r;
253
    const char *hostkey;
254
    size_t len;
255
    int type;
256

    
257
    hostkey = libssh2_session_hostkey(s->session, &len, &type);
258
    if (!hostkey) {
259
        ret = -EINVAL;
260
        session_error_report(s, "failed to read remote host key");
261
        goto out;
262
    }
263

    
264
    knh = libssh2_knownhost_init(s->session);
265
    if (!knh) {
266
        ret = -EINVAL;
267
        session_error_report(s, "failed to initialize known hosts support");
268
        goto out;
269
    }
270

    
271
    home = getenv("HOME");
272
    if (home) {
273
        knh_file = g_strdup_printf("%s/.ssh/known_hosts", home);
274
    } else {
275
        knh_file = g_strdup_printf("/root/.ssh/known_hosts");
276
    }
277

    
278
    /* Read all known hosts from OpenSSH-style known_hosts file. */
279
    libssh2_knownhost_readfile(knh, knh_file, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
280

    
281
    r = libssh2_knownhost_checkp(knh, host, port, hostkey, len,
282
                                 LIBSSH2_KNOWNHOST_TYPE_PLAIN|
283
                                 LIBSSH2_KNOWNHOST_KEYENC_RAW,
284
                                 &found);
285
    switch (r) {
286
    case LIBSSH2_KNOWNHOST_CHECK_MATCH:
287
        /* OK */
288
        DPRINTF("host key OK: %s", found->key);
289
        break;
290
    case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
291
        ret = -EINVAL;
292
        session_error_report(s, "host key does not match the one in known_hosts (found key %s)",
293
                             found->key);
294
        goto out;
295
    case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
296
        ret = -EINVAL;
297
        session_error_report(s, "no host key was found in known_hosts");
298
        goto out;
299
    case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
300
        ret = -EINVAL;
301
        session_error_report(s, "failure matching the host key with known_hosts");
302
        goto out;
303
    default:
304
        ret = -EINVAL;
305
        session_error_report(s, "unknown error matching the host key with known_hosts (%d)",
306
                             r);
307
        goto out;
308
    }
309

    
310
    /* known_hosts checking successful. */
311
    ret = 0;
312

    
313
 out:
314
    if (knh != NULL) {
315
        libssh2_knownhost_free(knh);
316
    }
317
    g_free(knh_file);
318
    return ret;
319
}
320

    
321
static unsigned hex2decimal(char ch)
322
{
323
    if (ch >= '0' && ch <= '9') {
324
        return (ch - '0');
325
    } else if (ch >= 'a' && ch <= 'f') {
326
        return 10 + (ch - 'a');
327
    } else if (ch >= 'A' && ch <= 'F') {
328
        return 10 + (ch - 'A');
329
    }
330

    
331
    return -1;
332
}
333

    
334
/* Compare the binary fingerprint (hash of host key) with the
335
 * host_key_check parameter.
336
 */
337
static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
338
                               const char *host_key_check)
339
{
340
    unsigned c;
341

    
342
    while (len > 0) {
343
        while (*host_key_check == ':')
344
            host_key_check++;
345
        if (!qemu_isxdigit(host_key_check[0]) ||
346
            !qemu_isxdigit(host_key_check[1]))
347
            return 1;
348
        c = hex2decimal(host_key_check[0]) * 16 +
349
            hex2decimal(host_key_check[1]);
350
        if (c - *fingerprint != 0)
351
            return c - *fingerprint;
352
        fingerprint++;
353
        len--;
354
        host_key_check += 2;
355
    }
356
    return *host_key_check - '\0';
357
}
358

    
359
static int
360
check_host_key_hash(BDRVSSHState *s, const char *hash,
361
                    int hash_type, size_t fingerprint_len)
362
{
363
    const char *fingerprint;
364

    
365
    fingerprint = libssh2_hostkey_hash(s->session, hash_type);
366
    if (!fingerprint) {
367
        session_error_report(s, "failed to read remote host key");
368
        return -EINVAL;
369
    }
370

    
371
    if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
372
                           hash) != 0) {
373
        error_report("remote host key does not match host_key_check '%s'",
374
                     hash);
375
        return -EPERM;
376
    }
377

    
378
    return 0;
379
}
380

    
381
static int check_host_key(BDRVSSHState *s, const char *host, int port,
382
                          const char *host_key_check)
383
{
384
    /* host_key_check=no */
385
    if (strcmp(host_key_check, "no") == 0) {
386
        return 0;
387
    }
388

    
389
    /* host_key_check=md5:xx:yy:zz:... */
390
    if (strncmp(host_key_check, "md5:", 4) == 0) {
391
        return check_host_key_hash(s, &host_key_check[4],
392
                                   LIBSSH2_HOSTKEY_HASH_MD5, 16);
393
    }
394

    
395
    /* host_key_check=sha1:xx:yy:zz:... */
396
    if (strncmp(host_key_check, "sha1:", 5) == 0) {
397
        return check_host_key_hash(s, &host_key_check[5],
398
                                   LIBSSH2_HOSTKEY_HASH_SHA1, 20);
399
    }
400

    
401
    /* host_key_check=yes */
402
    if (strcmp(host_key_check, "yes") == 0) {
403
        return check_host_key_knownhosts(s, host, port);
404
    }
405

    
406
    error_report("unknown host_key_check setting (%s)", host_key_check);
407
    return -EINVAL;
408
}
409

    
410
static int authenticate(BDRVSSHState *s, const char *user)
411
{
412
    int r, ret;
413
    const char *userauthlist;
414
    LIBSSH2_AGENT *agent = NULL;
415
    struct libssh2_agent_publickey *identity;
416
    struct libssh2_agent_publickey *prev_identity = NULL;
417

    
418
    userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
419
    if (strstr(userauthlist, "publickey") == NULL) {
420
        ret = -EPERM;
421
        error_report("remote server does not support \"publickey\" authentication");
422
        goto out;
423
    }
424

    
425
    /* Connect to ssh-agent and try each identity in turn. */
426
    agent = libssh2_agent_init(s->session);
427
    if (!agent) {
428
        ret = -EINVAL;
429
        session_error_report(s, "failed to initialize ssh-agent support");
430
        goto out;
431
    }
432
    if (libssh2_agent_connect(agent)) {
433
        ret = -ECONNREFUSED;
434
        session_error_report(s, "failed to connect to ssh-agent");
435
        goto out;
436
    }
437
    if (libssh2_agent_list_identities(agent)) {
438
        ret = -EINVAL;
439
        session_error_report(s, "failed requesting identities from ssh-agent");
440
        goto out;
441
    }
442

    
443
    for(;;) {
444
        r = libssh2_agent_get_identity(agent, &identity, prev_identity);
445
        if (r == 1) {           /* end of list */
446
            break;
447
        }
448
        if (r < 0) {
449
            ret = -EINVAL;
450
            session_error_report(s, "failed to obtain identity from ssh-agent");
451
            goto out;
452
        }
453
        r = libssh2_agent_userauth(agent, user, identity);
454
        if (r == 0) {
455
            /* Authenticated! */
456
            ret = 0;
457
            goto out;
458
        }
459
        /* Failed to authenticate with this identity, try the next one. */
460
        prev_identity = identity;
461
    }
462

    
463
    ret = -EPERM;
464
    error_report("failed to authenticate using publickey authentication "
465
                 "and the identities held by your ssh-agent");
466

    
467
 out:
468
    if (agent != NULL) {
469
        /* Note: libssh2 implementation implicitly calls
470
         * libssh2_agent_disconnect if necessary.
471
         */
472
        libssh2_agent_free(agent);
473
    }
474

    
475
    return ret;
476
}
477

    
478
static int connect_to_ssh(BDRVSSHState *s, QDict *options,
479
                          int ssh_flags, int creat_mode)
480
{
481
    int r, ret;
482
    Error *err = NULL;
483
    const char *host, *user, *path, *host_key_check;
484
    int port;
485

    
486
    host = qdict_get_str(options, "host");
487

    
488
    if (qdict_haskey(options, "port")) {
489
        port = qdict_get_int(options, "port");
490
    } else {
491
        port = 22;
492
    }
493

    
494
    path = qdict_get_str(options, "path");
495

    
496
    if (qdict_haskey(options, "user")) {
497
        user = qdict_get_str(options, "user");
498
    } else {
499
        user = g_get_user_name();
500
        if (!user) {
501
            ret = -errno;
502
            goto err;
503
        }
504
    }
505

    
506
    if (qdict_haskey(options, "host_key_check")) {
507
        host_key_check = qdict_get_str(options, "host_key_check");
508
    } else {
509
        host_key_check = "yes";
510
    }
511

    
512
    /* Construct the host:port name for inet_connect. */
513
    g_free(s->hostport);
514
    s->hostport = g_strdup_printf("%s:%d", host, port);
515

    
516
    /* Open the socket and connect. */
517
    s->sock = inet_connect(s->hostport, &err);
518
    if (err != NULL) {
519
        ret = -errno;
520
        qerror_report_err(err);
521
        error_free(err);
522
        goto err;
523
    }
524

    
525
    /* Create SSH session. */
526
    s->session = libssh2_session_init();
527
    if (!s->session) {
528
        ret = -EINVAL;
529
        session_error_report(s, "failed to initialize libssh2 session");
530
        goto err;
531
    }
532

    
533
#if TRACE_LIBSSH2 != 0
534
    libssh2_trace(s->session, TRACE_LIBSSH2);
535
#endif
536

    
537
    r = libssh2_session_handshake(s->session, s->sock);
538
    if (r != 0) {
539
        ret = -EINVAL;
540
        session_error_report(s, "failed to establish SSH session");
541
        goto err;
542
    }
543

    
544
    /* Check the remote host's key against known_hosts. */
545
    ret = check_host_key(s, host, port, host_key_check);
546
    if (ret < 0) {
547
        goto err;
548
    }
549

    
550
    /* Authenticate. */
551
    ret = authenticate(s, user);
552
    if (ret < 0) {
553
        goto err;
554
    }
555

    
556
    /* Start SFTP. */
557
    s->sftp = libssh2_sftp_init(s->session);
558
    if (!s->sftp) {
559
        session_error_report(s, "failed to initialize sftp handle");
560
        ret = -EINVAL;
561
        goto err;
562
    }
563

    
564
    /* Open the remote file. */
565
    DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
566
            path, ssh_flags, creat_mode);
567
    s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
568
    if (!s->sftp_handle) {
569
        session_error_report(s, "failed to open remote file '%s'", path);
570
        ret = -EINVAL;
571
        goto err;
572
    }
573

    
574
    r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
575
    if (r < 0) {
576
        sftp_error_report(s, "failed to read file attributes");
577
        return -EINVAL;
578
    }
579

    
580
    /* Delete the options we've used; any not deleted will cause the
581
     * block layer to give an error about unused options.
582
     */
583
    qdict_del(options, "host");
584
    qdict_del(options, "port");
585
    qdict_del(options, "user");
586
    qdict_del(options, "path");
587
    qdict_del(options, "host_key_check");
588

    
589
    return 0;
590

    
591
 err:
592
    if (s->sftp_handle) {
593
        libssh2_sftp_close(s->sftp_handle);
594
    }
595
    s->sftp_handle = NULL;
596
    if (s->sftp) {
597
        libssh2_sftp_shutdown(s->sftp);
598
    }
599
    s->sftp = NULL;
600
    if (s->session) {
601
        libssh2_session_disconnect(s->session,
602
                                   "from qemu ssh client: "
603
                                   "error opening connection");
604
        libssh2_session_free(s->session);
605
    }
606
    s->session = NULL;
607

    
608
    return ret;
609
}
610

    
611
static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags)
612
{
613
    BDRVSSHState *s = bs->opaque;
614
    int ret;
615
    int ssh_flags;
616

    
617
    ssh_state_init(s);
618

    
619
    ssh_flags = LIBSSH2_FXF_READ;
620
    if (bdrv_flags & BDRV_O_RDWR) {
621
        ssh_flags |= LIBSSH2_FXF_WRITE;
622
    }
623

    
624
    /* Start up SSH. */
625
    ret = connect_to_ssh(s, options, ssh_flags, 0);
626
    if (ret < 0) {
627
        goto err;
628
    }
629

    
630
    /* Go non-blocking. */
631
    libssh2_session_set_blocking(s->session, 0);
632

    
633
    return 0;
634

    
635
 err:
636
    if (s->sock >= 0) {
637
        close(s->sock);
638
    }
639
    s->sock = -1;
640

    
641
    return ret;
642
}
643

    
644
static QEMUOptionParameter ssh_create_options[] = {
645
    {
646
        .name = BLOCK_OPT_SIZE,
647
        .type = OPT_SIZE,
648
        .help = "Virtual disk size"
649
    },
650
    { NULL }
651
};
652

    
653
static int ssh_create(const char *filename, QEMUOptionParameter *options)
654
{
655
    int r, ret;
656
    Error *local_err = NULL;
657
    int64_t total_size = 0;
658
    QDict *uri_options = NULL;
659
    BDRVSSHState s;
660
    ssize_t r2;
661
    char c[1] = { '\0' };
662

    
663
    ssh_state_init(&s);
664

    
665
    /* Get desired file size. */
666
    while (options && options->name) {
667
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
668
            total_size = options->value.n;
669
        }
670
        options++;
671
    }
672
    DPRINTF("total_size=%" PRIi64, total_size);
673

    
674
    uri_options = qdict_new();
675
    r = parse_uri(filename, uri_options, &local_err);
676
    if (r < 0) {
677
        qerror_report_err(local_err);
678
        error_free(local_err);
679
        ret = r;
680
        goto out;
681
    }
682

    
683
    r = connect_to_ssh(&s, uri_options,
684
                       LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
685
                       LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644);
686
    if (r < 0) {
687
        ret = r;
688
        goto out;
689
    }
690

    
691
    if (total_size > 0) {
692
        libssh2_sftp_seek64(s.sftp_handle, total_size-1);
693
        r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
694
        if (r2 < 0) {
695
            sftp_error_report(&s, "truncate failed");
696
            ret = -EINVAL;
697
            goto out;
698
        }
699
        s.attrs.filesize = total_size;
700
    }
701

    
702
    ret = 0;
703

    
704
 out:
705
    ssh_state_free(&s);
706
    if (uri_options != NULL) {
707
        QDECREF(uri_options);
708
    }
709
    return ret;
710
}
711

    
712
static void ssh_close(BlockDriverState *bs)
713
{
714
    BDRVSSHState *s = bs->opaque;
715

    
716
    ssh_state_free(s);
717
}
718

    
719
static int ssh_has_zero_init(BlockDriverState *bs)
720
{
721
    BDRVSSHState *s = bs->opaque;
722
    /* Assume false, unless we can positively prove it's true. */
723
    int has_zero_init = 0;
724

    
725
    if (s->attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
726
        if (s->attrs.permissions & LIBSSH2_SFTP_S_IFREG) {
727
            has_zero_init = 1;
728
        }
729
    }
730

    
731
    return has_zero_init;
732
}
733

    
734
static void restart_coroutine(void *opaque)
735
{
736
    Coroutine *co = opaque;
737

    
738
    DPRINTF("co=%p", co);
739

    
740
    qemu_coroutine_enter(co, NULL);
741
}
742

    
743
static coroutine_fn void set_fd_handler(BDRVSSHState *s)
744
{
745
    int r;
746
    IOHandler *rd_handler = NULL, *wr_handler = NULL;
747
    Coroutine *co = qemu_coroutine_self();
748

    
749
    r = libssh2_session_block_directions(s->session);
750

    
751
    if (r & LIBSSH2_SESSION_BLOCK_INBOUND) {
752
        rd_handler = restart_coroutine;
753
    }
754
    if (r & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
755
        wr_handler = restart_coroutine;
756
    }
757

    
758
    DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock,
759
            rd_handler, wr_handler);
760

    
761
    qemu_aio_set_fd_handler(s->sock, rd_handler, wr_handler, co);
762
}
763

    
764
static coroutine_fn void clear_fd_handler(BDRVSSHState *s)
765
{
766
    DPRINTF("s->sock=%d", s->sock);
767
    qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL);
768
}
769

    
770
/* A non-blocking call returned EAGAIN, so yield, ensuring the
771
 * handlers are set up so that we'll be rescheduled when there is an
772
 * interesting event on the socket.
773
 */
774
static coroutine_fn void co_yield(BDRVSSHState *s)
775
{
776
    set_fd_handler(s);
777
    qemu_coroutine_yield();
778
    clear_fd_handler(s);
779
}
780

    
781
/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
782
 * in the remote file.  Notice that it just updates a field in the
783
 * sftp_handle structure, so there is no network traffic and it cannot
784
 * fail.
785
 *
786
 * However, `libssh2_sftp_seek64' does have a catastrophic effect on
787
 * performance since it causes the handle to throw away all in-flight
788
 * reads and buffered readahead data.  Therefore this function tries
789
 * to be intelligent about when to call the underlying libssh2 function.
790
 */
791
#define SSH_SEEK_WRITE 0
792
#define SSH_SEEK_READ  1
793
#define SSH_SEEK_FORCE 2
794

    
795
static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
796
{
797
    bool op_read = (flags & SSH_SEEK_READ) != 0;
798
    bool force = (flags & SSH_SEEK_FORCE) != 0;
799

    
800
    if (force || op_read != s->offset_op_read || offset != s->offset) {
801
        DPRINTF("seeking to offset=%" PRIi64, offset);
802
        libssh2_sftp_seek64(s->sftp_handle, offset);
803
        s->offset = offset;
804
        s->offset_op_read = op_read;
805
    }
806
}
807

    
808
static coroutine_fn int ssh_read(BDRVSSHState *s,
809
                                 int64_t offset, size_t size,
810
                                 QEMUIOVector *qiov)
811
{
812
    ssize_t r;
813
    size_t got;
814
    char *buf, *end_of_vec;
815
    struct iovec *i;
816

    
817
    DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
818

    
819
    ssh_seek(s, offset, SSH_SEEK_READ);
820

    
821
    /* This keeps track of the current iovec element ('i'), where we
822
     * will write to next ('buf'), and the end of the current iovec
823
     * ('end_of_vec').
824
     */
825
    i = &qiov->iov[0];
826
    buf = i->iov_base;
827
    end_of_vec = i->iov_base + i->iov_len;
828

    
829
    /* libssh2 has a hard-coded limit of 2000 bytes per request,
830
     * although it will also do readahead behind our backs.  Therefore
831
     * we may have to do repeated reads here until we have read 'size'
832
     * bytes.
833
     */
834
    for (got = 0; got < size; ) {
835
    again:
836
        DPRINTF("sftp_read buf=%p size=%zu", buf, end_of_vec - buf);
837
        r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
838
        DPRINTF("sftp_read returned %zd", r);
839

    
840
        if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
841
            co_yield(s);
842
            goto again;
843
        }
844
        if (r < 0) {
845
            sftp_error_report(s, "read failed");
846
            s->offset = -1;
847
            return -EIO;
848
        }
849
        if (r == 0) {
850
            /* EOF: Short read so pad the buffer with zeroes and return it. */
851
            qemu_iovec_memset(qiov, got, 0, size - got);
852
            return 0;
853
        }
854

    
855
        got += r;
856
        buf += r;
857
        s->offset += r;
858
        if (buf >= end_of_vec && got < size) {
859
            i++;
860
            buf = i->iov_base;
861
            end_of_vec = i->iov_base + i->iov_len;
862
        }
863
    }
864

    
865
    return 0;
866
}
867

    
868
static coroutine_fn int ssh_co_readv(BlockDriverState *bs,
869
                                     int64_t sector_num,
870
                                     int nb_sectors, QEMUIOVector *qiov)
871
{
872
    BDRVSSHState *s = bs->opaque;
873
    int ret;
874

    
875
    qemu_co_mutex_lock(&s->lock);
876
    ret = ssh_read(s, sector_num * BDRV_SECTOR_SIZE,
877
                   nb_sectors * BDRV_SECTOR_SIZE, qiov);
878
    qemu_co_mutex_unlock(&s->lock);
879

    
880
    return ret;
881
}
882

    
883
static int ssh_write(BDRVSSHState *s,
884
                     int64_t offset, size_t size,
885
                     QEMUIOVector *qiov)
886
{
887
    ssize_t r;
888
    size_t written;
889
    char *buf, *end_of_vec;
890
    struct iovec *i;
891

    
892
    DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
893

    
894
    ssh_seek(s, offset, SSH_SEEK_WRITE);
895

    
896
    /* This keeps track of the current iovec element ('i'), where we
897
     * will read from next ('buf'), and the end of the current iovec
898
     * ('end_of_vec').
899
     */
900
    i = &qiov->iov[0];
901
    buf = i->iov_base;
902
    end_of_vec = i->iov_base + i->iov_len;
903

    
904
    for (written = 0; written < size; ) {
905
    again:
906
        DPRINTF("sftp_write buf=%p size=%zu", buf, end_of_vec - buf);
907
        r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf);
908
        DPRINTF("sftp_write returned %zd", r);
909

    
910
        if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
911
            co_yield(s);
912
            goto again;
913
        }
914
        if (r < 0) {
915
            sftp_error_report(s, "write failed");
916
            s->offset = -1;
917
            return -EIO;
918
        }
919
        /* The libssh2 API is very unclear about this.  A comment in
920
         * the code says "nothing was acked, and no EAGAIN was
921
         * received!" which apparently means that no data got sent
922
         * out, and the underlying channel didn't return any EAGAIN
923
         * indication.  I think this is a bug in either libssh2 or
924
         * OpenSSH (server-side).  In any case, forcing a seek (to
925
         * discard libssh2 internal buffers), and then trying again
926
         * works for me.
927
         */
928
        if (r == 0) {
929
            ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE);
930
            co_yield(s);
931
            goto again;
932
        }
933

    
934
        written += r;
935
        buf += r;
936
        s->offset += r;
937
        if (buf >= end_of_vec && written < size) {
938
            i++;
939
            buf = i->iov_base;
940
            end_of_vec = i->iov_base + i->iov_len;
941
        }
942

    
943
        if (offset + written > s->attrs.filesize)
944
            s->attrs.filesize = offset + written;
945
    }
946

    
947
    return 0;
948
}
949

    
950
static coroutine_fn int ssh_co_writev(BlockDriverState *bs,
951
                                      int64_t sector_num,
952
                                      int nb_sectors, QEMUIOVector *qiov)
953
{
954
    BDRVSSHState *s = bs->opaque;
955
    int ret;
956

    
957
    qemu_co_mutex_lock(&s->lock);
958
    ret = ssh_write(s, sector_num * BDRV_SECTOR_SIZE,
959
                    nb_sectors * BDRV_SECTOR_SIZE, qiov);
960
    qemu_co_mutex_unlock(&s->lock);
961

    
962
    return ret;
963
}
964

    
965
static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
966
{
967
    if (!s->unsafe_flush_warning) {
968
        error_report("warning: ssh server %s does not support fsync",
969
                     s->hostport);
970
        if (what) {
971
            error_report("to support fsync, you need %s", what);
972
        }
973
        s->unsafe_flush_warning = true;
974
    }
975
}
976

    
977
#ifdef HAS_LIBSSH2_SFTP_FSYNC
978

    
979
static coroutine_fn int ssh_flush(BDRVSSHState *s)
980
{
981
    int r;
982

    
983
    DPRINTF("fsync");
984
 again:
985
    r = libssh2_sftp_fsync(s->sftp_handle);
986
    if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
987
        co_yield(s);
988
        goto again;
989
    }
990
    if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
991
        libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) {
992
        unsafe_flush_warning(s, "OpenSSH >= 6.3");
993
        return 0;
994
    }
995
    if (r < 0) {
996
        sftp_error_report(s, "fsync failed");
997
        return -EIO;
998
    }
999

    
1000
    return 0;
1001
}
1002

    
1003
static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1004
{
1005
    BDRVSSHState *s = bs->opaque;
1006
    int ret;
1007

    
1008
    qemu_co_mutex_lock(&s->lock);
1009
    ret = ssh_flush(s);
1010
    qemu_co_mutex_unlock(&s->lock);
1011

    
1012
    return ret;
1013
}
1014

    
1015
#else /* !HAS_LIBSSH2_SFTP_FSYNC */
1016

    
1017
static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1018
{
1019
    BDRVSSHState *s = bs->opaque;
1020

    
1021
    unsafe_flush_warning(s, "libssh2 >= 1.4.4");
1022
    return 0;
1023
}
1024

    
1025
#endif /* !HAS_LIBSSH2_SFTP_FSYNC */
1026

    
1027
static int64_t ssh_getlength(BlockDriverState *bs)
1028
{
1029
    BDRVSSHState *s = bs->opaque;
1030
    int64_t length;
1031

    
1032
    /* Note we cannot make a libssh2 call here. */
1033
    length = (int64_t) s->attrs.filesize;
1034
    DPRINTF("length=%" PRIi64, length);
1035

    
1036
    return length;
1037
}
1038

    
1039
static BlockDriver bdrv_ssh = {
1040
    .format_name                  = "ssh",
1041
    .protocol_name                = "ssh",
1042
    .instance_size                = sizeof(BDRVSSHState),
1043
    .bdrv_parse_filename          = ssh_parse_filename,
1044
    .bdrv_file_open               = ssh_file_open,
1045
    .bdrv_create                  = ssh_create,
1046
    .bdrv_close                   = ssh_close,
1047
    .bdrv_has_zero_init           = ssh_has_zero_init,
1048
    .bdrv_co_readv                = ssh_co_readv,
1049
    .bdrv_co_writev               = ssh_co_writev,
1050
    .bdrv_getlength               = ssh_getlength,
1051
    .bdrv_co_flush_to_disk        = ssh_co_flush,
1052
    .create_options               = ssh_create_options,
1053
};
1054

    
1055
static void bdrv_ssh_init(void)
1056
{
1057
    int r;
1058

    
1059
    r = libssh2_init(0);
1060
    if (r != 0) {
1061
        fprintf(stderr, "libssh2 initialization failed, %d\n", r);
1062
        exit(EXIT_FAILURE);
1063
    }
1064

    
1065
    bdrv_register(&bdrv_ssh);
1066
}
1067

    
1068
block_init(bdrv_ssh_init);