Previously key=value on the command line allowed the key to be pretty
much anything that didn't contain an '=' character. Even empty
strings were permitted.
This tightens up the permitted keys so they must contain only ASCII
alphanumeric, period, underscore or dash characters; must not be an
empty string; and must start with an ASCII alphabetic character.
---
docs/nbdkit-plugin.pod | 24 +++++++++++++++---------
src/main.c | 36 +++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index 570a142..fb5c7d7 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -376,15 +376,21 @@ optional list of C<key=value> arguments. These are passed to
the
plugin through this callback when the plugin is first loaded and
before any connections are accepted.
-This callback may be called zero or more times. Both C<key> and
-C<value> parameters will be non-NULL, but it is possible for either to
-be empty strings. The strings are owned by nbdkit but will remain
-valid for the lifetime of the plugin, so the plugin does not need to
-copy them.
-
-The format of the C<key> accepted by plugins is up to the plugin, but
-you should probably look at other plugins and follow the same
-conventions.
+This callback may be called zero or more times.
+
+Both C<key> and C<value> parameters will be non-NULL.
+
+They key will be a non-empty string beginning with an ASCII alphabetic
+character (C<A-Z> C<a-z>). The rest of the key must contain only
+ASCII alphanumeric plus period, underscore or dash characters (C<A-Z>
+C<a-z> C<0-9> C<.> C<_> C<->).
+
+The value may be an arbitrary string, including an empty string. The
+strings are owned by nbdkit but will remain valid for the lifetime of
+the plugin, so the plugin does not need to copy them.
+
+The names of C<key>s accepted by plugins is up to the plugin, but you
+should probably look at other plugins and follow the same conventions.
If the value is a relative path, then note that the server changes
directory when it starts up. See L</FILENAMES AND PATHS> above.
diff --git a/src/main.c b/src/main.c
index 9c18d6f..f4a800f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -72,6 +72,7 @@ static void fork_into_background (void);
static uid_t parseuser (const char *);
static gid_t parsegroup (const char *);
static unsigned int get_socket_activation (void);
+static int is_config_key (const char *key, size_t len);
struct debug_flag *debug_flags; /* -D */
int exit_with_parent; /* --exit-with-parent */
@@ -694,7 +695,7 @@ main (int argc, char *argv[])
magic_config_key = backend->magic_config_key (backend);
for (i = 0; optind < argc; ++i, ++optind) {
p = strchr (argv[optind], '=');
- if (p) { /* key=value */
+ if (p && is_config_key (argv[optind], p - argv[optind])) { /* key=value */
*p = '\0';
backend->config (backend, argv[optind], p+1);
}
@@ -1281,3 +1282,36 @@ get_socket_activation (void)
return nr_fds;
}
+
+/* When parsing plugin and filter config key=value from the command
+ * line, check that the key is a simple alphanumeric with period,
+ * underscore or dash.
+ *
+ * Note this doesn't return an error. If the key is not valid then we
+ * return false and the parsing code will assume that this is a bare
+ * value instead.
+ */
+static int
+is_config_key (const char *key, size_t len)
+{
+ static const char allowed_first[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ static const char allowed[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "._-";
+
+ if (len == 0)
+ return 0;
+
+ if (strchr (allowed_first, key[0]) == NULL)
+ return 0;
+
+ /* This works in context of the caller since key[len] == '='. */
+ if (strspn (key, allowed) != len)
+ return 0;
+
+ return 1;
+}
--
2.18.0