xref: /openbmc/qemu/block/ssh.c (revision b45c03f5)
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/error-report.h"
34 #include "qemu/sockets.h"
35 #include "qemu/uri.h"
36 #include "qapi/qmp/qint.h"
37 #include "qapi/qmp/qstring.h"
38 
39 /* DEBUG_SSH=1 enables the DPRINTF (debugging printf) statements in
40  * this block driver code.
41  *
42  * TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself.  Note
43  * that this requires that libssh2 was specially compiled with the
44  * `./configure --enable-debug' option, so most likely you will have
45  * to compile it yourself.  The meaning of <bitmask> is described
46  * here: http://www.libssh2.org/libssh2_trace.html
47  */
48 #define DEBUG_SSH     0
49 #define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
50 
51 #define DPRINTF(fmt, ...)                           \
52     do {                                            \
53         if (DEBUG_SSH) {                            \
54             fprintf(stderr, "ssh: %-15s " fmt "\n", \
55                     __func__, ##__VA_ARGS__);       \
56         }                                           \
57     } while (0)
58 
59 typedef struct BDRVSSHState {
60     /* Coroutine. */
61     CoMutex lock;
62 
63     /* SSH connection. */
64     int sock;                         /* socket */
65     LIBSSH2_SESSION *session;         /* ssh session */
66     LIBSSH2_SFTP *sftp;               /* sftp session */
67     LIBSSH2_SFTP_HANDLE *sftp_handle; /* sftp remote file handle */
68 
69     /* See ssh_seek() function below. */
70     int64_t offset;
71     bool offset_op_read;
72 
73     /* File attributes at open.  We try to keep the .filesize field
74      * updated if it changes (eg by writing at the end of the file).
75      */
76     LIBSSH2_SFTP_ATTRIBUTES attrs;
77 
78     /* Used to warn if 'flush' is not supported. */
79     char *hostport;
80     bool unsafe_flush_warning;
81 } BDRVSSHState;
82 
83 static void ssh_state_init(BDRVSSHState *s)
84 {
85     memset(s, 0, sizeof *s);
86     s->sock = -1;
87     s->offset = -1;
88     qemu_co_mutex_init(&s->lock);
89 }
90 
91 static void ssh_state_free(BDRVSSHState *s)
92 {
93     g_free(s->hostport);
94     if (s->sftp_handle) {
95         libssh2_sftp_close(s->sftp_handle);
96     }
97     if (s->sftp) {
98         libssh2_sftp_shutdown(s->sftp);
99     }
100     if (s->session) {
101         libssh2_session_disconnect(s->session,
102                                    "from qemu ssh client: "
103                                    "user closed the connection");
104         libssh2_session_free(s->session);
105     }
106     if (s->sock >= 0) {
107         close(s->sock);
108     }
109 }
110 
111 static void GCC_FMT_ATTR(3, 4)
112 session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
113 {
114     va_list args;
115     char *msg;
116 
117     va_start(args, fs);
118     msg = g_strdup_vprintf(fs, args);
119     va_end(args);
120 
121     if (s->session) {
122         char *ssh_err;
123         int ssh_err_code;
124 
125         /* This is not an errno.  See <libssh2.h>. */
126         ssh_err_code = libssh2_session_last_error(s->session,
127                                                   &ssh_err, NULL, 0);
128         error_setg(errp, "%s: %s (libssh2 error code: %d)",
129                    msg, ssh_err, ssh_err_code);
130     } else {
131         error_setg(errp, "%s", msg);
132     }
133     g_free(msg);
134 }
135 
136 static void GCC_FMT_ATTR(3, 4)
137 sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
138 {
139     va_list args;
140     char *msg;
141 
142     va_start(args, fs);
143     msg = g_strdup_vprintf(fs, args);
144     va_end(args);
145 
146     if (s->sftp) {
147         char *ssh_err;
148         int ssh_err_code;
149         unsigned long sftp_err_code;
150 
151         /* This is not an errno.  See <libssh2.h>. */
152         ssh_err_code = libssh2_session_last_error(s->session,
153                                                   &ssh_err, NULL, 0);
154         /* See <libssh2_sftp.h>. */
155         sftp_err_code = libssh2_sftp_last_error((s)->sftp);
156 
157         error_setg(errp,
158                    "%s: %s (libssh2 error code: %d, sftp error code: %lu)",
159                    msg, ssh_err, ssh_err_code, sftp_err_code);
160     } else {
161         error_setg(errp, "%s", msg);
162     }
163     g_free(msg);
164 }
165 
166 static void GCC_FMT_ATTR(2, 3)
167 sftp_error_report(BDRVSSHState *s, const char *fs, ...)
168 {
169     va_list args;
170 
171     va_start(args, fs);
172     error_vprintf(fs, args);
173 
174     if ((s)->sftp) {
175         char *ssh_err;
176         int ssh_err_code;
177         unsigned long sftp_err_code;
178 
179         /* This is not an errno.  See <libssh2.h>. */
180         ssh_err_code = libssh2_session_last_error(s->session,
181                                                   &ssh_err, NULL, 0);
182         /* See <libssh2_sftp.h>. */
183         sftp_err_code = libssh2_sftp_last_error((s)->sftp);
184 
185         error_printf(": %s (libssh2 error code: %d, sftp error code: %lu)",
186                      ssh_err, ssh_err_code, sftp_err_code);
187     }
188 
189     va_end(args);
190     error_printf("\n");
191 }
192 
193 static int parse_uri(const char *filename, QDict *options, Error **errp)
194 {
195     URI *uri = NULL;
196     QueryParams *qp = NULL;
197     int i;
198 
199     uri = uri_parse(filename);
200     if (!uri) {
201         return -EINVAL;
202     }
203 
204     if (strcmp(uri->scheme, "ssh") != 0) {
205         error_setg(errp, "URI scheme must be 'ssh'");
206         goto err;
207     }
208 
209     if (!uri->server || strcmp(uri->server, "") == 0) {
210         error_setg(errp, "missing hostname in URI");
211         goto err;
212     }
213 
214     if (!uri->path || strcmp(uri->path, "") == 0) {
215         error_setg(errp, "missing remote path in URI");
216         goto err;
217     }
218 
219     qp = query_params_parse(uri->query);
220     if (!qp) {
221         error_setg(errp, "could not parse query parameters");
222         goto err;
223     }
224 
225     if(uri->user && strcmp(uri->user, "") != 0) {
226         qdict_put(options, "user", qstring_from_str(uri->user));
227     }
228 
229     qdict_put(options, "host", qstring_from_str(uri->server));
230 
231     if (uri->port) {
232         qdict_put(options, "port", qint_from_int(uri->port));
233     }
234 
235     qdict_put(options, "path", qstring_from_str(uri->path));
236 
237     /* Pick out any query parameters that we understand, and ignore
238      * the rest.
239      */
240     for (i = 0; i < qp->n; ++i) {
241         if (strcmp(qp->p[i].name, "host_key_check") == 0) {
242             qdict_put(options, "host_key_check",
243                       qstring_from_str(qp->p[i].value));
244         }
245     }
246 
247     query_params_free(qp);
248     uri_free(uri);
249     return 0;
250 
251  err:
252     if (qp) {
253       query_params_free(qp);
254     }
255     if (uri) {
256       uri_free(uri);
257     }
258     return -EINVAL;
259 }
260 
261 static void ssh_parse_filename(const char *filename, QDict *options,
262                                Error **errp)
263 {
264     if (qdict_haskey(options, "user") ||
265         qdict_haskey(options, "host") ||
266         qdict_haskey(options, "port") ||
267         qdict_haskey(options, "path") ||
268         qdict_haskey(options, "host_key_check")) {
269         error_setg(errp, "user, host, port, path, host_key_check cannot be used at the same time as a file option");
270         return;
271     }
272 
273     parse_uri(filename, options, errp);
274 }
275 
276 static int check_host_key_knownhosts(BDRVSSHState *s,
277                                      const char *host, int port, Error **errp)
278 {
279     const char *home;
280     char *knh_file = NULL;
281     LIBSSH2_KNOWNHOSTS *knh = NULL;
282     struct libssh2_knownhost *found;
283     int ret, r;
284     const char *hostkey;
285     size_t len;
286     int type;
287 
288     hostkey = libssh2_session_hostkey(s->session, &len, &type);
289     if (!hostkey) {
290         ret = -EINVAL;
291         session_error_setg(errp, s, "failed to read remote host key");
292         goto out;
293     }
294 
295     knh = libssh2_knownhost_init(s->session);
296     if (!knh) {
297         ret = -EINVAL;
298         session_error_setg(errp, s,
299                            "failed to initialize known hosts support");
300         goto out;
301     }
302 
303     home = getenv("HOME");
304     if (home) {
305         knh_file = g_strdup_printf("%s/.ssh/known_hosts", home);
306     } else {
307         knh_file = g_strdup_printf("/root/.ssh/known_hosts");
308     }
309 
310     /* Read all known hosts from OpenSSH-style known_hosts file. */
311     libssh2_knownhost_readfile(knh, knh_file, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
312 
313     r = libssh2_knownhost_checkp(knh, host, port, hostkey, len,
314                                  LIBSSH2_KNOWNHOST_TYPE_PLAIN|
315                                  LIBSSH2_KNOWNHOST_KEYENC_RAW,
316                                  &found);
317     switch (r) {
318     case LIBSSH2_KNOWNHOST_CHECK_MATCH:
319         /* OK */
320         DPRINTF("host key OK: %s", found->key);
321         break;
322     case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
323         ret = -EINVAL;
324         session_error_setg(errp, s,
325                       "host key does not match the one in known_hosts"
326                       " (found key %s)", found->key);
327         goto out;
328     case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
329         ret = -EINVAL;
330         session_error_setg(errp, s, "no host key was found in known_hosts");
331         goto out;
332     case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
333         ret = -EINVAL;
334         session_error_setg(errp, s,
335                       "failure matching the host key with known_hosts");
336         goto out;
337     default:
338         ret = -EINVAL;
339         session_error_setg(errp, s, "unknown error matching the host key"
340                       " with known_hosts (%d)", r);
341         goto out;
342     }
343 
344     /* known_hosts checking successful. */
345     ret = 0;
346 
347  out:
348     if (knh != NULL) {
349         libssh2_knownhost_free(knh);
350     }
351     g_free(knh_file);
352     return ret;
353 }
354 
355 static unsigned hex2decimal(char ch)
356 {
357     if (ch >= '0' && ch <= '9') {
358         return (ch - '0');
359     } else if (ch >= 'a' && ch <= 'f') {
360         return 10 + (ch - 'a');
361     } else if (ch >= 'A' && ch <= 'F') {
362         return 10 + (ch - 'A');
363     }
364 
365     return -1;
366 }
367 
368 /* Compare the binary fingerprint (hash of host key) with the
369  * host_key_check parameter.
370  */
371 static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
372                                const char *host_key_check)
373 {
374     unsigned c;
375 
376     while (len > 0) {
377         while (*host_key_check == ':')
378             host_key_check++;
379         if (!qemu_isxdigit(host_key_check[0]) ||
380             !qemu_isxdigit(host_key_check[1]))
381             return 1;
382         c = hex2decimal(host_key_check[0]) * 16 +
383             hex2decimal(host_key_check[1]);
384         if (c - *fingerprint != 0)
385             return c - *fingerprint;
386         fingerprint++;
387         len--;
388         host_key_check += 2;
389     }
390     return *host_key_check - '\0';
391 }
392 
393 static int
394 check_host_key_hash(BDRVSSHState *s, const char *hash,
395                     int hash_type, size_t fingerprint_len, Error **errp)
396 {
397     const char *fingerprint;
398 
399     fingerprint = libssh2_hostkey_hash(s->session, hash_type);
400     if (!fingerprint) {
401         session_error_setg(errp, s, "failed to read remote host key");
402         return -EINVAL;
403     }
404 
405     if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
406                            hash) != 0) {
407         error_setg(errp, "remote host key does not match host_key_check '%s'",
408                    hash);
409         return -EPERM;
410     }
411 
412     return 0;
413 }
414 
415 static int check_host_key(BDRVSSHState *s, const char *host, int port,
416                           const char *host_key_check, Error **errp)
417 {
418     /* host_key_check=no */
419     if (strcmp(host_key_check, "no") == 0) {
420         return 0;
421     }
422 
423     /* host_key_check=md5:xx:yy:zz:... */
424     if (strncmp(host_key_check, "md5:", 4) == 0) {
425         return check_host_key_hash(s, &host_key_check[4],
426                                    LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
427     }
428 
429     /* host_key_check=sha1:xx:yy:zz:... */
430     if (strncmp(host_key_check, "sha1:", 5) == 0) {
431         return check_host_key_hash(s, &host_key_check[5],
432                                    LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
433     }
434 
435     /* host_key_check=yes */
436     if (strcmp(host_key_check, "yes") == 0) {
437         return check_host_key_knownhosts(s, host, port, errp);
438     }
439 
440     error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
441     return -EINVAL;
442 }
443 
444 static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
445 {
446     int r, ret;
447     const char *userauthlist;
448     LIBSSH2_AGENT *agent = NULL;
449     struct libssh2_agent_publickey *identity;
450     struct libssh2_agent_publickey *prev_identity = NULL;
451 
452     userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
453     if (strstr(userauthlist, "publickey") == NULL) {
454         ret = -EPERM;
455         error_setg(errp,
456                 "remote server does not support \"publickey\" authentication");
457         goto out;
458     }
459 
460     /* Connect to ssh-agent and try each identity in turn. */
461     agent = libssh2_agent_init(s->session);
462     if (!agent) {
463         ret = -EINVAL;
464         session_error_setg(errp, s, "failed to initialize ssh-agent support");
465         goto out;
466     }
467     if (libssh2_agent_connect(agent)) {
468         ret = -ECONNREFUSED;
469         session_error_setg(errp, s, "failed to connect to ssh-agent");
470         goto out;
471     }
472     if (libssh2_agent_list_identities(agent)) {
473         ret = -EINVAL;
474         session_error_setg(errp, s,
475                            "failed requesting identities from ssh-agent");
476         goto out;
477     }
478 
479     for(;;) {
480         r = libssh2_agent_get_identity(agent, &identity, prev_identity);
481         if (r == 1) {           /* end of list */
482             break;
483         }
484         if (r < 0) {
485             ret = -EINVAL;
486             session_error_setg(errp, s,
487                                "failed to obtain identity from ssh-agent");
488             goto out;
489         }
490         r = libssh2_agent_userauth(agent, user, identity);
491         if (r == 0) {
492             /* Authenticated! */
493             ret = 0;
494             goto out;
495         }
496         /* Failed to authenticate with this identity, try the next one. */
497         prev_identity = identity;
498     }
499 
500     ret = -EPERM;
501     error_setg(errp, "failed to authenticate using publickey authentication "
502                "and the identities held by your ssh-agent");
503 
504  out:
505     if (agent != NULL) {
506         /* Note: libssh2 implementation implicitly calls
507          * libssh2_agent_disconnect if necessary.
508          */
509         libssh2_agent_free(agent);
510     }
511 
512     return ret;
513 }
514 
515 static int connect_to_ssh(BDRVSSHState *s, QDict *options,
516                           int ssh_flags, int creat_mode, Error **errp)
517 {
518     int r, ret;
519     const char *host, *user, *path, *host_key_check;
520     int port;
521 
522     if (!qdict_haskey(options, "host")) {
523         ret = -EINVAL;
524         error_setg(errp, "No hostname was specified");
525         goto err;
526     }
527     host = qdict_get_str(options, "host");
528 
529     if (qdict_haskey(options, "port")) {
530         port = qdict_get_int(options, "port");
531     } else {
532         port = 22;
533     }
534 
535     if (!qdict_haskey(options, "path")) {
536         ret = -EINVAL;
537         error_setg(errp, "No path was specified");
538         goto err;
539     }
540     path = qdict_get_str(options, "path");
541 
542     if (qdict_haskey(options, "user")) {
543         user = qdict_get_str(options, "user");
544     } else {
545         user = g_get_user_name();
546         if (!user) {
547             error_setg_errno(errp, errno, "Can't get user name");
548             ret = -errno;
549             goto err;
550         }
551     }
552 
553     if (qdict_haskey(options, "host_key_check")) {
554         host_key_check = qdict_get_str(options, "host_key_check");
555     } else {
556         host_key_check = "yes";
557     }
558 
559     /* Construct the host:port name for inet_connect. */
560     g_free(s->hostport);
561     s->hostport = g_strdup_printf("%s:%d", host, port);
562 
563     /* Open the socket and connect. */
564     s->sock = inet_connect(s->hostport, errp);
565     if (s->sock < 0) {
566         ret = -EIO;
567         goto err;
568     }
569 
570     /* Create SSH session. */
571     s->session = libssh2_session_init();
572     if (!s->session) {
573         ret = -EINVAL;
574         session_error_setg(errp, s, "failed to initialize libssh2 session");
575         goto err;
576     }
577 
578 #if TRACE_LIBSSH2 != 0
579     libssh2_trace(s->session, TRACE_LIBSSH2);
580 #endif
581 
582     r = libssh2_session_handshake(s->session, s->sock);
583     if (r != 0) {
584         ret = -EINVAL;
585         session_error_setg(errp, s, "failed to establish SSH session");
586         goto err;
587     }
588 
589     /* Check the remote host's key against known_hosts. */
590     ret = check_host_key(s, host, port, host_key_check, errp);
591     if (ret < 0) {
592         goto err;
593     }
594 
595     /* Authenticate. */
596     ret = authenticate(s, user, errp);
597     if (ret < 0) {
598         goto err;
599     }
600 
601     /* Start SFTP. */
602     s->sftp = libssh2_sftp_init(s->session);
603     if (!s->sftp) {
604         session_error_setg(errp, s, "failed to initialize sftp handle");
605         ret = -EINVAL;
606         goto err;
607     }
608 
609     /* Open the remote file. */
610     DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
611             path, ssh_flags, creat_mode);
612     s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
613     if (!s->sftp_handle) {
614         session_error_setg(errp, s, "failed to open remote file '%s'", path);
615         ret = -EINVAL;
616         goto err;
617     }
618 
619     r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
620     if (r < 0) {
621         sftp_error_setg(errp, s, "failed to read file attributes");
622         return -EINVAL;
623     }
624 
625     /* Delete the options we've used; any not deleted will cause the
626      * block layer to give an error about unused options.
627      */
628     qdict_del(options, "host");
629     qdict_del(options, "port");
630     qdict_del(options, "user");
631     qdict_del(options, "path");
632     qdict_del(options, "host_key_check");
633 
634     return 0;
635 
636  err:
637     if (s->sftp_handle) {
638         libssh2_sftp_close(s->sftp_handle);
639     }
640     s->sftp_handle = NULL;
641     if (s->sftp) {
642         libssh2_sftp_shutdown(s->sftp);
643     }
644     s->sftp = NULL;
645     if (s->session) {
646         libssh2_session_disconnect(s->session,
647                                    "from qemu ssh client: "
648                                    "error opening connection");
649         libssh2_session_free(s->session);
650     }
651     s->session = NULL;
652 
653     return ret;
654 }
655 
656 static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
657                          Error **errp)
658 {
659     BDRVSSHState *s = bs->opaque;
660     int ret;
661     int ssh_flags;
662 
663     ssh_state_init(s);
664 
665     ssh_flags = LIBSSH2_FXF_READ;
666     if (bdrv_flags & BDRV_O_RDWR) {
667         ssh_flags |= LIBSSH2_FXF_WRITE;
668     }
669 
670     /* Start up SSH. */
671     ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
672     if (ret < 0) {
673         goto err;
674     }
675 
676     /* Go non-blocking. */
677     libssh2_session_set_blocking(s->session, 0);
678 
679     return 0;
680 
681  err:
682     if (s->sock >= 0) {
683         close(s->sock);
684     }
685     s->sock = -1;
686 
687     return ret;
688 }
689 
690 static QemuOptsList ssh_create_opts = {
691     .name = "ssh-create-opts",
692     .head = QTAILQ_HEAD_INITIALIZER(ssh_create_opts.head),
693     .desc = {
694         {
695             .name = BLOCK_OPT_SIZE,
696             .type = QEMU_OPT_SIZE,
697             .help = "Virtual disk size"
698         },
699         { /* end of list */ }
700     }
701 };
702 
703 static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
704 {
705     int r, ret;
706     int64_t total_size = 0;
707     QDict *uri_options = NULL;
708     BDRVSSHState s;
709     ssize_t r2;
710     char c[1] = { '\0' };
711 
712     ssh_state_init(&s);
713 
714     /* Get desired file size. */
715     total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
716                           BDRV_SECTOR_SIZE);
717     DPRINTF("total_size=%" PRIi64, total_size);
718 
719     uri_options = qdict_new();
720     r = parse_uri(filename, uri_options, errp);
721     if (r < 0) {
722         ret = r;
723         goto out;
724     }
725 
726     r = connect_to_ssh(&s, uri_options,
727                        LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
728                        LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
729                        0644, errp);
730     if (r < 0) {
731         ret = r;
732         goto out;
733     }
734 
735     if (total_size > 0) {
736         libssh2_sftp_seek64(s.sftp_handle, total_size-1);
737         r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
738         if (r2 < 0) {
739             sftp_error_setg(errp, &s, "truncate failed");
740             ret = -EINVAL;
741             goto out;
742         }
743         s.attrs.filesize = total_size;
744     }
745 
746     ret = 0;
747 
748  out:
749     ssh_state_free(&s);
750     if (uri_options != NULL) {
751         QDECREF(uri_options);
752     }
753     return ret;
754 }
755 
756 static void ssh_close(BlockDriverState *bs)
757 {
758     BDRVSSHState *s = bs->opaque;
759 
760     ssh_state_free(s);
761 }
762 
763 static int ssh_has_zero_init(BlockDriverState *bs)
764 {
765     BDRVSSHState *s = bs->opaque;
766     /* Assume false, unless we can positively prove it's true. */
767     int has_zero_init = 0;
768 
769     if (s->attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
770         if (s->attrs.permissions & LIBSSH2_SFTP_S_IFREG) {
771             has_zero_init = 1;
772         }
773     }
774 
775     return has_zero_init;
776 }
777 
778 static void restart_coroutine(void *opaque)
779 {
780     Coroutine *co = opaque;
781 
782     DPRINTF("co=%p", co);
783 
784     qemu_coroutine_enter(co, NULL);
785 }
786 
787 static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs)
788 {
789     int r;
790     IOHandler *rd_handler = NULL, *wr_handler = NULL;
791     Coroutine *co = qemu_coroutine_self();
792 
793     r = libssh2_session_block_directions(s->session);
794 
795     if (r & LIBSSH2_SESSION_BLOCK_INBOUND) {
796         rd_handler = restart_coroutine;
797     }
798     if (r & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
799         wr_handler = restart_coroutine;
800     }
801 
802     DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock,
803             rd_handler, wr_handler);
804 
805     aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
806                        rd_handler, wr_handler, co);
807 }
808 
809 static coroutine_fn void clear_fd_handler(BDRVSSHState *s,
810                                           BlockDriverState *bs)
811 {
812     DPRINTF("s->sock=%d", s->sock);
813     aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, NULL, NULL, NULL);
814 }
815 
816 /* A non-blocking call returned EAGAIN, so yield, ensuring the
817  * handlers are set up so that we'll be rescheduled when there is an
818  * interesting event on the socket.
819  */
820 static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
821 {
822     set_fd_handler(s, bs);
823     qemu_coroutine_yield();
824     clear_fd_handler(s, bs);
825 }
826 
827 /* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
828  * in the remote file.  Notice that it just updates a field in the
829  * sftp_handle structure, so there is no network traffic and it cannot
830  * fail.
831  *
832  * However, `libssh2_sftp_seek64' does have a catastrophic effect on
833  * performance since it causes the handle to throw away all in-flight
834  * reads and buffered readahead data.  Therefore this function tries
835  * to be intelligent about when to call the underlying libssh2 function.
836  */
837 #define SSH_SEEK_WRITE 0
838 #define SSH_SEEK_READ  1
839 #define SSH_SEEK_FORCE 2
840 
841 static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
842 {
843     bool op_read = (flags & SSH_SEEK_READ) != 0;
844     bool force = (flags & SSH_SEEK_FORCE) != 0;
845 
846     if (force || op_read != s->offset_op_read || offset != s->offset) {
847         DPRINTF("seeking to offset=%" PRIi64, offset);
848         libssh2_sftp_seek64(s->sftp_handle, offset);
849         s->offset = offset;
850         s->offset_op_read = op_read;
851     }
852 }
853 
854 static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
855                                  int64_t offset, size_t size,
856                                  QEMUIOVector *qiov)
857 {
858     ssize_t r;
859     size_t got;
860     char *buf, *end_of_vec;
861     struct iovec *i;
862 
863     DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
864 
865     ssh_seek(s, offset, SSH_SEEK_READ);
866 
867     /* This keeps track of the current iovec element ('i'), where we
868      * will write to next ('buf'), and the end of the current iovec
869      * ('end_of_vec').
870      */
871     i = &qiov->iov[0];
872     buf = i->iov_base;
873     end_of_vec = i->iov_base + i->iov_len;
874 
875     /* libssh2 has a hard-coded limit of 2000 bytes per request,
876      * although it will also do readahead behind our backs.  Therefore
877      * we may have to do repeated reads here until we have read 'size'
878      * bytes.
879      */
880     for (got = 0; got < size; ) {
881     again:
882         DPRINTF("sftp_read buf=%p size=%zu", buf, end_of_vec - buf);
883         r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
884         DPRINTF("sftp_read returned %zd", r);
885 
886         if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
887             co_yield(s, bs);
888             goto again;
889         }
890         if (r < 0) {
891             sftp_error_report(s, "read failed");
892             s->offset = -1;
893             return -EIO;
894         }
895         if (r == 0) {
896             /* EOF: Short read so pad the buffer with zeroes and return it. */
897             qemu_iovec_memset(qiov, got, 0, size - got);
898             return 0;
899         }
900 
901         got += r;
902         buf += r;
903         s->offset += r;
904         if (buf >= end_of_vec && got < size) {
905             i++;
906             buf = i->iov_base;
907             end_of_vec = i->iov_base + i->iov_len;
908         }
909     }
910 
911     return 0;
912 }
913 
914 static coroutine_fn int ssh_co_readv(BlockDriverState *bs,
915                                      int64_t sector_num,
916                                      int nb_sectors, QEMUIOVector *qiov)
917 {
918     BDRVSSHState *s = bs->opaque;
919     int ret;
920 
921     qemu_co_mutex_lock(&s->lock);
922     ret = ssh_read(s, bs, sector_num * BDRV_SECTOR_SIZE,
923                    nb_sectors * BDRV_SECTOR_SIZE, qiov);
924     qemu_co_mutex_unlock(&s->lock);
925 
926     return ret;
927 }
928 
929 static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
930                      int64_t offset, size_t size,
931                      QEMUIOVector *qiov)
932 {
933     ssize_t r;
934     size_t written;
935     char *buf, *end_of_vec;
936     struct iovec *i;
937 
938     DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
939 
940     ssh_seek(s, offset, SSH_SEEK_WRITE);
941 
942     /* This keeps track of the current iovec element ('i'), where we
943      * will read from next ('buf'), and the end of the current iovec
944      * ('end_of_vec').
945      */
946     i = &qiov->iov[0];
947     buf = i->iov_base;
948     end_of_vec = i->iov_base + i->iov_len;
949 
950     for (written = 0; written < size; ) {
951     again:
952         DPRINTF("sftp_write buf=%p size=%zu", buf, end_of_vec - buf);
953         r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf);
954         DPRINTF("sftp_write returned %zd", r);
955 
956         if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
957             co_yield(s, bs);
958             goto again;
959         }
960         if (r < 0) {
961             sftp_error_report(s, "write failed");
962             s->offset = -1;
963             return -EIO;
964         }
965         /* The libssh2 API is very unclear about this.  A comment in
966          * the code says "nothing was acked, and no EAGAIN was
967          * received!" which apparently means that no data got sent
968          * out, and the underlying channel didn't return any EAGAIN
969          * indication.  I think this is a bug in either libssh2 or
970          * OpenSSH (server-side).  In any case, forcing a seek (to
971          * discard libssh2 internal buffers), and then trying again
972          * works for me.
973          */
974         if (r == 0) {
975             ssh_seek(s, offset + written, SSH_SEEK_WRITE|SSH_SEEK_FORCE);
976             co_yield(s, bs);
977             goto again;
978         }
979 
980         written += r;
981         buf += r;
982         s->offset += r;
983         if (buf >= end_of_vec && written < size) {
984             i++;
985             buf = i->iov_base;
986             end_of_vec = i->iov_base + i->iov_len;
987         }
988 
989         if (offset + written > s->attrs.filesize)
990             s->attrs.filesize = offset + written;
991     }
992 
993     return 0;
994 }
995 
996 static coroutine_fn int ssh_co_writev(BlockDriverState *bs,
997                                       int64_t sector_num,
998                                       int nb_sectors, QEMUIOVector *qiov)
999 {
1000     BDRVSSHState *s = bs->opaque;
1001     int ret;
1002 
1003     qemu_co_mutex_lock(&s->lock);
1004     ret = ssh_write(s, bs, sector_num * BDRV_SECTOR_SIZE,
1005                     nb_sectors * BDRV_SECTOR_SIZE, qiov);
1006     qemu_co_mutex_unlock(&s->lock);
1007 
1008     return ret;
1009 }
1010 
1011 static void unsafe_flush_warning(BDRVSSHState *s, const char *what)
1012 {
1013     if (!s->unsafe_flush_warning) {
1014         error_report("warning: ssh server %s does not support fsync",
1015                      s->hostport);
1016         if (what) {
1017             error_report("to support fsync, you need %s", what);
1018         }
1019         s->unsafe_flush_warning = true;
1020     }
1021 }
1022 
1023 #ifdef HAS_LIBSSH2_SFTP_FSYNC
1024 
1025 static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
1026 {
1027     int r;
1028 
1029     DPRINTF("fsync");
1030  again:
1031     r = libssh2_sftp_fsync(s->sftp_handle);
1032     if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
1033         co_yield(s, bs);
1034         goto again;
1035     }
1036     if (r == LIBSSH2_ERROR_SFTP_PROTOCOL &&
1037         libssh2_sftp_last_error(s->sftp) == LIBSSH2_FX_OP_UNSUPPORTED) {
1038         unsafe_flush_warning(s, "OpenSSH >= 6.3");
1039         return 0;
1040     }
1041     if (r < 0) {
1042         sftp_error_report(s, "fsync failed");
1043         return -EIO;
1044     }
1045 
1046     return 0;
1047 }
1048 
1049 static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1050 {
1051     BDRVSSHState *s = bs->opaque;
1052     int ret;
1053 
1054     qemu_co_mutex_lock(&s->lock);
1055     ret = ssh_flush(s, bs);
1056     qemu_co_mutex_unlock(&s->lock);
1057 
1058     return ret;
1059 }
1060 
1061 #else /* !HAS_LIBSSH2_SFTP_FSYNC */
1062 
1063 static coroutine_fn int ssh_co_flush(BlockDriverState *bs)
1064 {
1065     BDRVSSHState *s = bs->opaque;
1066 
1067     unsafe_flush_warning(s, "libssh2 >= 1.4.4");
1068     return 0;
1069 }
1070 
1071 #endif /* !HAS_LIBSSH2_SFTP_FSYNC */
1072 
1073 static int64_t ssh_getlength(BlockDriverState *bs)
1074 {
1075     BDRVSSHState *s = bs->opaque;
1076     int64_t length;
1077 
1078     /* Note we cannot make a libssh2 call here. */
1079     length = (int64_t) s->attrs.filesize;
1080     DPRINTF("length=%" PRIi64, length);
1081 
1082     return length;
1083 }
1084 
1085 static BlockDriver bdrv_ssh = {
1086     .format_name                  = "ssh",
1087     .protocol_name                = "ssh",
1088     .instance_size                = sizeof(BDRVSSHState),
1089     .bdrv_parse_filename          = ssh_parse_filename,
1090     .bdrv_file_open               = ssh_file_open,
1091     .bdrv_create                  = ssh_create,
1092     .bdrv_close                   = ssh_close,
1093     .bdrv_has_zero_init           = ssh_has_zero_init,
1094     .bdrv_co_readv                = ssh_co_readv,
1095     .bdrv_co_writev               = ssh_co_writev,
1096     .bdrv_getlength               = ssh_getlength,
1097     .bdrv_co_flush_to_disk        = ssh_co_flush,
1098     .create_opts                  = &ssh_create_opts,
1099 };
1100 
1101 static void bdrv_ssh_init(void)
1102 {
1103     int r;
1104 
1105     r = libssh2_init(0);
1106     if (r != 0) {
1107         fprintf(stderr, "libssh2 initialization failed, %d\n", r);
1108         exit(EXIT_FAILURE);
1109     }
1110 
1111     bdrv_register(&bdrv_ssh);
1112 }
1113 
1114 block_init(bdrv_ssh_init);
1115