server: Allow longer NBD_OPT
[nbdkit/ericb.git] / server / protocol-handshake-newstyle.c
blob81d685cd96a269b80dc71bbae6c69858abdf7b36
1 /* nbdkit
2 * Copyright (C) 2013-2019 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <inttypes.h>
39 #include <string.h>
40 #include <unistd.h>
42 #include "internal.h"
43 #include "byte-swapping.h"
44 #include "nbd-protocol.h"
45 #include "protostrings.h"
47 /* Maximum number of client options we allow before giving up. */
48 #define MAX_NR_OPTIONS 32
50 /* Receive newstyle options. */
51 static int
52 send_newstyle_option_reply (struct connection *conn,
53 uint32_t option, uint32_t reply)
55 struct nbd_fixed_new_option_reply fixed_new_option_reply;
57 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
58 fixed_new_option_reply.option = htobe32 (option);
59 fixed_new_option_reply.reply = htobe32 (reply);
60 fixed_new_option_reply.replylen = htobe32 (0);
62 if (conn->send (conn,
63 &fixed_new_option_reply,
64 sizeof fixed_new_option_reply, 0) == -1) {
65 /* The protocol document says that the client is allowed to simply
66 * drop the connection after sending NBD_OPT_ABORT, or may read
67 * the reply.
69 if (option == NBD_OPT_ABORT)
70 debug ("write: %s: %m", name_of_nbd_opt (option));
71 else
72 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
73 return -1;
76 return 0;
79 static int
80 send_newstyle_option_reply_exportname (struct connection *conn,
81 uint32_t option, uint32_t reply)
83 struct nbd_fixed_new_option_reply fixed_new_option_reply;
84 size_t name_len = strlen (exportname);
85 uint32_t len;
87 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
88 fixed_new_option_reply.option = htobe32 (option);
89 fixed_new_option_reply.reply = htobe32 (reply);
90 fixed_new_option_reply.replylen = htobe32 (name_len + sizeof (len));
92 if (conn->send (conn,
93 &fixed_new_option_reply,
94 sizeof fixed_new_option_reply, SEND_MORE) == -1) {
95 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
96 return -1;
99 len = htobe32 (name_len);
100 if (conn->send (conn, &len, sizeof len, SEND_MORE) == -1) {
101 nbdkit_error ("write: %s: %s: %m",
102 name_of_nbd_opt (option), "sending length");
103 return -1;
105 if (conn->send (conn, exportname, name_len, 0) == -1) {
106 nbdkit_error ("write: %s: %s: %m",
107 name_of_nbd_opt (option), "sending export name");
108 return -1;
111 return 0;
114 static int
115 send_newstyle_option_reply_info_export (struct connection *conn,
116 uint32_t option, uint32_t reply,
117 uint16_t info, uint64_t exportsize)
119 struct nbd_fixed_new_option_reply fixed_new_option_reply;
120 struct nbd_fixed_new_option_reply_info_export export;
122 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
123 fixed_new_option_reply.option = htobe32 (option);
124 fixed_new_option_reply.reply = htobe32 (reply);
125 fixed_new_option_reply.replylen = htobe32 (sizeof export);
126 export.info = htobe16 (info);
127 export.exportsize = htobe64 (exportsize);
128 export.eflags = htobe16 (conn->eflags);
130 if (conn->send (conn,
131 &fixed_new_option_reply,
132 sizeof fixed_new_option_reply, SEND_MORE) == -1 ||
133 conn->send (conn, &export, sizeof export, 0) == -1) {
134 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
135 return -1;
138 return 0;
141 static int
142 send_newstyle_option_reply_meta_context (struct connection *conn,
143 uint32_t option, uint32_t reply,
144 uint32_t context_id,
145 const char *name)
147 struct nbd_fixed_new_option_reply fixed_new_option_reply;
148 struct nbd_fixed_new_option_reply_meta_context context;
149 const size_t namelen = strlen (name);
151 debug ("newstyle negotiation: %s: replying with %s id %d",
152 name_of_nbd_opt (option), name, context_id);
153 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
154 fixed_new_option_reply.option = htobe32 (option);
155 fixed_new_option_reply.reply = htobe32 (reply);
156 fixed_new_option_reply.replylen = htobe32 (sizeof context + namelen);
157 context.context_id = htobe32 (context_id);
159 if (conn->send (conn,
160 &fixed_new_option_reply,
161 sizeof fixed_new_option_reply, SEND_MORE) == -1 ||
162 conn->send (conn, &context, sizeof context, SEND_MORE) == -1 ||
163 conn->send (conn, name, namelen, 0) == -1) {
164 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
165 return -1;
168 return 0;
171 /* Sub-function during negotiate_handshake_newstyle, to uniformly handle
172 * a client hanging up on a message boundary.
174 static int __attribute__ ((format (printf, 4, 5)))
175 conn_recv_full (struct connection *conn, void *buf, size_t len,
176 const char *fmt, ...)
178 int r = conn->recv (conn, buf, len);
179 va_list args;
181 if (r == -1) {
182 va_start (args, fmt);
183 nbdkit_verror (fmt, args);
184 va_end (args);
185 return -1;
187 if (r == 0) {
188 /* During negotiation, client EOF on message boundary is less
189 * severe than failure in the middle of the buffer. */
190 debug ("client closed input socket, closing connection");
191 return -1;
193 return r;
196 /* Sub-function of negotiate_handshake_newstyle_options below. It
197 * must be called on all non-error paths out of the options for-loop
198 * in that function.
200 static int
201 finish_newstyle_options (struct connection *conn, uint64_t *exportsize)
203 if (protocol_common_open (conn, exportsize, &conn->eflags) == -1)
204 return -1;
206 debug ("newstyle negotiation: flags: export 0x%x", conn->eflags);
207 return 0;
210 /* Check that the string sent as part of @option, beginning at @buf,
211 * and with a client-reported length of @len, fits within @maxlen
212 * bytes and is well-formed. If not, report an error mentioning
213 * @name.
215 static int
216 check_string (uint32_t option, char *buf, uint32_t len, uint32_t maxlen,
217 const char *name)
219 if (len > NBD_MAX_STRING || len > maxlen) {
220 nbdkit_error ("%s: %s too long", name_of_nbd_opt (option), name);
221 return -1;
223 if (strnlen (buf, len) != len) {
224 nbdkit_error ("%s: %s may not include NUL bytes",
225 name_of_nbd_opt (option), name);
226 return -1;
228 /* TODO: Check for valid UTF-8? */
229 return 0;
232 /* Sub-function of negotiate_handshake_newstyle_options, to grab and
233 * validate an export name.
235 static int
236 check_export_name (struct connection *conn, uint32_t option, char *buf,
237 uint32_t exportnamelen, uint32_t maxlen, bool save)
239 if (check_string (option, buf, exportnamelen, maxlen, "export name") == -1)
240 return -1;
242 assert (exportnamelen < sizeof conn->exportname);
243 if (save) {
244 memcpy (conn->exportname, buf, exportnamelen);
245 conn->exportname[exportnamelen] = '\0';
247 debug ("newstyle negotiation: %s: client requested export '%.*s'",
248 name_of_nbd_opt (option), (int) exportnamelen, buf);
249 return 0;
252 static int
253 negotiate_handshake_newstyle_options (struct connection *conn)
255 struct nbd_new_option new_option;
256 size_t nr_options;
257 uint64_t version;
258 uint32_t option;
259 uint32_t optlen;
260 struct nbd_export_name_option_reply handshake_finish;
261 const char *optname;
262 uint64_t exportsize;
264 for (nr_options = 0; nr_options < MAX_NR_OPTIONS; ++nr_options) {
265 CLEANUP_FREE char *data = NULL;
267 if (conn_recv_full (conn, &new_option, sizeof new_option,
268 "reading option: conn->recv: %m") == -1)
269 return -1;
271 version = be64toh (new_option.version);
272 if (version != NBD_NEW_VERSION) {
273 nbdkit_error ("unknown option version %" PRIx64
274 ", expecting %" PRIx64,
275 version, NBD_NEW_VERSION);
276 return -1;
279 /* There is a maximum option length we will accept, regardless
280 * of the option type.
282 optlen = be32toh (new_option.optlen);
283 if (optlen > MAX_REQUEST_SIZE) {
284 nbdkit_error ("client option data too long (%" PRIu32 ")", optlen);
285 return -1;
287 data = malloc (optlen + 1); /* Allowing a trailing NUL helps some uses */
288 if (data == NULL) {
289 nbdkit_error ("malloc: %m");
290 return -1;
293 option = be32toh (new_option.option);
294 optname = name_of_nbd_opt (option);
296 /* If the client lacks fixed newstyle support, it should only send
297 * NBD_OPT_EXPORT_NAME.
299 if (!(conn->cflags & NBD_FLAG_FIXED_NEWSTYLE) &&
300 option != NBD_OPT_EXPORT_NAME) {
301 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID))
302 return -1;
303 continue;
306 /* In --tls=require / FORCEDTLS mode the only options allowed
307 * before TLS negotiation are NBD_OPT_ABORT and NBD_OPT_STARTTLS.
309 if (tls == 2 && !conn->using_tls &&
310 !(option == NBD_OPT_ABORT || option == NBD_OPT_STARTTLS)) {
311 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_TLS_REQD))
312 return -1;
313 continue;
316 switch (option) {
317 case NBD_OPT_EXPORT_NAME:
318 if (conn_recv_full (conn, data, optlen,
319 "read: %s: %m", name_of_nbd_opt (option)) == -1)
320 return -1;
321 if (check_export_name (conn, option, data, optlen, optlen, true) == -1)
322 return -1;
324 /* We have to finish the handshake by sending handshake_finish. */
325 if (finish_newstyle_options (conn, &exportsize) == -1)
326 return -1;
328 memset (&handshake_finish, 0, sizeof handshake_finish);
329 handshake_finish.exportsize = htobe64 (exportsize);
330 handshake_finish.eflags = htobe16 (conn->eflags);
332 if (conn->send (conn,
333 &handshake_finish,
334 (conn->cflags & NBD_FLAG_NO_ZEROES)
335 ? offsetof (struct nbd_export_name_option_reply, zeroes)
336 : sizeof handshake_finish, 0) == -1) {
337 nbdkit_error ("write: %s: %m", optname);
338 return -1;
340 break;
342 case NBD_OPT_ABORT:
343 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
344 return -1;
345 debug ("client sent %s to abort the connection",
346 name_of_nbd_opt (option));
347 return -1;
349 case NBD_OPT_LIST:
350 if (optlen != 0) {
351 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
352 == -1)
353 return -1;
354 if (conn_recv_full (conn, data, optlen,
355 "read: %s: %m", name_of_nbd_opt (option)) == -1)
356 return -1;
357 continue;
360 /* Send back the exportname. */
361 debug ("newstyle negotiation: %s: advertising export '%s'",
362 name_of_nbd_opt (option), exportname);
363 if (send_newstyle_option_reply_exportname (conn, option,
364 NBD_REP_SERVER) == -1)
365 return -1;
367 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
368 return -1;
369 break;
371 case NBD_OPT_STARTTLS:
372 if (optlen != 0) {
373 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
374 == -1)
375 return -1;
376 if (conn_recv_full (conn, data, optlen,
377 "read: %s: %m", name_of_nbd_opt (option)) == -1)
378 return -1;
379 continue;
382 if (tls == 0) { /* --tls=off (NOTLS mode). */
383 #ifdef HAVE_GNUTLS
384 #define NO_TLS_REPLY NBD_REP_ERR_POLICY
385 #else
386 #define NO_TLS_REPLY NBD_REP_ERR_UNSUP
387 #endif
388 if (send_newstyle_option_reply (conn, option, NO_TLS_REPLY) == -1)
389 return -1;
391 else /* --tls=on or --tls=require */ {
392 /* We can't upgrade to TLS twice on the same connection. */
393 if (conn->using_tls) {
394 if (send_newstyle_option_reply (conn, option,
395 NBD_REP_ERR_INVALID) == -1)
396 return -1;
397 continue;
400 /* We have to send the (unencrypted) reply before starting
401 * the handshake.
403 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
404 return -1;
406 /* Upgrade the connection to TLS. Also performs access control. */
407 if (crypto_negotiate_tls (conn, conn->sockin, conn->sockout) == -1)
408 return -1;
409 conn->using_tls = true;
410 debug ("using TLS on this connection");
412 break;
414 case NBD_OPT_INFO:
415 case NBD_OPT_GO:
416 if (conn_recv_full (conn, data, optlen,
417 "read: %s: %m", optname) == -1)
418 return -1;
420 if (optlen < 6) { /* 32 bit export length + 16 bit nr info */
421 debug ("newstyle negotiation: %s option length < 6", optname);
423 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
424 == -1)
425 return -1;
426 continue;
430 uint32_t exportnamelen;
431 uint16_t nrinfos;
432 uint16_t info;
433 size_t i;
435 /* Validate the name length and number of INFO requests. */
436 memcpy (&exportnamelen, &data[0], 4);
437 exportnamelen = be32toh (exportnamelen);
438 if (exportnamelen > optlen-6 /* NB optlen >= 6, see above */) {
439 debug ("newstyle negotiation: %s: export name too long", optname);
440 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
441 == -1)
442 return -1;
443 continue;
445 memcpy (&nrinfos, &data[exportnamelen+4], 2);
446 nrinfos = be16toh (nrinfos);
447 if (optlen != 4 + exportnamelen + 2 + 2*nrinfos) {
448 debug ("newstyle negotiation: %s: "
449 "number of information requests incorrect", optname);
450 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
451 == -1)
452 return -1;
453 continue;
456 /* As with NBD_OPT_EXPORT_NAME we print the export name and
457 * save it in the connection.
459 if (check_export_name (conn, option, &data[4], exportnamelen,
460 optlen - 6, true) == -1)
461 return -1;
463 /* The spec is confusing, but it is required that we send back
464 * NBD_INFO_EXPORT, even if the client did not request it!
465 * qemu client in particular does not request this, but will
466 * fail if we don't send it.
468 if (finish_newstyle_options (conn, &exportsize) == -1)
469 return -1;
471 if (send_newstyle_option_reply_info_export (conn, option,
472 NBD_REP_INFO,
473 NBD_INFO_EXPORT,
474 exportsize) == -1)
475 return -1;
477 /* For now we ignore all other info requests (but we must
478 * ignore NBD_INFO_EXPORT if it was requested, because we
479 * replied already above). Therefore this loop doesn't do
480 * much at the moment.
482 for (i = 0; i < nrinfos; ++i) {
483 memcpy (&info, &data[4 + exportnamelen + 2 + i*2], 2);
484 info = be16toh (info);
485 switch (info) {
486 case NBD_INFO_EXPORT: /* ignore - reply sent above */ break;
487 default:
488 debug ("newstyle negotiation: %s: "
489 "ignoring NBD_INFO_* request %u (%s)",
490 optname, (unsigned) info, name_of_nbd_info (info));
491 break;
496 /* Unlike NBD_OPT_EXPORT_NAME, NBD_OPT_GO sends back an ACK
497 * or ERROR packet.
499 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
500 return -1;
502 if (option == NBD_OPT_INFO) {
503 if (backend->finalize (backend, conn) == -1)
504 return -1;
505 backend_close (backend, conn);
508 break;
510 case NBD_OPT_STRUCTURED_REPLY:
511 if (optlen != 0) {
512 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
513 == -1)
514 return -1;
515 if (conn_recv_full (conn, data, optlen,
516 "read: %s: %m", name_of_nbd_opt (option)) == -1)
517 return -1;
518 continue;
521 debug ("newstyle negotiation: %s: client requested structured replies",
522 name_of_nbd_opt (option));
524 if (no_sr) {
525 /* Must fail with ERR_UNSUP for qemu 4.2 to remain happy;
526 * but failing with ERR_POLICY would have been nicer.
528 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
529 return -1;
530 debug ("newstyle negotiation: %s: structured replies are disabled",
531 name_of_nbd_opt (option));
532 break;
535 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
536 return -1;
538 conn->structured_replies = true;
539 break;
541 case NBD_OPT_LIST_META_CONTEXT:
542 case NBD_OPT_SET_META_CONTEXT:
544 uint32_t opt_index;
545 uint32_t exportnamelen;
546 uint32_t nr_queries;
547 uint32_t querylen;
548 const char *what;
550 if (conn_recv_full (conn, data, optlen, "read: %s: %m", optname) == -1)
551 return -1;
553 /* Note that we support base:allocation whether or not the plugin
554 * supports can_extents.
556 if (!conn->structured_replies) {
557 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
558 == -1)
559 return -1;
560 continue;
563 /* Minimum length of the option payload is:
564 * 32 bit export name length followed by empty export name
565 * + 32 bit number of queries followed by no queries
566 * = 8 bytes.
568 what = "optlen < 8";
569 if (optlen < 8) {
570 opt_meta_invalid_option_len:
571 debug ("newstyle negotiation: %s: invalid option length: %s",
572 optname, what);
574 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
575 == -1)
576 return -1;
577 continue;
580 /* Discard the export name, after validating it. */
581 memcpy (&exportnamelen, &data[0], 4);
582 exportnamelen = be32toh (exportnamelen);
583 what = "validating export name";
584 if (check_export_name (conn, option, &data[4], exportnamelen,
585 optlen - 8, false) == -1)
586 goto opt_meta_invalid_option_len;
587 opt_index = 4 + exportnamelen;
589 /* Read the number of queries. */
590 what = "reading number of queries";
591 if (opt_index+4 > optlen)
592 goto opt_meta_invalid_option_len;
593 memcpy (&nr_queries, &data[opt_index], 4);
594 nr_queries = be32toh (nr_queries);
595 opt_index += 4;
597 /* for LIST: nr_queries == 0 means return all meta contexts
598 * for SET: nr_queries == 0 means reset all contexts
600 debug ("newstyle negotiation: %s: %s count: %d", optname,
601 option == NBD_OPT_LIST_META_CONTEXT ? "query" : "set",
602 nr_queries);
603 if (option == NBD_OPT_SET_META_CONTEXT)
604 conn->meta_context_base_allocation = false;
605 if (nr_queries == 0) {
606 if (option == NBD_OPT_LIST_META_CONTEXT) {
607 if (send_newstyle_option_reply_meta_context
608 (conn, option, NBD_REP_META_CONTEXT,
609 0, "base:allocation") == -1)
610 return -1;
613 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
614 return -1;
616 else {
617 /* Read and answer each query. */
618 while (nr_queries > 0) {
619 what = "reading query string length";
620 if (opt_index+4 > optlen)
621 goto opt_meta_invalid_option_len;
622 memcpy (&querylen, &data[opt_index], 4);
623 querylen = be32toh (querylen);
624 opt_index += 4;
625 what = "reading query string";
626 if (check_string (option, &data[opt_index], querylen,
627 optlen - opt_index, "meta context query") == -1)
628 goto opt_meta_invalid_option_len;
630 debug ("newstyle negotiation: %s: %s %.*s",
631 optname,
632 option == NBD_OPT_LIST_META_CONTEXT ? "query" : "set",
633 (int) querylen, &data[opt_index]);
635 /* For LIST, "base:" returns all supported contexts in the
636 * base namespace. We only support "base:allocation".
638 if (option == NBD_OPT_LIST_META_CONTEXT &&
639 querylen == 5 &&
640 strncmp (&data[opt_index], "base:", 5) == 0) {
641 if (send_newstyle_option_reply_meta_context
642 (conn, option, NBD_REP_META_CONTEXT,
643 0, "base:allocation") == -1)
644 return -1;
646 /* "base:allocation" requested by name. */
647 else if (querylen == 15 &&
648 strncmp (&data[opt_index], "base:allocation", 15) == 0) {
649 if (send_newstyle_option_reply_meta_context
650 (conn, option, NBD_REP_META_CONTEXT,
651 option == NBD_OPT_SET_META_CONTEXT
652 ? base_allocation_id : 0,
653 "base:allocation") == -1)
654 return -1;
655 if (option == NBD_OPT_SET_META_CONTEXT)
656 conn->meta_context_base_allocation = true;
658 /* Every other query must be ignored. */
660 opt_index += querylen;
661 nr_queries--;
663 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
664 return -1;
666 debug ("newstyle negotiation: %s: reply complete", optname);
668 break;
670 default:
671 /* Unknown option. */
672 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
673 return -1;
674 if (conn_recv_full (conn, data, optlen,
675 "reading unknown option data: conn->recv: %m") == -1)
676 return -1;
679 /* Note, since it's not very clear from the protocol doc, that the
680 * client must send NBD_OPT_EXPORT_NAME or NBD_OPT_GO last, and
681 * that ends option negotiation.
683 if (option == NBD_OPT_EXPORT_NAME || option == NBD_OPT_GO)
684 break;
687 if (nr_options >= MAX_NR_OPTIONS) {
688 nbdkit_error ("client exceeded maximum number of options (%d)",
689 MAX_NR_OPTIONS);
690 return -1;
693 /* In --tls=require / FORCEDTLS mode, we must have upgraded to TLS
694 * by the time we finish option negotiation. If not, give up.
696 if (tls == 2 && !conn->using_tls) {
697 nbdkit_error ("non-TLS client tried to connect in --tls=require mode");
698 return -1;
701 return 0;
705 protocol_handshake_newstyle (struct connection *conn)
707 struct nbd_new_handshake handshake;
708 uint16_t gflags;
710 gflags = (NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES) & mask_handshake;
712 debug ("newstyle negotiation: flags: global 0x%x", gflags);
714 handshake.nbdmagic = htobe64 (NBD_MAGIC);
715 handshake.version = htobe64 (NBD_NEW_VERSION);
716 handshake.gflags = htobe16 (gflags);
718 if (conn->send (conn, &handshake, sizeof handshake, 0) == -1) {
719 nbdkit_error ("write: %s: %m", "sending newstyle handshake");
720 return -1;
723 /* Client now sends us its 32 bit flags word ... */
724 if (conn_recv_full (conn, &conn->cflags, sizeof conn->cflags,
725 "reading initial client flags: conn->recv: %m") == -1)
726 return -1;
727 conn->cflags = be32toh (conn->cflags);
728 /* ... which we check for accuracy. */
729 debug ("newstyle negotiation: client flags: 0x%x", conn->cflags);
730 if (conn->cflags & ~gflags) {
731 nbdkit_error ("client requested unexpected flags 0x%x", conn->cflags);
732 return -1;
735 /* Receive newstyle options. */
736 if (negotiate_handshake_newstyle_options (conn) == -1)
737 return -1;
739 return 0;