Fix parse_doc() to return GPG_ERR_BAD_DATA upon failure.
[pwmd.git] / src / xml.c
blobd17571092960e4b65fe7d097c5144a45555a94e7
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <err.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <libxml/xmlwriter.h>
34 #ifndef _
35 #include "gettext.h"
36 #define _(msgid) gettext(msgid)
37 #endif
39 #include "pwmd-error.h"
40 #include "util-misc.h"
41 #include "xml.h"
42 #include "mem.h"
43 #include "rcfile.h"
45 extern void log_write (const char *fmt, ...);
48 * 'element' must be allocated.
50 int
51 is_literal_element (char **element)
53 char *p;
55 if (!element || !*element)
56 return 0;
58 if (*(*element) == '!')
60 char *c;
62 for (p = *element, c = p + 1; *c; c++)
63 *p++ = *c;
65 *p = 0;
66 return 1;
69 return 0;
72 int
73 valid_xml_attribute (const char *str)
75 const char *p;
77 for (p = str; *p; p++)
79 if (!isascii (*p))
80 return 0;
83 return 1;
86 int
87 valid_xml_element (xmlChar * element)
89 char *p = (char *) element;
91 if (!element || !*element || *element == '!')
92 return 0;
94 for (; *p; p++)
96 if (isspace (*p))
97 return 0;
100 return 1;
104 valid_element_path (char **path, int with_content)
106 char **dup = NULL, **p;
107 int i, t;
109 if (!path || !*path)
110 return 0;
112 /* Save some memory by not duplicating the element content. */
113 if (with_content)
115 t = strv_length (path);
116 for (i = 0; i < t - 1; i++)
118 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
120 if (!tmp)
122 strv_free (dup);
123 return 0;
126 dup = tmp;
127 dup[i] = str_dup (path[i]);
128 dup[i + 1] = NULL;
131 else
132 dup = strv_dup (path);
134 if (!dup)
135 return 0;
137 for (p = dup; *p && *(*p); p++)
139 is_literal_element (&(*p));
140 if (!valid_xml_element ((xmlChar *) * p))
142 strv_free (dup);
143 return 0;
147 strv_free (dup);
148 return 1;
151 gpg_error_t
152 attr_ctime (xmlNodePtr n)
154 char *buf = str_asprintf ("%li", time (NULL));
155 gpg_error_t rc;
157 if (!buf)
158 return GPG_ERR_ENOMEM;
160 rc = add_attribute (n, "_ctime", buf);
161 xfree (buf);
162 return rc;
165 static gpg_error_t
166 create_new_element (xmlNodePtr parent, const char *name, xmlNodePtr * result)
168 xmlNodePtr n = xmlNewNode (NULL, (xmlChar *) "element");
169 gpg_error_t rc;
171 if (!n)
172 return GPG_ERR_ENOMEM;
174 rc = add_attribute (n, "_name", name);
175 if (!rc)
176 rc = attr_ctime (n);
178 if (!rc)
180 if (result)
181 *result = xmlAddChild (parent, n);
182 else
183 (void) xmlAddChild (parent, n);
185 else
186 xmlFreeNode (n);
188 return rc;
191 gpg_error_t
192 new_root_element (xmlDocPtr doc, char *name)
194 xmlNodePtr root = xmlDocGetRootElement (doc);
195 char *p = name;
197 if (!p || !root)
198 return GPG_ERR_BAD_DATA;
200 if (*p == '!')
201 p++;
203 if (!valid_xml_element ((xmlChar *) p))
204 return GPG_ERR_INV_VALUE;
206 return create_new_element (root, p, NULL);
209 static xmlDocPtr
210 create_dtd ()
212 xmlDocPtr doc;
213 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
215 if (!wr)
216 return NULL;
218 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
219 goto fail;
221 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
222 goto fail;
224 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
225 (xmlChar *) "(element)") == -1)
226 goto fail;
228 xmlTextWriterEndDTDElement (wr);
230 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
231 (xmlChar *) "_name CDATA #REQUIRED") ==
233 goto fail;
235 xmlTextWriterEndDTDAttlist (wr);
236 xmlTextWriterEndDTD (wr);
238 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
239 goto fail;
241 xmlTextWriterEndElement (wr);
242 xmlTextWriterEndDocument (wr);
243 xmlFreeTextWriter (wr);
244 return doc;
246 fail:
247 xmlTextWriterEndDocument (wr);
248 xmlFreeTextWriter (wr);
249 xmlFreeDoc (doc);
250 return NULL;
253 xmlDocPtr
254 new_document ()
256 return create_dtd ();
259 xmlNodePtr
260 find_element_node (xmlNodePtr node)
262 xmlNodePtr n = node;
264 if (n && n->type == XML_ELEMENT_NODE)
265 return n;
267 for (n = node; n; n = n->next)
269 if (n->type == XML_ELEMENT_NODE)
270 return n;
273 return NULL;
276 static xmlNodePtr
277 resolve_path (xmlDocPtr doc, xmlChar * path, char ***result, gpg_error_t * rc)
279 xmlNodePtr n;
280 char **req;
282 req = str_split ((char *) path, "\t", 0);
283 if (!req)
285 *rc = GPG_ERR_ENOMEM;
286 return NULL;
289 n = find_root_element (doc, &req, rc, NULL, 0, 0);
290 if (!n)
292 strv_free (req);
293 return NULL;
296 if (req[1])
297 n = find_elements (doc, n->children, req + 1, rc, NULL, NULL, NULL,
298 0, 0, NULL, 0);
300 if (*rc)
301 strv_free (req);
302 else
303 *result = req;
305 return n;
309 * Lists root element names; the value of the attribute "_name" of an element
310 * "element". If there's a target attribute both literal and non-literal
311 * element names will be added. This is the primary reason why XML entities
312 * cannot be used. There wouldn't be a way to get the literal an non-literal
313 * element paths.
315 gpg_error_t
316 list_root_elements (xmlDocPtr doc, struct string_s ** result,
317 int verbose, int with_target)
319 xmlNodePtr n = NULL;
320 struct slist_s *list = NULL;
321 int total, i;
322 struct string_s *string;
323 gpg_error_t rc = 0;
325 n = xmlDocGetRootElement (doc);
326 if (!n || !n->children)
327 return GPG_ERR_NO_DATA;
329 for (n = n->children; n; n = n->next)
331 xmlAttrPtr a;
332 xmlChar *val, *target;
333 struct slist_s *tlist;
334 char *tmp;
336 if (n->type != XML_ELEMENT_NODE)
337 continue;
339 a = xmlHasProp (n, (xmlChar *) "_name");
340 if (!a || !a->children->content)
341 continue;
343 val = xmlNodeGetContent (a->children);
344 if (!val)
346 rc = GPG_ERR_ENOMEM;
347 goto fail;
350 tmp =
351 str_asprintf ("!%s%s", (char *) val,
352 verbose ? find_element_node (n->children) ? " +" : "" :
353 "");
355 if (!tmp)
357 xmlFree (val);
358 rc = GPG_ERR_ENOMEM;
359 goto fail;
362 tlist = slist_append (list, tmp);
363 if (!tlist)
365 xmlFree (val);
366 rc = GPG_ERR_ENOMEM;
367 goto fail;
370 list = tlist;
371 target = node_has_attribute (n, (xmlChar *) "target");
372 if (target)
374 char *t = NULL;
376 if (verbose)
378 char **req = NULL;
379 xmlNodePtr tnode = resolve_path (doc, target, &req, &rc);
381 if (rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP)
383 t = str_asprintf ("%s %s", (char *) val,
384 rc == GPG_ERR_ELOOP ? "O" : "E");
385 rc = 0;
387 else if (!rc)
389 struct string_s *realpath = NULL;
391 if (with_target)
393 rc = build_realpath (doc, (char *) target, &realpath);
394 if (rc)
396 strv_free (req);
397 xmlFree (val);
398 xmlFree (target);
399 goto fail;
402 realpath = string_prepend (realpath, "T ");
405 t = str_asprintf ("%s%s%s%s", (char *) val,
406 (tnode
407 && find_element_node (tnode->children))
408 || realpath ? " " : "", tnode
409 && find_element_node (tnode->children) ?
410 "+" : "", realpath ? realpath->str : "");
412 if (realpath)
413 string_free (realpath, 1);
416 if (req)
417 strv_free (req);
419 else
420 t = str_dup ((char *) val);
422 if (!t || rc)
424 xmlFree (val);
425 xmlFree (target);
426 rc = rc ? rc : GPG_ERR_ENOMEM;
427 goto fail;
430 tlist = slist_append (list, t);
431 if (!tlist)
433 xmlFree (val);
434 xfree (t);
435 xmlFree (target);
436 rc = GPG_ERR_ENOMEM;
437 goto fail;
440 list = tlist;
443 xmlFree (val);
444 xmlFree (target);
447 total = slist_length (list);
448 if (!total)
449 return GPG_ERR_NO_DATA;
451 string = string_new (NULL);
452 if (!string)
454 rc = GPG_ERR_ENOMEM;
455 goto fail;
458 for (i = 0; i < total; i++)
460 char *val = slist_nth_data (list, i);
462 string_append_printf (string, "%s\n", val);
465 string = string_truncate (string, string->len - 1);
466 *result = string;
468 fail:
469 total = slist_length (list);
470 for (i = 0; i < total; i++)
471 xfree (slist_nth_data (list, i));
473 slist_free (list);
474 return rc;
478 * Prevents a sibling element past the current element path with the same
479 * element name.
481 static xmlNodePtr
482 find_stop_node (xmlNodePtr node)
484 xmlNodePtr n;
486 for (n = node->parent->children; n; n = n->next)
488 if (n == node)
489 return n->next;
492 return NULL;
495 xmlNodePtr
496 create_target_elements_cb (xmlNodePtr node, char **path,
497 gpg_error_t * rc, void *data)
499 int i;
500 char **req = path;
501 xmlNodePtr parent = data;
503 for (i = 0; req[i] && *req[i]; i++)
505 xmlNodePtr n;
507 if (parent && node == parent)
509 *rc = GPG_ERR_CONFLICT;
510 return NULL;
513 is_literal_element (&req[i]);
515 if ((n = find_element (node, req[i], find_stop_node (node))) == NULL ||
516 (n && n->parent == node->parent))
519 *rc = create_new_element (node, req[i], &node);
520 if (*rc)
521 return NULL;
523 else
524 node = n;
527 return node;
530 xmlNodePtr
531 find_text_node (xmlNodePtr node)
533 xmlNodePtr n = node;
535 if (n && n->type == XML_TEXT_NODE)
536 return n;
538 for (n = node; n; n = n->next)
540 if (n->type == XML_TEXT_NODE)
541 return n;
544 return NULL;
547 xmlNodePtr
548 create_elements_cb (xmlNodePtr node, char **elements,
549 gpg_error_t * rc, void *data)
551 int i;
552 char **req = elements;
554 if (node->type == XML_TEXT_NODE)
555 node = node->parent;
557 for (i = 0; req[i] && *req[i]; i++)
559 xmlNodePtr n;
562 * Strip the first '!' if needed. If there's another, it's an
563 * rc. The syntax has already been checked before calling this
564 * function.
566 is_literal_element (&req[i]);
567 n = find_element (node, req[i], find_stop_node (node));
570 * If the found element has the same parent as the current element,
571 * they are siblings and the new element needs to be created as a
572 * child of the current element (node).
574 if (n && n->parent == node->parent)
575 n = NULL;
577 if (!n)
579 *rc = create_new_element (node, req[i], &node);
580 if (*rc)
581 return NULL;
583 else
584 node = n;
587 return node;
590 /* The root element is really req[0]. It is need as a pointer in case there is
591 * a target attribute so it can be updated. */
592 xmlNodePtr
593 find_root_element (xmlDocPtr doc, char ***req, gpg_error_t * rc,
594 int *target, int recursion_depth, int stop)
596 xmlNodePtr n = xmlDocGetRootElement (doc);
597 int depth = 0;
598 char *root = str_dup (*req[0]);
599 int literal = is_literal_element (&root);
601 if (!root)
603 *rc = GPG_ERR_ENOMEM;
604 return NULL;
607 *rc = 0;
608 recursion_depth++;
610 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
612 xmlChar *t = xmlGetNodePath (n);
614 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
615 xmlFree (t);
616 xfree (root);
617 *rc = GPG_ERR_ELOOP;
618 return NULL;
621 while (n)
623 if (n->type == XML_ELEMENT_NODE)
625 if (depth == 0 && xmlStrEqual (n->name, (xmlChar *) "pwmd"))
627 n = n->children;
628 depth++;
629 continue;
632 if (depth == 1 && xmlStrEqual (n->name, (xmlChar *) "element"))
634 xmlChar *content = node_has_attribute (n, (xmlChar *) "_name");
636 if (!content)
637 continue;
639 if (xmlStrEqual (content, (xmlChar *) root))
641 char **nreq, **tmp = NULL;
643 if (literal == 1)
645 xmlFree (content);
646 xfree (root);
647 return n;
650 xmlFree (content);
651 content = node_has_attribute (n, (xmlChar *) "target");
653 if (target)
654 *target = 1;
656 if (!content || stop)
658 if (content)
659 xmlFree (content);
661 xfree (root);
662 return n;
665 if (strchr ((char *) content, '\t'))
667 nreq = str_split ((char *) content, "\t", 0);
668 xmlFree (content);
670 #if 0
672 * FIXME ENOMEM
674 if (!nreq)
676 *rc = GPG_ERR_ENOMEM;
677 return NULL;
679 #endif
681 tmp = *req;
682 tmp = strv_catv (nreq, tmp + 1);
683 strv_free (nreq);
685 if (!tmp)
687 xfree (root);
688 *rc = GPG_ERR_ENOMEM;
689 return NULL;
692 strv_free (*req);
693 *req = tmp;
695 else
697 if (strv_printf (&tmp, "%s", content) == 0)
699 xmlFree (content);
700 xfree (root);
701 *rc = GPG_ERR_ENOMEM;
702 return NULL;
705 xmlFree (content);
706 nreq = *req;
707 nreq = strv_catv (tmp, nreq + 1);
708 strv_free (tmp);
710 if (!nreq)
712 *rc = GPG_ERR_ENOMEM;
713 xfree (root);
714 return NULL;
717 strv_free (*req);
718 *req = nreq;
721 xfree (root);
723 find_root_element (doc, req, rc, target, recursion_depth,
725 return n;
728 xmlFree (content);
732 n = n->next;
735 xfree (root);
736 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
737 return NULL;
740 xmlNodePtr
741 find_element (xmlNodePtr node, char *element, xmlNodePtr stop)
743 xmlNodePtr n;
745 if (!node || !element)
746 return NULL;
748 for (n = node; n; n = n->next)
750 if (n->type != XML_ELEMENT_NODE)
751 continue;
753 if (n == stop)
754 break;
756 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
758 if (a && xmlStrEqual (a, (xmlChar *) element))
760 xmlFree (a);
761 return n;
764 xmlFree (a);
767 return NULL;
770 xmlChar *
771 node_has_attribute (xmlNodePtr n, xmlChar * attr)
773 xmlAttrPtr a = xmlHasProp (n, attr);
775 if (!a)
776 return NULL;
778 if (!a->children || !a->children->content)
779 return NULL;
781 return xmlGetProp (n, attr);
784 static int
785 element_to_literal (char **element)
787 char *p = str_asprintf ("!%s", *element);
789 if (!p)
790 return 0;
792 xfree (*element);
793 *element = p;
794 return 1;
797 /* Resolves elements in 'req' one at a time. It's recursive in case of
798 * "target" attributes. */
799 xmlNodePtr
800 find_elements (xmlDocPtr doc, xmlNodePtr node,
801 char **req, gpg_error_t * rc, int *target,
802 xmlNodePtr (*found_fn) (xmlNodePtr, char **, gpg_error_t *,
803 char **, void *),
804 xmlNodePtr (*not_found_fn) (xmlNodePtr, char **, gpg_error_t *,
805 void *), int is_list_command,
806 int recursion_depth, void *data, int stop)
808 xmlNodePtr n, last, last_node;
809 char **p;
810 int found = 0;
812 *rc = 0;
813 recursion_depth++;
815 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
817 xmlChar *t = xmlGetNodePath (node);
819 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
820 xmlFree (t);
821 recursion_depth--;
822 *rc = GPG_ERR_ELOOP;
823 return NULL;
826 for (last_node = last = n = node, p = req; *p; p++)
828 xmlNodePtr tmp;
829 char *t;
830 int literal;
832 if (!*(*p))
834 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
835 return NULL;
838 t = str_dup (*p);
839 if (!t)
841 *rc = GPG_ERR_ENOMEM;
842 return NULL;
845 literal = is_literal_element (&t);
846 n = find_element (last, t, NULL);
847 xfree (t);
849 if (!n)
851 if (not_found_fn)
852 return not_found_fn (found ? last_node : last_node->parent, p, rc,
853 data);
855 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
856 return NULL;
859 last = n->children;
860 last_node = n;
861 found = 1;
863 if (literal == 0)
865 xmlChar *content = node_has_attribute (n, (xmlChar *) "target");
866 char **nreq = NULL, **nnreq;
868 if (!content)
870 if (is_list_command == 1)
872 if (element_to_literal (&(*p)) == 0)
874 *rc = GPG_ERR_ENOMEM;
875 return NULL;
879 continue;
882 if (target)
883 *target = 1;
885 if (!*(p + 1) && stop)
887 xmlFree (content);
888 return n;
891 if (strchr ((char *) content, '\t') != NULL)
893 if ((nreq = str_split ((char *) content, "\t", 0)) == NULL)
895 xmlFree (content);
896 *rc = GPG_ERR_INV_VALUE;
897 return NULL;
900 else
902 if ((nreq = str_split ((char *) content, " ", 0)) == NULL)
904 xmlFree (content);
905 *rc = GPG_ERR_INV_VALUE;
906 return NULL;
910 xmlFree (content);
911 tmp = find_root_element (doc, &nreq, rc, target, 0, 0);
913 if (!tmp)
915 strv_free (nreq);
916 return NULL;
919 if (found_fn)
921 found_fn (tmp, nreq, rc, p + 1, data);
923 if (*rc)
925 strv_free (nreq);
926 return NULL;
930 if (!*(nreq + 1) && !*(p + 1))
932 strv_free (nreq);
933 return tmp;
936 nnreq = strv_catv (nreq + 1, p + 1);
937 strv_free (nreq);
939 // FIXME ENOMEM
940 if (!nnreq || !*nnreq)
942 if (nnreq)
943 strv_free (nnreq);
945 return tmp;
948 if (tmp->children)
949 n = find_elements (doc, tmp->children, nnreq, rc, NULL, found_fn,
950 not_found_fn, is_list_command, recursion_depth,
951 data, stop);
952 else
954 strv_free (nnreq);
956 if (not_found_fn)
957 return not_found_fn (tmp, p + 1, rc, data);
959 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
960 return NULL;
963 if (*(p + 1))
965 char **zz = p + 1, **qq = nnreq;
967 if (strv_length (nnreq) > strv_length (p + 1))
968 qq = nnreq + 1;
970 for (; *qq && *zz; zz++)
972 xfree (*zz);
973 *zz = str_dup (*qq++);
975 if (!*zz)
977 *rc = GPG_ERR_ENOMEM;
978 n = NULL;
979 break;
984 strv_free (nnreq);
985 return n;
989 return n;
992 static int
993 update_element_list (struct element_list_s *elements)
995 char *line;
996 struct slist_s *l;
998 if (!elements || !elements->elements)
999 return 1;
1001 line = strv_join ("\t", elements->elements);
1003 if (!line)
1004 return 0;
1006 strv_free (elements->elements);
1007 elements->elements = NULL;
1008 l = slist_append (elements->list, line);
1010 if (!l)
1011 return 0;
1013 elements->list = l;
1014 return 1;
1017 static gpg_error_t
1018 path_list_recurse (xmlDocPtr doc, xmlNodePtr node,
1019 struct element_list_s *elements)
1021 gpg_error_t rc = 0;
1022 xmlNodePtr n;
1023 gpg_error_t error_flag = 0;
1025 for (n = node; n; n = n->next)
1027 xmlChar *target = NULL;
1028 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
1029 int err = 0;
1031 if (!a)
1032 continue;
1034 if (n->type != XML_ELEMENT_NODE)
1035 goto children;
1037 if (elements->verbose)
1039 if (strv_printf
1040 (&elements->elements, "%s\t!%s%s", elements->prefix, a,
1041 find_element_node (n->children) ? " +" : "") == 0)
1043 xmlFree (a);
1044 return GPG_ERR_ENOMEM;
1047 else
1048 if (strv_printf (&elements->elements, "%s\t!%s", elements->prefix, a)
1049 == 0)
1051 xmlFree (a);
1052 return GPG_ERR_ENOMEM;
1055 if (update_element_list (elements) == 0)
1057 xmlFree (a);
1058 return GPG_ERR_ENOMEM;
1061 target = node_has_attribute (n, (xmlChar *) "target");
1063 if (target)
1065 char *tmp;
1066 char *save = elements->prefix;
1067 int r = elements->resolving;
1068 char **req = NULL;
1069 xmlNodePtr tnode;
1070 struct string_s *realpath = NULL;
1072 tnode = resolve_path (doc, target, &req, &rc);
1073 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_ELEMENT_NOT_FOUND)
1075 if (rc == GPG_ERR_ELOOP)
1077 xmlChar *t = xmlGetNodePath (n);
1079 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1080 xmlFree (t);
1083 if (elements->verbose)
1085 strv_printf (&elements->elements, "%s\t%s %s",
1086 elements->prefix, a,
1087 rc == GPG_ERR_ELOOP ? "O" : "E");
1088 error_flag = err = rc;
1089 rc = 0;
1090 goto update;
1094 if (!elements->verbose && rc)
1096 xmlFree (a);
1097 xmlFree (target);
1098 return rc;
1101 if (elements->with_target)
1103 rc = build_realpath (doc, (char *) target, &realpath);
1104 if (rc)
1106 xmlFree (a);
1107 xmlFree (target);
1108 return rc;
1111 realpath = string_prepend (realpath, "T ");
1114 if (elements->verbose)
1116 if (!strv_printf (&elements->elements, "%s\t%s%s%s%s",
1117 elements->prefix, a,
1118 (tnode && find_element_node (tnode->children))
1119 || realpath ? " " : "", tnode
1120 && find_element_node (tnode->children) ? "+" :
1121 "", realpath ? realpath->str : ""))
1123 xmlFree (a);
1124 xmlFree (target);
1125 return GPG_ERR_ENOMEM;
1128 else
1129 if (!strv_printf
1130 (&elements->elements, "%s\t%s", elements->prefix, a))
1132 xmlFree (a);
1133 xmlFree (target);
1134 return GPG_ERR_ENOMEM;
1137 update:
1138 if (realpath)
1139 string_free (realpath, 1);
1141 tmp = strv_join ("\t", elements->elements);
1143 if (!tmp)
1145 xmlFree (a);
1146 xmlFree (target);
1147 return GPG_ERR_ENOMEM;
1150 if (update_element_list (elements) == 0)
1152 xfree (tmp);
1153 xmlFree (a);
1154 xmlFree (target);
1155 return GPG_ERR_ENOMEM;
1158 if (!err && elements->recurse)
1160 /* Prune element flags. */
1161 if (elements->verbose && strchr (tmp, ' '))
1163 char *p;
1165 for (p = tmp; *p; p++)
1167 if (*p == ' ')
1169 *p = 0;
1170 break;
1175 elements->prefix = tmp;
1176 elements->resolving = 1;
1177 rc = create_path_list (doc, elements, (char *) target);
1178 elements->resolving = r;
1179 elements->prefix = save;
1181 if (rc && gpg_err_code (rc) != GPG_ERR_ELOOP)
1183 xfree (tmp);
1184 xmlFree (target);
1185 xmlFree (a);
1186 return rc;
1189 error_flag = err = rc;
1190 rc = 0;
1193 xfree (tmp);
1194 xmlFree (target);
1197 children:
1198 if (n->children && elements->recurse && err != GPG_ERR_ELOOP)
1200 char *tmp = str_asprintf ("%s\t!%s", elements->prefix, a);
1201 char *save = elements->prefix;
1203 if (!tmp)
1205 xmlFree (a);
1206 return GPG_ERR_ENOMEM;
1209 elements->prefix = tmp;
1210 rc = path_list_recurse (doc, n->children, elements);
1211 xfree (elements->prefix);
1212 elements->prefix = save;
1214 if (rc)
1216 xmlFree (a);
1217 return rc;
1221 xmlFree (a);
1224 return error_flag == GPG_ERR_ELOOP ? error_flag : rc;
1227 gpg_error_t
1228 add_attribute (xmlNodePtr node, const char *name, const char *value)
1230 char *buf;
1231 gpg_error_t rc;
1233 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
1234 return GPG_ERR_BAD_DATA;
1236 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
1237 return 0;
1239 buf = str_asprintf ("%li", time (NULL));
1240 rc = add_attribute (node, "_mtime", buf);
1241 xfree (buf);
1242 return rc;
1246 * From the element path 'path', find sub-nodes and append them to the list.
1248 gpg_error_t
1249 create_path_list (xmlDocPtr doc, struct element_list_s * elements, char *path)
1251 gpg_error_t rc;
1252 char **req, **req_orig;
1253 xmlNodePtr n;
1254 int a_target = 0;
1256 req = str_split (path, "\t", 0);
1257 if (!req)
1259 req = str_split (path, " ", 0);
1260 if (!req)
1261 return GPG_ERR_SYNTAX;
1264 req_orig = strv_dup (req);
1265 if (!req_orig)
1267 rc = GPG_ERR_ENOMEM;
1268 goto fail;
1271 n = find_root_element (doc, &req, &rc, &a_target, 0, 0);
1272 if ((rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP)
1273 && elements->verbose && a_target)
1275 rc = 0;
1276 goto done;
1279 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1281 rc = 0;
1282 goto fail;
1284 else if (!n)
1285 goto fail;
1287 if (a_target == 1)
1289 xfree (*req);
1290 *req = str_dup (*req_orig);
1293 if (*(req + 1))
1295 int e_target = 0;
1298 find_elements (doc, n->children, req + 1, &rc, &e_target, NULL, NULL,
1299 1, 0, NULL, 0);
1301 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1303 rc = 0;
1304 goto fail;
1306 else if (!n)
1307 goto fail;
1310 done:
1311 if (!elements->prefix)
1314 * FIXME
1316 * If any req_orig element contains no target the element should be
1317 * prefixed with the literal character. Not really crucial if the
1318 * client isn't human because child elements are prefixed for the
1319 * current path. But may be confusing if editing by hand.
1321 elements->prefix = strv_join ("\t", req_orig);
1323 if (!elements->prefix)
1325 rc = GPG_ERR_ENOMEM;
1326 goto fail;
1329 if (elements->verbose)
1331 int ret;
1332 struct string_s *realpath = NULL;
1334 if (a_target && elements->with_target)
1336 rc = build_realpath (doc, path, &realpath);
1337 if (rc)
1338 goto fail;
1340 realpath = string_prepend (realpath, "T ");
1343 ret = strv_printf (&elements->elements, "%s%s%s%s",
1344 elements->prefix,
1345 find_element_node (n->children)
1346 || realpath ? " " : "",
1347 find_element_node (n->children) ? "+" : "",
1348 realpath ? realpath->str : "");
1349 string_free (realpath, 1);
1350 if (!ret)
1352 rc = GPG_ERR_ENOMEM;
1353 goto fail;
1356 else if (strv_printf (&elements->elements, "%s", elements->prefix) == 0)
1358 rc = GPG_ERR_ENOMEM;
1359 goto fail;
1362 if (update_element_list (elements) == 0)
1364 rc = GPG_ERR_ENOMEM;
1365 goto fail;
1369 rc = path_list_recurse (doc, n->children, elements);
1371 fail:
1372 if (req_orig)
1373 strv_free (req_orig);
1375 strv_free (req);
1376 return rc;
1379 gpg_error_t
1380 recurse_xpath_nodeset (xmlDocPtr doc, xmlNodeSetPtr nodes,
1381 xmlChar * value, xmlBufferPtr * result, int cmd,
1382 const xmlChar * attr)
1384 int i = value ? nodes->nodeNr - 1 : 0;
1385 xmlBufferPtr buf;
1387 buf = xmlBufferCreate ();
1389 if (!buf)
1390 return GPG_ERR_ENOMEM;
1392 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
1394 xmlNodePtr n = nodes->nodeTab[i];
1395 gpg_error_t rc;
1397 if (!n)
1398 continue;
1400 if (!value && !attr)
1402 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
1404 *result = buf;
1405 return GPG_ERR_BAD_DATA;
1408 continue;
1411 if (!attr)
1413 xmlNodeSetContent (n, value);
1414 rc = update_element_mtime (n);
1416 if (rc)
1417 return rc;
1419 else
1421 if (!cmd)
1422 rc = add_attribute (n, (char *) attr, (char *) value);
1423 else
1424 rc = delete_attribute (n, attr);
1426 if (rc)
1427 return rc;
1431 *result = buf;
1432 return 0;
1435 static gpg_error_t
1436 convert_root_element (xmlNodePtr n)
1438 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1439 gpg_error_t rc;
1441 if (a)
1443 xmlFree (a);
1444 xmlChar *t = xmlGetNodePath (n);
1446 log_write (_
1447 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1449 xmlFree (t);
1450 return GPG_ERR_AMBIGUOUS_NAME;
1453 a = xmlGetProp (n, (xmlChar *) "name");
1455 if (a)
1457 rc = add_attribute (n, "_name", (char *) a);
1458 xmlFree (a);
1460 if (rc)
1461 return rc;
1463 rc = delete_attribute (n, (xmlChar *) "name");
1465 if (rc)
1466 return rc;
1468 xmlNodeSetName (n, (xmlChar *) "element");
1471 return 0;
1474 gpg_error_t
1475 delete_attribute (xmlNodePtr n, const xmlChar * name)
1477 xmlAttrPtr a;
1479 if ((a = xmlHasProp (n, name)) == NULL)
1480 return GPG_ERR_NOT_FOUND;
1482 if (xmlRemoveProp (a) == -1)
1483 return GPG_ERR_BAD_DATA;
1485 return update_element_mtime (n);
1488 static gpg_error_t
1489 convert_elements_recurse (xmlDocPtr doc, xmlNodePtr n, unsigned depth)
1491 gpg_error_t rc;
1493 depth++;
1495 for (n = n->children; n; n = n->next)
1497 if (n->type == XML_ELEMENT_NODE)
1499 xmlChar *a = NULL;
1501 if (depth > 1)
1503 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1505 xmlChar *t = xmlGetNodePath (n);
1507 log_write (_
1508 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1510 xmlFree (t);
1511 return GPG_ERR_AMBIGUOUS_NAME;
1514 a = xmlGetProp (n, (xmlChar *) "_name");
1516 if (a)
1518 xmlFree (a);
1519 xmlChar *t = xmlGetNodePath (n);
1521 log_write (_
1522 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1524 xmlFree (t);
1525 return GPG_ERR_AMBIGUOUS_NAME;
1528 xmlChar *tmp = xmlStrdup (n->name);
1530 if (!tmp)
1531 return GPG_ERR_ENOMEM;
1533 xmlNodeSetName (n, (xmlChar *) "element");
1534 rc = add_attribute (n, "_name", (char *) tmp);
1535 xmlFree (tmp);
1537 if (rc)
1538 return rc;
1540 else
1542 rc = convert_root_element (n);
1544 if (rc)
1545 return rc;
1549 if (n->children)
1551 rc = convert_elements_recurse (doc, n, depth);
1553 if (rc)
1554 return rc;
1558 return 0;
1561 /* Renames ALL elements to the new "element" name. Existing element names are
1562 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1563 * elements can contain common characters that the XML parser barfs on (an
1564 * email address for example. */
1565 gpg_error_t
1566 convert_pre_212_elements (xmlDocPtr doc)
1568 xmlNodePtr n = xmlDocGetRootElement (doc);
1570 log_write (_("Converting pre 2.12 data file..."));
1571 return convert_elements_recurse (doc, n, 0);
1574 gpg_error_t
1575 validate_import (xmlNodePtr node)
1577 gpg_error_t rc = 0;
1579 if (!node)
1580 return 0;
1582 for (xmlNodePtr n = node; n; n = n->next)
1584 if (n->type == XML_ELEMENT_NODE)
1586 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1588 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1590 if (!a)
1592 xmlChar *t = xmlGetNodePath (n);
1594 log_write (_("Missing attribute '_name' at %s."), t);
1595 xmlFree (t);
1596 return GPG_ERR_INV_VALUE;
1599 if (!valid_xml_element (a))
1601 xmlChar *t = xmlGetNodePath (n);
1603 log_write (_("'%s' is not a valid element name at %s."), a,
1605 xmlFree (a);
1606 xmlFree (t);
1607 return GPG_ERR_INV_VALUE;
1610 xmlFree (a);
1611 a = xmlGetProp (n, (xmlChar *) "_ctime");
1612 if (!a)
1613 attr_ctime (n);
1615 xmlFree (a);
1616 a = xmlGetProp (n, (xmlChar *) "_mtime");
1617 if (!a)
1618 update_element_mtime (n);
1619 xmlFree (a);
1621 else
1623 xmlChar *t = xmlGetNodePath (n);
1625 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1626 n->name, t);
1627 xmlFree (t);
1628 continue;
1632 if (n->children)
1634 rc = validate_import (n->children);
1636 if (rc)
1637 return rc;
1641 return rc;
1644 gpg_error_t
1645 update_element_mtime (xmlNodePtr n)
1647 return add_attribute (n, NULL, NULL);
1650 gpg_error_t
1651 unlink_node (xmlNodePtr n)
1653 gpg_error_t rc = 0;
1655 if (!n)
1656 return rc;
1658 if (n->parent)
1659 rc = update_element_mtime (n->parent);
1661 xmlUnlinkNode (n);
1662 return rc;
1665 gpg_error_t
1666 parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1668 xmlDocPtr doc;
1670 xmlResetLastError ();
1671 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1672 if (!doc && xmlGetLastError ())
1673 return GPG_ERR_BAD_DATA;
1675 *result = doc;
1676 return !doc ? GPG_ERR_ENOMEM : 0;
1679 static xmlNodePtr
1680 realpath_elements_cb (xmlNodePtr node, char **target,
1681 gpg_error_t * rc, char **req_orig, void *data)
1683 char *path = *(char **) data;
1684 char *tmp = NULL, *result;
1686 if (path)
1688 xfree (path);
1689 *(char **) data = NULL;
1692 path = strv_join ("\t", target);
1694 if (!path)
1696 *rc = GPG_ERR_ENOMEM;
1697 return NULL;
1700 if (req_orig)
1702 tmp = strv_join ("\t", req_orig);
1704 if (!tmp)
1706 xfree (path);
1707 *rc = GPG_ERR_ENOMEM;
1708 return NULL;
1712 if (tmp && *tmp)
1713 result = str_asprintf ("%s\t%s", path, tmp);
1714 else
1715 result = str_dup (path);
1717 if (!result)
1719 *rc = GPG_ERR_ENOMEM;
1720 xfree (path);
1721 xfree (tmp);
1722 return NULL;
1725 xfree (path);
1726 xfree (tmp);
1727 *(char **) data = result;
1728 return node;
1731 gpg_error_t
1732 build_realpath (xmlDocPtr doc, char *line, struct string_s ** result)
1734 gpg_error_t rc;
1735 char **req;
1736 char *t;
1737 int i;
1738 xmlNodePtr n;
1739 struct string_s *string;
1740 char *rp = NULL;
1742 if (strchr (line, '\t') != NULL)
1744 if ((req = str_split (line, "\t", 0)) == NULL)
1745 return GPG_ERR_SYNTAX;
1747 else
1749 if ((req = str_split (line, " ", 0)) == NULL)
1750 return GPG_ERR_SYNTAX;
1753 n = find_root_element (doc, &req, &rc, NULL, 0, 0);
1754 if (!n)
1756 strv_free (req);
1757 return rc;
1760 rp = strv_join ("\t", req);
1761 if (!rp)
1763 strv_free (req);
1764 return GPG_ERR_ENOMEM;
1767 if (req[1])
1769 n = find_elements (doc, n->children, req + 1, &rc,
1770 NULL, realpath_elements_cb, NULL, 0, 0, &rp, 0);
1771 if (!n)
1773 xfree (rp);
1774 strv_free (req);
1775 return rc;
1779 string = string_new (rp);
1780 xfree (rp);
1781 strv_free (req);
1782 if (!string)
1783 return GPG_ERR_ENOMEM;
1785 again:
1786 for (i = 0, t = string->str + i; *t; t++, i++)
1788 if ((!i && *t != '!') || (*t == '\t' && *(t + 1) && *(t + 1) != '!'))
1790 struct string_s *s = string_insert_c (string, !i ? i++ : ++i, '!');
1792 if (!s)
1794 string_free (string, 1);
1795 return GPG_ERR_ENOMEM;
1798 string = s;
1799 goto again;
1803 *result = string;
1804 return rc;
1807 #if 0
1808 static char *
1809 node_to_element_path (xmlNodePtr node)
1811 xmlNodePtr n;
1812 struct string_s *str = string_new ("");
1813 char *result;
1815 for (n = node; n; n = n->parent)
1817 xmlNodePtr child;
1819 for (child = n; child; child = child->next)
1821 if (child->type != XML_ELEMENT_NODE)
1822 continue;
1824 xmlChar *name = node_has_attribute (n, (xmlChar *) "_name");
1825 if (name)
1827 str = string_prepend (str, (char *) name);
1828 xmlFree (name);
1829 name = node_has_attribute (n, (xmlChar *) "target");
1830 if (name)
1831 str = string_prepend (str, "\t");
1832 else
1833 str = string_prepend (str, "\t!");
1834 xmlFree (name);
1836 break;
1840 str = string_erase (str, 0, 1);
1841 result = str->str;
1842 string_free (str, 0);
1843 return result;
1845 #endif
1848 * Recurse the element tree beginning at 'node' and find elements who point
1849 * back to 'src' or 'dst'. Also follows target attributes.
1851 static gpg_error_t
1852 find_child_to_target (xmlDocPtr doc, xmlNodePtr node,
1853 xmlNodePtr src, xmlNodePtr dst, unsigned depth,
1854 int is_target)
1856 xmlNodePtr n;
1857 gpg_error_t rc = 0;
1859 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1860 return gpg_error (GPG_ERR_ELOOP);
1862 for (n = node; n; n = n->next)
1864 xmlChar *target;
1866 if (n->type != XML_ELEMENT_NODE)
1867 continue;
1869 if (n == src || n == dst)
1870 return GPG_ERR_ELOOP;
1872 target = node_has_attribute (n, (xmlChar *) "target");
1873 if (target)
1875 xmlNodePtr tmp;
1876 char **result = NULL;
1878 tmp = resolve_path (doc, target, &result, &rc);
1879 xmlFree (target);
1880 strv_free (result);
1881 if (!rc)
1883 rc = find_child_to_target (doc, tmp, src, dst, ++depth, 1);
1884 depth--;
1887 if (rc && gpg_err_code (rc) != GPG_ERR_ELEMENT_NOT_FOUND)
1888 return rc;
1890 if (is_target)
1891 break;
1893 continue;
1896 if (n->children)
1898 rc = find_child_to_target (doc, n->children, src, dst, ++depth,0);
1899 depth--;
1900 if (rc)
1901 return rc;
1904 if (is_target)
1905 break;
1908 return rc;
1911 static gpg_error_t
1912 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1914 xmlNodePtr n;
1915 gpg_error_t rc = 0;
1917 for (n = src; n; n = n->next)
1919 if (n->type != XML_ELEMENT_NODE)
1920 continue;
1922 if (n == dst)
1924 rc = GPG_ERR_ELOOP;
1925 break;
1928 rc = find_child_of_parent (doc, n->children, dst);
1931 return rc;
1934 static gpg_error_t
1935 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1937 xmlNodePtr n;
1938 gpg_error_t rc = 0;
1940 for (n = node; n; n = n->parent)
1942 if (n->type != XML_ELEMENT_NODE)
1944 xmlNodePtr tmp;
1946 for (tmp = n->next; tmp; n = n->next)
1948 if (n->type != XML_ELEMENT_NODE)
1949 continue;
1951 if (tmp == dst)
1952 return GPG_ERR_ELOOP;
1956 if (n == dst)
1957 return GPG_ERR_ELOOP;
1960 return rc;
1963 gpg_error_t
1964 validate_target_attribute (xmlDocPtr doc, const char *src,
1965 xmlNodePtr dst_node)
1967 gpg_error_t rc;
1968 xmlNodePtr src_node;
1969 char **src_req = NULL;
1971 src_node = resolve_path (doc, (xmlChar *) src, &src_req, &rc);
1972 if (rc)
1973 goto fail;
1975 /* A destination element is a child of the source element. */
1976 rc = find_child_of_parent (doc, src_node->children, dst_node);
1977 if (rc)
1978 goto fail;
1980 /* The destination element is a parent of the source element. */
1981 rc = find_parent_of_child (doc, src_node->parent, dst_node);
1982 if (rc)
1983 goto fail;
1985 /* A destination child element contains a target to the source element. */
1986 rc = find_child_to_target (doc, dst_node->children, src_node, dst_node, 0, 0);
1987 if (rc)
1988 goto fail;
1990 fail:
1991 strv_free (src_req);
1992 return rc;