Fix EXPIRE status message.
[pwmd.git] / src / xml.c
blob4e96f5fdc0d45d631fe9a8176a7910cfab094571
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
3 2016, 2017
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"
50 #include "acl.h"
52 #define XML_LIST_FLAG_CHILDREN 0x0001
53 #define XML_LIST_HAS_TARGET 0x0002
54 #define XML_LIST_CHILD_TARGET 0x0004
55 #define XML_LIST_TARGET_ERROR 0x0008
56 #define XML_LIST_CHECK 0x0010
58 const char *reserved_attributes[] = {
59 "_name", "_mtime", "_ctime", "_acl", "target",
60 NULL
63 void log_write (const char *fmt, ...);
65 int
66 xml_valid_attribute_value (const char *str)
68 const char *p = str;
70 if (!p || !*p)
71 return 1;
73 while (*p)
75 if (*p++ == '\n')
76 return 0;
79 return 1;
82 int
83 xml_valid_attribute (const char *str)
85 wchar_t *wc;
86 size_t len, c;
87 int ret = xml_valid_element ((xmlChar *)str);
89 if (!ret)
90 return ret;
92 wc = str_to_wchar ((const char *)str);
93 if (!wc)
94 return 0;
96 len = wcslen (wc);
97 for (c = 0; c < len; c++)
99 switch (wc[c])
101 case '-':
102 case '.':
103 case '0' ... '9':
104 case 0xB7:
105 case 0x0300 ... 0x036F:
106 case 0x203F ... 0x2040:
107 if (!c)
109 xfree (wc);
110 return 0;
112 case ':': break;
113 case '_': break;
114 case 'A' ... 'Z': break;
115 case 'a' ... 'z': break;
116 case 0xC0 ... 0xD6: break;
117 case 0xD8 ... 0xF6: break;
118 case 0xF8 ... 0x2FF: break;
119 case 0x370 ... 0x37D: break;
120 case 0x37F ... 0x1FFF: break;
121 case 0x200C ... 0x200D: break;
122 case 0x2070 ... 0x218F: break;
123 case 0x2C00 ... 0x2FEF: break;
124 case 0x3001 ... 0xD7FF: break;
125 case 0xF900 ... 0xFDCF: break;
126 case 0xFDF0 ... 0xFFFD: break;
127 case 0x10000 ... 0xEFFFF: break;
128 default:
129 xfree (wc);
130 return 0;
134 xfree (wc);
135 return 1;
139 xml_valid_element (xmlChar *str)
141 wchar_t *wc;
142 size_t len, c;
144 if (!str || !*str)
145 return 0;
147 wc = str_to_wchar ((const char *)str);
148 if (!wc)
149 return 0;
151 len = wcslen (wc);
152 for (c = 0; c < len; c++)
154 if (iswspace(wc[c]))
156 xfree (wc);
157 return 0;
161 xfree (wc);
162 return 1;
166 xml_valid_element_path (char **path, int with_content)
168 char **dup = NULL, **p;
170 if (!path || !*path)
171 return 0;
173 /* Save some memory by not duplicating the element content. */
174 if (with_content)
176 int i, t = strv_length (path);
178 for (i = 0; i < t - 1; i++)
180 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
182 if (!tmp)
184 strv_free (dup);
185 return 0;
188 dup = tmp;
189 dup[i] = str_dup (path[i]);
190 dup[i + 1] = NULL;
193 else
194 dup = strv_dup (path);
196 if (!dup)
197 return 0;
199 for (p = dup; *p && *(*p); p++)
201 if (!xml_valid_element ((xmlChar *) * p))
203 strv_free (dup);
204 return 0;
208 strv_free (dup);
209 return 1;
212 static gpg_error_t
213 attr_ctime (struct client_s *client, xmlNodePtr n)
215 char *buf = str_asprintf ("%li", time (NULL));
216 gpg_error_t rc;
218 if (!buf)
219 return GPG_ERR_ENOMEM;
221 rc = xml_add_attribute (client, n, "_ctime", buf);
222 xfree (buf);
223 return rc;
226 static gpg_error_t
227 acl_check (struct client_s *client, xmlNodePtr n)
229 gpg_error_t rc = GPG_ERR_EACCES;
230 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
231 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
232 char **p;
233 int allowed = 0;
235 if (!acl || !*acl || !users || !*users)
237 xmlFree (acl);
238 strv_free(users);
239 return peer_is_invoker(client);
242 if (!peer_is_invoker(client))
244 xmlFree (acl);
245 strv_free(users);
246 return 0;
249 for (p = users; p && *p; p++)
251 #ifdef WITH_GNUTLS
252 rc = acl_check_common (client, *p,
253 client->thd->remote ? 0 : client->thd->peer->uid,
254 client->thd->remote ? 0 : client->thd->peer->gid,
255 &allowed);
256 #else
257 rc = acl_check_common (client, *p, client->thd->peer->uid,
258 client->thd->peer->gid, &allowed);
259 #endif
262 xmlFree(acl);
263 strv_free(users);
265 if (rc)
266 return rc;
268 return allowed ? 0 : GPG_ERR_EACCES;
271 static char *
272 create_acl_user (struct client_s *client)
274 #ifdef WITH_GNUTLS
275 if (client->thd->remote)
276 return str_asprintf ("#%s", client->thd->tls->fp);
277 #endif
279 return get_username (client->thd->peer->uid);
282 static gpg_error_t
283 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
284 const char *name, xmlNodePtr * result)
286 xmlNodePtr n;
287 gpg_error_t rc;
289 // Allow any client to create a non-existing root element.
290 if (parent->parent->type != XML_DOCUMENT_NODE)
292 rc = acl_check(client, parent);
293 if (rc)
294 return rc;
297 n = xmlNewNode (NULL, (xmlChar *) "element");
298 if (!n)
299 return GPG_ERR_ENOMEM;
301 rc = xml_add_attribute (client, n, "_name", name);
302 if (!rc)
303 rc = attr_ctime (client, n);
305 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
306 rc = xml_is_element_owner (client, parent);
308 if (!rc)
310 xmlNodePtr p = xmlAddChild (parent, n);
311 char *user = create_acl_user (client);
313 if (result)
314 *result = p;
316 rc = xml_add_attribute(client, p, "_acl", user);
317 xfree (user);
319 else
320 xmlFreeNode (n);
322 return rc;
325 gpg_error_t
326 xml_new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
328 xmlNodePtr root = xmlDocGetRootElement (doc);
330 if (!name || !root)
331 return GPG_ERR_BAD_DATA;
333 if (!xml_valid_element ((xmlChar *) name))
334 return GPG_ERR_INV_VALUE;
336 return create_new_element (client, 0, root, name, NULL);
339 static xmlDocPtr
340 create_dtd ()
342 xmlDocPtr doc;
343 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
345 if (!wr)
346 return NULL;
348 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
349 goto fail;
351 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
352 goto fail;
354 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
355 (xmlChar *) "(element)") == -1)
356 goto fail;
358 xmlTextWriterEndDTDElement (wr);
360 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
361 (xmlChar *) "_name CDATA #REQUIRED") ==
363 goto fail;
365 xmlTextWriterEndDTDAttlist (wr);
366 xmlTextWriterEndDTD (wr);
368 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
369 goto fail;
371 xmlTextWriterEndElement (wr);
372 xmlTextWriterEndDocument (wr);
373 xmlFreeTextWriter (wr);
374 return doc;
376 fail:
377 xmlTextWriterEndDocument (wr);
378 xmlFreeTextWriter (wr);
379 xmlFreeDoc (doc);
380 return NULL;
383 xmlDocPtr
384 xml_new_document ()
386 return create_dtd ();
389 static xmlNodePtr
390 find_element_node (xmlNodePtr node)
392 xmlNodePtr n = node;
394 if (n && n->type == XML_ELEMENT_NODE)
395 return n;
397 for (n = node; n; n = n->next)
399 if (n->type == XML_ELEMENT_NODE)
400 return n;
403 return NULL;
406 xmlNodePtr
407 xml_resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
408 char ***result, gpg_error_t *rc)
410 xmlNodePtr n;
411 struct xml_request_s *req;
413 *rc = xml_new_request (client, (char *)path, XML_CMD_REALPATH, &req);
414 if (*rc)
415 return NULL;
417 n = xml_find_elements (client, req, xmlDocGetRootElement (doc), rc);
418 if (!*rc)
420 if (result)
422 *result = strv_dup (req->args);
423 if (!*result)
425 *rc = GPG_ERR_ENOMEM;
426 n = NULL;
431 xml_free_request (req);
432 return n;
435 xmlNodePtr
436 xml_find_text_node (xmlNodePtr node)
438 xmlNodePtr n = node;
440 if (n && n->type == XML_TEXT_NODE)
441 return n;
443 for (n = node; n; n = n->next)
445 if (n->type == XML_TEXT_NODE)
446 return n;
449 return NULL;
452 /* Create an element 'path' starting at 'node'. Returns the node of the final
453 * created element.
455 xmlNodePtr
456 xml_create_element_path (struct client_s *client, struct xml_request_s *req,
457 xmlNodePtr node, char **path, gpg_error_t *rc)
459 char **p;
461 if (!xml_valid_element_path (path, 0))
463 *rc = GPG_ERR_INV_VALUE;
464 return NULL;
467 /* The parent node will be an XML_ELEMENT_NODE. Otherwise we would be
468 * creating element content. */
469 if (node->type == XML_TEXT_NODE)
470 node = node->parent;
472 for (p = path; p && *p; p++)
474 xmlNodePtr n = NULL;
476 if (node != xmlDocGetRootElement (req->doc))
478 n = xml_find_element (client, node, *p, rc);
479 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
480 return NULL;
482 *rc = 0;
486 * If the found element has the same parent as the current element then
487 * they are siblings and the new element needs to be created as a child
488 * of the current element (node).
490 if (n && n->parent == node->parent)
491 n = NULL;
493 if (!n)
495 *rc = create_new_element (client, 0, node, *p, &node);
496 if (*rc)
497 return NULL;
499 else
500 node = n;
503 return node;
506 /* Find the first XML_ELEMENT_NODE whose _name attribute matches 'element'. */
507 xmlNodePtr
508 xml_find_element (struct client_s *client, xmlNodePtr node, const char *element,
509 gpg_error_t *rc)
511 xmlNodePtr n;
513 *rc = 0;
515 if (!node || !element)
517 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
518 return NULL;
521 for (n = node; n; n = n->next)
523 if (n->type != XML_ELEMENT_NODE)
524 continue;
526 xmlChar *a = xml_attribute_value (n, (xmlChar *) "_name");
527 if (a && xmlStrEqual (a, (xmlChar *) element))
529 xmlFree (a);
530 *rc = acl_check (client, n);
531 return n; // Not NULL since the node may be needed later
534 xmlFree (a);
537 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
538 return NULL;
541 xmlChar *
542 xml_attribute_value (xmlNodePtr n, xmlChar * attr)
544 xmlAttrPtr a = xmlHasProp (n, attr);
546 if (!a)
547 return NULL;
549 if (!a->children || !a->children->content)
550 return NULL;
552 return xmlGetProp (n, attr);
555 static void
556 remove_non_reserved_attributes (xmlNodePtr n)
558 xmlAttrPtr a;
560 for (a = n->properties; a; a = a->next)
562 if (xml_reserved_attribute ((char *)a->name))
563 continue;
565 (void)xml_delete_attribute (NULL, n, a->name);
569 gpg_error_t
570 xml_add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
571 const char *value)
573 char *buf;
574 gpg_error_t rc = 0;
575 int is_target = 0;
577 if (client && name && !strcmp (name, "target"))
579 rc = xml_is_element_owner (client, node);
580 if (rc)
581 return rc;
583 is_target = 1;
585 else if (name && !strcmp (name, "expire"))
587 char *p;
588 time_t e;
590 if (!value || !*value)
591 return GPG_ERR_INV_VALUE;
593 errno = 0;
594 e = strtoul (value, &p, 10);
595 if (errno || *p || e == ULONG_MAX || *value == '-')
596 return GPG_ERR_INV_VALUE;
599 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
600 return GPG_ERR_BAD_DATA;
602 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
604 xmlChar *acl = xml_attribute_value (node, (xmlChar *) "_acl");
606 if (!acl)
608 char *user = create_acl_user (client);
610 if (user)
612 rc = xml_add_attribute (client, node, (char *) "_acl", user);
613 xfree (user);
616 return rc;
619 xmlFree (acl);
622 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
623 return 0;
625 if (is_target)
626 remove_non_reserved_attributes (node);
628 buf = str_asprintf ("%lu", time (NULL));
629 rc = xml_add_attribute (client, node, "_mtime", buf);
630 xfree (buf);
631 return rc;
634 static gpg_error_t
635 append_path_to_list (struct client_s *client, struct element_list_s *elements,
636 const char *path, gpg_error_t rc)
638 struct slist_s *l;
639 struct string_s *line;
641 (void)client;
642 line = string_new (NULL);
643 if (!line)
644 return GPG_ERR_ENOMEM;
646 if (rc == GPG_ERR_ELOOP)
647 string_append (line, "O");
648 else if (rc == GPG_ERR_EACCES)
649 string_append (line, "P");
650 else if (rc)
651 string_append (line, "E");
653 if (rc || elements->target)
654 string_prepend (line, " ");
656 if ((!rc || rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
657 || rc == GPG_ERR_ELEMENT_NOT_FOUND) && elements->target)
658 string_append_printf (line, "%sT %s",
659 (!rc && elements->flags & XML_LIST_FLAG_CHILDREN) ? "+" : "",
660 elements->target);
661 else if (!rc && (elements->flags & XML_LIST_FLAG_CHILDREN))
662 string_prepend (line, " +");
664 if (elements->prefix && elements->prefix->str)
665 string_prepend (line, elements->prefix->str);
666 else
667 string_prepend (line, path);
669 l = slist_append (elements->list, line->str);
670 if (l)
672 elements->list = l;
673 if (!(elements->flags & XML_LIST_CHECK))
674 rc = 0;
676 else
677 rc = GPG_ERR_ENOMEM;
679 string_free (line, 0);
680 return rc;
683 /* Removes the final element from the element prefix. */
684 static void
685 pop_element_prefix (struct element_list_s *elements)
687 char *p = strrchr (elements->prefix->str, '\t');
689 if (p)
690 string_truncate (elements->prefix,
691 elements->prefix->len - strlen (p));
694 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
695 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
698 * From the element path 'path', find sub-nodes and append them to the list.
700 gpg_error_t
701 xml_create_path_list (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
702 struct element_list_s *elements, char *path,
703 gpg_error_t rc)
705 xmlNodePtr n = NULL;
706 struct xml_request_s *req = NULL;
707 gpg_error_t trc = rc;
708 char *target_orig;
710 target_orig = rc && elements->target ? str_dup (elements->target) : NULL;
711 rc = xml_new_request (client, path, XML_CMD_LIST, &req);
712 if (rc)
714 xfree (target_orig);
715 return rc;
718 req->data = elements;
719 n = xml_find_elements (client, req,
720 node ? node : xmlDocGetRootElement (doc), &rc);
721 if (!rc)
722 elements->flags |=
723 find_element_node (n->children) ? XML_LIST_FLAG_CHILDREN : 0;
725 if (!rc && trc)
727 xfree (elements->target);
728 elements->target = target_orig;
729 elements->flags = 0;
730 elements->flags |= XML_LIST_HAS_TARGET;
732 else
733 xfree (target_orig);
735 rc = append_path_to_list (client, elements, path, trc ? trc : rc);
736 xmlFree (elements->target);
737 elements->target = NULL;
739 if (rc || trc || (elements->flags & XML_LIST_CHECK)
740 || (!elements->recurse && elements->depth) || elements->root_only)
742 xml_free_request (req);
743 return rc;
746 elements->flags = 0;
748 if (!rc && n && n->children)
750 for (n = n->children; n; n = n->next)
752 xmlChar *target = NULL;
753 xmlNodePtr tmp = NULL;
754 xmlChar *name;
755 struct string_s *newpath;
757 if (n->type != XML_ELEMENT_NODE)
758 continue;
760 name = xml_attribute_value (n, (xmlChar *) "_name");
761 if (!name)
762 continue;
764 newpath = string_new (NULL);
765 if (!newpath)
767 xmlFree (name);
768 rc = GPG_ERR_ENOMEM;
769 goto fail;
772 target = xml_attribute_value (n, (xmlChar *) "target");
773 if (target)
775 rc = xml_validate_target (client, req->doc, (char *)target, n);
776 elements->target = (char *)target;
777 elements->flags |= rc ? XML_LIST_TARGET_ERROR : 0;
779 else
780 tmp = n;
782 if (RESUMABLE_ERROR (rc))
784 struct string_s *s;
786 /* If there is a target for this node then resolve the full path
787 * starting at the document root. Otherwise, resolve the next
788 * element starting from the child node of the current node. In
789 * either case, append the current element in the element path to
790 * the prefix of the list string.
792 if (target)
794 string_truncate (newpath, 0);
795 s = string_append_printf (newpath, "%s", (char *)target);
797 else
798 s = string_append (newpath, (char *)name);
800 if (!s)
802 xmlFree (name);
803 string_free (newpath, 1);
804 rc = GPG_ERR_ENOMEM;
805 goto fail;
808 newpath = s;
809 if (!elements->depth)
811 /* There may be a single remaining element in the prefix left
812 * over from the previous truncation (see below). It is safe
813 * to truncate it here since depth == 0. */
814 string_truncate (elements->prefix, 0);
815 s = string_append_printf (elements->prefix, "%s\t%s",
816 path, name);
818 else
819 s = string_append_printf (elements->prefix, "\t%s", name);
821 if (!s)
823 xmlFree (name);
824 string_free (newpath, 1);
825 rc = GPG_ERR_ENOMEM;
826 goto fail;
829 elements->prefix = s;
830 elements->depth++;
831 rc = xml_create_path_list (client, doc, target ? NULL : tmp,
832 elements, newpath->str, rc);
833 elements->depth--;
834 if (!rc)
835 pop_element_prefix (elements);
838 string_free (newpath, 1);
839 xmlFree (name);
840 if (rc)
841 break;
845 fail:
846 xml_free_request (req);
847 return rc;
850 gpg_error_t
851 xml_recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
852 xmlNodeSetPtr nodes, xmlChar * value,
853 xmlBufferPtr * result, int cmd, const xmlChar * attr)
855 int i = value ? nodes->nodeNr - 1 : 0;
856 xmlBufferPtr buf;
858 buf = xmlBufferCreate ();
860 if (!buf)
861 return GPG_ERR_ENOMEM;
863 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
865 xmlNodePtr n = nodes->nodeTab[i];
866 gpg_error_t rc;
868 if (!n)
869 continue;
871 if (!value && !attr)
873 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
875 *result = buf;
876 return GPG_ERR_BAD_DATA;
879 continue;
882 if (!attr)
884 xmlNodeSetContent (n, value);
885 rc = xml_update_element_mtime (client, n);
887 if (rc)
888 return rc;
890 else
892 if (!cmd)
893 rc = xml_add_attribute (client, n, (char *) attr, (char *) value);
894 else
895 rc = xml_delete_attribute (client, n, attr);
897 if (rc)
898 return rc;
902 *result = buf;
903 return 0;
906 gpg_error_t
907 xml_delete_attribute (struct client_s *client, xmlNodePtr n,
908 const xmlChar *name)
910 xmlAttrPtr a;
911 gpg_error_t rc = 0;
913 if ((a = xmlHasProp (n, name)) == NULL)
914 return GPG_ERR_NOT_FOUND;
916 if (xmlRemoveProp (a) == -1)
917 return GPG_ERR_BAD_DATA;
919 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
921 char *user = create_acl_user (client);
923 rc = xml_add_attribute (client, n, (char *) "_acl", user);
924 xfree (user);
926 if (rc)
927 return rc;
930 return xml_update_element_mtime (client, n);
933 gpg_error_t
934 xml_validate_import (struct client_s *client, xmlNodePtr node)
936 gpg_error_t rc = 0;
938 if (!node)
939 return 0;
941 for (xmlNodePtr n = node; n; n = n->next)
943 if (n->type == XML_ELEMENT_NODE)
945 if (xmlStrEqual (n->name, (xmlChar *) "element"))
947 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
949 if (!a)
951 xmlChar *t = xmlGetNodePath (n);
953 log_write (_("Missing attribute '_name' at %s."), t);
954 xmlFree (t);
955 return GPG_ERR_INV_VALUE;
958 if (!xml_valid_element (a))
960 xmlChar *t = xmlGetNodePath (n);
962 log_write (_("'%s' is not a valid element name at %s."), a,
964 xmlFree (a);
965 xmlFree (t);
966 return GPG_ERR_INV_VALUE;
969 xmlFree (a);
970 a = xmlGetProp (n, (xmlChar *) "_ctime");
971 if (!a)
972 attr_ctime (client, n);
974 xmlFree (a);
975 a = xmlGetProp (n, (xmlChar *) "_mtime");
976 if (!a)
977 xml_update_element_mtime (client, n);
978 xmlFree (a);
980 else
982 xmlChar *t = xmlGetNodePath (n);
983 xmlNodePtr tmp = n->next;
985 log_write (_("Warning: unknown element '%s' at %s. Removing."),
986 n->name, t);
987 xmlFree (t);
988 (void)xml_unlink_node (client, n);
989 return xml_validate_import (client, tmp);
993 if (n->children)
995 rc = xml_validate_import (client, n->children);
996 if (rc)
997 return rc;
1001 return rc;
1004 gpg_error_t
1005 xml_update_element_mtime (struct client_s *client, xmlNodePtr n)
1007 return xml_add_attribute (client, n, NULL, NULL);
1010 gpg_error_t
1011 xml_unlink_node (struct client_s *client, xmlNodePtr n)
1013 gpg_error_t rc = 0;
1015 if (!n)
1016 return rc;
1018 if (n->parent)
1019 rc = xml_update_element_mtime (client, n->parent);
1021 xmlUnlinkNode (n);
1022 xmlFreeNodeList (n);
1023 return rc;
1026 gpg_error_t
1027 xml_parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1029 xmlDocPtr doc;
1031 xmlResetLastError ();
1032 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1033 if (!doc && xmlGetLastError ())
1034 return GPG_ERR_BAD_DATA;
1036 *result = doc;
1037 return !doc ? GPG_ERR_ENOMEM : 0;
1040 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1041 * target. 'path' is any remaining elements in the element path after this
1042 * element 'node' as passed to xml_find_elements() or the initial command. This
1043 * function may be recursive as it calls xml_find_elements().
1045 static xmlNodePtr
1046 do_realpath (struct client_s *client, struct xml_request_s *req,
1047 xmlNodePtr node, char **path, const xmlChar *target,
1048 gpg_error_t *rc) {
1049 char *line;
1050 char **result = NULL;
1051 struct xml_request_s *nreq = NULL;
1053 *rc = 0;
1055 result = str_split ((char *)target, "\t", 0);
1056 if (!result)
1058 *rc = GPG_ERR_ENOMEM;
1059 return NULL;
1062 /* Append the original path to the target path. */
1063 if (path)
1065 char **p = strv_catv (result, path);
1067 strv_free (result);
1068 if (!p)
1070 *rc = GPG_ERR_ENOMEM;
1071 return NULL;
1074 result = p;
1077 line = strv_join ("\t", result);
1078 if (!line)
1080 strv_free (result);
1081 *rc = GPG_ERR_ENOMEM;
1082 return NULL;
1085 /* To prevent overwriting any original client request flags. We are only
1086 * interested in the path here. */
1087 *rc = xml_new_request (client, line, XML_CMD_REALPATH, &nreq);
1088 xfree (line);
1089 if (*rc)
1091 strv_free (result);
1092 return NULL;
1095 nreq->depth = req->depth;
1096 strv_free (result);
1097 node = xml_find_elements (client, nreq, xmlDocGetRootElement (nreq->doc), rc);
1099 /* Update the original client request path with the resolved one. */
1100 if (!*rc)
1102 strv_free (req->args);
1103 req->args = nreq->args;
1104 nreq->args = NULL;
1107 xml_free_request (nreq);
1108 return node;
1111 #if 0
1112 static char *
1113 node_to_element_path (xmlNodePtr node)
1115 xmlNodePtr n;
1116 struct string_s *str = string_new ("");
1117 char *result;
1119 for (n = node; n; n = n->parent)
1121 xmlNodePtr child;
1123 for (child = n; child; child = child->next)
1125 if (child->type != XML_ELEMENT_NODE)
1126 continue;
1128 xmlChar *name = xml_attribute_value (n, (xmlChar *) "_name");
1129 if (name)
1131 str = string_prepend (str, (char *) name);
1132 xmlFree (name);
1133 name = xml_attribute_value (n, (xmlChar *) "target");
1134 if (name)
1135 str = string_prepend (str, "\t");
1136 else
1137 str = string_prepend (str, "\t!");
1138 xmlFree (name);
1140 break;
1144 str = string_erase (str, 0, 1);
1145 result = str->str;
1146 string_free (str, 0);
1147 return result;
1149 #endif
1151 /* Tests if 'path' references 'node' somewhere. */
1152 static gpg_error_t
1153 element_related (struct client_s *client, xmlDocPtr doc, const char *path,
1154 xmlNodePtr node, unsigned depth)
1156 gpg_error_t rc = GPG_ERR_NO_DATA;
1157 char **p;
1158 xmlNodePtr n = xmlDocGetRootElement (doc);
1160 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1161 return GPG_ERR_ELOOP;
1163 p = str_split (path, "\t", 0);
1164 if (!p)
1165 return GPG_ERR_ENOMEM;
1167 for (n = n->children; n && *p; p++, n = n->next)
1169 xmlNodePtr t;
1170 xmlChar *target;
1171 struct string_s *str = NULL;
1173 t = xml_find_element (client, n, *p, &rc);
1174 if (rc)
1176 rc = GPG_ERR_NO_DATA;
1177 break;
1180 if (t == node)
1182 rc = 0;
1183 break;
1186 target = xml_attribute_value (t, (xmlChar *)"target");
1187 if (!target)
1188 continue;
1190 str = string_new ((char *)target);
1191 xmlFree (target);
1192 if (!str)
1194 rc = GPG_ERR_ENOMEM;
1195 break;
1198 if (*(p+1))
1200 while (*++p)
1202 struct string_s *tmp;
1204 tmp = string_append_printf (str, "\t%s", *p);
1205 if (!tmp)
1207 string_free (str, 1);
1208 strv_free (p);
1209 return GPG_ERR_ENOMEM;
1212 str = tmp;
1216 rc = element_related (client, doc, str->str, n->children, ++depth);
1217 if (rc == GPG_ERR_ELOOP)
1218 rc = GPG_ERR_NO_DATA;
1220 string_free(str, 1);
1221 break;
1224 strv_free (p);
1225 return rc;
1229 * Recurse the element tree beginning at 'node' and find elements who point
1230 * back to 'dst'. Also follows target attributes.
1232 static gpg_error_t
1233 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1234 xmlNodePtr dst, unsigned depth, int is_target)
1236 xmlNodePtr n;
1237 gpg_error_t rc = 0;
1239 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1240 return node == dst ? GPG_ERR_ELOOP : 0;
1242 for (n = node; n; n = n->next)
1244 xmlChar *target;
1246 if (n->type != XML_ELEMENT_NODE)
1247 continue;
1249 if (n == dst && depth)
1250 return GPG_ERR_ELOOP;
1252 target = xml_attribute_value (n, (xmlChar *) "target");
1253 if (target)
1255 xmlNodePtr tmp;
1256 char **result = NULL;
1258 tmp = xml_resolve_path (client, doc, target, &result, &rc);
1259 strv_free (result);
1260 if (!rc)
1262 rc = find_child_to_target (client, doc, tmp, dst, ++depth, 1);
1263 depth--;
1265 else if (rc == GPG_ERR_ELOOP)
1267 gpg_error_t trc = element_related (client, doc, (char *)target,
1268 dst, 0);
1270 if (trc && trc != GPG_ERR_NO_DATA)
1271 rc = trc;
1272 else if (trc == GPG_ERR_NO_DATA)
1273 rc = 0;
1276 xmlFree (target);
1278 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
1279 return rc;
1281 rc = 0;
1282 if (is_target)
1283 break;
1285 continue;
1288 if (n->children)
1290 rc = find_child_to_target (client, doc, n->children, dst, ++depth, 0);
1291 depth--;
1292 if (rc)
1293 return rc;
1296 if (is_target)
1297 break;
1300 return rc;
1303 static gpg_error_t
1304 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1306 xmlNodePtr n;
1307 gpg_error_t rc = 0;
1309 for (n = src; n; n = n->next)
1311 if (n->type != XML_ELEMENT_NODE)
1312 continue;
1314 if (n == dst)
1316 rc = GPG_ERR_ELOOP;
1317 break;
1320 rc = find_child_of_parent (doc, n->children, dst);
1323 return rc;
1326 static gpg_error_t
1327 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1329 xmlNodePtr n;
1330 gpg_error_t rc = 0;
1332 (void)doc;
1333 for (n = node; n; n = n->parent)
1335 if (n->type != XML_ELEMENT_NODE)
1337 xmlNodePtr tmp;
1339 for (tmp = n->next; tmp; n = n->next)
1341 if (n->type != XML_ELEMENT_NODE)
1342 continue;
1344 if (tmp == dst)
1345 return GPG_ERR_ELOOP;
1349 if (n == dst)
1350 return GPG_ERR_ELOOP;
1353 return rc;
1356 void
1357 xml_free_element_list (struct element_list_s *elements)
1359 if (elements)
1361 if (elements->list)
1363 int total = slist_length (elements->list);
1364 int i;
1366 for (i = 0; i < total; i++)
1368 char *tmp = slist_nth_data (elements->list, i);
1369 xfree (tmp);
1372 slist_free (elements->list);
1375 string_free (elements->prefix, 1);
1376 xfree (elements->target);
1377 xfree (elements);
1381 /* This behaves like the LIST command with a specified path except it returns
1382 * an error.
1384 gpg_error_t
1385 xml_check_recursion (struct client_s *client, struct xml_request_s *req)
1387 gpg_error_t rc;
1388 struct element_list_s *elements;
1389 char *path = NULL;
1390 char **dup = strv_dup (req->args);
1392 if (!dup)
1393 return GPG_ERR_ENOMEM;
1396 elements = xcalloc (1, sizeof (struct element_list_s));
1397 if (!elements)
1399 rc = GPG_ERR_ENOMEM;
1400 goto fail;
1403 path = strv_join ("\t", dup);
1404 if (!path)
1406 rc = GPG_ERR_ENOMEM;
1407 goto fail;
1410 elements->flags |= XML_LIST_CHECK;
1411 elements->prefix = string_new (NULL);
1412 if (!elements->prefix)
1414 rc = GPG_ERR_ENOMEM;
1415 goto fail;
1418 rc = xml_create_path_list (client, req->doc, xmlDocGetRootElement (req->doc),
1419 elements, path, 0);
1421 fail:
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;
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, 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 /* Ignore errors for elements elsewhere in the document. */
1691 if (*rc == GPG_ERR_EACCES)
1692 *rc = 0;
1694 if (*rc)
1695 goto update_target;
1698 /* Create a new path based on the value of the current "target"
1699 * attribute. */
1700 char **nargs = str_split ((char *)target, "\t", 0);
1701 if (!nargs)
1703 xmlFree (target);
1704 *rc = GPG_ERR_INV_VALUE;
1705 req->data = req->cmd == XML_CMD_LIST ? elements : req->data;
1706 req->depth--;
1707 return NULL;
1710 /* Append the remaining elements to the target attributes path. */
1711 char **nnargs = strv_catv (nargs, p+1);
1712 strv_free (nargs);
1713 char **orig = req->args;
1714 req->args = nnargs;
1715 tmp = xml_find_elements (client, req, xmlDocGetRootElement (req->doc),
1716 rc);
1717 strv_free (nnargs);
1718 req->args = orig;
1720 update_target:
1721 if (req->cmd == XML_CMD_LIST && elements)
1723 /* A child node contained a target. Use this value rather than the
1724 * current target value as the target value for the list flag. */
1725 if (req->data && req->data != elements)
1727 struct element_list_s *e = req->data;
1729 xmlFree (target);
1730 target = xmlStrdup ((xmlChar *)e->target);
1731 xfree (e->target);
1733 if ((e->flags & XML_LIST_HAS_TARGET))
1734 elements->flags |= XML_LIST_HAS_TARGET;
1736 xfree (e);
1739 req->data = elements;
1740 if (req->data)
1742 if (!(elements->flags & XML_LIST_TARGET_ERROR))
1744 xfree (elements->target);
1745 elements->target = NULL;
1747 /* Restore the original target flag. */
1748 if ((elements->flags & XML_LIST_HAS_TARGET))
1749 elements->target = str_dup ((char *)target);
1754 xmlFree (target);
1755 req->depth--;
1756 return *rc ? NULL : tmp;
1759 req->depth--;
1760 return n;
1763 gpg_error_t
1764 xml_new_request (struct client_s *client, const char *line, xml_command_t cmd,
1765 struct xml_request_s **result)
1767 struct xml_request_s *req;
1768 char **pp = str_split ((char *) line, "\t", 0);
1770 if (!pp || !*pp)
1772 strv_free (pp);
1773 return GPG_ERR_SYNTAX;
1776 req = xcalloc (1, sizeof (struct xml_request_s));
1777 if (!req)
1779 strv_free (pp);
1780 return GPG_ERR_ENOMEM;
1783 req->cmd = cmd;
1784 req->args = pp;
1785 req->doc = client ? client->doc : NULL;
1786 *result = req;
1787 return 0;
1790 void
1791 xml_free_request (struct xml_request_s *r)
1793 if (!r)
1794 return;
1796 strv_free (r->args);
1797 xfree (r);
1801 xml_reserved_attribute (const char *name)
1803 int i;
1805 for (i = 0; reserved_attributes[i]; i++)
1807 if (!strcmp (name, reserved_attributes[i]))
1808 return 1;
1811 return 0;