More cancellation fixes.
[libpwmd.git] / src / xml.c
blobe7d6fe25fd0bc44e292d74249f67a40bb1451967
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <err.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <libxml/xmlwriter.h>
35 #include <wctype.h>
36 #include <sys/types.h>
37 #include <pwd.h>
39 #ifndef _
40 #include "gettext.h"
41 #define _(msgid) gettext(msgid)
42 #endif
44 #include "pwmd-error.h"
45 #include "util-misc.h"
46 #include "xml.h"
47 #include "mem.h"
48 #include "rcfile.h"
49 #include "commands.h"
51 #define XML_LIST_FLAG_CHILDREN 0x0001
52 #define XML_LIST_HAS_TARGET 0x0002
53 #define XML_LIST_CHILD_TARGET 0x0004
54 #define XML_LIST_TARGET_ERROR 0x0008
55 #define XML_LIST_CHECK 0x0010
57 const char *reserved_attributes[] = {
58 "_name", "_mtime", "_ctime", "_acl", "target",
59 NULL
62 extern void log_write (const char *fmt, ...);
64 int
65 xml_valid_attribute_value (const char *str)
67 const char *p = str;
69 if (!p || !*p)
70 return 1;
72 while (*p)
74 if (*p++ == '\n')
75 return 0;
78 return 1;
81 int
82 xml_valid_attribute (const char *str)
84 wchar_t *wc;
85 size_t len, c;
86 int ret = xml_valid_element ((xmlChar *)str);
88 if (!ret)
89 return ret;
91 wc = str_to_wchar ((const char *)str);
92 if (!wc)
93 return 0;
95 len = wcslen (wc);
96 for (c = 0; c < len; c++)
98 switch (wc[c])
100 case '-':
101 case '.':
102 case '0' ... '9':
103 case 0xB7:
104 case 0x0300 ... 0x036F:
105 case 0x203F ... 0x2040:
106 if (!c)
108 xfree (wc);
109 return 0;
111 case ':': break;
112 case '_': break;
113 case 'A' ... 'Z': break;
114 case 'a' ... 'z': break;
115 case 0xC0 ... 0xD6: break;
116 case 0xD8 ... 0xF6: break;
117 case 0xF8 ... 0x2FF: break;
118 case 0x370 ... 0x37D: break;
119 case 0x37F ... 0x1FFF: break;
120 case 0x200C ... 0x200D: break;
121 case 0x2070 ... 0x218F: break;
122 case 0x2C00 ... 0x2FEF: break;
123 case 0x3001 ... 0xD7FF: break;
124 case 0xF900 ... 0xFDCF: break;
125 case 0xFDF0 ... 0xFFFD: break;
126 case 0x10000 ... 0xEFFFF: break;
127 default:
128 xfree (wc);
129 return 0;
133 xfree (wc);
134 return 1;
138 xml_valid_element (xmlChar *str)
140 wchar_t *wc;
141 size_t len, c;
143 if (!str || !*str)
144 return 0;
146 wc = str_to_wchar ((const char *)str);
147 if (!wc)
148 return 0;
150 len = wcslen (wc);
151 for (c = 0; c < len; c++)
153 if (iswspace(wc[c]))
155 xfree (wc);
156 return 0;
160 xfree (wc);
161 return 1;
165 xml_valid_element_path (char **path, int with_content)
167 char **dup = NULL, **p;
169 if (!path || !*path)
170 return 0;
172 /* Save some memory by not duplicating the element content. */
173 if (with_content)
175 int i, t = strv_length (path);
177 for (i = 0; i < t - 1; i++)
179 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
181 if (!tmp)
183 strv_free (dup);
184 return 0;
187 dup = tmp;
188 dup[i] = str_dup (path[i]);
189 dup[i + 1] = NULL;
192 else
193 dup = strv_dup (path);
195 if (!dup)
196 return 0;
198 for (p = dup; *p && *(*p); p++)
200 if (!xml_valid_element ((xmlChar *) * p))
202 strv_free (dup);
203 return 0;
207 strv_free (dup);
208 return 1;
211 static gpg_error_t
212 attr_ctime (struct client_s *client, xmlNodePtr n)
214 char *buf = str_asprintf ("%li", time (NULL));
215 gpg_error_t rc;
217 if (!buf)
218 return GPG_ERR_ENOMEM;
220 rc = xml_add_attribute (client, n, "_ctime", buf);
221 xfree (buf);
222 return rc;
225 static gpg_error_t
226 acl_check (struct client_s *client, xmlNodePtr n)
228 gpg_error_t rc = GPG_ERR_EACCES;
229 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
230 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
231 char **p;
232 int allowed = 0;
234 if (!acl || !*acl || !users || !*users)
236 xmlFree (acl);
237 strv_free(users);
238 return peer_is_invoker(client);
241 if (!peer_is_invoker(client))
243 xmlFree (acl);
244 strv_free(users);
245 return 0;
248 for (p = users; p && *p; p++)
250 #ifdef WITH_GNUTLS
251 rc = acl_check_common (client, *p,
252 client->thd->remote ? 0 : client->thd->peer->uid,
253 client->thd->remote ? 0 : client->thd->peer->gid,
254 &allowed);
255 #else
256 rc = acl_check_common (client, *p, client->thd->peer->uid,
257 client->thd->peer->gid, &allowed);
258 #endif
261 xmlFree(acl);
262 strv_free(users);
264 if (rc)
265 return rc;
267 return allowed ? 0 : GPG_ERR_EACCES;
270 static char *
271 create_acl_user (struct client_s *client)
273 #ifdef WITH_GNUTLS
274 if (client->thd->remote)
275 return str_asprintf ("#%s", client->thd->tls->fp);
276 #endif
278 return get_username (client->thd->peer->uid);
281 static gpg_error_t
282 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
283 const char *name, xmlNodePtr * result)
285 xmlNodePtr n;
286 gpg_error_t rc;
288 // Allow any client to create a non-existing root element.
289 if (parent->parent->type != XML_DOCUMENT_NODE)
291 rc = acl_check(client, parent);
292 if (rc)
293 return rc;
296 n = xmlNewNode (NULL, (xmlChar *) "element");
297 if (!n)
298 return GPG_ERR_ENOMEM;
300 rc = xml_add_attribute (client, n, "_name", name);
301 if (!rc)
302 rc = attr_ctime (client, n);
304 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
305 rc = xml_is_element_owner (client, parent);
307 if (!rc)
309 xmlNodePtr p = xmlAddChild (parent, n);
310 char *user = create_acl_user (client);
312 if (result)
313 *result = p;
315 rc = xml_add_attribute(client, p, "_acl", user);
316 xfree (user);
318 else
319 xmlFreeNode (n);
321 return rc;
324 gpg_error_t
325 xml_new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
327 xmlNodePtr root = xmlDocGetRootElement (doc);
329 if (!name || !root)
330 return GPG_ERR_BAD_DATA;
332 if (!xml_valid_element ((xmlChar *) name))
333 return GPG_ERR_INV_VALUE;
335 return create_new_element (client, 0, root, name, NULL);
338 static xmlDocPtr
339 create_dtd ()
341 xmlDocPtr doc;
342 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
344 if (!wr)
345 return NULL;
347 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
348 goto fail;
350 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
351 goto fail;
353 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
354 (xmlChar *) "(element)") == -1)
355 goto fail;
357 xmlTextWriterEndDTDElement (wr);
359 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
360 (xmlChar *) "_name CDATA #REQUIRED") ==
362 goto fail;
364 xmlTextWriterEndDTDAttlist (wr);
365 xmlTextWriterEndDTD (wr);
367 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
368 goto fail;
370 xmlTextWriterEndElement (wr);
371 xmlTextWriterEndDocument (wr);
372 xmlFreeTextWriter (wr);
373 return doc;
375 fail:
376 xmlTextWriterEndDocument (wr);
377 xmlFreeTextWriter (wr);
378 xmlFreeDoc (doc);
379 return NULL;
382 xmlDocPtr
383 xml_new_document ()
385 return create_dtd ();
388 static xmlNodePtr
389 find_element_node (xmlNodePtr node)
391 xmlNodePtr n = node;
393 if (n && n->type == XML_ELEMENT_NODE)
394 return n;
396 for (n = node; n; n = n->next)
398 if (n->type == XML_ELEMENT_NODE)
399 return n;
402 return NULL;
405 xmlNodePtr
406 xml_resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
407 char ***result, gpg_error_t *rc)
409 xmlNodePtr n;
410 struct xml_request_s *req;
412 *rc = xml_new_request (client, (char *)path, XML_CMD_REALPATH, &req);
413 if (*rc)
414 return NULL;
416 n = xml_find_elements (client, req, xmlDocGetRootElement (doc), rc);
417 if (!*rc)
419 if (result)
421 *result = strv_dup (req->args);
422 if (!*result)
424 *rc = GPG_ERR_ENOMEM;
425 n = NULL;
430 xml_free_request (req);
431 return n;
434 xmlNodePtr
435 xml_find_text_node (xmlNodePtr node)
437 xmlNodePtr n = node;
439 if (n && n->type == XML_TEXT_NODE)
440 return n;
442 for (n = node; n; n = n->next)
444 if (n->type == XML_TEXT_NODE)
445 return n;
448 return NULL;
451 /* Create an element 'path' starting at 'node'. Returns the node of the final
452 * created element.
454 xmlNodePtr
455 xml_create_element_path (struct client_s *client, struct xml_request_s *req,
456 xmlNodePtr node, char **path, gpg_error_t *rc)
458 char **p;
460 if (!xml_valid_element_path (path, 0))
462 *rc = GPG_ERR_INV_VALUE;
463 return NULL;
466 /* The parent node will be an XML_ELEMENT_NODE. Otherwise we would be
467 * creating element content. */
468 if (node->type == XML_TEXT_NODE)
469 node = node->parent;
471 for (p = path; p && *p; p++)
473 xmlNodePtr n = NULL;
475 if (node != xmlDocGetRootElement (req->doc))
477 n = xml_find_element (client, node, *p, rc);
478 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
479 return NULL;
481 *rc = 0;
485 * If the found element has the same parent as the current element then
486 * they are siblings and the new element needs to be created as a child
487 * of the current element (node).
489 if (n && n->parent == node->parent)
490 n = NULL;
492 if (!n)
494 *rc = create_new_element (client, 0, node, *p, &node);
495 if (*rc)
496 return NULL;
498 else
499 node = n;
502 return node;
505 /* Find the first XML_ELEMENT_NODE whose _name attribute matches 'element'. */
506 xmlNodePtr
507 xml_find_element (struct client_s *client, xmlNodePtr node, const char *element,
508 gpg_error_t *rc)
510 xmlNodePtr n;
512 *rc = 0;
514 if (!node || !element)
516 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
517 return NULL;
520 for (n = node; n; n = n->next)
522 if (n->type != XML_ELEMENT_NODE)
523 continue;
525 xmlChar *a = xml_attribute_value (n, (xmlChar *) "_name");
526 if (a && xmlStrEqual (a, (xmlChar *) element))
528 xmlFree (a);
529 *rc = acl_check (client, n);
530 return n; // Not NULL since the node may be needed later
533 xmlFree (a);
536 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
537 return NULL;
540 xmlChar *
541 xml_attribute_value (xmlNodePtr n, xmlChar * attr)
543 xmlAttrPtr a = xmlHasProp (n, attr);
545 if (!a)
546 return NULL;
548 if (!a->children || !a->children->content)
549 return NULL;
551 return xmlGetProp (n, attr);
554 static void
555 remove_non_reserved_attributes (xmlNodePtr n)
557 xmlAttrPtr a;
559 for (a = n->properties; a; a = a->next)
561 if (xml_reserved_attribute ((char *)a->name))
562 continue;
564 (void)xml_delete_attribute (NULL, n, a->name);
568 gpg_error_t
569 xml_add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
570 const char *value)
572 char *buf;
573 gpg_error_t rc = 0;
574 int is_target = 0;
576 if (client && name && !strcmp (name, "target"))
578 rc = xml_is_element_owner (client, node);
579 if (rc)
580 return rc;
582 is_target = 1;
584 else if (name && !strcmp (name, "expire"))
586 char *p;
587 time_t e;
589 if (!value || !*value)
590 return GPG_ERR_INV_VALUE;
592 errno = 0;
593 e = strtoul (value, &p, 10);
594 if (errno || *p || e == ULONG_MAX || *value == '-')
595 return GPG_ERR_INV_VALUE;
598 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
599 return GPG_ERR_BAD_DATA;
601 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
603 xmlChar *acl = xml_attribute_value (node, (xmlChar *) "_acl");
605 if (!acl)
607 char *user = create_acl_user (client);
609 if (user)
611 rc = xml_add_attribute (client, node, (char *) "_acl", user);
612 xfree (user);
615 return rc;
618 xmlFree (acl);
621 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
622 return 0;
624 if (is_target)
625 remove_non_reserved_attributes (node);
627 buf = str_asprintf ("%lu", time (NULL));
628 rc = xml_add_attribute (client, node, "_mtime", buf);
629 xfree (buf);
630 return rc;
633 static gpg_error_t
634 append_path_to_list (struct client_s *client, struct element_list_s *elements,
635 const char *path, gpg_error_t rc)
637 struct slist_s *l;
638 struct string_s *line;
640 line = string_new (NULL);
641 if (!line)
642 return GPG_ERR_ENOMEM;
644 if (rc == GPG_ERR_ELOOP)
645 string_append (line, "O");
646 else if (rc == GPG_ERR_EACCES)
647 string_append (line, "P");
648 else if (rc)
649 string_append (line, "E");
651 if (rc || elements->target)
652 string_prepend (line, " ");
654 if ((!rc || rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
655 || rc == GPG_ERR_ELEMENT_NOT_FOUND) && elements->target)
656 string_append_printf (line, "%sT %s",
657 (!rc && elements->flags & XML_LIST_FLAG_CHILDREN) ? "+" : "",
658 elements->target);
659 else if (!rc && (elements->flags & XML_LIST_FLAG_CHILDREN))
660 string_prepend (line, " +");
662 if (elements->prefix && elements->prefix->str)
663 string_prepend (line, elements->prefix->str);
664 else
665 string_prepend (line, path);
667 l = slist_append (elements->list, line->str);
668 if (l)
670 elements->list = l;
671 if (!(elements->flags & XML_LIST_CHECK))
672 rc = 0;
674 else
675 rc = GPG_ERR_ENOMEM;
677 string_free (line, 0);
678 return rc;
681 /* Removes the final element from the element prefix. */
682 static void
683 pop_element_prefix (struct element_list_s *elements)
685 char *p = strrchr (elements->prefix->str, '\t');
687 if (p)
688 string_truncate (elements->prefix,
689 elements->prefix->len - strlen (p));
692 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
693 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
696 * From the element path 'path', find sub-nodes and append them to the list.
698 gpg_error_t
699 xml_create_path_list (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
700 struct element_list_s *elements, char *path,
701 gpg_error_t rc)
703 xmlNodePtr n = NULL;
704 struct xml_request_s *req = NULL;
705 gpg_error_t trc = rc;
706 char *target_orig;
708 target_orig = rc && elements->target ? str_dup (elements->target) : NULL;
709 rc = xml_new_request (client, path, XML_CMD_LIST, &req);
710 if (rc)
712 xfree (target_orig);
713 return rc;
716 req->data = elements;
717 n = xml_find_elements (client, req,
718 node ? node : xmlDocGetRootElement (doc), &rc);
719 if (!rc)
720 elements->flags |=
721 find_element_node (n->children) ? XML_LIST_FLAG_CHILDREN : 0;
723 if (!rc && trc)
725 xfree (elements->target);
726 elements->target = target_orig;
727 elements->flags = 0;
728 elements->flags |= XML_LIST_HAS_TARGET;
730 else
731 xfree (target_orig);
733 rc = append_path_to_list (client, elements, path, trc ? trc : rc);
734 xmlFree (elements->target);
735 elements->target = NULL;
737 if (rc || trc || (elements->flags & XML_LIST_CHECK)
738 || (!elements->recurse && elements->depth) || elements->root_only)
740 xml_free_request (req);
741 return rc;
744 elements->flags = 0;
746 if (!rc && n && n->children)
748 for (n = n->children; n; n = n->next)
750 xmlChar *target = NULL;
751 xmlNodePtr tmp = NULL;
752 xmlChar *name;
753 struct string_s *newpath;
755 if (n->type != XML_ELEMENT_NODE)
756 continue;
758 name = xml_attribute_value (n, (xmlChar *) "_name");
759 if (!name)
760 continue;
762 newpath = string_new (NULL);
763 if (!newpath)
765 xmlFree (name);
766 rc = GPG_ERR_ENOMEM;
767 goto fail;
770 target = xml_attribute_value (n, (xmlChar *) "target");
771 if (target)
773 rc = xml_validate_target (client, req->doc, (char *)target, n);
774 elements->target = (char *)target;
775 elements->flags |= rc ? XML_LIST_TARGET_ERROR : 0;
777 else
778 tmp = n;
780 if (RESUMABLE_ERROR (rc))
782 struct string_s *s;
784 /* If there is a target for this node then resolve the full path
785 * starting at the document root. Otherwise, resolve the next
786 * element starting from the child node of the current node. In
787 * either case, append the current element in the element path to
788 * the prefix of the list string.
790 if (target)
792 string_truncate (newpath, 0);
793 s = string_append_printf (newpath, "%s", (char *)target);
795 else
796 s = string_append (newpath, (char *)name);
798 if (!s)
800 xmlFree (name);
801 string_free (newpath, 1);
802 rc = GPG_ERR_ENOMEM;
803 goto fail;
806 newpath = s;
807 if (!elements->depth)
809 /* There may be a single remaining element in the prefix left
810 * over from the previous truncation (see below). It is safe
811 * to truncate it here since depth == 0. */
812 string_truncate (elements->prefix, 0);
813 s = string_append_printf (elements->prefix, "%s\t%s",
814 path, name);
816 else
817 s = string_append_printf (elements->prefix, "\t%s", name);
819 if (!s)
821 xmlFree (name);
822 string_free (newpath, 1);
823 rc = GPG_ERR_ENOMEM;
824 goto fail;
827 elements->prefix = s;
828 elements->depth++;
829 rc = xml_create_path_list (client, doc, target ? NULL : tmp,
830 elements, newpath->str, rc);
831 elements->depth--;
832 if (!rc)
833 pop_element_prefix (elements);
836 string_free (newpath, 1);
837 xmlFree (name);
838 if (rc)
839 break;
843 fail:
844 xml_free_request (req);
845 return rc;
848 gpg_error_t
849 xml_recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
850 xmlNodeSetPtr nodes, xmlChar * value,
851 xmlBufferPtr * result, int cmd, const xmlChar * attr)
853 int i = value ? nodes->nodeNr - 1 : 0;
854 xmlBufferPtr buf;
856 buf = xmlBufferCreate ();
858 if (!buf)
859 return GPG_ERR_ENOMEM;
861 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
863 xmlNodePtr n = nodes->nodeTab[i];
864 gpg_error_t rc;
866 if (!n)
867 continue;
869 if (!value && !attr)
871 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
873 *result = buf;
874 return GPG_ERR_BAD_DATA;
877 continue;
880 if (!attr)
882 xmlNodeSetContent (n, value);
883 rc = xml_update_element_mtime (client, n);
885 if (rc)
886 return rc;
888 else
890 if (!cmd)
891 rc = xml_add_attribute (client, n, (char *) attr, (char *) value);
892 else
893 rc = xml_delete_attribute (client, n, attr);
895 if (rc)
896 return rc;
900 *result = buf;
901 return 0;
904 gpg_error_t
905 xml_delete_attribute (struct client_s *client, xmlNodePtr n,
906 const xmlChar *name)
908 xmlAttrPtr a;
909 gpg_error_t rc = 0;
911 if ((a = xmlHasProp (n, name)) == NULL)
912 return GPG_ERR_NOT_FOUND;
914 if (xmlRemoveProp (a) == -1)
915 return GPG_ERR_BAD_DATA;
917 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
919 char *user = create_acl_user (client);
921 rc = xml_add_attribute (client, n, (char *) "_acl", user);
922 xfree (user);
924 if (rc)
925 return rc;
928 return xml_update_element_mtime (client, n);
931 gpg_error_t
932 xml_validate_import (struct client_s *client, xmlNodePtr node)
934 gpg_error_t rc = 0;
936 if (!node)
937 return 0;
939 for (xmlNodePtr n = node; n; n = n->next)
941 if (n->type == XML_ELEMENT_NODE)
943 if (xmlStrEqual (n->name, (xmlChar *) "element"))
945 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
947 if (!a)
949 xmlChar *t = xmlGetNodePath (n);
951 log_write (_("Missing attribute '_name' at %s."), t);
952 xmlFree (t);
953 return GPG_ERR_INV_VALUE;
956 if (!xml_valid_element (a))
958 xmlChar *t = xmlGetNodePath (n);
960 log_write (_("'%s' is not a valid element name at %s."), a,
962 xmlFree (a);
963 xmlFree (t);
964 return GPG_ERR_INV_VALUE;
967 xmlFree (a);
968 a = xmlGetProp (n, (xmlChar *) "_ctime");
969 if (!a)
970 attr_ctime (client, n);
972 xmlFree (a);
973 a = xmlGetProp (n, (xmlChar *) "_mtime");
974 if (!a)
975 xml_update_element_mtime (client, n);
976 xmlFree (a);
978 else
980 xmlChar *t = xmlGetNodePath (n);
981 xmlNodePtr tmp = n->next;
983 log_write (_("Warning: unknown element '%s' at %s. Removing."),
984 n->name, t);
985 xmlFree (t);
986 (void)xml_unlink_node (client, n);
987 return xml_validate_import (client, tmp);
991 if (n->children)
993 rc = xml_validate_import (client, n->children);
994 if (rc)
995 return rc;
999 return rc;
1002 gpg_error_t
1003 xml_update_element_mtime (struct client_s *client, xmlNodePtr n)
1005 return xml_add_attribute (client, n, NULL, NULL);
1008 gpg_error_t
1009 xml_unlink_node (struct client_s *client, xmlNodePtr n)
1011 gpg_error_t rc = 0;
1013 if (!n)
1014 return rc;
1016 if (n->parent)
1017 rc = xml_update_element_mtime (client, n->parent);
1019 xmlUnlinkNode (n);
1020 xmlFreeNodeList (n);
1021 return rc;
1024 gpg_error_t
1025 xml_parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1027 xmlDocPtr doc;
1029 xmlResetLastError ();
1030 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1031 if (!doc && xmlGetLastError ())
1032 return GPG_ERR_BAD_DATA;
1034 *result = doc;
1035 return !doc ? GPG_ERR_ENOMEM : 0;
1038 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1039 * target. 'path' is any remaining elements in the element path after this
1040 * element 'node' as passed to xml_find_elements() or the initial command. This
1041 * function may be recursive as it calls xml_find_elements().
1043 static xmlNodePtr
1044 do_realpath (struct client_s *client, struct xml_request_s *req,
1045 xmlNodePtr node, char **path, const xmlChar *target,
1046 gpg_error_t *rc) {
1047 char *line;
1048 char **result = NULL;
1049 struct xml_request_s *nreq;
1051 *rc = 0;
1053 result = str_split ((char *)target, "\t", 0);
1054 if (!result)
1056 *rc = GPG_ERR_ENOMEM;
1057 return NULL;
1060 /* Append the original path to the target path. */
1061 if (path)
1063 char **p = strv_catv (result, path);
1065 strv_free (result);
1066 if (!p)
1068 *rc = GPG_ERR_ENOMEM;
1069 return NULL;
1072 result = p;
1075 line = strv_join ("\t", result);
1076 if (!line)
1078 strv_free (result);
1079 *rc = GPG_ERR_ENOMEM;
1080 return NULL;
1083 /* To prevent overwriting any original client request flags. We are only
1084 * interested in the path here. */
1085 *rc = xml_new_request (client, line, XML_CMD_REALPATH, &nreq);
1086 xfree (line);
1087 if (*rc)
1089 strv_free (result);
1090 return NULL;
1093 nreq->depth = req->depth;
1094 strv_free (result);
1095 node = xml_find_elements (client, nreq, xmlDocGetRootElement (nreq->doc), rc);
1097 /* Update the original client request path with the resolved one. */
1098 if (!*rc)
1100 strv_free (req->args);
1101 req->args = nreq->args;
1102 nreq->args = NULL;
1105 xml_free_request (nreq);
1106 return node;
1109 #if 0
1110 static char *
1111 node_to_element_path (xmlNodePtr node)
1113 xmlNodePtr n;
1114 struct string_s *str = string_new ("");
1115 char *result;
1117 for (n = node; n; n = n->parent)
1119 xmlNodePtr child;
1121 for (child = n; child; child = child->next)
1123 if (child->type != XML_ELEMENT_NODE)
1124 continue;
1126 xmlChar *name = xml_attribute_value (n, (xmlChar *) "_name");
1127 if (name)
1129 str = string_prepend (str, (char *) name);
1130 xmlFree (name);
1131 name = xml_attribute_value (n, (xmlChar *) "target");
1132 if (name)
1133 str = string_prepend (str, "\t");
1134 else
1135 str = string_prepend (str, "\t!");
1136 xmlFree (name);
1138 break;
1142 str = string_erase (str, 0, 1);
1143 result = str->str;
1144 string_free (str, 0);
1145 return result;
1147 #endif
1149 /* Tests if 'path' references 'node' somewhere. */
1150 static gpg_error_t
1151 element_related (struct client_s *client, xmlDocPtr doc, const char *path,
1152 xmlNodePtr node, unsigned depth)
1154 gpg_error_t rc = GPG_ERR_NO_DATA;
1155 char **p;
1156 xmlNodePtr n = xmlDocGetRootElement (doc);
1158 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1159 return GPG_ERR_ELOOP;
1161 p = str_split (path, "\t", 0);
1162 if (!p)
1163 return GPG_ERR_ENOMEM;
1165 for (n = n->children; n && *p; p++, n = n->next)
1167 xmlNodePtr t;
1168 xmlChar *target;
1169 struct string_s *str = NULL;
1171 t = xml_find_element (client, n, *p, &rc);
1172 if (rc)
1174 rc = GPG_ERR_NO_DATA;
1175 break;
1178 if (t == node)
1180 rc = 0;
1181 break;
1184 target = xml_attribute_value (t, (xmlChar *)"target");
1185 if (!target)
1186 continue;
1188 str = string_new ((char *)target);
1189 xmlFree (target);
1190 if (!str)
1192 rc = GPG_ERR_ENOMEM;
1193 break;
1196 if (*(p+1))
1198 while (*++p)
1200 struct string_s *tmp;
1202 tmp = string_append_printf (str, "\t%s", *p);
1203 if (!tmp)
1205 string_free (str, 1);
1206 strv_free (p);
1207 return GPG_ERR_ENOMEM;
1210 str = tmp;
1214 rc = element_related (client, doc, str->str, n->children, ++depth);
1215 if (rc == GPG_ERR_ELOOP)
1216 rc = GPG_ERR_NO_DATA;
1218 string_free(str, 1);
1219 break;
1222 strv_free (p);
1223 return rc;
1227 * Recurse the element tree beginning at 'node' and find elements who point
1228 * back to 'dst'. Also follows target attributes.
1230 static gpg_error_t
1231 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1232 xmlNodePtr dst, unsigned depth, int is_target)
1234 xmlNodePtr n;
1235 gpg_error_t rc = 0;
1237 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1238 return node == dst ? GPG_ERR_ELOOP : 0;
1240 for (n = node; n; n = n->next)
1242 xmlChar *target;
1244 if (n->type != XML_ELEMENT_NODE)
1245 continue;
1247 if (n == dst && depth)
1248 return GPG_ERR_ELOOP;
1250 target = xml_attribute_value (n, (xmlChar *) "target");
1251 if (target)
1253 xmlNodePtr tmp;
1254 char **result = NULL;
1256 tmp = xml_resolve_path (client, doc, target, &result, &rc);
1257 strv_free (result);
1258 if (!rc)
1260 rc = find_child_to_target (client, doc, tmp, dst, ++depth, 1);
1261 depth--;
1263 else if (rc == GPG_ERR_ELOOP)
1265 gpg_error_t trc = element_related (client, doc, (char *)target,
1266 dst, 0);
1268 if (trc && trc != GPG_ERR_NO_DATA)
1269 rc = trc;
1270 else if (trc == GPG_ERR_NO_DATA)
1271 rc = 0;
1274 xmlFree (target);
1276 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
1277 return rc;
1279 rc = 0;
1280 if (is_target)
1281 break;
1283 continue;
1286 if (n->children)
1288 rc = find_child_to_target (client, doc, n->children, dst, ++depth, 0);
1289 depth--;
1290 if (rc)
1291 return rc;
1294 if (is_target)
1295 break;
1298 return rc;
1301 static gpg_error_t
1302 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1304 xmlNodePtr n;
1305 gpg_error_t rc = 0;
1307 for (n = src; n; n = n->next)
1309 if (n->type != XML_ELEMENT_NODE)
1310 continue;
1312 if (n == dst)
1314 rc = GPG_ERR_ELOOP;
1315 break;
1318 rc = find_child_of_parent (doc, n->children, dst);
1321 return rc;
1324 static gpg_error_t
1325 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1327 xmlNodePtr n;
1328 gpg_error_t rc = 0;
1330 for (n = node; n; n = n->parent)
1332 if (n->type != XML_ELEMENT_NODE)
1334 xmlNodePtr tmp;
1336 for (tmp = n->next; tmp; n = n->next)
1338 if (n->type != XML_ELEMENT_NODE)
1339 continue;
1341 if (tmp == dst)
1342 return GPG_ERR_ELOOP;
1346 if (n == dst)
1347 return GPG_ERR_ELOOP;
1350 return rc;
1353 void
1354 xml_free_element_list (struct element_list_s *elements)
1356 if (elements)
1358 if (elements->list)
1360 int total = slist_length (elements->list);
1361 int i;
1363 for (i = 0; i < total; i++)
1365 char *tmp = slist_nth_data (elements->list, i);
1366 xfree (tmp);
1369 slist_free (elements->list);
1372 string_free (elements->prefix, 1);
1373 xfree (elements->target);
1374 xfree (elements);
1378 /* This behaves like the LIST command with a specified path except it returns
1379 * an error.
1381 gpg_error_t
1382 xml_check_recursion (struct client_s *client, struct xml_request_s *req)
1384 gpg_error_t rc;
1385 struct element_list_s *elements;
1386 char *path = NULL;
1387 char **dup = strv_dup (req->args);
1389 if (!dup)
1390 return GPG_ERR_ENOMEM;
1393 elements = xcalloc (1, sizeof (struct element_list_s));
1394 if (!elements)
1396 rc = GPG_ERR_ENOMEM;
1397 goto fail;
1400 path = strv_join ("\t", dup);
1401 if (!path)
1403 rc = GPG_ERR_ENOMEM;
1404 goto fail;
1407 elements->flags |= XML_LIST_CHECK;
1408 elements->prefix = string_new (NULL);
1409 if (!elements->prefix)
1411 rc = GPG_ERR_ENOMEM;
1412 goto fail;
1415 rc = xml_create_path_list (client, req->doc, xmlDocGetRootElement (req->doc),
1416 elements, path, 0);
1418 fail:
1419 xml_free_element_list (elements);
1420 strv_free (dup);
1421 xfree (path);
1422 return rc;
1425 gpg_error_t
1426 xml_validate_target (struct client_s *client, xmlDocPtr doc, const char *src,
1427 xmlNodePtr dst)
1429 gpg_error_t rc;
1430 xmlNodePtr src_node;
1431 char **src_req = NULL;
1433 src_node = xml_resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
1434 if (rc)
1435 goto fail;
1437 client->flags |= FLAG_ACL_IGNORE;
1438 /* A destination element is a child of the source element. */
1439 rc = find_child_of_parent (doc, src_node->children, dst);
1440 if (rc)
1441 goto fail;
1443 /* The destination element is a parent of the source element. */
1444 rc = find_parent_of_child (doc, src_node->parent, dst);
1445 if (rc)
1446 goto fail;
1448 /* A destination child element contains a target to the source element. */
1449 if (dst)
1450 rc = find_child_to_target (client, doc,
1451 dst->children ? dst->children : dst, dst, 0, 0);
1452 if (rc)
1453 goto fail;
1455 fail:
1456 strv_free (src_req);
1457 client->flags &= ~(FLAG_ACL_IGNORE | FLAG_ACL_ERROR);
1458 return rc;
1461 /* The owner of the element is the first user listed in the _acl attribute
1462 * list. acl_check() should be called before calling this function. An empty
1463 * ACL is an error if the client is not an invoking_user.
1465 gpg_error_t
1466 xml_is_element_owner (struct client_s *client, xmlNodePtr n)
1468 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
1469 char **users;
1470 gpg_error_t rc = GPG_ERR_EACCES;
1472 if (!acl || !*acl)
1474 xmlFree (acl);
1475 return peer_is_invoker (client);
1478 users = str_split((char *)acl, ",", 0);
1479 if (users && *users)
1481 char *user;
1483 #ifdef WITH_GNUTLS
1484 if (client->thd->remote)
1485 user = str_asprintf ("#%s", client->thd->tls->fp);
1486 else
1487 user = get_username (client->thd->peer->uid);
1488 #else
1489 user = get_username (client->thd->peer->uid);
1490 #endif
1492 if (*user == '#')
1493 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
1494 else
1495 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
1497 if (rc)
1498 rc = peer_is_invoker (client);
1500 xfree (user);
1503 xmlFree (acl);
1504 strv_free (users);
1505 return rc;
1508 /* Find elements by matching element names in req->args starting at 'node'.
1509 * Returns the node of the final element in req->args on success or NULL on
1510 * failure and sets 'rc' to the error code. Some commands may need special
1511 * handling and will return the node of the previous found element.
1513 xmlNodePtr
1514 xml_find_elements (struct client_s *client, struct xml_request_s *req,
1515 xmlNodePtr node, gpg_error_t *rc)
1517 xmlNodePtr n, last;
1518 char **p = req->args;
1520 *rc = 0;
1521 req->depth++;
1523 if (max_recursion_depth >= 1 && req->depth > max_recursion_depth)
1525 req->depth--;
1526 *rc = GPG_ERR_ELOOP;
1527 return NULL;
1530 /* Beginning of a command/root element (<pwmd>). */
1531 if (node == xmlDocGetRootElement (req->doc))
1533 if (!node->children) // Empty tree
1535 if (req->cmd == XML_CMD_STORE)
1536 return xml_create_element_path (client, req, node, req->args, rc);
1538 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1539 req->depth--;
1540 return NULL;
1543 node = node->children; // Start searching at the first child of the root
1546 for (last = n = node, p = req->args; *p; p++)
1548 xmlNodePtr tmp = NULL;
1549 struct element_list_s *elements = NULL;
1551 // FIXME should not be reached in this function?
1552 if (!*(*p))
1554 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1555 req->depth--;
1556 return NULL;
1559 n = xml_find_element (client, n, *p, rc);
1560 if (*rc)
1562 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND && *rc != GPG_ERR_EACCES)
1564 req->depth--;
1565 return NULL;
1568 if (*rc == GPG_ERR_EACCES
1569 && (req->cmd == XML_CMD_ATTR_LIST || req->cmd == XML_CMD_ATTR
1570 || req->cmd == XML_CMD_ATTR_EXPIRE))
1572 req->depth--;
1573 if (*(p+1))
1574 return NULL;
1576 *rc = 0;
1577 return n;
1580 /* Fixes ATTR LIST when an element does not exist and the parent
1581 * denies access to children. Fixes leaking information about the
1582 * current elements children. */
1583 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND && last != n && last != node)
1585 gpg_error_t trc = acl_check (client, last);
1586 if (trc)
1587 *rc = trc;
1590 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND)
1592 if (req->cmd == XML_CMD_STORE || req->cmd == XML_CMD_ATTR_TARGET)
1594 *rc = 0;
1595 n = xml_create_element_path (client, req,
1596 *p == *req->args
1597 && node->parent == xmlDocGetRootElement (req->doc)
1598 ? node->parent : last, p, rc);
1599 req->depth--;
1600 return n;
1604 if (req->cmd != XML_CMD_LIST)
1606 req->depth--;
1607 return NULL;
1610 // Fall through to let LIST flags be appended.
1613 last = n;
1615 /* Follow a "target" attribute for each one found in each element. */
1616 xmlChar *target = xml_attribute_value (n, (xmlChar *) "target");
1617 if (!target || !*target)
1619 xmlFree (target);
1621 if (*rc)
1623 req->depth--;
1624 return NULL;
1627 /* This is the final element in req->args. Done. */
1628 if (!*(p+1))
1630 req->depth--;
1631 return n;
1634 n = n->children;
1635 continue;
1638 if (req->cmd == XML_CMD_REALPATH)
1640 n = do_realpath (client, req, n, p+1, target, rc);
1641 xmlFree (target);
1642 req->depth--;
1643 return n;
1645 else if (req->cmd == XML_CMD_DELETE || req->cmd == XML_CMD_RENAME
1646 || req->cmd == XML_CMD_MOVE || req->cmd == XML_CMD_ATTR
1647 || req->cmd == XML_CMD_ATTR_TARGET
1648 || req->cmd == XML_CMD_ATTR_LIST)
1650 /* No more elements to resolve. Return the node with the target. */
1651 if (!*(p+1))
1653 xmlFree (target);
1654 req->depth--;
1655 return n;
1658 else if (req->cmd == XML_CMD_LIST)
1660 elements = req->data;
1661 if (elements && !(elements->flags & XML_LIST_CHILD_TARGET))
1663 /* No further elements. Use this target in the list flags. */
1664 if (!*(p+1))
1665 elements->flags |= XML_LIST_HAS_TARGET;
1666 else
1668 /* Prevent replacing any following target value with the
1669 * current target value. */
1670 req->data = NULL;
1673 else if (!elements)
1675 struct element_list_s *e = xcalloc (1, sizeof (struct element_list_s));
1677 e->target = str_dup ((char *)target);
1678 e->flags |= XML_LIST_CHILD_TARGET;
1680 if (!*(p+1))
1681 e->flags |= XML_LIST_HAS_TARGET;
1683 req->data = elements = e;
1686 *rc = xml_validate_target (client, req->doc, (char *)target, n);
1687 /* Ignore errors for elements elsewhere in the document. */
1688 if (*rc == GPG_ERR_EACCES)
1689 *rc = 0;
1691 if (*rc)
1692 goto update_target;
1695 /* Create a new path based on the value of the current "target"
1696 * attribute. */
1697 char **nargs = str_split ((char *)target, "\t", 0);
1698 if (!nargs)
1700 xmlFree (target);
1701 *rc = GPG_ERR_INV_VALUE;
1702 req->data = req->cmd == XML_CMD_LIST ? elements : req->data;
1703 req->depth--;
1704 return NULL;
1707 /* Append the remaining elements to the target attributes path. */
1708 char **nnargs = strv_catv (nargs, p+1);
1709 strv_free (nargs);
1710 char **orig = req->args;
1711 req->args = nnargs;
1712 tmp = xml_find_elements (client, req, xmlDocGetRootElement (req->doc),
1713 rc);
1714 strv_free (nnargs);
1715 req->args = orig;
1717 update_target:
1718 if (req->cmd == XML_CMD_LIST && elements)
1720 /* A child node contained a target. Use this value rather than the
1721 * current target value as the target value for the list flag. */
1722 if (req->data && req->data != elements)
1724 struct element_list_s *e = req->data;
1726 xmlFree (target);
1727 target = xmlStrdup ((xmlChar *)e->target);
1728 xfree (e->target);
1730 if ((e->flags & XML_LIST_HAS_TARGET))
1731 elements->flags |= XML_LIST_HAS_TARGET;
1733 xfree (e);
1736 req->data = elements;
1737 if (req->data)
1739 if (!(elements->flags & XML_LIST_TARGET_ERROR))
1741 xfree (elements->target);
1742 elements->target = NULL;
1744 /* Restore the original target flag. */
1745 if ((elements->flags & XML_LIST_HAS_TARGET))
1746 elements->target = str_dup ((char *)target);
1751 xmlFree (target);
1752 req->depth--;
1753 return *rc ? NULL : tmp;
1756 req->depth--;
1757 return n;
1760 gpg_error_t
1761 xml_new_request (struct client_s *client, const char *line, xml_command_t cmd,
1762 struct xml_request_s **result)
1764 struct xml_request_s *req;
1765 char **pp = str_split ((char *) line, "\t", 0);
1767 if (!pp || !*pp)
1769 strv_free (pp);
1770 return GPG_ERR_SYNTAX;
1773 req = xcalloc (1, sizeof (struct xml_request_s));
1774 if (!req)
1776 strv_free (pp);
1777 return GPG_ERR_ENOMEM;
1780 req->cmd = cmd;
1781 req->args = pp;
1782 req->doc = client ? client->doc : NULL;
1783 *result = req;
1784 return 0;
1787 void
1788 xml_free_request (struct xml_request_s *r)
1790 if (!r)
1791 return;
1793 strv_free (r->args);
1794 xfree (r);
1798 xml_reserved_attribute (const char *name)
1800 int i;
1802 for (i = 0; reserved_attributes[i]; i++)
1804 if (!strcmp (name, reserved_attributes[i]))
1805 return 1;
1808 return 0;