diff options
author | Werner Koch <[email protected]> | 2025-04-07 12:31:38 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2025-04-07 12:31:38 +0000 |
commit | d0b7d33536736ef6f3d41575b6f58b2d3a7c139b (patch) | |
tree | 66256d2befac883a87ca9afe746aa8c972264dfc | |
parent | Allow name-value lookup w/o a trailing colon for the name. (diff) | |
download | libgpg-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.in | 1 | ||||
-rw-r--r-- | src/name-value.c | 82 | ||||
-rw-r--r-- | tests/t-name-value.c | 126 |
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) |