Version 3.0.12.
[pwmd.git] / src / xml.c
blob08038d9ca94ac936423c77445cf604db510eed9a
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.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"
48 extern void log_write (const char *fmt, ...);
51 * 'element' must be allocated.
53 int
54 is_literal_element (char **element)
56 char *p;
58 if (!element || !*element)
59 return 0;
61 if (*(*element) == '!')
63 char *c;
65 for (p = *element, c = p + 1; *c; c++)
66 *p++ = *c;
68 *p = 0;
69 return 1;
72 return 0;
75 int
76 valid_xml_attribute (const char *str)
78 return valid_xml_element ((xmlChar *)str);
81 int
82 valid_xml_element (xmlChar *str)
84 wchar_t *wc;
85 size_t len, c;
87 if (!str || !*str || *str == '!')
88 return 0;
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 if (iswspace(wc[c]))
99 xfree (wc);
100 return 0;
104 xfree (wc);
105 return 1;
109 valid_element_path (char **path, int with_content)
111 char **dup = NULL, **p;
113 if (!path || !*path)
114 return 0;
116 /* Save some memory by not duplicating the element content. */
117 if (with_content)
119 int i, t = strv_length (path);
121 for (i = 0; i < t - 1; i++)
123 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
125 if (!tmp)
127 strv_free (dup);
128 return 0;
131 dup = tmp;
132 dup[i] = str_dup (path[i]);
133 dup[i + 1] = NULL;
136 else
137 dup = strv_dup (path);
139 if (!dup)
140 return 0;
142 for (p = dup; *p && *(*p); p++)
144 is_literal_element (&(*p));
145 if (!valid_xml_element ((xmlChar *) * p))
147 strv_free (dup);
148 return 0;
152 strv_free (dup);
153 return 1;
156 gpg_error_t
157 attr_ctime (struct client_s *client, xmlNodePtr n)
159 char *buf = str_asprintf ("%li", time (NULL));
160 gpg_error_t rc;
162 if (!buf)
163 return GPG_ERR_ENOMEM;
165 rc = add_attribute (client, n, "_ctime", buf);
166 xfree (buf);
167 return rc;
170 static gpg_error_t
171 acl_check (struct client_s *client, xmlNodePtr n)
173 gpg_error_t rc = GPG_ERR_EACCES;
174 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
175 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
176 char **p;
177 int allowed = 0;
179 if (!acl || !*acl || !users || !*users)
181 xmlFree (acl);
182 strv_free(users);
183 return peer_is_invoker(client);
186 if (!peer_is_invoker(client))
187 return 0;
189 for (p = users; *p; p++)
191 #ifdef WITH_GNUTLS
192 rc = acl_check_common (client, *p,
193 client->thd->remote ? 0 : client->thd->peer->uid,
194 client->thd->remote ? 0 : client->thd->peer->gid,
195 &allowed);
196 #else
197 rc = acl_check_common (client, *p, client->thd->peer->uid,
198 client->thd->peer->gid, &allowed);
199 #endif
202 xmlFree(acl);
203 strv_free(users);
204 if (rc)
205 return rc;
207 return allowed ? 0 : GPG_ERR_EACCES;
210 static char *
211 create_acl_user (struct client_s *client)
213 #ifdef WITH_GNUTLS
214 if (client->thd->remote)
215 return str_asprintf ("#%s", client->thd->tls->fp);
216 #endif
218 return get_username (client->thd->peer->uid);
221 static gpg_error_t
222 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
223 const char *name, xmlNodePtr * result)
225 xmlNodePtr n;
226 gpg_error_t rc;
228 // Allow any client to create a non-existing root element.
229 if (parent->parent->type != XML_DOCUMENT_NODE)
231 rc = acl_check(client, parent);
232 if (rc)
233 return rc;
236 n = xmlNewNode (NULL, (xmlChar *) "element");
237 if (!n)
238 return GPG_ERR_ENOMEM;
240 rc = add_attribute (client, n, "_name", name);
241 if (!rc)
242 rc = attr_ctime (client, n);
244 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
245 rc = is_element_owner (client, parent);
247 if (!rc)
249 xmlNodePtr p = xmlAddChild (parent, n);
250 char *user = create_acl_user (client);
252 if (result)
253 *result = p;
255 rc = add_attribute(client, p, "_acl", user);
256 xfree (user);
258 else
259 xmlFreeNode (n);
261 return rc;
264 gpg_error_t
265 new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
267 xmlNodePtr root = xmlDocGetRootElement (doc);
268 char *p = name;
270 if (!p || !root)
271 return GPG_ERR_BAD_DATA;
273 if (*p == '!')
274 p++;
276 if (!valid_xml_element ((xmlChar *) p))
277 return GPG_ERR_INV_VALUE;
279 return create_new_element (client, 0, root, p, NULL);
282 static xmlDocPtr
283 create_dtd ()
285 xmlDocPtr doc;
286 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
288 if (!wr)
289 return NULL;
291 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
292 goto fail;
294 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
295 goto fail;
297 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
298 (xmlChar *) "(element)") == -1)
299 goto fail;
301 xmlTextWriterEndDTDElement (wr);
303 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
304 (xmlChar *) "_name CDATA #REQUIRED") ==
306 goto fail;
308 xmlTextWriterEndDTDAttlist (wr);
309 xmlTextWriterEndDTD (wr);
311 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
312 goto fail;
314 xmlTextWriterEndElement (wr);
315 xmlTextWriterEndDocument (wr);
316 xmlFreeTextWriter (wr);
317 return doc;
319 fail:
320 xmlTextWriterEndDocument (wr);
321 xmlFreeTextWriter (wr);
322 xmlFreeDoc (doc);
323 return NULL;
326 xmlDocPtr
327 new_document ()
329 return create_dtd ();
332 xmlNodePtr
333 find_element_node (xmlNodePtr node)
335 xmlNodePtr n = node;
337 if (n && n->type == XML_ELEMENT_NODE)
338 return n;
340 for (n = node; n; n = n->next)
342 if (n->type == XML_ELEMENT_NODE)
343 return n;
346 return NULL;
349 static xmlNodePtr
350 resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
351 char ***result, gpg_error_t * rc)
353 xmlNodePtr n;
354 char **req;
356 req = str_split ((char *) path, "\t", 0);
357 if (!req)
359 *rc = GPG_ERR_ENOMEM;
360 return NULL;
363 n = find_root_element (client, doc, &req, rc, NULL, 0, 0);
364 if (!n)
366 strv_free (req);
367 return NULL;
370 if (req[1])
371 n = find_elements (client, doc, n->children, req + 1, rc, NULL, NULL, NULL,
372 0, 0, NULL, 0);
374 if (*rc)
375 strv_free (req);
376 else
377 *result = req;
379 return n;
383 * Lists root element names; the value of the attribute "_name" of an element
384 * "element". If there's a target attribute both literal and non-literal
385 * element names will be added. This is the primary reason why XML entities
386 * cannot be used. There wouldn't be a way to get the literal an non-literal
387 * element paths.
389 gpg_error_t
390 list_root_elements (struct client_s *client, xmlDocPtr doc,
391 struct string_s ** result, int verbose, int with_target)
393 xmlNodePtr n = NULL;
394 struct slist_s *list = NULL;
395 int total, i;
396 struct string_s *string;
397 gpg_error_t rc = 0;
399 n = xmlDocGetRootElement (doc);
400 if (!n || !n->children)
401 return GPG_ERR_NO_DATA;
403 for (n = n->children; n; n = n->next)
405 xmlAttrPtr a;
406 xmlChar *val, *target;
407 struct slist_s *tlist;
408 char *tmp;
410 if (n->type != XML_ELEMENT_NODE)
411 continue;
413 a = xmlHasProp (n, (xmlChar *) "_name");
414 if (!a || !a->children->content)
415 continue;
417 val = xmlNodeGetContent (a->children);
418 if (!val)
420 rc = GPG_ERR_ENOMEM;
421 goto fail;
424 tmp = str_asprintf ("!%s%s", (char *) val,
425 verbose ? find_element_node (n->children) ? " +"
426 : "" : "");
428 if (!tmp)
430 xmlFree (val);
431 rc = GPG_ERR_ENOMEM;
432 goto fail;
435 tlist = slist_append (list, tmp);
436 if (!tlist)
438 xmlFree (val);
439 rc = GPG_ERR_ENOMEM;
440 goto fail;
443 list = tlist;
444 target = node_has_attribute (n, (xmlChar *) "target");
445 if (target)
447 char *t = NULL;
449 if (verbose)
451 char **req = NULL;
452 xmlNodePtr tnode = resolve_path (client, doc, target, &req, &rc);
454 if (rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
455 || rc == GPG_ERR_EACCES)
457 t = str_asprintf ("%s %s", (char *) val,
458 rc == GPG_ERR_ELOOP ? "O" :
459 rc == GPG_ERR_EACCES ? "P" : "E");
460 rc = 0;
462 else if (!rc)
464 struct string_s *realpath = NULL;
466 if (with_target)
468 rc = build_realpath (client, doc, (char *) target,
469 &realpath);
470 if (rc)
472 strv_free (req);
473 xmlFree (val);
474 xmlFree (target);
475 goto fail;
478 realpath = string_prepend (realpath, "T ");
481 t = str_asprintf ("%s%s%s%s", (char *) val,
482 (tnode
483 && find_element_node (tnode->children))
484 || realpath ? " " : "", tnode
485 && find_element_node (tnode->children) ?
486 "+" : "", realpath ? realpath->str : "");
488 if (realpath)
489 string_free (realpath, 1);
492 if (req)
493 strv_free (req);
495 else
496 t = str_dup ((char *) val);
498 if (!t || rc)
500 xmlFree (val);
501 xmlFree (target);
502 rc = rc ? rc : GPG_ERR_ENOMEM;
503 goto fail;
506 tlist = slist_append (list, t);
507 if (!tlist)
509 xmlFree (val);
510 xfree (t);
511 xmlFree (target);
512 rc = GPG_ERR_ENOMEM;
513 goto fail;
516 list = tlist;
519 xmlFree (val);
520 xmlFree (target);
523 total = slist_length (list);
524 if (!total)
525 return GPG_ERR_NO_DATA;
527 string = string_new (NULL);
528 if (!string)
530 rc = GPG_ERR_ENOMEM;
531 goto fail;
534 for (i = 0; i < total; i++)
536 char *val = slist_nth_data (list, i);
538 string_append_printf (string, "%s\n", val);
541 string = string_truncate (string, string->len - 1);
542 *result = string;
544 fail:
545 total = slist_length (list);
546 for (i = 0; i < total; i++)
547 xfree (slist_nth_data (list, i));
549 slist_free (list);
550 return rc;
554 * Prevents a sibling element past the current element path with the same
555 * element name.
557 static xmlNodePtr
558 find_stop_node (xmlNodePtr node)
560 xmlNodePtr n;
562 for (n = node->parent->children; n; n = n->next)
564 if (n == node)
565 return n->next;
568 return NULL;
571 xmlNodePtr
572 create_target_elements_cb (struct client_s *client, int verify,
573 xmlNodePtr node, char **path, gpg_error_t *rc,
574 void *data)
576 int i;
577 char **req = path;
578 xmlNodePtr parent = data;
580 for (i = 0; req[i] && *req[i]; i++)
582 xmlNodePtr n;
584 if (parent && node == parent)
586 *rc = GPG_ERR_CONFLICT;
587 return NULL;
590 is_literal_element (&req[i]);
592 if ((n = find_element (client, node, req[i],
593 find_stop_node (node), rc)) == NULL ||
594 (n && n->parent == node->parent))
597 if (!*rc)
598 *rc = create_new_element (client, verify, node, req[i], &node);
600 if (*rc)
601 return NULL;
603 else
604 node = n;
607 return node;
610 xmlNodePtr
611 find_text_node (xmlNodePtr node)
613 xmlNodePtr n = node;
615 if (n && n->type == XML_TEXT_NODE)
616 return n;
618 for (n = node; n; n = n->next)
620 if (n->type == XML_TEXT_NODE)
621 return n;
624 return NULL;
627 xmlNodePtr
628 create_elements_cb (struct client_s *client, int verify, xmlNodePtr node,
629 char **elements, gpg_error_t * rc, void *data)
631 int i;
632 char **req = elements;
634 if (node->type == XML_TEXT_NODE)
635 node = node->parent;
637 for (i = 0; req[i] && *req[i]; i++)
639 xmlNodePtr n;
642 * Strip the first '!' if needed. If there's another, it's an
643 * rc. The syntax has already been checked before calling this
644 * function.
646 is_literal_element (&req[i]);
647 n = find_element (client, node, req[i], find_stop_node (node), rc);
648 if (*rc)
649 return NULL;
652 * If the found element has the same parent as the current element,
653 * they are siblings and the new element needs to be created as a
654 * child of the current element (node).
656 if (n && n->parent == node->parent)
657 n = NULL;
659 if (!n)
661 *rc = create_new_element (client, 0, node, req[i], &node);
662 if (*rc)
663 return NULL;
665 else
666 node = n;
669 return node;
672 /* The root element is really req[0]. It is need as a pointer in case there is
673 * a target attribute so it can be updated. */
674 xmlNodePtr
675 find_root_element (struct client_s *client, xmlDocPtr doc, char ***req,
676 gpg_error_t * rc, int *target, int recursion_depth,
677 int stop)
679 xmlNodePtr n = xmlDocGetRootElement (doc);
680 int depth = 0;
681 char *root = str_dup (*req[0]);
682 int literal = is_literal_element (&root);
684 if (!root)
686 *rc = GPG_ERR_ENOMEM;
687 return NULL;
690 *rc = 0;
691 recursion_depth++;
693 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
695 xmlChar *t = xmlGetNodePath (n);
697 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
698 xmlFree (t);
699 xfree (root);
700 *rc = GPG_ERR_ELOOP;
701 return NULL;
704 while (n)
706 if (n->type == XML_ELEMENT_NODE)
708 if (depth == 0 && xmlStrEqual (n->name, (xmlChar *) "pwmd"))
710 n = n->children;
711 depth++;
712 continue;
715 if (depth == 1 && xmlStrEqual (n->name, (xmlChar *) "element"))
717 xmlChar *content = node_has_attribute (n, (xmlChar *) "_name");
719 if (!content)
720 continue;
722 if (xmlStrEqual (content, (xmlChar *) root))
724 char **nreq, **tmp = NULL;
726 *rc = acl_check(client, n);
727 if (*rc)
729 xmlFree (content);
730 xfree (root);
731 return NULL;
734 if (literal == 1)
736 xmlFree (content);
737 xfree (root);
738 return n;
741 xmlFree (content);
742 content = node_has_attribute (n, (xmlChar *) "target");
744 if (content && target)
745 *target = 1;
747 if (!content || stop)
749 if (content)
750 xmlFree (content);
752 xfree (root);
753 return n;
756 if (strchr ((char *) content, '\t'))
758 nreq = str_split ((char *) content, "\t", 0);
759 xmlFree (content);
761 #if 0
763 * FIXME ENOMEM
765 if (!nreq)
767 *rc = GPG_ERR_ENOMEM;
768 return NULL;
770 #endif
772 tmp = *req;
773 tmp = strv_catv (nreq, tmp + 1);
774 strv_free (nreq);
776 if (!tmp)
778 xfree (root);
779 *rc = GPG_ERR_ENOMEM;
780 return NULL;
783 strv_free (*req);
784 *req = tmp;
786 else
788 if (strv_printf (&tmp, "%s", content) == 0)
790 xmlFree (content);
791 xfree (root);
792 *rc = GPG_ERR_ENOMEM;
793 return NULL;
796 xmlFree (content);
797 nreq = *req;
798 nreq = strv_catv (tmp, nreq + 1);
799 strv_free (tmp);
801 if (!nreq)
803 *rc = GPG_ERR_ENOMEM;
804 xfree (root);
805 return NULL;
808 strv_free (*req);
809 *req = nreq;
812 xfree (root);
813 n = find_root_element (client, doc, req, rc, target,
814 recursion_depth, 0);
815 return n;
818 xmlFree (content);
822 n = n->next;
825 xfree (root);
826 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
827 return NULL;
830 xmlNodePtr
831 find_element (struct client_s *client, xmlNodePtr node, char *element,
832 xmlNodePtr stop, gpg_error_t *rc)
834 xmlNodePtr n;
836 *rc = 0;
838 if (!node || !element)
839 return NULL;
841 for (n = node; n; n = n->next)
843 if (n->type != XML_ELEMENT_NODE)
844 continue;
846 if (n == stop)
847 break;
849 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
851 if (a && xmlStrEqual (a, (xmlChar *) element))
853 xmlFree (a);
855 *rc = acl_check(client, n);
856 if (*rc)
857 n = NULL;
859 return n;
862 xmlFree (a);
865 return NULL;
868 xmlChar *
869 node_has_attribute (xmlNodePtr n, xmlChar * attr)
871 xmlAttrPtr a = xmlHasProp (n, attr);
873 if (!a)
874 return NULL;
876 if (!a->children || !a->children->content)
877 return NULL;
879 return xmlGetProp (n, attr);
882 static int
883 element_to_literal (char **element)
885 char *p = str_asprintf ("!%s", *element);
887 if (!p)
888 return 0;
890 xfree (*element);
891 *element = p;
892 return 1;
895 /* Resolves elements in 'req' one at a time. It's recursive in case of
896 * "target" attributes. */
897 xmlNodePtr
898 find_elements (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
899 char **req, gpg_error_t * rc, int *target,
900 xmlNodePtr (*found_fn) (struct client_s *, xmlNodePtr, char **,
901 gpg_error_t *, char **, void *),
902 xmlNodePtr (*not_found_fn) (struct client_s *, int, xmlNodePtr,
903 char **, gpg_error_t *, void *),
904 int is_list_command, int recursion_depth, void *data, int stop)
906 xmlNodePtr n, last, last_node;
907 char **p;
908 int found = 0;
910 *rc = 0;
911 recursion_depth++;
913 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
915 xmlChar *t = xmlGetNodePath (node);
917 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
918 xmlFree (t);
919 recursion_depth--;
920 *rc = GPG_ERR_ELOOP;
921 return NULL;
924 for (last_node = last = n = node, p = req; *p; p++)
926 xmlNodePtr tmp;
927 char *t;
928 int literal;
930 if (!*(*p))
932 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
933 return NULL;
936 t = str_dup (*p);
937 if (!t)
939 *rc = GPG_ERR_ENOMEM;
940 return NULL;
943 literal = is_literal_element (&t);
944 n = find_element (client, last, t, NULL, rc);
945 xfree (t);
947 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
948 return NULL;
950 if (!n)
952 if (not_found_fn)
953 return not_found_fn (client, 0,
954 found ? last_node : last_node->parent, p,
955 rc, data);
957 if (!*rc)
958 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
960 return NULL;
963 last = n->children;
964 last_node = n;
965 found = 1;
967 if (literal == 0)
969 xmlChar *content = node_has_attribute (n, (xmlChar *) "target");
970 char **nreq = NULL, **nnreq;
972 if (!content)
974 if (is_list_command == 1)
976 if (element_to_literal (&(*p)) == 0)
978 *rc = GPG_ERR_ENOMEM;
979 return NULL;
983 continue;
986 if (target)
987 *target = 1;
989 if (!*(p + 1) && stop)
991 xmlFree (content);
992 return n;
995 if (strchr ((char *) content, '\t') != NULL)
997 if ((nreq = str_split ((char *) content, "\t", 0)) == NULL)
999 xmlFree (content);
1000 *rc = GPG_ERR_INV_VALUE;
1001 return NULL;
1004 else
1006 if ((nreq = str_split ((char *) content, " ", 0)) == NULL)
1008 xmlFree (content);
1009 *rc = GPG_ERR_INV_VALUE;
1010 return NULL;
1014 xmlFree (content);
1015 tmp = find_root_element (client, doc, &nreq, rc, target, 0, 0);
1017 if (!tmp)
1019 strv_free (nreq);
1020 return NULL;
1023 if (found_fn)
1025 found_fn (client, tmp, nreq, rc, p + 1, data);
1027 if (*rc)
1029 strv_free (nreq);
1030 return NULL;
1034 if (!*(nreq + 1) && !*(p + 1))
1036 strv_free (nreq);
1037 return tmp;
1040 nnreq = strv_catv (nreq + 1, p + 1);
1041 strv_free (nreq);
1043 // FIXME ENOMEM
1044 if (!nnreq || !*nnreq)
1046 if (nnreq)
1047 strv_free (nnreq);
1049 return tmp;
1052 if (tmp->children)
1053 n = find_elements (client, doc, tmp->children, nnreq, rc, NULL,
1054 found_fn, not_found_fn, is_list_command,
1055 recursion_depth, data, stop);
1056 else
1058 strv_free (nnreq);
1060 if (not_found_fn)
1061 return not_found_fn (client, 0, tmp, p + 1, rc, data);
1063 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1064 return NULL;
1067 if (*(p + 1))
1069 char **zz = p + 1, **qq = nnreq;
1071 if (strv_length (nnreq) > strv_length (p + 1))
1072 qq = nnreq + 1;
1074 for (; *qq && *zz; zz++)
1076 xfree (*zz);
1077 *zz = str_dup (*qq++);
1079 if (!*zz)
1081 *rc = GPG_ERR_ENOMEM;
1082 n = NULL;
1083 break;
1088 strv_free (nnreq);
1089 return n;
1093 return n;
1096 static int
1097 update_element_list (struct element_list_s *elements)
1099 char *line;
1100 struct slist_s *l;
1102 if (!elements || !elements->elements)
1103 return 1;
1105 line = strv_join ("\t", elements->elements);
1107 if (!line)
1108 return 0;
1110 strv_free (elements->elements);
1111 elements->elements = NULL;
1112 l = slist_append (elements->list, line);
1114 if (!l)
1115 return 0;
1117 elements->list = l;
1118 return 1;
1121 static gpg_error_t
1122 path_list_recurse (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1123 struct element_list_s *elements)
1125 gpg_error_t rc = 0;
1126 xmlNodePtr n;
1127 gpg_error_t error_flag = 0;
1129 for (n = node; n; n = n->next)
1131 xmlChar *target = NULL;
1132 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
1133 gpg_error_t err = 0;
1134 char *path = NULL;
1136 rc = 0;
1137 if (!a)
1138 continue;
1140 if (n->type != XML_ELEMENT_NODE)
1141 goto children;
1143 rc = acl_check(client, n);
1145 if (elements->verbose)
1147 if (strv_printf
1148 (&elements->elements, "%s\t!%s%s%s", elements->prefix, a,
1149 !rc && find_element_node (n->children) ? " +" : "",
1150 rc == GPG_ERR_EACCES ? " P" : "") == 0)
1152 xmlFree (a);
1153 return GPG_ERR_ENOMEM;
1156 else
1157 if (strv_printf (&elements->elements, "%s\t!%s", elements->prefix, a)
1158 == 0)
1160 xmlFree (a);
1161 return GPG_ERR_ENOMEM;
1164 if (update_element_list (elements) == 0)
1166 xmlFree (a);
1167 return GPG_ERR_ENOMEM;
1171 if (rc == GPG_ERR_EACCES)
1173 xmlFree(a);
1174 error_flag = rc;
1175 continue;
1177 else if (rc)
1179 xmlFree (a);
1180 return rc;
1183 target = node_has_attribute (n, (xmlChar *) "target");
1184 if (target)
1186 char *tmp;
1187 char *save = elements->prefix;
1188 int r = elements->resolving;
1189 char **req = NULL;
1190 xmlNodePtr tnode;
1191 struct string_s *realpath = NULL;
1193 tnode = resolve_path (client, doc, target, &req, &rc);
1194 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_ELEMENT_NOT_FOUND
1195 || rc == GPG_ERR_EACCES)
1197 if (rc == GPG_ERR_ELOOP)
1199 xmlChar *t = xmlGetNodePath (n);
1201 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1202 xmlFree (t);
1205 if (elements->verbose)
1207 error_flag = err = rc;
1208 rc = 0;
1211 else if (!elements->verbose && rc)
1213 xmlFree (a);
1214 xmlFree (target);
1215 return rc;
1218 path = str_asprintf("%s\t%s", elements->prefix, a);
1219 rc = validate_target_attribute (client, client->doc, path, tnode);
1220 xfree (path);
1221 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
1222 || rc == GPG_ERR_ELEMENT_NOT_FOUND)
1224 if (rc != GPG_ERR_ELEMENT_NOT_FOUND)
1225 error_flag = err = rc;
1227 rc = 0;
1229 else if (rc)
1231 xmlFree (a);
1232 xmlFree (target);
1233 return rc;
1236 if (err)
1238 strv_printf (&elements->elements, "%s\t%s %s", elements->prefix,
1240 err == GPG_ERR_ELOOP ? "O" :
1241 err == GPG_ERR_EACCES ? "P" : "E");
1244 if (!err && elements->with_target)
1246 rc = build_realpath (client, doc, (char *) target, &realpath);
1247 if (rc)
1249 xmlFree (a);
1250 xmlFree (target);
1251 return rc;
1254 realpath = string_prepend (realpath, "T ");
1257 if (!err && elements->verbose)
1259 if (!strv_printf (&elements->elements, "%s\t%s%s%s%s",
1260 elements->prefix, a,
1261 (tnode && find_element_node (tnode->children))
1262 || realpath ? " " : "", tnode
1263 && find_element_node (tnode->children) ? "+" :
1264 "", realpath ? realpath->str : ""))
1266 xmlFree (a);
1267 xmlFree (target);
1268 return GPG_ERR_ENOMEM;
1271 else if (!err)
1272 if (!strv_printf
1273 (&elements->elements, "%s\t%s", elements->prefix, a))
1275 xmlFree (a);
1276 xmlFree (target);
1277 return GPG_ERR_ENOMEM;
1280 if (realpath)
1281 string_free (realpath, 1);
1283 tmp = strv_join ("\t", elements->elements);
1284 if (!tmp)
1286 xmlFree (a);
1287 xmlFree (target);
1288 return GPG_ERR_ENOMEM;
1291 if (update_element_list (elements) == 0)
1293 xfree (tmp);
1294 xmlFree (a);
1295 xmlFree (target);
1296 return GPG_ERR_ENOMEM;
1299 if (!err && elements->recurse)
1301 /* Prune element flags. */
1302 if (elements->verbose && strchr (tmp, ' '))
1304 char *p;
1306 for (p = tmp; *p; p++)
1308 if (*p == ' ')
1310 *p = 0;
1311 break;
1316 elements->prefix = tmp;
1317 elements->resolving = 1;
1318 rc = create_path_list (client, doc, elements, (char *) target);
1319 elements->resolving = r;
1320 elements->prefix = save;
1322 if (rc && gpg_err_code (rc) != GPG_ERR_ELOOP
1323 && gpg_err_code(rc) != GPG_ERR_EACCES)
1325 xfree (tmp);
1326 xmlFree (target);
1327 xmlFree (a);
1328 return rc;
1331 error_flag = err = rc;
1332 rc = 0;
1335 xfree (tmp);
1336 xmlFree (target);
1339 children:
1340 if (n->children && elements->recurse && err != GPG_ERR_EACCES)
1342 char *tmp = str_asprintf ("%s\t!%s", elements->prefix, a);
1343 char *save = elements->prefix;
1345 if (!tmp)
1347 xmlFree (a);
1348 return GPG_ERR_ENOMEM;
1351 elements->prefix = tmp;
1352 rc = path_list_recurse (client, doc, n->children, elements);
1353 xfree (elements->prefix);
1354 elements->prefix = save;
1356 if (rc)
1358 if (gpg_err_code(rc) == GPG_ERR_ELOOP
1359 || gpg_err_code (rc) == GPG_ERR_EACCES
1360 || gpg_err_code (rc) == GPG_ERR_ELEMENT_NOT_FOUND)
1362 error_flag = err = rc;
1363 rc = 0;
1365 else
1367 xmlFree (a);
1368 return rc;
1373 xmlFree (a);
1376 return error_flag == GPG_ERR_ELOOP || error_flag == GPG_ERR_EACCES
1377 ? error_flag : rc;
1380 gpg_error_t
1381 add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
1382 const char *value)
1384 char *buf;
1385 gpg_error_t rc = 0;
1387 if (client && name && !strcmp (name, "target"))
1389 rc = is_element_owner (client, node);
1390 if (rc)
1391 return rc;
1394 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
1395 return GPG_ERR_BAD_DATA;
1397 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
1399 xmlChar *acl = node_has_attribute (node, (xmlChar *) "_acl");
1401 if (!acl)
1403 char *user = create_acl_user (client);
1405 if (user)
1407 rc = add_attribute (client, node, (char *) "_acl", user);
1408 xfree (user);
1411 return rc;
1414 xmlFree (acl);
1417 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
1418 return 0;
1420 buf = str_asprintf ("%li", time (NULL));
1421 rc = add_attribute (client, node, "_mtime", buf);
1422 xfree (buf);
1423 return rc;
1427 * From the element path 'path', find sub-nodes and append them to the list.
1429 gpg_error_t
1430 create_path_list (struct client_s *client, xmlDocPtr doc,
1431 struct element_list_s * elements, char *path)
1433 gpg_error_t rc;
1434 char **req, **req_orig;
1435 xmlNodePtr n;
1436 int a_target = 0;
1438 req = str_split (path, "\t", 0);
1439 if (!req)
1441 req = str_split (path, " ", 0);
1442 if (!req)
1443 return GPG_ERR_SYNTAX;
1446 req_orig = strv_dup (req);
1447 if (!req_orig)
1449 rc = GPG_ERR_ENOMEM;
1450 goto fail;
1453 n = find_root_element (client, doc, &req, &rc, &a_target, 0, 0);
1454 if ((rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
1455 || rc == GPG_ERR_EACCES)
1456 && elements->verbose && a_target)
1458 if (rc != GPG_ERR_EACCES)
1459 rc = 0;
1461 goto done;
1464 if (rc == GPG_ERR_EACCES)
1465 goto done;
1467 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1469 rc = 0;
1470 goto fail;
1472 else if (!n)
1473 goto fail;
1475 if (a_target == 1)
1477 xfree (*req);
1478 *req = str_dup (*req_orig);
1481 if (*(req + 1))
1483 int e_target = 0;
1486 find_elements (client, doc, n->children, req + 1, &rc, &e_target,
1487 NULL, NULL, 1, 0, NULL, 0);
1489 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1491 rc = 0;
1492 goto fail;
1494 else if (!n)
1495 goto fail;
1498 done:
1499 if (!elements->prefix)
1502 * FIXME
1504 * If any req_orig element contains no target the element should be
1505 * prefixed with the literal character. Not really crucial if the
1506 * client isn't human because child elements are prefixed for the
1507 * current path. But may be confusing if editing by hand.
1509 elements->prefix = strv_join ("\t", req_orig);
1511 if (!elements->prefix)
1513 rc = GPG_ERR_ENOMEM;
1514 goto fail;
1517 if (elements->verbose)
1519 int ret;
1520 struct string_s *realpath = NULL;
1521 gpg_error_t allowed = rc;
1523 rc = 0;
1525 if (!allowed && a_target && elements->with_target)
1527 rc = build_realpath (client, doc, path, &realpath);
1528 if (rc)
1529 goto fail;
1531 realpath = string_prepend (realpath, "T ");
1534 ret = strv_printf (&elements->elements, "%s%s%s%s%s",
1535 elements->prefix,
1536 (!allowed && n && find_element_node (n->children))
1537 || realpath ? " " : "",
1538 (!allowed && n && find_element_node (n->children)) ? "+" : "",
1539 !allowed && realpath ? realpath->str : "",
1540 allowed ? " P" : "");
1541 string_free (realpath, 1);
1542 if (!ret)
1544 rc = GPG_ERR_ENOMEM;
1545 goto fail;
1548 else if (strv_printf (&elements->elements, "%s", elements->prefix) == 0)
1550 rc = GPG_ERR_ENOMEM;
1551 goto fail;
1554 if (update_element_list (elements) == 0)
1556 rc = GPG_ERR_ENOMEM;
1557 goto fail;
1561 rc = path_list_recurse (client, doc, n ? n->children : n, elements);
1563 fail:
1564 if (req_orig)
1565 strv_free (req_orig);
1567 strv_free (req);
1568 return rc;
1571 gpg_error_t
1572 recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
1573 xmlNodeSetPtr nodes, xmlChar * value,
1574 xmlBufferPtr * result, int cmd, const xmlChar * attr)
1576 int i = value ? nodes->nodeNr - 1 : 0;
1577 xmlBufferPtr buf;
1579 buf = xmlBufferCreate ();
1581 if (!buf)
1582 return GPG_ERR_ENOMEM;
1584 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
1586 xmlNodePtr n = nodes->nodeTab[i];
1587 gpg_error_t rc;
1589 if (!n)
1590 continue;
1592 if (!value && !attr)
1594 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
1596 *result = buf;
1597 return GPG_ERR_BAD_DATA;
1600 continue;
1603 if (!attr)
1605 xmlNodeSetContent (n, value);
1606 rc = update_element_mtime (client, n);
1608 if (rc)
1609 return rc;
1611 else
1613 if (!cmd)
1614 rc = add_attribute (client, n, (char *) attr, (char *) value);
1615 else
1616 rc = delete_attribute (client, n, attr);
1618 if (rc)
1619 return rc;
1623 *result = buf;
1624 return 0;
1627 static gpg_error_t
1628 convert_root_element (struct client_s *client, xmlNodePtr n)
1630 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1631 gpg_error_t rc;
1633 if (a)
1635 xmlFree (a);
1636 xmlChar *t = xmlGetNodePath (n);
1638 log_write (_
1639 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1641 xmlFree (t);
1642 return GPG_ERR_AMBIGUOUS_NAME;
1645 a = xmlGetProp (n, (xmlChar *) "name");
1647 if (a)
1649 rc = add_attribute (client, n, "_name", (char *) a);
1650 xmlFree (a);
1652 if (rc)
1653 return rc;
1655 rc = delete_attribute (client, n, (xmlChar *) "name");
1657 if (rc)
1658 return rc;
1660 xmlNodeSetName (n, (xmlChar *) "element");
1663 return 0;
1666 gpg_error_t
1667 delete_attribute (struct client_s *client, xmlNodePtr n, const xmlChar * name)
1669 xmlAttrPtr a;
1670 gpg_error_t rc = 0;
1672 if ((a = xmlHasProp (n, name)) == NULL)
1673 return GPG_ERR_NOT_FOUND;
1675 if (xmlRemoveProp (a) == -1)
1676 return GPG_ERR_BAD_DATA;
1678 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
1680 char *user = create_acl_user (client);
1682 rc = add_attribute (client, n, (char *) "_acl", user);
1683 xfree (user);
1685 if (rc)
1686 return rc;
1689 return update_element_mtime (client, n);
1692 static gpg_error_t
1693 convert_elements_recurse (struct client_s *client, xmlDocPtr doc,
1694 xmlNodePtr n, unsigned depth)
1696 gpg_error_t rc;
1698 depth++;
1700 for (n = n->children; n; n = n->next)
1702 if (n->type == XML_ELEMENT_NODE)
1704 if (depth > 1)
1706 xmlChar *a = NULL;
1708 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1710 xmlChar *t = xmlGetNodePath (n);
1712 log_write (_
1713 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1715 xmlFree (t);
1716 return GPG_ERR_AMBIGUOUS_NAME;
1719 a = xmlGetProp (n, (xmlChar *) "_name");
1720 if (a)
1722 xmlFree (a);
1723 xmlChar *t = xmlGetNodePath (n);
1725 log_write (_
1726 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1728 xmlFree (t);
1729 return GPG_ERR_AMBIGUOUS_NAME;
1732 xmlChar *tmp = xmlStrdup (n->name);
1734 if (!tmp)
1735 return GPG_ERR_ENOMEM;
1737 xmlNodeSetName (n, (xmlChar *) "element");
1738 rc = add_attribute (client, n, "_name", (char *) tmp);
1739 xmlFree (tmp);
1741 if (rc)
1742 return rc;
1744 else
1746 rc = convert_root_element (client, n);
1748 if (rc)
1749 return rc;
1753 if (n->children)
1755 rc = convert_elements_recurse (client, doc, n, depth);
1757 if (rc)
1758 return rc;
1762 return 0;
1765 /* Renames ALL elements to the new "element" name. Existing element names are
1766 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1767 * elements can contain common characters that the XML parser barfs on (an
1768 * email address for example. */
1769 gpg_error_t
1770 convert_pre_212_elements (xmlDocPtr doc)
1772 xmlNodePtr n = xmlDocGetRootElement (doc);
1774 log_write (_("Converting pre 2.12 data file..."));
1775 return convert_elements_recurse (NULL, doc, n, 0);
1778 gpg_error_t
1779 validate_import (struct client_s *client, xmlNodePtr node)
1781 gpg_error_t rc = 0;
1783 if (!node)
1784 return 0;
1786 for (xmlNodePtr n = node; n; n = n->next)
1788 if (n->type == XML_ELEMENT_NODE)
1790 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1792 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1794 if (!a)
1796 xmlChar *t = xmlGetNodePath (n);
1798 log_write (_("Missing attribute '_name' at %s."), t);
1799 xmlFree (t);
1800 return GPG_ERR_INV_VALUE;
1803 if (!valid_xml_element (a))
1805 xmlChar *t = xmlGetNodePath (n);
1807 log_write (_("'%s' is not a valid element name at %s."), a,
1809 xmlFree (a);
1810 xmlFree (t);
1811 return GPG_ERR_INV_VALUE;
1814 xmlFree (a);
1815 a = xmlGetProp (n, (xmlChar *) "_ctime");
1816 if (!a)
1817 attr_ctime (client, n);
1819 xmlFree (a);
1820 a = xmlGetProp (n, (xmlChar *) "_mtime");
1821 if (!a)
1822 update_element_mtime (client, n);
1823 xmlFree (a);
1825 else
1827 xmlChar *t = xmlGetNodePath (n);
1829 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1830 n->name, t);
1831 xmlFree (t);
1832 continue;
1836 if (n->children)
1838 rc = validate_import (client, n->children);
1840 if (rc)
1841 return rc;
1845 return rc;
1848 gpg_error_t
1849 update_element_mtime (struct client_s *client, xmlNodePtr n)
1851 return add_attribute (client, n, NULL, NULL);
1854 gpg_error_t
1855 unlink_node (struct client_s *client, xmlNodePtr n)
1857 gpg_error_t rc = 0;
1859 if (!n)
1860 return rc;
1862 if (n->parent)
1863 rc = update_element_mtime (client, n->parent);
1865 xmlUnlinkNode (n);
1866 return rc;
1869 gpg_error_t
1870 parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1872 xmlDocPtr doc;
1874 xmlResetLastError ();
1875 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1876 if (!doc && xmlGetLastError ())
1877 return GPG_ERR_BAD_DATA;
1879 *result = doc;
1880 return !doc ? GPG_ERR_ENOMEM : 0;
1883 static xmlNodePtr
1884 realpath_elements_cb (struct client_s *client, xmlNodePtr node, char **target,
1885 gpg_error_t * rc, char **req_orig, void *data)
1887 char *path = *(char **) data;
1888 char *tmp = NULL, *result;
1890 if (path)
1892 xfree (path);
1893 *(char **) data = NULL;
1896 path = strv_join ("\t", target);
1898 if (!path)
1900 *rc = GPG_ERR_ENOMEM;
1901 return NULL;
1904 if (req_orig)
1906 tmp = strv_join ("\t", req_orig);
1908 if (!tmp)
1910 xfree (path);
1911 *rc = GPG_ERR_ENOMEM;
1912 return NULL;
1916 if (tmp && *tmp)
1917 result = str_asprintf ("%s\t%s", path, tmp);
1918 else
1919 result = str_dup (path);
1921 if (!result)
1923 *rc = GPG_ERR_ENOMEM;
1924 xfree (path);
1925 xfree (tmp);
1926 return NULL;
1929 xfree (path);
1930 xfree (tmp);
1931 *(char **) data = result;
1932 return node;
1935 gpg_error_t
1936 build_realpath (struct client_s *client, xmlDocPtr doc, char *line,
1937 struct string_s ** result)
1939 gpg_error_t rc;
1940 char **req;
1941 char *t;
1942 int i;
1943 xmlNodePtr n;
1944 struct string_s *string;
1945 char *rp = NULL;
1947 if (strchr (line, '\t') != NULL)
1949 if ((req = str_split (line, "\t", 0)) == NULL)
1950 return GPG_ERR_SYNTAX;
1952 else
1954 if ((req = str_split (line, " ", 0)) == NULL)
1955 return GPG_ERR_SYNTAX;
1958 n = find_root_element (client, doc, &req, &rc, NULL, 0, 0);
1959 if (!n)
1961 strv_free (req);
1962 return rc;
1965 rp = strv_join ("\t", req);
1966 if (!rp)
1968 strv_free (req);
1969 return GPG_ERR_ENOMEM;
1972 if (req[1])
1974 n = find_elements (client, doc, n->children, req + 1, &rc, NULL,
1975 realpath_elements_cb, NULL, 0, 0, &rp, 0);
1976 if (!n)
1978 xfree (rp);
1979 strv_free (req);
1980 return rc;
1984 string = string_new (rp);
1985 xfree (rp);
1986 strv_free (req);
1987 if (!string)
1988 return GPG_ERR_ENOMEM;
1990 again:
1991 for (i = 0, t = string->str + i; *t; t++, i++)
1993 if ((!i && *t != '!') || (*t == '\t' && *(t + 1) && *(t + 1) != '!'))
1995 struct string_s *s = string_insert_c (string, !i ? i++ : ++i, '!');
1997 if (!s)
1999 string_free (string, 1);
2000 return GPG_ERR_ENOMEM;
2003 string = s;
2004 goto again;
2008 *result = string;
2009 return rc;
2012 #if 0
2013 static char *
2014 node_to_element_path (xmlNodePtr node)
2016 xmlNodePtr n;
2017 struct string_s *str = string_new ("");
2018 char *result;
2020 for (n = node; n; n = n->parent)
2022 xmlNodePtr child;
2024 for (child = n; child; child = child->next)
2026 if (child->type != XML_ELEMENT_NODE)
2027 continue;
2029 xmlChar *name = node_has_attribute (n, (xmlChar *) "_name");
2030 if (name)
2032 str = string_prepend (str, (char *) name);
2033 xmlFree (name);
2034 name = node_has_attribute (n, (xmlChar *) "target");
2035 if (name)
2036 str = string_prepend (str, "\t");
2037 else
2038 str = string_prepend (str, "\t!");
2039 xmlFree (name);
2041 break;
2045 str = string_erase (str, 0, 1);
2046 result = str->str;
2047 string_free (str, 0);
2048 return result;
2050 #endif
2053 * Recurse the element tree beginning at 'node' and find elements who point
2054 * back to 'src' or 'dst'. Also follows target attributes.
2056 static gpg_error_t
2057 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
2058 xmlNodePtr src, xmlNodePtr dst, unsigned depth,
2059 int is_target)
2061 xmlNodePtr n;
2062 gpg_error_t rc = 0;
2064 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
2065 return gpg_error (GPG_ERR_ELOOP);
2067 for (n = node; n; n = n->next)
2069 xmlChar *target;
2071 if (n->type != XML_ELEMENT_NODE)
2072 continue;
2074 if (n == src || n == dst)
2075 return GPG_ERR_ELOOP;
2077 target = node_has_attribute (n, (xmlChar *) "target");
2078 if (target)
2080 xmlNodePtr tmp;
2081 char **result = NULL;
2083 tmp = resolve_path (client, doc, target, &result, &rc);
2084 xmlFree (target);
2085 strv_free (result);
2086 if (!rc)
2088 rc = find_child_to_target (client, doc, tmp, src, dst, ++depth,
2090 depth--;
2093 if (rc && gpg_err_code (rc) != GPG_ERR_ELEMENT_NOT_FOUND)
2094 return rc;
2096 if (is_target)
2097 break;
2099 continue;
2102 if (n->children)
2104 rc = find_child_to_target (client, doc, n->children, src, dst,
2105 ++depth,0);
2106 depth--;
2107 if (rc)
2108 return rc;
2111 if (is_target)
2112 break;
2115 return rc;
2118 static gpg_error_t
2119 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
2121 xmlNodePtr n;
2122 gpg_error_t rc = 0;
2124 for (n = src; n; n = n->next)
2126 if (n->type != XML_ELEMENT_NODE)
2127 continue;
2129 if (n == dst)
2131 rc = GPG_ERR_ELOOP;
2132 break;
2135 rc = find_child_of_parent (doc, n->children, dst);
2138 return rc;
2141 static gpg_error_t
2142 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
2144 xmlNodePtr n;
2145 gpg_error_t rc = 0;
2147 for (n = node; n; n = n->parent)
2149 if (n->type != XML_ELEMENT_NODE)
2151 xmlNodePtr tmp;
2153 for (tmp = n->next; tmp; n = n->next)
2155 if (n->type != XML_ELEMENT_NODE)
2156 continue;
2158 if (tmp == dst)
2159 return GPG_ERR_ELOOP;
2163 if (n == dst)
2164 return GPG_ERR_ELOOP;
2167 return rc;
2170 gpg_error_t
2171 validate_target_attribute (struct client_s *client, xmlDocPtr doc,
2172 const char *src, xmlNodePtr dst_node)
2174 gpg_error_t rc;
2175 xmlNodePtr src_node;
2176 char **src_req = NULL;
2178 src_node = resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
2179 if (rc)
2180 goto fail;
2182 /* A destination element is a child of the source element. */
2183 rc = find_child_of_parent (doc, src_node->children, dst_node);
2184 if (rc)
2185 goto fail;
2187 /* The destination element is a parent of the source element. */
2188 rc = find_parent_of_child (doc, src_node->parent, dst_node);
2189 if (rc)
2190 goto fail;
2192 /* A destination child element contains a target to the source element. */
2193 rc = find_child_to_target (client, doc, dst_node->children, src_node,
2194 dst_node, 0, 0);
2195 if (rc)
2196 goto fail;
2198 fail:
2199 strv_free (src_req);
2200 return rc;
2203 /* The owner of the element is the first user listed in the _acl attribute
2204 * list. acl_check() should be called before calling this function. An empty
2205 * ACL is an error if the client is not invoking_user.
2207 gpg_error_t
2208 is_element_owner (struct client_s *client, xmlNodePtr n)
2210 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
2211 char **users;
2212 gpg_error_t rc = GPG_ERR_EACCES;
2214 if (!acl || !*acl)
2216 xmlFree (acl);
2217 return peer_is_invoker (client);
2220 users = str_split((char *)acl, ",", 0);
2221 if (users && *users)
2223 char *user;
2225 #ifdef WITH_GNUTLS
2226 if (client->thd->remote)
2227 user = str_asprintf ("#%s", client->thd->tls->fp);
2228 else
2229 user = get_username (client->thd->peer->uid);
2230 #else
2231 user = get_username (client->thd->peer->uid);
2232 #endif
2234 if (*user == '#')
2235 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
2236 else
2237 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
2239 if (rc)
2240 rc = peer_is_invoker (client);
2242 xfree (user);
2245 strv_free (users);
2246 return rc;