Remove non-reserved attributes when setting "target".
[pwmd.git] / src / xml.c
blob059a3cd3f78b00a46a657b6f2f4ea91b2b945415
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 static void
572 remove_non_reserved_attributes (xmlNodePtr n)
574 xmlAttrPtr a;
576 for (a = n->properties; a; a = a->next)
578 if (xml_reserved_attribute ((char *)a->name))
579 continue;
581 (void)xml_delete_attribute (NULL, n, a->name);
585 gpg_error_t
586 xml_add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
587 const char *value)
589 char *buf;
590 gpg_error_t rc = 0;
591 int is_target = 0;
593 if (client && name && !strcmp (name, "target"))
595 rc = xml_is_element_owner (client, node);
596 if (rc)
597 return rc;
599 is_target = 1;
601 else if (name && !strcmp (name, "expire"))
603 char *p;
604 time_t e;
606 if (!value || !*value)
607 return GPG_ERR_INV_VALUE;
609 errno = 0;
610 e = strtoul (value, &p, 10);
611 if (errno || *p || e == ULONG_MAX || *value == '-')
612 return GPG_ERR_INV_VALUE;
615 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
616 return GPG_ERR_BAD_DATA;
618 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
620 xmlChar *acl = xml_attribute_value (node, (xmlChar *) "_acl");
622 if (!acl)
624 char *user = create_acl_user (client);
626 if (user)
628 rc = xml_add_attribute (client, node, (char *) "_acl", user);
629 xfree (user);
632 return rc;
635 xmlFree (acl);
638 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
639 return 0;
641 if (is_target)
642 remove_non_reserved_attributes (node);
644 buf = str_asprintf ("%lu", time (NULL));
645 rc = xml_add_attribute (client, node, "_mtime", buf);
646 xfree (buf);
647 return rc;
650 static gpg_error_t
651 append_path_to_list (struct client_s *client, struct element_list_s *elements,
652 const char *path, gpg_error_t rc)
654 struct slist_s *l;
655 struct string_s *line;
657 line = string_new (NULL);
658 if (!line)
659 return GPG_ERR_ENOMEM;
661 if (rc == GPG_ERR_ELOOP)
662 string_append (line, "O");
663 else if (rc == GPG_ERR_EACCES)
664 string_append (line, "P");
665 else if (rc)
666 string_append (line, "E");
668 if (rc || elements->target)
669 string_prepend (line, " ");
671 if ((!rc || rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
672 || rc == GPG_ERR_ELEMENT_NOT_FOUND) && elements->target)
673 string_append_printf (line, "%sT %s",
674 (!rc && elements->flags & XML_LIST_FLAG_CHILDREN) ? "+" : "",
675 elements->target);
676 else if (!rc && (elements->flags & XML_LIST_FLAG_CHILDREN))
677 string_prepend (line, " +");
679 if (elements->prefix && elements->prefix->str)
680 string_prepend (line, elements->prefix->str);
681 else
682 string_prepend (line, path);
684 l = slist_append (elements->list, line->str);
685 if (l)
687 elements->list = l;
688 if (!(elements->flags & XML_LIST_CHECK))
689 rc = 0;
691 else
692 rc = GPG_ERR_ENOMEM;
694 string_free (line, 0);
695 return rc;
698 /* Removes the final element from the element prefix. */
699 static void
700 pop_element_prefix (struct element_list_s *elements)
702 char *p = strrchr (elements->prefix->str, '\t');
704 if (p)
705 string_truncate (elements->prefix,
706 elements->prefix->len - strlen (p));
709 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
710 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
713 * From the element path 'path', find sub-nodes and append them to the list.
715 gpg_error_t
716 xml_create_path_list (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
717 struct element_list_s *elements, char *path,
718 gpg_error_t rc)
720 xmlNodePtr n = NULL;
721 struct xml_request_s *req = NULL;
722 gpg_error_t trc = rc;
723 char *target_orig;
725 target_orig = rc && elements->target ? str_dup (elements->target) : NULL;
726 rc = xml_new_request (client, path, XML_CMD_LIST, &req);
727 if (rc)
729 xfree (target_orig);
730 return rc;
733 req->data = elements;
734 n = xml_find_elements (client, req,
735 node ? node : xmlDocGetRootElement (doc), &rc);
736 if (!rc)
737 elements->flags |=
738 find_element_node (n->children) ? XML_LIST_FLAG_CHILDREN : 0;
740 if (!rc && trc)
742 xfree (elements->target);
743 elements->target = target_orig;
744 elements->flags = 0;
745 elements->flags |= XML_LIST_HAS_TARGET;
747 else
748 xfree (target_orig);
750 rc = append_path_to_list (client, elements, path, trc ? trc : rc);
751 xmlFree (elements->target);
752 elements->target = NULL;
754 if (rc || trc || (elements->flags & XML_LIST_CHECK)
755 || (!elements->recurse && elements->depth) || elements->root_only)
757 xml_free_request (req);
758 return rc;
761 elements->flags = 0;
763 if (!rc && n && n->children)
765 for (n = n->children; n; n = n->next)
767 xmlChar *target = NULL;
768 xmlNodePtr tmp = NULL;
769 xmlChar *name;
770 struct string_s *newpath;
772 if (n->type != XML_ELEMENT_NODE)
773 continue;
775 name = xml_attribute_value (n, (xmlChar *) "_name");
776 if (!name)
777 continue;
779 newpath = string_new (NULL);
780 if (!newpath)
782 xmlFree (name);
783 rc = GPG_ERR_ENOMEM;
784 goto fail;
787 target = xml_attribute_value (n, (xmlChar *) "target");
788 if (target)
790 rc = xml_validate_target (client, req->doc, (char *)target, n);
791 elements->target = (char *)target;
792 elements->flags |= rc ? XML_LIST_TARGET_ERROR : 0;
794 else
795 tmp = n;
797 if (RESUMABLE_ERROR (rc))
799 struct string_s *s;
801 /* If there is a target for this node then resolve the full path
802 * starting at the document root. Otherwise, resolve the next
803 * element starting from the child node of the current node. In
804 * either case, append the current element in the element path to
805 * the prefix of the list string.
807 if (target)
809 string_truncate (newpath, 0);
810 s = string_append_printf (newpath, "%s", (char *)target);
812 else
813 s = string_append (newpath, (char *)name);
815 if (!s)
817 xmlFree (name);
818 string_free (newpath, 1);
819 rc = GPG_ERR_ENOMEM;
820 goto fail;
823 newpath = s;
824 if (!elements->depth)
826 /* There may be a single remaining element in the prefix left
827 * over from the previous truncation (see below). It is safe
828 * to truncate it here since depth == 0. */
829 string_truncate (elements->prefix, 0);
830 s = string_append_printf (elements->prefix, "%s\t%s",
831 path, name);
833 else
834 s = string_append_printf (elements->prefix, "\t%s", name);
836 if (!s)
838 xmlFree (name);
839 string_free (newpath, 1);
840 rc = GPG_ERR_ENOMEM;
841 goto fail;
844 elements->prefix = s;
845 elements->depth++;
846 rc = xml_create_path_list (client, doc, target ? NULL : tmp,
847 elements, newpath->str, rc);
848 elements->depth--;
849 if (!rc)
850 pop_element_prefix (elements);
853 string_free (newpath, 1);
854 xmlFree (name);
855 if (rc)
856 break;
860 fail:
861 xml_free_request (req);
862 return rc;
865 gpg_error_t
866 xml_recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
867 xmlNodeSetPtr nodes, xmlChar * value,
868 xmlBufferPtr * result, int cmd, const xmlChar * attr)
870 int i = value ? nodes->nodeNr - 1 : 0;
871 xmlBufferPtr buf;
873 buf = xmlBufferCreate ();
875 if (!buf)
876 return GPG_ERR_ENOMEM;
878 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
880 xmlNodePtr n = nodes->nodeTab[i];
881 gpg_error_t rc;
883 if (!n)
884 continue;
886 if (!value && !attr)
888 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
890 *result = buf;
891 return GPG_ERR_BAD_DATA;
894 continue;
897 if (!attr)
899 xmlNodeSetContent (n, value);
900 rc = xml_update_element_mtime (client, n);
902 if (rc)
903 return rc;
905 else
907 if (!cmd)
908 rc = xml_add_attribute (client, n, (char *) attr, (char *) value);
909 else
910 rc = xml_delete_attribute (client, n, attr);
912 if (rc)
913 return rc;
917 *result = buf;
918 return 0;
921 gpg_error_t
922 xml_delete_attribute (struct client_s *client, xmlNodePtr n,
923 const xmlChar *name)
925 xmlAttrPtr a;
926 gpg_error_t rc = 0;
928 if ((a = xmlHasProp (n, name)) == NULL)
929 return GPG_ERR_NOT_FOUND;
931 if (xmlRemoveProp (a) == -1)
932 return GPG_ERR_BAD_DATA;
934 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
936 char *user = create_acl_user (client);
938 rc = xml_add_attribute (client, n, (char *) "_acl", user);
939 xfree (user);
941 if (rc)
942 return rc;
945 return xml_update_element_mtime (client, n);
948 gpg_error_t
949 xml_validate_import (struct client_s *client, xmlNodePtr node)
951 gpg_error_t rc = 0;
953 if (!node)
954 return 0;
956 for (xmlNodePtr n = node; n; n = n->next)
958 if (n->type == XML_ELEMENT_NODE)
960 if (xmlStrEqual (n->name, (xmlChar *) "element"))
962 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
964 if (!a)
966 xmlChar *t = xmlGetNodePath (n);
968 log_write (_("Missing attribute '_name' at %s."), t);
969 xmlFree (t);
970 return GPG_ERR_INV_VALUE;
973 if (!xml_valid_element (a))
975 xmlChar *t = xmlGetNodePath (n);
977 log_write (_("'%s' is not a valid element name at %s."), a,
979 xmlFree (a);
980 xmlFree (t);
981 return GPG_ERR_INV_VALUE;
984 xmlFree (a);
985 a = xmlGetProp (n, (xmlChar *) "_ctime");
986 if (!a)
987 attr_ctime (client, n);
989 xmlFree (a);
990 a = xmlGetProp (n, (xmlChar *) "_mtime");
991 if (!a)
992 xml_update_element_mtime (client, n);
993 xmlFree (a);
995 else
997 xmlChar *t = xmlGetNodePath (n);
999 // FIXME: unlink unknown node.
1000 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1001 n->name, t);
1002 xmlFree (t);
1003 continue;
1007 if (n->children)
1009 rc = xml_validate_import (client, n->children);
1010 if (rc)
1011 return rc;
1015 return rc;
1018 gpg_error_t
1019 xml_update_element_mtime (struct client_s *client, xmlNodePtr n)
1021 return xml_add_attribute (client, n, NULL, NULL);
1024 gpg_error_t
1025 xml_unlink_node (struct client_s *client, xmlNodePtr n)
1027 gpg_error_t rc = 0;
1029 if (!n)
1030 return rc;
1032 if (n->parent)
1033 rc = xml_update_element_mtime (client, n->parent);
1035 xmlUnlinkNode (n);
1036 xmlFreeNodeList (n);
1037 return rc;
1040 gpg_error_t
1041 xml_parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1043 xmlDocPtr doc;
1045 xmlResetLastError ();
1046 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1047 if (!doc && xmlGetLastError ())
1048 return GPG_ERR_BAD_DATA;
1050 *result = doc;
1051 return !doc ? GPG_ERR_ENOMEM : 0;
1054 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1055 * target. 'path' is any remaining elements in the element path after this
1056 * element 'node' as passed to xml_find_elements() or the initial command. This
1057 * function may be recursive as it calls xml_find_elements().
1059 static xmlNodePtr
1060 do_realpath (struct client_s *client, struct xml_request_s *req,
1061 xmlNodePtr node, char **path, const xmlChar *target,
1062 gpg_error_t *rc) {
1063 char *line;
1064 char **result = NULL;
1065 struct xml_request_s *nreq;
1067 *rc = 0;
1069 result = str_split ((char *)target, "\t", 0);
1070 if (!result)
1072 *rc = GPG_ERR_ENOMEM;
1073 return NULL;
1076 /* Append the original path to the target path. */
1077 if (path)
1079 char **p = strv_catv (result, path);
1081 if (!p)
1083 strv_free (result);
1084 *rc = GPG_ERR_ENOMEM;
1085 return NULL;
1088 result = p;
1091 line = strv_join ("\t", result);
1092 if (!line)
1094 strv_free (result);
1095 *rc = GPG_ERR_ENOMEM;
1096 return NULL;
1099 /* To prevent overwriting any original client request flags. We are only
1100 * interested in the path here. */
1101 *rc = xml_new_request (client, line, XML_CMD_REALPATH, &nreq);
1102 if (*rc)
1104 strv_free (result);
1105 return NULL;
1108 nreq->depth = req->depth;
1109 strv_free (result);
1110 node = xml_find_elements (client, nreq, xmlDocGetRootElement (nreq->doc), rc);
1112 /* Update the original client request path with the resolved one. */
1113 if (!*rc)
1115 strv_free (req->args);
1116 req->args = nreq->args;
1117 nreq->args = NULL;
1120 xml_free_request (nreq);
1121 return node;
1124 #if 0
1125 static char *
1126 node_to_element_path (xmlNodePtr node)
1128 xmlNodePtr n;
1129 struct string_s *str = string_new ("");
1130 char *result;
1132 for (n = node; n; n = n->parent)
1134 xmlNodePtr child;
1136 for (child = n; child; child = child->next)
1138 if (child->type != XML_ELEMENT_NODE)
1139 continue;
1141 xmlChar *name = xml_attribute_value (n, (xmlChar *) "_name");
1142 if (name)
1144 str = string_prepend (str, (char *) name);
1145 xmlFree (name);
1146 name = xml_attribute_value (n, (xmlChar *) "target");
1147 if (name)
1148 str = string_prepend (str, "\t");
1149 else
1150 str = string_prepend (str, "\t!");
1151 xmlFree (name);
1153 break;
1157 str = string_erase (str, 0, 1);
1158 result = str->str;
1159 string_free (str, 0);
1160 return result;
1162 #endif
1164 /* Tests if 'path' references 'node' somewhere. */
1165 static gpg_error_t
1166 element_related (struct client_s *client, xmlDocPtr doc, const char *path,
1167 xmlNodePtr node, unsigned depth)
1169 gpg_error_t rc = GPG_ERR_NO_DATA;
1170 char **p;
1171 xmlNodePtr n = xmlDocGetRootElement (doc);
1173 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1174 return GPG_ERR_ELOOP;
1176 p = str_split (path, "\t", 0);
1177 if (!p)
1178 return GPG_ERR_ENOMEM;
1180 for (n = n->children; n && *p; p++, n = n->next)
1182 xmlNodePtr t;
1183 xmlChar *target;
1184 struct string_s *str = NULL;
1186 t = xml_find_element (client, n, *p, NULL, &rc);
1187 if (rc)
1189 rc = GPG_ERR_NO_DATA;
1190 break;
1193 if (t == node)
1195 rc = 0;
1196 break;
1199 target = xml_attribute_value (t, (xmlChar *)"target");
1200 if (!target)
1201 continue;
1203 str = string_new ((char *)target);
1204 xmlFree (target);
1205 if (!str)
1207 rc = GPG_ERR_ENOMEM;
1208 break;
1211 if (*(p+1))
1213 while (*++p)
1215 struct string_s *tmp;
1217 tmp = string_append_printf (str, "\t%s", *p);
1218 if (!tmp)
1220 string_free (str, 1);
1221 strv_free (p);
1222 return GPG_ERR_ENOMEM;
1225 str = tmp;
1229 rc = element_related (client, doc, str->str, n->children, ++depth);
1230 if (rc == GPG_ERR_ELOOP)
1231 rc = GPG_ERR_NO_DATA;
1233 string_free(str, 1);
1234 break;
1237 strv_free (p);
1238 return rc;
1242 * Recurse the element tree beginning at 'node' and find elements who point
1243 * back to 'dst'. Also follows target attributes.
1245 static gpg_error_t
1246 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1247 xmlNodePtr dst, unsigned depth, int is_target)
1249 xmlNodePtr n;
1250 gpg_error_t rc = 0;
1252 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1253 return node == dst ? GPG_ERR_ELOOP : 0;
1255 for (n = node; n; n = n->next)
1257 xmlChar *target;
1259 if (n->type != XML_ELEMENT_NODE)
1260 continue;
1262 if (n == dst && depth)
1263 return GPG_ERR_ELOOP;
1265 target = xml_attribute_value (n, (xmlChar *) "target");
1266 if (target)
1268 xmlNodePtr tmp;
1269 char **result = NULL;
1271 tmp = xml_resolve_path (client, doc, target, &result, &rc);
1272 strv_free (result);
1273 if (!rc)
1275 rc = find_child_to_target (client, doc, tmp, dst, ++depth, 1);
1276 depth--;
1278 else if (rc == GPG_ERR_ELOOP)
1280 gpg_error_t trc = element_related (client, doc, (char *)target,
1281 dst, 0);
1283 if (trc && trc != GPG_ERR_NO_DATA)
1284 rc = trc;
1285 else if (trc == GPG_ERR_NO_DATA)
1286 rc = 0;
1289 xmlFree (target);
1291 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
1292 return rc;
1294 rc = 0;
1295 if (is_target)
1296 break;
1298 continue;
1301 if (n->children)
1303 rc = find_child_to_target (client, doc, n->children, dst, ++depth, 0);
1304 depth--;
1305 if (rc)
1306 return rc;
1309 if (is_target)
1310 break;
1313 return rc;
1316 static gpg_error_t
1317 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1319 xmlNodePtr n;
1320 gpg_error_t rc = 0;
1322 for (n = src; n; n = n->next)
1324 if (n->type != XML_ELEMENT_NODE)
1325 continue;
1327 if (n == dst)
1329 rc = GPG_ERR_ELOOP;
1330 break;
1333 rc = find_child_of_parent (doc, n->children, dst);
1336 return rc;
1339 static gpg_error_t
1340 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1342 xmlNodePtr n;
1343 gpg_error_t rc = 0;
1345 for (n = node; n; n = n->parent)
1347 if (n->type != XML_ELEMENT_NODE)
1349 xmlNodePtr tmp;
1351 for (tmp = n->next; tmp; n = n->next)
1353 if (n->type != XML_ELEMENT_NODE)
1354 continue;
1356 if (tmp == dst)
1357 return GPG_ERR_ELOOP;
1361 if (n == dst)
1362 return GPG_ERR_ELOOP;
1365 return rc;
1368 void
1369 xml_free_element_list (struct element_list_s *elements)
1371 if (elements)
1373 if (elements->list)
1375 int total = slist_length (elements->list);
1376 int i;
1378 for (i = 0; i < total; i++)
1380 char *tmp = slist_nth_data (elements->list, i);
1381 xfree (tmp);
1384 slist_free (elements->list);
1387 string_free (elements->prefix, 1);
1388 xfree (elements->target);
1389 xfree (elements);
1393 /* This behaves like the LIST command with a specified path except it returns
1394 * an error.
1396 gpg_error_t
1397 xml_check_recursion (struct client_s *client, struct xml_request_s *req,
1398 int content)
1400 gpg_error_t rc;
1401 struct element_list_s *elements;
1402 char *tmp = NULL;
1403 char *path = NULL;
1404 char **dup = strv_dup (req->args);
1406 if (!dup)
1407 return GPG_ERR_ENOMEM;
1409 if (!content)
1411 tmp = dup[strv_length (dup)-1];
1412 dup[strv_length (dup)-1] = NULL;
1415 elements = xcalloc (1, sizeof (struct element_list_s));
1416 if (!elements)
1418 rc = GPG_ERR_ENOMEM;
1419 goto fail;
1422 path = strv_join ("\t", dup);
1423 if (!path)
1425 rc = GPG_ERR_ENOMEM;
1426 goto fail;
1429 elements->flags |= XML_LIST_CHECK;
1430 elements->prefix = string_new (NULL);
1431 if (!elements->prefix)
1433 rc = GPG_ERR_ENOMEM;
1434 goto fail;
1437 rc = xml_create_path_list (client, req->doc, xmlDocGetRootElement (req->doc),
1438 elements, path, 0);
1440 fail:
1441 xfree (tmp);
1442 xml_free_element_list (elements);
1443 strv_free (dup);
1444 xfree (path);
1445 return rc;
1448 gpg_error_t
1449 xml_validate_target (struct client_s *client, xmlDocPtr doc, const char *src,
1450 xmlNodePtr dst)
1452 gpg_error_t rc;
1453 xmlNodePtr src_node;
1454 char **src_req = NULL;
1456 src_node = xml_resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
1457 if (rc)
1458 goto fail;
1460 client->flags |= FLAG_ACL_IGNORE;
1461 /* A destination element is a child of the source element. */
1462 rc = find_child_of_parent (doc, src_node->children, dst);
1463 if (rc)
1464 goto fail;
1466 /* The destination element is a parent of the source element. */
1467 rc = find_parent_of_child (doc, src_node->parent, dst);
1468 if (rc)
1469 goto fail;
1471 /* A destination child element contains a target to the source element. */
1472 if (dst)
1473 rc = find_child_to_target (client, doc,
1474 dst->children ? dst->children : dst, dst, 0, 0);
1475 if (rc)
1476 goto fail;
1478 fail:
1479 strv_free (src_req);
1480 client->flags &= ~(FLAG_ACL_IGNORE | FLAG_ACL_ERROR);
1481 return rc;
1484 /* The owner of the element is the first user listed in the _acl attribute
1485 * list. acl_check() should be called before calling this function. An empty
1486 * ACL is an error if the client is not an invoking_user.
1488 gpg_error_t
1489 xml_is_element_owner (struct client_s *client, xmlNodePtr n)
1491 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
1492 char **users;
1493 gpg_error_t rc = GPG_ERR_EACCES;
1495 if (!acl || !*acl)
1497 xmlFree (acl);
1498 return peer_is_invoker (client);
1501 users = str_split((char *)acl, ",", 0);
1502 if (users && *users)
1504 char *user;
1506 #ifdef WITH_GNUTLS
1507 if (client->thd->remote)
1508 user = str_asprintf ("#%s", client->thd->tls->fp);
1509 else
1510 user = get_username (client->thd->peer->uid);
1511 #else
1512 user = get_username (client->thd->peer->uid);
1513 #endif
1515 if (*user == '#')
1516 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
1517 else
1518 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
1520 if (rc)
1521 rc = peer_is_invoker (client);
1523 xfree (user);
1526 xmlFree (acl);
1527 strv_free (users);
1528 return rc;
1531 /* Find elements by matching element names in req->args starting at 'node'.
1532 * Returns the node of the final element in req->args on success or NULL on
1533 * failure and sets 'rc' to the error code. Some commands may need special
1534 * handling and will return the node of the previous found element.
1536 xmlNodePtr
1537 xml_find_elements (struct client_s *client, struct xml_request_s *req,
1538 xmlNodePtr node, gpg_error_t *rc)
1540 xmlNodePtr n, last;
1541 char **p = req->args;
1543 *rc = 0;
1544 req->depth++;
1546 if (max_recursion_depth >= 1 && req->depth > max_recursion_depth)
1548 req->depth--;
1549 *rc = GPG_ERR_ELOOP;
1550 return NULL;
1553 /* Beginning of a command/root element (<pwmd>). */
1554 if (node == xmlDocGetRootElement (req->doc))
1556 if (!node->children) // Empty tree
1558 if (req->cmd == XML_CMD_STORE)
1559 return xml_create_element_path (client, req, node, req->args, rc);
1561 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1562 req->depth--;
1563 return NULL;
1566 node = node->children; // Start searching at the first child of the root
1569 for (last = n = node, p = req->args; *p; p++)
1571 xmlNodePtr tmp = NULL;
1572 struct element_list_s *elements = NULL;
1574 // FIXME should not be reached in this function?
1575 if (!*(*p))
1577 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1578 req->depth--;
1579 return NULL;
1582 n = xml_find_element (client, n, *p, NULL, rc);
1583 if (*rc)
1585 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND && *rc != GPG_ERR_EACCES)
1587 req->depth--;
1588 return NULL;
1591 if (*rc == GPG_ERR_EACCES
1592 && (req->cmd == XML_CMD_ATTR_LIST || req->cmd == XML_CMD_ATTR
1593 || req->cmd == XML_CMD_ATTR_EXPIRE))
1595 req->depth--;
1596 if (*(p+1))
1597 return NULL;
1599 *rc = 0;
1600 return n;
1603 /* Fixes ATTR LIST when an element does not exist and the parent
1604 * denies access to children. Fixes leaking information about the
1605 * current elements children. */
1606 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND && last != n && last != node)
1608 gpg_error_t trc = acl_check (client, last);
1609 if (trc)
1610 *rc = trc;
1613 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND)
1615 if (req->cmd == XML_CMD_STORE || req->cmd == XML_CMD_ATTR_TARGET)
1617 *rc = 0;
1618 n = xml_create_element_path (client, req,
1619 *p == *req->args
1620 && node->parent == xmlDocGetRootElement (req->doc)
1621 ? node->parent : last, p, rc);
1622 req->depth--;
1623 return n;
1627 if (req->cmd != XML_CMD_LIST)
1629 req->depth--;
1630 return NULL;
1633 // Fall through to let LIST flags be appended.
1636 last = n;
1638 /* Follow a "target" attribute for each one found in each element. */
1639 xmlChar *target = xml_attribute_value (n, (xmlChar *) "target");
1640 if (!target || !*target)
1642 xmlFree (target);
1644 if (*rc)
1646 req->depth--;
1647 return NULL;
1650 /* This is the final element in req->args. Done. */
1651 if (!*(p+1))
1653 req->depth--;
1654 return n;
1657 n = n->children;
1658 continue;
1661 if (req->cmd == XML_CMD_REALPATH)
1663 n = do_realpath (client, req, n, p+1, target, rc);
1664 xmlFree (target);
1665 req->depth--;
1666 return n;
1668 else if (req->cmd == XML_CMD_DELETE || req->cmd == XML_CMD_RENAME
1669 || req->cmd == XML_CMD_MOVE || req->cmd == XML_CMD_ATTR
1670 || req->cmd == XML_CMD_ATTR_TARGET
1671 || req->cmd == XML_CMD_ATTR_LIST)
1673 /* No more elements to resolve. Return the node with the target. */
1674 if (!*(p+1))
1676 xmlFree (target);
1677 req->depth--;
1678 return n;
1681 else if (req->cmd == XML_CMD_LIST)
1683 elements = req->data;
1684 if (elements && !(elements->flags & XML_LIST_CHILD_TARGET))
1686 /* No further elements. Use this target in the list flags. */
1687 if (!*(p+1))
1688 elements->flags |= XML_LIST_HAS_TARGET;
1689 else
1691 /* Prevent replacing any following target value with the
1692 * current target value. */
1693 req->data = NULL;
1696 else if (!elements)
1698 struct element_list_s *e = xcalloc (1, sizeof (struct element_list_s));
1700 e->target = str_dup ((char *)target);
1701 e->flags |= XML_LIST_CHILD_TARGET;
1703 if (!*(p+1))
1704 e->flags |= XML_LIST_HAS_TARGET;
1706 req->data = elements = e;
1709 *rc = xml_validate_target (client, req->doc, (char *)target, n);
1710 if (*rc)
1711 goto update_target;
1714 /* Create a new path based on the value of the current "target"
1715 * attribute. */
1716 char **nargs = str_split ((char *)target, "\t", 0);
1717 if (!nargs)
1719 xmlFree (target);
1720 *rc = GPG_ERR_INV_VALUE;
1721 req->data = req->cmd == XML_CMD_LIST ? elements : req->data;
1722 req->depth--;
1723 return NULL;
1726 /* Append the remaining elements to the target attributes path. */
1727 char **nnargs = strv_catv (nargs, p+1);
1728 strv_free (nargs);
1729 char **orig = req->args;
1730 req->args = nnargs;
1731 tmp = xml_find_elements (client, req, xmlDocGetRootElement (req->doc),
1732 rc);
1733 strv_free (nnargs);
1734 req->args = orig;
1736 update_target:
1737 if (req->cmd == XML_CMD_LIST && elements)
1739 /* A child node contained a target. Use this value rather than the
1740 * current target value as the target value for the list flag. */
1741 if (req->data && req->data != elements)
1743 struct element_list_s *e = req->data;
1745 xmlFree (target);
1746 target = xmlStrdup ((xmlChar *)e->target);
1747 xfree (e->target);
1749 if ((e->flags & XML_LIST_HAS_TARGET))
1750 elements->flags |= XML_LIST_HAS_TARGET;
1752 xfree (e);
1755 req->data = elements;
1756 if (req->data)
1758 if (!(elements->flags & XML_LIST_TARGET_ERROR))
1760 xfree (elements->target);
1761 elements->target = NULL;
1763 /* Restore the original target flag. */
1764 if ((elements->flags & XML_LIST_HAS_TARGET))
1765 elements->target = str_dup ((char *)target);
1770 xmlFree (target);
1771 req->depth--;
1772 return *rc ? NULL : tmp;
1775 req->depth--;
1776 return n;
1779 gpg_error_t
1780 xml_new_request (struct client_s *client, const char *line, xml_command_t cmd,
1781 struct xml_request_s **result)
1783 struct xml_request_s *req;
1784 char **pp = str_split ((char *) line, "\t", 0);
1786 if (!pp || !*pp)
1788 strv_free (pp);
1789 return GPG_ERR_SYNTAX;
1792 req = xcalloc (1, sizeof (struct xml_request_s));
1793 if (!req)
1795 strv_free (pp);
1796 return GPG_ERR_ENOMEM;
1799 req->cmd = cmd;
1800 req->args = pp;
1801 req->doc = client ? client->doc : NULL;
1802 *result = req;
1803 return 0;
1806 void
1807 xml_free_request (struct xml_request_s *r)
1809 if (!r)
1810 return;
1812 strv_free (r->args);
1813 xfree (r);
1817 xml_reserved_attribute (const char *name)
1819 int i;
1821 for (i = 0; reserved_attributes[i]; i++)
1823 if (!strcmp (name, reserved_attributes[i]))
1824 return 1;
1827 return 0;