aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2025-04-07 12:31:38 +0000
committerWerner Koch <[email protected]>2025-04-07 12:31:38 +0000
commitd0b7d33536736ef6f3d41575b6f58b2d3a7c139b (patch)
tree66256d2befac883a87ca9afe746aa8c972264dfc
parentAllow name-value lookup w/o a trailing colon for the name. (diff)
downloadlibgpg-error-d0b7d33536736ef6f3d41575b6f58b2d3a7c139b.tar.gz
libgpg-error-d0b7d33536736ef6f3d41575b6f58b2d3a7c139b.zip
Add a section mode to the name-value functions.
* src/gpg-error.h.in (GPGRT_NVC_SECTION): New. * src/name-value.c (_gpgrt_name_value_container): Add section_mode. (_gpgrt_nvc_new): Set it. (_gpgrt_nvc_get_flag): Return it. (valid_name): Add arg sectionmode and change callers. (do_nvc_parse): Parse section names in section mode. (_gpgrt_nvc_write): Return an error in section mode.
-rw-r--r--src/gpg-error.h.in1
-rw-r--r--src/name-value.c82
-rw-r--r--tests/t-name-value.c126
3 files changed, 190 insertions, 19 deletions
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index 5a95baf..1bfe6a7 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1053,6 +1053,7 @@ typedef struct _gpgrt_name_value_entry *gpgrt_nve_t;
#define GPGRT_NVC_WIPE 2 /* Wipe the values on free. */
#define GPGRT_NVC_PRIVKEY 4 /* Enable private key mode. */
+#define GPGRT_NVC_SECTION 8 /* Enable section mode. */
#define GPGRT_NVC_MODIFIED 256 /* Return the modified flag. */
/* Return a name-value container according to the given flags.
diff --git a/src/name-value.c b/src/name-value.c
index 76e305a..987eb36 100644
--- a/src/name-value.c
+++ b/src/name-value.c
@@ -35,6 +35,7 @@ struct _gpgrt_name_value_container
struct _gpgrt_name_value_entry *last;
unsigned int wipe_on_free:1;
unsigned int private_key_mode:1;
+ unsigned int section_mode:1;
unsigned int modified:1;
};
@@ -148,6 +149,7 @@ _gpgrt_nvc_new (unsigned int flags)
}
else if ((flags & GPGRT_NVC_WIPE))
nvc->wipe_on_free = 1;
+ nvc->section_mode = !!(flags & GPGRT_NVC_SECTION);
return nvc;
}
@@ -209,6 +211,8 @@ _gpgrt_nvc_get_flag (gpgrt_nvc_t cont, unsigned int flags, int clear)
ret = cont->private_key_mode;
else if ((flags & GPGRT_NVC_WIPE))
ret = cont->wipe_on_free;
+ else if ((flags & GPGRT_NVC_SECTION))
+ ret = cont->section_mode;
return !!ret;
}
@@ -223,11 +227,23 @@ _gpgrt_nvc_get_flag (gpgrt_nvc_t cont, unsigned int flags, int clear)
* optional colon if NAME is valid; returns 0 if the name is not
* valid. The length of the name must be less than 255. */
static unsigned int
-valid_name (const char *name)
+valid_name (const char *name, int sectionmode)
{
size_t i;
- size_t len = strlen (name);
+ size_t len, extralen;
+ const char *s;
+
+ /* In section mode we skip over the first colon. We require that
+ * after the colon at least one other characters is found. */
+ if (sectionmode && (s=strchr (name, ':')) && s[1] && s[1] != ':')
+ {
+ extralen = s + 1 - name;
+ name = s+1;
+ }
+ else
+ extralen = 0;
+ len = strlen (name);
if (!alphap (name) || !len || len > 255)
return 0;
if (name[len-1] == ':') /* The colon is optional. */
@@ -239,7 +255,7 @@ valid_name (const char *name)
if (!alnump (name + i) && name[i] != '-')
return 0;
- return len;
+ return len + extralen;
}
@@ -437,7 +453,7 @@ do_nvc_add (gpgrt_nvc_t cont, char *name, char *value,
gpgrt_assert (value || raw_value);
- namelen = name ? valid_name (name) : 0;
+ namelen = name ? valid_name (name, cont->section_mode) : 0;
if (name && !namelen)
{
err = GPG_ERR_INV_NAME;
@@ -558,7 +574,7 @@ _gpgrt_nvc_set (gpgrt_nvc_t cont, const char *name, const char *value)
{
gpgrt_nve_t e;
- if (! valid_name (name))
+ if (! valid_name (name, cont->section_mode))
return GPG_ERR_INV_NAME;
e = _gpgrt_nvc_lookup (cont, name);
@@ -630,7 +646,7 @@ _gpgrt_nvc_delete (gpgrt_nvc_t cont, gpgrt_nve_t entry, const char *name)
{
if (entry)
do_nvc_delete (cont, entry);
- else if (valid_name (name))
+ else if (valid_name (name, cont->section_mode))
{
while ((entry = _gpgrt_nvc_lookup (cont, name)))
do_nvc_delete (cont, entry);
@@ -705,6 +721,7 @@ do_nvc_parse (gpgrt_nvc_t *result, int *errlinep, estream_t stream,
char *buf = NULL;
size_t buf_len = 0;
char *name = NULL;
+ char *section = NULL;
gpgrt_strlist_t raw_value = NULL;
unsigned int slflags;
@@ -719,7 +736,8 @@ do_nvc_parse (gpgrt_nvc_t *result, int *errlinep, estream_t stream,
*errlinep = 0;
while ((len = _gpgrt_read_line (stream, &buf, &buf_len, NULL)) > 0)
{
- char *p;
+ char *p, *p2;
+
if (errlinep)
*errlinep += 1;
@@ -752,7 +770,44 @@ do_nvc_parse (gpgrt_nvc_t *result, int *errlinep, estream_t stream,
name = NULL;
raw_value = NULL;
- if (*p != 0 && *p != '#')
+ if ((flags & GPGRT_NVC_SECTION) && *p == '[' && (p2=strchr (p+1, ']')))
+ {
+ /* This is a section header. Extract it so that we can
+ * prepend all names with it. We allow a comment after the
+ * section and spaces after the [ and before the ]. No
+ * spaces inside the section name. We also limit the name
+ * to 200 characters. */
+ _gpgrt_trim_spaces (p2+1);
+ if (p == p2 || (p2[1] && p2[1] != '#'))
+ {
+ err = GPG_ERR_INV_VALUE;
+ goto leave;
+ }
+ *p2 = 0;
+ p++;
+ _gpgrt_trim_spaces (p);
+ if (!*p || strpbrk (p, " \t#:") || strlen (p) > 200)
+ {
+ err = GPG_ERR_INV_VALUE; /* No or invalid section name */
+ goto leave;
+ }
+ xfree (section);
+ section = xtrystrdup (p);
+ if (!section)
+ {
+ err = _gpg_err_code_from_syserror ();
+ goto leave;
+ }
+ /* Map all backslashes to slashes. */
+ for (p2=section; *p2; p2++)
+ if (*p2 == '\\')
+ *p2 = '/';
+
+ continue;
+ }
+
+
+ if (*p && *p != '#')
{
char *colon, *value, tmp;
@@ -766,7 +821,10 @@ do_nvc_parse (gpgrt_nvc_t *result, int *errlinep, estream_t stream,
value = colon + 1;
tmp = *value;
*value = 0;
- name = xtrystrdup (p);
+ if (section)
+ name = _gpgrt_strconcat (section, ":", p, NULL);
+ else
+ name = xtrystrdup (p);
*value = tmp;
if (!name)
{
@@ -802,6 +860,7 @@ do_nvc_parse (gpgrt_nvc_t *result, int *errlinep, estream_t stream,
}
leave:
+ xfree (section);
xfree (name);
xfree (buf);
if (err)
@@ -858,6 +917,11 @@ _gpgrt_nvc_write (gpgrt_nvc_t cont, estream_t stream)
gpgrt_nve_t entry;
gpgrt_nve_t keyentry = NULL;
+ /* We can't yet write out in section mode because we merge entries
+ * from the same section and do not keep a raw representation. */
+ if (cont->section_mode)
+ return GPG_ERR_NOT_IMPLEMENTED;
+
for (entry = cont->first; entry; entry = entry->next)
{
if (cont->private_key_mode
diff --git a/tests/t-name-value.c b/tests/t-name-value.c
index b4c618c..b0e542b 100644
--- a/tests/t-name-value.c
+++ b/tests/t-name-value.c
@@ -31,16 +31,19 @@
static void test_getting_values (gpgrt_nvc_t cont);
+static void test_getting_section_values (gpgrt_nvc_t pk);
static void test_key_extraction (gpgrt_nvc_t pk);
static void test_iteration (gpgrt_nvc_t pk);
static void test_whitespace (gpgrt_nvc_t pk);
static int private_key_mode;
+static int section_mode;
static struct
{
char *value;
void (*test_func) (gpgrt_nvc_t);
+ int only_section_mode;
} tests[] =
{
{
@@ -118,6 +121,22 @@ static struct
" (#D2760001240102000005000011730000# OPENPGP.1)\n"
" )))\n",
test_key_extraction
+ },
+ {
+ "# This is a test for section mode\n"
+ "[ HKLM\\Software\\Bla\\Foo ]# the section name\n"
+ "Myname: Erika\n"
+ "Surname: Musterfrau\n"
+ "\n"
+ "[\\Software\\blub]\n"
+ "Myname: Otto Blub\n"
+ "Surname: Ottoman\n"
+ "[HKLM\\Software/Bla\\Foo ] # Add stuff to the first section\n"
+ "Url: https://example.org\n"
+ "Url: http://example.de\n"
+ "Surname: Hacker\n"
+ "# last comment\n",
+ test_getting_section_values, 1
}
};
@@ -161,6 +180,71 @@ test_getting_values (gpgrt_nvc_t pk)
static void
+test_getting_section_values (gpgrt_nvc_t pk)
+{
+ gpgrt_nve_t e;
+ const char *value;
+
+ enter_test_function ();
+
+ e = gpgrt_nvc_lookup (pk, "MyName");
+ if (e)
+ fail ("nvc_lookup unexpected succeeded at line %d\n", __LINE__);
+
+ e = gpgrt_nvc_lookup (pk, "HKLM/Software/Bla/Foo:MyName");
+ if (!e)
+ fail ("nvc_lookup failed at line %d\n", __LINE__);
+ else
+ {
+ value = gpgrt_nve_value (e);
+ show ("value for %s is ->%s<-\n", gpgrt_nve_name (e), value);
+ }
+
+ e = gpgrt_nvc_lookup (pk, "HKLM/Software/Bla/Foo:SurName");
+ if (!e)
+ fail ("nvc_lookup failed at line %d\n", __LINE__);
+ else
+ {
+ value = gpgrt_nve_value (e);
+ show ("value for %s is ->%s<-\n", gpgrt_nve_name (e), value);
+ }
+ e = gpgrt_nve_next (e, "HKLM/Software/Bla/Foo:SurName");
+ if (!e)
+ fail ("nvc_next failed at line %d\n", __LINE__);
+ else
+ {
+ value = gpgrt_nve_value (e);
+ show ("value for %s is ->%s<-\n", gpgrt_nve_name (e), value);
+ }
+ e = gpgrt_nve_next (e, "HKLM/Software/Bla/Foo:surname");
+ if (e)
+ fail ("nve_next unexpected succeeded at line %d\n", __LINE__);
+
+ e = gpgrt_nvc_lookup (pk, "HKLM/Software/Bla/Foo:Url");
+ if (!e)
+ fail ("nvc_lookup failed at line %d\n", __LINE__);
+ else
+ {
+ value = gpgrt_nve_value (e);
+ show ("value for %s is ->%s<-\n", gpgrt_nve_name (e), value);
+ }
+ e = gpgrt_nve_next (e, "HKLM/Software/Bla/Foo:Url");
+ if (!e)
+ fail ("nve_next failed at line %d\n", __LINE__);
+ else
+ {
+ value = gpgrt_nve_value (e);
+ show ("value for %s is ->%s<-\n", gpgrt_nve_name (e), value);
+ }
+ e = gpgrt_nve_next (e, "HKLM/Software/Bla/Foo:Url");
+ if (e)
+ fail ("nve_next unexpected succeeded at line %d\n", __LINE__);
+
+ leave_test_function ();
+}
+
+
+static void
test_key_extraction (gpgrt_nvc_t pk)
{
const char *key;
@@ -258,6 +342,7 @@ run_tests (void)
gpg_error_t err;
gpgrt_nvc_t pk;
int i;
+ int errlno;
for (i = 0; i < DIM (tests); i++)
{
@@ -265,26 +350,38 @@ run_tests (void)
char *buf;
size_t len;
+ if (tests[i].only_section_mode && !section_mode)
+ continue;
+
len = strlen (tests[i].value);
source = es_mopen (tests[i].value, len, len,
0, dummy_realloc, dummy_free, "r");
gpgrt_assert (source);
if (private_key_mode)
- err = gpgrt_nvc_parse (&pk, NULL, source, GPGRT_NVC_PRIVKEY);
+ err = gpgrt_nvc_parse (&pk, &errlno, source, GPGRT_NVC_PRIVKEY);
+ else if (section_mode)
+ err = gpgrt_nvc_parse (&pk, &errlno, source, GPGRT_NVC_SECTION);
else
- err = gpgrt_nvc_parse (&pk, NULL, source, 0);
+ err = gpgrt_nvc_parse (&pk, &errlno, source, 0);
+ if (err)
+ show ("parser failed at input line %d: %s\n",
+ errlno, gpg_strerror (err));
gpgrt_assert (err == 0);
gpgrt_assert (pk);
- if (verbose)
- {
- err = gpgrt_nvc_write (pk, es_stderr);
- gpgrt_assert (err == 0);
- }
-
- buf = nvc_to_string (pk);
- gpgrt_assert (memcmp (tests[i].value, buf, len) == 0);
+ if (section_mode)
+ buf = NULL; /* nvc_to_string does not yet work. */
+ else
+ {
+ if (verbose)
+ {
+ err = gpgrt_nvc_write (pk, es_stderr);
+ gpgrt_assert (err == 0);
+ }
+ buf = nvc_to_string (pk);
+ gpgrt_assert (memcmp (tests[i].value, buf, len) == 0);
+ }
es_fclose (source);
xfree (buf);
@@ -308,6 +405,8 @@ run_modification_tests (void)
gpgrt_nve_t e;
char *buf;
+ enter_test_function ();
+
pk = gpgrt_nvc_new (private_key_mode? GPGRT_NVC_PRIVKEY : 0);
gpgrt_assert (pk);
@@ -454,6 +553,8 @@ run_modification_tests (void)
gpgrt_assert (strcmp (buf, "Key: (hello world)\n") == 0);
xfree (buf);
gpgrt_nvc_release (pk);
+
+ leave_test_function ();
}
@@ -586,6 +687,11 @@ main (int argc, char **argv)
run_tests ();
run_modification_tests ();
+ show ("again in section mode\n");
+ private_key_mode = 0;
+ section_mode = 1;
+ run_tests ();
+
show ("testing name-value functions finished\n");
}
else if (command == CMD_PARSE)