Compare a valid passphrase against "<?xml ". Skip the version string
[pwmd.git] / src / xml.c
blob7b37efa812a754812ab886ed63790030734740c4
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2009 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gcrypt.h>
30 #include <libxml/xmlwriter.h>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "pwmd_error.h"
37 #include "misc.h"
38 #include "xml.h"
40 static xmlNodePtr find_element(xmlNodePtr node, gchar *element, xmlNodePtr stop);
41 static xmlChar *node_has_attribute(xmlNodePtr n, xmlChar *attr);
44 * 'element' must be allocated.
46 gboolean is_literal_element(gchar **element)
48 gchar *p;
50 if (!element || !*element)
51 return FALSE;
53 if (*(*element) == '!') {
54 gchar *c;
56 for (p = *element, c = p+1; *c; c++)
57 *p++ = *c;
59 *p = 0;
60 return TRUE;
63 return FALSE;
67 * Fails if 'element' begins with punctuation or digit or contains whitespace.
69 * I'm not sure about using g_unichar_isspace() rather than isspace()?
71 gboolean valid_xml_element(xmlChar *element)
73 gunichar c;
74 glong len;
75 gchar *p = (gchar *)element;
77 if (!element || !*element)
78 return FALSE;
80 if (*p == '!')
81 p++;
83 len = g_utf8_strlen(p, -1) - 1;
84 c = g_utf8_get_char(p++);
86 if (g_unichar_ispunct(c) == TRUE || g_unichar_isdigit(c) == TRUE ||
87 g_unichar_isspace(c) == TRUE)
88 return FALSE;
90 while (*p && len--) {
91 c = g_utf8_get_char(p++);
93 if (g_unichar_isspace(c))
94 return FALSE;
97 return TRUE;
100 gboolean valid_element_path(gchar **path, gboolean has_value)
102 gchar **p;
104 for (p = path; *p; p++) {
106 * An empty element is valid and don't check the syntax of the
107 * content.
109 if (has_value == TRUE && (!*(p+1) || !*p[0]))
110 break;
112 if (valid_xml_element((xmlChar *)*p) == FALSE)
113 return FALSE;
116 return TRUE;
119 gpg_error_t new_account(xmlDocPtr doc, gchar *name)
121 xmlNodePtr root = xmlDocGetRootElement(doc);
122 xmlAttrPtr a;
123 xmlNodePtr n;
124 gchar *p = name;
126 if (!p || !root)
127 return EPWMD_LIBXML_ERROR;
129 if (*p == '!')
130 p++;
132 n = xmlNewNode(NULL, (xmlChar *)"root");
133 n = xmlAddChild(root, n);
134 a = xmlNewProp(n, (xmlChar *)"name", (xmlChar *)p);
135 return 0;
138 xmlDocPtr create_dtd()
140 xmlDocPtr doc;
141 xmlTextWriterPtr wr = xmlNewTextWriterDoc(&doc, 0);
143 if (!wr)
144 return NULL;
146 if (xmlTextWriterStartDocument(wr, NULL, NULL, NULL))
147 goto fail;
149 if (xmlTextWriterStartDTD(wr, (xmlChar *)"pwmd", NULL, NULL) == -1)
150 goto fail;
152 if (xmlTextWriterWriteDTDElement(wr, (xmlChar *)"pwmd",
153 (xmlChar *)"(root)") == -1)
154 goto fail;
156 xmlTextWriterEndDTDElement(wr);
158 if (xmlTextWriterWriteDTDAttlist(wr, (xmlChar *)"root",
159 (xmlChar *)"name CDATA #REQUIRED") == -1)
160 goto fail;
162 xmlTextWriterEndDTDAttlist(wr);
163 xmlTextWriterEndDTD(wr);
165 if (xmlTextWriterStartElement(wr, (xmlChar *)"pwmd"))
166 goto fail;
168 xmlTextWriterEndElement(wr);
169 xmlTextWriterEndDocument(wr);
170 xmlFreeTextWriter(wr);
171 return doc;
173 fail:
174 xmlTextWriterEndDocument(wr);
175 xmlFreeTextWriter(wr);
176 xmlFreeDoc(doc);
177 return NULL;
180 xmlChar *new_document()
182 xmlChar *xml;
183 gint len;
184 xmlDocPtr doc = create_dtd();
186 if (!doc)
187 return NULL;
189 xmlDocDumpMemory(doc, &xml, &len);
190 xmlFreeDoc(doc);
191 return xml;
195 * Lists root account element names. If there's a target attribute both
196 * literal and non-literal element names will be added.
198 gpg_error_t list_accounts(xmlDocPtr doc, GString **result)
200 xmlNodePtr n = NULL;
201 GSList *list = NULL;
202 gint total, i;
203 GString *string;
204 gpg_error_t rc = 0;
206 n = xmlDocGetRootElement(doc);
208 if (!n || !n->children)
209 return EPWMD_EMPTY_ELEMENT;
211 for (n = n->children; n; n = n->next) {
212 xmlAttrPtr a;
213 xmlChar *val, *target;
214 GSList *tlist;
215 gchar *tmp;
217 if (n->type != XML_ELEMENT_NODE)
218 continue;
220 a = xmlHasProp(n, (xmlChar *)"name");
222 if (!a || !a->children->content)
223 continue;
225 val = xmlNodeGetContent(a->children);
227 if (!val) {
228 rc = gpg_error_from_errno(ENOMEM);
229 goto fail;
232 tmp = g_strdup_printf("!%s", (gchar *)val);
234 if (!tmp) {
235 xmlFree(val);
236 rc = gpg_error_from_errno(ENOMEM);
237 goto fail;
240 tlist = g_slist_append(list, tmp);
242 if (!tlist) {
243 xmlFree(val);
244 rc = gpg_error_from_errno(ENOMEM);
245 goto fail;
248 list = tlist;
249 target = node_has_attribute(n, (xmlChar *)"target");
251 if (target) {
252 gchar *t = g_strdup((gchar *)val);
254 if (!t) {
255 xmlFree(val);
256 xmlFree(target);
257 rc = gpg_error_from_errno(ENOMEM);
258 goto fail;
261 tlist = g_slist_append(list, t);
263 if (!tlist) {
264 g_free(t);
265 xmlFree(target);
266 rc = gpg_error_from_errno(ENOMEM);
267 goto fail;
270 list = tlist;
273 xmlFree(val);
274 xmlFree(target);
277 total = g_slist_length(list);
279 if (!total)
280 return EPWMD_EMPTY_ELEMENT;
282 string = g_string_new(NULL);
284 if (!string) {
285 rc = gpg_error_from_errno(ENOMEM);
286 goto fail;
289 for (i = 0; i < total; i++) {
290 gchar *val = g_slist_nth_data(list, i);
292 g_string_append_printf(string, "%s\n", val);
295 string = g_string_truncate(string, string->len - 1);
296 *result = string;
298 fail:
299 total = g_slist_length(list);
301 for (i = 0; i < total; i++)
302 g_free(g_slist_nth_data(list, i));
304 g_slist_free(list);
305 return rc;
309 * Prevents a sibling element past the current element path with the same
310 * element name.
312 static xmlNodePtr find_stop_node(xmlNodePtr node)
314 xmlNodePtr n;
316 for (n = node->parent->children; n; n = n->next) {
317 if (n == node)
318 return n->next;
321 return NULL;
325 * Alot like create_elements_cb() but doesn't use the last element of 'req' as
326 * content but as an element.
328 xmlNodePtr create_target_elements_cb(xmlNodePtr node, gchar **path,
329 gpg_error_t *rc, void *data)
331 gint i;
332 char **req = path;
334 if (xmlStrEqual(node->name, (xmlChar *)*req))
335 req++;
337 for (i = 0; req[i]; i++) {
338 xmlNodePtr n;
340 if ((n = find_element(node, req[i], find_stop_node(node))) == NULL ||
341 (n && n->parent == node->parent)) {
342 is_literal_element(&req[i]);
343 n = xmlNewNode(NULL, (xmlChar *)req[i]);
345 if (!n) {
346 *rc = gpg_error_from_errno(ENOMEM);
347 return NULL;
350 node = xmlAddChild(node, n);
352 if (!node) {
353 *rc = gpg_error_from_errno(ENOMEM);
354 return NULL;
357 else
358 node = n;
361 return node;
364 xmlNodePtr find_text_node(xmlNodePtr node)
366 xmlNodePtr n = node;
368 if (n && n->type == XML_TEXT_NODE)
369 return n;
371 for (n = node; n; n = n->next) {
372 if (n->type == XML_TEXT_NODE)
373 return n;
376 return NULL;
379 xmlNodePtr create_elements_cb(xmlNodePtr node, gchar **elements,
380 gpg_error_t *rc, void *data)
382 gint i;
383 gchar **req = elements;
385 if (node->type == XML_TEXT_NODE)
386 node = node->parent;
388 if (node->name && xmlStrEqual(node->name, (xmlChar *)*req))
389 req++;
391 for (i = 0; req[i]; i++) {
392 xmlNodePtr n;
394 if (req[i+1]) {
396 * Strip the first '!' if needed. If there's another, it's an
397 * rc. The syntax has already been checked before calling this
398 * function.
400 is_literal_element(&req[i]);
404 * The value of the element tree.
406 if (!req[i+1]) {
407 n = find_text_node(node->children);
409 if (!n)
410 /* Use AddContent here to prevent overwriting any children. */
411 xmlNodeAddContent(node, (xmlChar *)req[i]);
412 else if (n && !*req[i])
413 xmlNodeSetContent(n, NULL);
414 else
415 xmlNodeSetContent(n, (xmlChar *)req[i]);
417 break;
420 n = find_element(node, req[i], find_stop_node(node));
423 * If the found element has the same parent as the current element,
424 * they are siblings and the new element needs to be created as a
425 * child of the current element (node).
427 if (n && n->parent == node->parent)
428 n = NULL;
430 if (!n) {
431 n = xmlNewNode(NULL, (xmlChar *)req[i]);
433 if (!n) {
434 *rc = gpg_error_from_errno(ENOMEM);
435 return NULL;
438 node = xmlAddChild(node, n);
440 if (!node) {
441 *rc = gpg_error_from_errno(ENOMEM);
442 return NULL;
445 else
446 node = n;
449 return node;
452 xmlNodePtr find_account(xmlDocPtr doc, gchar ***req, gpg_error_t *rc,
453 gboolean *target, gint recursion_depth)
455 xmlNodePtr n = xmlDocGetRootElement(doc);
456 gint depth = 0;
457 gchar *account = g_strdup(*req[0]);
458 gboolean literal = is_literal_element(&account);
460 if (!account) {
461 *rc = gpg_error_from_errno(ENOMEM);
462 return NULL;
465 *rc = 0;
466 recursion_depth++;
468 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth) {
469 xmlChar *t = xmlGetNodePath(n);
471 log_write("%s: %s", pwmd_strerror(EPWMD_LOOP), t);
472 xmlFree(t);
473 *rc = EPWMD_LOOP;
474 return NULL;
477 while (n) {
478 if (n->type == XML_ELEMENT_NODE) {
479 if (depth == 0 && xmlStrEqual(n->name, (xmlChar *)"pwmd")) {
480 n = n->children;
481 depth++;
482 continue;
485 if (depth == 1 && xmlStrEqual(n->name, (xmlChar *)"root")) {
486 xmlChar *content = node_has_attribute(n, (xmlChar *)"name");
488 if (!content)
489 continue;
491 if (xmlStrEqual(content, (xmlChar *)account)) {
492 gchar **nreq, **tmp = NULL;
494 if (literal == TRUE) {
495 xmlFree(content);
496 g_free(account);
497 return n;
500 xmlFree(content);
501 content = node_has_attribute(n, (xmlChar *)"target");
503 if (!content) {
504 g_free(account);
505 return n;
508 if (strchr((gchar *)content, '\t')) {
509 nreq = split_input_line((gchar *)content, "\t", 0);
510 xmlFree(content);
512 #if 0
514 * FIXME ENOMEM
516 if (!nreq) {
517 *rc = gpg_error_from_errno(ENOMEM);
518 return NULL;
520 #endif
522 tmp = *req;
523 tmp = strvcatv(nreq, tmp+1);
524 g_strfreev(nreq);
526 if (!tmp) {
527 *rc = gpg_error_from_errno(ENOMEM);
528 return NULL;
531 g_strfreev(*req);
532 *req = tmp;
534 else {
535 if (strv_printf(&tmp, "%s", content) == FALSE) {
536 xmlFree(content);
537 *rc = gpg_error_from_errno(ENOMEM);
538 return NULL;
541 xmlFree(content);
542 nreq = *req;
543 nreq = strvcatv(tmp, nreq+1);
544 g_strfreev(tmp);
546 if (!nreq) {
547 *rc = gpg_error_from_errno(ENOMEM);
548 return NULL;
551 g_strfreev(*req);
552 *req = nreq;
555 if (target)
556 *target = TRUE;
558 g_free(account);
559 n = find_account(doc, req, rc, target, recursion_depth);
560 return n;
565 n = n->next;
568 g_free(account);
569 *rc = EPWMD_ELEMENT_NOT_FOUND;
570 return NULL;
573 static xmlNodePtr find_element(xmlNodePtr node, gchar *element, xmlNodePtr stop)
575 xmlNodePtr n;
577 if (!node || !element)
578 return NULL;
580 for (n = node; n; n = n->next) {
581 if (n->type != XML_ELEMENT_NODE)
582 continue;
584 if (n == stop)
585 break;
587 if (xmlStrEqual(n->name, (xmlChar *)element))
588 return n;
591 return NULL;
594 static xmlChar *node_has_attribute(xmlNodePtr n, xmlChar *attr)
596 xmlAttrPtr a = xmlHasProp(n, attr);
598 if (!a)
599 return NULL;
601 if (!a->children || !a->children->content)
602 return NULL;
604 return xmlGetProp(n, attr);
607 static gboolean element_to_literal(gchar **element)
609 gchar *p = g_strdup_printf("!%s", *element);
611 if (!p)
612 return FALSE;
614 g_free(*element);
615 *element = p;
616 return TRUE;
619 xmlNodePtr find_elements(xmlDocPtr doc, xmlNodePtr node,
620 gchar **req, gpg_error_t *rc, gboolean *target,
621 xmlNodePtr (*found_fn)(xmlNodePtr, gchar **, gpg_error_t *, gchar **, void *),
622 xmlNodePtr (*not_found_fn)(xmlNodePtr, gchar **, gpg_error_t *, void *),
623 gboolean is_list_command, gint recursion_depth, void *data)
625 xmlNodePtr n, last, last_node;
626 gchar **p;
627 gint found = 0;
629 *rc = 0;
630 recursion_depth++;
632 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth) {
633 xmlChar *t = xmlGetNodePath(node);
635 log_write("%s: %s", pwmd_strerror(EPWMD_LOOP), t);
636 xmlFree(t);
637 recursion_depth--;
638 *rc = EPWMD_LOOP;
639 return NULL;
642 for (last_node = last = n = node, p = req; *p; p++) {
643 xmlNodePtr tmp;
644 gchar *t = g_strdup(*p);
645 gboolean literal;
647 if (!t) {
648 *rc = gpg_error_from_errno(ENOMEM);
649 return NULL;
652 literal = is_literal_element(&t);
653 n = find_element(last, t, NULL);
654 g_free(t);
656 if (!n) {
657 if (not_found_fn)
658 return not_found_fn(found ? last_node : last_node->parent, p, rc, data);
660 *rc = EPWMD_ELEMENT_NOT_FOUND;
661 return NULL;
664 last = n->children;
665 last_node = n;
666 found = 1;
668 if (literal == FALSE) {
669 xmlChar *content = node_has_attribute(n, (xmlChar *)"target");
670 gchar **nreq = NULL, **nnreq;
672 if (!content) {
673 if (is_list_command == TRUE) {
674 if (element_to_literal(&(*p)) == FALSE) {
675 *rc = gpg_error_from_errno(ENOMEM);
676 return NULL;
680 continue;
683 if (strchr((gchar *)content, '\t') != NULL) {
684 if ((nreq = split_input_line((gchar *)content, "\t", 0)) == NULL) {
685 xmlFree(content);
686 *rc = EPWMD_INVALID_ELEMENT;
687 return NULL;
690 else {
691 if ((nreq = split_input_line((gchar *)content, " ", 0)) == NULL) {
692 xmlFree(content);
693 *rc = EPWMD_INVALID_ELEMENT;
694 return NULL;
698 xmlFree(content);
699 tmp = find_account(doc, &nreq, rc, target, 0);
701 if (!tmp) {
702 g_strfreev(nreq);
703 return NULL;
706 if (found_fn) {
707 found_fn(tmp, nreq, rc, p+1, data);
709 if (*rc) {
710 g_strfreev(nreq);
711 return NULL;
715 nnreq = strvcatv(nreq+1, p+1);
716 g_strfreev(nreq);
718 // FIXME ENOMEM
719 if (!nnreq || !*nnreq) {
720 if (nnreq)
721 g_strfreev(nnreq);
723 return tmp;
726 if (target)
727 *target = TRUE;
729 n = find_elements(doc, tmp->children, nnreq, rc, NULL, found_fn,
730 not_found_fn, is_list_command, recursion_depth, data);
732 if (*(p+1)) {
733 gchar **zz = p+1, **qq = nnreq;
735 if (g_strv_length(nnreq) > g_strv_length(p+1))
736 qq = nnreq+1;
738 for (; *qq && *zz; zz++) {
739 g_free(*zz);
740 *zz = g_strdup(*qq++);
742 if (!*zz) {
743 *rc = gpg_error_from_errno(ENOMEM);
744 n = NULL;
745 break;
750 g_strfreev(nnreq);
751 return n;
755 return n;
758 static gboolean update_element_list(struct element_list_s *elements)
760 gchar *line;
761 GSList *l;
763 if (!elements || !elements->elements)
764 return TRUE;
766 line = g_strjoinv("\t", elements->elements);
768 if (!line)
769 return FALSE;
771 g_strfreev(elements->elements);
772 elements->elements = NULL;
773 l = g_slist_append(elements->list, line);
775 if (!l)
776 return FALSE;
778 elements->list = l;
779 return TRUE;
782 static gpg_error_t path_list_recurse(xmlDocPtr doc, xmlNodePtr node,
783 struct element_list_s *elements)
785 gpg_error_t rc = 0;
786 xmlNodePtr n;
788 for (n = node; n; n = n->next) {
789 xmlChar *target = NULL;
791 if (n->type != XML_ELEMENT_NODE)
792 goto children;
794 if (strv_printf(&elements->elements, "%s\t!%s", elements->prefix, n->name) == FALSE)
795 return gpg_err_code_from_errno(ENOMEM);
797 if (update_element_list(elements) == FALSE)
798 return gpg_err_code_from_errno(ENOMEM);
800 target = node_has_attribute(n, (xmlChar *)"target");
802 if (target) {
803 gchar *tmp;
804 gchar *save = elements->prefix;
805 gboolean r = elements->resolving;
807 elements->depth++;
809 if (max_recursion_depth >= 1 && elements->depth > max_recursion_depth) {
810 xmlChar *t = xmlGetNodePath(n);
811 log_write("%s: %s", pwmd_strerror(EPWMD_LOOP), t);
812 xmlFree(t);
813 xmlFree(target);
814 return EPWMD_LOOP;
817 if (strv_printf(&elements->elements, "%s\t%s", elements->prefix, n->name) == FALSE) {
818 xmlFree(target);
819 return gpg_err_code_from_errno(ENOMEM);
822 tmp = g_strjoinv("\t", elements->elements);
824 if (!tmp) {
825 xmlFree(target);
826 return gpg_err_code_from_errno(ENOMEM);
829 if (update_element_list(elements) == FALSE) {
830 xmlFree(target);
831 return gpg_err_code_from_errno(ENOMEM);
834 elements->prefix = tmp;
835 elements->resolving = TRUE;
836 rc = create_path_list(doc, elements, (gchar *)target);
837 xmlFree(target);
838 elements->resolving = r;
839 elements->depth--;
840 g_free(tmp);
841 elements->prefix = save;
843 if (rc)
844 return rc;
847 children:
848 if (n->children) {
849 gchar *tmp = g_strdup_printf("%s\t!%s", elements->prefix, n->name);
850 gchar *save = elements->prefix;
852 if (!tmp)
853 return gpg_err_code_from_errno(ENOMEM);
855 elements->prefix = tmp;
856 rc = path_list_recurse(doc, n->children, elements);
857 g_free(elements->prefix);
858 elements->prefix = save;
860 if (rc)
861 return rc;
865 return rc;
869 * From the element path 'path', find sub-nodes and append them to the list.
871 gpg_error_t create_path_list(xmlDocPtr doc, struct element_list_s *elements,
872 gchar *path)
874 gpg_error_t rc;
875 gchar **req, **req_orig;
876 xmlNodePtr n;
877 gboolean a_target = FALSE;
879 req = split_input_line(path, "\t", 0);
881 if (!req) {
882 req = split_input_line(path, " ", 0);
884 if (!req)
885 return EPWMD_COMMAND_SYNTAX;
888 req_orig = g_strdupv(req);
890 if (!req_orig) {
891 rc = gpg_err_code_from_errno(ENOMEM);
892 goto fail;
895 n = find_account(doc, &req, &rc, &a_target, 0);
897 if (!n && rc == EPWMD_ELEMENT_NOT_FOUND && elements->resolving == TRUE) {
898 rc = 0;
899 goto fail;
901 else if (!n)
902 goto fail;
904 if (a_target == TRUE) {
905 g_free(*req);
906 *req = g_strdup(*req_orig);
909 if (*(req+1)) {
910 gboolean e_target = FALSE;
912 n = find_elements(doc, n->children, req+1, &rc, &e_target, NULL, NULL, TRUE, 0, NULL);
914 if (!n && rc == EPWMD_ELEMENT_NOT_FOUND && elements->resolving == TRUE) {
915 rc = 0;
916 goto fail;
918 else if (!n)
919 goto fail;
922 if (!elements->prefix) {
924 * FIXME
926 * If any req_orig element contains no target the element should be
927 * prefixed with the literal character. Not really crucial if the
928 * client isn't human because child elements are prefixed for the
929 * current path. But may be confusing if editing by hand.
931 elements->prefix = g_strjoinv("\t", req_orig);
933 if (!elements->prefix) {
934 rc = gpg_err_code_from_errno(ENOMEM);
935 goto fail;
938 if (strv_printf(&elements->elements, "%s", elements->prefix) == FALSE) {
939 rc = gpg_err_code_from_errno(ENOMEM);
940 goto fail;
943 if (update_element_list(elements) == FALSE) {
944 rc = gpg_err_code_from_errno(ENOMEM);
945 goto fail;
949 rc = path_list_recurse(doc, n->children, elements);
951 fail:
952 if (req_orig)
953 g_strfreev(req_orig);
955 g_strfreev(req);
956 return rc;
959 gpg_error_t recurse_xpath_nodeset(xmlDocPtr doc, xmlNodeSetPtr nodes,
960 xmlChar *value, xmlBufferPtr *result)
962 gint i = value ? nodes->nodeNr - 1 : 0;
963 xmlBufferPtr buf;
965 buf = xmlBufferCreate();
967 if (!buf)
968 return gpg_err_code_from_errno(ENOMEM);
970 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++) {
971 xmlNodePtr n = nodes->nodeTab[i];
973 if (!n)
974 continue;
976 if (!value) {
977 if (xmlNodeDump(buf, doc, n, 0, 0) == -1) {
978 *result = buf;
979 return EPWMD_LIBXML_ERROR;
982 continue;
985 xmlNodeSetContent(n, value);
988 *result = buf;
989 return 0;
992 /* Updates the DTD and renames the root "accounts" and "account" elements. */
993 gpg_error_t convert_xml(gchar **xml, goffset *len)
995 gpg_error_t rc = EPWMD_LIBXML_ERROR;
996 xmlDocPtr doc, new = NULL;
997 xmlNodePtr n;
999 doc = xmlReadMemory(*xml, *len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1001 if (!doc)
1002 return EPWMD_LIBXML_ERROR;
1004 gcry_free(*xml);
1005 *xml = NULL;
1006 n = xmlDocGetRootElement(doc);
1007 xmlNodeSetName(n, (xmlChar *)"pwmd");
1009 for (n = n->children; n; n = n->next) {
1010 if (xmlStrcmp(n->name, (xmlChar *)"account") == 0)
1011 xmlNodeSetName(n, (xmlChar *)"root");
1014 new = create_dtd();
1016 if (!new)
1017 goto fail;
1019 n = xmlDocGetRootElement(doc);
1020 xmlDocSetRootElement(new, n);
1021 xmlDocDumpMemory(new, (xmlChar **)xml, (gint *)len);
1022 xmlDocSetRootElement(new, xmlCopyNode(n, 0));
1023 rc = 0;
1025 fail:
1026 if (new)
1027 xmlFreeDoc(new);
1029 xmlFreeDoc(doc);
1030 return rc;