On Tue, Feb 14, 2017 at 04:41:00PM +0000, Niels Thykier wrote: > Wouter Verhelst: > > Hi Niels, > > > > On Sun, Feb 12, 2017 at 08:52:00AM +0000, Niels Thykier wrote: > >> Any news on this bug? > > > > I'm going to release (upstream) nbd 3.15.2 later this week (probably on > > thursday), which contains the fix: > > > > https://github.com/NetworkBlockDevice/nbd/compare/nbd-3.15.1...master > > > > This patch series includes: > > > > - The fix for this bug, commit a43a2d8; > > - Several minor documentation fixes (e.g., fixed the sorting of a listing > > in a > > man page); > > - A better fix for the issue of nbd-client-udeb being compiled against > > GnuTLS > > that does not break the build on kFreeBSD etc; > > - The ability to change the GnuTLS priority string, to follow TLS best > > practices and allow people to lock down the TLS configuration > > > > I would like to update nbd to that version; but if the release team > > prefers, I can cherry-pick a43a2d8 onto 3.15.1 and upload that instead. > > > > Thanks for getting back to me on this. > > On the note of the actual changes, could you please provide a (source) > debdiff, so I know what we are looking at?
Attached. Unfortunately, there's a bit of churn because I forgot to rename nbd-3.15.1.tar.gz to nbd_3.15.1.orig.tar.gz, thereby causing it to be uploaded as a native package, with a bit of stuff that shouldn't have been in there. At least it didn't contain random junk like in the past, but a .gitignore, some autotools metadata files, as well as a few files that are meant to be shipped as symlinks rather than copies of files from elsewhere in the tree (e.g., tests/run/buffer.c) do show up in the debdiff. If you ignore those, what remains is the changelog entry plus the changes that I pointed to earlier. Thanks for looking at this, -- < ron> I mean, the main *practical* problem with C++, is there's like a dozen people in the world who think they really understand all of its rules, and pretty much all of them are just lying to themselves too. -- #debian-devel, OFTC, 2016-02-12
diff -Nru nbd-3.15.1/debian/changelog nbd-3.15.2/debian/changelog --- nbd-3.15.1/debian/changelog 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/debian/changelog 2017-02-22 09:10:22.000000000 +0100 @@ -1,3 +1,12 @@ +nbd (1:3.15.2-1) unstable; urgency=medium + + * New upstream release + - Fixes data corruption with multiple threads and copyonwrite enabled; + Closes: #852288, #849504. Why did I create multiple bugs for this? + Ah well, no matter. + + -- Wouter Verhelst <wou...@debian.org> Wed, 22 Feb 2017 00:09:31 +0100 + nbd (1:3.15.1-2) unstable; urgency=medium * Build nbd-client a second time with GnuTLS disabled, and install diff -Nru nbd-3.15.1/.deps/libcliserv_la-cliserv.Plo nbd-3.15.2/.deps/libcliserv_la-cliserv.Plo --- nbd-3.15.1/.deps/libcliserv_la-cliserv.Plo 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/libcliserv_la-cliserv.Plo 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/libnbdsrv_la-nbdsrv.Plo nbd-3.15.2/.deps/libnbdsrv_la-nbdsrv.Plo --- nbd-3.15.1/.deps/libnbdsrv_la-nbdsrv.Plo 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/libnbdsrv_la-nbdsrv.Plo 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/libnbdsrv_la-treefiles.Plo nbd-3.15.2/.deps/libnbdsrv_la-treefiles.Plo --- nbd-3.15.1/.deps/libnbdsrv_la-treefiles.Plo 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/libnbdsrv_la-treefiles.Plo 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/make-integrityhuge.Po nbd-3.15.2/.deps/make-integrityhuge.Po --- nbd-3.15.1/.deps/make-integrityhuge.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/make-integrityhuge.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/nbd_client-buffer.Po nbd-3.15.2/.deps/nbd_client-buffer.Po --- nbd-3.15.1/.deps/nbd_client-buffer.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/nbd_client-buffer.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/nbd_client-crypto-gnutls.Po nbd-3.15.2/.deps/nbd_client-crypto-gnutls.Po --- nbd-3.15.1/.deps/nbd_client-crypto-gnutls.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/nbd_client-crypto-gnutls.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/nbd_client-nbd-client.Po nbd-3.15.2/.deps/nbd_client-nbd-client.Po --- nbd-3.15.1/.deps/nbd_client-nbd-client.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/nbd_client-nbd-client.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/nbd_server-nbd-server.Po nbd-3.15.2/.deps/nbd_server-nbd-server.Po --- nbd-3.15.1/.deps/nbd_server-nbd-server.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/nbd_server-nbd-server.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/.deps/nbd_trdump-nbd-trdump.Po nbd-3.15.2/.deps/nbd_trdump-nbd-trdump.Po --- nbd-3.15.1/.deps/nbd_trdump-nbd-trdump.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.deps/nbd_trdump-nbd-trdump.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/doc/proto.md nbd-3.15.2/doc/proto.md --- nbd-3.15.1/doc/proto.md 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/doc/proto.md 2017-02-14 02:13:30.000000000 +0100 @@ -307,7 +307,7 @@ by the client. `NBD_CMD_FLUSH` is modelled on the Linux kernel empty bio with -`REQ_FLUSH` set. `NBD_CMD_FLAG_FUA` is modelled on the Linux +`REQ_PREFLUSH` set. `NBD_CMD_FLAG_FUA` is modelled on the Linux kernel bio with `REQ_FUA` set. In case of ambiguity in this specification, the [kernel documentation](https://www.kernel.org/doc/Documentation/block/writeback_cache_control.txt) @@ -697,6 +697,8 @@ the export. - bit 9, `NBD_FLAG_SEND_BLOCK_STATUS`: defined by the experimental `BLOCK_STATUS` [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-blockstatus/doc/proto.md). +- bit 10, `NBD_FLAG_SEND_RESIZE`: defined by the experimental `RESIZE` + [extensio](https://github.com/NetworkBlockDevice/nbd/blob/extension-resize/doc/proto.md). Clients SHOULD ignore unknown flags. @@ -989,6 +991,11 @@ including one or more sectors beyond the size of the device. It SHOULD return `EPERM` if it receives a write zeroes request on a read-only export. +* `NBD_CMD_RESIZE` (7) + + Defined by the experimental `RESIZE` + [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-resize/doc/proto.md). + * Other requests Some third-party implementations may require additional protocol diff -Nru nbd-3.15.1/.gitignore nbd-3.15.2/.gitignore --- nbd-3.15.1/.gitignore 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,56 +0,0 @@ -.deps -.dirstamp -Makefile -autom4te.cache -autoscan.log -config.h -*~ -config.* -file -nbd-client.8 -nbd-server.1 -stamp-h.in -stamp-h1 -Doxyfile -compile -manpage.refs -manpage.links -mkinstalldirs -nbd-tester-client -nbd-client -nbd-server -doc/doxygen-output -nbd-server.config -nbd-server.5 -nbd-trdump.1 -nbdtab.5 -*.o -nbd-client.8.in -nbd-server.1.in -nbd-server.5.in -nbd-trdump.1.in -nbdtab.5.in -Makefile.in -config.h.in -aclocal.m4 -INSTALL -depcomp -install-sh -configure -man/*.sh -man/*.sh.in -man/manpage.log -make-integrityhuge -nbd-trdump -missing -libtool -*.lo -ltmain.sh -.libs/ -*.la -support/lt* -support/libtool.m4 -ar-lib -tests/run/cliserv.c -.debhelper -*debhelper.log diff -Nru nbd-3.15.1/gznbd/.deps/gznbd-gznbd.Po nbd-3.15.2/gznbd/.deps/gznbd-gznbd.Po --- nbd-3.15.1/gznbd/.deps/gznbd-gznbd.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/gznbd/.deps/gznbd-gznbd.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/gznbd/.gitignore nbd-3.15.2/gznbd/.gitignore --- nbd-3.15.1/gznbd/.gitignore 2013-12-23 20:34:24.000000000 +0100 +++ nbd-3.15.2/gznbd/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -gznbd diff -Nru nbd-3.15.1/Makefile.am nbd-3.15.2/Makefile.am --- nbd-3.15.1/Makefile.am 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/Makefile.am 2017-02-22 09:10:22.000000000 +0100 @@ -38,3 +38,4 @@ nbd_client_LDADD = $(client_libs) endif endif +endif diff -Nru nbd-3.15.1/man/manpage.links nbd-3.15.2/man/manpage.links --- nbd-3.15.1/man/manpage.links 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/man/manpage.links 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -NBDTAB.5 $sysconfdir/nbdtab.5 diff -Nru nbd-3.15.1/man/manpage.refs nbd-3.15.2/man/manpage.refs --- nbd-3.15.1/man/manpage.refs 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/man/manpage.refs 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -{ - '' => '', - '' => '' -} diff -Nru nbd-3.15.1/man/nbd-server.5.in.sgml nbd-3.15.2/man/nbd-server.5.in.sgml --- nbd-3.15.1/man/nbd-server.5.in.sgml 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/man/nbd-server.5.in.sgml 2017-02-14 02:13:30.000000000 +0100 @@ -124,6 +124,32 @@ </listitem> </varlistentry> <varlistentry> + <term><option>cacertfile</option></term> + <listitem> + <para> + Optional; string + </para> + <para>If this option is set, it should contain a path to + a PEM format X.509 CA certificate used for validating client + certificates supplied by the client. If this option is not + set then client certificates will not be checked.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>certfile</option></term> + <listitem> + <para> + Optional; string + </para> + <para>If this option is set, it should contain a path to + a PEM format X.509 public certificate used for TLS negotiation + with the client. If <option>keyfile</option> is set but + <option>certfile</option> is not set, then the server will + attempt to read the certificate from the path specified + by <option>keyfile</option>.</para> + </listitem> + </varlistentry> + <varlistentry> <term><option>force_tls</option></term> <listitem> <para> @@ -199,6 +225,17 @@ </listitem> </varlistentry> <varlistentry> + <term><option>keyfile</option></term> + <listitem> + <para> + Optional; string + </para> + <para>If this option is set, it should contain a path to + a PEM format X.509 private key used for TLS negotiation + with the client. This option must be set to enable TLS.</para> + </listitem> + </varlistentry> + <varlistentry> <term><option>listenaddr</option></term> <listitem> <para> @@ -318,43 +355,6 @@ </listitem> </varlistentry> <varlistentry> - <term><option>keyfile</option></term> - <listitem> - <para> - Optional; string - </para> - <para>If this option is set, it should contain a path to - a PEM format X.509 private key used for TLS negotiation - with the client. This option must be set to enable TLS.</para> - </listitem> - </varlistentry> - <varlistentry> - <term><option>certfile</option></term> - <listitem> - <para> - Optional; string - </para> - <para>If this option is set, it should contain a path to - a PEM format X.509 public certificate used for TLS negotiation - with the client. If <option>keyfile</option> is set but - <option>certfile</option> is not set, then the server will - attempt to read the certificate from the path specified - by <option>keyfile</option>.</para> - </listitem> - </varlistentry> - <varlistentry> - <term><option>cacertfile</option></term> - <listitem> - <para> - Optional; string - </para> - <para>If this option is set, it should contain a path to - a PEM format X.509 CA certificate used for validating client - certificates supplied by the client. If this option is not - set then client certificates will not be checked.</para> - </listitem> - </varlistentry> - <varlistentry> <term><option>tlsonly</option></term> <listitem> <para>Optional; boolean.</para> @@ -368,6 +368,28 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term><option>tlsprio</option></term> + <listitem> + <para>Optional; string; default NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE</para> + <para>This option allows to configure the GnuTLS priority + string, which is used to select the algorithms which GnuTLS + will allow to be negotiated with the client. The NBD + STARTTLS specification requires that clients and servers + require TLS1.2 or higher by default, so the default string + disables all older versions of the TLS protocol.</para> + <para>Not all versions of GnuTLS support the + %SERVER_PRECEDENCE flag, which exists to signal that the + server should pay no attention to the algorithm preferences + selected by the client. If you're using an older version of + GnuTLS (e.g., 2.12), it may be necessary to specify a + priority string that does not include the %SERVER_PRECEDENCE + flag.</para> + <para>For an explanation of the possible values of this + option, see the "Priority strings" chapter in the GnuTLS + documentation.</para> + </listitem> + </varlistentry> </variablelist> </refsect1> <refsect1> diff -Nru nbd-3.15.1/man/nbd-server.5.sh.in nbd-3.15.2/man/nbd-server.5.sh.in --- nbd-3.15.1/man/nbd-server.5.sh.in 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/man/nbd-server.5.sh.in 2017-02-14 02:15:06.000000000 +0100 @@ -67,6 +67,24 @@ \fBnbd-client -l\fR to get a list of exports on this server. .TP +\fBcacertfile\fR +Optional; string + +If this option is set, it should contain a path to +a PEM format X.509 CA certificate used for validating client +certificates supplied by the client. If this option is not +set then client certificates will not be checked. +.TP +\fBcertfile\fR +Optional; string + +If this option is set, it should contain a path to +a PEM format X.509 public certificate used for TLS negotiation +with the client. If \fBkeyfile\fR is set but +\fBcertfile\fR is not set, then the server will +attempt to read the certificate from the path specified +by \fBkeyfile\fR\&. +.TP \fBforce_tls\fR Optional; boolean. @@ -120,6 +138,13 @@ whatsoever have been configured, in which case it will exit with an appropriate error message) .TP +\fBkeyfile\fR +Optional; string + +If this option is set, it should contain a path to +a PEM format X.509 private key used for TLS negotiation +with the client. This option must be set to enable TLS. +.TP \fBlistenaddr\fR Optional; string @@ -201,31 +226,6 @@ with the specified name. Only newstyle negotiation is supported on UNIX domain sockets. .TP -\fBkeyfile\fR -Optional; string - -If this option is set, it should contain a path to -a PEM format X.509 private key used for TLS negotiation -with the client. This option must be set to enable TLS. -.TP -\fBcertfile\fR -Optional; string - -If this option is set, it should contain a path to -a PEM format X.509 public certificate used for TLS negotiation -with the client. If \fBkeyfile\fR is set but -\fBcertfile\fR is not set, then the server will -attempt to read the certificate from the path specified -by \fBkeyfile\fR\&. -.TP -\fBcacertfile\fR -Optional; string - -If this option is set, it should contain a path to -a PEM format X.509 CA certificate used for validating client -certificates supplied by the client. If this option is not -set then client certificates will not be checked. -.TP \fBtlsonly\fR Optional; boolean. @@ -236,6 +236,28 @@ in the section corresponding to the specific export. In order for TLS to work at all, the \fBkeyfile\fR option must be specified in the generic section. +.TP +\fBtlsprio\fR +Optional; string; default NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE + +This option allows to configure the GnuTLS priority +string, which is used to select the algorithms which GnuTLS +will allow to be negotiated with the client. The NBD +STARTTLS specification requires that clients and servers +require TLS1.2 or higher by default, so the default string +disables all older versions of the TLS protocol. + +Not all versions of GnuTLS support the +%SERVER_PRECEDENCE flag, which exists to signal that the +server should pay no attention to the algorithm preferences +selected by the client. If you're using an older version of +GnuTLS (e.g., 2.12), it may be necessary to specify a +priority string that does not include the %SERVER_PRECEDENCE +flag. + +For an explanation of the possible values of this +option, see the "Priority strings" chapter in the GnuTLS +documentation. .SH "OPTIONS FOR EXPORT SECTIONS" .TP \fBauthfile\fR diff -Nru nbd-3.15.1/nbd-server.c nbd-3.15.2/nbd-server.c --- nbd-3.15.1/nbd-server.c 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/nbd-server.c 2017-02-14 02:13:30.000000000 +0100 @@ -262,6 +262,7 @@ gchar *certfile; /**< certificate file */ gchar *keyfile; /**< key file */ gchar *cacertfile; /**< CA certificate file */ + gchar *tlsprio; /**< TLS priority string */ gint flags; /**< global flags */ gint threads; /**< maximum number of parallel threads we want to run */ }; @@ -778,6 +779,7 @@ { "certfile", FALSE, PARAM_STRING, &(genconftmp.certfile), 0 }, { "keyfile", FALSE, PARAM_STRING, &(genconftmp.keyfile), 0 }, { "cacertfile", FALSE, PARAM_STRING, &(genconftmp.cacertfile), 0 }, + { "tlsprio", FALSE, PARAM_STRING, &(genconftmp.tlsprio), 0 }, }; PARAM* p=gp; int p_size=sizeof(gp)/sizeof(PARAM); @@ -796,6 +798,8 @@ memset(&genconftmp, 0, sizeof(struct generic_conf)); + genconftmp.tlsprio = "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE"; + if (genconf) { /* Use the passed configuration values as defaults. The * parsing algorithm below updates all parameter targets @@ -1626,7 +1630,7 @@ gnutls_certificate_set_verify_function(x509_cred, verify_cert); check_rv(gnutls_certificate_set_x509_trust_file(x509_cred, genconf->cacertfile, GNUTLS_X509_FMT_PEM)); check_rv(gnutls_certificate_set_x509_key_file(x509_cred, genconf->certfile, genconf->keyfile, GNUTLS_X509_FMT_PEM)); - check_rv(gnutls_priority_init(&priority_cache, "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE", NULL)); + check_rv(gnutls_priority_init(&priority_cache, genconf->tlsprio, NULL)); check_rv(gnutls_init(session, GNUTLS_SERVER)); check_rv(gnutls_priority_set(*session, priority_cache)); check_rv(gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, x509_cred)); @@ -3238,6 +3242,7 @@ dousers(genconf.user, genconf.group); #if HAVE_GNUTLS + gnutls_global_init(); static gnutls_dh_params_t dh_params; gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, diff -Nru nbd-3.15.1/systemd/.gitignore nbd-3.15.2/systemd/.gitignore --- nbd-3.15.1/systemd/.gitignore 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/systemd/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,3 +0,0 @@ -nbd@.service -n...@.service.sh -n...@.service.sh.in diff -Nru nbd-3.15.1/tests/code/.deps/clientacl.Po nbd-3.15.2/tests/code/.deps/clientacl.Po --- nbd-3.15.1/tests/code/.deps/clientacl.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/code/.deps/clientacl.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/code/.deps/dup.Po nbd-3.15.2/tests/code/.deps/dup.Po --- nbd-3.15.1/tests/code/.deps/dup.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/code/.deps/dup.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/code/.deps/mask.Po nbd-3.15.2/tests/code/.deps/mask.Po --- nbd-3.15.1/tests/code/.deps/mask.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/code/.deps/mask.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/code/.deps/punchdummy.Po nbd-3.15.2/tests/code/.deps/punchdummy.Po --- nbd-3.15.1/tests/code/.deps/punchdummy.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/code/.deps/punchdummy.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/code/.deps/size.Po nbd-3.15.2/tests/code/.deps/size.Po --- nbd-3.15.1/tests/code/.deps/size.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/code/.deps/size.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/code/.deps/trim.Po nbd-3.15.2/tests/code/.deps/trim.Po --- nbd-3.15.1/tests/code/.deps/trim.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/code/.deps/trim.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/code/.gitignore nbd-3.15.2/tests/code/.gitignore --- nbd-3.15.1/tests/code/.gitignore 2016-11-21 22:43:24.000000000 +0100 +++ nbd-3.15.2/tests/code/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,5 +0,0 @@ -clientacl -dup -mask -size -trim diff -Nru nbd-3.15.1/tests/run/buffer.c nbd-3.15.2/tests/run/buffer.c --- nbd-3.15.1/tests/run/buffer.c 1970-01-01 01:00:00.000000000 +0100 +++ nbd-3.15.2/tests/run/buffer.c 2017-01-14 15:47:43.000000000 +0100 @@ -0,0 +1,225 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2016 Wrymouth Innovation Ltd + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include <sys/types.h> + +#include "buffer.h" + +typedef struct buffer +{ + char *buf; + ssize_t size; + ssize_t hwm; + ssize_t ridx; + ssize_t widx; + int empty; +} buffer_t; + +/* the buffer is organised internally as follows: + * + * * There are b->size bytes in the buffer. + * + * * Bytes are at offsets 0 to b->size-1 + * + * * b->ridx points to the first readable byte + * + * * b->widx points to the first empty space + * + * * b->ridx < b->widx indicates a non-wrapped buffer: + * + * 0 ridx widx size + * | | | | + * V V V V + * ........XXXXXXXXX................ + * + * * b->ridx > b->widx indicates a wrapped buffer: + * + * 0 widx ridx size + * | | | | + * V V V V + * XXXXXXXX.........XXXXXXXXXXXXXXXX + * + * * b->ridx == b->widx indicates a FULL buffer: + * + * * b->ridx == b->widx indicates a wrapped buffer: + * + * 0 widx == ridx size + * | | | + * V V V + * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + * + * An empty buffer is indicated by empty=1 + * + */ + +buffer_t * +bufNew (ssize_t size, ssize_t hwm) +{ + buffer_t *b = calloc (1, sizeof (buffer_t)); + b->buf = calloc (1, size); + b->size = size; + b->hwm = hwm; + b->empty = 1; + return b; +} + + +void +bufFree (buffer_t * b) +{ + free (b->buf); + free (b); +} + +/* get a maximal span to read. Returns 0 if buffer + * is empty + */ +ssize_t +bufGetReadSpan (buffer_t * b, void **addr) +{ + if (b->empty) + { + *addr = NULL; + return 0; + } + *addr = &(b->buf[b->ridx]); + ssize_t len = b->widx - b->ridx; + if (len <= 0) + len = b->size - b->ridx; + return len; +} + +/* get a maximal span to write. Returns 0 id buffer is full + */ +ssize_t +bufGetWriteSpan (buffer_t * b, void **addr) +{ + if (b->empty) + { + *addr = b->buf; + b->ridx = 0; + b->widx = 0; + return b->size; + } + if (b->ridx == b->widx) + { + *addr = NULL; + return 0; + } + *addr = &(b->buf[b->widx]); + ssize_t len = b->ridx - b->widx; + if (len <= 0) + len = b->size - b->widx; + return len; +} + +/* mark size bytes as read */ +void +bufDoneRead (buffer_t * b, ssize_t size) +{ + while (!b->empty && (size > 0)) + { + /* empty can't occur here, so equal pointers means full */ + ssize_t len = b->widx - b->ridx; + if (len <= 0) + len = b->size - b->ridx; + + /* len is the number of bytes in one read span */ + if (len > size) + len = size; + + b->ridx += len; + if (b->ridx >= b->size) + b->ridx = 0; + + if (b->ridx == b->widx) + { + b->ridx = 0; + b->widx = 0; + b->empty = 1; + } + + size -= len; + } +} + +/* mark size bytes as written */ +void +bufDoneWrite (buffer_t * b, ssize_t size) +{ + while ((b->empty || (b->ridx != b->widx)) && (size > 0)) + { + /* full can't occur here, so equal pointers means empty */ + ssize_t len = b->ridx - b->widx; + if (len <= 0) + len = b->size - b->widx; + + /* len is the number of bytes in one write span */ + if (len > size) + len = size; + + b->widx += len; + if (b->widx >= b->size) + b->widx = 0; + + /* it can't be empty as we've written at least one byte */ + b->empty = 0; + + size -= len; + } +} + +int +bufIsEmpty (buffer_t * b) +{ + return b->empty; +} + +int +bufIsFull (buffer_t * b) +{ + return !b->empty && (b->ridx == b->widx); +} + +int +bufIsOverHWM (buffer_t * b) +{ + return bufGetCount (b) > b->hwm; +} + +ssize_t +bufGetFree (buffer_t * b) +{ + return b->size - bufGetCount (b); +} + +ssize_t +bufGetCount (buffer_t * b) +{ + if (b->empty) + return 0; + return b->widx - b->ridx + ((b->ridx < b->widx) ? 0 : b->size); +} diff -Nru nbd-3.15.1/tests/run/cliserv.c nbd-3.15.2/tests/run/cliserv.c --- nbd-3.15.1/tests/run/cliserv.c 1970-01-01 01:00:00.000000000 +0100 +++ nbd-3.15.2/tests/run/cliserv.c 2017-01-14 15:47:43.000000000 +0100 @@ -0,0 +1,128 @@ +#include <config.h> +#include <fcntl.h> +#include <stdio.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <cliserv.h> +#include <nbd-debug.h> + +const u64 cliserv_magic = 0x00420281861253LL; +const u64 opts_magic = 0x49484156454F5054LL; +const u64 rep_magic = 0x3e889045565a9LL; + +/** + * Set a socket to blocking or non-blocking + * + * @param fd The socket's FD + * @param nb non-zero to set to non-blocking, else 0 to set to blocking + * @return 0 - OK, -1 failed + */ +int set_nonblocking(int fd, int nb) { + int sf = fcntl (fd, F_GETFL, 0); + if (sf == -1) + return -1; + return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK)); +} + + +void setmysockopt(int sock) { + int size = 1; +#if 0 + if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) + INFO("(no sockopt/1: %m)"); +#endif +#ifdef IPPROTO_TCP + size = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &size, sizeof(int)) < 0) + INFO("(no sockopt/2: %m)"); +#endif +#if 0 + size = 1024; + if (setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0) + INFO("(no sockopt/3: %m)"); +#endif +} + +void err_nonfatal(const char *s) { + char s1[150], *s2; + + strncpy(s1, s, sizeof(s1)); + if ((s2 = strstr(s, "%m"))) { + strcpy(s1 + (s2 - s), strerror(errno)); + s2 += 2; + strcpy(s1 + strlen(s1), s2); + } +#ifndef sun + /* Solaris doesn't have %h in syslog */ + else if ((s2 = strstr(s, "%h"))) { + strcpy(s1 + (s2 - s), hstrerror(h_errno)); + s2 += 2; + strcpy(s1 + strlen(s1), s2); + } +#endif + + s1[sizeof(s1)-1] = '\0'; +#ifdef ISSERVER + syslog(LOG_ERR, "%s", s1); + syslog(LOG_ERR, "Exiting."); +#endif + fprintf(stderr, "Error: %s\n", s1); +} + +void err(const char *s) { + err_nonfatal(s); + fprintf(stderr, "Exiting.\n"); + exit(EXIT_FAILURE); +} + +void logging(const char* name) { +#ifdef ISSERVER + openlog(name, LOG_PID, LOG_DAEMON); +#endif + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +} + +#ifndef ntohll +#ifdef WORDS_BIGENDIAN +uint64_t ntohll(uint64_t a) { + return a; +} +#else +uint64_t ntohll(uint64_t a) { + u32 lo = a & 0xffffffff; + u32 hi = a >> 32U; + lo = ntohl(lo); + hi = ntohl(hi); + return ((uint64_t) lo) << 32U | hi; +} +#endif +#endif + +/** + * Read data from a file descriptor into a buffer + * + * @param f a file descriptor + * @param buf a buffer + * @param len the number of bytes to be read + **/ +void readit(int f, void *buf, size_t len) { + ssize_t res; + while (len > 0) { + DEBUG("*"); + res = read(f, buf, len); + if (res > 0) { + len -= res; + buf += res; + } else if (res < 0) { + if(errno != EAGAIN) { + err("Read failed: %m"); + } + } else { + err("Read failed: End of file"); + } + } +} diff -Nru nbd-3.15.1/tests/run/crypto-gnutls.c nbd-3.15.2/tests/run/crypto-gnutls.c --- nbd-3.15.1/tests/run/crypto-gnutls.c 1970-01-01 01:00:00.000000000 +0100 +++ nbd-3.15.2/tests/run/crypto-gnutls.c 2017-01-14 15:47:43.000000000 +0100 @@ -0,0 +1,627 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2016 Wrymouth Innovation Ltd + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#define _GNU_SOURCE +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "crypto-gnutls.h" +#include "buffer.h" + +#define MAX_CERTS 10 + +#define FALSE 0 +#define TRUE 1 + +#define PRIORITY "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2" + +typedef struct tlssession +{ + gnutls_certificate_credentials_t creds; + gnutls_session_t session; + char *hostname; + int (*quitfn) (void *opaque); + int (*erroutfn) (void *opaque, const char *format, va_list ap); + int debug; + void *opaque; +} tlssession_t; + +#define BUF_SIZE 65536 +#define BUF_HWM ((BUF_SIZE*3)/4) + +static int +falsequit (void *opaque) +{ + return FALSE; +} + +static int +quit (tlssession_t * s) +{ + return s->quitfn (s->opaque); +} + + +static int +stderrout (void *opaque, const char *format, va_list ap) +{ + return vfprintf (stderr, format, ap); +} + +static int +errout (tlssession_t * s, const char *format, ...) +{ + va_list ap; + int ret; + va_start (ap, format); + ret = s->erroutfn (s->opaque, format, ap); + va_end (ap); + return ret; +} + +static int +debugout (tlssession_t * s, const char *format, ...) +{ + va_list ap; + int ret = 0; + va_start (ap, format); + if (s->debug) + ret = s->erroutfn (s->opaque, format, ap); + va_end (ap); + return ret; +} + +static int +socksetnonblock (int fd, int nb) +{ + int sf = fcntl (fd, F_GETFL, 0); + if (sf == -1) + return -1; + return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK)); +} + +/* From (public domain) example file in GNUTLS + * + * This function will try to verify the peer's certificate, and + * also check if the hostname matches, and the activation, expiration dates. + */ +static int +verify_certificate_callback (gnutls_session_t session) +{ + unsigned int status; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size; + int ret; + gnutls_x509_crt_t cert; + tlssession_t *s; + + /* read session pointer */ + s = (tlssession_t *) gnutls_session_get_ptr (session); + + /* This verification function uses the trusted CAs in the credentials + * structure. So you must have installed one or more CA certificates. + */ + ret = gnutls_certificate_verify_peers2 (session, &status); + if (ret < 0) + { + debugout (s, "Could not verfify peer certificate due to an error\n"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + if (status & GNUTLS_CERT_INVALID) + debugout (s, "The certificate is not trusted.\n"); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + debugout (s, "The certificate hasn't got a known issuer.\n"); + + if (status & GNUTLS_CERT_REVOKED) + debugout (s, "The certificate has been revoked.\n"); + + if (status & GNUTLS_CERT_EXPIRED) + debugout (s, "The certificate has expired\n"); + + if (status & GNUTLS_CERT_NOT_ACTIVATED) + debugout (s, "The certificate is not yet activated\n"); + + if (status) + return GNUTLS_E_CERTIFICATE_ERROR; + + if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) + return GNUTLS_E_CERTIFICATE_ERROR; + + if (gnutls_x509_crt_init (&cert) < 0) + { + debugout (s, "error in initialization\n"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + cert_list = gnutls_certificate_get_peers (session, &cert_list_size); + if (cert_list == NULL) + { + debugout (s, "No certificate was found!\n"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + /* check only the first certificate - seems to be what curl does */ + if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) + { + debugout (s, "error parsing certificate\n"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + if (s->hostname && *s->hostname) + { + if (!gnutls_x509_crt_check_hostname (cert, s->hostname)) + { + debugout (s, + "The certificate's owner does not match hostname '%s'\n", + s->hostname); + return GNUTLS_E_CERTIFICATE_ERROR; + } + } + + gnutls_x509_crt_deinit (cert); + + debugout (s, "Peer passed certificate verification\n"); + + /* notify gnutls to continue handshake normally */ + return 0; +} + +tlssession_t * +tlssession_new (int isserver, + char *keyfile, char *certfile, char *cacertfile, + char *hostname, int insecure, int debug, + int (*quitfn) (void *opaque), + int (*erroutfn) (void *opaque, const char *format, + va_list ap), void *opaque) +{ + int ret; + tlssession_t *s = calloc (1, sizeof (tlssession_t)); + + if (quitfn) + s->quitfn = quitfn; + else + s->quitfn = falsequit; + + if (erroutfn) + s->erroutfn = erroutfn; + else + s->erroutfn = stderrout; + + if (hostname) + s->hostname = strdup (hostname); + + s->debug = debug; + + if (gnutls_certificate_allocate_credentials (&s->creds) < 0) + { + errout (s, "Certificate allocation memory error\n"); + goto error; + } + + if (cacertfile != NULL) + { + ret = + gnutls_certificate_set_x509_trust_file (s->creds, cacertfile, + GNUTLS_X509_FMT_PEM); + if (ret < 0) + { + errout (s, "Error setting the x509 trust file: %s\n", + gnutls_strerror (ret)); + goto error; + } + + if (!insecure) + { + gnutls_certificate_set_verify_function (s->creds, + verify_certificate_callback); + gnutls_certificate_set_verify_flags (s->creds, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); + } + } + + if (keyfile && !certfile) + certfile = keyfile; + + if (certfile != NULL && keyfile != NULL) + { + ret = + gnutls_certificate_set_x509_key_file (s->creds, certfile, keyfile, + GNUTLS_X509_FMT_PEM); + + if (ret < 0) + { + errout (s, + "Error loading certificate or key file (%s, %s): %s\n", + certfile, keyfile, gnutls_strerror (ret)); + goto error; + } + } + + if (isserver) + { + ret = gnutls_init (&s->session, GNUTLS_SERVER); + } + else + { + ret = gnutls_init (&s->session, GNUTLS_CLIENT); + } + if (ret < 0) + { + errout (s, "Cannot initialize GNUTLS session: %s\n", + gnutls_strerror (ret)); + goto error; + } + + gnutls_session_set_ptr (s->session, (void *) s); + + ret = gnutls_set_default_priority (s->session); + if (ret < 0) + { + errout (s, "Cannot set default GNUTLS session priority: %s\n", + gnutls_strerror (ret)); + goto error; + } + + const char *errpos = NULL; + ret = gnutls_priority_set_direct (s->session, PRIORITY, &errpos); + if (ret < 0) + { + errout (s, "Cannot set GNUTLS session priority: %s\n", + gnutls_strerror (ret)); + goto error; + } + + gnutls_session_set_ptr (s->session, (void *) s); + + ret = gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, s->creds); + if (ret < 0) + { + errout (s, "Cannot set session GNUTL credentials: %s\n", + gnutls_strerror (ret)); + goto error; + } + + if (isserver) + { + /* requests but does not check a client certificate */ + gnutls_certificate_server_set_request (s->session, GNUTLS_CERT_REQUEST); + } + + + return s; + +error: + if (s->session) + gnutls_deinit (s->session); + free (s); + return NULL; +} + +void +tlssession_close (tlssession_t * s) +{ + if (s->session) + gnutls_deinit (s->session); + free (s->hostname); + free (s); +} + +int +tlssession_init () +{ + return gnutls_global_init (); +} + + +int +tlssession_mainloop (int cryptfd, int plainfd, tlssession_t * s) +{ + fd_set readfds; + fd_set writefds; + int maxfd; + int tls_wr_interrupted = 0; + int plainEOF = FALSE; + int cryptEOF = FALSE; + int ret; + + buffer_t *plainToCrypt = bufNew (BUF_SIZE, BUF_HWM); + buffer_t *cryptToPlain = bufNew (BUF_SIZE, BUF_HWM); + + if (socksetnonblock (cryptfd, 0) < 0) + { + errout (s, "Could not turn on blocking: %m"); + goto error; + } + + /* set it up to work with our FD */ + gnutls_transport_set_ptr (s->session, + (gnutls_transport_ptr_t) (intptr_t) cryptfd); + + + /* Now do the handshake */ + ret = gnutls_handshake (s->session); + if (ret < 0) + { + errout (s, "TLS handshake failed: %s\n", gnutls_strerror (ret)); + goto error; + } + + if (socksetnonblock (cryptfd, 1) < 0) + { + errout (s, "Could not turn on non-blocking on crypt FD: %m"); + goto error; + } + + if (socksetnonblock (plainfd, 1) < 0) + { + errout (s, "Could not turn on non-blocking on plain FD: %m"); + goto error; + } + + maxfd = (plainfd > cryptfd) ? plainfd + 1 : cryptfd + 1; + + while ((!plainEOF || !cryptEOF) && !quit (s)) + { + struct timeval timeout; + int result; + int selecterrno; + int wait = TRUE; + + FD_ZERO (&readfds); + FD_ZERO (&writefds); + + size_t buffered = gnutls_record_check_pending (s->session); + if (buffered) + wait = FALSE; /* do not wait for select to return if we have buffered data */ + + if (plainEOF) + { + /* plain text end has closed, but me may still have + * data yet to write to the crypt end */ + if (bufIsEmpty (plainToCrypt) && !tls_wr_interrupted) + { + cryptEOF = TRUE; + break; + } + } + else + { + if (!bufIsEmpty (cryptToPlain)) + FD_SET (plainfd, &writefds); + if (!bufIsOverHWM (plainToCrypt)) + FD_SET (plainfd, &readfds); + } + + if (cryptEOF) + { + /* crypt end has closed, but me way still have data to + * write from the crypt buffer */ + if (bufIsEmpty (cryptToPlain) && !buffered) + { + plainEOF = TRUE; + break; + } + } + else + { + if (!bufIsEmpty (plainToCrypt) || tls_wr_interrupted) + FD_SET (cryptfd, &writefds); + if (!bufIsOverHWM (cryptToPlain)) + FD_SET (cryptfd, &readfds); + } + + /* Repeat select whilst EINTR happens */ + do + { + timeout.tv_sec = wait ? 1 : 0; + timeout.tv_usec = 0; + result = select (maxfd, &readfds, &writefds, NULL, &timeout); + + selecterrno = errno; + } + while ((result == -1) && (selecterrno == EINTR) && !quit (s)); + if (quit (s)) + break; + + if (FD_ISSET (plainfd, &readfds)) + { + /* we can read at least one byte */ + void *addr = NULL; + /* get a span of characters to write to the + * buffer. As the empty portion may wrap the end of the + * circular buffer this might not be all we could read. + */ + ssize_t len = bufGetWriteSpan (plainToCrypt, &addr); + if (len > 0) + { + ssize_t ret; + do + { + ret = read (plainfd, addr, (size_t) len); + } + while ((ret < 0) && (errno == EINTR) && !quit (s)); + if (quit (s)) + break; + if (ret < 0) + { + errout (s, "Error on read from plain socket: %m\n"); + goto error; + } + if (ret == 0) + { + plainEOF = TRUE; + } + else + { + bufDoneWrite (plainToCrypt, ret); /* mark ret bytes as written to the buffer */ + } + } + } + + if (FD_ISSET (plainfd, &writefds)) + { + /* we can write at least one byte */ + void *addr = NULL; + /* get a span of characters to read from the buffer + * as the full portion may wrap the end of the circular buffer + * this might not be all we have to write. + */ + ssize_t len = bufGetReadSpan (cryptToPlain, &addr); + if (len > 0) + { + ssize_t ret; + do + { + ret = write (plainfd, addr, (size_t) len); + } + while ((ret < 0) && (errno == EINTR) && !quit (s)); + if (quit (s)) + break; + if (ret < 0) + { + errout (s, "Error on write to plain socket: %m\n"); + goto error; + } + bufDoneRead (cryptToPlain, ret); /* mark ret bytes as read from the buffer */ + } + } + + if (FD_ISSET (cryptfd, &readfds) || buffered) + { + /* we can read at least one byte */ + void *addr = NULL; + /* get a span of characters to write to the + * buffer. As the empty portion may wrap the end of the + * circular buffer this might not be all we could read. + */ + ssize_t len = bufGetWriteSpan (cryptToPlain, &addr); + if (len > 0) + { + ssize_t ret; + do + { + ret = gnutls_record_recv (s->session, addr, (size_t) len); + } + while (ret == GNUTLS_E_INTERRUPTED && !quit (s)); + /* do not loop on GNUTLS_E_AGAIN - this means we'd block so we'd loop for + * ever + */ + if (quit (s)) + break; + if (ret < 0 && ret != GNUTLS_E_AGAIN) + { + errout (s, "Error on read from crypt socket: %s\n", + gnutls_strerror (ret)); + goto error; + } + if (ret == 0) + { + cryptEOF = TRUE; + } + else + { + bufDoneWrite (cryptToPlain, ret); /* mark ret bytes as written to the buffer */ + } + } + } + + if (FD_ISSET (cryptfd, &writefds)) + { + /* we can write at least one byte */ + void *addr = NULL; + /* get a span of characters to read from the buffer + * as the full portion may wrap the end of the circular buffer + * this might not be all we have to write. + */ + ssize_t len = bufGetReadSpan (plainToCrypt, &addr); + if (len > 0) + { + ssize_t ret; + do + { + if (tls_wr_interrupted) + { + ret = gnutls_record_send (s->session, NULL, 0); + } + else + { + ret = gnutls_record_send (s->session, addr, len); + } + } + while (ret == GNUTLS_E_INTERRUPTED && !quit (s)); + if (quit (s)) + break; + if (ret == GNUTLS_E_AGAIN) + { + /* we need to call this again with NULL parameters + * as it blocked + */ + tls_wr_interrupted = TRUE; + } + else if (ret < 0) + { + errout (s, "Error on write to crypto socket: %s\n", + gnutls_strerror (ret)); + goto error; + } + else + { + bufDoneRead (plainToCrypt, ret); /* mark ret bytes as read from the buffer */ + } + } + } + } + + ret = 0; + goto freereturn; + +error: + ret = -1; + +freereturn: + gnutls_bye (s->session, GNUTLS_SHUT_RDWR); + shutdown (plainfd, SHUT_RDWR); + bufFree (plainToCrypt); + bufFree (cryptToPlain); + return ret; +} diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-buffer.Po nbd-3.15.2/tests/run/.deps/nbd_tester_client-buffer.Po --- nbd-3.15.1/tests/run/.deps/nbd_tester_client-buffer.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-buffer.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-cliserv.Po nbd-3.15.2/tests/run/.deps/nbd_tester_client-cliserv.Po --- nbd-3.15.1/tests/run/.deps/nbd_tester_client-cliserv.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-cliserv.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po nbd-3.15.2/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po --- nbd-3.15.1/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po nbd-3.15.2/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po --- nbd-3.15.1/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po 2016-12-20 20:36:11.000000000 +0100 +++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -# dummy