Add an extra parameter to nbd_connect_uri to control what URIs are permitted, in case the caller wants to pass in user-controlled URIs but have some control over who/what/how the connection happens. For example: nbd_connect_uri (nbd, "nbd://localhost", LIBNBD_CONNECT_URI_REQUIRE_TLS) => error: URI must specify an encrypted connection: Permission denied This obviously breaks the existing C API. --- TODO | 1 - docs/libnbd.pod | 2 +- examples/batched-read-write.c | 2 +- examples/strict-structured-reads.c | 2 +- examples/threaded-reads-and-writes.c | 5 +-- generator/generator | 50 +++++++++++++++++++++++++--- lib/connect.c | 33 ++++++++++++++++-- tests/aio-parallel-load.c | 3 +- tests/connect-uri-tcp.c | 2 +- tests/connect-uri-unix.c | 3 +- 10 files changed, 87 insertions(+), 16 deletions(-) diff --git a/TODO b/TODO index 8e067c0..1dd64d7 100644 --- a/TODO +++ b/TODO @@ -31,7 +31,6 @@ Suggested API improvements: connecting: - nbd_connect_tcp: allow control over whether IPv4 or IPv6 is desired - - nbd_connect_uri: allow control over which features are enabled - nbd_connect_command: allow passing char **env TLS: diff --git a/docs/libnbd.pod b/docs/libnbd.pod index 01964de..7018621 100644 --- a/docs/libnbd.pod +++ b/docs/libnbd.pod @@ -364,7 +364,7 @@ when it is available. To connect to a URI via the high level API, use: - nbd_connect_uri (nbd, "nbd://example.com/"); + nbd_connect_uri (nbd, "nbd://example.com/", LIBNBD_CONNECT_URI_ALL); This feature is implemented by calling other libnbd APIs to set up the export name, TLS parameters, and finally connect over a Unix domain diff --git a/examples/batched-read-write.c b/examples/batched-read-write.c index d39a1e5..1b876da 100644 --- a/examples/batched-read-write.c +++ b/examples/batched-read-write.c @@ -143,7 +143,7 @@ main (int argc, char *argv[]) /* Connect synchronously as this is simpler. */ if (argc == 2) { if (strstr (argv[1], "://")) { - if (nbd_connect_uri (nbd, argv[1]) == -1) { + if (nbd_connect_uri (nbd, argv[1], LIBNBD_CONNECT_URI_ALL) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/examples/strict-structured-reads.c b/examples/strict-structured-reads.c index b3880b7..fcf1186 100644 --- a/examples/strict-structured-reads.c +++ b/examples/strict-structured-reads.c @@ -197,7 +197,7 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } if (strstr (argv[1], "://")) { - if (nbd_connect_uri (nbd, argv[1]) == -1) { + if (nbd_connect_uri (nbd, argv[1], LIBNBD_CONNECT_URI_ALL) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/examples/threaded-reads-and-writes.c b/examples/threaded-reads-and-writes.c index 85d6e42..864e2f4 100644 --- a/examples/threaded-reads-and-writes.c +++ b/examples/threaded-reads-and-writes.c @@ -89,7 +89,7 @@ main (int argc, char *argv[]) /* Connect first to check if the server supports writes and multi-conn. */ if (argc == 2) { if (strstr (argv[1], "://")) { - if (nbd_connect_uri (nbd, argv[1]) == -1) { + if (nbd_connect_uri (nbd, argv[1], LIBNBD_CONNECT_URI_ALL) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } @@ -211,7 +211,8 @@ start_thread (void *arg) if (status->argc == 2) { if (strstr (status->argv[1], "://")) { - if (nbd_connect_uri (nbd, status->argv[1]) == -1) { + if (nbd_connect_uri (nbd, status->argv[1], + LIBNBD_CONNECT_URI_ALL) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/generator/generator b/generator/generator index fe24738..5f5523a 100755 --- a/generator/generator +++ b/generator/generator @@ -939,7 +939,17 @@ let cmd_flags = { "REQ_ONE", 1 lsl 3; ] } -let all_flags = [ cmd_flags ] +let connect_uri_allow_flags = { + flag_prefix = "CONNECT_URI"; + all_flags_bitmask = true; + flags = [ + "ALLOW_TCP", 1 lsl 0; + "ALLOW_UNIX", 1 lsl 1; + "ALLOW_TLS", 1 lsl 2; + "REQUIRE_TLS", 1 lsl 3; + ] +} +let all_flags = [ cmd_flags; connect_uri_allow_flags ] (* Calls. * @@ -1225,7 +1235,8 @@ C<\"qemu:dirty-bitmap:...\"> for qemu-nbd "connect_uri", { default_call with - args = [ String "uri" ]; ret = RErr; + args = [ String "uri"; Flags ("allow", connect_uri_allow_flags) ]; + ret = RErr; permitted_states = [ Created ]; shortdesc = "connect to NBD URI"; longdesc = "\ @@ -1238,7 +1249,37 @@ the connection has been made. This call will fail if libnbd was not compiled with libxml2; you can test whether this is the case with C<nbd_supports_uri>. Support for URIs that require TLS will fail if libnbd was not compiled with -gnutls; you can test whether this is the case with C<nbd_supports_tls>."; +gnutls; you can test whether this is the case with C<nbd_supports_tls>. + +The C<allow> parameter lets you choose which NBD URI features +are enabled, in case for example you don't want to allow +remote connections. Currently defined flags are: + +=over 4 + +=item C<LIBNBD_CONNECT_URI_ALLOW_TCP> + +Allow TCP sockets. + +=item C<LIBNBD_CONNECT_URI_ALLOW_UNIX> + +Allow Unix domain sockets. + +=item C<LIBNBD_CONNECT_URI_ALLOW_TLS> + +Allow TLS encryption. + +=item C<LIBNBD_CONNECT_URI_REQUIRE_TLS> + +Require TLS encryption. + +=item C<LIBNBD_CONNECT_URI_ALL> + +Enables all features which are defined at the time that +the program is compiled. Later features added to libnbd +will not be allowed unless you recompile your program. + +=back"; }; "connect_unix", { @@ -1737,7 +1778,8 @@ on the connection."; "aio_connect_uri", { default_call with - args = [ String "uri" ]; ret = RErr; + args = [ String "uri"; Flags ("allow", connect_uri_allow_flags) ]; + ret = RErr; permitted_states = [ Created ]; shortdesc = "connect to an NBD URI"; longdesc = "\ diff --git a/lib/connect.c b/lib/connect.c index f98bcdb..a4c594e 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -73,9 +73,10 @@ wait_until_connected (struct nbd_handle *h) /* Connect to an NBD URI. */ int -nbd_unlocked_connect_uri (struct nbd_handle *h, const char *uri) +nbd_unlocked_connect_uri (struct nbd_handle *h, + const char *uri, uint32_t allow) { - if (nbd_unlocked_aio_connect_uri (h, uri) == -1) + if (nbd_unlocked_aio_connect_uri (h, uri, allow) == -1) return -1; return wait_until_connected (h); @@ -228,7 +229,8 @@ error: #endif int -nbd_unlocked_aio_connect_uri (struct nbd_handle *h, const char *raw_uri) +nbd_unlocked_aio_connect_uri (struct nbd_handle *h, + const char *raw_uri, uint32_t allow) { #ifdef HAVE_LIBXML2 xmlURIPtr uri = NULL; @@ -276,6 +278,31 @@ nbd_unlocked_aio_connect_uri (struct nbd_handle *h, const char *raw_uri) goto cleanup; } + /* If the user specified the REQUIRE_TLS flag, we assume they must + * also mean to ALLOW_TLS. + */ + if ((allow & LIBNBD_CONNECT_URI_REQUIRE_TLS) != 0) + allow |= LIBNBD_CONNECT_URI_ALLOW_TLS; + + /* Check allow flags. */ + if (tcp && !(allow & LIBNBD_CONNECT_URI_ALLOW_TCP)) { + set_error (EPERM, "TCP URIs are not allowed"); + goto cleanup; + } + if (!tcp && !(allow & LIBNBD_CONNECT_URI_ALLOW_UNIX)) { + set_error (EPERM, "Unix domain socket URIs are not allowed"); + goto cleanup; + } + if (tls && !(allow & LIBNBD_CONNECT_URI_ALLOW_TLS)) { + set_error (EPERM, "TLS encrypted URIs are not allowed"); + goto cleanup; + } + if (!tls && (allow & LIBNBD_CONNECT_URI_REQUIRE_TLS)) { + set_error (EPERM, "URI must specify an encrypted connection " + "(use nbds: or nbds+unix:)"); + goto cleanup; + } + /* Insist on the scheme://[authority][/absname][?queries] form. */ if (strncmp (raw_uri + strlen (uri->scheme), "://", 3)) { set_error (EINVAL, "URI must begin with '%s://'", uri->scheme); diff --git a/tests/aio-parallel-load.c b/tests/aio-parallel-load.c index 614c22b..16c2aa2 100644 --- a/tests/aio-parallel-load.c +++ b/tests/aio-parallel-load.c @@ -220,7 +220,8 @@ start_thread (void *arg) /* Connect to nbdkit. */ if (strstr (connection, "://")) { - if (nbd_connect_uri (nbd, connection) == -1) { + if (nbd_connect_uri (nbd, connection, + LIBNBD_CONNECT_URI_ALLOW_UNIX) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/tests/connect-uri-tcp.c b/tests/connect-uri-tcp.c index 0c5c1df..b33d94c 100644 --- a/tests/connect-uri-tcp.c +++ b/tests/connect-uri-tcp.c @@ -80,7 +80,7 @@ main (int argc, char *argv[]) snprintf (uri, sizeof uri, "nbd://localhost:%d", port); - if (nbd_connect_uri (nbd, uri) == -1) { + if (nbd_connect_uri (nbd, uri, LIBNBD_CONNECT_URI_ALLOW_TCP) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/tests/connect-uri-unix.c b/tests/connect-uri-unix.c index 1e27d26..601fdf0 100644 --- a/tests/connect-uri-unix.c +++ b/tests/connect-uri-unix.c @@ -71,7 +71,8 @@ main (int argc, char *argv[]) exit (77); } - if (nbd_connect_uri (nbd, "nbd+unix:///?socket=" SOCKET) == -1) { + if (nbd_connect_uri (nbd, "nbd+unix:///?socket=" SOCKET, + LIBNBD_CONNECT_URI_ALLOW_UNIX) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } -- 2.22.0