Version 3.0.8.
[pwmd.git] / src / xml.c
blobe92b4f5aff420bf9d3617a33d3e2f247a01d08a9
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 (struct client_s *client, 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 (client, n, "_ctime", buf);
164 xfree (buf);
165 return rc;
168 static gpg_error_t
169 acl_check (struct client_s *client, xmlNodePtr n)
171 gpg_error_t rc = GPG_ERR_EACCES;
172 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
173 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
174 char **p;
175 int allowed = 0;
177 if (!acl || !users || !*users)
179 strv_free(users);
180 return peer_is_invoker(client);
183 if (!peer_is_invoker(client))
184 return 0;
186 for (p = users; *p; p++)
188 #ifdef WITH_GNUTLS
189 rc = acl_check_common (client, *p,
190 client->thd->remote ? 0 : client->thd->peer->uid,
191 client->thd->remote ? 0 : client->thd->peer->gid,
192 &allowed);
193 #else
194 rc = acl_check_common (client, *p, client->thd->peer->uid,
195 client->thd->peer->gid, &allowed);
196 #endif
199 xmlFree(acl);
200 strv_free(users);
201 if (rc)
202 return rc;
204 return allowed ? 0 : GPG_ERR_EACCES;
207 static char *
208 create_acl_user (struct client_s *client)
210 #ifdef WITH_GNUTLS
211 if (client->thd->remote)
212 return str_asprintf ("#%s", client->thd->tls->fp);
213 #endif
215 return get_username (client->thd->peer->uid);
218 static gpg_error_t
219 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
220 const char *name, xmlNodePtr * result)
222 xmlNodePtr n;
223 gpg_error_t rc;
225 // Allow any client to create a non-existing root element.
226 if (parent->parent->type != XML_DOCUMENT_NODE)
228 rc = acl_check(client, parent);
229 if (rc)
230 return rc;
233 n = xmlNewNode (NULL, (xmlChar *) "element");
234 if (!n)
235 return GPG_ERR_ENOMEM;
237 rc = add_attribute (client, n, "_name", name);
238 if (!rc)
239 rc = attr_ctime (client, n);
241 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
243 rc = peer_is_invoker (client);
244 if (rc == GPG_ERR_EACCES)
245 rc = is_element_owner (client, parent);
248 if (!rc)
250 xmlNodePtr p = xmlAddChild (parent, n);
251 char *user = create_acl_user (client);
253 if (result)
254 *result = p;
256 rc = add_attribute(client, p, "_acl", user);
257 xfree (user);
259 else
260 xmlFreeNode (n);
262 return rc;
265 gpg_error_t
266 new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
268 xmlNodePtr root = xmlDocGetRootElement (doc);
269 char *p = name;
271 if (!p || !root)
272 return GPG_ERR_BAD_DATA;
274 if (*p == '!')
275 p++;
277 if (!valid_xml_element ((xmlChar *) p))
278 return GPG_ERR_INV_VALUE;
280 return create_new_element (client, 0, root, p, NULL);
283 static xmlDocPtr
284 create_dtd ()
286 xmlDocPtr doc;
287 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
289 if (!wr)
290 return NULL;
292 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
293 goto fail;
295 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
296 goto fail;
298 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
299 (xmlChar *) "(element)") == -1)
300 goto fail;
302 xmlTextWriterEndDTDElement (wr);
304 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
305 (xmlChar *) "_name CDATA #REQUIRED") ==
307 goto fail;
309 xmlTextWriterEndDTDAttlist (wr);
310 xmlTextWriterEndDTD (wr);
312 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
313 goto fail;
315 xmlTextWriterEndElement (wr);
316 xmlTextWriterEndDocument (wr);
317 xmlFreeTextWriter (wr);
318 return doc;
320 fail:
321 xmlTextWriterEndDocument (wr);
322 xmlFreeTextWriter (wr);
323 xmlFreeDoc (doc);
324 return NULL;
327 xmlDocPtr
328 new_document ()
330 return create_dtd ();
333 xmlNodePtr
334 find_element_node (xmlNodePtr node)
336 xmlNodePtr n = node;
338 if (n && n->type == XML_ELEMENT_NODE)
339 return n;
341 for (n = node; n; n = n->next)
343 if (n->type == XML_ELEMENT_NODE)
344 return n;
347 return NULL;
350 static xmlNodePtr
351 resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
352 char ***result, gpg_error_t * rc)
354 xmlNodePtr n;
355 char **req;
357 req = str_split ((char *) path, "\t", 0);
358 if (!req)
360 *rc = GPG_ERR_ENOMEM;
361 return NULL;
364 n = find_root_element (client, doc, &req, rc, NULL, 0, 0);
365 if (!n)
367 strv_free (req);
368 return NULL;
371 if (req[1])
372 n = find_elements (client, doc, n->children, req + 1, rc, NULL, NULL, NULL,
373 0, 0, NULL, 0);
375 if (*rc)
376 strv_free (req);
377 else
378 *result = req;
380 return n;
384 * Lists root element names; the value of the attribute "_name" of an element
385 * "element". If there's a target attribute both literal and non-literal
386 * element names will be added. This is the primary reason why XML entities
387 * cannot be used. There wouldn't be a way to get the literal an non-literal
388 * element paths.
390 gpg_error_t
391 list_root_elements (struct client_s *client, xmlDocPtr doc,
392 struct string_s ** result, int verbose, int with_target)
394 xmlNodePtr n = NULL;
395 struct slist_s *list = NULL;
396 int total, i;
397 struct string_s *string;
398 gpg_error_t rc = 0;
400 n = xmlDocGetRootElement (doc);
401 if (!n || !n->children)
402 return GPG_ERR_NO_DATA;
404 for (n = n->children; n; n = n->next)
406 xmlAttrPtr a;
407 xmlChar *val, *target;
408 struct slist_s *tlist;
409 char *tmp;
411 if (n->type != XML_ELEMENT_NODE)
412 continue;
414 a = xmlHasProp (n, (xmlChar *) "_name");
415 if (!a || !a->children->content)
416 continue;
418 val = xmlNodeGetContent (a->children);
419 if (!val)
421 rc = GPG_ERR_ENOMEM;
422 goto fail;
425 tmp = str_asprintf ("!%s%s", (char *) val,
426 verbose ? find_element_node (n->children) ? " +"
427 : "" : "");
429 if (!tmp)
431 xmlFree (val);
432 rc = GPG_ERR_ENOMEM;
433 goto fail;
436 tlist = slist_append (list, tmp);
437 if (!tlist)
439 xmlFree (val);
440 rc = GPG_ERR_ENOMEM;
441 goto fail;
444 list = tlist;
445 target = node_has_attribute (n, (xmlChar *) "target");
446 if (target)
448 char *t = NULL;
450 if (verbose)
452 char **req = NULL;
453 xmlNodePtr tnode = resolve_path (client, doc, target, &req, &rc);
455 if (rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
456 || rc == GPG_ERR_EACCES)
458 t = str_asprintf ("%s %s", (char *) val,
459 rc == GPG_ERR_ELOOP ? "O" :
460 rc == GPG_ERR_EACCES ? "P" : "E");
461 rc = 0;
463 else if (!rc)
465 struct string_s *realpath = NULL;
467 if (with_target)
469 rc = build_realpath (client, doc, (char *) target,
470 &realpath);
471 if (rc)
473 strv_free (req);
474 xmlFree (val);
475 xmlFree (target);
476 goto fail;
479 realpath = string_prepend (realpath, "T ");
482 t = str_asprintf ("%s%s%s%s", (char *) val,
483 (tnode
484 && find_element_node (tnode->children))
485 || realpath ? " " : "", tnode
486 && find_element_node (tnode->children) ?
487 "+" : "", realpath ? realpath->str : "");
489 if (realpath)
490 string_free (realpath, 1);
493 if (req)
494 strv_free (req);
496 else
497 t = str_dup ((char *) val);
499 if (!t || rc)
501 xmlFree (val);
502 xmlFree (target);
503 rc = rc ? rc : GPG_ERR_ENOMEM;
504 goto fail;
507 tlist = slist_append (list, t);
508 if (!tlist)
510 xmlFree (val);
511 xfree (t);
512 xmlFree (target);
513 rc = GPG_ERR_ENOMEM;
514 goto fail;
517 list = tlist;
520 xmlFree (val);
521 xmlFree (target);
524 total = slist_length (list);
525 if (!total)
526 return GPG_ERR_NO_DATA;
528 string = string_new (NULL);
529 if (!string)
531 rc = GPG_ERR_ENOMEM;
532 goto fail;
535 for (i = 0; i < total; i++)
537 char *val = slist_nth_data (list, i);
539 string_append_printf (string, "%s\n", val);
542 string = string_truncate (string, string->len - 1);
543 *result = string;
545 fail:
546 total = slist_length (list);
547 for (i = 0; i < total; i++)
548 xfree (slist_nth_data (list, i));
550 slist_free (list);
551 return rc;
555 * Prevents a sibling element past the current element path with the same
556 * element name.
558 static xmlNodePtr
559 find_stop_node (xmlNodePtr node)
561 xmlNodePtr n;
563 for (n = node->parent->children; n; n = n->next)
565 if (n == node)
566 return n->next;
569 return NULL;
572 xmlNodePtr
573 create_target_elements_cb (struct client_s *client, int verify,
574 xmlNodePtr node, char **path, gpg_error_t *rc,
575 void *data)
577 int i;
578 char **req = path;
579 xmlNodePtr parent = data;
581 for (i = 0; req[i] && *req[i]; i++)
583 xmlNodePtr n;
585 if (parent && node == parent)
587 *rc = GPG_ERR_CONFLICT;
588 return NULL;
591 is_literal_element (&req[i]);
593 if ((n = find_element (client, node, req[i],
594 find_stop_node (node), rc)) == NULL ||
595 (n && n->parent == node->parent))
598 if (!*rc)
599 *rc = create_new_element (client, verify, node, req[i], &node);
601 if (*rc)
602 return NULL;
604 else
605 node = n;
608 return node;
611 xmlNodePtr
612 find_text_node (xmlNodePtr node)
614 xmlNodePtr n = node;
616 if (n && n->type == XML_TEXT_NODE)
617 return n;
619 for (n = node; n; n = n->next)
621 if (n->type == XML_TEXT_NODE)
622 return n;
625 return NULL;
628 xmlNodePtr
629 create_elements_cb (struct client_s *client, int verify, xmlNodePtr node,
630 char **elements, gpg_error_t * rc, void *data)
632 int i;
633 char **req = elements;
635 if (node->type == XML_TEXT_NODE)
636 node = node->parent;
638 for (i = 0; req[i] && *req[i]; i++)
640 xmlNodePtr n;
643 * Strip the first '!' if needed. If there's another, it's an
644 * rc. The syntax has already been checked before calling this
645 * function.
647 is_literal_element (&req[i]);
648 n = find_element (client, node, req[i], find_stop_node (node), rc);
649 if (*rc)
650 return NULL;
653 * If the found element has the same parent as the current element,
654 * they are siblings and the new element needs to be created as a
655 * child of the current element (node).
657 if (n && n->parent == node->parent)
658 n = NULL;
660 if (!n)
662 *rc = create_new_element (client, 0, node, req[i], &node);
663 if (*rc)
664 return NULL;
666 else
667 node = n;
670 return node;
673 /* The root element is really req[0]. It is need as a pointer in case there is
674 * a target attribute so it can be updated. */
675 xmlNodePtr
676 find_root_element (struct client_s *client, xmlDocPtr doc, char ***req,
677 gpg_error_t * rc, int *target, int recursion_depth,
678 int stop)
680 xmlNodePtr n = xmlDocGetRootElement (doc);
681 int depth = 0;
682 char *root = str_dup (*req[0]);
683 int literal = is_literal_element (&root);
685 if (!root)
687 *rc = GPG_ERR_ENOMEM;
688 return NULL;
691 *rc = 0;
692 recursion_depth++;
694 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
696 xmlChar *t = xmlGetNodePath (n);
698 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
699 xmlFree (t);
700 xfree (root);
701 *rc = GPG_ERR_ELOOP;
702 return NULL;
705 while (n)
707 if (n->type == XML_ELEMENT_NODE)
709 if (depth == 0 && xmlStrEqual (n->name, (xmlChar *) "pwmd"))
711 n = n->children;
712 depth++;
713 continue;
716 if (depth == 1 && xmlStrEqual (n->name, (xmlChar *) "element"))
718 xmlChar *content = node_has_attribute (n, (xmlChar *) "_name");
720 if (!content)
721 continue;
723 if (xmlStrEqual (content, (xmlChar *) root))
725 char **nreq, **tmp = NULL;
727 *rc = acl_check(client, n);
728 if (*rc)
730 xmlFree (content);
731 xfree (root);
732 return NULL;
735 if (literal == 1)
737 xmlFree (content);
738 xfree (root);
739 return n;
742 xmlFree (content);
743 content = node_has_attribute (n, (xmlChar *) "target");
745 if (target)
746 *target = 1;
748 if (!content || stop)
750 if (content)
751 xmlFree (content);
753 xfree (root);
754 return n;
757 if (strchr ((char *) content, '\t'))
759 nreq = str_split ((char *) content, "\t", 0);
760 xmlFree (content);
762 #if 0
764 * FIXME ENOMEM
766 if (!nreq)
768 *rc = GPG_ERR_ENOMEM;
769 return NULL;
771 #endif
773 tmp = *req;
774 tmp = strv_catv (nreq, tmp + 1);
775 strv_free (nreq);
777 if (!tmp)
779 xfree (root);
780 *rc = GPG_ERR_ENOMEM;
781 return NULL;
784 strv_free (*req);
785 *req = tmp;
787 else
789 if (strv_printf (&tmp, "%s", content) == 0)
791 xmlFree (content);
792 xfree (root);
793 *rc = GPG_ERR_ENOMEM;
794 return NULL;
797 xmlFree (content);
798 nreq = *req;
799 nreq = strv_catv (tmp, nreq + 1);
800 strv_free (tmp);
802 if (!nreq)
804 *rc = GPG_ERR_ENOMEM;
805 xfree (root);
806 return NULL;
809 strv_free (*req);
810 *req = nreq;
813 xfree (root);
814 n = find_root_element (client, doc, req, rc, target,
815 recursion_depth, 0);
816 return n;
819 xmlFree (content);
823 n = n->next;
826 xfree (root);
827 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
828 return NULL;
831 xmlNodePtr
832 find_element (struct client_s *client, xmlNodePtr node, char *element,
833 xmlNodePtr stop, gpg_error_t *rc)
835 xmlNodePtr n;
837 *rc = 0;
839 if (!node || !element)
840 return NULL;
842 for (n = node; n; n = n->next)
844 if (n->type != XML_ELEMENT_NODE)
845 continue;
847 if (n == stop)
848 break;
850 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
852 if (a && xmlStrEqual (a, (xmlChar *) element))
854 xmlFree (a);
856 *rc = acl_check(client, n);
857 if (*rc)
858 n = NULL;
860 return n;
863 xmlFree (a);
866 return NULL;
869 xmlChar *
870 node_has_attribute (xmlNodePtr n, xmlChar * attr)
872 xmlAttrPtr a = xmlHasProp (n, attr);
874 if (!a)
875 return NULL;
877 if (!a->children || !a->children->content)
878 return NULL;
880 return xmlGetProp (n, attr);
883 static int
884 element_to_literal (char **element)
886 char *p = str_asprintf ("!%s", *element);
888 if (!p)
889 return 0;
891 xfree (*element);
892 *element = p;
893 return 1;
896 /* Resolves elements in 'req' one at a time. It's recursive in case of
897 * "target" attributes. */
898 xmlNodePtr
899 find_elements (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
900 char **req, gpg_error_t * rc, int *target,
901 xmlNodePtr (*found_fn) (struct client_s *, xmlNodePtr, char **,
902 gpg_error_t *, char **, void *),
903 xmlNodePtr (*not_found_fn) (struct client_s *, int, xmlNodePtr,
904 char **, gpg_error_t *, void *),
905 int is_list_command, int recursion_depth, void *data, int stop)
907 xmlNodePtr n, last, last_node;
908 char **p;
909 int found = 0;
911 *rc = 0;
912 recursion_depth++;
914 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
916 xmlChar *t = xmlGetNodePath (node);
918 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
919 xmlFree (t);
920 recursion_depth--;
921 *rc = GPG_ERR_ELOOP;
922 return NULL;
925 for (last_node = last = n = node, p = req; *p; p++)
927 xmlNodePtr tmp;
928 char *t;
929 int literal;
931 if (!*(*p))
933 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
934 return NULL;
937 t = str_dup (*p);
938 if (!t)
940 *rc = GPG_ERR_ENOMEM;
941 return NULL;
944 literal = is_literal_element (&t);
945 n = find_element (client, last, t, NULL, rc);
946 xfree (t);
948 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
949 return NULL;
951 if (!n)
953 if (not_found_fn)
954 return not_found_fn (client, 0,
955 found ? last_node : last_node->parent, p,
956 rc, data);
958 if (!*rc)
959 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
961 return NULL;
964 last = n->children;
965 last_node = n;
966 found = 1;
968 if (literal == 0)
970 xmlChar *content = node_has_attribute (n, (xmlChar *) "target");
971 char **nreq = NULL, **nnreq;
973 if (!content)
975 if (is_list_command == 1)
977 if (element_to_literal (&(*p)) == 0)
979 *rc = GPG_ERR_ENOMEM;
980 return NULL;
984 continue;
987 if (target)
988 *target = 1;
990 if (!*(p + 1) && stop)
992 xmlFree (content);
993 return n;
996 if (strchr ((char *) content, '\t') != NULL)
998 if ((nreq = str_split ((char *) content, "\t", 0)) == NULL)
1000 xmlFree (content);
1001 *rc = GPG_ERR_INV_VALUE;
1002 return NULL;
1005 else
1007 if ((nreq = str_split ((char *) content, " ", 0)) == NULL)
1009 xmlFree (content);
1010 *rc = GPG_ERR_INV_VALUE;
1011 return NULL;
1015 xmlFree (content);
1016 tmp = find_root_element (client, doc, &nreq, rc, target, 0, 0);
1018 if (!tmp)
1020 strv_free (nreq);
1021 return NULL;
1024 if (found_fn)
1026 found_fn (client, tmp, nreq, rc, p + 1, data);
1028 if (*rc)
1030 strv_free (nreq);
1031 return NULL;
1035 if (!*(nreq + 1) && !*(p + 1))
1037 strv_free (nreq);
1038 return tmp;
1041 nnreq = strv_catv (nreq + 1, p + 1);
1042 strv_free (nreq);
1044 // FIXME ENOMEM
1045 if (!nnreq || !*nnreq)
1047 if (nnreq)
1048 strv_free (nnreq);
1050 return tmp;
1053 if (tmp->children)
1054 n = find_elements (client, doc, tmp->children, nnreq, rc, NULL,
1055 found_fn, not_found_fn, is_list_command,
1056 recursion_depth, data, stop);
1057 else
1059 strv_free (nnreq);
1061 if (not_found_fn)
1062 return not_found_fn (client, 0, tmp, p + 1, rc, data);
1064 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1065 return NULL;
1068 if (*(p + 1))
1070 char **zz = p + 1, **qq = nnreq;
1072 if (strv_length (nnreq) > strv_length (p + 1))
1073 qq = nnreq + 1;
1075 for (; *qq && *zz; zz++)
1077 xfree (*zz);
1078 *zz = str_dup (*qq++);
1080 if (!*zz)
1082 *rc = GPG_ERR_ENOMEM;
1083 n = NULL;
1084 break;
1089 strv_free (nnreq);
1090 return n;
1094 return n;
1097 static int
1098 update_element_list (struct element_list_s *elements)
1100 char *line;
1101 struct slist_s *l;
1103 if (!elements || !elements->elements)
1104 return 1;
1106 line = strv_join ("\t", elements->elements);
1108 if (!line)
1109 return 0;
1111 strv_free (elements->elements);
1112 elements->elements = NULL;
1113 l = slist_append (elements->list, line);
1115 if (!l)
1116 return 0;
1118 elements->list = l;
1119 return 1;
1122 static gpg_error_t
1123 path_list_recurse (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1124 struct element_list_s *elements)
1126 gpg_error_t rc = 0;
1127 xmlNodePtr n;
1128 gpg_error_t error_flag = 0;
1130 for (n = node; n; n = n->next)
1132 xmlChar *target = NULL;
1133 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
1134 gpg_error_t err = 0;
1135 char *path = NULL;
1137 rc = 0;
1138 if (!a)
1139 continue;
1141 if (n->type != XML_ELEMENT_NODE)
1142 goto children;
1144 rc = acl_check(client, n);
1146 if (elements->verbose)
1148 if (strv_printf
1149 (&elements->elements, "%s\t!%s%s%s", elements->prefix, a,
1150 !rc && find_element_node (n->children) ? " +" : "",
1151 rc == GPG_ERR_EACCES ? " P" : "") == 0)
1153 xmlFree (a);
1154 return GPG_ERR_ENOMEM;
1157 else
1158 if (strv_printf (&elements->elements, "%s\t!%s", elements->prefix, a)
1159 == 0)
1161 xmlFree (a);
1162 return GPG_ERR_ENOMEM;
1165 if (update_element_list (elements) == 0)
1167 xmlFree (a);
1168 return GPG_ERR_ENOMEM;
1172 if (rc == GPG_ERR_EACCES)
1174 xmlFree(a);
1175 error_flag = rc;
1176 continue;
1178 else if (rc)
1180 xmlFree (a);
1181 return rc;
1184 target = node_has_attribute (n, (xmlChar *) "target");
1185 if (target)
1187 char *tmp;
1188 char *save = elements->prefix;
1189 int r = elements->resolving;
1190 char **req = NULL;
1191 xmlNodePtr tnode;
1192 struct string_s *realpath = NULL;
1194 tnode = resolve_path (client, doc, target, &req, &rc);
1195 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_ELEMENT_NOT_FOUND
1196 || rc == GPG_ERR_EACCES)
1198 if (rc == GPG_ERR_ELOOP)
1200 xmlChar *t = xmlGetNodePath (n);
1202 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1203 xmlFree (t);
1206 if (elements->verbose)
1208 error_flag = err = rc;
1209 rc = 0;
1212 else if (!elements->verbose && rc)
1214 xmlFree (a);
1215 xmlFree (target);
1216 return rc;
1219 path = str_asprintf("%s\t%s", elements->prefix, a);
1220 rc = validate_target_attribute (client, client->doc, path, tnode);
1221 xfree (path);
1222 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
1223 || rc == GPG_ERR_ELEMENT_NOT_FOUND)
1225 if (rc != GPG_ERR_ELEMENT_NOT_FOUND)
1226 error_flag = err = rc;
1228 rc = 0;
1230 else if (rc)
1232 xmlFree (a);
1233 xmlFree (target);
1234 return rc;
1237 if (err)
1239 strv_printf (&elements->elements, "%s\t%s %s", elements->prefix,
1241 err == GPG_ERR_ELOOP ? "O" :
1242 err == GPG_ERR_EACCES ? "P" : "E");
1245 if (!err && elements->with_target)
1247 rc = build_realpath (client, doc, (char *) target, &realpath);
1248 if (rc)
1250 xmlFree (a);
1251 xmlFree (target);
1252 return rc;
1255 realpath = string_prepend (realpath, "T ");
1258 if (!err && elements->verbose)
1260 if (!strv_printf (&elements->elements, "%s\t%s%s%s%s",
1261 elements->prefix, a,
1262 (tnode && find_element_node (tnode->children))
1263 || realpath ? " " : "", tnode
1264 && find_element_node (tnode->children) ? "+" :
1265 "", realpath ? realpath->str : ""))
1267 xmlFree (a);
1268 xmlFree (target);
1269 return GPG_ERR_ENOMEM;
1272 else if (!err)
1273 if (!strv_printf
1274 (&elements->elements, "%s\t%s", elements->prefix, a))
1276 xmlFree (a);
1277 xmlFree (target);
1278 return GPG_ERR_ENOMEM;
1281 if (realpath)
1282 string_free (realpath, 1);
1284 tmp = strv_join ("\t", elements->elements);
1285 if (!tmp)
1287 xmlFree (a);
1288 xmlFree (target);
1289 return GPG_ERR_ENOMEM;
1292 if (update_element_list (elements) == 0)
1294 xfree (tmp);
1295 xmlFree (a);
1296 xmlFree (target);
1297 return GPG_ERR_ENOMEM;
1300 if (!err && elements->recurse)
1302 /* Prune element flags. */
1303 if (elements->verbose && strchr (tmp, ' '))
1305 char *p;
1307 for (p = tmp; *p; p++)
1309 if (*p == ' ')
1311 *p = 0;
1312 break;
1317 elements->prefix = tmp;
1318 elements->resolving = 1;
1319 rc = create_path_list (client, doc, elements, (char *) target);
1320 elements->resolving = r;
1321 elements->prefix = save;
1323 if (rc && gpg_err_code (rc) != GPG_ERR_ELOOP
1324 && gpg_err_code(rc) != GPG_ERR_EACCES)
1326 xfree (tmp);
1327 xmlFree (target);
1328 xmlFree (a);
1329 return rc;
1332 error_flag = err = rc;
1333 rc = 0;
1336 xfree (tmp);
1337 xmlFree (target);
1340 children:
1341 if (n->children && elements->recurse && err != GPG_ERR_EACCES)
1343 char *tmp = str_asprintf ("%s\t!%s", elements->prefix, a);
1344 char *save = elements->prefix;
1346 if (!tmp)
1348 xmlFree (a);
1349 return GPG_ERR_ENOMEM;
1352 elements->prefix = tmp;
1353 rc = path_list_recurse (client, doc, n->children, elements);
1354 xfree (elements->prefix);
1355 elements->prefix = save;
1357 if (rc)
1359 if (gpg_err_code(rc) == GPG_ERR_ELOOP
1360 || gpg_err_code (rc) == GPG_ERR_EACCES
1361 || gpg_err_code (rc) == GPG_ERR_ELEMENT_NOT_FOUND)
1363 error_flag = err = rc;
1364 rc = 0;
1366 else
1368 xmlFree (a);
1369 return rc;
1374 xmlFree (a);
1377 return error_flag == GPG_ERR_ELOOP || error_flag == GPG_ERR_EACCES
1378 ? error_flag : rc;
1381 gpg_error_t
1382 add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
1383 const char *value)
1385 char *buf;
1386 gpg_error_t rc = 0;
1388 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
1389 return GPG_ERR_BAD_DATA;
1391 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
1393 xmlChar *acl = node_has_attribute (node, (xmlChar *) "_acl");
1395 if (!acl)
1397 char *user = create_acl_user (client);
1399 if (user)
1401 rc = add_attribute (client, node, (char *) "_acl", user);
1402 xfree (user);
1405 return rc;
1408 xmlFree (acl);
1411 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
1412 return 0;
1414 buf = str_asprintf ("%li", time (NULL));
1415 rc = add_attribute (client, node, "_mtime", buf);
1416 xfree (buf);
1417 return rc;
1421 * From the element path 'path', find sub-nodes and append them to the list.
1423 gpg_error_t
1424 create_path_list (struct client_s *client, xmlDocPtr doc,
1425 struct element_list_s * elements, char *path)
1427 gpg_error_t rc;
1428 char **req, **req_orig;
1429 xmlNodePtr n;
1430 int a_target = 0;
1432 req = str_split (path, "\t", 0);
1433 if (!req)
1435 req = str_split (path, " ", 0);
1436 if (!req)
1437 return GPG_ERR_SYNTAX;
1440 req_orig = strv_dup (req);
1441 if (!req_orig)
1443 rc = GPG_ERR_ENOMEM;
1444 goto fail;
1447 n = find_root_element (client, doc, &req, &rc, &a_target, 0, 0);
1448 if ((rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
1449 || rc == GPG_ERR_EACCES)
1450 && elements->verbose && a_target)
1452 if (rc != GPG_ERR_EACCES)
1453 rc = 0;
1455 goto done;
1458 if (rc == GPG_ERR_EACCES)
1459 goto done;
1461 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1463 rc = 0;
1464 goto fail;
1466 else if (!n)
1467 goto fail;
1469 if (a_target == 1)
1471 xfree (*req);
1472 *req = str_dup (*req_orig);
1475 if (*(req + 1))
1477 int e_target = 0;
1480 find_elements (client, doc, n->children, req + 1, &rc, &e_target,
1481 NULL, NULL, 1, 0, NULL, 0);
1483 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1485 rc = 0;
1486 goto fail;
1488 else if (!n)
1489 goto fail;
1492 done:
1493 if (!elements->prefix)
1496 * FIXME
1498 * If any req_orig element contains no target the element should be
1499 * prefixed with the literal character. Not really crucial if the
1500 * client isn't human because child elements are prefixed for the
1501 * current path. But may be confusing if editing by hand.
1503 elements->prefix = strv_join ("\t", req_orig);
1505 if (!elements->prefix)
1507 rc = GPG_ERR_ENOMEM;
1508 goto fail;
1511 if (elements->verbose)
1513 int ret;
1514 struct string_s *realpath = NULL;
1515 gpg_error_t allowed = rc;
1517 rc = 0;
1519 if (!allowed && a_target && elements->with_target)
1521 rc = build_realpath (client, doc, path, &realpath);
1522 if (rc)
1523 goto fail;
1525 realpath = string_prepend (realpath, "T ");
1528 ret = strv_printf (&elements->elements, "%s%s%s%s%s",
1529 elements->prefix,
1530 (!allowed && n && find_element_node (n->children))
1531 || realpath ? " " : "",
1532 (!allowed && n && find_element_node (n->children)) ? "+" : "",
1533 !allowed && realpath ? realpath->str : "",
1534 allowed ? " P" : "");
1535 string_free (realpath, 1);
1536 if (!ret)
1538 rc = GPG_ERR_ENOMEM;
1539 goto fail;
1542 else if (strv_printf (&elements->elements, "%s", elements->prefix) == 0)
1544 rc = GPG_ERR_ENOMEM;
1545 goto fail;
1548 if (update_element_list (elements) == 0)
1550 rc = GPG_ERR_ENOMEM;
1551 goto fail;
1555 rc = path_list_recurse (client, doc, n ? n->children : n, elements);
1557 fail:
1558 if (req_orig)
1559 strv_free (req_orig);
1561 strv_free (req);
1562 return rc;
1565 gpg_error_t
1566 recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
1567 xmlNodeSetPtr nodes, xmlChar * value,
1568 xmlBufferPtr * result, int cmd, const xmlChar * attr)
1570 int i = value ? nodes->nodeNr - 1 : 0;
1571 xmlBufferPtr buf;
1573 buf = xmlBufferCreate ();
1575 if (!buf)
1576 return GPG_ERR_ENOMEM;
1578 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
1580 xmlNodePtr n = nodes->nodeTab[i];
1581 gpg_error_t rc;
1583 if (!n)
1584 continue;
1586 if (!value && !attr)
1588 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
1590 *result = buf;
1591 return GPG_ERR_BAD_DATA;
1594 continue;
1597 if (!attr)
1599 xmlNodeSetContent (n, value);
1600 rc = update_element_mtime (client, n);
1602 if (rc)
1603 return rc;
1605 else
1607 if (!cmd)
1608 rc = add_attribute (client, n, (char *) attr, (char *) value);
1609 else
1610 rc = delete_attribute (client, n, attr);
1612 if (rc)
1613 return rc;
1617 *result = buf;
1618 return 0;
1621 static gpg_error_t
1622 convert_root_element (struct client_s *client, xmlNodePtr n)
1624 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1625 gpg_error_t rc;
1627 if (a)
1629 xmlFree (a);
1630 xmlChar *t = xmlGetNodePath (n);
1632 log_write (_
1633 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1635 xmlFree (t);
1636 return GPG_ERR_AMBIGUOUS_NAME;
1639 a = xmlGetProp (n, (xmlChar *) "name");
1641 if (a)
1643 rc = add_attribute (client, n, "_name", (char *) a);
1644 xmlFree (a);
1646 if (rc)
1647 return rc;
1649 rc = delete_attribute (client, n, (xmlChar *) "name");
1651 if (rc)
1652 return rc;
1654 xmlNodeSetName (n, (xmlChar *) "element");
1657 return 0;
1660 gpg_error_t
1661 delete_attribute (struct client_s *client, xmlNodePtr n, const xmlChar * name)
1663 xmlAttrPtr a;
1664 gpg_error_t rc = 0;
1666 if ((a = xmlHasProp (n, name)) == NULL)
1667 return GPG_ERR_NOT_FOUND;
1669 if (xmlRemoveProp (a) == -1)
1670 return GPG_ERR_BAD_DATA;
1672 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
1674 char *user = create_acl_user (client);
1676 rc = add_attribute (client, n, (char *) "_acl", user);
1677 xfree (user);
1679 if (rc)
1680 return rc;
1683 return update_element_mtime (client, n);
1686 static gpg_error_t
1687 convert_elements_recurse (struct client_s *client, xmlDocPtr doc,
1688 xmlNodePtr n, unsigned depth)
1690 gpg_error_t rc;
1692 depth++;
1694 for (n = n->children; n; n = n->next)
1696 if (n->type == XML_ELEMENT_NODE)
1698 if (depth > 1)
1700 xmlChar *a = NULL;
1702 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1704 xmlChar *t = xmlGetNodePath (n);
1706 log_write (_
1707 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1709 xmlFree (t);
1710 return GPG_ERR_AMBIGUOUS_NAME;
1713 a = xmlGetProp (n, (xmlChar *) "_name");
1714 if (a)
1716 xmlFree (a);
1717 xmlChar *t = xmlGetNodePath (n);
1719 log_write (_
1720 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1722 xmlFree (t);
1723 return GPG_ERR_AMBIGUOUS_NAME;
1726 xmlChar *tmp = xmlStrdup (n->name);
1728 if (!tmp)
1729 return GPG_ERR_ENOMEM;
1731 xmlNodeSetName (n, (xmlChar *) "element");
1732 rc = add_attribute (client, n, "_name", (char *) tmp);
1733 xmlFree (tmp);
1735 if (rc)
1736 return rc;
1738 else
1740 rc = convert_root_element (client, n);
1742 if (rc)
1743 return rc;
1747 if (n->children)
1749 rc = convert_elements_recurse (client, doc, n, depth);
1751 if (rc)
1752 return rc;
1756 return 0;
1759 /* Renames ALL elements to the new "element" name. Existing element names are
1760 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1761 * elements can contain common characters that the XML parser barfs on (an
1762 * email address for example. */
1763 gpg_error_t
1764 convert_pre_212_elements (xmlDocPtr doc)
1766 xmlNodePtr n = xmlDocGetRootElement (doc);
1768 log_write (_("Converting pre 2.12 data file..."));
1769 return convert_elements_recurse (NULL, doc, n, 0);
1772 gpg_error_t
1773 validate_import (struct client_s *client, xmlNodePtr node)
1775 gpg_error_t rc = 0;
1777 if (!node)
1778 return 0;
1780 for (xmlNodePtr n = node; n; n = n->next)
1782 if (n->type == XML_ELEMENT_NODE)
1784 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1786 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1788 if (!a)
1790 xmlChar *t = xmlGetNodePath (n);
1792 log_write (_("Missing attribute '_name' at %s."), t);
1793 xmlFree (t);
1794 return GPG_ERR_INV_VALUE;
1797 if (!valid_xml_element (a))
1799 xmlChar *t = xmlGetNodePath (n);
1801 log_write (_("'%s' is not a valid element name at %s."), a,
1803 xmlFree (a);
1804 xmlFree (t);
1805 return GPG_ERR_INV_VALUE;
1808 xmlFree (a);
1809 a = xmlGetProp (n, (xmlChar *) "_ctime");
1810 if (!a)
1811 attr_ctime (client, n);
1813 xmlFree (a);
1814 a = xmlGetProp (n, (xmlChar *) "_mtime");
1815 if (!a)
1816 update_element_mtime (client, n);
1817 xmlFree (a);
1819 else
1821 xmlChar *t = xmlGetNodePath (n);
1823 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1824 n->name, t);
1825 xmlFree (t);
1826 continue;
1830 if (n->children)
1832 rc = validate_import (client, n->children);
1834 if (rc)
1835 return rc;
1839 return rc;
1842 gpg_error_t
1843 update_element_mtime (struct client_s *client, xmlNodePtr n)
1845 return add_attribute (client, n, NULL, NULL);
1848 gpg_error_t
1849 unlink_node (struct client_s *client, xmlNodePtr n)
1851 gpg_error_t rc = 0;
1853 if (!n)
1854 return rc;
1856 if (n->parent)
1857 rc = update_element_mtime (client, n->parent);
1859 xmlUnlinkNode (n);
1860 return rc;
1863 gpg_error_t
1864 parse_doc (const char *xml, size_t len, xmlDocPtr *result)
1866 xmlDocPtr doc;
1868 xmlResetLastError ();
1869 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
1870 if (!doc && xmlGetLastError ())
1871 return GPG_ERR_BAD_DATA;
1873 *result = doc;
1874 return !doc ? GPG_ERR_ENOMEM : 0;
1877 static xmlNodePtr
1878 realpath_elements_cb (struct client_s *client, xmlNodePtr node, char **target,
1879 gpg_error_t * rc, char **req_orig, void *data)
1881 char *path = *(char **) data;
1882 char *tmp = NULL, *result;
1884 if (path)
1886 xfree (path);
1887 *(char **) data = NULL;
1890 path = strv_join ("\t", target);
1892 if (!path)
1894 *rc = GPG_ERR_ENOMEM;
1895 return NULL;
1898 if (req_orig)
1900 tmp = strv_join ("\t", req_orig);
1902 if (!tmp)
1904 xfree (path);
1905 *rc = GPG_ERR_ENOMEM;
1906 return NULL;
1910 if (tmp && *tmp)
1911 result = str_asprintf ("%s\t%s", path, tmp);
1912 else
1913 result = str_dup (path);
1915 if (!result)
1917 *rc = GPG_ERR_ENOMEM;
1918 xfree (path);
1919 xfree (tmp);
1920 return NULL;
1923 xfree (path);
1924 xfree (tmp);
1925 *(char **) data = result;
1926 return node;
1929 gpg_error_t
1930 build_realpath (struct client_s *client, xmlDocPtr doc, char *line,
1931 struct string_s ** result)
1933 gpg_error_t rc;
1934 char **req;
1935 char *t;
1936 int i;
1937 xmlNodePtr n;
1938 struct string_s *string;
1939 char *rp = NULL;
1941 if (strchr (line, '\t') != NULL)
1943 if ((req = str_split (line, "\t", 0)) == NULL)
1944 return GPG_ERR_SYNTAX;
1946 else
1948 if ((req = str_split (line, " ", 0)) == NULL)
1949 return GPG_ERR_SYNTAX;
1952 n = find_root_element (client, doc, &req, &rc, NULL, 0, 0);
1953 if (!n)
1955 strv_free (req);
1956 return rc;
1959 rp = strv_join ("\t", req);
1960 if (!rp)
1962 strv_free (req);
1963 return GPG_ERR_ENOMEM;
1966 if (req[1])
1968 n = find_elements (client, doc, n->children, req + 1, &rc, NULL,
1969 realpath_elements_cb, NULL, 0, 0, &rp, 0);
1970 if (!n)
1972 xfree (rp);
1973 strv_free (req);
1974 return rc;
1978 string = string_new (rp);
1979 xfree (rp);
1980 strv_free (req);
1981 if (!string)
1982 return GPG_ERR_ENOMEM;
1984 again:
1985 for (i = 0, t = string->str + i; *t; t++, i++)
1987 if ((!i && *t != '!') || (*t == '\t' && *(t + 1) && *(t + 1) != '!'))
1989 struct string_s *s = string_insert_c (string, !i ? i++ : ++i, '!');
1991 if (!s)
1993 string_free (string, 1);
1994 return GPG_ERR_ENOMEM;
1997 string = s;
1998 goto again;
2002 *result = string;
2003 return rc;
2006 #if 0
2007 static char *
2008 node_to_element_path (xmlNodePtr node)
2010 xmlNodePtr n;
2011 struct string_s *str = string_new ("");
2012 char *result;
2014 for (n = node; n; n = n->parent)
2016 xmlNodePtr child;
2018 for (child = n; child; child = child->next)
2020 if (child->type != XML_ELEMENT_NODE)
2021 continue;
2023 xmlChar *name = node_has_attribute (n, (xmlChar *) "_name");
2024 if (name)
2026 str = string_prepend (str, (char *) name);
2027 xmlFree (name);
2028 name = node_has_attribute (n, (xmlChar *) "target");
2029 if (name)
2030 str = string_prepend (str, "\t");
2031 else
2032 str = string_prepend (str, "\t!");
2033 xmlFree (name);
2035 break;
2039 str = string_erase (str, 0, 1);
2040 result = str->str;
2041 string_free (str, 0);
2042 return result;
2044 #endif
2047 * Recurse the element tree beginning at 'node' and find elements who point
2048 * back to 'src' or 'dst'. Also follows target attributes.
2050 static gpg_error_t
2051 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
2052 xmlNodePtr src, xmlNodePtr dst, unsigned depth,
2053 int is_target)
2055 xmlNodePtr n;
2056 gpg_error_t rc = 0;
2058 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
2059 return gpg_error (GPG_ERR_ELOOP);
2061 for (n = node; n; n = n->next)
2063 xmlChar *target;
2065 if (n->type != XML_ELEMENT_NODE)
2066 continue;
2068 if (n == src || n == dst)
2069 return GPG_ERR_ELOOP;
2071 target = node_has_attribute (n, (xmlChar *) "target");
2072 if (target)
2074 xmlNodePtr tmp;
2075 char **result = NULL;
2077 tmp = resolve_path (client, doc, target, &result, &rc);
2078 xmlFree (target);
2079 strv_free (result);
2080 if (!rc)
2082 rc = find_child_to_target (client, doc, tmp, src, dst, ++depth,
2084 depth--;
2087 if (rc && gpg_err_code (rc) != GPG_ERR_ELEMENT_NOT_FOUND)
2088 return rc;
2090 if (is_target)
2091 break;
2093 continue;
2096 if (n->children)
2098 rc = find_child_to_target (client, doc, n->children, src, dst,
2099 ++depth,0);
2100 depth--;
2101 if (rc)
2102 return rc;
2105 if (is_target)
2106 break;
2109 return rc;
2112 static gpg_error_t
2113 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
2115 xmlNodePtr n;
2116 gpg_error_t rc = 0;
2118 for (n = src; n; n = n->next)
2120 if (n->type != XML_ELEMENT_NODE)
2121 continue;
2123 if (n == dst)
2125 rc = GPG_ERR_ELOOP;
2126 break;
2129 rc = find_child_of_parent (doc, n->children, dst);
2132 return rc;
2135 static gpg_error_t
2136 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
2138 xmlNodePtr n;
2139 gpg_error_t rc = 0;
2141 for (n = node; n; n = n->parent)
2143 if (n->type != XML_ELEMENT_NODE)
2145 xmlNodePtr tmp;
2147 for (tmp = n->next; tmp; n = n->next)
2149 if (n->type != XML_ELEMENT_NODE)
2150 continue;
2152 if (tmp == dst)
2153 return GPG_ERR_ELOOP;
2157 if (n == dst)
2158 return GPG_ERR_ELOOP;
2161 return rc;
2164 gpg_error_t
2165 validate_target_attribute (struct client_s *client, xmlDocPtr doc,
2166 const char *src, xmlNodePtr dst_node)
2168 gpg_error_t rc;
2169 xmlNodePtr src_node;
2170 char **src_req = NULL;
2172 src_node = resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
2173 if (rc)
2174 goto fail;
2176 /* A destination element is a child of the source element. */
2177 rc = find_child_of_parent (doc, src_node->children, dst_node);
2178 if (rc)
2179 goto fail;
2181 /* The destination element is a parent of the source element. */
2182 rc = find_parent_of_child (doc, src_node->parent, dst_node);
2183 if (rc)
2184 goto fail;
2186 /* A destination child element contains a target to the source element. */
2187 rc = find_child_to_target (client, doc, dst_node->children, src_node,
2188 dst_node, 0, 0);
2189 if (rc)
2190 goto fail;
2192 fail:
2193 strv_free (src_req);
2194 return rc;
2197 /* The owner of the element is the first user listed in the _acl attribute
2198 * list. acl_check() should be called before calling this function. An empty
2199 * ACL is an error if the client is not invoking_user.
2201 gpg_error_t
2202 is_element_owner (struct client_s *client, xmlNodePtr n)
2204 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
2205 char **users;
2206 gpg_error_t rc = GPG_ERR_EACCES;
2208 if (!acl || !*acl)
2210 xmlFree (acl);
2211 return 0;
2214 users = str_split((char *)acl, ",", 0);
2215 if (users && *users)
2217 char *user;
2219 #ifdef WITH_GNUTLS
2220 if (client->thd->remote)
2221 user = str_asprintf ("#%s", client->thd->tls->fp);
2222 else
2223 user = get_username (client->thd->peer->uid);
2224 #else
2225 user = get_username (client->thd->peer->uid);
2226 #endif
2228 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
2229 xfree (user);
2232 strv_free (users);
2233 return rc;