Update copyright year.
[pwmd.git] / src / xml.c
blob881717a135c581379df2781d4cfbac46c7964bbe
1 /*
2 Copyright (C) 2006-2019 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
11 Pwmd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <err.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <libxml/xmlwriter.h>
33 #include <wctype.h>
34 #include <sys/types.h>
35 #include <pwd.h>
37 #ifndef _
38 #include "gettext.h"
39 #define _(msgid) gettext(msgid)
40 #endif
42 #include "pwmd-error.h"
43 #include "util-misc.h"
44 #include "xml.h"
45 #include "mem.h"
46 #include "rcfile.h"
47 #include "commands.h"
48 #include "acl.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 const char *protected_attributes[] = {
62 "_name", "_mtime", "_ctime", NULL
65 void log_write (const char *fmt, ...);
67 gpg_error_t
68 xml_protected_attr (const char *a)
70 int i;
72 for (i = 0; protected_attributes[i]; i++)
74 if (!strcmp (a, protected_attributes[i]))
75 return GPG_ERR_EPERM;
78 return 0;
81 int
82 xml_valid_attribute_value (const char *str)
84 const char *p = str;
86 if (!p || !*p)
87 return 1;
89 while (*p)
91 if (*p++ == '\n')
92 return 0;
95 return 1;
98 int
99 xml_valid_attribute (const char *str)
101 wchar_t *wc;
102 size_t len, c;
103 int ret = xml_valid_element ((xmlChar *)str);
105 if (!ret)
106 return ret;
108 wc = str_to_wchar ((const char *)str);
109 if (!wc)
110 return 0;
112 len = wcslen (wc);
113 for (c = 0; c < len; c++)
115 /* Fixes cygwin compile time warning about exceeding the maximum value
116 * for the type in the switch() statement below. */
117 if (wc[c] >= 0x10000 && wc[c] <= 0xEFFFF)
118 continue;
120 switch (wc[c])
122 case '-':
123 case '.':
124 case '0' ... '9':
125 case 0xB7:
126 case 0x0300 ... 0x036F:
127 case 0x203F ... 0x2040:
128 if (!c)
130 xfree (wc);
131 return 0;
133 case ':': break;
134 case '_': break;
135 case 'A' ... 'Z': break;
136 case 'a' ... 'z': break;
137 case 0xC0 ... 0xD6: break;
138 case 0xD8 ... 0xF6: break;
139 case 0xF8 ... 0x2FF: break;
140 case 0x370 ... 0x37D: break;
141 case 0x37F ... 0x1FFF: break;
142 case 0x200C ... 0x200D: break;
143 case 0x2070 ... 0x218F: break;
144 case 0x2C00 ... 0x2FEF: break;
145 case 0x3001 ... 0xD7FF: break;
146 case 0xF900 ... 0xFDCF: break;
147 case 0xFDF0 ... 0xFFFD: break;
148 default:
149 xfree (wc);
150 return 0;
154 xfree (wc);
155 return 1;
159 xml_valid_element (xmlChar *str)
161 wchar_t *wc;
162 size_t len, c;
164 if (!str || !*str)
165 return 0;
167 wc = str_to_wchar ((const char *)str);
168 if (!wc)
169 return 0;
171 len = wcslen (wc);
172 for (c = 0; c < len; c++)
174 if (iswspace(wc[c]))
176 xfree (wc);
177 return 0;
181 xfree (wc);
182 return 1;
186 xml_valid_element_path (char **path, int with_content)
188 char **dup = NULL, **p;
190 if (!path || !*path)
191 return 0;
193 /* Save some memory by not duplicating the element content. */
194 if (with_content)
196 int i, t = strv_length (path);
198 for (i = 0; i < t - 1; i++)
200 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
202 if (!tmp)
204 strv_free (dup);
205 return 0;
208 dup = tmp;
209 dup[i] = str_dup (path[i]);
210 dup[i + 1] = NULL;
213 else
214 dup = strv_dup (path);
216 if (!dup)
217 return 0;
219 for (p = dup; *p && *(*p); p++)
221 if (!xml_valid_element ((xmlChar *) * p))
223 strv_free (dup);
224 return 0;
228 strv_free (dup);
229 return 1;
232 static gpg_error_t
233 attr_ctime (struct client_s *client, xmlNodePtr n)
235 char *buf = str_asprintf ("%li", time (NULL));
236 gpg_error_t rc;
238 if (!buf)
239 return GPG_ERR_ENOMEM;
241 rc = xml_add_attribute (client, n, "_ctime", buf);
242 xfree (buf);
243 return rc;
246 gpg_error_t
247 xml_acl_check (struct client_s *client, xmlNodePtr n)
249 gpg_error_t rc = GPG_ERR_EACCES;
250 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
251 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
252 char **p;
253 int allowed = 0;
255 if (!acl || !*acl || !users || !*users)
257 xmlFree (acl);
258 strv_free(users);
259 return peer_is_invoker(client);
262 if (!peer_is_invoker(client))
264 xmlFree (acl);
265 strv_free(users);
266 return 0;
269 for (p = users; p && *p; p++)
271 #ifdef WITH_GNUTLS
272 rc = acl_check_common (client, *p,
273 client->thd->remote ? 0 : client->thd->peer->uid,
274 client->thd->remote ? 0 : client->thd->peer->gid,
275 &allowed);
276 #else
277 rc = acl_check_common (client, *p, client->thd->peer->uid,
278 client->thd->peer->gid, &allowed);
279 #endif
282 xmlFree(acl);
283 strv_free(users);
285 if (rc)
286 return rc;
288 return allowed ? 0 : GPG_ERR_EACCES;
291 static char *
292 create_acl_user (struct client_s *client)
294 #ifdef WITH_GNUTLS
295 if (client->thd->remote)
296 return str_asprintf ("#%s", client->thd->tls->fp);
297 #endif
299 return get_username (client->thd->peer->uid);
302 static gpg_error_t
303 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
304 const char *name, xmlNodePtr * result)
306 xmlNodePtr n;
307 gpg_error_t rc;
309 // Allow any client to create a non-existing root element.
310 if (parent->parent->type != XML_DOCUMENT_NODE)
312 rc = xml_acl_check(client, parent);
313 if (rc)
314 return rc;
317 n = xmlNewNode (NULL, (xmlChar *) "element");
318 if (!n)
319 return GPG_ERR_ENOMEM;
321 rc = xml_add_attribute (client, n, "_name", name);
322 if (!rc)
323 rc = attr_ctime (client, n);
325 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
326 rc = xml_is_element_owner (client, parent);
328 if (!rc)
330 xmlNodePtr p = xmlAddChild (parent, n);
331 char *user = create_acl_user (client);
333 if (result)
334 *result = p;
336 rc = xml_add_attribute(client, p, "_acl", user);
337 xfree (user);
339 else
340 xmlFreeNode (n);
342 return rc;
345 gpg_error_t
346 xml_new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
348 xmlNodePtr root = xmlDocGetRootElement (doc);
350 if (!name || !root)
351 return GPG_ERR_BAD_DATA;
353 if (!xml_valid_element ((xmlChar *) name))
354 return GPG_ERR_INV_VALUE;
356 return create_new_element (client, 0, root, name, NULL);
359 static xmlDocPtr
360 create_dtd ()
362 xmlDocPtr doc;
363 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
365 if (!wr)
366 return NULL;
368 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
369 goto fail;
371 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
372 goto fail;
374 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
375 (xmlChar *) "(element)") == -1)
376 goto fail;
378 xmlTextWriterEndDTDElement (wr);
380 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
381 (xmlChar *) "_name CDATA #REQUIRED") ==
383 goto fail;
385 xmlTextWriterEndDTDAttlist (wr);
386 xmlTextWriterEndDTD (wr);
388 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
389 goto fail;
391 xmlTextWriterEndElement (wr);
392 xmlTextWriterEndDocument (wr);
393 xmlFreeTextWriter (wr);
394 return doc;
396 fail:
397 xmlTextWriterEndDocument (wr);
398 xmlFreeTextWriter (wr);
399 xmlFreeDoc (doc);
400 return NULL;
403 xmlDocPtr
404 xml_new_document ()
406 return create_dtd ();
409 static xmlNodePtr
410 find_element_node (xmlNodePtr node)
412 xmlNodePtr n = node;
414 if (n && n->type == XML_ELEMENT_NODE)
415 return n;
417 for (n = node; n; n = n->next)
419 if (n->type == XML_ELEMENT_NODE)
420 return n;
423 return NULL;
426 xmlNodePtr
427 xml_resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
428 char ***result, gpg_error_t *rc)
430 xmlNodePtr n;
431 struct xml_request_s *req;
433 *rc = xml_new_request (client, (char *)path, XML_CMD_REALPATH, &req);
434 if (*rc)
435 return NULL;
437 n = xml_find_elements (client, req, xmlDocGetRootElement (doc), rc);
438 if (!*rc)
440 if (result)
442 *result = strv_dup (req->args);
443 if (!*result)
445 *rc = GPG_ERR_ENOMEM;
446 n = NULL;
451 xml_free_request (req);
452 return n;
455 xmlNodePtr
456 xml_find_text_node (xmlNodePtr node)
458 xmlNodePtr n = node;
460 if (n && n->type == XML_TEXT_NODE)
461 return n;
463 for (n = node; n; n = n->next)
465 if (n->type == XML_TEXT_NODE)
466 return n;
469 return NULL;
472 /* Create an element 'path' starting at 'node'. Returns the node of the final
473 * created element.
475 xmlNodePtr
476 xml_create_element_path (struct client_s *client, struct xml_request_s *req,
477 xmlNodePtr node, char **path, gpg_error_t *rc)
479 char **p;
481 if (!xml_valid_element_path (path, 0))
483 *rc = GPG_ERR_INV_VALUE;
484 return NULL;
487 /* The parent node will be an XML_ELEMENT_NODE. Otherwise we would be
488 * creating element content. */
489 if (node->type == XML_TEXT_NODE)
490 node = node->parent;
492 for (p = path; p && *p; p++)
494 xmlNodePtr n = NULL;
496 if (node != xmlDocGetRootElement (req->doc))
498 n = xml_find_element (client, node, *p, rc);
499 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
500 return NULL;
502 *rc = 0;
506 * If the found element has the same parent as the current element then
507 * they are siblings and the new element needs to be created as a child
508 * of the current element (node).
510 if (n && n->parent == node->parent)
511 n = NULL;
513 if (!n)
515 *rc = create_new_element (client, 0, node, *p, &node);
516 if (*rc)
517 return NULL;
519 else
520 node = n;
523 return node;
526 /* Find the first XML_ELEMENT_NODE whose _name attribute matches 'element'. */
527 xmlNodePtr
528 xml_find_element (struct client_s *client, xmlNodePtr node, const char *element,
529 gpg_error_t *rc)
531 xmlNodePtr n;
533 *rc = 0;
535 if (!node || !element)
537 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
538 return NULL;
541 for (n = node; n; n = n->next)
543 if (n->type != XML_ELEMENT_NODE)
544 continue;
546 xmlChar *a = xml_attribute_value (n, (xmlChar *) "_name");
547 if (a && xmlStrEqual (a, (xmlChar *) element))
549 xmlFree (a);
550 *rc = xml_acl_check (client, n);
551 return n; // Not NULL since the node may be needed later
554 xmlFree (a);
557 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
558 return NULL;
561 xmlChar *
562 xml_attribute_value (xmlNodePtr n, xmlChar * attr)
564 xmlAttrPtr a = xmlHasProp (n, attr);
566 if (!a)
567 return NULL;
569 if (!a->children || !a->children->content)
570 return NULL;
572 return xmlGetProp (n, attr);
575 gpg_error_t
576 xml_remove_user_attributes (struct client_s *client, xmlNodePtr n)
578 gpg_error_t rc = 0;
579 xmlAttrPtr a = n->properties;
581 while (a)
583 if (!xml_reserved_attribute ((const char *)a->name))
585 rc = xml_delete_attribute (client, n, a->name);
586 if (rc)
587 break;
589 a = n->properties;
591 else
592 a = a->next;
595 return rc;
598 gpg_error_t
599 xml_add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
600 const char *value)
602 char *buf;
603 gpg_error_t rc = 0;
604 int is_target = 0;
606 if (client && name && !strcmp (name, "_target"))
608 rc = xml_is_element_owner (client, node);
609 if (rc)
610 return rc;
612 is_target = 1;
614 else if (name && (!strcmp (name, "_expire")
615 || !strcmp (name, "_ctime")
616 || !strcmp (name, "_mtime")))
618 char *p;
619 time_t e;
621 if (!value || !*value)
622 return GPG_ERR_INV_VALUE;
624 errno = 0;
625 e = strtoul (value, &p, 10);
626 if (errno || *p || e == ULONG_MAX || *value == '-')
627 return GPG_ERR_INV_VALUE;
630 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
631 return GPG_ERR_BAD_DATA;
633 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
635 xmlChar *acl = xml_attribute_value (node, (xmlChar *) "_acl");
637 if (!acl)
639 char *user = create_acl_user (client);
641 if (user)
643 rc = xml_add_attribute (client, node, (char *) "_acl", user);
644 xfree (user);
647 return rc;
650 xmlFree (acl);
653 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
654 return 0;
656 if (is_target)
657 xml_remove_user_attributes (client, node);
659 buf = str_asprintf ("%lu", time (NULL));
660 rc = xml_add_attribute (client, node, "_mtime", buf);
661 xfree (buf);
662 return rc;
665 static gpg_error_t
666 append_path_to_list (struct client_s *client, struct element_list_s *elements,
667 const char *path, gpg_error_t rc)
669 struct slist_s *l;
670 struct string_s *line;
672 (void)client;
673 line = string_new (NULL);
674 if (!line)
675 return GPG_ERR_ENOMEM;
677 if (rc == GPG_ERR_ELOOP)
678 string_append (line, "O");
679 else if (rc == GPG_ERR_EACCES)
680 string_append (line, "P");
681 else if (rc)
682 string_append (line, "E");
684 if (rc || elements->target)
685 string_prepend (line, " ");
687 if ((!rc || rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
688 || rc == GPG_ERR_ELEMENT_NOT_FOUND) && elements->target)
689 string_append_printf (line, "%sT %s",
690 (!rc && elements->flags & XML_LIST_FLAG_CHILDREN) ? "+" : "",
691 elements->target);
692 else if (!rc && (elements->flags & XML_LIST_FLAG_CHILDREN))
693 string_prepend (line, " +");
695 if (elements->prefix && elements->prefix->str)
696 string_prepend (line, elements->prefix->str);
697 else
698 string_prepend (line, path);
700 l = slist_append (elements->list, line->str);
701 if (l)
703 elements->list = l;
704 if (!(elements->flags & XML_LIST_CHECK))
705 rc = 0;
707 else
708 rc = GPG_ERR_ENOMEM;
710 string_free (line, 0);
711 return rc;
714 /* Removes the final element from the element prefix. */
715 static void
716 pop_element_prefix (struct element_list_s *elements)
718 char *p = strrchr (elements->prefix->str, '\t');
720 if (p)
721 string_truncate (elements->prefix,
722 elements->prefix->len - strlen (p));
725 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
726 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
729 * From the element path 'path', find sub-nodes and append them to the list.
731 gpg_error_t
732 xml_create_path_list (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
733 struct element_list_s *elements, char *path,
734 gpg_error_t rc)
736 xmlNodePtr n = NULL;
737 struct xml_request_s *req = NULL;
738 gpg_error_t trc = rc;
739 char *target_orig;
741 target_orig = rc && elements->target ? str_dup (elements->target) : NULL;
742 rc = xml_new_request (client, path, XML_CMD_LIST, &req);
743 if (rc)
745 xfree (target_orig);
746 return rc;
749 req->data = elements;
750 n = xml_find_elements (client, req,
751 node ? node : xmlDocGetRootElement (doc), &rc);
752 if (!rc)
753 elements->flags |=
754 find_element_node (n->children) ? XML_LIST_FLAG_CHILDREN : 0;
756 if (!rc && trc)
758 xfree (elements->target);
759 elements->target = target_orig;
760 elements->flags = 0;
761 elements->flags |= XML_LIST_HAS_TARGET;
763 else
764 xfree (target_orig);
766 rc = append_path_to_list (client, elements, path, trc ? trc : rc);
767 xmlFree (elements->target);
768 elements->target = NULL;
770 if (rc || trc || (elements->flags & XML_LIST_CHECK)
771 || (!elements->recurse && elements->depth) || elements->root_only)
773 xml_free_request (req);
774 return rc;
777 elements->flags = 0;
779 if (!rc && n && n->children)
781 for (n = n->children; n; n = n->next)
783 xmlChar *target = NULL;
784 xmlNodePtr tmp = NULL;
785 xmlChar *name;
786 struct string_s *newpath;
788 if (n->type != XML_ELEMENT_NODE)
789 continue;
791 name = xml_attribute_value (n, (xmlChar *) "_name");
792 if (!name)
793 continue;
795 newpath = string_new (NULL);
796 if (!newpath)
798 xmlFree (name);
799 rc = GPG_ERR_ENOMEM;
800 goto fail;
803 target = xml_attribute_value (n, (xmlChar *) "_target");
804 if (target)
806 rc = xml_validate_target (client, req->doc, (char *)target, n);
807 elements->target = (char *)target;
808 elements->flags |= rc ? XML_LIST_TARGET_ERROR : 0;
810 else
811 tmp = n;
813 if (RESUMABLE_ERROR (rc))
815 struct string_s *s;
817 /* If there is a target for this node then resolve the full path
818 * starting at the document root. Otherwise, resolve the next
819 * element starting from the child node of the current node. In
820 * either case, append the current element in the element path to
821 * the prefix of the list string.
823 if (target)
825 string_truncate (newpath, 0);
826 s = string_append_printf (newpath, "%s", (char *)target);
828 else
829 s = string_append (newpath, (char *)name);
831 if (!s)
833 xmlFree (name);
834 string_free (newpath, 1);
835 rc = GPG_ERR_ENOMEM;
836 goto fail;
839 newpath = s;
840 if (!elements->depth)
842 /* There may be a single remaining element in the prefix left
843 * over from the previous truncation (see below). It is safe
844 * to truncate it here since depth == 0. */
845 string_truncate (elements->prefix, 0);
846 s = string_append_printf (elements->prefix, "%s\t%s",
847 path, name);
849 else
850 s = string_append_printf (elements->prefix, "\t%s", name);
852 if (!s)
854 xmlFree (name);
855 string_free (newpath, 1);
856 rc = GPG_ERR_ENOMEM;
857 goto fail;
860 elements->prefix = s;
861 elements->depth++;
862 rc = xml_create_path_list (client, doc, target ? NULL : tmp,
863 elements, newpath->str, rc);
864 elements->depth--;
865 if (!rc)
866 pop_element_prefix (elements);
869 string_free (newpath, 1);
870 xmlFree (name);
871 if (rc)
872 break;
876 fail:
877 xml_free_request (req);
878 return rc;
881 gpg_error_t
882 xml_recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
883 xmlNodeSetPtr nodes, xmlChar * value,
884 xmlBufferPtr * result, int cmd, const xmlChar * attr)
886 int i = value ? nodes->nodeNr - 1 : 0;
887 xmlBufferPtr buf;
889 buf = xmlBufferCreate ();
891 if (!buf)
892 return GPG_ERR_ENOMEM;
894 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
896 xmlNodePtr n = nodes->nodeTab[i];
897 gpg_error_t rc;
899 if (!n)
900 continue;
902 if (!value && !attr)
904 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
906 *result = buf;
907 return GPG_ERR_BAD_DATA;
910 continue;
913 if (!attr)
915 xmlNodeSetContent (n, value);
916 rc = xml_update_element_mtime (client, n);
918 if (rc)
919 return rc;
921 else
923 if (!cmd)
924 rc = xml_add_attribute (client, n, (char *) attr, (char *) value);
925 else
926 rc = xml_delete_attribute (client, n, attr);
928 if (rc)
929 return rc;
933 *result = buf;
934 return 0;
937 gpg_error_t
938 xml_delete_attribute (struct client_s *client, xmlNodePtr n,
939 const xmlChar *name)
941 xmlAttrPtr a;
942 gpg_error_t rc = 0;
944 if ((a = xmlHasProp (n, name)) == NULL)
945 return GPG_ERR_NOT_FOUND;
947 if (xmlRemoveProp (a) == -1)
948 return GPG_ERR_BAD_DATA;
950 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
952 char *user = create_acl_user (client);
954 rc = xml_add_attribute (client, n, (char *) "_acl", user);
955 xfree (user);
957 if (rc)
958 return rc;
961 return xml_update_element_mtime (client, n);
964 gpg_error_t
965 xml_validate_import (struct client_s *client, xmlNodePtr node)
967 gpg_error_t rc = 0;
969 if (!node)
970 return 0;
972 for (xmlNodePtr n = node; n; n = n->next)
974 if (n->type == XML_ELEMENT_NODE)
976 if (xmlStrEqual (n->name, (xmlChar *) "element"))
978 xmlChar *a = xmlGetProp (n, (xmlChar *) "_target");
980 if (a)
982 xmlFree (a);
983 rc = xml_remove_user_attributes (client, n);
984 if (!rc)
985 rc = xml_unlink_node (client, n->children);
988 if (rc)
989 break;
991 a = xmlGetProp (n, (xmlChar *) "_name");
992 if (!a)
994 xmlChar *t = xmlGetNodePath (n);
996 log_write (_("Missing attribute '_name' at %s."), t);
997 xmlFree (t);
998 return GPG_ERR_INV_VALUE;
1001 if (!xml_valid_element (a))
1003 xmlChar *t = xmlGetNodePath (n);
1005 log_write (_("'%s' is not a valid element name at %s."), a,
1007 xmlFree (a);
1008 xmlFree (t);
1009 return GPG_ERR_INV_VALUE;
1012 xmlFree (a);
1013 a = xmlGetProp (n, (xmlChar *) "_ctime");
1014 if (!a)
1015 attr_ctime (client, n);
1017 xmlFree (a);
1018 a = xmlGetProp (n, (xmlChar *) "_mtime");
1019 if (!a)
1020 xml_update_element_mtime (client, n);
1021 xmlFree (a);
1023 else
1025 xmlChar *t = xmlGetNodePath (n);
1026 xmlNodePtr tmp = n->next;
1028 log_write (_("Warning: unknown element '%s' at %s. Removing."),
1029 n->name, t);
1030 xmlFree (t);
1031 (void)xml_unlink_node (client, n);
1032 return xml_validate_import (client, tmp);
1036 if (n->children)
1038 rc = xml_validate_import (client, n->children);
1039 if (rc)
1040 return rc;
1044 return rc;
1047 gpg_error_t
1048 xml_update_element_mtime (struct client_s *client, xmlNodePtr n)
1050 return xml_add_attribute (client, n, NULL, NULL);
1053 gpg_error_t
1054 xml_unlink_node (struct client_s *client, xmlNodePtr n)
1056 gpg_error_t rc = 0;
1058 if (!n)
1059 return rc;
1061 if (n->parent)
1062 rc = xml_update_element_mtime (client, n->parent);
1064 xmlUnlinkNode (n);
1065 xmlFreeNodeList (n);
1066 return rc;
1069 static gpg_error_t
1070 recurse_rename_attribute (xmlNodePtr root, const char *old, const char *name)
1072 xmlNodePtr n;
1073 gpg_error_t rc = 0;
1075 for (n = root; n; n = n->next)
1077 xmlAttrPtr attr = xmlHasProp (n, (xmlChar *)old);
1079 if (attr)
1081 xmlChar *a = xml_attribute_value (n, (xmlChar *)old);
1083 if (a && !xmlSetProp (n, (xmlChar *) name, a))
1084 rc = GPG_ERR_BAD_DATA;
1086 xmlFree (a);
1088 if (!rc)
1090 if (xmlRemoveProp (attr) == -1)
1091 rc = GPG_ERR_BAD_DATA;
1095 if (rc)
1096 break;
1098 rc = recurse_rename_attribute (n->children, old, name);
1099 if (rc)
1100 break;
1103 return rc;
1106 static gpg_error_t
1107 update_to_version (xmlDocPtr doc)
1109 xmlNodePtr root = xmlDocGetRootElement (doc);
1110 xmlChar *v = xml_attribute_value (root, (xmlChar *)"_version");
1111 gpg_error_t rc;
1113 // Pwmd 3.2.0 or later. No updates needed ATM.
1114 if (v)
1116 xmlFree (v);
1117 return 0;
1120 rc = recurse_rename_attribute (root->children, "target", "_target");
1121 if (!rc)
1122 rc = recurse_rename_attribute (root->children, "expire", "_expire");
1124 if (!rc)
1125 rc = recurse_rename_attribute (root->children, "expire_increment", "_age");
1127 return rc;
1130 gpg_error_t
1131 xml_parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1133 xmlDocPtr doc;
1134 gpg_error_t rc;
1136 xmlResetLastError ();
1137 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1138 if (!doc && xmlGetLastError ())
1139 return GPG_ERR_BAD_DATA;
1141 *result = doc;
1142 if (doc)
1143 rc = update_to_version (doc);
1144 else
1145 rc = GPG_ERR_ENOMEM;
1147 return rc;
1150 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1151 * target. 'path' is any remaining elements in the element path after this
1152 * element 'node' as passed to xml_find_elements() or the initial command. This
1153 * function may be recursive as it calls xml_find_elements().
1155 static xmlNodePtr
1156 do_realpath (struct client_s *client, struct xml_request_s *req,
1157 xmlNodePtr node, char **path, const xmlChar *target,
1158 gpg_error_t *rc) {
1159 char *line;
1160 char **result = NULL;
1161 struct xml_request_s *nreq = NULL;
1163 *rc = 0;
1165 result = str_split ((char *)target, "\t", 0);
1166 if (!result)
1168 *rc = GPG_ERR_ENOMEM;
1169 return NULL;
1172 /* Append the original path to the target path. */
1173 if (path)
1175 char **p = strv_catv (result, path);
1177 strv_free (result);
1178 if (!p)
1180 *rc = GPG_ERR_ENOMEM;
1181 return NULL;
1184 result = p;
1187 line = strv_join ("\t", result);
1188 if (!line)
1190 strv_free (result);
1191 *rc = GPG_ERR_ENOMEM;
1192 return NULL;
1195 /* To prevent overwriting any original client request flags. We are only
1196 * interested in the path here. */
1197 *rc = xml_new_request (client, line, XML_CMD_REALPATH, &nreq);
1198 xfree (line);
1199 if (*rc)
1201 strv_free (result);
1202 return NULL;
1205 nreq->depth = req->depth;
1206 strv_free (result);
1207 node = xml_find_elements (client, nreq, xmlDocGetRootElement (nreq->doc), rc);
1209 /* Update the original client request path with the resolved one. */
1210 if (!*rc)
1212 strv_free (req->args);
1213 req->args = nreq->args;
1214 nreq->args = NULL;
1217 xml_free_request (nreq);
1218 return node;
1221 #if 0
1222 static char *
1223 node_to_element_path (xmlNodePtr node)
1225 xmlNodePtr n;
1226 struct string_s *str = string_new ("");
1227 char *result;
1229 for (n = node; n; n = n->parent)
1231 xmlNodePtr child;
1233 for (child = n; child; child = child->next)
1235 if (child->type != XML_ELEMENT_NODE)
1236 continue;
1238 xmlChar *name = xml_attribute_value (n, (xmlChar *) "_name");
1239 if (name)
1241 str = string_prepend (str, (char *) name);
1242 xmlFree (name);
1243 name = xml_attribute_value (n, (xmlChar *) "_target");
1244 if (name)
1245 str = string_prepend (str, "\t");
1246 else
1247 str = string_prepend (str, "\t!");
1248 xmlFree (name);
1250 break;
1254 str = string_erase (str, 0, 1);
1255 result = str->str;
1256 string_free (str, 0);
1257 return result;
1259 #endif
1261 /* Tests if 'path' references 'node' somewhere. */
1262 static gpg_error_t
1263 element_related (struct client_s *client, xmlDocPtr doc, const char *path,
1264 xmlNodePtr node, unsigned depth)
1266 gpg_error_t rc = GPG_ERR_NO_DATA;
1267 char **p;
1268 xmlNodePtr n = xmlDocGetRootElement (doc);
1270 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1271 return GPG_ERR_ELOOP;
1273 p = str_split (path, "\t", 0);
1274 if (!p)
1275 return GPG_ERR_ENOMEM;
1277 for (n = n->children; n && *p; p++, n = n->next)
1279 xmlNodePtr t;
1280 xmlChar *target;
1281 struct string_s *str = NULL;
1283 t = xml_find_element (client, n, *p, &rc);
1284 if (rc)
1286 rc = GPG_ERR_NO_DATA;
1287 break;
1290 if (t == node)
1292 rc = 0;
1293 break;
1296 target = xml_attribute_value (t, (xmlChar *)"_target");
1297 if (!target)
1298 continue;
1300 str = string_new ((char *)target);
1301 xmlFree (target);
1302 if (!str)
1304 rc = GPG_ERR_ENOMEM;
1305 break;
1308 if (*(p+1))
1310 while (*++p)
1312 struct string_s *tmp;
1314 tmp = string_append_printf (str, "\t%s", *p);
1315 if (!tmp)
1317 string_free (str, 1);
1318 strv_free (p);
1319 return GPG_ERR_ENOMEM;
1322 str = tmp;
1326 rc = element_related (client, doc, str->str, n->children, ++depth);
1327 if (rc == GPG_ERR_ELOOP)
1328 rc = GPG_ERR_NO_DATA;
1330 string_free(str, 1);
1331 break;
1334 strv_free (p);
1335 return rc;
1339 * Recurse the element tree beginning at 'node' and find elements who point
1340 * back to 'dst'. Also follows target attributes.
1342 static gpg_error_t
1343 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1344 xmlNodePtr dst, unsigned depth, int is_target)
1346 xmlNodePtr n;
1347 gpg_error_t rc = 0;
1349 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
1350 return node == dst ? GPG_ERR_ELOOP : 0;
1352 for (n = node; n; n = n->next)
1354 xmlChar *target;
1356 if (n->type != XML_ELEMENT_NODE)
1357 continue;
1359 if (n == dst && depth)
1360 return GPG_ERR_ELOOP;
1362 target = xml_attribute_value (n, (xmlChar *) "_target");
1363 if (target)
1365 xmlNodePtr tmp;
1366 char **result = NULL;
1368 tmp = xml_resolve_path (client, doc, target, &result, &rc);
1369 strv_free (result);
1370 if (!rc)
1372 rc = find_child_to_target (client, doc, tmp, dst, ++depth, 1);
1373 depth--;
1375 else if (rc == GPG_ERR_ELOOP)
1377 gpg_error_t trc = element_related (client, doc, (char *)target,
1378 dst, 0);
1380 if (trc && trc != GPG_ERR_NO_DATA)
1381 rc = trc;
1382 else if (trc == GPG_ERR_NO_DATA)
1383 rc = 0;
1386 xmlFree (target);
1388 if (rc && rc != GPG_ERR_ELEMENT_NOT_FOUND)
1389 return rc;
1391 rc = 0;
1392 if (is_target)
1393 break;
1395 continue;
1398 if (n->children)
1400 rc = find_child_to_target (client, doc, n->children, dst, ++depth, 0);
1401 depth--;
1402 if (rc)
1403 return rc;
1406 if (is_target)
1407 break;
1410 return rc;
1413 static gpg_error_t
1414 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
1416 xmlNodePtr n;
1417 gpg_error_t rc = 0;
1419 for (n = src; n; n = n->next)
1421 if (n->type != XML_ELEMENT_NODE)
1422 continue;
1424 if (n == dst)
1426 rc = GPG_ERR_ELOOP;
1427 break;
1430 rc = find_child_of_parent (doc, n->children, dst);
1433 return rc;
1436 static gpg_error_t
1437 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
1439 xmlNodePtr n;
1440 gpg_error_t rc = 0;
1442 (void)doc;
1443 for (n = node; n; n = n->parent)
1445 if (n->type != XML_ELEMENT_NODE)
1447 xmlNodePtr tmp;
1449 for (tmp = n->next; tmp; n = n->next)
1451 if (n->type != XML_ELEMENT_NODE)
1452 continue;
1454 if (tmp == dst)
1455 return GPG_ERR_ELOOP;
1459 if (n == dst)
1460 return GPG_ERR_ELOOP;
1463 return rc;
1466 void
1467 xml_free_element_list (struct element_list_s *elements)
1469 if (elements)
1471 if (elements->list)
1473 int total = slist_length (elements->list);
1474 int i;
1476 for (i = 0; i < total; i++)
1478 char *tmp = slist_nth_data (elements->list, i);
1479 xfree (tmp);
1482 slist_free (elements->list);
1485 string_free (elements->prefix, 1);
1486 xfree (elements->target);
1487 xfree (elements);
1491 /* This behaves like the LIST command with a specified path except it returns
1492 * an error.
1494 gpg_error_t
1495 xml_check_recursion (struct client_s *client, struct xml_request_s *req)
1497 gpg_error_t rc;
1498 struct element_list_s *elements;
1499 char *path = NULL;
1500 char **dup = strv_dup (req->args);
1502 if (!dup)
1503 return GPG_ERR_ENOMEM;
1506 elements = xcalloc (1, sizeof (struct element_list_s));
1507 if (!elements)
1509 rc = GPG_ERR_ENOMEM;
1510 goto fail;
1513 path = strv_join ("\t", dup);
1514 if (!path)
1516 rc = GPG_ERR_ENOMEM;
1517 goto fail;
1520 elements->flags |= XML_LIST_CHECK;
1521 elements->prefix = string_new (NULL);
1522 if (!elements->prefix)
1524 rc = GPG_ERR_ENOMEM;
1525 goto fail;
1528 rc = xml_create_path_list (client, req->doc, xmlDocGetRootElement (req->doc),
1529 elements, path, 0);
1531 fail:
1532 xml_free_element_list (elements);
1533 strv_free (dup);
1534 xfree (path);
1535 return rc;
1538 gpg_error_t
1539 xml_validate_target (struct client_s *client, xmlDocPtr doc, const char *src,
1540 xmlNodePtr dst)
1542 gpg_error_t rc;
1543 xmlNodePtr src_node;
1544 char **src_req = NULL;
1546 src_node = xml_resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
1547 if (rc)
1548 goto fail;
1550 client->flags |= FLAG_ACL_IGNORE;
1551 /* A destination element is a child of the source element. */
1552 rc = find_child_of_parent (doc, src_node->children, dst);
1553 if (rc)
1554 goto fail;
1556 /* The destination element is a parent of the source element. */
1557 rc = find_parent_of_child (doc, src_node->parent, dst);
1558 if (rc)
1559 goto fail;
1561 /* A destination child element contains a target to the source element. */
1562 if (dst)
1563 rc = find_child_to_target (client, doc,
1564 dst->children ? dst->children : dst, dst, 0, 0);
1565 if (rc)
1566 goto fail;
1568 fail:
1569 strv_free (src_req);
1570 client->flags &= ~(FLAG_ACL_IGNORE | FLAG_ACL_ERROR);
1571 return rc;
1574 /* The owner of the element is the first user listed in the _acl attribute
1575 * list. xml_acl_check() should be called before calling this function. An empty
1576 * ACL is an error if the client is not an invoking_user.
1578 gpg_error_t
1579 xml_is_element_owner (struct client_s *client, xmlNodePtr n)
1581 xmlChar *acl = xml_attribute_value (n, (xmlChar *) "_acl");
1582 char **users;
1583 gpg_error_t rc = GPG_ERR_EACCES;
1585 if (!acl || !*acl)
1587 xmlFree (acl);
1588 return peer_is_invoker (client);
1591 users = str_split((char *)acl, ",", 0);
1592 if (users && *users)
1594 char *user;
1596 #ifdef WITH_GNUTLS
1597 if (client->thd->remote)
1598 user = str_asprintf ("#%s", client->thd->tls->fp);
1599 else
1600 user = get_username (client->thd->peer->uid);
1601 #else
1602 user = get_username (client->thd->peer->uid);
1603 #endif
1605 if (*user == '#')
1606 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
1607 else
1608 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
1610 if (rc)
1611 rc = peer_is_invoker (client);
1613 xfree (user);
1616 xmlFree (acl);
1617 strv_free (users);
1618 return rc;
1621 /* Find elements by matching element names in req->args starting at 'node'.
1622 * Returns the node of the final element in req->args on success or NULL on
1623 * failure and sets 'rc' to the error code. Some commands may need special
1624 * handling and will return the node of the previous found element.
1626 xmlNodePtr
1627 xml_find_elements (struct client_s *client, struct xml_request_s *req,
1628 xmlNodePtr node, gpg_error_t *rc)
1630 xmlNodePtr n, last;
1631 char **p;
1633 *rc = 0;
1634 req->depth++;
1636 if (max_recursion_depth >= 1 && req->depth > max_recursion_depth)
1638 req->depth--;
1639 *rc = GPG_ERR_ELOOP;
1640 return NULL;
1643 /* Beginning of a command/root element (<pwmd>). */
1644 if (node == xmlDocGetRootElement (req->doc))
1646 if (!node->children) // Empty tree
1648 if (req->cmd == XML_CMD_STORE)
1649 return xml_create_element_path (client, req, node, req->args, rc);
1651 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1652 req->depth--;
1653 return NULL;
1656 node = node->children; // Start searching at the first child of the root
1659 for (last = n = node, p = req->args; *p; p++)
1661 xmlNodePtr tmp = NULL;
1662 struct element_list_s *elements = NULL;
1664 // FIXME should not be reached in this function?
1665 if (!*(*p))
1667 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1668 req->depth--;
1669 return NULL;
1672 n = xml_find_element (client, n, *p, rc);
1673 if (*rc)
1675 if (*rc != GPG_ERR_ELEMENT_NOT_FOUND && *rc != GPG_ERR_EACCES)
1677 req->depth--;
1678 return NULL;
1681 if (*rc == GPG_ERR_EACCES
1682 && (req->cmd == XML_CMD_ATTR_LIST || req->cmd == XML_CMD_ATTR
1683 || req->cmd == XML_CMD_ATTR_EXPIRE))
1685 req->depth--;
1686 if (*(p+1))
1687 return NULL;
1689 *rc = 0;
1690 return n;
1693 /* Fixes ATTR LIST when an element does not exist and the parent
1694 * denies access to children. Fixes leaking information about the
1695 * current elements children. */
1696 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND && last != n && last != node)
1698 gpg_error_t trc = xml_acl_check (client, last);
1699 if (trc)
1700 *rc = trc;
1703 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND)
1705 if (req->cmd == XML_CMD_STORE || req->cmd == XML_CMD_ATTR_TARGET)
1707 *rc = 0;
1708 n = xml_create_element_path (client, req,
1709 *p == *req->args
1710 && node->parent == xmlDocGetRootElement (req->doc)
1711 ? node->parent : last, p, rc);
1712 req->depth--;
1713 return n;
1717 if (req->cmd != XML_CMD_LIST && req->cmd != XML_CMD_REALPATH)
1719 req->depth--;
1720 return NULL;
1723 // Fall through to let LIST flags be appended.
1726 last = n;
1728 /* Follow a "_target" attribute for each one found in each element. */
1729 xmlChar *target = xml_attribute_value (n, (xmlChar *) "_target");
1730 if (!target || !*target)
1732 xmlFree (target);
1734 if (*rc)
1736 req->depth--;
1737 return NULL;
1740 /* This is the final element in req->args. Done. */
1741 if (!*(p+1))
1743 req->depth--;
1744 return n;
1747 n = n->children;
1748 continue;
1751 if (req->cmd == XML_CMD_REALPATH)
1753 n = do_realpath (client, req, n, p+1, target, rc);
1754 xmlFree (target);
1755 req->depth--;
1756 return n;
1758 else if (req->cmd == XML_CMD_DELETE || req->cmd == XML_CMD_RENAME
1759 || req->cmd == XML_CMD_MOVE || req->cmd == XML_CMD_ATTR
1760 || req->cmd == XML_CMD_ATTR_TARGET
1761 || req->cmd == XML_CMD_ATTR_LIST)
1763 /* No more elements to resolve. Return the node with the target. */
1764 if (!*(p+1))
1766 xmlFree (target);
1767 req->depth--;
1768 return n;
1771 else if (req->cmd == XML_CMD_LIST)
1773 elements = req->data;
1774 if (elements && !(elements->flags & XML_LIST_CHILD_TARGET))
1776 /* No further elements. Use this target in the list flags. */
1777 if (!*(p+1))
1778 elements->flags |= XML_LIST_HAS_TARGET;
1779 else
1781 /* Prevent replacing any following target value with the
1782 * current target value. */
1783 req->data = NULL;
1786 else if (!elements)
1788 struct element_list_s *e = xcalloc (1, sizeof (struct element_list_s));
1790 e->target = str_dup ((char *)target);
1791 e->flags |= XML_LIST_CHILD_TARGET;
1793 if (!*(p+1))
1794 e->flags |= XML_LIST_HAS_TARGET;
1796 req->data = elements = e;
1799 gpg_error_t rc_orig = *rc;
1800 *rc = xml_validate_target (client, req->doc, (char *)target, n);
1801 /* Ignore errors for elements elsewhere in the document. */
1802 if (*rc == GPG_ERR_EACCES)
1803 *rc = 0;
1805 if (rc_orig != *rc)
1806 *rc = *rc ? *rc : rc_orig;
1808 if (*rc)
1809 goto update_target;
1812 /* Create a new path based on the value of the current "_target"
1813 * attribute. */
1814 char **nargs = str_split ((char *)target, "\t", 0);
1815 if (!nargs)
1817 xmlFree (target);
1818 *rc = GPG_ERR_INV_VALUE;
1819 req->data = req->cmd == XML_CMD_LIST ? elements : req->data;
1820 req->depth--;
1821 return NULL;
1824 /* Append the remaining elements to the target attributes path. */
1825 char **nnargs = strv_catv (nargs, p+1);
1826 strv_free (nargs);
1827 char **orig = req->args;
1828 req->args = nnargs;
1829 tmp = xml_find_elements (client, req, xmlDocGetRootElement (req->doc),
1830 rc);
1831 strv_free (nnargs);
1832 req->args = orig;
1834 update_target:
1835 if (req->cmd == XML_CMD_LIST && elements)
1837 /* A child node contained a target. Use this value rather than the
1838 * current target value as the target value for the list flag. */
1839 if (req->data && req->data != elements)
1841 struct element_list_s *e = req->data;
1843 xmlFree (target);
1844 target = xmlStrdup ((xmlChar *)e->target);
1845 xfree (e->target);
1847 if ((e->flags & XML_LIST_HAS_TARGET))
1848 elements->flags |= XML_LIST_HAS_TARGET;
1850 xfree (e);
1853 req->data = elements;
1854 if (req->data)
1856 if (!(elements->flags & XML_LIST_TARGET_ERROR))
1858 xfree (elements->target);
1859 elements->target = NULL;
1861 /* Restore the original target flag. */
1862 if ((elements->flags & XML_LIST_HAS_TARGET))
1863 elements->target = str_dup ((char *)target);
1868 xmlFree (target);
1869 req->depth--;
1870 return *rc ? NULL : tmp;
1873 req->depth--;
1874 return n;
1877 gpg_error_t
1878 xml_new_request (struct client_s *client, const char *line, xml_command_t cmd,
1879 struct xml_request_s **result)
1881 struct xml_request_s *req;
1882 char **pp = str_split ((char *) line, "\t", 0);
1884 if (!pp || !*pp)
1886 strv_free (pp);
1887 return GPG_ERR_SYNTAX;
1890 req = xcalloc (1, sizeof (struct xml_request_s));
1891 if (!req)
1893 strv_free (pp);
1894 return GPG_ERR_ENOMEM;
1897 req->cmd = cmd;
1898 req->args = pp;
1899 req->doc = client ? client->doc : NULL;
1900 *result = req;
1901 return 0;
1904 void
1905 xml_free_request (struct xml_request_s *r)
1907 if (!r)
1908 return;
1910 strv_free (r->args);
1911 xfree (r);
1915 xml_reserved_attribute (const char *name)
1917 int i;
1919 for (i = 0; reserved_attributes[i]; i++)
1921 if (!strcmp (name, reserved_attributes[i]))
1922 return 1;
1925 return 0;