find_elements(): don't leak information about children.
[pwmd.git] / src / xml.c
blob4d37651174546b02ccd362f2c7819abe2cb6e6f4
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
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"
47 #include "commands.h"
49 extern void log_write (const char *fmt, ...);
52 * 'element' must be allocated.
54 int
55 is_literal_element (char **element)
57 char *p;
59 if (!element || !*element)
60 return 0;
62 if (*(*element) == '!')
64 char *c;
66 for (p = *element, c = p + 1; *c; c++)
67 *p++ = *c;
69 *p = 0;
70 return 1;
73 return 0;
76 int
77 valid_xml_attribute_value (const char *str)
79 const char *p = str;
81 if (!p || !*p)
82 return 1;
84 while (*p)
86 if (*p++ == '\n')
87 return 0;
90 return 1;
93 int
94 valid_xml_attribute (const char *str)
96 wchar_t *wc;
97 size_t len, c;
98 int ret = valid_xml_element ((xmlChar *)str);
100 if (!ret)
101 return ret;
103 wc = str_to_wchar ((const char *)str);
104 if (!wc)
105 return 0;
107 len = wcslen (wc);
108 for (c = 0; c < len; c++)
110 switch (wc[c])
112 case '-':
113 case '.':
114 case '0' ... '9':
115 case 0xB7:
116 case 0x0300 ... 0x036F:
117 case 0x203F ... 0x2040:
118 if (!c)
120 xfree (wc);
121 return 0;
123 case ':': break;
124 case '_': break;
125 case 'A' ... 'Z': break;
126 case 'a' ... 'z': break;
127 case 0xC0 ... 0xD6: break;
128 case 0xD8 ... 0xF6: break;
129 case 0xF8 ... 0x2FF: break;
130 case 0x370 ... 0x37D: break;
131 case 0x37F ... 0x1FFF: break;
132 case 0x200C ... 0x200D: break;
133 case 0x2070 ... 0x218F: break;
134 case 0x2C00 ... 0x2FEF: break;
135 case 0x3001 ... 0xD7FF: break;
136 case 0xF900 ... 0xFDCF: break;
137 case 0xFDF0 ... 0xFFFD: break;
138 case 0x10000 ... 0xEFFFF: break;
139 default:
140 xfree (wc);
141 return 0;
145 xfree (wc);
146 return 1;
150 valid_xml_element (xmlChar *str)
152 wchar_t *wc;
153 size_t len, c;
155 if (!str || !*str || *str == '!')
156 return 0;
158 wc = str_to_wchar ((const char *)str);
159 if (!wc)
160 return 0;
162 len = wcslen (wc);
163 for (c = 0; c < len; c++)
165 if (iswspace(wc[c]))
167 xfree (wc);
168 return 0;
172 xfree (wc);
173 return 1;
177 valid_element_path (char **path, int with_content)
179 char **dup = NULL, **p;
181 if (!path || !*path)
182 return 0;
184 /* Save some memory by not duplicating the element content. */
185 if (with_content)
187 int i, t = strv_length (path);
189 for (i = 0; i < t - 1; i++)
191 char **tmp = xrealloc (dup, (i + 2) * sizeof (char *));
193 if (!tmp)
195 strv_free (dup);
196 return 0;
199 dup = tmp;
200 dup[i] = str_dup (path[i]);
201 dup[i + 1] = NULL;
204 else
205 dup = strv_dup (path);
207 if (!dup)
208 return 0;
210 for (p = dup; *p && *(*p); p++)
212 is_literal_element (&(*p));
213 if (!valid_xml_element ((xmlChar *) * p))
215 strv_free (dup);
216 return 0;
220 strv_free (dup);
221 return 1;
224 gpg_error_t
225 attr_ctime (struct client_s *client, xmlNodePtr n)
227 char *buf = str_asprintf ("%li", time (NULL));
228 gpg_error_t rc;
230 if (!buf)
231 return GPG_ERR_ENOMEM;
233 rc = add_attribute (client, n, "_ctime", buf);
234 xfree (buf);
235 return rc;
238 static gpg_error_t
239 acl_check (struct client_s *client, xmlNodePtr n)
241 gpg_error_t rc = GPG_ERR_EACCES;
242 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
243 char **users = acl ? str_split((char *)acl, ",", 0) : NULL;
244 char **p;
245 int allowed = 0;
247 if (!acl || !*acl || !users || !*users)
249 xmlFree (acl);
250 strv_free(users);
251 return peer_is_invoker(client);
254 if (!peer_is_invoker(client))
256 xmlFree (acl);
257 strv_free(users);
258 return 0;
261 for (p = users; *p; p++)
263 #ifdef WITH_GNUTLS
264 rc = acl_check_common (client, *p,
265 client->thd->remote ? 0 : client->thd->peer->uid,
266 client->thd->remote ? 0 : client->thd->peer->gid,
267 &allowed);
268 #else
269 rc = acl_check_common (client, *p, client->thd->peer->uid,
270 client->thd->peer->gid, &allowed);
271 #endif
274 xmlFree(acl);
275 strv_free(users);
277 // ATTR LIST makes use of FLAG_ACL_IGNORE to allow listing of element
278 // attributes that the client is not normally allowed access to.
279 if ((rc == GPG_ERR_EACCES || !allowed) && client->flags & FLAG_ACL_IGNORE)
281 rc = 0;
282 client->flags &= ~FLAG_ACL_IGNORE;
284 // This flag is used in ATTR LIST to prevent listing attributes of
285 // children whose parent ACL does not allow access to the client.
286 client->flags |= FLAG_ACL_ERROR;
287 allowed = 1;
290 if (rc)
291 return rc;
293 return allowed ? 0 : GPG_ERR_EACCES;
296 static char *
297 create_acl_user (struct client_s *client)
299 #ifdef WITH_GNUTLS
300 if (client->thd->remote)
301 return str_asprintf ("#%s", client->thd->tls->fp);
302 #endif
304 return get_username (client->thd->peer->uid);
307 static gpg_error_t
308 create_new_element (struct client_s *client, int verify, xmlNodePtr parent,
309 const char *name, xmlNodePtr * result)
311 xmlNodePtr n;
312 gpg_error_t rc;
314 // Allow any client to create a non-existing root element.
315 if (parent->parent->type != XML_DOCUMENT_NODE)
317 rc = acl_check(client, parent);
318 if (rc)
319 return rc;
322 n = xmlNewNode (NULL, (xmlChar *) "element");
323 if (!n)
324 return GPG_ERR_ENOMEM;
326 rc = add_attribute (client, n, "_name", name);
327 if (!rc)
328 rc = attr_ctime (client, n);
330 if (!rc && verify && parent->parent->type != XML_DOCUMENT_NODE)
331 rc = is_element_owner (client, parent);
333 if (!rc)
335 xmlNodePtr p = xmlAddChild (parent, n);
336 char *user = create_acl_user (client);
338 if (result)
339 *result = p;
341 rc = add_attribute(client, p, "_acl", user);
342 xfree (user);
344 else
345 xmlFreeNode (n);
347 return rc;
350 gpg_error_t
351 new_root_element (struct client_s *client, xmlDocPtr doc, char *name)
353 xmlNodePtr root = xmlDocGetRootElement (doc);
354 char *p = name;
356 if (!p || !root)
357 return GPG_ERR_BAD_DATA;
359 if (*p == '!')
360 p++;
362 if (!valid_xml_element ((xmlChar *) p))
363 return GPG_ERR_INV_VALUE;
365 return create_new_element (client, 0, root, p, NULL);
368 static xmlDocPtr
369 create_dtd ()
371 xmlDocPtr doc;
372 xmlTextWriterPtr wr = xmlNewTextWriterDoc (&doc, 0);
374 if (!wr)
375 return NULL;
377 if (xmlTextWriterStartDocument (wr, NULL, "UTF-8", "yes"))
378 goto fail;
380 if (xmlTextWriterStartDTD (wr, (xmlChar *) "pwmd", NULL, NULL) == -1)
381 goto fail;
383 if (xmlTextWriterWriteDTDElement (wr, (xmlChar *) "pwmd",
384 (xmlChar *) "(element)") == -1)
385 goto fail;
387 xmlTextWriterEndDTDElement (wr);
389 if (xmlTextWriterWriteDTDAttlist (wr, (xmlChar *) "element",
390 (xmlChar *) "_name CDATA #REQUIRED") ==
392 goto fail;
394 xmlTextWriterEndDTDAttlist (wr);
395 xmlTextWriterEndDTD (wr);
397 if (xmlTextWriterStartElement (wr, (xmlChar *) "pwmd"))
398 goto fail;
400 xmlTextWriterEndElement (wr);
401 xmlTextWriterEndDocument (wr);
402 xmlFreeTextWriter (wr);
403 return doc;
405 fail:
406 xmlTextWriterEndDocument (wr);
407 xmlFreeTextWriter (wr);
408 xmlFreeDoc (doc);
409 return NULL;
412 xmlDocPtr
413 new_document ()
415 return create_dtd ();
418 xmlNodePtr
419 find_element_node (xmlNodePtr node)
421 xmlNodePtr n = node;
423 if (n && n->type == XML_ELEMENT_NODE)
424 return n;
426 for (n = node; n; n = n->next)
428 if (n->type == XML_ELEMENT_NODE)
429 return n;
432 return NULL;
435 static xmlNodePtr
436 resolve_path (struct client_s *client, xmlDocPtr doc, xmlChar * path,
437 char ***result, gpg_error_t * rc)
439 xmlNodePtr n;
440 char **req;
442 req = str_split ((char *) path, "\t", 0);
443 if (!req)
445 *rc = GPG_ERR_ENOMEM;
446 return NULL;
449 n = find_root_element (client, doc, &req, rc, NULL, 0, 0);
450 if (*rc)
452 strv_free (req);
453 return n;
456 if (req[1])
457 n = find_elements (client, doc, n->children, req + 1, rc, NULL, NULL, NULL,
458 0, 0, NULL, 0);
460 if (*rc)
461 strv_free (req);
462 else
463 *result = req;
465 return n;
469 * Lists root element names; the value of the attribute "_name" of an element
470 * "element". If there's a target attribute both literal and non-literal
471 * element names will be added. This is the primary reason why XML entities
472 * cannot be used. There wouldn't be a way to get the literal an non-literal
473 * element paths.
475 gpg_error_t
476 list_root_elements (struct client_s *client, xmlDocPtr doc,
477 struct string_s ** result, int verbose, int with_target)
479 xmlNodePtr n = NULL;
480 struct slist_s *list = NULL;
481 int total, i;
482 struct string_s *string;
483 gpg_error_t rc = 0;
485 n = xmlDocGetRootElement (doc);
486 if (!n || !n->children)
487 return GPG_ERR_NO_DATA;
489 for (n = n->children; n; n = n->next)
491 xmlAttrPtr a;
492 xmlChar *val, *target;
493 struct slist_s *tlist;
494 char *tmp;
496 if (n->type != XML_ELEMENT_NODE)
497 continue;
499 a = xmlHasProp (n, (xmlChar *) "_name");
500 if (!a || !a->children->content)
501 continue;
503 val = xmlNodeGetContent (a->children);
504 if (!val)
506 rc = GPG_ERR_ENOMEM;
507 goto fail;
510 tmp = str_asprintf ("!%s%s", (char *) val,
511 verbose ? find_element_node (n->children) ? " +"
512 : "" : "");
514 if (!tmp)
516 xmlFree (val);
517 rc = GPG_ERR_ENOMEM;
518 goto fail;
521 tlist = slist_append (list, tmp);
522 if (!tlist)
524 xmlFree (val);
525 rc = GPG_ERR_ENOMEM;
526 goto fail;
529 list = tlist;
530 target = node_has_attribute (n, (xmlChar *) "target");
531 if (target)
533 char *t = NULL;
535 if (verbose)
537 char **req = NULL;
538 xmlNodePtr tnode = resolve_path (client, doc, target, &req, &rc);
540 if (rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
541 || rc == GPG_ERR_EACCES)
543 t = str_asprintf ("%s %s%s%s", (char *) val,
544 rc == GPG_ERR_ELOOP ? "O" :
545 rc == GPG_ERR_EACCES ? "P" : "E",
546 with_target ? "T " : "",
547 with_target ? (char *)target : "");
548 rc = 0;
550 else if (!rc)
552 struct string_s *realpath = NULL;
554 if (with_target)
556 rc = build_realpath (client, doc, (char *) target,
557 &realpath);
558 if (rc)
560 strv_free (req);
561 xmlFree (val);
562 xmlFree (target);
563 goto fail;
566 realpath = string_prepend (realpath, "T ");
569 t = str_asprintf ("%s%s%s%s", (char *) val,
570 (tnode
571 && find_element_node (tnode->children))
572 || realpath ? " " : "", tnode
573 && find_element_node (tnode->children) ?
574 "+" : "", realpath ? realpath->str : "");
576 if (realpath)
577 string_free (realpath, 1);
580 if (req)
581 strv_free (req);
583 else
584 t = str_dup ((char *) val);
586 if (!t || rc)
588 xmlFree (val);
589 xmlFree (target);
590 rc = rc ? rc : GPG_ERR_ENOMEM;
591 goto fail;
594 tlist = slist_append (list, t);
595 if (!tlist)
597 xmlFree (val);
598 xfree (t);
599 xmlFree (target);
600 rc = GPG_ERR_ENOMEM;
601 goto fail;
604 list = tlist;
607 xmlFree (val);
608 xmlFree (target);
611 total = slist_length (list);
612 if (!total)
613 return GPG_ERR_NO_DATA;
615 string = string_new (NULL);
616 if (!string)
618 rc = GPG_ERR_ENOMEM;
619 goto fail;
622 for (i = 0; i < total; i++)
624 char *val = slist_nth_data (list, i);
626 string_append_printf (string, "%s\n", val);
629 string = string_truncate (string, string->len - 1);
630 *result = string;
632 fail:
633 total = slist_length (list);
634 for (i = 0; i < total; i++)
635 xfree (slist_nth_data (list, i));
637 slist_free (list);
638 return rc;
642 * Prevents a sibling element past the current element path with the same
643 * element name.
645 static xmlNodePtr
646 find_stop_node (xmlNodePtr node)
648 xmlNodePtr n;
650 for (n = node->parent->children; n; n = n->next)
652 if (n == node)
653 return n->next;
656 return NULL;
659 xmlNodePtr
660 create_target_elements_cb (struct client_s *client, int verify,
661 xmlNodePtr node, char **path, gpg_error_t *rc,
662 void *data)
664 int i;
665 char **req = path;
666 xmlNodePtr parent = data;
668 for (i = 0; req[i] && *req[i]; i++)
670 xmlNodePtr n;
672 if (parent && node == parent)
674 *rc = GPG_ERR_CONFLICT;
675 return NULL;
678 is_literal_element (&req[i]);
680 if ((n = find_element (client, node, req[i],
681 find_stop_node (node), rc)) == NULL ||
682 (n && n->parent == node->parent))
685 if (!*rc)
686 *rc = create_new_element (client, verify, node, req[i], &node);
688 if (*rc)
689 return NULL;
691 else
692 node = n;
695 return node;
698 xmlNodePtr
699 find_text_node (xmlNodePtr node)
701 xmlNodePtr n = node;
703 if (n && n->type == XML_TEXT_NODE)
704 return n;
706 for (n = node; n; n = n->next)
708 if (n->type == XML_TEXT_NODE)
709 return n;
712 return NULL;
715 xmlNodePtr
716 create_elements_cb (struct client_s *client, int verify, xmlNodePtr node,
717 char **elements, gpg_error_t * rc, void *data)
719 int i;
720 char **req = elements;
722 if (*rc && *rc != GPG_ERR_ELEMENT_NOT_FOUND)
723 return NULL;
725 if (node->type == XML_TEXT_NODE)
726 node = node->parent;
728 for (i = 0; req[i] && *req[i]; i++)
730 xmlNodePtr n;
733 * Strip the first '!' if needed. If there's another, it's an
734 * rc. The syntax has already been checked before calling this
735 * function.
737 is_literal_element (&req[i]);
738 n = find_element (client, node, req[i], find_stop_node (node), rc);
739 if (*rc)
740 return NULL;
743 * If the found element has the same parent as the current element,
744 * they are siblings and the new element needs to be created as a
745 * child of the current element (node).
747 if (n && n->parent == node->parent)
748 n = NULL;
750 if (!n)
752 *rc = create_new_element (client, 0, node, req[i], &node);
753 if (*rc)
754 return NULL;
756 else
757 node = n;
760 return node;
763 /* The root element is really req[0]. It is need as a pointer in case there is
764 * a target attribute so it can be updated. */
765 xmlNodePtr
766 find_root_element (struct client_s *client, xmlDocPtr doc, char ***req,
767 gpg_error_t * rc, int *target, int recursion_depth,
768 int stop)
770 xmlNodePtr n = xmlDocGetRootElement (doc);
771 int depth = 0;
772 char *root = str_dup (*req[0]);
773 int literal = is_literal_element (&root);
775 if (!root)
777 *rc = GPG_ERR_ENOMEM;
778 return NULL;
781 *rc = 0;
782 recursion_depth++;
784 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
786 xmlChar *t = xmlGetNodePath (n);
788 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
789 xmlFree (t);
790 xfree (root);
791 *rc = GPG_ERR_ELOOP;
792 return NULL;
795 while (n)
797 if (n->type == XML_ELEMENT_NODE)
799 if (depth == 0 && xmlStrEqual (n->name, (xmlChar *) "pwmd"))
801 n = n->children;
802 depth++;
803 continue;
806 if (depth == 1 && xmlStrEqual (n->name, (xmlChar *) "element"))
808 xmlChar *content = node_has_attribute (n, (xmlChar *) "_name");
810 if (!content)
811 continue;
813 if (xmlStrEqual (content, (xmlChar *) root))
815 char **nreq, **tmp = NULL;
816 int acl = client->flags & FLAG_ACL_IGNORE;
818 *rc = acl_check(client, n);
819 if ((*rc && *rc != GPG_ERR_EACCES)
820 || (*rc == GPG_ERR_EACCES && !acl))
822 xmlFree (content);
823 xfree (root);
824 return n;
827 if (acl)
829 *rc = 0;
830 // This flag is cleared in acl_check() but we always
831 // allow ATTR LIST of root elements.
832 client->flags |= FLAG_ACL_IGNORE;
835 if (literal == 1)
837 xmlFree (content);
838 xfree (root);
839 return n;
842 xmlFree (content);
843 content = node_has_attribute (n, (xmlChar *) "target");
845 if (content && target)
846 *target = 1;
848 if (!content || stop)
850 if (content)
851 xmlFree (content);
853 xfree (root);
854 return n;
857 if (strchr ((char *) content, '\t'))
859 nreq = str_split ((char *) content, "\t", 0);
860 xmlFree (content);
862 #if 0
864 * FIXME ENOMEM
866 if (!nreq)
868 *rc = GPG_ERR_ENOMEM;
869 return NULL;
871 #endif
873 tmp = *req;
874 tmp = strv_catv (nreq, tmp + 1);
875 strv_free (nreq);
877 if (!tmp)
879 xfree (root);
880 *rc = GPG_ERR_ENOMEM;
881 return NULL;
884 strv_free (*req);
885 *req = tmp;
887 else
889 if (strv_printf (&tmp, "%s", content) == 0)
891 xmlFree (content);
892 xfree (root);
893 *rc = GPG_ERR_ENOMEM;
894 return NULL;
897 xmlFree (content);
898 nreq = *req;
899 nreq = strv_catv (tmp, nreq + 1);
900 strv_free (tmp);
902 if (!nreq)
904 *rc = GPG_ERR_ENOMEM;
905 xfree (root);
906 return NULL;
909 strv_free (*req);
910 *req = nreq;
913 xfree (root);
914 return find_root_element (client, doc, req, rc, target,
915 recursion_depth, 0);
918 xmlFree (content);
922 n = n->next;
925 xfree (root);
926 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
927 return NULL;
930 xmlNodePtr
931 find_element (struct client_s *client, xmlNodePtr node, char *element,
932 xmlNodePtr stop, gpg_error_t *rc)
934 xmlNodePtr n;
936 *rc = 0;
938 if (!node || !element)
939 return NULL;
941 for (n = node; n; n = n->next)
943 if (n->type != XML_ELEMENT_NODE)
944 continue;
946 if (n == stop)
947 break;
949 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
951 if (a && xmlStrEqual (a, (xmlChar *) element))
953 xmlFree (a);
955 // Prevent ATTR LIST showing child element attributes for a parent
956 // whos ACL denies the client.
957 if (client->flags & FLAG_ACL_ERROR)
959 *rc = GPG_ERR_EACCES;
960 return NULL;
963 *rc = acl_check(client, n);
964 if (*rc)
965 n = NULL;
967 return n;
970 xmlFree (a);
973 return NULL;
976 xmlChar *
977 node_has_attribute (xmlNodePtr n, xmlChar * attr)
979 xmlAttrPtr a = xmlHasProp (n, attr);
981 if (!a)
982 return NULL;
984 if (!a->children || !a->children->content)
985 return NULL;
987 return xmlGetProp (n, attr);
990 static int
991 element_to_literal (char **element)
993 char *p = str_asprintf ("!%s", *element);
995 if (!p)
996 return 0;
998 xfree (*element);
999 *element = p;
1000 return 1;
1003 /* Resolves elements in 'req' one at a time. It's recursive in case of
1004 * "target" attributes. */
1005 xmlNodePtr
1006 find_elements (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1007 char **req, gpg_error_t * rc, int *target,
1008 xmlNodePtr (*found_fn) (struct client_s *, xmlNodePtr, char **,
1009 gpg_error_t *, char **, void *),
1010 xmlNodePtr (*not_found_fn) (struct client_s *, int, xmlNodePtr,
1011 char **, gpg_error_t *, void *),
1012 int is_list_command, int recursion_depth, void *data, int stop)
1014 xmlNodePtr n, last, last_node;
1015 char **p;
1016 int found = 0;
1018 *rc = 0;
1019 recursion_depth++;
1021 if (max_recursion_depth >= 1 && recursion_depth > max_recursion_depth)
1023 xmlChar *t = xmlGetNodePath (node);
1025 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1026 xmlFree (t);
1027 recursion_depth--;
1028 *rc = GPG_ERR_ELOOP;
1029 return NULL;
1032 for (last_node = last = n = node, p = req; *p; p++)
1034 xmlNodePtr tmp;
1035 char *t;
1036 int literal;
1038 if (!*(*p))
1040 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1041 return NULL;
1044 t = str_dup (*p);
1045 if (!t)
1047 *rc = GPG_ERR_ENOMEM;
1048 return NULL;
1051 literal = is_literal_element (&t);
1052 n = find_element (client, last, t, NULL, rc);
1053 xfree (t);
1054 if (!n)
1056 if (!*rc)
1057 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1059 /* Fixes ATTR LIST when an element does not exist and the parent
1060 * denies access to children. Fixes leaking information about the
1061 * current elements children. */
1062 if (*rc == GPG_ERR_ELEMENT_NOT_FOUND && last_node != n)
1064 gpg_error_t trc = acl_check (client, last_node);
1065 if (trc)
1066 *rc = trc;
1069 if (not_found_fn)
1070 return not_found_fn (client, 0,
1071 found ? last_node : last_node->parent, p,
1072 rc, data);
1073 return NULL;
1076 last = n->children;
1077 last_node = n;
1078 found = 1;
1080 if (literal == 0)
1082 xmlChar *content = node_has_attribute (n, (xmlChar *) "target");
1083 char **nreq = NULL, **nnreq;
1085 if (!content)
1087 if (is_list_command == 1)
1089 if (element_to_literal (&(*p)) == 0)
1091 *rc = GPG_ERR_ENOMEM;
1092 return NULL;
1096 continue;
1099 if (target)
1100 *target = 1;
1102 if (!*(p + 1) && stop)
1104 xmlFree (content);
1105 return n;
1108 if (strchr ((char *) content, '\t') != NULL)
1110 if ((nreq = str_split ((char *) content, "\t", 0)) == NULL)
1112 xmlFree (content);
1113 *rc = GPG_ERR_INV_VALUE;
1114 return NULL;
1117 else
1119 if ((nreq = str_split ((char *) content, " ", 0)) == NULL)
1121 xmlFree (content);
1122 *rc = GPG_ERR_INV_VALUE;
1123 return NULL;
1127 xmlFree (content);
1128 tmp = find_root_element (client, doc, &nreq, rc, target, 0, 0);
1129 if (*rc)
1131 strv_free (nreq);
1132 if (not_found_fn && *rc == GPG_ERR_EACCES)
1133 return not_found_fn (client, 0, NULL, p, rc, data);
1134 return tmp;
1137 if (found_fn)
1139 found_fn (client, tmp, nreq, rc, p + 1, data);
1141 if (*rc)
1143 strv_free (nreq);
1144 return NULL;
1148 if (!*(nreq + 1) && !*(p + 1))
1150 strv_free (nreq);
1151 return tmp;
1154 nnreq = strv_catv (nreq + 1, p + 1);
1155 strv_free (nreq);
1157 // FIXME ENOMEM
1158 if (!nnreq || !*nnreq)
1160 strv_free (nnreq);
1161 return tmp;
1164 if (tmp->children)
1166 n = find_elements (client, doc, tmp->children, nnreq, rc, NULL,
1167 found_fn, not_found_fn, is_list_command,
1168 recursion_depth, data, stop);
1169 if (!n)
1171 strv_free (nnreq);
1172 return NULL;
1175 else
1177 strv_free (nnreq);
1178 if (not_found_fn)
1179 return not_found_fn (client, 0, tmp, p, rc, data);
1181 *rc = GPG_ERR_ELEMENT_NOT_FOUND;
1182 return NULL;
1185 if (*(p + 1))
1187 char **zz = p + 1, **qq = nnreq;
1189 if (strv_length (nnreq) > strv_length (p + 1))
1190 qq = nnreq + 1;
1192 for (; *qq && *zz; zz++)
1194 xfree (*zz);
1195 *zz = str_dup (*qq++);
1197 if (!*zz)
1199 *rc = GPG_ERR_ENOMEM;
1200 n = NULL;
1201 break;
1206 strv_free (nnreq);
1207 return n;
1211 return n;
1214 static int
1215 update_element_list (struct element_list_s *elements)
1217 char *line;
1218 struct slist_s *l;
1220 if (!elements || !elements->elements)
1221 return 1;
1223 line = strv_join ("\t", elements->elements);
1225 if (!line)
1226 return 0;
1228 strv_free (elements->elements);
1229 elements->elements = NULL;
1230 l = slist_append (elements->list, line);
1232 if (!l)
1233 return 0;
1235 elements->list = l;
1236 return 1;
1239 static gpg_error_t
1240 path_list_recurse (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
1241 struct element_list_s *elements)
1243 gpg_error_t rc = 0;
1244 xmlNodePtr n;
1245 gpg_error_t error_flag = 0;
1247 for (n = node; n; n = n->next)
1249 xmlChar *target = NULL;
1250 xmlChar *a = node_has_attribute (n, (xmlChar *) "_name");
1251 gpg_error_t err = 0;
1252 char *path = NULL;
1254 rc = 0;
1255 if (!a)
1256 continue;
1258 if (n->type != XML_ELEMENT_NODE)
1259 goto children;
1261 rc = acl_check(client, n);
1263 if (elements->verbose)
1265 if (strv_printf
1266 (&elements->elements, "%s\t!%s%s%s", elements->prefix, a,
1267 !rc && find_element_node (n->children) ? " +" : "",
1268 rc == GPG_ERR_EACCES ? " P" : rc ? " E" : "") == 0)
1270 xmlFree (a);
1271 return GPG_ERR_ENOMEM;
1274 else
1275 if (strv_printf (&elements->elements, "%s\t!%s", elements->prefix, a)
1276 == 0)
1278 xmlFree (a);
1279 return GPG_ERR_ENOMEM;
1282 if (update_element_list (elements) == 0)
1284 xmlFree (a);
1285 return GPG_ERR_ENOMEM;
1288 if (rc == GPG_ERR_EACCES)
1290 xmlFree(a);
1291 error_flag = rc;
1292 continue;
1294 else if (rc)
1296 xmlFree (a);
1297 return rc;
1300 target = node_has_attribute (n, (xmlChar *) "target");
1301 if (target)
1303 char *tmp;
1304 char *save = elements->prefix;
1305 int r = elements->resolving;
1306 char **req = NULL;
1307 xmlNodePtr tnode;
1308 struct string_s *realpath = NULL;
1310 tnode = resolve_path (client, doc, target, &req, &rc);
1311 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_ELEMENT_NOT_FOUND
1312 || rc == GPG_ERR_EACCES)
1314 if (rc == GPG_ERR_ELOOP)
1316 xmlChar *t = xmlGetNodePath (n);
1318 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP), t);
1319 xmlFree (t);
1322 if (elements->verbose)
1324 error_flag = err = rc;
1325 rc = 0;
1328 else if (!elements->verbose && rc)
1330 xmlFree (a);
1331 xmlFree (target);
1332 return rc;
1335 path = str_asprintf("%s\t%s", elements->prefix, a);
1336 rc = validate_target_attribute (client, client->doc, path, tnode);
1337 xfree (path);
1338 if (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES
1339 || rc == GPG_ERR_ELEMENT_NOT_FOUND)
1341 if (rc != GPG_ERR_ELEMENT_NOT_FOUND)
1342 error_flag = err = rc;
1344 rc = 0;
1346 else if (rc)
1348 xmlFree (a);
1349 xmlFree (target);
1350 return rc;
1353 if (err)
1355 strv_printf (&elements->elements, "%s\t%s %s%s%s",
1356 elements->prefix, a,
1357 err == GPG_ERR_ELOOP ? "O" :
1358 err == GPG_ERR_EACCES ? "P" : "E",
1359 elements->with_target ? "T " : "",
1360 elements->with_target ? (char *)target : "");
1362 else if (!err && elements->with_target)
1364 rc = build_realpath (client, doc, (char *) target, &realpath);
1365 if (rc)
1367 xmlFree (a);
1368 xmlFree (target);
1369 return rc;
1372 realpath = string_prepend (realpath, "T ");
1375 if (!err && elements->verbose)
1377 if (!strv_printf (&elements->elements, "%s\t%s%s%s%s",
1378 elements->prefix, a,
1379 (tnode && find_element_node (tnode->children))
1380 || realpath ? " " : "", tnode
1381 && find_element_node (tnode->children) ? "+" :
1382 "", realpath ? realpath->str : ""))
1384 xmlFree (a);
1385 xmlFree (target);
1386 return GPG_ERR_ENOMEM;
1389 else if (!err)
1390 if (!strv_printf
1391 (&elements->elements, "%s\t%s", elements->prefix, a))
1393 xmlFree (a);
1394 xmlFree (target);
1395 return GPG_ERR_ENOMEM;
1398 if (realpath)
1399 string_free (realpath, 1);
1401 tmp = strv_join ("\t", elements->elements);
1402 if (!tmp)
1404 xmlFree (a);
1405 xmlFree (target);
1406 return GPG_ERR_ENOMEM;
1409 if (update_element_list (elements) == 0)
1411 xfree (tmp);
1412 xmlFree (a);
1413 xmlFree (target);
1414 return GPG_ERR_ENOMEM;
1417 if (!err && elements->recurse)
1419 /* Prune element flags. */
1420 if (elements->verbose && strchr (tmp, ' '))
1422 char *p;
1424 for (p = tmp; *p; p++)
1426 if (*p == ' ')
1428 *p = 0;
1429 break;
1434 elements->prefix = tmp;
1435 elements->resolving = 1;
1436 rc = create_path_list (client, doc, elements, (char *) target);
1437 elements->resolving = r;
1438 elements->prefix = save;
1440 if (rc && gpg_err_code (rc) != GPG_ERR_ELOOP
1441 && gpg_err_code(rc) != GPG_ERR_EACCES)
1443 xfree (tmp);
1444 xmlFree (target);
1445 xmlFree (a);
1446 return rc;
1449 error_flag = err = rc;
1450 rc = 0;
1453 xfree (tmp);
1454 xmlFree (target);
1457 children:
1458 if (n->children && elements->recurse)
1460 char *tmp = str_asprintf ("%s\t!%s", elements->prefix, a);
1461 char *save = elements->prefix;
1463 if (!tmp)
1465 xmlFree (a);
1466 return GPG_ERR_ENOMEM;
1469 elements->prefix = tmp;
1470 rc = path_list_recurse (client, doc, n->children, elements);
1471 xfree (elements->prefix);
1472 elements->prefix = save;
1474 if (rc)
1476 if (gpg_err_code(rc) == GPG_ERR_ELOOP
1477 || gpg_err_code (rc) == GPG_ERR_EACCES
1478 || gpg_err_code (rc) == GPG_ERR_ELEMENT_NOT_FOUND)
1480 error_flag = err = rc;
1481 rc = 0;
1483 else
1485 xmlFree (a);
1486 return rc;
1491 xmlFree (a);
1494 return error_flag == GPG_ERR_ELOOP || error_flag == GPG_ERR_EACCES
1495 ? error_flag : rc;
1498 gpg_error_t
1499 add_attribute (struct client_s *client, xmlNodePtr node, const char *name,
1500 const char *value)
1502 char *buf;
1503 gpg_error_t rc = 0;
1505 if (client && name && !strcmp (name, "target"))
1507 rc = is_element_owner (client, node);
1508 if (rc)
1509 return rc;
1512 if (name && !xmlSetProp (node, (xmlChar *) name, (xmlChar *) value))
1513 return GPG_ERR_BAD_DATA;
1515 if (client && name && !xmlStrEqual ((xmlChar *) name, (xmlChar *) "_acl"))
1517 xmlChar *acl = node_has_attribute (node, (xmlChar *) "_acl");
1519 if (!acl)
1521 char *user = create_acl_user (client);
1523 if (user)
1525 rc = add_attribute (client, node, (char *) "_acl", user);
1526 xfree (user);
1529 return rc;
1532 xmlFree (acl);
1535 if (name && xmlStrEqual ((xmlChar *) name, (xmlChar *) "_mtime"))
1536 return 0;
1538 buf = str_asprintf ("%li", time (NULL));
1539 rc = add_attribute (client, node, "_mtime", buf);
1540 xfree (buf);
1541 return rc;
1544 static xmlNodePtr
1545 list_not_found_cb (struct client_s *client, int i, xmlNodePtr node,
1546 char **req, gpg_error_t *rc, void *data)
1548 struct element_list_s *elements = data;
1550 if (*rc != GPG_ERR_EACCES)
1551 return NULL;
1553 elements->data = strv_dup (req);
1554 return NULL;
1558 * From the element path 'path', find sub-nodes and append them to the list.
1560 gpg_error_t
1561 create_path_list (struct client_s *client, xmlDocPtr doc,
1562 struct element_list_s * elements, char *path)
1564 gpg_error_t rc;
1565 char **req, **req_orig;
1566 xmlNodePtr n;
1567 int a_target = 0;
1568 int root_only = 0;
1569 int allowed = 1;
1571 req = str_split (path, "\t", 0);
1572 if (!req)
1574 req = str_split (path, " ", 0);
1575 if (!req)
1576 return GPG_ERR_SYNTAX;
1579 req_orig = strv_dup (req);
1580 if (!req_orig)
1582 rc = GPG_ERR_ENOMEM;
1583 goto fail;
1586 n = find_root_element (client, doc, &req, &rc, &a_target, 0, 0);
1587 if ((rc == GPG_ERR_ELEMENT_NOT_FOUND || rc == GPG_ERR_ELOOP
1588 || rc == GPG_ERR_EACCES) && elements->verbose && a_target)
1590 if (rc == GPG_ERR_EACCES)
1591 allowed = 0;
1593 root_only = 1;
1594 goto done;
1597 if (rc == GPG_ERR_EACCES)
1599 allowed = 0;
1600 root_only = 1;
1601 goto done;
1604 if (!n && rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1606 rc = 0;
1607 goto fail;
1609 else if (!n)
1610 goto fail;
1612 if (a_target == 1)
1614 xfree (*req);
1615 *req = str_dup (*req_orig);
1618 if (*(req + 1))
1620 int e_target = 0;
1622 n = find_elements (client, doc, n->children, req + 1, &rc, &e_target,
1623 NULL, list_not_found_cb, 1, 0, elements, 0);
1624 if (rc == GPG_ERR_ELEMENT_NOT_FOUND && elements->resolving == 1)
1626 rc = 0;
1627 goto fail;
1629 else if (rc && rc != GPG_ERR_EACCES)
1630 goto fail;
1631 else if (rc)
1632 allowed = 0;
1635 done:
1636 if (!elements->prefix)
1639 * FIXME
1641 * If any req_orig element contains no target the element should be
1642 * prefixed with the literal character. Not really crucial if the
1643 * client isn't human because child elements are prefixed for the
1644 * current path. But may be confusing if editing by hand.
1646 if (elements->data)
1648 /* This is needed to prune the original requested element path to the
1649 * length of the failed element in the path. */
1650 int x = strv_length (req_orig)-strv_length ((char **)elements->data);
1651 int i;
1652 char **tmp = NULL;
1654 for (i = 0; i <= x; i++)
1655 tmp = strv_cat (tmp, str_dup (req_orig[i]));
1657 elements->prefix = strv_join ("\t", tmp);
1658 strv_free (tmp);
1659 strv_free (elements->data);
1660 elements->data = NULL;
1662 else
1664 if (root_only)
1665 elements->prefix = str_dup (*req_orig);
1666 else
1667 elements->prefix = strv_join ("\t", req_orig);
1670 if (!elements->prefix)
1672 rc = GPG_ERR_ENOMEM;
1673 goto fail;
1676 if (elements->verbose)
1678 int ret;
1679 struct string_s *realpath = NULL;
1681 if (!rc && allowed && a_target && elements->with_target)
1683 rc = build_realpath (client, doc, path, &realpath);
1684 if (rc)
1685 goto fail;
1687 realpath = string_prepend (realpath, "T ");
1690 ret = strv_printf (&elements->elements, "%s%s%s%s%s%s%s",
1691 elements->prefix,
1692 (allowed && n && find_element_node (n->children))
1693 || realpath ? " " : "",
1694 (allowed && n && find_element_node (n->children)) ? "+" : "",
1695 allowed && realpath ? realpath->str : "",
1696 rc == GPG_ERR_ELOOP ? " O" : "",
1697 rc == GPG_ERR_ELEMENT_NOT_FOUND ? " E" : "",
1698 !allowed ? " P" : "");
1699 string_free (realpath, 1);
1700 if (!ret)
1702 rc = GPG_ERR_ENOMEM;
1703 goto fail;
1706 else
1708 if (strv_printf (&elements->elements, "%s", elements->prefix) == 0)
1710 rc = GPG_ERR_ENOMEM;
1711 goto fail;
1715 if (update_element_list (elements) == 0)
1717 rc = GPG_ERR_ENOMEM;
1718 goto fail;
1722 if (allowed)
1723 rc = path_list_recurse (client, doc, n ? n->children : n, elements);
1725 fail:
1726 strv_free (req_orig);
1727 strv_free (req);
1728 return rc;
1731 gpg_error_t
1732 recurse_xpath_nodeset (struct client_s *client, xmlDocPtr doc,
1733 xmlNodeSetPtr nodes, xmlChar * value,
1734 xmlBufferPtr * result, int cmd, const xmlChar * attr)
1736 int i = value ? nodes->nodeNr - 1 : 0;
1737 xmlBufferPtr buf;
1739 buf = xmlBufferCreate ();
1741 if (!buf)
1742 return GPG_ERR_ENOMEM;
1744 for (; value ? i >= 0 : i < nodes->nodeNr; value ? i-- : i++)
1746 xmlNodePtr n = nodes->nodeTab[i];
1747 gpg_error_t rc;
1749 if (!n)
1750 continue;
1752 if (!value && !attr)
1754 if (xmlNodeDump (buf, doc, n, 0, 0) == -1)
1756 *result = buf;
1757 return GPG_ERR_BAD_DATA;
1760 continue;
1763 if (!attr)
1765 xmlNodeSetContent (n, value);
1766 rc = update_element_mtime (client, n);
1768 if (rc)
1769 return rc;
1771 else
1773 if (!cmd)
1774 rc = add_attribute (client, n, (char *) attr, (char *) value);
1775 else
1776 rc = delete_attribute (client, n, attr);
1778 if (rc)
1779 return rc;
1783 *result = buf;
1784 return 0;
1787 static gpg_error_t
1788 convert_root_element (struct client_s *client, xmlNodePtr n)
1790 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1791 gpg_error_t rc;
1793 if (a)
1795 xmlFree (a);
1796 xmlChar *t = xmlGetNodePath (n);
1798 log_write (_
1799 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1801 xmlFree (t);
1802 return GPG_ERR_AMBIGUOUS_NAME;
1805 a = xmlGetProp (n, (xmlChar *) "name");
1807 if (a)
1809 rc = add_attribute (client, n, "_name", (char *) a);
1810 xmlFree (a);
1812 if (rc)
1813 return rc;
1815 rc = delete_attribute (client, n, (xmlChar *) "name");
1817 if (rc)
1818 return rc;
1820 xmlNodeSetName (n, (xmlChar *) "element");
1823 return 0;
1826 gpg_error_t
1827 delete_attribute (struct client_s *client, xmlNodePtr n, const xmlChar * name)
1829 xmlAttrPtr a;
1830 gpg_error_t rc = 0;
1832 if ((a = xmlHasProp (n, name)) == NULL)
1833 return GPG_ERR_NOT_FOUND;
1835 if (xmlRemoveProp (a) == -1)
1836 return GPG_ERR_BAD_DATA;
1838 if (client && xmlStrEqual (name, (xmlChar *) "_acl"))
1840 char *user = create_acl_user (client);
1842 rc = add_attribute (client, n, (char *) "_acl", user);
1843 xfree (user);
1845 if (rc)
1846 return rc;
1849 return update_element_mtime (client, n);
1852 static gpg_error_t
1853 convert_elements_recurse (struct client_s *client, xmlDocPtr doc,
1854 xmlNodePtr n, unsigned depth)
1856 gpg_error_t rc;
1858 depth++;
1860 for (n = n->children; n; n = n->next)
1862 if (n->type == XML_ELEMENT_NODE)
1864 if (depth > 1)
1866 xmlChar *a = NULL;
1868 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1870 xmlChar *t = xmlGetNodePath (n);
1872 log_write (_
1873 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1875 xmlFree (t);
1876 return GPG_ERR_AMBIGUOUS_NAME;
1879 a = xmlGetProp (n, (xmlChar *) "_name");
1880 if (a)
1882 xmlFree (a);
1883 xmlChar *t = xmlGetNodePath (n);
1885 log_write (_
1886 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1888 xmlFree (t);
1889 return GPG_ERR_AMBIGUOUS_NAME;
1892 xmlChar *tmp = xmlStrdup (n->name);
1894 if (!tmp)
1895 return GPG_ERR_ENOMEM;
1897 xmlNodeSetName (n, (xmlChar *) "element");
1898 rc = add_attribute (client, n, "_name", (char *) tmp);
1899 xmlFree (tmp);
1901 if (rc)
1902 return rc;
1904 else
1906 rc = convert_root_element (client, n);
1908 if (rc)
1909 return rc;
1913 if (n->children)
1915 rc = convert_elements_recurse (client, doc, n, depth);
1917 if (rc)
1918 return rc;
1922 return 0;
1925 /* Renames ALL elements to the new "element" name. Existing element names are
1926 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1927 * elements can contain common characters that the XML parser barfs on (an
1928 * email address for example. */
1929 gpg_error_t
1930 convert_pre_212_elements (xmlDocPtr doc)
1932 xmlNodePtr n = xmlDocGetRootElement (doc);
1934 log_write (_("Converting pre 2.12 data file..."));
1935 return convert_elements_recurse (NULL, doc, n, 0);
1938 gpg_error_t
1939 validate_import (struct client_s *client, xmlNodePtr node)
1941 gpg_error_t rc = 0;
1943 if (!node)
1944 return 0;
1946 for (xmlNodePtr n = node; n; n = n->next)
1948 if (n->type == XML_ELEMENT_NODE)
1950 if (xmlStrEqual (n->name, (xmlChar *) "element"))
1952 xmlChar *a = xmlGetProp (n, (xmlChar *) "_name");
1954 if (!a)
1956 xmlChar *t = xmlGetNodePath (n);
1958 log_write (_("Missing attribute '_name' at %s."), t);
1959 xmlFree (t);
1960 return GPG_ERR_INV_VALUE;
1963 if (!valid_xml_element (a))
1965 xmlChar *t = xmlGetNodePath (n);
1967 log_write (_("'%s' is not a valid element name at %s."), a,
1969 xmlFree (a);
1970 xmlFree (t);
1971 return GPG_ERR_INV_VALUE;
1974 xmlFree (a);
1975 a = xmlGetProp (n, (xmlChar *) "_ctime");
1976 if (!a)
1977 attr_ctime (client, n);
1979 xmlFree (a);
1980 a = xmlGetProp (n, (xmlChar *) "_mtime");
1981 if (!a)
1982 update_element_mtime (client, n);
1983 xmlFree (a);
1985 else
1987 xmlChar *t = xmlGetNodePath (n);
1989 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1990 n->name, t);
1991 xmlFree (t);
1992 continue;
1996 if (n->children)
1998 rc = validate_import (client, n->children);
2000 if (rc)
2001 return rc;
2005 return rc;
2008 gpg_error_t
2009 update_element_mtime (struct client_s *client, xmlNodePtr n)
2011 return add_attribute (client, n, NULL, NULL);
2014 gpg_error_t
2015 unlink_node (struct client_s *client, xmlNodePtr n)
2017 gpg_error_t rc = 0;
2019 if (!n)
2020 return rc;
2022 if (n->parent)
2023 rc = update_element_mtime (client, n->parent);
2025 xmlUnlinkNode (n);
2026 return rc;
2029 gpg_error_t
2030 parse_doc (const char *xml, size_t len, xmlDocPtr *result)
2032 xmlDocPtr doc;
2034 xmlResetLastError ();
2035 doc = xmlReadMemory (xml, len, NULL, "UTF-8", XML_PARSE_NOBLANKS);
2036 if (!doc && xmlGetLastError ())
2037 return GPG_ERR_BAD_DATA;
2039 *result = doc;
2040 return !doc ? GPG_ERR_ENOMEM : 0;
2043 static xmlNodePtr
2044 realpath_elements_cb (struct client_s *client, xmlNodePtr node, char **target,
2045 gpg_error_t * rc, char **req_orig, void *data)
2047 char *path = *(char **) data;
2048 char *tmp = NULL, *result;
2050 if (path)
2052 xfree (path);
2053 *(char **) data = NULL;
2056 path = strv_join ("\t", target);
2058 if (!path)
2060 *rc = GPG_ERR_ENOMEM;
2061 return NULL;
2064 if (req_orig)
2066 tmp = strv_join ("\t", req_orig);
2068 if (!tmp)
2070 xfree (path);
2071 *rc = GPG_ERR_ENOMEM;
2072 return NULL;
2076 if (tmp && *tmp)
2077 result = str_asprintf ("%s\t%s", path, tmp);
2078 else
2079 result = str_dup (path);
2081 if (!result)
2083 *rc = GPG_ERR_ENOMEM;
2084 xfree (path);
2085 xfree (tmp);
2086 return NULL;
2089 xfree (path);
2090 xfree (tmp);
2091 *(char **) data = result;
2092 return node;
2095 gpg_error_t
2096 build_realpath (struct client_s *client, xmlDocPtr doc, char *line,
2097 struct string_s ** result)
2099 gpg_error_t rc;
2100 char **req;
2101 char *t;
2102 int i;
2103 xmlNodePtr n;
2104 struct string_s *string;
2105 char *rp = NULL;
2107 if (strchr (line, '\t') != NULL)
2109 if ((req = str_split (line, "\t", 0)) == NULL)
2110 return GPG_ERR_SYNTAX;
2112 else
2114 if ((req = str_split (line, " ", 0)) == NULL)
2115 return GPG_ERR_SYNTAX;
2118 n = find_root_element (client, doc, &req, &rc, NULL, 0, 0);
2119 if (rc)
2121 strv_free (req);
2122 return rc;
2125 rp = strv_join ("\t", req);
2126 if (!rp)
2128 strv_free (req);
2129 return GPG_ERR_ENOMEM;
2132 if (req[1])
2134 n = find_elements (client, doc, n->children, req + 1, &rc, NULL,
2135 realpath_elements_cb, NULL, 0, 0, &rp, 0);
2136 if (!n)
2138 xfree (rp);
2139 strv_free (req);
2140 return rc;
2144 string = string_new (rp);
2145 xfree (rp);
2146 strv_free (req);
2147 if (!string)
2148 return GPG_ERR_ENOMEM;
2150 again:
2151 for (i = 0, t = string->str + i; *t; t++, i++)
2153 if ((!i && *t != '!') || (*t == '\t' && *(t + 1) && *(t + 1) != '!'))
2155 struct string_s *s = string_insert_c (string, !i ? i++ : ++i, '!');
2157 if (!s)
2159 string_free (string, 1);
2160 return GPG_ERR_ENOMEM;
2163 string = s;
2164 goto again;
2168 *result = string;
2169 return rc;
2172 #if 0
2173 static char *
2174 node_to_element_path (xmlNodePtr node)
2176 xmlNodePtr n;
2177 struct string_s *str = string_new ("");
2178 char *result;
2180 for (n = node; n; n = n->parent)
2182 xmlNodePtr child;
2184 for (child = n; child; child = child->next)
2186 if (child->type != XML_ELEMENT_NODE)
2187 continue;
2189 xmlChar *name = node_has_attribute (n, (xmlChar *) "_name");
2190 if (name)
2192 str = string_prepend (str, (char *) name);
2193 xmlFree (name);
2194 name = node_has_attribute (n, (xmlChar *) "target");
2195 if (name)
2196 str = string_prepend (str, "\t");
2197 else
2198 str = string_prepend (str, "\t!");
2199 xmlFree (name);
2201 break;
2205 str = string_erase (str, 0, 1);
2206 result = str->str;
2207 string_free (str, 0);
2208 return result;
2210 #endif
2213 * Recurse the element tree beginning at 'node' and find elements who point
2214 * back to 'src' or 'dst'. Also follows target attributes.
2216 static gpg_error_t
2217 find_child_to_target (struct client_s *client, xmlDocPtr doc, xmlNodePtr node,
2218 xmlNodePtr src, xmlNodePtr dst, unsigned depth,
2219 int is_target)
2221 xmlNodePtr n;
2222 gpg_error_t rc = 0;
2224 if (max_recursion_depth >= 1 && depth > max_recursion_depth)
2225 return gpg_error (GPG_ERR_ELOOP);
2227 for (n = node; n; n = n->next)
2229 xmlChar *target;
2231 if (n->type != XML_ELEMENT_NODE)
2232 continue;
2234 if (n == src || n == dst)
2235 return GPG_ERR_ELOOP;
2237 target = node_has_attribute (n, (xmlChar *) "target");
2238 if (target)
2240 xmlNodePtr tmp;
2241 char **result = NULL;
2243 tmp = resolve_path (client, doc, target, &result, &rc);
2244 xmlFree (target);
2245 strv_free (result);
2246 if (!rc)
2248 rc = find_child_to_target (client, doc, tmp, src, dst, ++depth,
2250 depth--;
2253 if (rc && gpg_err_code (rc) != GPG_ERR_ELEMENT_NOT_FOUND)
2254 return rc;
2256 if (is_target)
2257 break;
2259 continue;
2262 if (n->children)
2264 rc = find_child_to_target (client, doc, n->children, src, dst,
2265 ++depth,0);
2266 depth--;
2267 if (rc)
2268 return rc;
2271 if (is_target)
2272 break;
2275 return rc;
2278 static gpg_error_t
2279 find_child_of_parent (xmlDocPtr doc, xmlNodePtr src, xmlNodePtr dst)
2281 xmlNodePtr n;
2282 gpg_error_t rc = 0;
2284 for (n = src; n; n = n->next)
2286 if (n->type != XML_ELEMENT_NODE)
2287 continue;
2289 if (n == dst)
2291 rc = GPG_ERR_ELOOP;
2292 break;
2295 rc = find_child_of_parent (doc, n->children, dst);
2298 return rc;
2301 static gpg_error_t
2302 find_parent_of_child (xmlDocPtr doc, xmlNodePtr node, xmlNodePtr dst)
2304 xmlNodePtr n;
2305 gpg_error_t rc = 0;
2307 for (n = node; n; n = n->parent)
2309 if (n->type != XML_ELEMENT_NODE)
2311 xmlNodePtr tmp;
2313 for (tmp = n->next; tmp; n = n->next)
2315 if (n->type != XML_ELEMENT_NODE)
2316 continue;
2318 if (tmp == dst)
2319 return GPG_ERR_ELOOP;
2323 if (n == dst)
2324 return GPG_ERR_ELOOP;
2327 return rc;
2330 gpg_error_t
2331 validate_target_attribute (struct client_s *client, xmlDocPtr doc,
2332 const char *src, xmlNodePtr dst_node)
2334 gpg_error_t rc;
2335 xmlNodePtr src_node;
2336 char **src_req = NULL;
2338 src_node = resolve_path (client, doc, (xmlChar *) src, &src_req, &rc);
2339 if (rc)
2340 goto fail;
2342 client->flags |= FLAG_ACL_IGNORE;
2343 /* A destination element is a child of the source element. */
2344 rc = find_child_of_parent (doc, src_node->children, dst_node);
2345 if (rc)
2346 goto fail;
2348 /* The destination element is a parent of the source element. */
2349 rc = find_parent_of_child (doc, src_node->parent, dst_node);
2350 if (rc)
2351 goto fail;
2353 /* A destination child element contains a target to the source element. */
2354 if (dst_node)
2355 rc = find_child_to_target (client, doc, dst_node->children, src_node,
2356 dst_node, 0, 0);
2357 if (rc)
2358 goto fail;
2360 fail:
2361 strv_free (src_req);
2362 client->flags &= ~(FLAG_ACL_IGNORE | FLAG_ACL_ERROR);
2363 return rc;
2366 /* The owner of the element is the first user listed in the _acl attribute
2367 * list. acl_check() should be called before calling this function. An empty
2368 * ACL is an error if the client is not invoking_user.
2370 gpg_error_t
2371 is_element_owner (struct client_s *client, xmlNodePtr n)
2373 xmlChar *acl = node_has_attribute (n, (xmlChar *) "_acl");
2374 char **users;
2375 gpg_error_t rc = GPG_ERR_EACCES;
2377 if (!acl || !*acl)
2379 xmlFree (acl);
2380 return peer_is_invoker (client);
2383 users = str_split((char *)acl, ",", 0);
2384 if (users && *users)
2386 char *user;
2388 #ifdef WITH_GNUTLS
2389 if (client->thd->remote)
2390 user = str_asprintf ("#%s", client->thd->tls->fp);
2391 else
2392 user = get_username (client->thd->peer->uid);
2393 #else
2394 user = get_username (client->thd->peer->uid);
2395 #endif
2397 if (*user == '#')
2398 rc = !strcasecmp (*users, user) ? 0 : GPG_ERR_EACCES;
2399 else
2400 rc = !strcmp (*users, user) ? 0 : GPG_ERR_EACCES;
2402 if (rc)
2403 rc = peer_is_invoker (client);
2405 xfree (user);
2408 strv_free (users);
2409 return rc;