s/xml_reserved_element/xml_reserved_attribute.
[pwmd.git] / src / xml.c
blobbf37b91a2d4b94cc173d406246077f83c0c1a570
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 <err.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <libxml/xmlwriter.h>
34 #include <wctype.h>
35 #include <sys/types.h>
36 #include <pwd.h>
38 #ifndef _
39 #include "gettext.h"
40 #define _(msgid) gettext(msgid)
41 #endif
43 #include "pwmd-error.h"
44 #include "util-misc.h"
45 #include "xml.h"
46 #include "mem.h"
47 #include "rcfile.h"
48 #include "commands.h"
50 #define XML_LIST_FLAG_CHILDREN 0x0001
51 #define XML_LIST_HAS_TARGET 0x0002
52 #define XML_LIST_CHILD_TARGET 0x0004
53 #define XML_LIST_TARGET_ERROR 0x0008
54 #define XML_LIST_CHECK 0x0010
56 const char *reserved_attributes[] = {
57 "_name", "_mtime", "_ctime", "_acl", "target",
58 NULL
61 extern void log_write (const char *fmt, ...);
63 int
64 xml_valid_attribute_value (const char *str)
66 const char *p = str;
68 if (!p || !*p)
69 return 1;
71 while (*p)
73 if (*p++ == '\n')
74 return 0;
77 return 1;
80 int
81 xml_valid_attribute (const char *str)
83 wchar_t *wc;
84 size_t len, c;
85 int ret = xml_valid_element ((xmlChar *)str);
87 if (!ret)
88 return ret;
90 wc = str_to_wchar ((const char *)str);
91 if (!wc)
92 return 0;
94 len = wcslen (wc);
95 for (c = 0; c < len; c++)
97 switch (wc[c])
99 case '-':
100 case '.':
101 case '0' ... '9':
102 case 0xB7:
103 case 0x0300 ... 0x036F:
104 case 0x203F ... 0x2040:
105 if (!c)
107 xfree (wc);
108 return 0;
110 case ':': break;
111 case '_': break;
112 case 'A' ... 'Z': break;
113 case 'a' ... 'z': break;
114 case 0xC0 ... 0xD6: break;
115 case 0xD8 ... 0xF6: break;
116 case 0xF8 ... 0x2FF: break;
117 case 0x370 ... 0x37D: break;
118 case 0x37F ... 0x1FFF: break;
119 case 0x200C ... 0x200D: break;
120 case 0x2070 ... 0x218F: break;
121 case 0x2C00 ... 0x2FEF: break;
122 case 0x3001 ... 0xD7FF: break;
123 case 0xF900 ... 0xFDCF: break;
124 case 0xFDF0 ... 0xFFFD: break;
125 case 0x10000 ... 0xEFFFF: break;
126 default:
127 xfree (wc);
128 return 0;
132 xfree (wc);
133 return 1;
137 xml_valid_element (xmlChar *str)
139 wchar_t *wc;
140 size_t len, c;
142 if (!str || !*str)
143 return 0;
145 wc = str_to_wchar ((const char *)str);
146 if (!wc)
147 return 0;
149 len = wcslen (wc);
150 for (c = 0; c < len; c++)
152 if (iswspace(wc[c]))
154 xfree (wc);
155 return 0;
159 xfree (wc);
160 return 1;
164 xml_valid_element_path (char **path, int with_content)
166 char **dup = NULL, **p;
168 if (!path || !*path)
169 return 0;
171 /* Save some memory by not duplicating the element content. */
172 if (with_content)
174 int i, t = strv_length (path);
176 for (i = 0; i < t - 1; i++)
178 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
180 if (!tmp)
182 strv_free (dup);
183 return 0;
186 dup = tmp;
187 dup[i] = str_dup (path[i]);
188 dup[i + 1] = NULL;
191 else
192 dup = strv_dup (path);
194 if (!dup)
195 return 0;
197 for (p = dup; *p && *(*p); p++)
199 if (!xml_valid_element ((xmlChar *) * p))
201 strv_free (dup);
202 return 0;
206 strv_free (dup);
207 return 1;
210 static gpg_error_t
211 attr_ctime (struct client_s *client, xmlNodePtr n)
213 char *buf = str_asprintf ("%li", time (NULL));
214 gpg_error_t rc;
216 if (!buf)
217 return GPG_ERR_ENOMEM;
219 rc = xml_add_attribute (client, n, "_ctime", buf);
220 xfree (buf);
221 return rc;
224 static gpg_error_t
225 acl_check (struct client_s *client, xmlNodePtr n)
227 gpg_error_t rc = GPG_ERR_EACCES;
228 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
229 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
230 char **p;
231 int allowed = 0;
233 if (!acl || !*acl || !users || !*users)
235 xmlFree (acl);
236 strv_free(users);
237 return peer_is_invoker(client);
240 if (!peer_is_invoker(client))
242 xmlFree (acl);
243 strv_free(users);
244 return 0;
247 for (p = users; p && *p; p++)
249 #ifdef WITH_GNUTLS
250 rc = acl_check_common (client, *p,
251 client->thd->remote ? 0 : client->thd->peer->uid,
252 client->thd->remote ? 0 : client->thd->peer->gid,
253 &allowed);
254 #else
255 rc = acl_check_common (client, *p, client->thd->peer->uid,
256 client->thd->peer->gid, &allowed);
257 #endif
260 xmlFree(acl);
261 strv_free(users);
263 if (rc)
264 return rc;
266 return allowed ? 0 : GPG_ERR_EACCES;
269 static char *
270 create_acl_user (struct client_s *client)
272 #ifdef WITH_GNUTLS
273 if (client->thd->remote)
274 return str_asprintf ("#%s", client->thd->tls->fp);
275 #endif
277 return get_username (client->thd->peer->uid);
280 static gpg_error_t
281 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
282 const char *name, xmlNodePtr * result)
284 xmlNodePtr n;
285 gpg_error_t rc;
287 // Allow any client to create a non-existing root element.
288 if (parent->parent->type != XML_DOCUMENT_NODE)
290 rc = acl_check(client, parent);
291 if (rc)
292 return rc;
295 n = xmlNewNode (NULL, (xmlChar *) "element");
296 if (!n)
297 return GPG_ERR_ENOMEM;
299 rc = xml_add_attribute (client, n, "_name", name);
300 if (!rc)
301 rc = attr_ctime (client, n);
303 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
304 rc = xml_is_element_owner (client, parent);
306 if (!rc)
308 xmlNodePtr p = xmlAddChild (parent, n);
309 char *user = create_acl_user (client);
311 if (result)
312 *result = p;
314 rc = xml_add_attribute(client, p, "_acl", user);
315 xfree (user);
317 else
318 xmlFreeNode (n);
320 return rc;
323 gpg_error_t
324 xml_new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
326 xmlNodePtr root = xmlDocGetRootElement (doc);
328 if (!name || !root)
329 return GPG_ERR_BAD_DATA;
331 if (!xml_valid_element ((xmlChar *) name))
332 return GPG_ERR_INV_VALUE;
334 return create_new_element (client, 0, root, name, NULL);
337 static xmlDocPtr
338 create_dtd ()
340 xmlDocPtr doc;
341 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
343 if (!wr)
344 return NULL;
346 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
347 goto fail;
349 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
350 goto fail;
352 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
353 (xmlChar *) "(element)") == -1)
354 goto fail;
356 xmlTextWriterEndDTDElement (wr);
358 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
359 (xmlChar *) "_name CDATA #REQUIRED") ==
361 goto fail;
363 xmlTextWriterEndDTDAttlist (wr);
364 xmlTextWriterEndDTD (wr);
366 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
367 goto fail;
369 xmlTextWriterEndElement (wr);
370 xmlTextWriterEndDocument (wr);
371 xmlFreeTextWriter (wr);
372 return doc;
374 fail:
375 xmlTextWriterEndDocument (wr);
376 xmlFreeTextWriter (wr);
377 xmlFreeDoc (doc);
378 return NULL;
381 xmlDocPtr
382 xml_new_document ()
384 return create_dtd ();
387 static xmlNodePtr
388 find_element_node (xmlNodePtr node)
390 xmlNodePtr n = node;
392 if (n && n->type == XML_ELEMENT_NODE)
393 return n;
395 for (n = node; n; n = n->next)
397 if (n->type == XML_ELEMENT_NODE)
398 return n;
401 return NULL;
404 xmlNodePtr
405 xml_resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
406 char ***result, gpg_error_t *rc)
408 xmlNodePtr n;
409 struct xml_request_s *req;
411 *rc = xml_new_request (client, (char *)path, XML_CMD_REALPATH, &req);
412 if (*rc)
413 return NULL;
415 n = xml_find_elements (client, req, xmlDocGetRootElement (doc), rc);
416 if (!*rc)
418 if (result)
420 *result = strv_dup (req->args);
421 if (!*result)
423 *rc = GPG_ERR_ENOMEM;
424 n = NULL;
429 xml_free_request (req);
430 return n;
434 * Prevents a sibling element past the current element path with the same
435 * element name.
437 static xmlNodePtr
438 find_sibling_node (xmlNodePtr node)
440 xmlNodePtr n;
442 if (!node || !node->parent)
443 return NULL;
445 for (n = node->parent->children; n; n = n->next)
447 if (n == node)
448 return n->next;
451 return NULL;
454 xmlNodePtr
455 xml_find_text_node (xmlNodePtr node)
457 xmlNodePtr n = node;
459 if (n && n->type == XML_TEXT_NODE)
460 return n;
462 for (n = node; n; n = n->next)
464 if (n->type == XML_TEXT_NODE)
465 return n;
468 return NULL;
471 /* Create an element 'path' starting at 'node'. Returns the node of the final
472 * created element.
474 xmlNodePtr
475 xml_create_element_path (struct client_s *client, struct xml_request_s *req,
476 xmlNodePtr node, char **path, gpg_error_t *rc)
478 char **p;
480 /* The parent node will be an XML_ELEMENT_NODE. Otherwise we would be
481 * creating element content. */
482 if (node->type == XML_TEXT_NODE)
483 node = node->parent;
485 for (p = path; p && *p; p++)
487 xmlNodePtr n = NULL;
489 if (node != xmlDocGetRootElement (req->doc))
491 n = xml_find_element (client, node, *p, find_sibling_node (node), rc);
492 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
493 return NULL;
495 *rc = 0;
499 * If the found element has the same parent as the current element then
500 * they are siblings and the new element needs to be created as a child
501 * of the current element (node).
503 if (n && n->parent == node->parent)
504 n = NULL;
506 if (!n)
508 *rc = create_new_element (client, 0, node, *p, &node);
509 if (*rc)
510 return NULL;
512 else
513 node = n;
516 return node;
519 /* Find the first XML_ELEMENT_NODE whose _name attribute matches 'element'. */
520 xmlNodePtr
521 xml_find_element (struct client_s *client, xmlNodePtr node, const char *element,
522 xmlNodePtr stop, gpg_error_t *rc)
524 xmlNodePtr n;
526 *rc = 0;
528 if (!node || !element)
530 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
531 return NULL;
534 for (n = node; n; n = n->next)
536 if (n->type != XML_ELEMENT_NODE)
537 continue;
539 if (n == stop)
540 return 0; // FIXME?
542 xmlChar *a = xml_attribute_value (n, (xmlChar *) "_name");
543 if (a && xmlStrEqual (a, (xmlChar *) element))
545 xmlFree (a);
546 *rc = acl_check (client, n);
547 return n; // Not NULL since the node may be needed later
550 xmlFree (a);
553 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
554 return NULL;
557 xmlChar *
558 xml_attribute_value (xmlNodePtr n, xmlChar * attr)
560 xmlAttrPtr a = xmlHasProp (n, attr);
562 if (!a)
563 return NULL;
565 if (!a->children || !a->children->content)
566 return NULL;
568 return xmlGetProp (n, attr);
571 gpg_error_t
572 xml_add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
573 const char *value)
575 char *buf;
576 gpg_error_t rc = 0;
578 if (client && name && !strcmp (name, "target"))
580 rc = xml_is_element_owner (client, node);
581 if (rc)
582 return rc;
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 buf = str_asprintf ("%lu", time (NULL));
625 rc = xml_add_attribute (client, node, "_mtime", buf);
626 xfree (buf);
627 return rc;
630 static gpg_error_t
631 append_path_to_list (struct client_s *client, struct element_list_s *elements,
632 const char *path, gpg_error_t rc)
634 struct slist_s *l;
635 struct string_s *line;
637 line = string_new (NULL);
638 if (!line)
639 return GPG_ERR_ENOMEM;
641 if (rc == GPG_ERR_ELOOP)
642 string_append (line, "O");
643 else if (rc == GPG_ERR_EACCES)
644 string_append (line, "P");
645 else if (rc)
646 string_append (line, "E");
648 if (rc || elements->target)
649 string_prepend (line, " ");
651 if ((!rc || rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
652 || rc == GPG_ERR_ELEMENT_NOT_FOUND) && elements->target)
653 string_append_printf (line, "%sT %s",
654 (!rc && elements->flags & XML_LIST_FLAG_CHILDREN) ? "+" : "",
655 elements->target);
656 else if (!rc && (elements->flags & XML_LIST_FLAG_CHILDREN))
657 string_prepend (line, " +");
659 if (elements->prefix && elements->prefix->str)
660 string_prepend (line, elements->prefix->str);
661 else
662 string_prepend (line, path);
664 l = slist_append (elements->list, line->str);
665 if (l)
667 elements->list = l;
668 if (!(elements->flags & XML_LIST_CHECK))
669 rc = 0;
671 else
672 rc = GPG_ERR_ENOMEM;
674 string_free (line, 0);
675 return rc;
678 /* Removes the final element from the element prefix. */
679 static void
680 pop_element_prefix (struct element_list_s *elements)
682 char *p = strrchr (elements->prefix->str, '\t');
684 if (p)
685 string_truncate (elements->prefix,
686 elements->prefix->len - strlen (p));
689 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
690 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
693 * From the element path 'path', find sub-nodes and append them to the list.
695 gpg_error_t
696 xml_create_path_list (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
697 struct element_list_s *elements, char *path,
698 gpg_error_t rc)
700 xmlNodePtr n = NULL;
701 struct xml_request_s *req = NULL;
702 gpg_error_t trc = rc;
703 char *target_orig;
705 target_orig = rc && elements->target ? str_dup (elements->target) : NULL;
706 rc = xml_new_request (client, path, XML_CMD_LIST, &req);
707 if (rc)
709 xfree (target_orig);
710 return rc;
713 req->data = elements;
714 n = xml_find_elements (client, req,
715 node ? node : xmlDocGetRootElement (doc), &rc);
716 if (!rc)
717 elements->flags |=
718 find_element_node (n->children) ? XML_LIST_FLAG_CHILDREN : 0;
720 if (!rc && trc)
722 xfree (elements->target);
723 elements->target = target_orig;
724 elements->flags = 0;
725 elements->flags |= XML_LIST_HAS_TARGET;
727 else
728 xfree (target_orig);
730 rc = append_path_to_list (client, elements, path, trc ? trc : rc);
731 xmlFree (elements->target);
732 elements->target = NULL;
734 if (rc || trc || (elements->flags & XML_LIST_CHECK)
735 || (!elements->recurse && elements->depth) || elements->root_only)
737 xml_free_request (req);
738 return rc;
741 elements->flags = 0;
743 if (!rc && n && n->children)
745 for (n = n->children; n; n = n->next)
747 xmlChar *target = NULL;
748 xmlNodePtr tmp = NULL;
749 xmlChar *name;
750 struct string_s *newpath;
752 if (n->type != XML_ELEMENT_NODE)
753 continue;
755 name = xml_attribute_value (n, (xmlChar *) "_name");
756 if (!name)
757 continue;
759 newpath = string_new (NULL);
760 if (!newpath)
762 xmlFree (name);
763 rc = GPG_ERR_ENOMEM;
764 goto fail;
767 target = xml_attribute_value (n, (xmlChar *) "target");
768 if (target)
770 rc = xml_validate_target (client, req->doc, (char *)target, n);
771 elements->target = (char *)target;
772 elements->flags |= rc ? XML_LIST_TARGET_ERROR : 0;
774 else
775 tmp = n;
777 if (RESUMABLE_ERROR (rc))
779 struct string_s *s;
781 /* If there is a target for this node then resolve the full path
782 * starting at the document root. Otherwise, resolve the next
783 * element starting from the child node of the current node. In
784 * either case, append the current element in the element path to
785 * the prefix of the list string.
787 if (target)
789 string_truncate (newpath, 0);
790 s = string_append_printf (newpath, "%s", (char *)target);
792 else
793 s = string_append (newpath, (char *)name);
795 if (!s)
797 xmlFree (name);
798 string_free (newpath, 1);
799 rc = GPG_ERR_ENOMEM;
800 goto fail;
803 newpath = s;
804 if (!elements->depth)
806 /* There may be a single remaining element in the prefix left
807 * over from the previous truncation (see below). It is safe
808 * to truncate it here since depth == 0. */
809 string_truncate (elements->prefix, 0);
810 s = string_append_printf (elements->prefix, "%s\t%s",
811 path, name);
813 else
814 s = string_append_printf (elements->prefix, "\t%s", name);
816 if (!s)
818 xmlFree (name);
819 string_free (newpath, 1);
820 rc = GPG_ERR_ENOMEM;
821 goto fail;
824 elements->prefix = s;
825 elements->depth++;
826 rc = xml_create_path_list (client, doc, target ? NULL : tmp,
827 elements, newpath->str, rc);
828 elements->depth--;
829 if (!rc)
830 pop_element_prefix (elements);
833 string_free (newpath, 1);
834 xmlFree (name);
835 if (rc)
836 break;
840 fail:
841 xml_free_request (req);
842 return rc;
845 gpg_error_t
846 xml_recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
847 xmlNodeSetPtr nodes, xmlChar * value,
848 xmlBufferPtr * result, int cmd, const xmlChar * attr)
850 int i = value ? nodes->nodeNr - 1 : 0;
851 xmlBufferPtr buf;
853 buf = xmlBufferCreate ();
855 if (!buf)
856 return GPG_ERR_ENOMEM;
858 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
860 xmlNodePtr n = nodes->nodeTab[i];
861 gpg_error_t rc;
863 if (!n)
864 continue;
866 if (!value && !attr)
868 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
870 *result = buf;
871 return GPG_ERR_BAD_DATA;
874 continue;
877 if (!attr)
879 xmlNodeSetContent (n, value);
880 rc = xml_update_element_mtime (client, n);
882 if (rc)
883 return rc;
885 else
887 if (!cmd)
888 rc = xml_add_attribute (client, n, (char *) attr, (char *) value);
889 else
890 rc = xml_delete_attribute (client, n, attr);
892 if (rc)
893 return rc;
897 *result = buf;
898 return 0;
901 gpg_error_t
902 xml_delete_attribute (struct client_s *client, xmlNodePtr n,
903 const xmlChar *name)
905 xmlAttrPtr a;
906 gpg_error_t rc = 0;
908 if ((a = xmlHasProp (n, name)) == NULL)
909 return GPG_ERR_NOT_FOUND;
911 if (xmlRemoveProp (a) == -1)
912 return GPG_ERR_BAD_DATA;
914 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
916 char *user = create_acl_user (client);
918 rc = xml_add_attribute (client, n, (char *) "_acl", user);
919 xfree (user);
921 if (rc)
922 return rc;
925 return xml_update_element_mtime (client, n);
928 gpg_error_t
929 xml_validate_import (struct client_s *client, xmlNodePtr node)
931 gpg_error_t rc = 0;
933 if (!node)
934 return 0;
936 for (xmlNodePtr n = node; n; n = n->next)
938 if (n->type == XML_ELEMENT_NODE)
940 if (xmlStrEqual (n->name, (xmlChar *) "element"))
942 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
944 if (!a)
946 xmlChar *t = xmlGetNodePath (n);
948 log_write (_("Missing attribute '_name' at %s."), t);
949 xmlFree (t);
950 return GPG_ERR_INV_VALUE;
953 if (!xml_valid_element (a))
955 xmlChar *t = xmlGetNodePath (n);
957 log_write (_("'%s' is not a valid element name at %s."), a,
959 xmlFree (a);
960 xmlFree (t);
961 return GPG_ERR_INV_VALUE;
964 xmlFree (a);
965 a = xmlGetProp (n, (xmlChar *) "_ctime");
966 if (!a)
967 attr_ctime (client, n);
969 xmlFree (a);
970 a = xmlGetProp (n, (xmlChar *) "_mtime");
971 if (!a)
972 xml_update_element_mtime (client, n);
973 xmlFree (a);
975 else
977 xmlChar *t = xmlGetNodePath (n);
979 // FIXME: unlink unknown node.
980 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
981 n->name, t);
982 xmlFree (t);
983 continue;
987 if (n->children)
989 rc = xml_validate_import (client, n->children);
990 if (rc)
991 return rc;
995 return rc;
998 gpg_error_t
999 xml_update_element_mtime (struct client_s *client, xmlNodePtr n)
1001 return xml_add_attribute (client, n, NULL, NULL);
1004 gpg_error_t
1005 xml_unlink_node (struct client_s *client, xmlNodePtr n)
1007 gpg_error_t rc = 0;
1009 if (!n)
1010 return rc;
1012 if (n->parent)
1013 rc = xml_update_element_mtime (client, n->parent);
1015 xmlUnlinkNode (n);
1016 xmlFreeNodeList (n);
1017 return rc;
1020 gpg_error_t
1021 xml_parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1023 xmlDocPtr doc;
1025 xmlResetLastError ();
1026 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1027 if (!doc && xmlGetLastError ())
1028 return GPG_ERR_BAD_DATA;
1030 *result = doc;
1031 return !doc ? GPG_ERR_ENOMEM : 0;
1034 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1035 * target. 'path' is any remaining elements in the element path after this
1036 * element 'node' as passed to xml_find_elements() or the initial command. This
1037 * function may be recursive as it calls xml_find_elements().
1039 static xmlNodePtr
1040 do_realpath (struct client_s *client, struct xml_request_s *req,
1041 xmlNodePtr node, char **path, const xmlChar *target,
1042 gpg_error_t *rc) {
1043 char *line;
1044 char **result = NULL;
1045 struct xml_request_s *nreq;
1047 *rc = 0;
1049 result = str_split ((char *)target, "\t", 0);
1050 if (!result)
1052 *rc = GPG_ERR_ENOMEM;
1053 return NULL;
1056 /* Append the original path to the target path. */
1057 if (path)
1059 char **p = strv_catv (result, path);
1061 if (!p)
1063 strv_free (result);
1064 *rc = GPG_ERR_ENOMEM;
1065 return NULL;
1068 result = p;
1071 line = strv_join ("\t", result);
1072 if (!line)
1074 strv_free (result);
1075 *rc = GPG_ERR_ENOMEM;
1076 return NULL;
1079 /* To prevent overwriting any original client request flags. We are only
1080 * interested in the path here. */
1081 *rc = xml_new_request (client, line, XML_CMD_REALPATH, &nreq);
1082 if (*rc)
1084 strv_free (result);
1085 return NULL;
1088 nreq->depth = req->depth;
1089 strv_free (result);
1090 node = xml_find_elements (client, nreq, xmlDocGetRootElement (nreq->doc), rc);
1092 /* Update the original client request path with the resolved one. */
1093 if (!*rc)
1095 strv_free (req->args);
1096 req->args = nreq->args;
1097 nreq->args = NULL;
1100 xml_free_request (nreq);
1101 return node;
1104 #if 0
1105 static char *
1106 node_to_element_path (xmlNodePtr node)
1108 xmlNodePtr n;
1109 struct string_s *str = string_new ("");
1110 char *result;
1112 for (n = node; n; n = n->parent)
1114 xmlNodePtr child;
1116 for (child = n; child; child = child->next)
1118 if (child->type != XML_ELEMENT_NODE)
1119 continue;
1121 xmlChar *name = xml_attribute_value (n, (xmlChar *) "_name");
1122 if (name)
1124 str = string_prepend (str, (char *) name);
1125 xmlFree (name);
1126 name = xml_attribute_value (n, (xmlChar *) "target");
1127 if (name)
1128 str = string_prepend (str, "\t");
1129 else
1130 str = string_prepend (str, "\t!");
1131 xmlFree (name);
1133 break;
1137 str = string_erase (str, 0, 1);
1138 result = str->str;
1139 string_free (str, 0);
1140 return result;
1142 #endif
1144 /* Tests if 'path' references 'node' somewhere. */
1145 static gpg_error_t
1146 element_related (struct client_s *client, xmlDocPtr doc, const char *path,
1147 xmlNodePtr node, unsigned depth)
1149 gpg_error_t rc = GPG_ERR_NO_DATA;
1150 char **p;
1151 xmlNodePtr n = xmlDocGetRootElement (doc);
1153 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1154 return GPG_ERR_ELOOP;
1156 p = str_split (path, "\t", 0);
1157 if (!p)
1158 return GPG_ERR_ENOMEM;
1160 for (n = n->children; n && *p; p++, n = n->next)
1162 xmlNodePtr t;
1163 xmlChar *target;
1164 struct string_s *str = NULL;
1166 t = xml_find_element (client, n, *p, NULL, &rc);
1167 if (rc)
1169 rc = GPG_ERR_NO_DATA;
1170 break;
1173 if (t == node)
1175 rc = 0;
1176 break;
1179 target = xml_attribute_value (t, (xmlChar *)"target");
1180 if (!target)
1181 continue;
1183 str = string_new ((char *)target);
1184 xmlFree (target);
1185 if (!str)
1187 rc = GPG_ERR_ENOMEM;
1188 break;
1191 if (*(p+1))
1193 while (*++p)
1195 struct string_s *tmp;
1197 tmp = string_append_printf (str, "\t%s", *p);
1198 if (!tmp)
1200 string_free (str, 1);
1201 strv_free (p);
1202 return GPG_ERR_ENOMEM;
1205 str = tmp;
1209 rc = element_related (client, doc, str->str, n->children, ++depth);
1210 if (rc == GPG_ERR_ELOOP)
1211 rc = GPG_ERR_NO_DATA;
1213 string_free(str, 1);
1214 break;
1217 strv_free (p);
1218 return rc;
1222 * Recurse the element tree beginning at 'node' and find elements who point
1223 * back to 'dst'. Also follows target attributes.
1225 static gpg_error_t
1226 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1227 xmlNodePtr dst, unsigned depth, int is_target)
1229 xmlNodePtr n;
1230 gpg_error_t rc = 0;
1232 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1233 return node == dst ? GPG_ERR_ELOOP : 0;
1235 for (n = node; n; n = n->next)
1237 xmlChar *target;
1239 if (n->type != XML_ELEMENT_NODE)
1240 continue;
1242 if (n == dst && depth)
1243 return GPG_ERR_ELOOP;
1245 target = xml_attribute_value (n, (xmlChar *) "target");
1246 if (target)
1248 xmlNodePtr tmp;
1249 char **result = NULL;
1251 tmp = xml_resolve_path (client, doc, target, &result, &rc);
1252 strv_free (result);
1253 if (!rc)
1255 rc = find_child_to_target (client, doc, tmp, dst, ++depth, 1);
1256 depth--;
1258 else if (rc == GPG_ERR_ELOOP)
1260 gpg_error_t trc = element_related (client, doc, (char *)target,
1261 dst, 0);
1263 if (trc && trc != GPG_ERR_NO_DATA)
1264 rc = trc;
1265 else if (trc == GPG_ERR_NO_DATA)
1266 rc = 0;
1269 xmlFree (target);
1271 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
1272 return rc;
1274 rc = 0;
1275 if (is_target)
1276 break;
1278 continue;
1281 if (n->children)
1283 rc = find_child_to_target (client, doc, n->children, dst, ++depth, 0);
1284 depth--;
1285 if (rc)
1286 return rc;
1289 if (is_target)
1290 break;
1293 return rc;
1296 static gpg_error_t
1297 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1299 xmlNodePtr n;
1300 gpg_error_t rc = 0;
1302 for (n = src; n; n = n->next)
1304 if (n->type != XML_ELEMENT_NODE)
1305 continue;
1307 if (n == dst)
1309 rc = GPG_ERR_ELOOP;
1310 break;
1313 rc = find_child_of_parent (doc, n->children, dst);
1316 return rc;
1319 static gpg_error_t
1320 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1322 xmlNodePtr n;
1323 gpg_error_t rc = 0;
1325 for (n = node; n; n = n->parent)
1327 if (n->type != XML_ELEMENT_NODE)
1329 xmlNodePtr tmp;
1331 for (tmp = n->next; tmp; n = n->next)
1333 if (n->type != XML_ELEMENT_NODE)
1334 continue;
1336 if (tmp == dst)
1337 return GPG_ERR_ELOOP;
1341 if (n == dst)
1342 return GPG_ERR_ELOOP;
1345 return rc;
1348 void
1349 xml_free_element_list (struct element_list_s *elements)
1351 if (elements)
1353 if (elements->list)
1355 int total = slist_length (elements->list);
1356 int i;
1358 for (i = 0; i < total; i++)
1360 char *tmp = slist_nth_data (elements->list, i);
1361 xfree (tmp);
1364 slist_free (elements->list);
1367 string_free (elements->prefix, 1);
1368 xfree (elements->target);
1369 xfree (elements);
1373 /* This behaves like the LIST command with a specified path except it returns
1374 * an error.
1376 gpg_error_t
1377 xml_check_recursion (struct client_s *client, struct xml_request_s *req,
1378 int content)
1380 gpg_error_t rc;
1381 struct element_list_s *elements;
1382 char *tmp = NULL;
1383 char *path = NULL;
1384 char **dup = strv_dup (req->args);
1386 if (!dup)
1387 return GPG_ERR_ENOMEM;
1389 if (!content)
1391 tmp = dup[strv_length (dup)-1];
1392 dup[strv_length (dup)-1] = NULL;
1395 elements = xcalloc (1, sizeof (struct element_list_s));
1396 if (!elements)
1398 rc = GPG_ERR_ENOMEM;
1399 goto fail;
1402 path = strv_join ("\t", dup);
1403 if (!path)
1405 rc = GPG_ERR_ENOMEM;
1406 goto fail;
1409 elements->flags |= XML_LIST_CHECK;
1410 elements->prefix = string_new (NULL);
1411 if (!elements->prefix)
1413 rc = GPG_ERR_ENOMEM;
1414 goto fail;
1417 rc = xml_create_path_list (client, req->doc, xmlDocGetRootElement (req->doc),
1418 elements, path, 0);
1420 fail:
1421 xfree (tmp);
1422 xml_free_element_list (elements);
1423 strv_free (dup);
1424 xfree (path);
1425 return rc;
1428 gpg_error_t
1429 xml_validate_target (struct client_s *client, xmlDocPtr doc, const char *src,
1430 xmlNodePtr dst)
1432 gpg_error_t rc;
1433 xmlNodePtr src_node;
1434 char **src_req = NULL;
1436 src_node = xml_resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
1437 if (rc)
1438 goto fail;
1440 client->flags |= FLAG_ACL_IGNORE;
1441 /* A destination element is a child of the source element. */
1442 rc = find_child_of_parent (doc, src_node->children, dst);
1443 if (rc)
1444 goto fail;
1446 /* The destination element is a parent of the source element. */
1447 rc = find_parent_of_child (doc, src_node->parent, dst);
1448 if (rc)
1449 goto fail;
1451 /* A destination child element contains a target to the source element. */
1452 if (dst)
1453 rc = find_child_to_target (client, doc,
1454 dst->children ? dst->children : dst, dst, 0, 0);
1455 if (rc)
1456 goto fail;
1458 fail:
1459 strv_free (src_req);
1460 client->flags &= ~(FLAG_ACL_IGNORE | FLAG_ACL_ERROR);
1461 return rc;
1464 /* The owner of the element is the first user listed in the _acl attribute
1465 * list. acl_check() should be called before calling this function. An empty
1466 * ACL is an error if the client is not an invoking_user.
1468 gpg_error_t
1469 xml_is_element_owner (struct client_s *client, xmlNodePtr n)
1471 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
1472 char **users;
1473 gpg_error_t rc = GPG_ERR_EACCES;
1475 if (!acl || !*acl)
1477 xmlFree (acl);
1478 return peer_is_invoker (client);
1481 users = str_split((char *)acl, ",", 0);
1482 if (users && *users)
1484 char *user;
1486 #ifdef WITH_GNUTLS
1487 if (client->thd->remote)
1488 user = str_asprintf ("#%s", client->thd->tls->fp);
1489 else
1490 user = get_username (client->thd->peer->uid);
1491 #else
1492 user = get_username (client->thd->peer->uid);
1493 #endif
1495 if (*user == '#')
1496 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
1497 else
1498 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
1500 if (rc)
1501 rc = peer_is_invoker (client);
1503 xfree (user);
1506 xmlFree (acl);
1507 strv_free (users);
1508 return rc;
1511 /* Find elements by matching element names in req->args starting at 'node'.
1512 * Returns the node of the final element in req->args on success or NULL on
1513 * failure and sets 'rc' to the error code. Some commands may need special
1514 * handling and will return the node of the previous found element.
1516 xmlNodePtr
1517 xml_find_elements (struct client_s *client, struct xml_request_s *req,
1518 xmlNodePtr node, gpg_error_t *rc)
1520 xmlNodePtr n, last;
1521 char **p = req->args;
1523 *rc = 0;
1524 req->depth++;
1526 if (max_recursion_depth >= 1 && req->depth > max_recursion_depth)
1528 req->depth--;
1529 *rc = GPG_ERR_ELOOP;
1530 return NULL;
1533 /* Beginning of a command/root element (<pwmd>). */
1534 if (node == xmlDocGetRootElement (req->doc))
1536 if (!node->children) // Empty tree
1538 if (req->cmd == XML_CMD_STORE)
1539 return xml_create_element_path (client, req, node, req->args, rc);
1541 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1542 req->depth--;
1543 return NULL;
1546 node = node->children; // Start searching at the first child of the root
1549 for (last = n = node, p = req->args; *p; p++)
1551 xmlNodePtr tmp = NULL;
1552 struct element_list_s *elements = NULL;
1554 // FIXME should not be reached in this function?
1555 if (!*(*p))
1557 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1558 req->depth--;
1559 return NULL;
1562 n = xml_find_element (client, n, *p, NULL, rc);
1563 if (*rc)
1565 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND && *rc != GPG_ERR_EACCES)
1567 req->depth--;
1568 return NULL;
1571 if (*rc == GPG_ERR_EACCES
1572 && (req->cmd == XML_CMD_ATTR_LIST || req->cmd == XML_CMD_ATTR
1573 || req->cmd == XML_CMD_ATTR_EXPIRE))
1575 req->depth--;
1576 if (*(p+1))
1577 return NULL;
1579 *rc = 0;
1580 return n;
1583 /* Fixes ATTR LIST when an element does not exist and the parent
1584 * denies access to children. Fixes leaking information about the
1585 * current elements children. */
1586 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND && last != n && last != node)
1588 gpg_error_t trc = acl_check (client, last);
1589 if (trc)
1590 *rc = trc;
1593 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND)
1595 if (req->cmd == XML_CMD_STORE || req->cmd == XML_CMD_ATTR_TARGET)
1597 *rc = 0;
1598 n = xml_create_element_path (client, req,
1599 *p == *req->args
1600 && node->parent == xmlDocGetRootElement (req->doc)
1601 ? node->parent : last, p, rc);
1602 req->depth--;
1603 return n;
1607 if (req->cmd != XML_CMD_LIST)
1609 req->depth--;
1610 return NULL;
1613 // Fall through to let LIST flags be appended.
1616 last = n;
1618 /* Follow a "target" attribute for each one found in each element. */
1619 xmlChar *target = xml_attribute_value (n, (xmlChar *) "target");
1620 if (!target || !*target)
1622 xmlFree (target);
1624 if (*rc)
1626 req->depth--;
1627 return NULL;
1630 /* This is the final element in req->args. Done. */
1631 if (!*(p+1))
1633 req->depth--;
1634 return n;
1637 n = n->children;
1638 continue;
1641 if (req->cmd == XML_CMD_REALPATH)
1643 n = do_realpath (client, req, n, p+1, target, rc);
1644 xmlFree (target);
1645 req->depth--;
1646 return n;
1648 else if (req->cmd == XML_CMD_DELETE || req->cmd == XML_CMD_RENAME
1649 || req->cmd == XML_CMD_MOVE || req->cmd == XML_CMD_ATTR
1650 || req->cmd == XML_CMD_ATTR_TARGET
1651 || req->cmd == XML_CMD_ATTR_LIST)
1653 /* No more elements to resolve. Return the node with the target. */
1654 if (!*(p+1))
1656 xmlFree (target);
1657 req->depth--;
1658 return n;
1661 else if (req->cmd == XML_CMD_LIST)
1663 elements = req->data;
1664 if (elements && !(elements->flags & XML_LIST_CHILD_TARGET))
1666 /* No further elements. Use this target in the list flags. */
1667 if (!*(p+1))
1668 elements->flags |= XML_LIST_HAS_TARGET;
1669 else
1671 /* Prevent replacing any following target value with the
1672 * current target value. */
1673 req->data = NULL;
1676 else if (!elements)
1678 struct element_list_s *e = xcalloc (1, sizeof (struct element_list_s));
1680 e->target = str_dup ((char *)target);
1681 e->flags |= XML_LIST_CHILD_TARGET;
1683 if (!*(p+1))
1684 e->flags |= XML_LIST_HAS_TARGET;
1686 req->data = elements = e;
1689 *rc = xml_validate_target (client, req->doc, (char *)target, n);
1690 if (*rc)
1691 goto update_target;
1694 /* Create a new path based on the value of the current "target"
1695 * attribute. */
1696 char **nargs = str_split ((char *)target, "\t", 0);
1697 if (!nargs)
1699 xmlFree (target);
1700 *rc = GPG_ERR_INV_VALUE;
1701 req->data = req->cmd == XML_CMD_LIST ? elements : req->data;
1702 req->depth--;
1703 return NULL;
1706 /* Append the remaining elements to the target attributes path. */
1707 char **nnargs = strv_catv (nargs, p+1);
1708 strv_free (nargs);
1709 char **orig = req->args;
1710 req->args = nnargs;
1711 tmp = xml_find_elements (client, req, xmlDocGetRootElement (req->doc),
1712 rc);
1713 strv_free (nnargs);
1714 req->args = orig;
1716 update_target:
1717 if (req->cmd == XML_CMD_LIST && elements)
1719 /* A child node contained a target. Use this value rather than the
1720 * current target value as the target value for the list flag. */
1721 if (req->data && req->data != elements)
1723 struct element_list_s *e = req->data;
1725 xmlFree (target);
1726 target = xmlStrdup ((xmlChar *)e->target);
1727 xfree (e->target);
1729 if ((e->flags & XML_LIST_HAS_TARGET))
1730 elements->flags |= XML_LIST_HAS_TARGET;
1732 xfree (e);
1735 req->data = elements;
1736 if (req->data)
1738 if (!(elements->flags & XML_LIST_TARGET_ERROR))
1740 xfree (elements->target);
1741 elements->target = NULL;
1743 /* Restore the original target flag. */
1744 if ((elements->flags & XML_LIST_HAS_TARGET))
1745 elements->target = str_dup ((char *)target);
1750 xmlFree (target);
1751 req->depth--;
1752 return *rc ? NULL : tmp;
1755 req->depth--;
1756 return n;
1759 gpg_error_t
1760 xml_new_request (struct client_s *client, const char *line, xml_command_t cmd,
1761 struct xml_request_s **result)
1763 struct xml_request_s *req;
1764 char **pp = str_split ((char *) line, "\t", 0);
1766 if (!pp || !*pp)
1768 strv_free (pp);
1769 return GPG_ERR_SYNTAX;
1772 req = xcalloc (1, sizeof (struct xml_request_s));
1773 if (!req)
1775 strv_free (pp);
1776 return GPG_ERR_ENOMEM;
1779 req->cmd = cmd;
1780 req->args = pp;
1781 req->doc = client ? client->doc : NULL;
1782 *result = req;
1783 return 0;
1786 void
1787 xml_free_request (struct xml_request_s *r)
1789 if (!r)
1790 return;
1792 strv_free (r->args);
1793 xfree (r);
1797 xml_reserved_attribute (const char *name)
1799 int i;
1801 for (i = 0; reserved_attributes[i]; i++)
1803 if (!strcmp (name, reserved_attributes[i]))
1804 return 1;
1807 return 0;