Add STATUS_MODIFIED.
[pwmd.git] / src / xml.c
blob581f3f21313d599eb76a96fce3ef4e2a74f627ea
1 /*
2 Copyright (C) 2006-2022 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd 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 Pwmd. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #include <errno.h>
28 #include <err.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34 #include <ctype.h>
35 #include <libxml/xmlwriter.h>
36 #include <wctype.h>
37 #include <sys/types.h>
38 #include <pwd.h>
40 #ifndef _
41 #include "gettext.h"
42 #define _(msgid) gettext(msgid)
43 #endif
45 #include "pwmd-error.h"
46 #include "util-misc.h"
47 #include "xml.h"
48 #include "mem.h"
49 #include "rcfile.h"
50 #include "commands.h"
51 #include "acl.h"
53 #define XML_LIST_FLAG_CHILDREN 0x0001
54 #define XML_LIST_HAS_TARGET 0x0002
55 #define XML_LIST_CHILD_TARGET 0x0004
56 #define XML_LIST_TARGET_ERROR 0x0008
57 #define XML_LIST_CHECK 0x0010
59 const char *reserved_attributes[] = {
60 "_name", "_mtime", "_ctime", "_acl", "_target",
61 NULL
64 const char *protected_attributes[] = {
65 "_name", "_mtime", "_ctime", NULL
68 void log_write (const char *fmt, ...);
69 static xmlRegexpPtr username_re;
71 gpg_error_t
72 xml_init ()
74 xmlMemSetup (xfree, xmalloc, xrealloc, str_dup);
75 xmlInitMemory ();
76 xmlInitGlobals ();
77 xmlInitParser ();
78 xmlXPathInit ();
79 username_re = xmlRegexpCompile ((xmlChar *)"[a-zA-Z#][-.a-zA-Z0-9]*");
80 return username_re ? 0 : GPG_ERR_ENOMEM;
83 void
84 xml_deinit ()
86 xmlCleanupParser ();
87 xmlCleanupGlobals ();
88 xmlRegFreeRegexp (username_re);
91 gpg_error_t
92 xml_protected_attr (const char *a)
94 int i;
96 for (i = 0; protected_attributes[i]; i++)
98 if (!strcmp (a, protected_attributes[i]))
99 return GPG_ERR_EPERM;
102 return 0;
106 xml_valid_attribute_value (const char *str)
108 const char *p = str;
110 if (!p || !*p)
111 return 1;
113 while (*p)
115 if (*p++ == '\n')
116 return 0;
119 return 1;
123 xml_valid_attribute (const char *str)
125 wchar_t *wc;
126 size_t len, c;
127 int ret = xml_valid_element ((xmlChar *)str);
129 if (!ret)
130 return ret;
132 wc = str_to_wchar ((const char *)str);
133 if (!wc)
134 return 0;
136 len = wcslen (wc);
137 for (c = 0; c < len; c++)
139 /* Fixes cygwin compile time warning about exceeding the maximum value
140 * for the type in the switch() statement below. */
141 if (wc[c] >= 0x10000 && wc[c] <= 0xEFFFF)
142 continue;
144 switch (wc[c])
146 case '-':
147 case '.':
148 case '0' ... '9':
149 case 0xB7:
150 case 0x0300 ... 0x036F:
151 case 0x203F ... 0x2040:
152 if (!c)
154 xfree (wc);
155 return 0;
157 case ':': break;
158 case '_': break;
159 case 'A' ... 'Z': break;
160 case 'a' ... 'z': break;
161 case 0xC0 ... 0xD6: break;
162 case 0xD8 ... 0xF6: break;
163 case 0xF8 ... 0x2FF: break;
164 case 0x370 ... 0x37D: break;
165 case 0x37F ... 0x1FFF: break;
166 case 0x200C ... 0x200D: break;
167 case 0x2070 ... 0x218F: break;
168 case 0x2C00 ... 0x2FEF: break;
169 case 0x3001 ... 0xD7FF: break;
170 case 0xF900 ... 0xFDCF: break;
171 case 0xFDF0 ... 0xFFFD: break;
172 default:
173 xfree (wc);
174 return 0;
178 xfree (wc);
179 return 1;
183 xml_valid_element (xmlChar *str)
185 wchar_t *wc;
186 size_t len, c;
188 if (!str || !*str)
189 return 0;
191 wc = str_to_wchar ((const char *)str);
192 if (!wc)
193 return 0;
195 len = wcslen (wc);
196 for (c = 0; c < len; c++)
198 if (iswspace(wc[c]))
200 xfree (wc);
201 return 0;
205 xfree (wc);
206 return 1;
210 xml_valid_element_path (char **path, int with_content)
212 char **dup = NULL, **p;
214 if (!path || !*path)
215 return 0;
217 /* Save some memory by not duplicating the element content. */
218 if (with_content)
220 int i, t = strv_length (path);
222 for (i = 0; i < t - 1; i++)
224 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
226 if (!tmp)
228 strv_free (dup);
229 return 0;
232 dup = tmp;
233 dup[i] = str_dup (path[i]);
234 dup[i + 1] = NULL;
237 else
238 dup = strv_dup (path);
240 if (!dup)
241 return 0;
243 for (p = dup; *p && *(*p); p++)
245 if (!xml_valid_element ((xmlChar *) * p))
247 strv_free (dup);
248 return 0;
252 strv_free (dup);
253 return 1;
256 static gpg_error_t
257 attr_ctime (struct client_s *client, xmlNodePtr n)
259 char *buf = str_asprintf ("%li", time (NULL));
260 gpg_error_t rc;
262 if (!buf)
263 return GPG_ERR_ENOMEM;
265 rc = xml_add_attribute (client, n, "_ctime", buf);
266 xfree (buf);
267 return rc;
270 gpg_error_t
271 xml_acl_check (struct client_s *client, xmlNodePtr n)
273 gpg_error_t rc = GPG_ERR_EACCES;
274 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
275 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
276 char **p;
277 int allowed = 0;
279 if (!acl || !*acl || !users || !*users)
281 xmlFree (acl);
282 strv_free(users);
283 return peer_is_invoker(client);
286 if (!peer_is_invoker(client))
288 xmlFree (acl);
289 strv_free(users);
290 return 0;
293 for (p = users; p && *p; p++)
295 #ifdef WITH_GNUTLS
296 rc = acl_check_common (client, *p,
297 client->thd->remote ? 0 : client->thd->peer->uid,
298 client->thd->remote ? 0 : client->thd->peer->gid,
299 &allowed);
300 #else
301 rc = acl_check_common (client, *p, client->thd->peer->uid,
302 client->thd->peer->gid, &allowed);
303 #endif
306 xmlFree(acl);
307 strv_free(users);
309 if (rc)
310 return rc;
312 return allowed ? 0 : GPG_ERR_EACCES;
315 static char *
316 create_acl_user (struct client_s *client)
318 #ifdef WITH_GNUTLS
319 if (client->thd->remote)
320 return str_asprintf ("#%s", client->thd->tls->fp);
321 #endif
323 return get_username (client->thd->peer->uid);
326 static gpg_error_t
327 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
328 const char *name, xmlNodePtr * result)
330 xmlNodePtr n;
331 gpg_error_t rc;
332 int root = 0;
334 // Allow any client to create a non-existing root element.
335 if (parent->parent->type != XML_DOCUMENT_NODE)
337 rc = xml_acl_check(client, parent);
338 if (rc)
339 return rc;
341 else
342 root = 1;
344 n = xmlNewNode (NULL, (xmlChar *) "element");
345 if (!n)
346 return GPG_ERR_ENOMEM;
348 rc = xml_add_attribute (client, n, "_name", name);
349 if (!rc)
350 rc = attr_ctime (client, n);
352 if (!rc && verify && !root)
353 rc = xml_is_element_owner (client, parent, 0);
355 if (!rc)
357 xmlNodePtr p = xmlAddChild (parent, n);
358 char *user = create_acl_user (client);
360 if (result)
361 *result = p;
363 if (root || (client->flags & FLAG_NO_INHERIT_ACL))
364 rc = xml_add_attribute(client, p, "_acl", user);
365 else
367 /* Inherit the parent _acl attribute and make the current user the
368 owner. */
369 xmlChar *a = xml_attribute_value (parent, (xmlChar *)"_acl");
370 if (a)
372 if (xml_is_element_owner (client, parent, 1))
374 char *tmp = str_asprintf ("%s,%s", user, a);
376 rc = xml_add_attribute(client, p, "_acl", tmp);
377 xfree (tmp);
379 else
380 rc = xml_add_attribute(client, p, "_acl", (char *)a);
383 xmlFree (a);
386 xfree (user);
388 else
389 xmlFreeNode (n);
391 return rc;
394 gpg_error_t
395 xml_new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
397 xmlNodePtr root = xmlDocGetRootElement (doc);
399 if (!name || !root)
400 return GPG_ERR_BAD_DATA;
402 if (!xml_valid_element ((xmlChar *) name))
403 return GPG_ERR_INV_VALUE;
405 return create_new_element (client, 0, root, name, NULL);
408 static xmlDocPtr
409 create_dtd ()
411 xmlDocPtr doc;
412 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
414 if (!wr)
415 return NULL;
417 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
418 goto fail;
420 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
421 goto fail;
423 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
424 (xmlChar *) "(element)") == -1)
425 goto fail;
427 xmlTextWriterEndDTDElement (wr);
429 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
430 (xmlChar *) "_name CDATA #REQUIRED") ==
432 goto fail;
434 xmlTextWriterEndDTDAttlist (wr);
435 xmlTextWriterEndDTD (wr);
437 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
438 goto fail;
440 xmlTextWriterEndElement (wr);
441 xmlTextWriterEndDocument (wr);
442 xmlFreeTextWriter (wr);
443 return doc;
445 fail:
446 xmlTextWriterEndDocument (wr);
447 xmlFreeTextWriter (wr);
448 xmlFreeDoc (doc);
449 return NULL;
452 xmlDocPtr
453 xml_new_document ()
455 return create_dtd ();
458 static xmlNodePtr
459 find_element_node (xmlNodePtr node)
461 xmlNodePtr n = node;
463 if (n && n->type == XML_ELEMENT_NODE)
464 return n;
466 for (n = node; n; n = n->next)
468 if (n->type == XML_ELEMENT_NODE)
469 return n;
472 return NULL;
475 xmlNodePtr
476 xml_resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
477 char ***result, gpg_error_t *rc)
479 xmlNodePtr n;
480 struct xml_request_s *req;
482 *rc = xml_new_request (client, (char *)path, XML_CMD_REALPATH, &req);
483 if (*rc)
484 return NULL;
486 n = xml_find_elements (client, req, xmlDocGetRootElement (doc), rc);
487 if (!*rc)
489 if (result)
491 *result = strv_dup (req->args);
492 if (!*result)
494 *rc = GPG_ERR_ENOMEM;
495 n = NULL;
500 xml_free_request (req);
501 return n;
504 xmlNodePtr
505 xml_find_text_node (xmlNodePtr node)
507 xmlNodePtr n = node;
509 if (n && n->type == XML_TEXT_NODE)
510 return n;
512 for (n = node; n; n = n->next)
514 if (n->type == XML_TEXT_NODE)
515 return n;
518 return NULL;
521 /* Create an element 'path' starting at 'node'. Returns the node of the final
522 * created element.
524 xmlNodePtr
525 xml_create_element_path (struct client_s *client, struct xml_request_s *req,
526 xmlNodePtr node, char **path, gpg_error_t *rc)
528 char **p;
530 if (!xml_valid_element_path (path, 0))
532 *rc = GPG_ERR_INV_VALUE;
533 return NULL;
536 /* The parent node will be an XML_ELEMENT_NODE. Otherwise we would be
537 * creating element content. */
538 if (node->type == XML_TEXT_NODE)
539 node = node->parent;
541 for (p = path; p && *p; p++)
543 xmlNodePtr n = NULL;
545 if (node != xmlDocGetRootElement (req->doc))
547 n = xml_find_element (client, node->children, *p, rc);
548 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
549 return NULL;
551 *rc = 0;
555 * If the found element has the same parent as the current element then
556 * they are siblings and the new element needs to be created as a child
557 * of the current element (node).
559 if (n && n->parent == node->parent)
560 n = NULL;
562 if (!n)
564 *rc = create_new_element (client, 0, node, *p, &node);
565 if (*rc)
566 return NULL;
568 else
569 node = n;
572 return node;
575 /* Find the first XML_ELEMENT_NODE whose _name attribute matches 'element'. */
576 xmlNodePtr
577 xml_find_element (struct client_s *client, xmlNodePtr node, const char *element,
578 gpg_error_t *rc)
580 xmlNodePtr n;
582 *rc = 0;
584 if (!node || !element)
586 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
587 return NULL;
590 for (n = node; n; n = n->next)
592 if (n->type != XML_ELEMENT_NODE)
593 continue;
595 xmlChar *a = xml_attribute_value (n, (xmlChar *) "_name");
596 if (a && xmlStrEqual (a, (xmlChar *) element))
598 xmlFree (a);
599 *rc = xml_acl_check (client, n);
600 return n; // Not NULL since the node may be needed later
603 xmlFree (a);
606 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
607 return NULL;
610 xmlChar *
611 xml_attribute_value (xmlNodePtr n, xmlChar * attr)
613 xmlAttrPtr a = xmlHasProp (n, attr);
615 if (!a)
616 return NULL;
618 if (!a->children || !a->children->content)
619 return NULL;
621 return xmlGetProp (n, attr);
624 gpg_error_t
625 xml_remove_user_attributes (struct client_s *client, xmlNodePtr n)
627 gpg_error_t rc = 0;
628 xmlAttrPtr a = n->properties;
630 while (a)
632 if (!xml_reserved_attribute ((const char *)a->name))
634 rc = xml_delete_attribute (client, n, a->name);
635 if (rc)
636 break;
638 a = n->properties;
640 else
641 a = a->next;
644 return rc;
647 gpg_error_t
648 xml_valid_username (const char *str)
650 char **list = str_split (str, ",", 0);
651 char **p;
653 if (!list)
654 return str && *str ? GPG_ERR_ENOMEM : GPG_ERR_INV_VALUE;
656 for (p = list; *p; p++)
658 int e = xmlRegexpExec (username_re, (xmlChar *)*p);
659 if (e != 1)
661 strv_free (list);
662 return GPG_ERR_INV_USER_ID;
666 strv_free (list);
667 return 0;
670 gpg_error_t
671 xml_add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
672 const char *value)
674 char *buf;
675 gpg_error_t rc = 0;
676 int is_target = 0;
678 if (client && name && !strcmp (name, "_target"))
680 rc = xml_is_element_owner (client, node, 0);
681 if (rc)
682 return rc;
684 is_target = 1;
686 else if (name && (!strcmp (name, "_expire")
687 || !strcmp (name, "_ctime")
688 || !strcmp (name, "_mtime")))
690 char *p;
691 time_t e;
693 if (!value || !*value)
694 return GPG_ERR_INV_VALUE;
696 errno = 0;
697 e = strtoul (value, &p, 10);
698 if (errno || *p || e == ULONG_MAX || *value == '-')
699 return GPG_ERR_INV_VALUE;
702 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
703 return GPG_ERR_BAD_DATA;
705 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
707 xmlChar *acl = xml_attribute_value (node, (xmlChar *) "_acl");
709 if (!acl || !*acl)
711 char *user = create_acl_user (client);
713 if (user)
715 rc = xml_add_attribute (client, node, (char *) "_acl", user);
716 xfree (user);
719 return rc;
722 xmlFree (acl);
725 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
726 return 0;
728 if (is_target)
729 xml_remove_user_attributes (client, node);
731 buf = str_asprintf ("%lu", time (NULL));
732 rc = xml_add_attribute (client, node, "_mtime", buf);
733 xfree (buf);
734 return rc;
737 static gpg_error_t
738 append_path_to_list (struct client_s *client, struct element_list_s *elements,
739 const char *path, gpg_error_t rc)
741 struct slist_s *l;
742 struct string_s *line;
744 (void)client;
745 line = string_new (NULL);
746 if (!line)
747 return GPG_ERR_ENOMEM;
749 if (rc == GPG_ERR_ELOOP)
750 string_append (line, "O");
751 else if (rc == GPG_ERR_EACCES)
752 string_append (line, "P");
753 else if (rc)
754 string_append (line, "E");
756 if (rc || elements->target)
757 string_prepend (line, " ");
759 if ((!rc || rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
760 || rc == GPG_ERR_ELEMENT_NOT_FOUND) && elements->target)
761 string_append_printf (line, "%sT %s",
762 (!rc && elements->flags & XML_LIST_FLAG_CHILDREN) ? "+" : "",
763 elements->target);
764 else if (!rc && (elements->flags & XML_LIST_FLAG_CHILDREN))
765 string_prepend (line, " +");
767 if (elements->prefix && elements->prefix->str)
768 string_prepend (line, elements->prefix->str);
769 else
770 string_prepend (line, path);
772 l = slist_append (elements->list, line->str);
773 if (l)
775 elements->list = l;
776 if (!(elements->flags & XML_LIST_CHECK))
777 rc = 0;
779 else
780 rc = GPG_ERR_ENOMEM;
782 string_free (line, 0);
783 return rc;
786 /* Removes the final element from the element prefix. */
787 static void
788 pop_element_prefix (struct element_list_s *elements)
790 char *p = strrchr (elements->prefix->str, '\t');
792 if (p)
793 string_truncate (elements->prefix,
794 elements->prefix->len - strlen (p));
797 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
798 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
801 * From the element path 'path', find sub-nodes and append them to the list.
803 gpg_error_t
804 xml_create_path_list (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
805 struct element_list_s *elements, char *path,
806 gpg_error_t rc)
808 xmlNodePtr n = NULL;
809 struct xml_request_s *req = NULL;
810 gpg_error_t trc = rc;
811 char *target_orig;
813 target_orig = rc && elements->target ? str_dup (elements->target) : NULL;
814 rc = xml_new_request (client, path, XML_CMD_LIST, &req);
815 if (rc)
817 xfree (target_orig);
818 return rc;
821 req->data = elements;
822 n = xml_find_elements (client, req,
823 node ? node : xmlDocGetRootElement (doc), &rc);
824 if (!rc)
825 elements->flags |=
826 find_element_node (n->children) ? XML_LIST_FLAG_CHILDREN : 0;
828 if (!rc && trc)
830 xfree (elements->target);
831 elements->target = target_orig;
832 elements->flags = 0;
833 elements->flags |= XML_LIST_HAS_TARGET;
835 else
836 xfree (target_orig);
838 rc = append_path_to_list (client, elements, path, trc ? trc : rc);
839 xmlFree (elements->target);
840 elements->target = NULL;
842 if (rc || trc || (elements->flags & XML_LIST_CHECK)
843 || (!elements->recurse && elements->depth) || elements->root_only)
845 xml_free_request (req);
846 return rc;
849 elements->flags = 0;
851 if (!rc && n && n->children)
853 for (n = n->children; n; n = n->next)
855 xmlChar *target = NULL;
856 xmlNodePtr tmp = NULL;
857 xmlChar *name;
858 struct string_s *newpath;
860 if (n->type != XML_ELEMENT_NODE)
861 continue;
863 name = xml_attribute_value (n, (xmlChar *) "_name");
864 if (!name)
865 continue;
867 newpath = string_new (NULL);
868 if (!newpath)
870 xmlFree (name);
871 rc = GPG_ERR_ENOMEM;
872 goto fail;
875 target = xml_attribute_value (n, (xmlChar *) "_target");
876 if (target)
878 rc = xml_validate_target (client, req->doc, (char *)target, n);
879 elements->target = (char *)target;
880 elements->flags |= rc ? XML_LIST_TARGET_ERROR : 0;
882 else
883 tmp = n;
885 if (RESUMABLE_ERROR (rc))
887 struct string_s *s;
889 /* If there is a target for this node then resolve the full path
890 * starting at the document root. Otherwise, resolve the next
891 * element starting from the child node of the current node. In
892 * either case, append the current element in the element path to
893 * the prefix of the list string.
895 if (target)
897 string_truncate (newpath, 0);
898 s = string_append_printf (newpath, "%s", (char *)target);
900 else
901 s = string_append (newpath, (char *)name);
903 if (!s)
905 xmlFree (name);
906 string_free (newpath, 1);
907 rc = GPG_ERR_ENOMEM;
908 goto fail;
911 newpath = s;
912 if (!elements->depth)
914 /* There may be a single remaining element in the prefix left
915 * over from the previous truncation (see below). It is safe
916 * to truncate it here since depth == 0. */
917 string_truncate (elements->prefix, 0);
918 s = string_append_printf (elements->prefix, "%s\t%s",
919 path, name);
921 else
922 s = string_append_printf (elements->prefix, "\t%s", name);
924 if (!s)
926 xmlFree (name);
927 string_free (newpath, 1);
928 rc = GPG_ERR_ENOMEM;
929 goto fail;
932 elements->prefix = s;
933 elements->depth++;
934 rc = xml_create_path_list (client, doc, target ? NULL : tmp,
935 elements, newpath->str, rc);
936 elements->depth--;
937 if (!rc)
938 pop_element_prefix (elements);
941 string_free (newpath, 1);
942 xmlFree (name);
943 if (rc)
944 break;
948 fail:
949 xml_free_request (req);
950 return rc;
953 gpg_error_t
954 xml_recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
955 xmlNodeSetPtr nodes, xmlChar * value,
956 xmlBufferPtr * result, int cmd, const xmlChar * attr)
958 int i = value ? nodes->nodeNr - 1 : 0;
959 xmlBufferPtr buf;
961 buf = xmlBufferCreate ();
963 if (!buf)
964 return GPG_ERR_ENOMEM;
966 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
968 xmlNodePtr n = nodes->nodeTab[i];
969 gpg_error_t rc;
971 if (!n)
972 continue;
974 if (!value && !attr)
976 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
978 *result = buf;
979 return GPG_ERR_BAD_DATA;
982 continue;
985 if (!attr)
987 xmlNodeSetContent (n, value);
988 rc = xml_update_element_mtime (client, n);
990 if (rc)
991 return rc;
993 else
995 if (!cmd)
996 rc = xml_add_attribute (client, n, (char *) attr, (char *) value);
997 else
998 rc = xml_delete_attribute (client, n, attr);
1000 if (rc)
1001 return rc;
1005 *result = buf;
1006 return 0;
1009 gpg_error_t
1010 xml_delete_attribute (struct client_s *client, xmlNodePtr n,
1011 const xmlChar *name)
1013 xmlAttrPtr a;
1014 gpg_error_t rc = 0;
1016 if ((a = xmlHasProp (n, name)) == NULL)
1017 return GPG_ERR_NOT_FOUND;
1019 if (xmlRemoveProp (a) == -1)
1020 return GPG_ERR_BAD_DATA;
1022 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
1024 char *user = create_acl_user (client);
1026 rc = xml_add_attribute (client, n, (char *) "_acl", user);
1027 xfree (user);
1029 if (rc)
1030 return rc;
1033 return xml_update_element_mtime (client, n);
1036 gpg_error_t
1037 xml_validate_import (struct client_s *client, xmlNodePtr node)
1039 gpg_error_t rc = 0;
1041 if (!node)
1042 return 0;
1044 for (xmlNodePtr n = node; n; n = n->next)
1046 if (n->type == XML_ELEMENT_NODE)
1048 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1050 xmlChar *a = xmlGetProp (n, (xmlChar *) "_target");
1052 if (a)
1054 xmlFree (a);
1055 rc = xml_remove_user_attributes (client, n);
1056 if (!rc)
1057 rc = xml_unlink_node (client, n->children);
1060 if (rc)
1061 break;
1063 a = xmlGetProp (n, (xmlChar *) "_name");
1064 if (!a)
1066 xmlChar *t = xmlGetNodePath (n);
1068 log_write (_("Missing attribute '_name' at %s."), t);
1069 xmlFree (t);
1070 return GPG_ERR_INV_VALUE;
1073 if (!xml_valid_element (a))
1075 xmlChar *t = xmlGetNodePath (n);
1077 log_write (_("'%s' is not a valid element name at %s."), a,
1079 xmlFree (a);
1080 xmlFree (t);
1081 return GPG_ERR_INV_VALUE;
1084 xmlFree (a);
1085 a = xmlGetProp (n, (xmlChar *) "_ctime");
1086 if (!a)
1087 attr_ctime (client, n);
1089 xmlFree (a);
1090 a = xmlGetProp (n, (xmlChar *) "_mtime");
1091 if (!a)
1092 xml_update_element_mtime (client, n);
1093 xmlFree (a);
1095 else
1097 xmlChar *t = xmlGetNodePath (n);
1098 xmlNodePtr tmp = n->next;
1100 log_write (_("Warning: unknown element '%s' at %s. Removing."),
1101 n->name, t);
1102 xmlFree (t);
1103 (void)xml_unlink_node (client, n);
1104 return xml_validate_import (client, tmp);
1108 if (n->children)
1110 rc = xml_validate_import (client, n->children);
1111 if (rc)
1112 return rc;
1116 return rc;
1119 gpg_error_t
1120 xml_update_element_mtime (struct client_s *client, xmlNodePtr n)
1122 return xml_add_attribute (client, n, NULL, NULL);
1125 gpg_error_t
1126 xml_unlink_node (struct client_s *client, xmlNodePtr n)
1128 gpg_error_t rc = 0;
1130 if (!n)
1131 return rc;
1133 if (n->parent)
1134 rc = xml_update_element_mtime (client, n->parent);
1136 xmlUnlinkNode (n);
1137 xmlFreeNodeList (n);
1138 return rc;
1141 static gpg_error_t
1142 recurse_rename_attribute (xmlNodePtr root, const char *old, const char *name)
1144 xmlNodePtr n;
1145 gpg_error_t rc = 0;
1147 for (n = root; n; n = n->next)
1149 xmlAttrPtr attr = xmlHasProp (n, (xmlChar *)old);
1151 if (attr)
1153 xmlChar *a = xml_attribute_value (n, (xmlChar *)old);
1155 if (a && !xmlSetProp (n, (xmlChar *) name, a))
1156 rc = GPG_ERR_BAD_DATA;
1158 xmlFree (a);
1160 if (!rc)
1162 if (xmlRemoveProp (attr) == -1)
1163 rc = GPG_ERR_BAD_DATA;
1167 if (rc)
1168 break;
1170 rc = recurse_rename_attribute (n->children, old, name);
1171 if (rc)
1172 break;
1175 return rc;
1178 static gpg_error_t
1179 update_to_version (xmlDocPtr doc)
1181 xmlNodePtr root = xmlDocGetRootElement (doc);
1182 xmlChar *v = xml_attribute_value (root, (xmlChar *)"_version");
1183 gpg_error_t rc;
1185 // Pwmd 3.2.0 or later. No updates needed ATM.
1186 if (v)
1188 xmlFree (v);
1189 return 0;
1192 rc = recurse_rename_attribute (root->children, "target", "_target");
1193 if (!rc)
1194 rc = recurse_rename_attribute (root->children, "expire", "_expire");
1196 if (!rc)
1197 rc = recurse_rename_attribute (root->children, "expire_increment", "_age");
1199 return rc;
1202 gpg_error_t
1203 xml_parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1205 xmlDocPtr doc;
1206 gpg_error_t rc;
1208 xmlResetLastError ();
1209 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1210 if (!doc && xmlGetLastError ())
1211 return GPG_ERR_BAD_DATA;
1213 *result = doc;
1214 if (doc)
1215 rc = update_to_version (doc);
1216 else
1217 rc = GPG_ERR_ENOMEM;
1219 return rc;
1222 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1223 * target. 'path' is any remaining elements in the element path after this
1224 * element 'node' as passed to xml_find_elements() or the initial command. This
1225 * function may be recursive as it calls xml_find_elements().
1227 static xmlNodePtr
1228 do_realpath (struct client_s *client, struct xml_request_s *req,
1229 xmlNodePtr node, char **path, const xmlChar *target,
1230 gpg_error_t *rc) {
1231 char *line;
1232 char **result = NULL;
1233 struct xml_request_s *nreq = NULL;
1235 *rc = 0;
1237 result = str_split ((char *)target, "\t", 0);
1238 if (!result)
1240 *rc = GPG_ERR_ENOMEM;
1241 return NULL;
1244 /* Append the original path to the target path. */
1245 if (path)
1247 char **p = strv_catv (result, path);
1249 strv_free (result);
1250 if (!p)
1252 *rc = GPG_ERR_ENOMEM;
1253 return NULL;
1256 result = p;
1259 line = strv_join ("\t", result);
1260 if (!line)
1262 strv_free (result);
1263 *rc = GPG_ERR_ENOMEM;
1264 return NULL;
1267 /* To prevent overwriting any original client request flags. We are only
1268 * interested in the path here. */
1269 *rc = xml_new_request (client, line, XML_CMD_REALPATH, &nreq);
1270 xfree (line);
1271 if (*rc)
1273 strv_free (result);
1274 return NULL;
1277 nreq->depth = req->depth;
1278 strv_free (result);
1279 node = xml_find_elements (client, nreq, xmlDocGetRootElement (nreq->doc), rc);
1281 /* Update the original client request path with the resolved one. */
1282 if (!*rc)
1284 strv_free (req->args);
1285 req->args = nreq->args;
1286 nreq->args = NULL;
1289 xml_free_request (nreq);
1290 return node;
1293 #if 0
1294 static char *
1295 node_to_element_path (xmlNodePtr node)
1297 xmlNodePtr n;
1298 struct string_s *str = string_new ("");
1299 char *result;
1301 for (n = node; n; n = n->parent)
1303 xmlNodePtr child;
1305 for (child = n; child; child = child->next)
1307 if (child->type != XML_ELEMENT_NODE)
1308 continue;
1310 xmlChar *name = xml_attribute_value (n, (xmlChar *) "_name");
1311 if (name)
1313 str = string_prepend (str, (char *) name);
1314 xmlFree (name);
1315 name = xml_attribute_value (n, (xmlChar *) "_target");
1316 if (name)
1317 str = string_prepend (str, "\t");
1318 else
1319 str = string_prepend (str, "\t!");
1320 xmlFree (name);
1322 break;
1326 str = string_erase (str, 0, 1);
1327 result = str->str;
1328 string_free (str, 0);
1329 return result;
1331 #endif
1333 /* Tests if 'path' references 'node' somewhere. */
1334 static gpg_error_t
1335 element_related (struct client_s *client, xmlDocPtr doc, const char *path,
1336 xmlNodePtr node, unsigned depth)
1338 gpg_error_t rc = GPG_ERR_NO_DATA;
1339 char **p, **orig;
1340 xmlNodePtr n = xmlDocGetRootElement (doc);
1342 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1343 return GPG_ERR_ELOOP;
1345 orig = p = str_split (path, "\t", 0);
1346 if (!p)
1347 return GPG_ERR_ENOMEM;
1349 for (n = n->children; n && *p; p++, n = n->next)
1351 xmlNodePtr t;
1352 xmlChar *target;
1353 struct string_s *str = NULL;
1355 t = xml_find_element (client, n, *p, &rc);
1356 if (rc)
1358 rc = GPG_ERR_NO_DATA;
1359 break;
1362 if (t == node)
1364 rc = 0;
1365 break;
1368 target = xml_attribute_value (t, (xmlChar *)"_target");
1369 if (!target)
1370 continue;
1372 str = string_new ((char *)target);
1373 xmlFree (target);
1374 if (!str)
1376 rc = GPG_ERR_ENOMEM;
1377 break;
1380 if (*(p+1))
1382 while (*(++p))
1384 struct string_s *tmp;
1386 tmp = string_append_printf (str, "\t%s", *p);
1387 if (!tmp)
1389 string_free (str, 1);
1390 strv_free (p);
1391 return GPG_ERR_ENOMEM;
1394 str = tmp;
1398 rc = element_related (client, doc, str->str, n->children, ++depth);
1399 if (rc == GPG_ERR_ELOOP)
1400 rc = GPG_ERR_NO_DATA;
1402 string_free(str, 1);
1403 break;
1406 strv_free (orig);
1407 return rc;
1411 * Recurse the element tree beginning at 'node' and find elements who point
1412 * back to 'dst'. Also follows target attributes.
1414 static gpg_error_t
1415 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1416 xmlNodePtr dst, unsigned depth, int is_target)
1418 xmlNodePtr n;
1419 gpg_error_t rc = 0;
1421 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1422 return node == dst ? GPG_ERR_ELOOP : 0;
1424 for (n = node; n; n = n->next)
1426 xmlChar *target;
1428 if (n->type != XML_ELEMENT_NODE)
1429 continue;
1431 if (n == dst && depth)
1432 return GPG_ERR_ELOOP;
1434 target = xml_attribute_value (n, (xmlChar *) "_target");
1435 if (target)
1437 xmlNodePtr tmp;
1438 char **result = NULL;
1440 tmp = xml_resolve_path (client, doc, target, &result, &rc);
1441 strv_free (result);
1442 if (!rc)
1444 rc = find_child_to_target (client, doc, tmp, dst, ++depth, 1);
1445 depth--;
1447 else if (rc == GPG_ERR_ELOOP)
1449 gpg_error_t trc = element_related (client, doc, (char *)target,
1450 dst, 0);
1452 if (trc && trc != GPG_ERR_NO_DATA)
1453 rc = trc;
1454 else if (trc == GPG_ERR_NO_DATA)
1455 rc = 0;
1458 xmlFree (target);
1460 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
1461 return rc;
1463 rc = 0;
1464 if (is_target)
1465 break;
1467 continue;
1470 if (n->children)
1472 rc = find_child_to_target (client, doc, n->children, dst, ++depth, 0);
1473 depth--;
1474 if (rc)
1475 return rc;
1478 if (is_target)
1479 break;
1482 return rc;
1485 static gpg_error_t
1486 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1488 xmlNodePtr n;
1489 gpg_error_t rc = 0;
1491 for (n = src; n; n = n->next)
1493 if (n->type != XML_ELEMENT_NODE)
1494 continue;
1496 if (n == dst)
1498 rc = GPG_ERR_ELOOP;
1499 break;
1502 rc = find_child_of_parent (doc, n->children, dst);
1505 return rc;
1508 static gpg_error_t
1509 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1511 xmlNodePtr n;
1512 gpg_error_t rc = 0;
1514 (void)doc;
1515 for (n = node; n; n = n->parent)
1517 if (n->type != XML_ELEMENT_NODE)
1519 xmlNodePtr tmp;
1521 for (tmp = n->next; tmp; n = n->next)
1523 if (n->type != XML_ELEMENT_NODE)
1524 continue;
1526 if (tmp == dst)
1527 return GPG_ERR_ELOOP;
1531 if (n == dst)
1532 return GPG_ERR_ELOOP;
1535 return rc;
1538 void
1539 xml_free_element_list (struct element_list_s *elements)
1541 if (elements)
1543 if (elements->list)
1545 int total = slist_length (elements->list);
1546 int i;
1548 for (i = 0; i < total; i++)
1550 char *tmp = slist_nth_data (elements->list, i);
1551 xfree (tmp);
1554 slist_free (elements->list);
1557 string_free (elements->prefix, 1);
1558 xfree (elements->target);
1559 xfree (elements);
1563 /* This behaves like the LIST command with a specified path except it returns
1564 * an error.
1566 gpg_error_t
1567 xml_check_recursion (struct client_s *client, struct xml_request_s *req)
1569 gpg_error_t rc;
1570 struct element_list_s *elements;
1571 char *path = NULL;
1572 char **dup = strv_dup (req->args);
1574 if (!dup)
1575 return GPG_ERR_ENOMEM;
1578 elements = xcalloc (1, sizeof (struct element_list_s));
1579 if (!elements)
1581 rc = GPG_ERR_ENOMEM;
1582 goto fail;
1585 path = strv_join ("\t", dup);
1586 if (!path)
1588 rc = GPG_ERR_ENOMEM;
1589 goto fail;
1592 elements->flags |= XML_LIST_CHECK;
1593 elements->prefix = string_new (NULL);
1594 if (!elements->prefix)
1596 rc = GPG_ERR_ENOMEM;
1597 goto fail;
1600 rc = xml_create_path_list (client, req->doc, xmlDocGetRootElement (req->doc),
1601 elements, path, 0);
1603 fail:
1604 xml_free_element_list (elements);
1605 strv_free (dup);
1606 xfree (path);
1607 return rc;
1610 gpg_error_t
1611 xml_validate_target (struct client_s *client, xmlDocPtr doc, const char *src,
1612 xmlNodePtr dst)
1614 gpg_error_t rc;
1615 xmlNodePtr src_node;
1616 char **src_req = NULL;
1618 src_node = xml_resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
1619 if (rc)
1620 goto fail;
1622 client->flags |= FLAG_ACL_IGNORE;
1623 /* A destination element is a child of the source element. */
1624 rc = find_child_of_parent (doc, src_node->children, dst);
1625 if (rc)
1626 goto fail;
1628 /* The destination element is a parent of the source element. */
1629 rc = find_parent_of_child (doc, src_node->parent, dst);
1630 if (rc)
1631 goto fail;
1633 /* A destination child element contains a target to the source element. */
1634 if (dst)
1635 rc = find_child_to_target (client, doc,
1636 dst->children ? dst->children : dst, dst, 0, 0);
1637 if (rc)
1638 goto fail;
1640 fail:
1641 strv_free (src_req);
1642 client->flags &= ~(FLAG_ACL_IGNORE | FLAG_ACL_ERROR);
1643 return rc;
1646 /* The owner of the element is the first user listed in the _acl attribute
1647 * list. xml_acl_check() should be called before calling this function. An
1648 * empty ACL is an error if the client is not an invoking_user. The 'strict'
1649 * parameter will not check if the current user is an invoking one.
1651 gpg_error_t
1652 xml_is_element_owner (struct client_s *client, xmlNodePtr n, int strict)
1654 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
1655 char **users;
1656 gpg_error_t rc = GPG_ERR_EACCES;
1658 if (!acl || !*acl)
1660 xmlFree (acl);
1661 return peer_is_invoker (client);
1664 users = str_split((char *)acl, ",", 0);
1665 if (users && *users)
1667 char *user;
1669 #ifdef WITH_GNUTLS
1670 if (client->thd->remote)
1671 user = str_asprintf ("#%s", client->thd->tls->fp);
1672 else
1673 user = get_username (client->thd->peer->uid);
1674 #else
1675 user = get_username (client->thd->peer->uid);
1676 #endif
1678 if (*user == '#')
1679 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
1680 else
1681 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
1683 if (rc && !strict)
1684 rc = peer_is_invoker (client);
1686 xfree (user);
1689 xmlFree (acl);
1690 strv_free (users);
1691 return rc;
1694 /* Find elements by matching element names in req->args starting at 'node'.
1695 * Returns the node of the final element in req->args on success or NULL on
1696 * failure and sets 'rc' to the error code. Some commands may need special
1697 * handling and will return the node of the previous found element.
1699 xmlNodePtr
1700 xml_find_elements (struct client_s *client, struct xml_request_s *req,
1701 xmlNodePtr node, gpg_error_t *rc)
1703 xmlNodePtr n, last;
1704 char **p;
1706 *rc = 0;
1707 req->depth++;
1709 if (max_recursion_depth >= 1 && req->depth > max_recursion_depth)
1711 req->depth--;
1712 *rc = GPG_ERR_ELOOP;
1713 return NULL;
1716 /* Beginning of a command/root element (<pwmd>). */
1717 if (node == xmlDocGetRootElement (req->doc))
1719 if (!node->children) // Empty tree
1721 if (req->cmd == XML_CMD_STORE)
1722 return xml_create_element_path (client, req, node, req->args, rc);
1724 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1725 req->depth--;
1726 return NULL;
1729 node = node->children; // Start searching at the first child of the root
1732 for (last = n = node, p = req->args; *p; p++)
1734 xmlNodePtr tmp = NULL;
1735 struct element_list_s *elements = NULL;
1737 // FIXME should not be reached in this function?
1738 if (!*(*p))
1740 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1741 req->depth--;
1742 return NULL;
1745 n = xml_find_element (client, n, *p, rc);
1746 if (*rc)
1748 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND && *rc != GPG_ERR_EACCES)
1750 req->depth--;
1751 return NULL;
1754 if (*rc == GPG_ERR_EACCES
1755 && (req->cmd == XML_CMD_ATTR_LIST || req->cmd == XML_CMD_ATTR
1756 || req->cmd == XML_CMD_ATTR_EXPIRE))
1758 req->depth--;
1759 if (*(p+1))
1760 return NULL;
1762 *rc = 0;
1763 return n;
1766 /* Fixes ATTR LIST when an element does not exist and the parent
1767 * denies access to children. Fixes leaking information about the
1768 * current elements children. */
1769 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND && last != n && last != node)
1771 gpg_error_t trc = xml_acl_check (client, last);
1772 if (trc)
1773 *rc = trc;
1776 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND)
1778 if (req->cmd == XML_CMD_STORE || req->cmd == XML_CMD_ATTR_TARGET)
1780 *rc = 0;
1781 n = xml_create_element_path (client, req,
1782 *p == *req->args
1783 && node->parent == xmlDocGetRootElement (req->doc)
1784 ? node->parent : last, p, rc);
1785 if (!*rc)
1786 req->flags |= XML_REQUEST_FLAG_CREATED;
1788 req->depth--;
1789 return n;
1793 if (req->cmd != XML_CMD_LIST && req->cmd != XML_CMD_REALPATH)
1795 req->depth--;
1796 return NULL;
1799 // Fall through to let LIST flags be appended.
1802 last = n;
1804 /* Follow a "_target" attribute for each one found in each element. */
1805 xmlChar *target = xml_attribute_value (n, (xmlChar *) "_target");
1806 if (!target || !*target)
1808 xmlFree (target);
1810 if (*rc)
1812 req->depth--;
1813 return NULL;
1816 /* This is the final element in req->args. Done. */
1817 if (!*(p+1))
1819 req->depth--;
1820 return n;
1823 n = n->children;
1824 continue;
1827 if (req->cmd == XML_CMD_REALPATH)
1829 n = do_realpath (client, req, n, p+1, target, rc);
1830 xmlFree (target);
1831 req->depth--;
1832 return n;
1834 else if (req->cmd == XML_CMD_DELETE || req->cmd == XML_CMD_RENAME
1835 || req->cmd == XML_CMD_MOVE || req->cmd == XML_CMD_ATTR
1836 || req->cmd == XML_CMD_ATTR_TARGET
1837 || req->cmd == XML_CMD_ATTR_LIST)
1839 /* No more elements to resolve. Return the node with the target. */
1840 if (!*(p+1))
1842 xmlFree (target);
1843 req->depth--;
1844 return n;
1847 else if (req->cmd == XML_CMD_LIST)
1849 elements = req->data;
1850 if (elements && !(elements->flags & XML_LIST_CHILD_TARGET))
1852 /* No further elements. Use this target in the list flags. */
1853 if (!*(p+1))
1854 elements->flags |= XML_LIST_HAS_TARGET;
1855 else
1857 /* Prevent replacing any following target value with the
1858 * current target value. */
1859 req->data = NULL;
1862 else if (!elements)
1864 struct element_list_s *e = xcalloc (1, sizeof (struct element_list_s));
1866 e->target = str_dup ((char *)target);
1867 e->flags |= XML_LIST_CHILD_TARGET;
1869 if (!*(p+1))
1870 e->flags |= XML_LIST_HAS_TARGET;
1872 req->data = elements = e;
1875 gpg_error_t rc_orig = *rc;
1876 *rc = xml_validate_target (client, req->doc, (char *)target, n);
1877 /* Ignore errors for elements elsewhere in the document. */
1878 if (*rc == GPG_ERR_EACCES)
1879 *rc = 0;
1881 if (rc_orig != *rc)
1882 *rc = *rc ? *rc : rc_orig;
1884 if (*rc)
1885 goto update_target;
1888 /* Create a new path based on the value of the current "_target"
1889 * attribute. */
1890 char **nargs = str_split ((char *)target, "\t", 0);
1891 if (!nargs)
1893 xmlFree (target);
1894 *rc = GPG_ERR_INV_VALUE;
1895 req->data = req->cmd == XML_CMD_LIST ? elements : req->data;
1896 req->depth--;
1897 return NULL;
1900 /* Append the remaining elements to the target attributes path. */
1901 char **nnargs = strv_catv (nargs, p+1);
1902 strv_free (nargs);
1903 char **orig = req->args;
1904 req->args = nnargs;
1905 tmp = xml_find_elements (client, req, xmlDocGetRootElement (req->doc),
1906 rc);
1907 strv_free (nnargs);
1908 req->args = orig;
1910 update_target:
1911 if (req->cmd == XML_CMD_LIST && elements)
1913 /* A child node contained a target. Use this value rather than the
1914 * current target value as the target value for the list flag. */
1915 if (req->data && req->data != elements)
1917 struct element_list_s *e = req->data;
1919 xmlFree (target);
1920 target = xmlStrdup ((xmlChar *)e->target);
1921 xfree (e->target);
1923 if ((e->flags & XML_LIST_HAS_TARGET))
1924 elements->flags |= XML_LIST_HAS_TARGET;
1926 xfree (e);
1929 req->data = elements;
1930 if (req->data)
1932 if (!(elements->flags & XML_LIST_TARGET_ERROR))
1934 xfree (elements->target);
1935 elements->target = NULL;
1937 /* Restore the original target flag. */
1938 if (target && (elements->flags & XML_LIST_HAS_TARGET))
1939 elements->target = str_dup ((char *)target);
1944 xmlFree (target);
1945 req->depth--;
1946 return *rc ? NULL : tmp;
1949 req->depth--;
1950 return n;
1953 gpg_error_t
1954 xml_new_request (struct client_s *client, const char *line, xml_command_t cmd,
1955 struct xml_request_s **result)
1957 struct xml_request_s *req;
1958 char **pp = str_split ((char *) line, "\t", 0);
1960 if (!pp || !*pp)
1962 strv_free (pp);
1963 return GPG_ERR_SYNTAX;
1966 req = xcalloc (1, sizeof (struct xml_request_s));
1967 if (!req)
1969 strv_free (pp);
1970 return GPG_ERR_ENOMEM;
1973 req->cmd = cmd;
1974 req->args = pp;
1975 req->doc = client ? client->doc : NULL;
1976 *result = req;
1977 return 0;
1980 void
1981 xml_free_request (struct xml_request_s *r)
1983 if (!r)
1984 return;
1986 strv_free (r->args);
1987 xfree (r);
1991 xml_reserved_attribute (const char *name)
1993 int i;
1995 for (i = 0; reserved_attributes[i]; i++)
1997 if (!strcmp (name, reserved_attributes[i]))
1998 return 1;
2001 return 0;