Richard W.M. Jones
2019-Oct-17 21:38 UTC
[Libguestfs] [PATCH nbdkit] server: Allow file descriptors to be passed to nbdkit_read_password.
Allow password parameters such as ‘password=-FD’ where FD is a file
descriptor number inherited by nbdkit from the parent process. This
is another way to allow programs to hand passwords to nbdkit in a very
secure way, for example over a pipe so they never touch the
filesystem.
Previously nbdkit allowed you to use literal passwords on the command
line if they began with a ‘-’ (but were not just that single
character). However that was contrary to the documentation, and this
commit now prevents that.
---
docs/nbdkit-plugin.pod | 4 ++
plugins/curl/nbdkit-curl-plugin.pod | 10 ++++-
plugins/ssh/nbdkit-ssh-plugin.pod | 8 +++-
plugins/vddk/nbdkit-vddk-plugin.pod | 11 +++++-
server/public.c | 58 +++++++++++++++++++++--------
server/test-public.c | 31 +++++++++++++++
6 files changed, 102 insertions(+), 20 deletions(-)
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index e34ffd1..0afd5e1 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -1120,6 +1120,10 @@ or from a file:
nbdkit myplugin password=+/tmp/secret
+or from a file descriptor inherited by nbdkit:
+
+ nbdkit myplugin password=-99
+
(If the password begins with a C<-> or C<+> character then it must
be
passed in a file).
diff --git a/plugins/curl/nbdkit-curl-plugin.pod
b/plugins/curl/nbdkit-curl-plugin.pod
index 63500a4..827e0bd 100644
--- a/plugins/curl/nbdkit-curl-plugin.pod
+++ b/plugins/curl/nbdkit-curl-plugin.pod
@@ -70,10 +70,16 @@ Ask for the password (interactively) when nbdkit starts up.
=item B<password=+>FILENAME
-Read the password from the named file. This is the most secure method
+Read the password from the named file. This is a secure method
to supply a password, as long as you set the permissions on the file
appropriately.
+=item B<password=->FD
+
+Read the password from file descriptor number C<FD>, inherited from
+the parent process when nbdkit starts up. This is also a secure
+method to supply a password.
+
=item B<protocols=>PROTO,PROTO,...
Limit the protocols that are allowed in the URL. Use this option for
@@ -100,6 +106,8 @@ The default is to allow any protocol.
=item B<proxy-password=+>FILENAME
+=item B<proxy-password=->FD
+
=item B<proxy-user=>USERNAME
Set the proxy username and password.
diff --git a/plugins/ssh/nbdkit-ssh-plugin.pod
b/plugins/ssh/nbdkit-ssh-plugin.pod
index 0d0bc2b..687c08c 100644
--- a/plugins/ssh/nbdkit-ssh-plugin.pod
+++ b/plugins/ssh/nbdkit-ssh-plugin.pod
@@ -96,10 +96,16 @@ Ask for the password (interactively) when nbdkit starts up.
=item B<password=+>FILENAME
-Read the password from the named file. This is the most secure method
+Read the password from the named file. This is a secure method
to supply a password, as long as you set the permissions on the file
appropriately.
+=item B<password=->FD
+
+Read the password from file descriptor number C<FD>, inherited from
+the parent process when nbdkit starts up. This is also a secure
+method to supply a password.
+
=item [B<path=>]PATH
Specify the path to the remote file. This can be a relative path in
diff --git a/plugins/vddk/nbdkit-vddk-plugin.pod
b/plugins/vddk/nbdkit-vddk-plugin.pod
index bf6f7e7..4ae647c 100644
--- a/plugins/vddk/nbdkit-vddk-plugin.pod
+++ b/plugins/vddk/nbdkit-vddk-plugin.pod
@@ -6,7 +6,8 @@ nbdkit-vddk-plugin - nbdkit VMware VDDK plugin
nbdkit vddk file=FILENAME [config=FILENAME] [libdir=LIBRARY]
[vm=moref=ID] [server=HOSTNAME] [user=USERNAME]
- [password=PASSWORD | password=- | password=+FILENAME]
+ [password=PASSWORD | password=- | password=+FILENAME |
+ password=-FD]
[cookie=COOKIE] [thumbprint=THUMBPRINT]
[port=PORT] [nfchostport=PORT] [single-link=true]
[snapshot=MOREF] [transports=MODE:MODE:...]
@@ -140,10 +141,16 @@ Ask for the password (interactively) when nbdkit starts
up.
=item B<password=+>FILENAME
-Read the password from the named file. This is the most secure method
+Read the password from the named file. This is a secure method
to supply a password, as long as you set the permissions on the file
appropriately.
+=item B<password=->FD
+
+Read the password from file descriptor number C<FD>, inherited from
+the parent process when nbdkit starts up. This is also a secure
+method to supply a password.
+
=item B<port=>PORT
The port on the VCenter/ESXi host. Defaults to 443.
diff --git a/server/public.c b/server/public.c
index 9a3aa31..418945f 100644
--- a/server/public.c
+++ b/server/public.c
@@ -405,6 +405,8 @@ nbdkit_parse_bool (const char *str)
}
/* Read a password from configuration value. */
+static int read_password_from_fd (const char *what, int fd, char **password);
+
int
nbdkit_read_password (const char *value, char **password)
{
@@ -412,7 +414,6 @@ nbdkit_read_password (const char *value, char **password)
struct termios orig, temp;
ssize_t r;
size_t n;
- FILE *fp;
*password = NULL;
@@ -448,6 +449,16 @@ nbdkit_read_password (const char *value, char **password)
(*password)[r-1] = '\0';
}
+ /* Read from numbered file descriptor. */
+ else if (value[0] == '-') {
+ int fd;
+
+ if (nbdkit_parse_int ("password file descriptor", &value[1],
&fd) == -1)
+ return -1;
+ if (read_password_from_fd (&value[1], fd, password) == -1)
+ return -1;
+ }
+
/* Read password from a file. */
else if (value[0] == '+') {
int fd;
@@ -457,22 +468,8 @@ nbdkit_read_password (const char *value, char **password)
nbdkit_error ("open %s: %m", &value[1]);
return -1;
}
- fp = fdopen (fd, "r");
- if (fp == NULL) {
- nbdkit_error ("fdopen %s: %m", &value[1]);
- close (fd);
+ if (read_password_from_fd (&value[1], fd, password) == -1)
return -1;
- }
- r = getline (password, &n, fp);
- err = errno;
- fclose (fp);
- if (r == -1) {
- errno = err;
- nbdkit_error ("could not read password from file %s: %m",
&value[1]);
- return -1;
- }
- if (*password && r > 0 && (*password)[r-1] ==
'\n')
- (*password)[r-1] = '\0';
}
/* Parameter is the password. */
@@ -487,6 +484,35 @@ nbdkit_read_password (const char *value, char **password)
return 0;
}
+static int
+read_password_from_fd (const char *what, int fd, char **password)
+{
+ FILE *fp;
+ size_t n;
+ ssize_t r;
+ int err;
+
+ fp = fdopen (fd, "r");
+ if (fp == NULL) {
+ nbdkit_error ("fdopen %s: %m", what);
+ close (fd);
+ return -1;
+ }
+ r = getline (password, &n, fp);
+ err = errno;
+ fclose (fp);
+ if (r == -1) {
+ errno = err;
+ nbdkit_error ("could not read password from %s: %m", what);
+ return -1;
+ }
+
+ if (*password && r > 0 && (*password)[r-1] ==
'\n')
+ (*password)[r-1] = '\0';
+
+ return 0;
+}
+
int
nbdkit_nanosleep (unsigned sec, unsigned nsec)
{
diff --git a/server/test-public.c b/server/test-public.c
index ea10189..4a7eb17 100644
--- a/server/test-public.c
+++ b/server/test-public.c
@@ -335,6 +335,8 @@ test_nbdkit_read_password (void)
{
bool pass = true;
char template[] = "+/tmp/nbdkit_testpw_XXXXXX";
+ char template2[] = "/tmp/nbdkit_testpw2_XXXXXX";
+ char fdbuf[16];
char *pw = template;
int fd;
@@ -391,6 +393,35 @@ test_nbdkit_read_password (void)
unlink (&template[1]);
}
+ /* Test reading password from file descriptor. */
+ fd = mkstemp (template2);
+ if (fd < 0) {
+ perror ("mkstemp");
+ pass = false;
+ }
+ else if (write (fd, "abc\n", 4) != 4) {
+ fprintf (stderr, "Failed to write to file %s\n", template2);
+ pass = false;
+ }
+ else {
+ snprintf (fdbuf, sizeof fdbuf, "-%d", fd);
+ lseek (fd, 0, 0);
+ if (nbdkit_read_password (fdbuf, &pw) == -1) {
+ fprintf (stderr, "Failed to read password from fd %s\n",
fdbuf);
+ pass = false;
+ }
+ else if (strcmp (pw, "abc") != 0) {
+ fprintf (stderr, "Wrong file password, expected 'abc' got
'%s'\n", pw);
+ pass = false;
+ }
+ free (pw);
+ }
+
+ if (fd >= 0) {
+ /* Don't close fd, it is closed by nbdkit_read_password. */
+ unlink (template2);
+ }
+
if (error_flagged) {
fprintf (stderr, "Wrong error message handling\n");
pass = false;
--
2.23.0
Eric Blake
2019-Oct-17 21:50 UTC
Re: [Libguestfs] [PATCH nbdkit] server: Allow file descriptors to be passed to nbdkit_read_password.
On 10/17/19 4:38 PM, Richard W.M. Jones wrote:> Allow password parameters such as ‘password=-FD’ where FD is a file > descriptor number inherited by nbdkit from the parent process. This > is another way to allow programs to hand passwords to nbdkit in a very > secure way, for example over a pipe so they never touch the > filesystem. > > Previously nbdkit allowed you to use literal passwords on the command > line if they began with a ‘-’ (but were not just that single > character). However that was contrary to the documentation, and this > commit now prevents that. > ---> > +static int > +read_password_from_fd (const char *what, int fd, char **password) > +{ > + FILE *fp; > + size_t n; > + ssize_t r; > + int err; > + > + fp = fdopen (fd, "r"); > + if (fp == NULL) { > + nbdkit_error ("fdopen %s: %m", what); > + close (fd); > + return -1; > + } > + r = getline (password, &n, fp);This prevents a password from containing a newline. Is that a problem? Can a password contain a literal newline when passed literally through the command line? If so, that feels inconsistent.> + err = errno; > + fclose (fp); > + if (r == -1) { > + errno = err; > + nbdkit_error ("could not read password from %s: %m", what); > + return -1; > + } > + > + if (*password && r > 0 && (*password)[r-1] == '\n') > + (*password)[r-1] = '\0'; > + > + return 0; > +} > +> +++ b/server/test-public.c > @@ -335,6 +335,8 @@ test_nbdkit_read_password (void) > { > bool pass = true; > char template[] = "+/tmp/nbdkit_testpw_XXXXXX"; > + char template2[] = "/tmp/nbdkit_testpw2_XXXXXX"; > + char fdbuf[16]; > char *pw = template; > int fd; > > @@ -391,6 +393,35 @@ test_nbdkit_read_password (void) > unlink (&template[1]); > } > > + /* Test reading password from file descriptor. */ > + fd = mkstemp (template2); > + if (fd < 0) { > + perror ("mkstemp"); > + pass = false; > + } > + else if (write (fd, "abc\n", 4) != 4) { > + fprintf (stderr, "Failed to write to file %s\n", template2); > + pass = false; > + }But at least you test that newlines are stripped when using a file descriptor, so the addition seems self-consistent (even if we need more documentation on how newlines in passwords are handled). -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
Richard W.M. Jones
2019-Oct-18 07:41 UTC
Re: [Libguestfs] [PATCH nbdkit] server: Allow file descriptors to be passed to nbdkit_read_password.
On Thu, Oct 17, 2019 at 04:50:20PM -0500, Eric Blake wrote:> On 10/17/19 4:38 PM, Richard W.M. Jones wrote: > >Allow password parameters such as ‘password=-FD’ where FD is a file > >descriptor number inherited by nbdkit from the parent process. This > >is another way to allow programs to hand passwords to nbdkit in a very > >secure way, for example over a pipe so they never touch the > >filesystem. > > > >Previously nbdkit allowed you to use literal passwords on the command > >line if they began with a ‘-’ (but were not just that single > >character). However that was contrary to the documentation, and this > >commit now prevents that. > >--- > > >+static int > >+read_password_from_fd (const char *what, int fd, char **password) > >+{ > >+ FILE *fp; > >+ size_t n; > >+ ssize_t r; > >+ int err; > >+ > >+ fp = fdopen (fd, "r"); > >+ if (fp == NULL) { > >+ nbdkit_error ("fdopen %s: %m", what); > >+ close (fd); > >+ return -1; > >+ } > >+ r = getline (password, &n, fp); > > This prevents a password from containing a newline. Is that a > problem? Can a password contain a literal newline when passed > literally through the command line? If so, that feels inconsistent.I believe that's also a problem with the current code, as I simply factored out this function from the existing code for "+file". Anyone who has a password containing a newline presumably also has a problem logging in (to any reasonable server)? Rich.> >+ err = errno; > >+ fclose (fp); > >+ if (r == -1) { > >+ errno = err; > >+ nbdkit_error ("could not read password from %s: %m", what); > >+ return -1; > >+ } > >+ > >+ if (*password && r > 0 && (*password)[r-1] == '\n') > >+ (*password)[r-1] = '\0'; > >+ > >+ return 0; > >+} > >+ > > >+++ b/server/test-public.c > >@@ -335,6 +335,8 @@ test_nbdkit_read_password (void) > > { > > bool pass = true; > > char template[] = "+/tmp/nbdkit_testpw_XXXXXX"; > >+ char template2[] = "/tmp/nbdkit_testpw2_XXXXXX"; > >+ char fdbuf[16]; > > char *pw = template; > > int fd; > >@@ -391,6 +393,35 @@ test_nbdkit_read_password (void) > > unlink (&template[1]); > > } > >+ /* Test reading password from file descriptor. */ > >+ fd = mkstemp (template2); > >+ if (fd < 0) { > >+ perror ("mkstemp"); > >+ pass = false; > >+ } > >+ else if (write (fd, "abc\n", 4) != 4) { > >+ fprintf (stderr, "Failed to write to file %s\n", template2); > >+ pass = false; > >+ } > > But at least you test that newlines are stripped when using a file > descriptor, so the addition seems self-consistent (even if we need > more documentation on how newlines in passwords are handled). > > -- > Eric Blake, Principal Software Engineer > Red Hat, Inc. +1-919-301-3226 > Virtualization: qemu.org | libvirt.org-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
Seemingly Similar Threads
- [PATCH nbdkit] server: Allow file descriptors to be passed to nbdkit_read_password.
- [nbdkit PATCH v2 1/3] server: Add nbdkit_stdio_safe
- [nbdkit PATCH 1/2] server: Add nbdkit_stdio_safe
- [PATCH nbdkit 5/9 patch split 2/5] lib: Move code for parsing, passwords and paths into libnbdkit.so.
- [PATCH nbdkit 1/3] server: Disallow password=- from non-tty and fix error message (RHBZ#1842440).