From 3a96009e00d043e3abe29ef4459e5681e2dcb7b7 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Fri, 21 Sep 2007 21:01:43 -0400 Subject: [PATCH] Added configuration parameter "recursion_depth". This specifies the maximum number of recursions when an element contains a "target" attribute. When exceeded, the command will fail and return EPWMD_LOOP. The default is 20 but can be changed at compile time. Setting to 0 disables detection completely. --- TODO | 4 ---- configure.ac | 3 +++ doc/config.example | 4 ++++ doc/pwmd.1 | 7 ++++++- po/pwmd.pot | 52 ++++++++++++++++++++++++++-------------------------- src/common.h | 1 + src/pwmd.c | 5 +++++ src/pwmd_error.c | 2 +- src/pwmd_error.h | 1 + src/xml.c | 32 +++++++++++++++++++++++++++++++- 10 files changed, 78 insertions(+), 33 deletions(-) diff --git a/TODO b/TODO index c75a9159..a15307d8 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,3 @@ -Detect "target" attribute loops and return an error. I don't think this is -even possible since a target may reference itself but have following element's -that differ. It may be better to have a target depth limit instead. - Add ZPROGRESS status messages when compressing and decompressing. This would require a small(er) compression and decompression chunk size in order to display the progress which will affect compression ratio. diff --git a/configure.ac b/configure.ac index 13546185..dab95c3e 100644 --- a/configure.ac +++ b/configure.ac @@ -121,6 +121,9 @@ AC_DEFUN([AC_MEM_DEBUG], AC_ARG_ENABLE(mem_debug, AC_HELP_STRING([--enable-mem-debug], [Enable memory debugging.]), AC_MEM_DEBUG([$enableval]), AC_MEM_DEBUG) +AC_DEFINE([DEFAULT_RECURSION_DEPTH], 20, \ + [Default number of target recursions before returning an error.]) + AM_CONDITIONAL(MEM_DEBUG, test x"${ac_cv_sys_mem_debug}" != xno) AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile po/Makefile.in]) AC_OUTPUT diff --git a/doc/config.example b/doc/config.example index 04d08d9a..9c21cb04 100644 --- a/doc/config.example +++ b/doc/config.example @@ -52,6 +52,10 @@ # To disable compression entirely, set to 0. #compression_level=6 +# The maximum recursion depth when resolving elements that contain a "target" +# attribute. When this value is exceeded an error will be returned. +#recursion_depth=20 + # END GLOBAL SETTINGS # File specific settings are allowed by placing the filename in braces. diff --git a/doc/pwmd.1 b/doc/pwmd.1 index 0af3093b..67b923ad 100644 --- a/doc/pwmd.1 +++ b/doc/pwmd.1 @@ -15,7 +15,7 @@ \\$2 \(laURL: \\$1 \(ra\\$3 .. .if \n[.g] .mso www.tmac -.TH PWMD 1 "03 Aug 2007" "Password Manager Daemon" "Password Manager Daemon" +.TH PWMD 1 "21 Sep 2007" "Password Manager Daemon" "Password Manager Daemon" .SH NAME pwmd \- local socket data server @@ -132,6 +132,11 @@ The default compression level for data files from \fI1\fP to \fI9\fP, \fI1\fP being the fastest but least compression and \fI9\fP being the slowest but best compression. To disable compression entirely, set to \fI0\fP. The default is \fI6\fP. +.TP +.I "recursion_depth=" +The maximum number of times to resolve a target attribute for a single element +in an element path. An error is returned when this value is exceeded. The +default is \fI20\fP but can be disabled by setting to \fI0\fP. .SH SIGNALS .TP .B SIGHUP diff --git a/po/pwmd.pot b/po/pwmd.pot index 632025fc..09349271 100644 --- a/po/pwmd.pot +++ b/po/pwmd.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: bjk@luxsci.net\n" -"POT-Creation-Date: 2007-08-30 20:32-0400\n" +"POT-Creation-Date: 2007-09-21 20:58-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -59,116 +59,116 @@ msgstr "" msgid "exiting" msgstr "" -#: src/pwmd.c:442 +#: src/pwmd.c:447 #, c-format msgid "%s: skipping empty file" msgstr "" -#: src/pwmd.c:458 +#: src/pwmd.c:463 #, c-format msgid "Password for '%s': " msgstr "" -#: src/pwmd.c:462 +#: src/pwmd.c:467 #, c-format msgid "%s: skipping file" msgstr "" -#: src/pwmd.c:472 src/pwmd.c:864 +#: src/pwmd.c:477 src/pwmd.c:869 #, c-format msgid "%s: invalid password, skipping" msgstr "" -#: src/pwmd.c:477 +#: src/pwmd.c:482 #, c-format msgid "%s: invalid password" msgstr "" -#: src/pwmd.c:527 +#: src/pwmd.c:532 msgid "New password: " msgstr "" -#: src/pwmd.c:528 +#: src/pwmd.c:533 msgid "Invalid password." msgstr "" -#: src/pwmd.c:533 +#: src/pwmd.c:538 msgid "Verify password: " msgstr "" -#: src/pwmd.c:534 src/pwmd.c:541 +#: src/pwmd.c:539 src/pwmd.c:546 msgid "Passwords do not match." msgstr "" -#: src/pwmd.c:722 +#: src/pwmd.c:727 #, c-format msgid "%s: empty file?" msgstr "" -#: src/pwmd.c:825 +#: src/pwmd.c:830 #, c-format msgid "%s: invalid characters in filename" msgstr "" -#: src/pwmd.c:834 +#: src/pwmd.c:839 #, c-format msgid "%s: file already cached, skipping" msgstr "" -#: src/pwmd.c:880 +#: src/pwmd.c:885 #, c-format msgid "%s: file added to the cache" msgstr "" -#: src/pwmd.c:1002 +#: src/pwmd.c:1007 #, c-format msgid "%s: socket_path not defined" msgstr "" -#: src/pwmd.c:1014 +#: src/pwmd.c:1019 #, c-format msgid "%s: data_directory not defined" msgstr "" -#: src/pwmd.c:1035 +#: src/pwmd.c:1040 #, c-format msgid "cache size must be in multiples of %li" msgstr "" -#: src/pwmd.c:1143 +#: src/pwmd.c:1148 msgid "Done. Daemonizing..." msgstr "" -#: src/pwmd.c:1143 +#: src/pwmd.c:1148 msgid "Done. Waiting for connections..." msgstr "" -#: src/pwmd.c:1171 +#: src/pwmd.c:1176 #, c-format msgid "" "Either there is another pwmd running or '%s' is a \n" "stale socket. Please remove it manually." msgstr "" -#: src/pwmd.c:1216 +#: src/pwmd.c:1221 msgid "started" msgstr "" -#: src/pwmd.c:1247 +#: src/pwmd.c:1252 #, c-format msgid "new connection: pid=%i" msgstr "" -#: src/pwmd.c:1264 +#: src/pwmd.c:1269 msgid "waiting for all clients to disconnect" msgstr "" -#: src/pwmd.c:1268 +#: src/pwmd.c:1273 #, c-format msgid "%i clients remain" msgstr "" -#: src/pwmd.c:1287 +#: src/pwmd.c:1292 msgid "pwmd exiting normally" msgstr "" @@ -185,7 +185,7 @@ msgid "Element not found" msgstr "" #: src/pwmd_error.c:46 -msgid "Trailing element" +msgid "Recursion loop" msgstr "" #: src/pwmd_error.c:48 diff --git a/src/common.h b/src/common.h index 2f4c25f5..c0150008 100644 --- a/src/common.h +++ b/src/common.h @@ -50,6 +50,7 @@ struct client_s { gcry_error_t gcryerrno; gsize gcrykeysize, gcryblocksize; GKeyFile *keyfileh; +int max_recursion_depth; void log_write(const gchar *fmt, ...); gpg_error_t send_error(assuan_context_t ctx, gpg_error_t pwmd_errno); diff --git a/src/pwmd.c b/src/pwmd.c index 7de58ab7..ed7dc4d7 100644 --- a/src/pwmd.c +++ b/src/pwmd.c @@ -362,6 +362,11 @@ static void set_rcfile_defaults(GKeyFile *kf) if (g_key_file_has_key(kf, "default", "compression_level", NULL) == FALSE) g_key_file_set_integer(kf, "default", "compression_level", 6); + + if (g_key_file_has_key(kf, "default", "recursion_depth", NULL) == FALSE) + g_key_file_set_integer(kf, "default", "recursion_depth", DEFAULT_RECURSION_DEPTH); + + max_recursion_depth = g_key_file_get_integer(kf, "default", "recursion_depth", NULL); } static GKeyFile *parse_rcfile(int cmdline) diff --git a/src/pwmd_error.c b/src/pwmd_error.c index 42972c31..ce06d24d 100644 --- a/src/pwmd_error.c +++ b/src/pwmd_error.c @@ -43,7 +43,7 @@ const char *pwmd_strerror(gpg_error_t e) case GPG_ERR_USER_3: return N_("Element not found"); case GPG_ERR_USER_4: - return N_("Trailing element"); + return N_("Recursion loop"); case GPG_ERR_USER_5: return N_("Invalid character in element"); case GPG_ERR_USER_6: diff --git a/src/pwmd_error.h b/src/pwmd_error.h index 436ccc0b..828044f9 100644 --- a/src/pwmd_error.h +++ b/src/pwmd_error.h @@ -25,6 +25,7 @@ #define EPWMD_MAX_SLOTS GPG_ERR_USER_2 #define EPWMD_ELEMENT_NOT_FOUND GPG_ERR_USER_3 #define EPWMD_TRAILING_ELEMENT GPG_ERR_USER_4 /* no longer used */ +#define EPWMD_LOOP GPG_ERR_USER_4 #define EPWMD_INVALID_ELEMENT GPG_ERR_USER_5 #define EPWMD_EMPTY_ELEMENT GPG_ERR_USER_6 #define EPWMD_ACCOUNT_EXISTS GPG_ERR_USER_7 diff --git a/src/xml.c b/src/xml.c index 14177ee4..4b6bd478 100644 --- a/src/xml.c +++ b/src/xml.c @@ -34,6 +34,7 @@ #include "pwmd_error.h" #include "xml.h" +#include "common.h" void log_write(const gchar *fmt, ...); gboolean strv_printf(gchar ***array, const gchar *fmt, ...); @@ -334,8 +335,16 @@ xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *error, gint depth = 0; gchar *account = g_strdup(*req[0]); gboolean literal = is_literal_element(&account); + static int recursion_depth; *error = 0; + recursion_depth++; + + if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth) { + recursion_depth--; + *error = EPWMD_LOOP; + return NULL; + } for (n = doc->children; n;) { if (n->type == XML_ELEMENT_NODE) { @@ -356,6 +365,7 @@ xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *error, if (literal == TRUE) { g_free(account); + recursion_depth--; return n; } @@ -363,6 +373,7 @@ xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *error, if (!content) { g_free(account); + recursion_depth--; return n; } @@ -387,7 +398,9 @@ xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *error, *target = TRUE; g_free(account); - return find_account(doc, req, error, target); + n = find_account(doc, req, error, target); + recursion_depth--; + return n; } } } @@ -397,6 +410,7 @@ xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *error, g_free(account); *error = EPWMD_ELEMENT_NOT_FOUND; + recursion_depth--; return NULL; } @@ -455,8 +469,16 @@ xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node, xmlNodePtr n, last, last_node; gchar **p; gint found = 0; + static int recursion_depth; *error = 0; + recursion_depth++; + + if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth) { + recursion_depth--; + *error = EPWMD_LOOP; + return NULL; + } for (last_node = last = n = node, p = req; *p; p++) { xmlNodePtr tmp; @@ -467,6 +489,8 @@ xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node, g_free(t); if (!n) { + recursion_depth--; + if (not_found_fn) return not_found_fn(found ? last_node : last_node->parent, p, error, data); @@ -490,12 +514,14 @@ xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node, if (strchr((gchar *)content, '\t') != NULL) { if ((nreq = split_input_line((gchar *)content, "\t", 0)) == NULL) { *error = EPWMD_INVALID_ELEMENT; + recursion_depth--; return NULL; } } else { if ((nreq = split_input_line((gchar *)content, " ", 0)) == NULL) { *error = EPWMD_INVALID_ELEMENT; + recursion_depth--; return NULL; } } @@ -504,6 +530,7 @@ xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node, if (!tmp) { g_strfreev(nreq); + recursion_depth--; return NULL; } @@ -517,6 +544,7 @@ xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node, if (nnreq) g_strfreev(nnreq); + recursion_depth--; return tmp; } @@ -539,10 +567,12 @@ xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node, } g_strfreev(nnreq); + recursion_depth--; return n; } } + recursion_depth--; return n; } -- 2.11.4.GIT