LIST command recursion loop fixes.
[pwmd.git] / src / xml.c
bloba82a86994017e712f9e48eed5ccb34dd8edcefc1
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 len = wcslen (wc);
93 for (c = 0; c < len; c++)
95 if (iswspace(wc[c]))
97 xfree (wc);
98 return 0;
102 xfree (wc);
103 return 1;
107 valid_element_path (char **path, int with_content)
109 char **dup = NULL, **p;
111 if (!path || !*path)
112 return 0;
114 /* Save some memory by not duplicating the element content. */
115 if (with_content)
117 int i, t = strv_length (path);
119 for (i = 0; i < t - 1; i++)
121 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
123 if (!tmp)
125 strv_free (dup);
126 return 0;
129 dup = tmp;
130 dup[i] = str_dup (path[i]);
131 dup[i + 1] = NULL;
134 else
135 dup = strv_dup (path);
137 if (!dup)
138 return 0;
140 for (p = dup; *p && *(*p); p++)
142 is_literal_element (&(*p));
143 if (!valid_xml_element ((xmlChar *) * p))
145 strv_free (dup);
146 return 0;
150 strv_free (dup);
151 return 1;
154 gpg_error_t
155 attr_ctime (xmlNodePtr n)
157 char *buf = str_asprintf ("%li", time (NULL));
158 gpg_error_t rc;
160 if (!buf)
161 return GPG_ERR_ENOMEM;
163 rc = add_attribute (n, "_ctime", buf);
164 xfree (buf);
165 return rc;
168 // FIXME add parameter to want RW or RO access to the XML node.
169 static gpg_error_t
170 acl_check (struct client_s *client, xmlNodePtr n)
172 gpg_error_t rc = GPG_ERR_EPERM;
173 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
174 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
175 char **p;
176 int allowed = 0;
178 if (!acl || !users || !*users)
180 strv_free(users);
181 return peer_is_invoker(client);
184 if (!peer_is_invoker(client))
185 return 0;
187 for (p = users; *p; p++)
189 #ifdef WITH_GNUTLS
190 rc = acl_check_common (client, *p,
191 client->thd->remote ? 0 : client->thd->peer->uid,
192 client->thd->remote ? 0 : client->thd->peer->gid,
193 &allowed);
194 #else
195 rc = acl_check_common (client, *p, client->thd->peer->uid,
196 client->thd->peer->gid, &allowed);
197 #endif
200 xmlFree(acl);
201 strv_free(users);
202 if (rc)
203 return rc;
205 return allowed ? 0 : GPG_ERR_EPERM;
208 static char *
209 create_acl_user (struct client_s *client)
211 #ifdef WITH_GNUTLS
212 if (client->thd->remote)
213 return str_asprintf ("#%s", client->thd->tls->fp);
214 #endif
216 return get_username (client->thd->peer->uid);
219 static gpg_error_t
220 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
221 const char *name, xmlNodePtr * result)
223 xmlNodePtr n;
224 gpg_error_t rc;
226 // Allow any client to create a non-existing root element.
227 if (parent->parent->type != XML_DOCUMENT_NODE)
229 rc = acl_check(client, parent);
230 if (rc)
231 return rc;
234 n = xmlNewNode (NULL, (xmlChar *) "element");
235 if (!n)
236 return GPG_ERR_ENOMEM;
238 rc = add_attribute (n, "_name", name);
239 if (!rc)
240 rc = attr_ctime (n);
242 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
244 rc = peer_is_invoker (client);
245 if (rc == GPG_ERR_EPERM)
246 rc = is_element_owner (client, parent);
249 if (!rc)
251 xmlNodePtr p = xmlAddChild (parent, n);
252 char *user = create_acl_user (client);
254 if (result)
255 *result = p;
257 rc = add_attribute(p, "_acl", user);
258 xfree (user);
260 else
261 xmlFreeNode (n);
263 return rc;
266 gpg_error_t
267 new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
269 xmlNodePtr root = xmlDocGetRootElement (doc);
270 char *p = name;
272 if (!p || !root)
273 return GPG_ERR_BAD_DATA;
275 if (*p == '!')
276 p++;
278 if (!valid_xml_element ((xmlChar *) p))
279 return GPG_ERR_INV_VALUE;
281 return create_new_element (client, 0, root, p, NULL);
284 static xmlDocPtr
285 create_dtd ()
287 xmlDocPtr doc;
288 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
290 if (!wr)
291 return NULL;
293 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
294 goto fail;
296 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
297 goto fail;
299 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
300 (xmlChar *) "(element)") == -1)
301 goto fail;
303 xmlTextWriterEndDTDElement (wr);
305 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
306 (xmlChar *) "_name CDATA #REQUIRED") ==
308 goto fail;
310 xmlTextWriterEndDTDAttlist (wr);
311 xmlTextWriterEndDTD (wr);
313 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
314 goto fail;
316 xmlTextWriterEndElement (wr);
317 xmlTextWriterEndDocument (wr);
318 xmlFreeTextWriter (wr);
319 return doc;
321 fail:
322 xmlTextWriterEndDocument (wr);
323 xmlFreeTextWriter (wr);
324 xmlFreeDoc (doc);
325 return NULL;
328 xmlDocPtr
329 new_document ()
331 return create_dtd ();
334 xmlNodePtr
335 find_element_node (xmlNodePtr node)
337 xmlNodePtr n = node;
339 if (n && n->type == XML_ELEMENT_NODE)
340 return n;
342 for (n = node; n; n = n->next)
344 if (n->type == XML_ELEMENT_NODE)
345 return n;
348 return NULL;
351 static xmlNodePtr
352 resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
353 char ***result, gpg_error_t * rc)
355 xmlNodePtr n;
356 char **req;
358 req = str_split ((char *) path, "\t", 0);
359 if (!req)
361 *rc = GPG_ERR_ENOMEM;
362 return NULL;
365 n = find_root_element (client, doc, &req, rc, NULL, 0, 0);
366 if (!n)
368 strv_free (req);
369 return NULL;
372 if (req[1])
373 n = find_elements (client, doc, n->children, req + 1, rc, NULL, NULL, NULL,
374 0, 0, NULL, 0);
376 if (*rc)
377 strv_free (req);
378 else
379 *result = req;
381 return n;
385 * Lists root element names; the value of the attribute "_name" of an element
386 * "element". If there's a target attribute both literal and non-literal
387 * element names will be added. This is the primary reason why XML entities
388 * cannot be used. There wouldn't be a way to get the literal an non-literal
389 * element paths.
391 gpg_error_t
392 list_root_elements (struct client_s *client, xmlDocPtr doc,
393 struct string_s ** result, int verbose, int with_target)
395 xmlNodePtr n = NULL;
396 struct slist_s *list = NULL;
397 int total, i;
398 struct string_s *string;
399 gpg_error_t rc = 0;
401 n = xmlDocGetRootElement (doc);
402 if (!n || !n->children)
403 return GPG_ERR_NO_DATA;
405 for (n = n->children; n; n = n->next)
407 xmlAttrPtr a;
408 xmlChar *val, *target;
409 struct slist_s *tlist;
410 char *tmp;
412 if (n->type != XML_ELEMENT_NODE)
413 continue;
415 a = xmlHasProp (n, (xmlChar *) "_name");
416 if (!a || !a->children->content)
417 continue;
419 val = xmlNodeGetContent (a->children);
420 if (!val)
422 rc = GPG_ERR_ENOMEM;
423 goto fail;
426 tmp = str_asprintf ("!%s%s", (char *) val,
427 verbose ? find_element_node (n->children) ? " +"
428 : "" : "");
430 if (!tmp)
432 xmlFree (val);
433 rc = GPG_ERR_ENOMEM;
434 goto fail;
437 tlist = slist_append (list, tmp);
438 if (!tlist)
440 xmlFree (val);
441 rc = GPG_ERR_ENOMEM;
442 goto fail;
445 list = tlist;
446 target = node_has_attribute (n, (xmlChar *) "target");
447 if (target)
449 char *t = NULL;
451 if (verbose)
453 char **req = NULL;
454 xmlNodePtr tnode = resolve_path (client, doc, target, &req, &rc);
456 if (rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
457 || rc == GPG_ERR_EPERM)
459 t = str_asprintf ("%s %s", (char *) val,
460 rc == GPG_ERR_ELOOP ? "O" :
461 rc == GPG_ERR_EPERM ? "P" : "E");
462 rc = 0;
464 else if (!rc)
466 struct string_s *realpath = NULL;
468 if (with_target)
470 rc = build_realpath (client, doc, (char *) target,
471 &realpath);
472 if (rc)
474 strv_free (req);
475 xmlFree (val);
476 xmlFree (target);
477 goto fail;
480 realpath = string_prepend (realpath, "T ");
483 t = str_asprintf ("%s%s%s%s", (char *) val,
484 (tnode
485 && find_element_node (tnode->children))
486 || realpath ? " " : "", tnode
487 && find_element_node (tnode->children) ?
488 "+" : "", realpath ? realpath->str : "");
490 if (realpath)
491 string_free (realpath, 1);
494 if (req)
495 strv_free (req);
497 else
498 t = str_dup ((char *) val);
500 if (!t || rc)
502 xmlFree (val);
503 xmlFree (target);
504 rc = rc ? rc : GPG_ERR_ENOMEM;
505 goto fail;
508 tlist = slist_append (list, t);
509 if (!tlist)
511 xmlFree (val);
512 xfree (t);
513 xmlFree (target);
514 rc = GPG_ERR_ENOMEM;
515 goto fail;
518 list = tlist;
521 xmlFree (val);
522 xmlFree (target);
525 total = slist_length (list);
526 if (!total)
527 return GPG_ERR_NO_DATA;
529 string = string_new (NULL);
530 if (!string)
532 rc = GPG_ERR_ENOMEM;
533 goto fail;
536 for (i = 0; i < total; i++)
538 char *val = slist_nth_data (list, i);
540 string_append_printf (string, "%s\n", val);
543 string = string_truncate (string, string->len - 1);
544 *result = string;
546 fail:
547 total = slist_length (list);
548 for (i = 0; i < total; i++)
549 xfree (slist_nth_data (list, i));
551 slist_free (list);
552 return rc;
556 * Prevents a sibling element past the current element path with the same
557 * element name.
559 static xmlNodePtr
560 find_stop_node (xmlNodePtr node)
562 xmlNodePtr n;
564 for (n = node->parent->children; n; n = n->next)
566 if (n == node)
567 return n->next;
570 return NULL;
573 xmlNodePtr
574 create_target_elements_cb (struct client_s *client, int verify,
575 xmlNodePtr node, char **path, gpg_error_t *rc,
576 void *data)
578 int i;
579 char **req = path;
580 xmlNodePtr parent = data;
582 for (i = 0; req[i] && *req[i]; i++)
584 xmlNodePtr n;
586 if (parent && node == parent)
588 *rc = GPG_ERR_CONFLICT;
589 return NULL;
592 is_literal_element (&req[i]);
594 if ((n = find_element (client, node, req[i],
595 find_stop_node (node), rc)) == NULL ||
596 (n && n->parent == node->parent))
599 if (!*rc)
600 *rc = create_new_element (client, verify, node, req[i], &node);
602 if (*rc)
603 return NULL;
605 else
606 node = n;
609 return node;
612 xmlNodePtr
613 find_text_node (xmlNodePtr node)
615 xmlNodePtr n = node;
617 if (n && n->type == XML_TEXT_NODE)
618 return n;
620 for (n = node; n; n = n->next)
622 if (n->type == XML_TEXT_NODE)
623 return n;
626 return NULL;
629 xmlNodePtr
630 create_elements_cb (struct client_s *client, int verify, xmlNodePtr node,
631 char **elements, gpg_error_t * rc, void *data)
633 int i;
634 char **req = elements;
636 if (node->type == XML_TEXT_NODE)
637 node = node->parent;
639 for (i = 0; req[i] && *req[i]; i++)
641 xmlNodePtr n;
644 * Strip the first '!' if needed. If there's another, it's an
645 * rc. The syntax has already been checked before calling this
646 * function.
648 is_literal_element (&req[i]);
649 n = find_element (client, node, req[i], find_stop_node (node), rc);
650 if (*rc)
651 return NULL;
654 * If the found element has the same parent as the current element,
655 * they are siblings and the new element needs to be created as a
656 * child of the current element (node).
658 if (n && n->parent == node->parent)
659 n = NULL;
661 if (!n)
663 *rc = create_new_element (client, 0, node, req[i], &node);
664 if (*rc)
665 return NULL;
667 else
668 node = n;
671 return node;
674 /* The root element is really req[0]. It is need as a pointer in case there is
675 * a target attribute so it can be updated. */
676 xmlNodePtr
677 find_root_element (struct client_s *client, xmlDocPtr doc, char ***req,
678 gpg_error_t * rc, int *target, int recursion_depth,
679 int stop)
681 xmlNodePtr n = xmlDocGetRootElement (doc);
682 int depth = 0;
683 char *root = str_dup (*req[0]);
684 int literal = is_literal_element (&root);
686 if (!root)
688 *rc = GPG_ERR_ENOMEM;
689 return NULL;
692 *rc = 0;
693 recursion_depth++;
695 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
697 xmlChar *t = xmlGetNodePath (n);
699 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
700 xmlFree (t);
701 xfree (root);
702 *rc = GPG_ERR_ELOOP;
703 return NULL;
706 while (n)
708 if (n->type == XML_ELEMENT_NODE)
710 if (depth == 0 && xmlStrEqual (n->name, (xmlChar *) "pwmd"))
712 n = n->children;
713 depth++;
714 continue;
717 if (depth == 1 && xmlStrEqual (n->name, (xmlChar *) "element"))
719 xmlChar *content = node_has_attribute (n, (xmlChar *) "_name");
721 if (!content)
722 continue;
724 if (xmlStrEqual (content, (xmlChar *) root))
726 char **nreq, **tmp = NULL;
728 *rc = acl_check(client, n);
729 if (*rc)
731 xmlFree (content);
732 xfree (root);
733 return NULL;
736 if (literal == 1)
738 xmlFree (content);
739 xfree (root);
740 return n;
743 xmlFree (content);
744 content = node_has_attribute (n, (xmlChar *) "target");
746 if (target)
747 *target = 1;
749 if (!content || stop)
751 if (content)
752 xmlFree (content);
754 xfree (root);
755 return n;
758 if (strchr ((char *) content, '\t'))
760 nreq = str_split ((char *) content, "\t", 0);
761 xmlFree (content);
763 #if 0
765 * FIXME ENOMEM
767 if (!nreq)
769 *rc = GPG_ERR_ENOMEM;
770 return NULL;
772 #endif
774 tmp = *req;
775 tmp = strv_catv (nreq, tmp + 1);
776 strv_free (nreq);
778 if (!tmp)
780 xfree (root);
781 *rc = GPG_ERR_ENOMEM;
782 return NULL;
785 strv_free (*req);
786 *req = tmp;
788 else
790 if (strv_printf (&tmp, "%s", content) == 0)
792 xmlFree (content);
793 xfree (root);
794 *rc = GPG_ERR_ENOMEM;
795 return NULL;
798 xmlFree (content);
799 nreq = *req;
800 nreq = strv_catv (tmp, nreq + 1);
801 strv_free (tmp);
803 if (!nreq)
805 *rc = GPG_ERR_ENOMEM;
806 xfree (root);
807 return NULL;
810 strv_free (*req);
811 *req = nreq;
814 xfree (root);
815 n = find_root_element (client, doc, req, rc, target,
816 recursion_depth, 0);
817 return n;
820 xmlFree (content);
824 n = n->next;
827 xfree (root);
828 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
829 return NULL;
832 xmlNodePtr
833 find_element (struct client_s *client, xmlNodePtr node, char *element,
834 xmlNodePtr stop, gpg_error_t *rc)
836 xmlNodePtr n;
838 *rc = 0;
840 if (!node || !element)
841 return NULL;
843 for (n = node; n; n = n->next)
845 if (n->type != XML_ELEMENT_NODE)
846 continue;
848 if (n == stop)
849 break;
851 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
853 if (a && xmlStrEqual (a, (xmlChar *) element))
855 xmlFree (a);
857 *rc = acl_check(client, n);
858 if (*rc)
859 n = NULL;
861 return n;
864 xmlFree (a);
867 return NULL;
870 xmlChar *
871 node_has_attribute (xmlNodePtr n, xmlChar * attr)
873 xmlAttrPtr a = xmlHasProp (n, attr);
875 if (!a)
876 return NULL;
878 if (!a->children || !a->children->content)
879 return NULL;
881 return xmlGetProp (n, attr);
884 static int
885 element_to_literal (char **element)
887 char *p = str_asprintf ("!%s", *element);
889 if (!p)
890 return 0;
892 xfree (*element);
893 *element = p;
894 return 1;
897 /* Resolves elements in 'req' one at a time. It's recursive in case of
898 * "target" attributes. */
899 xmlNodePtr
900 find_elements (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
901 char **req, gpg_error_t * rc, int *target,
902 xmlNodePtr (*found_fn) (struct client_s *, xmlNodePtr, char **,
903 gpg_error_t *, char **, void *),
904 xmlNodePtr (*not_found_fn) (struct client_s *, int, xmlNodePtr,
905 char **, gpg_error_t *, void *),
906 int is_list_command, int recursion_depth, void *data, int stop)
908 xmlNodePtr n, last, last_node;
909 char **p;
910 int found = 0;
912 *rc = 0;
913 recursion_depth++;
915 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
917 xmlChar *t = xmlGetNodePath (node);
919 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
920 xmlFree (t);
921 recursion_depth--;
922 *rc = GPG_ERR_ELOOP;
923 return NULL;
926 for (last_node = last = n = node, p = req; *p; p++)
928 xmlNodePtr tmp;
929 char *t;
930 int literal;
932 if (!*(*p))
934 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
935 return NULL;
938 t = str_dup (*p);
939 if (!t)
941 *rc = GPG_ERR_ENOMEM;
942 return NULL;
945 literal = is_literal_element (&t);
946 n = find_element (client, last, t, NULL, rc);
947 xfree (t);
949 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
950 return NULL;
952 if (!n)
954 if (not_found_fn)
955 return not_found_fn (client, 0,
956 found ? last_node : last_node->parent, p,
957 rc, data);
959 if (!*rc)
960 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
962 return NULL;
965 last = n->children;
966 last_node = n;
967 found = 1;
969 if (literal == 0)
971 xmlChar *content = node_has_attribute (n, (xmlChar *) "target");
972 char **nreq = NULL, **nnreq;
974 if (!content)
976 if (is_list_command == 1)
978 if (element_to_literal (&(*p)) == 0)
980 *rc = GPG_ERR_ENOMEM;
981 return NULL;
985 continue;
988 if (target)
989 *target = 1;
991 if (!*(p + 1) && stop)
993 xmlFree (content);
994 return n;
997 if (strchr ((char *) content, '\t') != NULL)
999 if ((nreq = str_split ((char *) content, "\t", 0)) == NULL)
1001 xmlFree (content);
1002 *rc = GPG_ERR_INV_VALUE;
1003 return NULL;
1006 else
1008 if ((nreq = str_split ((char *) content, " ", 0)) == NULL)
1010 xmlFree (content);
1011 *rc = GPG_ERR_INV_VALUE;
1012 return NULL;
1016 xmlFree (content);
1017 tmp = find_root_element (client, doc, &nreq, rc, target, 0, 0);
1019 if (!tmp)
1021 strv_free (nreq);
1022 return NULL;
1025 if (found_fn)
1027 found_fn (client, tmp, nreq, rc, p + 1, data);
1029 if (*rc)
1031 strv_free (nreq);
1032 return NULL;
1036 if (!*(nreq + 1) && !*(p + 1))
1038 strv_free (nreq);
1039 return tmp;
1042 nnreq = strv_catv (nreq + 1, p + 1);
1043 strv_free (nreq);
1045 // FIXME ENOMEM
1046 if (!nnreq || !*nnreq)
1048 if (nnreq)
1049 strv_free (nnreq);
1051 return tmp;
1054 if (tmp->children)
1055 n = find_elements (client, doc, tmp->children, nnreq, rc, NULL,
1056 found_fn, not_found_fn, is_list_command,
1057 recursion_depth, data, stop);
1058 else
1060 strv_free (nnreq);
1062 if (not_found_fn)
1063 return not_found_fn (client, 0, tmp, p + 1, rc, data);
1065 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1066 return NULL;
1069 if (*(p + 1))
1071 char **zz = p + 1, **qq = nnreq;
1073 if (strv_length (nnreq) > strv_length (p + 1))
1074 qq = nnreq + 1;
1076 for (; *qq && *zz; zz++)
1078 xfree (*zz);
1079 *zz = str_dup (*qq++);
1081 if (!*zz)
1083 *rc = GPG_ERR_ENOMEM;
1084 n = NULL;
1085 break;
1090 strv_free (nnreq);
1091 return n;
1095 return n;
1098 static int
1099 update_element_list (struct element_list_s *elements)
1101 char *line;
1102 struct slist_s *l;
1104 if (!elements || !elements->elements)
1105 return 1;
1107 line = strv_join ("\t", elements->elements);
1109 if (!line)
1110 return 0;
1112 strv_free (elements->elements);
1113 elements->elements = NULL;
1114 l = slist_append (elements->list, line);
1116 if (!l)
1117 return 0;
1119 elements->list = l;
1120 return 1;
1123 static gpg_error_t
1124 path_list_recurse (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1125 struct element_list_s *elements)
1127 gpg_error_t rc = 0;
1128 xmlNodePtr n;
1129 gpg_error_t error_flag = 0;
1131 for (n = node; n; n = n->next)
1133 xmlChar *target = NULL;
1134 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
1135 gpg_error_t err = 0;
1136 char *path = NULL;
1138 rc = 0;
1139 if (!a)
1140 continue;
1142 if (n->type != XML_ELEMENT_NODE)
1143 goto children;
1145 rc = acl_check(client, n);
1147 if (elements->verbose)
1149 if (strv_printf
1150 (&elements->elements, "%s\t!%s%s%s", elements->prefix, a,
1151 !rc && find_element_node (n->children) ? " +" : "",
1152 rc == GPG_ERR_EPERM ? " P" : "") == 0)
1154 xmlFree (a);
1155 return GPG_ERR_ENOMEM;
1158 else
1159 if (strv_printf (&elements->elements, "%s\t!%s", elements->prefix, a)
1160 == 0)
1162 xmlFree (a);
1163 return GPG_ERR_ENOMEM;
1166 if (update_element_list (elements) == 0)
1168 xmlFree (a);
1169 return GPG_ERR_ENOMEM;
1173 if (rc == GPG_ERR_EPERM)
1175 xmlFree(a);
1176 error_flag = rc;
1177 continue;
1179 else if (rc)
1181 xmlFree (a);
1182 return rc;
1185 target = node_has_attribute (n, (xmlChar *) "target");
1186 if (target)
1188 char *tmp;
1189 char *save = elements->prefix;
1190 int r = elements->resolving;
1191 char **req = NULL;
1192 xmlNodePtr tnode;
1193 struct string_s *realpath = NULL;
1195 tnode = resolve_path (client, doc, target, &req, &rc);
1196 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_ELEMENT_NOT_FOUND
1197 || rc == GPG_ERR_EPERM)
1199 if (rc == GPG_ERR_ELOOP)
1201 xmlChar *t = xmlGetNodePath (n);
1203 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1204 xmlFree (t);
1207 if (elements->verbose)
1209 error_flag = err = rc;
1210 rc = 0;
1213 else if (!elements->verbose && rc)
1215 xmlFree (a);
1216 xmlFree (target);
1217 return rc;
1220 path = str_asprintf("%s\t%s", elements->prefix, a);
1221 rc = validate_target_attribute (client, client->doc, path, tnode);
1222 xfree (path);
1223 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EPERM
1224 || rc == GPG_ERR_ELEMENT_NOT_FOUND)
1226 if (rc != GPG_ERR_ELEMENT_NOT_FOUND)
1227 error_flag = err = rc;
1229 rc = 0;
1231 else if (rc)
1233 xmlFree (a);
1234 xmlFree (target);
1235 return rc;
1238 if (err)
1240 strv_printf (&elements->elements, "%s\t%s %s", elements->prefix,
1242 err == GPG_ERR_ELOOP ? "O" :
1243 err == GPG_ERR_EPERM ? "P" : "E");
1246 if (!err && elements->with_target)
1248 rc = build_realpath (client, doc, (char *) target, &realpath);
1249 if (rc)
1251 xmlFree (a);
1252 xmlFree (target);
1253 return rc;
1256 realpath = string_prepend (realpath, "T ");
1259 if (!err && elements->verbose)
1261 if (!strv_printf (&elements->elements, "%s\t%s%s%s%s",
1262 elements->prefix, a,
1263 (tnode && find_element_node (tnode->children))
1264 || realpath ? " " : "", tnode
1265 && find_element_node (tnode->children) ? "+" :
1266 "", realpath ? realpath->str : ""))
1268 xmlFree (a);
1269 xmlFree (target);
1270 return GPG_ERR_ENOMEM;
1273 else if (!err)
1274 if (!strv_printf
1275 (&elements->elements, "%s\t%s", elements->prefix, a))
1277 xmlFree (a);
1278 xmlFree (target);
1279 return GPG_ERR_ENOMEM;
1282 if (realpath)
1283 string_free (realpath, 1);
1285 tmp = strv_join ("\t", elements->elements);
1286 if (!tmp)
1288 xmlFree (a);
1289 xmlFree (target);
1290 return GPG_ERR_ENOMEM;
1293 if (update_element_list (elements) == 0)
1295 xfree (tmp);
1296 xmlFree (a);
1297 xmlFree (target);
1298 return GPG_ERR_ENOMEM;
1301 if (!err && elements->recurse)
1303 /* Prune element flags. */
1304 if (elements->verbose && strchr (tmp, ' '))
1306 char *p;
1308 for (p = tmp; *p; p++)
1310 if (*p == ' ')
1312 *p = 0;
1313 break;
1318 elements->prefix = tmp;
1319 elements->resolving = 1;
1320 rc = create_path_list (client, doc, elements, (char *) target);
1321 elements->resolving = r;
1322 elements->prefix = save;
1324 if (rc && gpg_err_code (rc) != GPG_ERR_ELOOP
1325 && gpg_err_code(rc) != GPG_ERR_EPERM)
1327 xfree (tmp);
1328 xmlFree (target);
1329 xmlFree (a);
1330 return rc;
1333 error_flag = err = rc;
1334 rc = 0;
1337 xfree (tmp);
1338 xmlFree (target);
1341 children:
1342 if (n->children && elements->recurse && err != GPG_ERR_EPERM)
1344 char *tmp = str_asprintf ("%s\t!%s", elements->prefix, a);
1345 char *save = elements->prefix;
1347 if (!tmp)
1349 xmlFree (a);
1350 return GPG_ERR_ENOMEM;
1353 elements->prefix = tmp;
1354 rc = path_list_recurse (client, doc, n->children, elements);
1355 xfree (elements->prefix);
1356 elements->prefix = save;
1358 if (rc)
1360 if (gpg_err_code(rc) == GPG_ERR_ELOOP
1361 || gpg_err_code (rc) == GPG_ERR_EPERM
1362 || gpg_err_code (rc) == GPG_ERR_ELEMENT_NOT_FOUND)
1364 error_flag = err = rc;
1365 rc = 0;
1367 else
1369 xmlFree (a);
1370 return rc;
1375 xmlFree (a);
1378 return error_flag == GPG_ERR_ELOOP || error_flag == GPG_ERR_EPERM
1379 ? error_flag : rc;
1382 gpg_error_t
1383 add_attribute (xmlNodePtr node, const char *name, const char *value)
1385 char *buf;
1386 gpg_error_t rc;
1388 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
1389 return GPG_ERR_BAD_DATA;
1391 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
1392 return 0;
1394 buf = str_asprintf ("%li", time (NULL));
1395 rc = add_attribute (node, "_mtime", buf);
1396 xfree (buf);
1397 return rc;
1401 * From the element path 'path', find sub-nodes and append them to the list.
1403 gpg_error_t
1404 create_path_list (struct client_s *client, xmlDocPtr doc,
1405 struct element_list_s * elements, char *path)
1407 gpg_error_t rc;
1408 char **req, **req_orig;
1409 xmlNodePtr n;
1410 int a_target = 0;
1412 req = str_split (path, "\t", 0);
1413 if (!req)
1415 req = str_split (path, " ", 0);
1416 if (!req)
1417 return GPG_ERR_SYNTAX;
1420 req_orig = strv_dup (req);
1421 if (!req_orig)
1423 rc = GPG_ERR_ENOMEM;
1424 goto fail;
1427 n = find_root_element (client, doc, &req, &rc, &a_target, 0, 0);
1428 if ((rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
1429 || rc == GPG_ERR_EPERM)
1430 && elements->verbose && a_target)
1432 if (rc != GPG_ERR_EPERM)
1433 rc = 0;
1435 goto done;
1438 if (rc == GPG_ERR_EPERM)
1439 goto done;
1441 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1443 rc = 0;
1444 goto fail;
1446 else if (!n)
1447 goto fail;
1449 if (a_target == 1)
1451 xfree (*req);
1452 *req = str_dup (*req_orig);
1455 if (*(req + 1))
1457 int e_target = 0;
1460 find_elements (client, doc, n->children, req + 1, &rc, &e_target,
1461 NULL, NULL, 1, 0, NULL, 0);
1463 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1465 rc = 0;
1466 goto fail;
1468 else if (!n)
1469 goto fail;
1472 done:
1473 if (!elements->prefix)
1476 * FIXME
1478 * If any req_orig element contains no target the element should be
1479 * prefixed with the literal character. Not really crucial if the
1480 * client isn't human because child elements are prefixed for the
1481 * current path. But may be confusing if editing by hand.
1483 elements->prefix = strv_join ("\t", req_orig);
1485 if (!elements->prefix)
1487 rc = GPG_ERR_ENOMEM;
1488 goto fail;
1491 if (elements->verbose)
1493 int ret;
1494 struct string_s *realpath = NULL;
1495 gpg_error_t allowed = rc;
1497 rc = 0;
1499 if (!allowed && a_target && elements->with_target)
1501 rc = build_realpath (client, doc, path, &realpath);
1502 if (rc)
1503 goto fail;
1505 realpath = string_prepend (realpath, "T ");
1508 ret = strv_printf (&elements->elements, "%s%s%s%s%s",
1509 elements->prefix,
1510 (!allowed && n && find_element_node (n->children))
1511 || realpath ? " " : "",
1512 (!allowed && n && find_element_node (n->children)) ? "+" : "",
1513 !allowed && realpath ? realpath->str : "",
1514 allowed ? " P" : "");
1515 string_free (realpath, 1);
1516 if (!ret)
1518 rc = GPG_ERR_ENOMEM;
1519 goto fail;
1522 else if (strv_printf (&elements->elements, "%s", elements->prefix) == 0)
1524 rc = GPG_ERR_ENOMEM;
1525 goto fail;
1528 if (update_element_list (elements) == 0)
1530 rc = GPG_ERR_ENOMEM;
1531 goto fail;
1535 rc = path_list_recurse (client, doc, n ? n->children : n, elements);
1537 fail:
1538 if (req_orig)
1539 strv_free (req_orig);
1541 strv_free (req);
1542 return rc;
1545 gpg_error_t
1546 recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
1547 xmlNodeSetPtr nodes, xmlChar * value,
1548 xmlBufferPtr * result, int cmd, const xmlChar * attr)
1550 int i = value ? nodes->nodeNr - 1 : 0;
1551 xmlBufferPtr buf;
1553 buf = xmlBufferCreate ();
1555 if (!buf)
1556 return GPG_ERR_ENOMEM;
1558 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
1560 xmlNodePtr n = nodes->nodeTab[i];
1561 gpg_error_t rc;
1563 if (!n)
1564 continue;
1566 if (!value && !attr)
1568 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
1570 *result = buf;
1571 return GPG_ERR_BAD_DATA;
1574 continue;
1577 if (!attr)
1579 xmlNodeSetContent (n, value);
1580 rc = update_element_mtime (n);
1582 if (rc)
1583 return rc;
1585 else
1587 if (!cmd)
1588 rc = add_attribute (n, (char *) attr, (char *) value);
1589 else
1590 rc = delete_attribute (client, n, attr);
1592 if (rc)
1593 return rc;
1597 *result = buf;
1598 return 0;
1601 static gpg_error_t
1602 convert_root_element (struct client_s *client, xmlNodePtr n)
1604 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1605 gpg_error_t rc;
1607 if (a)
1609 xmlFree (a);
1610 xmlChar *t = xmlGetNodePath (n);
1612 log_write (_
1613 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1615 xmlFree (t);
1616 return GPG_ERR_AMBIGUOUS_NAME;
1619 a = xmlGetProp (n, (xmlChar *) "name");
1621 if (a)
1623 rc = add_attribute (n, "_name", (char *) a);
1624 xmlFree (a);
1626 if (rc)
1627 return rc;
1629 rc = delete_attribute (client, n, (xmlChar *) "name");
1631 if (rc)
1632 return rc;
1634 xmlNodeSetName (n, (xmlChar *) "element");
1637 return 0;
1640 gpg_error_t
1641 delete_attribute (struct client_s *client, xmlNodePtr n, const xmlChar * name)
1643 xmlAttrPtr a;
1644 gpg_error_t rc = 0;
1646 if ((a = xmlHasProp (n, name)) == NULL)
1647 return GPG_ERR_NOT_FOUND;
1649 if (xmlRemoveProp (a) == -1)
1650 return GPG_ERR_BAD_DATA;
1652 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
1654 char *user = create_acl_user (client);
1656 rc = add_attribute (n, (char *) "_acl", user);
1657 xfree (user);
1659 if (rc)
1660 return rc;
1663 return update_element_mtime (n);
1666 static gpg_error_t
1667 convert_elements_recurse (struct client_s *client, xmlDocPtr doc,
1668 xmlNodePtr n, unsigned depth)
1670 gpg_error_t rc;
1672 depth++;
1674 for (n = n->children; n; n = n->next)
1676 if (n->type == XML_ELEMENT_NODE)
1678 if (depth > 1)
1680 xmlChar *a = NULL;
1682 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1684 xmlChar *t = xmlGetNodePath (n);
1686 log_write (_
1687 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1689 xmlFree (t);
1690 return GPG_ERR_AMBIGUOUS_NAME;
1693 a = xmlGetProp (n, (xmlChar *) "_name");
1694 if (a)
1696 xmlFree (a);
1697 xmlChar *t = xmlGetNodePath (n);
1699 log_write (_
1700 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1702 xmlFree (t);
1703 return GPG_ERR_AMBIGUOUS_NAME;
1706 xmlChar *tmp = xmlStrdup (n->name);
1708 if (!tmp)
1709 return GPG_ERR_ENOMEM;
1711 xmlNodeSetName (n, (xmlChar *) "element");
1712 rc = add_attribute (n, "_name", (char *) tmp);
1713 xmlFree (tmp);
1715 if (rc)
1716 return rc;
1718 else
1720 rc = convert_root_element (client, n);
1722 if (rc)
1723 return rc;
1727 if (n->children)
1729 rc = convert_elements_recurse (client, doc, n, depth);
1731 if (rc)
1732 return rc;
1736 return 0;
1739 /* Renames ALL elements to the new "element" name. Existing element names are
1740 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1741 * elements can contain common characters that the XML parser barfs on (an
1742 * email address for example. */
1743 gpg_error_t
1744 convert_pre_212_elements (xmlDocPtr doc)
1746 xmlNodePtr n = xmlDocGetRootElement (doc);
1748 log_write (_("Converting pre 2.12 data file..."));
1749 return convert_elements_recurse (NULL, doc, n, 0);
1752 gpg_error_t
1753 validate_import (xmlNodePtr node)
1755 gpg_error_t rc = 0;
1757 if (!node)
1758 return 0;
1760 for (xmlNodePtr n = node; n; n = n->next)
1762 if (n->type == XML_ELEMENT_NODE)
1764 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1766 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1768 if (!a)
1770 xmlChar *t = xmlGetNodePath (n);
1772 log_write (_("Missing attribute '_name' at %s."), t);
1773 xmlFree (t);
1774 return GPG_ERR_INV_VALUE;
1777 if (!valid_xml_element (a))
1779 xmlChar *t = xmlGetNodePath (n);
1781 log_write (_("'%s' is not a valid element name at %s."), a,
1783 xmlFree (a);
1784 xmlFree (t);
1785 return GPG_ERR_INV_VALUE;
1788 xmlFree (a);
1789 a = xmlGetProp (n, (xmlChar *) "_ctime");
1790 if (!a)
1791 attr_ctime (n);
1793 xmlFree (a);
1794 a = xmlGetProp (n, (xmlChar *) "_mtime");
1795 if (!a)
1796 update_element_mtime (n);
1797 xmlFree (a);
1799 else
1801 xmlChar *t = xmlGetNodePath (n);
1803 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1804 n->name, t);
1805 xmlFree (t);
1806 continue;
1810 if (n->children)
1812 rc = validate_import (n->children);
1814 if (rc)
1815 return rc;
1819 return rc;
1822 gpg_error_t
1823 update_element_mtime (xmlNodePtr n)
1825 return add_attribute (n, NULL, NULL);
1828 gpg_error_t
1829 unlink_node (xmlNodePtr n)
1831 gpg_error_t rc = 0;
1833 if (!n)
1834 return rc;
1836 if (n->parent)
1837 rc = update_element_mtime (n->parent);
1839 xmlUnlinkNode (n);
1840 return rc;
1843 gpg_error_t
1844 parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1846 xmlDocPtr doc;
1848 xmlResetLastError ();
1849 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1850 if (!doc && xmlGetLastError ())
1851 return GPG_ERR_BAD_DATA;
1853 *result = doc;
1854 return !doc ? GPG_ERR_ENOMEM : 0;
1857 static xmlNodePtr
1858 realpath_elements_cb (struct client_s *client, xmlNodePtr node, char **target,
1859 gpg_error_t * rc, char **req_orig, void *data)
1861 char *path = *(char **) data;
1862 char *tmp = NULL, *result;
1864 if (path)
1866 xfree (path);
1867 *(char **) data = NULL;
1870 path = strv_join ("\t", target);
1872 if (!path)
1874 *rc = GPG_ERR_ENOMEM;
1875 return NULL;
1878 if (req_orig)
1880 tmp = strv_join ("\t", req_orig);
1882 if (!tmp)
1884 xfree (path);
1885 *rc = GPG_ERR_ENOMEM;
1886 return NULL;
1890 if (tmp && *tmp)
1891 result = str_asprintf ("%s\t%s", path, tmp);
1892 else
1893 result = str_dup (path);
1895 if (!result)
1897 *rc = GPG_ERR_ENOMEM;
1898 xfree (path);
1899 xfree (tmp);
1900 return NULL;
1903 xfree (path);
1904 xfree (tmp);
1905 *(char **) data = result;
1906 return node;
1909 gpg_error_t
1910 build_realpath (struct client_s *client, xmlDocPtr doc, char *line,
1911 struct string_s ** result)
1913 gpg_error_t rc;
1914 char **req;
1915 char *t;
1916 int i;
1917 xmlNodePtr n;
1918 struct string_s *string;
1919 char *rp = NULL;
1921 if (strchr (line, '\t') != NULL)
1923 if ((req = str_split (line, "\t", 0)) == NULL)
1924 return GPG_ERR_SYNTAX;
1926 else
1928 if ((req = str_split (line, " ", 0)) == NULL)
1929 return GPG_ERR_SYNTAX;
1932 n = find_root_element (client, doc, &req, &rc, NULL, 0, 0);
1933 if (!n)
1935 strv_free (req);
1936 return rc;
1939 rp = strv_join ("\t", req);
1940 if (!rp)
1942 strv_free (req);
1943 return GPG_ERR_ENOMEM;
1946 if (req[1])
1948 n = find_elements (client, doc, n->children, req + 1, &rc, NULL,
1949 realpath_elements_cb, NULL, 0, 0, &rp, 0);
1950 if (!n)
1952 xfree (rp);
1953 strv_free (req);
1954 return rc;
1958 string = string_new (rp);
1959 xfree (rp);
1960 strv_free (req);
1961 if (!string)
1962 return GPG_ERR_ENOMEM;
1964 again:
1965 for (i = 0, t = string->str + i; *t; t++, i++)
1967 if ((!i && *t != '!') || (*t == '\t' && *(t + 1) && *(t + 1) != '!'))
1969 struct string_s *s = string_insert_c (string, !i ? i++ : ++i, '!');
1971 if (!s)
1973 string_free (string, 1);
1974 return GPG_ERR_ENOMEM;
1977 string = s;
1978 goto again;
1982 *result = string;
1983 return rc;
1986 #if 0
1987 static char *
1988 node_to_element_path (xmlNodePtr node)
1990 xmlNodePtr n;
1991 struct string_s *str = string_new ("");
1992 char *result;
1994 for (n = node; n; n = n->parent)
1996 xmlNodePtr child;
1998 for (child = n; child; child = child->next)
2000 if (child->type != XML_ELEMENT_NODE)
2001 continue;
2003 xmlChar *name = node_has_attribute (n, (xmlChar *) "_name");
2004 if (name)
2006 str = string_prepend (str, (char *) name);
2007 xmlFree (name);
2008 name = node_has_attribute (n, (xmlChar *) "target");
2009 if (name)
2010 str = string_prepend (str, "\t");
2011 else
2012 str = string_prepend (str, "\t!");
2013 xmlFree (name);
2015 break;
2019 str = string_erase (str, 0, 1);
2020 result = str->str;
2021 string_free (str, 0);
2022 return result;
2024 #endif
2027 * Recurse the element tree beginning at 'node' and find elements who point
2028 * back to 'src' or 'dst'. Also follows target attributes.
2030 static gpg_error_t
2031 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
2032 xmlNodePtr src, xmlNodePtr dst, unsigned depth,
2033 int is_target)
2035 xmlNodePtr n;
2036 gpg_error_t rc = 0;
2038 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
2039 return gpg_error (GPG_ERR_ELOOP);
2041 for (n = node; n; n = n->next)
2043 xmlChar *target;
2045 if (n->type != XML_ELEMENT_NODE)
2046 continue;
2048 if (n == src || n == dst)
2049 return GPG_ERR_ELOOP;
2051 target = node_has_attribute (n, (xmlChar *) "target");
2052 if (target)
2054 xmlNodePtr tmp;
2055 char **result = NULL;
2057 tmp = resolve_path (client, doc, target, &result, &rc);
2058 xmlFree (target);
2059 strv_free (result);
2060 if (!rc)
2062 rc = find_child_to_target (client, doc, tmp, src, dst, ++depth,
2064 depth--;
2067 if (rc && gpg_err_code (rc) != GPG_ERR_ELEMENT_NOT_FOUND)
2068 return rc;
2070 if (is_target)
2071 break;
2073 continue;
2076 if (n->children)
2078 rc = find_child_to_target (client, doc, n->children, src, dst,
2079 ++depth,0);
2080 depth--;
2081 if (rc)
2082 return rc;
2085 if (is_target)
2086 break;
2089 return rc;
2092 static gpg_error_t
2093 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
2095 xmlNodePtr n;
2096 gpg_error_t rc = 0;
2098 for (n = src; n; n = n->next)
2100 if (n->type != XML_ELEMENT_NODE)
2101 continue;
2103 if (n == dst)
2105 rc = GPG_ERR_ELOOP;
2106 break;
2109 rc = find_child_of_parent (doc, n->children, dst);
2112 return rc;
2115 static gpg_error_t
2116 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
2118 xmlNodePtr n;
2119 gpg_error_t rc = 0;
2121 for (n = node; n; n = n->parent)
2123 if (n->type != XML_ELEMENT_NODE)
2125 xmlNodePtr tmp;
2127 for (tmp = n->next; tmp; n = n->next)
2129 if (n->type != XML_ELEMENT_NODE)
2130 continue;
2132 if (tmp == dst)
2133 return GPG_ERR_ELOOP;
2137 if (n == dst)
2138 return GPG_ERR_ELOOP;
2141 return rc;
2144 gpg_error_t
2145 validate_target_attribute (struct client_s *client, xmlDocPtr doc,
2146 const char *src, xmlNodePtr dst_node)
2148 gpg_error_t rc;
2149 xmlNodePtr src_node;
2150 char **src_req = NULL;
2152 src_node = resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
2153 if (rc)
2154 goto fail;
2156 /* A destination element is a child of the source element. */
2157 rc = find_child_of_parent (doc, src_node->children, dst_node);
2158 if (rc)
2159 goto fail;
2161 /* The destination element is a parent of the source element. */
2162 rc = find_parent_of_child (doc, src_node->parent, dst_node);
2163 if (rc)
2164 goto fail;
2166 /* A destination child element contains a target to the source element. */
2167 rc = find_child_to_target (client, doc, dst_node->children, src_node,
2168 dst_node, 0, 0);
2169 if (rc)
2170 goto fail;
2172 fail:
2173 strv_free (src_req);
2174 return rc;
2177 /* The owner of the element is the first user listed in the _acl attribute
2178 * list. acl_check() should be called before calling this function. An empty
2179 * ACL is an error if the client is not invoking_user.
2181 gpg_error_t
2182 is_element_owner (struct client_s *client, xmlNodePtr n)
2184 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
2185 char **users;
2186 gpg_error_t rc = GPG_ERR_EPERM;
2188 if (!acl || !*acl)
2190 xmlFree (acl);
2191 return 0;
2194 users = str_split((char *)acl, ",", 0);
2195 if (users && *users)
2197 char *user;
2199 #ifdef WITH_GNUTLS
2200 if (client->thd->remote)
2201 user = str_asprintf ("#%s", client->thd->tls->fp);
2202 else
2203 user = get_username (client->thd->peer->uid);
2204 #else
2205 user = get_username (client->thd->peer->uid);
2206 #endif
2208 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EPERM;
2209 xfree (user);
2212 strv_free (users);
2213 return rc;