Fix valid_xml_element() and valid_xml_attribute() to use XML spec.
[pwmd.git] / src / xml.c
blobdf74af6356b3df650d96c86a5b28cf3f48566024
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 return valid_xml_element ((xmlChar *)str);
78 int
79 valid_xml_element (xmlChar *str)
81 wchar_t *wc;
82 size_t len, c;
84 if (!str || !*str || *str == '!')
85 return 0;
87 wc = str_to_wchar ((const char *)str);
88 len = wcslen (wc);
90 for (c = 0; c < len; c++)
92 switch (wc[c])
94 case '-':
95 case '.':
96 case '0' ... '9':
97 case 0xB7:
98 case 0x0300 ... 0x036F:
99 case 0x203F ... 0x2040:
100 if (!c)
102 xfree (wc);
103 return 0;
105 case ':': break;
106 case '_': break;
107 case 'A' ... 'Z': break;
108 case 'a' ... 'z': break;
109 case 0xC0 ... 0xD6: break;
110 case 0xD8 ... 0xF6: break;
111 case 0xF8 ... 0x2FF: break;
112 case 0x370 ... 0x37D: break;
113 case 0x37F ... 0x1FFF: break;
114 case 0x200C ... 0x200D: break;
115 case 0x2070 ... 0x218F: break;
116 case 0x2C00 ... 0x2FEF: break;
117 case 0x3001 ... 0xD7FF: break;
118 case 0xF900 ... 0xFDCF: break;
119 case 0xFDF0 ... 0xFFFD: break;
120 case 0x10000 ... 0xEFFFF: break;
121 default:
122 xfree (wc);
123 return 0;
127 xfree (wc);
128 return 1;
132 valid_element_path (char **path, int with_content)
134 char **dup = NULL, **p;
135 int i, t;
137 if (!path || !*path)
138 return 0;
140 /* Save some memory by not duplicating the element content. */
141 if (with_content)
143 t = strv_length (path);
144 for (i = 0; i < t - 1; i++)
146 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
148 if (!tmp)
150 strv_free (dup);
151 return 0;
154 dup = tmp;
155 dup[i] = str_dup (path[i]);
156 dup[i + 1] = NULL;
159 else
160 dup = strv_dup (path);
162 if (!dup)
163 return 0;
165 for (p = dup; *p && *(*p); p++)
167 is_literal_element (&(*p));
168 if (!valid_xml_element ((xmlChar *) * p))
170 strv_free (dup);
171 return 0;
175 strv_free (dup);
176 return 1;
179 gpg_error_t
180 attr_ctime (xmlNodePtr n)
182 char *buf = str_asprintf ("%li", time (NULL));
183 gpg_error_t rc;
185 if (!buf)
186 return GPG_ERR_ENOMEM;
188 rc = add_attribute (n, "_ctime", buf);
189 xfree (buf);
190 return rc;
193 static gpg_error_t
194 create_new_element (xmlNodePtr parent, const char *name, xmlNodePtr * result)
196 xmlNodePtr n = xmlNewNode (NULL, (xmlChar *) "element");
197 gpg_error_t rc;
199 if (!n)
200 return GPG_ERR_ENOMEM;
202 rc = add_attribute (n, "_name", name);
203 if (!rc)
204 rc = attr_ctime (n);
206 if (!rc)
208 if (result)
209 *result = xmlAddChild (parent, n);
210 else
211 (void) xmlAddChild (parent, n);
213 else
214 xmlFreeNode (n);
216 return rc;
219 gpg_error_t
220 new_root_element (xmlDocPtr doc, char *name)
222 xmlNodePtr root = xmlDocGetRootElement (doc);
223 char *p = name;
225 if (!p || !root)
226 return GPG_ERR_BAD_DATA;
228 if (*p == '!')
229 p++;
231 if (!valid_xml_element ((xmlChar *) p))
232 return GPG_ERR_INV_VALUE;
234 return create_new_element (root, p, NULL);
237 static xmlDocPtr
238 create_dtd ()
240 xmlDocPtr doc;
241 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
243 if (!wr)
244 return NULL;
246 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
247 goto fail;
249 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
250 goto fail;
252 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
253 (xmlChar *) "(element)") == -1)
254 goto fail;
256 xmlTextWriterEndDTDElement (wr);
258 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
259 (xmlChar *) "_name CDATA #REQUIRED") ==
261 goto fail;
263 xmlTextWriterEndDTDAttlist (wr);
264 xmlTextWriterEndDTD (wr);
266 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
267 goto fail;
269 xmlTextWriterEndElement (wr);
270 xmlTextWriterEndDocument (wr);
271 xmlFreeTextWriter (wr);
272 return doc;
274 fail:
275 xmlTextWriterEndDocument (wr);
276 xmlFreeTextWriter (wr);
277 xmlFreeDoc (doc);
278 return NULL;
281 xmlDocPtr
282 new_document ()
284 return create_dtd ();
287 xmlNodePtr
288 find_element_node (xmlNodePtr node)
290 xmlNodePtr n = node;
292 if (n && n->type == XML_ELEMENT_NODE)
293 return n;
295 for (n = node; n; n = n->next)
297 if (n->type == XML_ELEMENT_NODE)
298 return n;
301 return NULL;
304 static xmlNodePtr
305 resolve_path (xmlDocPtr doc, xmlChar * path, char ***result, gpg_error_t * rc)
307 xmlNodePtr n;
308 char **req;
310 req = str_split ((char *) path, "\t", 0);
311 if (!req)
313 *rc = GPG_ERR_ENOMEM;
314 return NULL;
317 n = find_root_element (doc, &req, rc, NULL, 0, 0);
318 if (!n)
320 strv_free (req);
321 return NULL;
324 if (req[1])
325 n = find_elements (doc, n->children, req + 1, rc, NULL, NULL, NULL,
326 0, 0, NULL, 0);
328 if (*rc)
329 strv_free (req);
330 else
331 *result = req;
333 return n;
337 * Lists root element names; the value of the attribute "_name" of an element
338 * "element". If there's a target attribute both literal and non-literal
339 * element names will be added. This is the primary reason why XML entities
340 * cannot be used. There wouldn't be a way to get the literal an non-literal
341 * element paths.
343 gpg_error_t
344 list_root_elements (xmlDocPtr doc, struct string_s ** result,
345 int verbose, int with_target)
347 xmlNodePtr n = NULL;
348 struct slist_s *list = NULL;
349 int total, i;
350 struct string_s *string;
351 gpg_error_t rc = 0;
353 n = xmlDocGetRootElement (doc);
354 if (!n || !n->children)
355 return GPG_ERR_NO_DATA;
357 for (n = n->children; n; n = n->next)
359 xmlAttrPtr a;
360 xmlChar *val, *target;
361 struct slist_s *tlist;
362 char *tmp;
364 if (n->type != XML_ELEMENT_NODE)
365 continue;
367 a = xmlHasProp (n, (xmlChar *) "_name");
368 if (!a || !a->children->content)
369 continue;
371 val = xmlNodeGetContent (a->children);
372 if (!val)
374 rc = GPG_ERR_ENOMEM;
375 goto fail;
378 tmp =
379 str_asprintf ("!%s%s", (char *) val,
380 verbose ? find_element_node (n->children) ? " +" : "" :
381 "");
383 if (!tmp)
385 xmlFree (val);
386 rc = GPG_ERR_ENOMEM;
387 goto fail;
390 tlist = slist_append (list, tmp);
391 if (!tlist)
393 xmlFree (val);
394 rc = GPG_ERR_ENOMEM;
395 goto fail;
398 list = tlist;
399 target = node_has_attribute (n, (xmlChar *) "target");
400 if (target)
402 char *t = NULL;
404 if (verbose)
406 char **req = NULL;
407 xmlNodePtr tnode = resolve_path (doc, target, &req, &rc);
409 if (rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP)
411 t = str_asprintf ("%s %s", (char *) val,
412 rc == GPG_ERR_ELOOP ? "O" : "E");
413 rc = 0;
415 else if (!rc)
417 struct string_s *realpath = NULL;
419 if (with_target)
421 rc = build_realpath (doc, (char *) target, &realpath);
422 if (rc)
424 strv_free (req);
425 xmlFree (val);
426 xmlFree (target);
427 goto fail;
430 realpath = string_prepend (realpath, "T ");
433 t = str_asprintf ("%s%s%s%s", (char *) val,
434 (tnode
435 && find_element_node (tnode->children))
436 || realpath ? " " : "", tnode
437 && find_element_node (tnode->children) ?
438 "+" : "", realpath ? realpath->str : "");
440 if (realpath)
441 string_free (realpath, 1);
444 if (req)
445 strv_free (req);
447 else
448 t = str_dup ((char *) val);
450 if (!t || rc)
452 xmlFree (val);
453 xmlFree (target);
454 rc = rc ? rc : GPG_ERR_ENOMEM;
455 goto fail;
458 tlist = slist_append (list, t);
459 if (!tlist)
461 xmlFree (val);
462 xfree (t);
463 xmlFree (target);
464 rc = GPG_ERR_ENOMEM;
465 goto fail;
468 list = tlist;
471 xmlFree (val);
472 xmlFree (target);
475 total = slist_length (list);
476 if (!total)
477 return GPG_ERR_NO_DATA;
479 string = string_new (NULL);
480 if (!string)
482 rc = GPG_ERR_ENOMEM;
483 goto fail;
486 for (i = 0; i < total; i++)
488 char *val = slist_nth_data (list, i);
490 string_append_printf (string, "%s\n", val);
493 string = string_truncate (string, string->len - 1);
494 *result = string;
496 fail:
497 total = slist_length (list);
498 for (i = 0; i < total; i++)
499 xfree (slist_nth_data (list, i));
501 slist_free (list);
502 return rc;
506 * Prevents a sibling element past the current element path with the same
507 * element name.
509 static xmlNodePtr
510 find_stop_node (xmlNodePtr node)
512 xmlNodePtr n;
514 for (n = node->parent->children; n; n = n->next)
516 if (n == node)
517 return n->next;
520 return NULL;
523 xmlNodePtr
524 create_target_elements_cb (xmlNodePtr node, char **path,
525 gpg_error_t * rc, void *data)
527 int i;
528 char **req = path;
529 xmlNodePtr parent = data;
531 for (i = 0; req[i] && *req[i]; i++)
533 xmlNodePtr n;
535 if (parent && node == parent)
537 *rc = GPG_ERR_CONFLICT;
538 return NULL;
541 is_literal_element (&req[i]);
543 if ((n = find_element (node, req[i], find_stop_node (node))) == NULL ||
544 (n && n->parent == node->parent))
547 *rc = create_new_element (node, req[i], &node);
548 if (*rc)
549 return NULL;
551 else
552 node = n;
555 return node;
558 xmlNodePtr
559 find_text_node (xmlNodePtr node)
561 xmlNodePtr n = node;
563 if (n && n->type == XML_TEXT_NODE)
564 return n;
566 for (n = node; n; n = n->next)
568 if (n->type == XML_TEXT_NODE)
569 return n;
572 return NULL;
575 xmlNodePtr
576 create_elements_cb (xmlNodePtr node, char **elements,
577 gpg_error_t * rc, void *data)
579 int i;
580 char **req = elements;
582 if (node->type == XML_TEXT_NODE)
583 node = node->parent;
585 for (i = 0; req[i] && *req[i]; i++)
587 xmlNodePtr n;
590 * Strip the first '!' if needed. If there's another, it's an
591 * rc. The syntax has already been checked before calling this
592 * function.
594 is_literal_element (&req[i]);
595 n = find_element (node, req[i], find_stop_node (node));
598 * If the found element has the same parent as the current element,
599 * they are siblings and the new element needs to be created as a
600 * child of the current element (node).
602 if (n && n->parent == node->parent)
603 n = NULL;
605 if (!n)
607 *rc = create_new_element (node, req[i], &node);
608 if (*rc)
609 return NULL;
611 else
612 node = n;
615 return node;
618 /* The root element is really req[0]. It is need as a pointer in case there is
619 * a target attribute so it can be updated. */
620 xmlNodePtr
621 find_root_element (xmlDocPtr doc, char ***req, gpg_error_t * rc,
622 int *target, int recursion_depth, int stop)
624 xmlNodePtr n = xmlDocGetRootElement (doc);
625 int depth = 0;
626 char *root = str_dup (*req[0]);
627 int literal = is_literal_element (&root);
629 if (!root)
631 *rc = GPG_ERR_ENOMEM;
632 return NULL;
635 *rc = 0;
636 recursion_depth++;
638 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
640 xmlChar *t = xmlGetNodePath (n);
642 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
643 xmlFree (t);
644 xfree (root);
645 *rc = GPG_ERR_ELOOP;
646 return NULL;
649 while (n)
651 if (n->type == XML_ELEMENT_NODE)
653 if (depth == 0 && xmlStrEqual (n->name, (xmlChar *) "pwmd"))
655 n = n->children;
656 depth++;
657 continue;
660 if (depth == 1 && xmlStrEqual (n->name, (xmlChar *) "element"))
662 xmlChar *content = node_has_attribute (n, (xmlChar *) "_name");
664 if (!content)
665 continue;
667 if (xmlStrEqual (content, (xmlChar *) root))
669 char **nreq, **tmp = NULL;
671 if (literal == 1)
673 xmlFree (content);
674 xfree (root);
675 return n;
678 xmlFree (content);
679 content = node_has_attribute (n, (xmlChar *) "target");
681 if (target)
682 *target = 1;
684 if (!content || stop)
686 if (content)
687 xmlFree (content);
689 xfree (root);
690 return n;
693 if (strchr ((char *) content, '\t'))
695 nreq = str_split ((char *) content, "\t", 0);
696 xmlFree (content);
698 #if 0
700 * FIXME ENOMEM
702 if (!nreq)
704 *rc = GPG_ERR_ENOMEM;
705 return NULL;
707 #endif
709 tmp = *req;
710 tmp = strv_catv (nreq, tmp + 1);
711 strv_free (nreq);
713 if (!tmp)
715 xfree (root);
716 *rc = GPG_ERR_ENOMEM;
717 return NULL;
720 strv_free (*req);
721 *req = tmp;
723 else
725 if (strv_printf (&tmp, "%s", content) == 0)
727 xmlFree (content);
728 xfree (root);
729 *rc = GPG_ERR_ENOMEM;
730 return NULL;
733 xmlFree (content);
734 nreq = *req;
735 nreq = strv_catv (tmp, nreq + 1);
736 strv_free (tmp);
738 if (!nreq)
740 *rc = GPG_ERR_ENOMEM;
741 xfree (root);
742 return NULL;
745 strv_free (*req);
746 *req = nreq;
749 xfree (root);
751 find_root_element (doc, req, rc, target, recursion_depth,
753 return n;
756 xmlFree (content);
760 n = n->next;
763 xfree (root);
764 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
765 return NULL;
768 xmlNodePtr
769 find_element (xmlNodePtr node, char *element, xmlNodePtr stop)
771 xmlNodePtr n;
773 if (!node || !element)
774 return NULL;
776 for (n = node; n; n = n->next)
778 if (n->type != XML_ELEMENT_NODE)
779 continue;
781 if (n == stop)
782 break;
784 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
786 if (a && xmlStrEqual (a, (xmlChar *) element))
788 xmlFree (a);
789 return n;
792 xmlFree (a);
795 return NULL;
798 xmlChar *
799 node_has_attribute (xmlNodePtr n, xmlChar * attr)
801 xmlAttrPtr a = xmlHasProp (n, attr);
803 if (!a)
804 return NULL;
806 if (!a->children || !a->children->content)
807 return NULL;
809 return xmlGetProp (n, attr);
812 static int
813 element_to_literal (char **element)
815 char *p = str_asprintf ("!%s", *element);
817 if (!p)
818 return 0;
820 xfree (*element);
821 *element = p;
822 return 1;
825 /* Resolves elements in 'req' one at a time. It's recursive in case of
826 * "target" attributes. */
827 xmlNodePtr
828 find_elements (xmlDocPtr doc, xmlNodePtr node,
829 char **req, gpg_error_t * rc, int *target,
830 xmlNodePtr (*found_fn) (xmlNodePtr, char **, gpg_error_t *,
831 char **, void *),
832 xmlNodePtr (*not_found_fn) (xmlNodePtr, char **, gpg_error_t *,
833 void *), int is_list_command,
834 int recursion_depth, void *data, int stop)
836 xmlNodePtr n, last, last_node;
837 char **p;
838 int found = 0;
840 *rc = 0;
841 recursion_depth++;
843 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
845 xmlChar *t = xmlGetNodePath (node);
847 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
848 xmlFree (t);
849 recursion_depth--;
850 *rc = GPG_ERR_ELOOP;
851 return NULL;
854 for (last_node = last = n = node, p = req; *p; p++)
856 xmlNodePtr tmp;
857 char *t;
858 int literal;
860 if (!*(*p))
862 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
863 return NULL;
866 t = str_dup (*p);
867 if (!t)
869 *rc = GPG_ERR_ENOMEM;
870 return NULL;
873 literal = is_literal_element (&t);
874 n = find_element (last, t, NULL);
875 xfree (t);
877 if (!n)
879 if (not_found_fn)
880 return not_found_fn (found ? last_node : last_node->parent, p, rc,
881 data);
883 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
884 return NULL;
887 last = n->children;
888 last_node = n;
889 found = 1;
891 if (literal == 0)
893 xmlChar *content = node_has_attribute (n, (xmlChar *) "target");
894 char **nreq = NULL, **nnreq;
896 if (!content)
898 if (is_list_command == 1)
900 if (element_to_literal (&(*p)) == 0)
902 *rc = GPG_ERR_ENOMEM;
903 return NULL;
907 continue;
910 if (target)
911 *target = 1;
913 if (!*(p + 1) && stop)
915 xmlFree (content);
916 return n;
919 if (strchr ((char *) content, '\t') != NULL)
921 if ((nreq = str_split ((char *) content, "\t", 0)) == NULL)
923 xmlFree (content);
924 *rc = GPG_ERR_INV_VALUE;
925 return NULL;
928 else
930 if ((nreq = str_split ((char *) content, " ", 0)) == NULL)
932 xmlFree (content);
933 *rc = GPG_ERR_INV_VALUE;
934 return NULL;
938 xmlFree (content);
939 tmp = find_root_element (doc, &nreq, rc, target, 0, 0);
941 if (!tmp)
943 strv_free (nreq);
944 return NULL;
947 if (found_fn)
949 found_fn (tmp, nreq, rc, p + 1, data);
951 if (*rc)
953 strv_free (nreq);
954 return NULL;
958 if (!*(nreq + 1) && !*(p + 1))
960 strv_free (nreq);
961 return tmp;
964 nnreq = strv_catv (nreq + 1, p + 1);
965 strv_free (nreq);
967 // FIXME ENOMEM
968 if (!nnreq || !*nnreq)
970 if (nnreq)
971 strv_free (nnreq);
973 return tmp;
976 if (tmp->children)
977 n = find_elements (doc, tmp->children, nnreq, rc, NULL, found_fn,
978 not_found_fn, is_list_command, recursion_depth,
979 data, stop);
980 else
982 strv_free (nnreq);
984 if (not_found_fn)
985 return not_found_fn (tmp, p + 1, rc, data);
987 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
988 return NULL;
991 if (*(p + 1))
993 char **zz = p + 1, **qq = nnreq;
995 if (strv_length (nnreq) > strv_length (p + 1))
996 qq = nnreq + 1;
998 for (; *qq && *zz; zz++)
1000 xfree (*zz);
1001 *zz = str_dup (*qq++);
1003 if (!*zz)
1005 *rc = GPG_ERR_ENOMEM;
1006 n = NULL;
1007 break;
1012 strv_free (nnreq);
1013 return n;
1017 return n;
1020 static int
1021 update_element_list (struct element_list_s *elements)
1023 char *line;
1024 struct slist_s *l;
1026 if (!elements || !elements->elements)
1027 return 1;
1029 line = strv_join ("\t", elements->elements);
1031 if (!line)
1032 return 0;
1034 strv_free (elements->elements);
1035 elements->elements = NULL;
1036 l = slist_append (elements->list, line);
1038 if (!l)
1039 return 0;
1041 elements->list = l;
1042 return 1;
1045 static gpg_error_t
1046 path_list_recurse (xmlDocPtr doc, xmlNodePtr node,
1047 struct element_list_s *elements)
1049 gpg_error_t rc = 0;
1050 xmlNodePtr n;
1051 gpg_error_t error_flag = 0;
1053 for (n = node; n; n = n->next)
1055 xmlChar *target = NULL;
1056 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
1057 int err = 0;
1059 if (!a)
1060 continue;
1062 if (n->type != XML_ELEMENT_NODE)
1063 goto children;
1065 if (elements->verbose)
1067 if (strv_printf
1068 (&elements->elements, "%s\t!%s%s", elements->prefix, a,
1069 find_element_node (n->children) ? " +" : "") == 0)
1071 xmlFree (a);
1072 return GPG_ERR_ENOMEM;
1075 else
1076 if (strv_printf (&elements->elements, "%s\t!%s", elements->prefix, a)
1077 == 0)
1079 xmlFree (a);
1080 return GPG_ERR_ENOMEM;
1083 if (update_element_list (elements) == 0)
1085 xmlFree (a);
1086 return GPG_ERR_ENOMEM;
1089 target = node_has_attribute (n, (xmlChar *) "target");
1091 if (target)
1093 char *tmp;
1094 char *save = elements->prefix;
1095 int r = elements->resolving;
1096 char **req = NULL;
1097 xmlNodePtr tnode;
1098 struct string_s *realpath = NULL;
1100 tnode = resolve_path (doc, target, &req, &rc);
1101 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_ELEMENT_NOT_FOUND)
1103 if (rc == GPG_ERR_ELOOP)
1105 xmlChar *t = xmlGetNodePath (n);
1107 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1108 xmlFree (t);
1111 if (elements->verbose)
1113 strv_printf (&elements->elements, "%s\t%s %s",
1114 elements->prefix, a,
1115 rc == GPG_ERR_ELOOP ? "O" : "E");
1116 error_flag = err = rc;
1117 rc = 0;
1118 goto update;
1122 if (!elements->verbose && rc)
1124 xmlFree (a);
1125 xmlFree (target);
1126 return rc;
1129 if (elements->with_target)
1131 rc = build_realpath (doc, (char *) target, &realpath);
1132 if (rc)
1134 xmlFree (a);
1135 xmlFree (target);
1136 return rc;
1139 realpath = string_prepend (realpath, "T ");
1142 if (elements->verbose)
1144 if (!strv_printf (&elements->elements, "%s\t%s%s%s%s",
1145 elements->prefix, a,
1146 (tnode && find_element_node (tnode->children))
1147 || realpath ? " " : "", tnode
1148 && find_element_node (tnode->children) ? "+" :
1149 "", realpath ? realpath->str : ""))
1151 xmlFree (a);
1152 xmlFree (target);
1153 return GPG_ERR_ENOMEM;
1156 else
1157 if (!strv_printf
1158 (&elements->elements, "%s\t%s", elements->prefix, a))
1160 xmlFree (a);
1161 xmlFree (target);
1162 return GPG_ERR_ENOMEM;
1165 update:
1166 if (realpath)
1167 string_free (realpath, 1);
1169 tmp = strv_join ("\t", elements->elements);
1171 if (!tmp)
1173 xmlFree (a);
1174 xmlFree (target);
1175 return GPG_ERR_ENOMEM;
1178 if (update_element_list (elements) == 0)
1180 xfree (tmp);
1181 xmlFree (a);
1182 xmlFree (target);
1183 return GPG_ERR_ENOMEM;
1186 if (!err && elements->recurse)
1188 /* Prune element flags. */
1189 if (elements->verbose && strchr (tmp, ' '))
1191 char *p;
1193 for (p = tmp; *p; p++)
1195 if (*p == ' ')
1197 *p = 0;
1198 break;
1203 elements->prefix = tmp;
1204 elements->resolving = 1;
1205 rc = create_path_list (doc, elements, (char *) target);
1206 elements->resolving = r;
1207 elements->prefix = save;
1209 if (rc && gpg_err_code (rc) != GPG_ERR_ELOOP)
1211 xfree (tmp);
1212 xmlFree (target);
1213 xmlFree (a);
1214 return rc;
1217 error_flag = err = rc;
1218 rc = 0;
1221 xfree (tmp);
1222 xmlFree (target);
1225 children:
1226 if (n->children && elements->recurse && err != GPG_ERR_ELOOP)
1228 char *tmp = str_asprintf ("%s\t!%s", elements->prefix, a);
1229 char *save = elements->prefix;
1231 if (!tmp)
1233 xmlFree (a);
1234 return GPG_ERR_ENOMEM;
1237 elements->prefix = tmp;
1238 rc = path_list_recurse (doc, n->children, elements);
1239 xfree (elements->prefix);
1240 elements->prefix = save;
1242 if (rc)
1244 xmlFree (a);
1245 return rc;
1249 xmlFree (a);
1252 return error_flag == GPG_ERR_ELOOP ? error_flag : rc;
1255 gpg_error_t
1256 add_attribute (xmlNodePtr node, const char *name, const char *value)
1258 char *buf;
1259 gpg_error_t rc;
1261 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
1262 return GPG_ERR_BAD_DATA;
1264 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
1265 return 0;
1267 buf = str_asprintf ("%li", time (NULL));
1268 rc = add_attribute (node, "_mtime", buf);
1269 xfree (buf);
1270 return rc;
1274 * From the element path 'path', find sub-nodes and append them to the list.
1276 gpg_error_t
1277 create_path_list (xmlDocPtr doc, struct element_list_s * elements, char *path)
1279 gpg_error_t rc;
1280 char **req, **req_orig;
1281 xmlNodePtr n;
1282 int a_target = 0;
1284 req = str_split (path, "\t", 0);
1285 if (!req)
1287 req = str_split (path, " ", 0);
1288 if (!req)
1289 return GPG_ERR_SYNTAX;
1292 req_orig = strv_dup (req);
1293 if (!req_orig)
1295 rc = GPG_ERR_ENOMEM;
1296 goto fail;
1299 n = find_root_element (doc, &req, &rc, &a_target, 0, 0);
1300 if ((rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP)
1301 && elements->verbose && a_target)
1303 rc = 0;
1304 goto done;
1307 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1309 rc = 0;
1310 goto fail;
1312 else if (!n)
1313 goto fail;
1315 if (a_target == 1)
1317 xfree (*req);
1318 *req = str_dup (*req_orig);
1321 if (*(req + 1))
1323 int e_target = 0;
1326 find_elements (doc, n->children, req + 1, &rc, &e_target, NULL, NULL,
1327 1, 0, NULL, 0);
1329 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1331 rc = 0;
1332 goto fail;
1334 else if (!n)
1335 goto fail;
1338 done:
1339 if (!elements->prefix)
1342 * FIXME
1344 * If any req_orig element contains no target the element should be
1345 * prefixed with the literal character. Not really crucial if the
1346 * client isn't human because child elements are prefixed for the
1347 * current path. But may be confusing if editing by hand.
1349 elements->prefix = strv_join ("\t", req_orig);
1351 if (!elements->prefix)
1353 rc = GPG_ERR_ENOMEM;
1354 goto fail;
1357 if (elements->verbose)
1359 int ret;
1360 struct string_s *realpath = NULL;
1362 if (a_target && elements->with_target)
1364 rc = build_realpath (doc, path, &realpath);
1365 if (rc)
1366 goto fail;
1368 realpath = string_prepend (realpath, "T ");
1371 ret = strv_printf (&elements->elements, "%s%s%s%s",
1372 elements->prefix,
1373 find_element_node (n->children)
1374 || realpath ? " " : "",
1375 find_element_node (n->children) ? "+" : "",
1376 realpath ? realpath->str : "");
1377 string_free (realpath, 1);
1378 if (!ret)
1380 rc = GPG_ERR_ENOMEM;
1381 goto fail;
1384 else if (strv_printf (&elements->elements, "%s", elements->prefix) == 0)
1386 rc = GPG_ERR_ENOMEM;
1387 goto fail;
1390 if (update_element_list (elements) == 0)
1392 rc = GPG_ERR_ENOMEM;
1393 goto fail;
1397 rc = path_list_recurse (doc, n->children, elements);
1399 fail:
1400 if (req_orig)
1401 strv_free (req_orig);
1403 strv_free (req);
1404 return rc;
1407 gpg_error_t
1408 recurse_xpath_nodeset (xmlDocPtr doc, xmlNodeSetPtr nodes,
1409 xmlChar * value, xmlBufferPtr * result, int cmd,
1410 const xmlChar * attr)
1412 int i = value ? nodes->nodeNr - 1 : 0;
1413 xmlBufferPtr buf;
1415 buf = xmlBufferCreate ();
1417 if (!buf)
1418 return GPG_ERR_ENOMEM;
1420 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
1422 xmlNodePtr n = nodes->nodeTab[i];
1423 gpg_error_t rc;
1425 if (!n)
1426 continue;
1428 if (!value && !attr)
1430 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
1432 *result = buf;
1433 return GPG_ERR_BAD_DATA;
1436 continue;
1439 if (!attr)
1441 xmlNodeSetContent (n, value);
1442 rc = update_element_mtime (n);
1444 if (rc)
1445 return rc;
1447 else
1449 if (!cmd)
1450 rc = add_attribute (n, (char *) attr, (char *) value);
1451 else
1452 rc = delete_attribute (n, attr);
1454 if (rc)
1455 return rc;
1459 *result = buf;
1460 return 0;
1463 static gpg_error_t
1464 convert_root_element (xmlNodePtr n)
1466 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1467 gpg_error_t rc;
1469 if (a)
1471 xmlFree (a);
1472 xmlChar *t = xmlGetNodePath (n);
1474 log_write (_
1475 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1477 xmlFree (t);
1478 return GPG_ERR_AMBIGUOUS_NAME;
1481 a = xmlGetProp (n, (xmlChar *) "name");
1483 if (a)
1485 rc = add_attribute (n, "_name", (char *) a);
1486 xmlFree (a);
1488 if (rc)
1489 return rc;
1491 rc = delete_attribute (n, (xmlChar *) "name");
1493 if (rc)
1494 return rc;
1496 xmlNodeSetName (n, (xmlChar *) "element");
1499 return 0;
1502 gpg_error_t
1503 delete_attribute (xmlNodePtr n, const xmlChar * name)
1505 xmlAttrPtr a;
1507 if ((a = xmlHasProp (n, name)) == NULL)
1508 return GPG_ERR_NOT_FOUND;
1510 if (xmlRemoveProp (a) == -1)
1511 return GPG_ERR_BAD_DATA;
1513 return update_element_mtime (n);
1516 static gpg_error_t
1517 convert_elements_recurse (xmlDocPtr doc, xmlNodePtr n, unsigned depth)
1519 gpg_error_t rc;
1521 depth++;
1523 for (n = n->children; n; n = n->next)
1525 if (n->type == XML_ELEMENT_NODE)
1527 xmlChar *a = NULL;
1529 if (depth > 1)
1531 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1533 xmlChar *t = xmlGetNodePath (n);
1535 log_write (_
1536 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1538 xmlFree (t);
1539 return GPG_ERR_AMBIGUOUS_NAME;
1542 a = xmlGetProp (n, (xmlChar *) "_name");
1544 if (a)
1546 xmlFree (a);
1547 xmlChar *t = xmlGetNodePath (n);
1549 log_write (_
1550 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1552 xmlFree (t);
1553 return GPG_ERR_AMBIGUOUS_NAME;
1556 xmlChar *tmp = xmlStrdup (n->name);
1558 if (!tmp)
1559 return GPG_ERR_ENOMEM;
1561 xmlNodeSetName (n, (xmlChar *) "element");
1562 rc = add_attribute (n, "_name", (char *) tmp);
1563 xmlFree (tmp);
1565 if (rc)
1566 return rc;
1568 else
1570 rc = convert_root_element (n);
1572 if (rc)
1573 return rc;
1577 if (n->children)
1579 rc = convert_elements_recurse (doc, n, depth);
1581 if (rc)
1582 return rc;
1586 return 0;
1589 /* Renames ALL elements to the new "element" name. Existing element names are
1590 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1591 * elements can contain common characters that the XML parser barfs on (an
1592 * email address for example. */
1593 gpg_error_t
1594 convert_pre_212_elements (xmlDocPtr doc)
1596 xmlNodePtr n = xmlDocGetRootElement (doc);
1598 log_write (_("Converting pre 2.12 data file..."));
1599 return convert_elements_recurse (doc, n, 0);
1602 gpg_error_t
1603 validate_import (xmlNodePtr node)
1605 gpg_error_t rc = 0;
1607 if (!node)
1608 return 0;
1610 for (xmlNodePtr n = node; n; n = n->next)
1612 if (n->type == XML_ELEMENT_NODE)
1614 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1616 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1618 if (!a)
1620 xmlChar *t = xmlGetNodePath (n);
1622 log_write (_("Missing attribute '_name' at %s."), t);
1623 xmlFree (t);
1624 return GPG_ERR_INV_VALUE;
1627 if (!valid_xml_element (a))
1629 xmlChar *t = xmlGetNodePath (n);
1631 log_write (_("'%s' is not a valid element name at %s."), a,
1633 xmlFree (a);
1634 xmlFree (t);
1635 return GPG_ERR_INV_VALUE;
1638 xmlFree (a);
1639 a = xmlGetProp (n, (xmlChar *) "_ctime");
1640 if (!a)
1641 attr_ctime (n);
1643 xmlFree (a);
1644 a = xmlGetProp (n, (xmlChar *) "_mtime");
1645 if (!a)
1646 update_element_mtime (n);
1647 xmlFree (a);
1649 else
1651 xmlChar *t = xmlGetNodePath (n);
1653 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1654 n->name, t);
1655 xmlFree (t);
1656 continue;
1660 if (n->children)
1662 rc = validate_import (n->children);
1664 if (rc)
1665 return rc;
1669 return rc;
1672 gpg_error_t
1673 update_element_mtime (xmlNodePtr n)
1675 return add_attribute (n, NULL, NULL);
1678 gpg_error_t
1679 unlink_node (xmlNodePtr n)
1681 gpg_error_t rc = 0;
1683 if (!n)
1684 return rc;
1686 if (n->parent)
1687 rc = update_element_mtime (n->parent);
1689 xmlUnlinkNode (n);
1690 return rc;
1693 gpg_error_t
1694 parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1696 xmlDocPtr doc;
1698 xmlResetLastError ();
1699 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1700 if (!doc && xmlGetLastError ())
1701 return GPG_ERR_BAD_DATA;
1703 *result = doc;
1704 return !doc ? GPG_ERR_ENOMEM : 0;
1707 static xmlNodePtr
1708 realpath_elements_cb (xmlNodePtr node, char **target,
1709 gpg_error_t * rc, char **req_orig, void *data)
1711 char *path = *(char **) data;
1712 char *tmp = NULL, *result;
1714 if (path)
1716 xfree (path);
1717 *(char **) data = NULL;
1720 path = strv_join ("\t", target);
1722 if (!path)
1724 *rc = GPG_ERR_ENOMEM;
1725 return NULL;
1728 if (req_orig)
1730 tmp = strv_join ("\t", req_orig);
1732 if (!tmp)
1734 xfree (path);
1735 *rc = GPG_ERR_ENOMEM;
1736 return NULL;
1740 if (tmp && *tmp)
1741 result = str_asprintf ("%s\t%s", path, tmp);
1742 else
1743 result = str_dup (path);
1745 if (!result)
1747 *rc = GPG_ERR_ENOMEM;
1748 xfree (path);
1749 xfree (tmp);
1750 return NULL;
1753 xfree (path);
1754 xfree (tmp);
1755 *(char **) data = result;
1756 return node;
1759 gpg_error_t
1760 build_realpath (xmlDocPtr doc, char *line, struct string_s ** result)
1762 gpg_error_t rc;
1763 char **req;
1764 char *t;
1765 int i;
1766 xmlNodePtr n;
1767 struct string_s *string;
1768 char *rp = NULL;
1770 if (strchr (line, '\t') != NULL)
1772 if ((req = str_split (line, "\t", 0)) == NULL)
1773 return GPG_ERR_SYNTAX;
1775 else
1777 if ((req = str_split (line, " ", 0)) == NULL)
1778 return GPG_ERR_SYNTAX;
1781 n = find_root_element (doc, &req, &rc, NULL, 0, 0);
1782 if (!n)
1784 strv_free (req);
1785 return rc;
1788 rp = strv_join ("\t", req);
1789 if (!rp)
1791 strv_free (req);
1792 return GPG_ERR_ENOMEM;
1795 if (req[1])
1797 n = find_elements (doc, n->children, req + 1, &rc,
1798 NULL, realpath_elements_cb, NULL, 0, 0, &rp, 0);
1799 if (!n)
1801 xfree (rp);
1802 strv_free (req);
1803 return rc;
1807 string = string_new (rp);
1808 xfree (rp);
1809 strv_free (req);
1810 if (!string)
1811 return GPG_ERR_ENOMEM;
1813 again:
1814 for (i = 0, t = string->str + i; *t; t++, i++)
1816 if ((!i && *t != '!') || (*t == '\t' && *(t + 1) && *(t + 1) != '!'))
1818 struct string_s *s = string_insert_c (string, !i ? i++ : ++i, '!');
1820 if (!s)
1822 string_free (string, 1);
1823 return GPG_ERR_ENOMEM;
1826 string = s;
1827 goto again;
1831 *result = string;
1832 return rc;
1835 #if 0
1836 static char *
1837 node_to_element_path (xmlNodePtr node)
1839 xmlNodePtr n;
1840 struct string_s *str = string_new ("");
1841 char *result;
1843 for (n = node; n; n = n->parent)
1845 xmlNodePtr child;
1847 for (child = n; child; child = child->next)
1849 if (child->type != XML_ELEMENT_NODE)
1850 continue;
1852 xmlChar *name = node_has_attribute (n, (xmlChar *) "_name");
1853 if (name)
1855 str = string_prepend (str, (char *) name);
1856 xmlFree (name);
1857 name = node_has_attribute (n, (xmlChar *) "target");
1858 if (name)
1859 str = string_prepend (str, "\t");
1860 else
1861 str = string_prepend (str, "\t!");
1862 xmlFree (name);
1864 break;
1868 str = string_erase (str, 0, 1);
1869 result = str->str;
1870 string_free (str, 0);
1871 return result;
1873 #endif
1876 * Recurse the element tree beginning at 'node' and find elements who point
1877 * back to 'src' or 'dst'. Also follows target attributes.
1879 static gpg_error_t
1880 find_child_to_target (xmlDocPtr doc, xmlNodePtr node,
1881 xmlNodePtr src, xmlNodePtr dst, unsigned depth,
1882 int is_target)
1884 xmlNodePtr n;
1885 gpg_error_t rc = 0;
1887 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1888 return gpg_error (GPG_ERR_ELOOP);
1890 for (n = node; n; n = n->next)
1892 xmlChar *target;
1894 if (n->type != XML_ELEMENT_NODE)
1895 continue;
1897 if (n == src || n == dst)
1898 return GPG_ERR_ELOOP;
1900 target = node_has_attribute (n, (xmlChar *) "target");
1901 if (target)
1903 xmlNodePtr tmp;
1904 char **result = NULL;
1906 tmp = resolve_path (doc, target, &result, &rc);
1907 xmlFree (target);
1908 strv_free (result);
1909 if (!rc)
1911 rc = find_child_to_target (doc, tmp, src, dst, ++depth, 1);
1912 depth--;
1915 if (rc && gpg_err_code (rc) != GPG_ERR_ELEMENT_NOT_FOUND)
1916 return rc;
1918 if (is_target)
1919 break;
1921 continue;
1924 if (n->children)
1926 rc = find_child_to_target (doc, n->children, src, dst, ++depth,0);
1927 depth--;
1928 if (rc)
1929 return rc;
1932 if (is_target)
1933 break;
1936 return rc;
1939 static gpg_error_t
1940 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1942 xmlNodePtr n;
1943 gpg_error_t rc = 0;
1945 for (n = src; n; n = n->next)
1947 if (n->type != XML_ELEMENT_NODE)
1948 continue;
1950 if (n == dst)
1952 rc = GPG_ERR_ELOOP;
1953 break;
1956 rc = find_child_of_parent (doc, n->children, dst);
1959 return rc;
1962 static gpg_error_t
1963 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1965 xmlNodePtr n;
1966 gpg_error_t rc = 0;
1968 for (n = node; n; n = n->parent)
1970 if (n->type != XML_ELEMENT_NODE)
1972 xmlNodePtr tmp;
1974 for (tmp = n->next; tmp; n = n->next)
1976 if (n->type != XML_ELEMENT_NODE)
1977 continue;
1979 if (tmp == dst)
1980 return GPG_ERR_ELOOP;
1984 if (n == dst)
1985 return GPG_ERR_ELOOP;
1988 return rc;
1991 gpg_error_t
1992 validate_target_attribute (xmlDocPtr doc, const char *src,
1993 xmlNodePtr dst_node)
1995 gpg_error_t rc;
1996 xmlNodePtr src_node;
1997 char **src_req = NULL;
1999 src_node = resolve_path (doc, (xmlChar *) src, &src_req, &rc);
2000 if (rc)
2001 goto fail;
2003 /* A destination element is a child of the source element. */
2004 rc = find_child_of_parent (doc, src_node->children, dst_node);
2005 if (rc)
2006 goto fail;
2008 /* The destination element is a parent of the source element. */
2009 rc = find_parent_of_child (doc, src_node->parent, dst_node);
2010 if (rc)
2011 goto fail;
2013 /* A destination child element contains a target to the source element. */
2014 rc = find_child_to_target (doc, dst_node->children, src_node, dst_node, 0, 0);
2015 if (rc)
2016 goto fail;
2018 fail:
2019 strv_free (src_req);
2020 return rc;