2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
33 #include <libxml/xmlwriter.h>
35 #include <sys/types.h>
40 #define _(msgid) gettext(msgid)
43 #include "pwmd-error.h"
44 #include "util-misc.h"
50 #define XML_LIST_FLAG_CHILDREN 0x0001
51 #define XML_LIST_HAS_TARGET 0x0002
52 #define XML_LIST_CHILD_TARGET 0x0004
53 #define XML_LIST_TARGET_ERROR 0x0008
54 #define XML_LIST_CHECK 0x0010
56 const char *reserved_attributes
[] = {
57 "_name", "_mtime", "_ctime", "_acl", "target",
61 extern void log_write (const char *fmt
, ...);
64 xml_valid_attribute_value (const char *str
)
81 xml_valid_attribute (const char *str
)
85 int ret
= xml_valid_element ((xmlChar
*)str
);
90 wc
= str_to_wchar ((const char *)str
);
95 for (c
= 0; c
< len
; c
++)
103 case 0x0300 ... 0x036F:
104 case 0x203F ... 0x2040:
112 case 'A' ... 'Z': break;
113 case 'a' ... 'z': break;
114 case 0xC0 ... 0xD6: break;
115 case 0xD8 ... 0xF6: break;
116 case 0xF8 ... 0x2FF: break;
117 case 0x370 ... 0x37D: break;
118 case 0x37F ... 0x1FFF: break;
119 case 0x200C ... 0x200D: break;
120 case 0x2070 ... 0x218F: break;
121 case 0x2C00 ... 0x2FEF: break;
122 case 0x3001 ... 0xD7FF: break;
123 case 0xF900 ... 0xFDCF: break;
124 case 0xFDF0 ... 0xFFFD: break;
125 case 0x10000 ... 0xEFFFF: break;
137 xml_valid_element (xmlChar
*str
)
145 wc
= str_to_wchar ((const char *)str
);
150 for (c
= 0; c
< len
; c
++)
164 xml_valid_element_path (char **path
, int with_content
)
166 char **dup
= NULL
, **p
;
171 /* Save some memory by not duplicating the element content. */
174 int i
, t
= strv_length (path
);
176 for (i
= 0; i
< t
- 1; i
++)
178 char **tmp
= xrealloc (dup
, (i
+ 2) * sizeof (char *));
187 dup
[i
] = str_dup (path
[i
]);
192 dup
= strv_dup (path
);
197 for (p
= dup
; *p
&& *(*p
); p
++)
199 if (!xml_valid_element ((xmlChar
*) * p
))
211 attr_ctime (struct client_s
*client
, xmlNodePtr n
)
213 char *buf
= str_asprintf ("%li", time (NULL
));
217 return GPG_ERR_ENOMEM
;
219 rc
= xml_add_attribute (client
, n
, "_ctime", buf
);
225 acl_check (struct client_s
*client
, xmlNodePtr n
)
227 gpg_error_t rc
= GPG_ERR_EACCES
;
228 xmlChar
*acl
= xml_attribute_value (n
, (xmlChar
*) "_acl");
229 char **users
= acl
? str_split((char *)acl
, ",", 0) : NULL
;
233 if (!acl
|| !*acl
|| !users
|| !*users
)
237 return peer_is_invoker(client
);
240 if (!peer_is_invoker(client
))
247 for (p
= users
; p
&& *p
; p
++)
250 rc
= acl_check_common (client
, *p
,
251 client
->thd
->remote
? 0 : client
->thd
->peer
->uid
,
252 client
->thd
->remote
? 0 : client
->thd
->peer
->gid
,
255 rc
= acl_check_common (client
, *p
, client
->thd
->peer
->uid
,
256 client
->thd
->peer
->gid
, &allowed
);
266 return allowed
? 0 : GPG_ERR_EACCES
;
270 create_acl_user (struct client_s
*client
)
273 if (client
->thd
->remote
)
274 return str_asprintf ("#%s", client
->thd
->tls
->fp
);
277 return get_username (client
->thd
->peer
->uid
);
281 create_new_element (struct client_s
*client
, int verify
, xmlNodePtr parent
,
282 const char *name
, xmlNodePtr
* result
)
287 // Allow any client to create a non-existing root element.
288 if (parent
->parent
->type
!= XML_DOCUMENT_NODE
)
290 rc
= acl_check(client
, parent
);
295 n
= xmlNewNode (NULL
, (xmlChar
*) "element");
297 return GPG_ERR_ENOMEM
;
299 rc
= xml_add_attribute (client
, n
, "_name", name
);
301 rc
= attr_ctime (client
, n
);
303 if (!rc
&& verify
&& parent
->parent
->type
!= XML_DOCUMENT_NODE
)
304 rc
= xml_is_element_owner (client
, parent
);
308 xmlNodePtr p
= xmlAddChild (parent
, n
);
309 char *user
= create_acl_user (client
);
314 rc
= xml_add_attribute(client
, p
, "_acl", user
);
324 xml_new_root_element (struct client_s
*client
, xmlDocPtr doc
, char *name
)
326 xmlNodePtr root
= xmlDocGetRootElement (doc
);
329 return GPG_ERR_BAD_DATA
;
331 if (!xml_valid_element ((xmlChar
*) name
))
332 return GPG_ERR_INV_VALUE
;
334 return create_new_element (client
, 0, root
, name
, NULL
);
341 xmlTextWriterPtr wr
= xmlNewTextWriterDoc (&doc
, 0);
346 if (xmlTextWriterStartDocument (wr
, NULL
, "UTF-8", "yes"))
349 if (xmlTextWriterStartDTD (wr
, (xmlChar
*) "pwmd", NULL
, NULL
) == -1)
352 if (xmlTextWriterWriteDTDElement (wr
, (xmlChar
*) "pwmd",
353 (xmlChar
*) "(element)") == -1)
356 xmlTextWriterEndDTDElement (wr
);
358 if (xmlTextWriterWriteDTDAttlist (wr
, (xmlChar
*) "element",
359 (xmlChar
*) "_name CDATA #REQUIRED") ==
363 xmlTextWriterEndDTDAttlist (wr
);
364 xmlTextWriterEndDTD (wr
);
366 if (xmlTextWriterStartElement (wr
, (xmlChar
*) "pwmd"))
369 xmlTextWriterEndElement (wr
);
370 xmlTextWriterEndDocument (wr
);
371 xmlFreeTextWriter (wr
);
375 xmlTextWriterEndDocument (wr
);
376 xmlFreeTextWriter (wr
);
384 return create_dtd ();
388 find_element_node (xmlNodePtr node
)
392 if (n
&& n
->type
== XML_ELEMENT_NODE
)
395 for (n
= node
; n
; n
= n
->next
)
397 if (n
->type
== XML_ELEMENT_NODE
)
405 xml_resolve_path (struct client_s
*client
, xmlDocPtr doc
, xmlChar
* path
,
406 char ***result
, gpg_error_t
*rc
)
409 struct xml_request_s
*req
;
411 *rc
= xml_new_request (client
, (char *)path
, XML_CMD_REALPATH
, &req
);
415 n
= xml_find_elements (client
, req
, xmlDocGetRootElement (doc
), rc
);
420 *result
= strv_dup (req
->args
);
423 *rc
= GPG_ERR_ENOMEM
;
429 xml_free_request (req
);
434 * Prevents a sibling element past the current element path with the same
438 find_sibling_node (xmlNodePtr node
)
442 if (!node
|| !node
->parent
)
445 for (n
= node
->parent
->children
; n
; n
= n
->next
)
455 xml_find_text_node (xmlNodePtr node
)
459 if (n
&& n
->type
== XML_TEXT_NODE
)
462 for (n
= node
; n
; n
= n
->next
)
464 if (n
->type
== XML_TEXT_NODE
)
471 /* Create an element 'path' starting at 'node'. Returns the node of the final
475 xml_create_element_path (struct client_s
*client
, struct xml_request_s
*req
,
476 xmlNodePtr node
, char **path
, gpg_error_t
*rc
)
480 /* The parent node will be an XML_ELEMENT_NODE. Otherwise we would be
481 * creating element content. */
482 if (node
->type
== XML_TEXT_NODE
)
485 for (p
= path
; p
&& *p
; p
++)
489 if (node
!= xmlDocGetRootElement (req
->doc
))
491 n
= xml_find_element (client
, node
, *p
, find_sibling_node (node
), rc
);
492 if (*rc
&& *rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
499 * If the found element has the same parent as the current element then
500 * they are siblings and the new element needs to be created as a child
501 * of the current element (node).
503 if (n
&& n
->parent
== node
->parent
)
508 *rc
= create_new_element (client
, 0, node
, *p
, &node
);
519 /* Find the first XML_ELEMENT_NODE whose _name attribute matches 'element'. */
521 xml_find_element (struct client_s
*client
, xmlNodePtr node
, const char *element
,
522 xmlNodePtr stop
, gpg_error_t
*rc
)
528 if (!node
|| !element
)
530 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
534 for (n
= node
; n
; n
= n
->next
)
536 if (n
->type
!= XML_ELEMENT_NODE
)
542 xmlChar
*a
= xml_attribute_value (n
, (xmlChar
*) "_name");
543 if (a
&& xmlStrEqual (a
, (xmlChar
*) element
))
546 *rc
= acl_check (client
, n
);
547 return n
; // Not NULL since the node may be needed later
553 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
558 xml_attribute_value (xmlNodePtr n
, xmlChar
* attr
)
560 xmlAttrPtr a
= xmlHasProp (n
, attr
);
565 if (!a
->children
|| !a
->children
->content
)
568 return xmlGetProp (n
, attr
);
572 remove_non_reserved_attributes (xmlNodePtr n
)
576 for (a
= n
->properties
; a
; a
= a
->next
)
578 if (xml_reserved_attribute ((char *)a
->name
))
581 (void)xml_delete_attribute (NULL
, n
, a
->name
);
586 xml_add_attribute (struct client_s
*client
, xmlNodePtr node
, const char *name
,
593 if (client
&& name
&& !strcmp (name
, "target"))
595 rc
= xml_is_element_owner (client
, node
);
601 else if (name
&& !strcmp (name
, "expire"))
606 if (!value
|| !*value
)
607 return GPG_ERR_INV_VALUE
;
610 e
= strtoul (value
, &p
, 10);
611 if (errno
|| *p
|| e
== ULONG_MAX
|| *value
== '-')
612 return GPG_ERR_INV_VALUE
;
615 if (name
&& !xmlSetProp (node
, (xmlChar
*) name
, (xmlChar
*) value
))
616 return GPG_ERR_BAD_DATA
;
618 if (client
&& name
&& !xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_acl"))
620 xmlChar
*acl
= xml_attribute_value (node
, (xmlChar
*) "_acl");
624 char *user
= create_acl_user (client
);
628 rc
= xml_add_attribute (client
, node
, (char *) "_acl", user
);
638 if (name
&& xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_mtime"))
642 remove_non_reserved_attributes (node
);
644 buf
= str_asprintf ("%lu", time (NULL
));
645 rc
= xml_add_attribute (client
, node
, "_mtime", buf
);
651 append_path_to_list (struct client_s
*client
, struct element_list_s
*elements
,
652 const char *path
, gpg_error_t rc
)
655 struct string_s
*line
;
657 line
= string_new (NULL
);
659 return GPG_ERR_ENOMEM
;
661 if (rc
== GPG_ERR_ELOOP
)
662 string_append (line
, "O");
663 else if (rc
== GPG_ERR_EACCES
)
664 string_append (line
, "P");
666 string_append (line
, "E");
668 if (rc
|| elements
->target
)
669 string_prepend (line
, " ");
671 if ((!rc
|| rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_EACCES
672 || rc
== GPG_ERR_ELEMENT_NOT_FOUND
) && elements
->target
)
673 string_append_printf (line
, "%sT %s",
674 (!rc
&& elements
->flags
& XML_LIST_FLAG_CHILDREN
) ? "+" : "",
676 else if (!rc
&& (elements
->flags
& XML_LIST_FLAG_CHILDREN
))
677 string_prepend (line
, " +");
679 if (elements
->prefix
&& elements
->prefix
->str
)
680 string_prepend (line
, elements
->prefix
->str
);
682 string_prepend (line
, path
);
684 l
= slist_append (elements
->list
, line
->str
);
688 if (!(elements
->flags
& XML_LIST_CHECK
))
694 string_free (line
, 0);
698 /* Removes the final element from the element prefix. */
700 pop_element_prefix (struct element_list_s
*elements
)
702 char *p
= strrchr (elements
->prefix
->str
, '\t');
705 string_truncate (elements
->prefix
,
706 elements
->prefix
->len
- strlen (p
));
709 #define RESUMABLE_ERROR(rc) (rc == GPG_ERR_ELOOP || rc == GPG_ERR_EACCES \
710 || rc == GPG_ERR_ELEMENT_NOT_FOUND || !rc)
713 * From the element path 'path', find sub-nodes and append them to the list.
716 xml_create_path_list (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
717 struct element_list_s
*elements
, char *path
,
721 struct xml_request_s
*req
= NULL
;
722 gpg_error_t trc
= rc
;
725 target_orig
= rc
&& elements
->target
? str_dup (elements
->target
) : NULL
;
726 rc
= xml_new_request (client
, path
, XML_CMD_LIST
, &req
);
733 req
->data
= elements
;
734 n
= xml_find_elements (client
, req
,
735 node
? node
: xmlDocGetRootElement (doc
), &rc
);
738 find_element_node (n
->children
) ? XML_LIST_FLAG_CHILDREN
: 0;
742 xfree (elements
->target
);
743 elements
->target
= target_orig
;
745 elements
->flags
|= XML_LIST_HAS_TARGET
;
750 rc
= append_path_to_list (client
, elements
, path
, trc
? trc
: rc
);
751 xmlFree (elements
->target
);
752 elements
->target
= NULL
;
754 if (rc
|| trc
|| (elements
->flags
& XML_LIST_CHECK
)
755 || (!elements
->recurse
&& elements
->depth
) || elements
->root_only
)
757 xml_free_request (req
);
763 if (!rc
&& n
&& n
->children
)
765 for (n
= n
->children
; n
; n
= n
->next
)
767 xmlChar
*target
= NULL
;
768 xmlNodePtr tmp
= NULL
;
770 struct string_s
*newpath
;
772 if (n
->type
!= XML_ELEMENT_NODE
)
775 name
= xml_attribute_value (n
, (xmlChar
*) "_name");
779 newpath
= string_new (NULL
);
787 target
= xml_attribute_value (n
, (xmlChar
*) "target");
790 rc
= xml_validate_target (client
, req
->doc
, (char *)target
, n
);
791 elements
->target
= (char *)target
;
792 elements
->flags
|= rc
? XML_LIST_TARGET_ERROR
: 0;
797 if (RESUMABLE_ERROR (rc
))
801 /* If there is a target for this node then resolve the full path
802 * starting at the document root. Otherwise, resolve the next
803 * element starting from the child node of the current node. In
804 * either case, append the current element in the element path to
805 * the prefix of the list string.
809 string_truncate (newpath
, 0);
810 s
= string_append_printf (newpath
, "%s", (char *)target
);
813 s
= string_append (newpath
, (char *)name
);
818 string_free (newpath
, 1);
824 if (!elements
->depth
)
826 /* There may be a single remaining element in the prefix left
827 * over from the previous truncation (see below). It is safe
828 * to truncate it here since depth == 0. */
829 string_truncate (elements
->prefix
, 0);
830 s
= string_append_printf (elements
->prefix
, "%s\t%s",
834 s
= string_append_printf (elements
->prefix
, "\t%s", name
);
839 string_free (newpath
, 1);
844 elements
->prefix
= s
;
846 rc
= xml_create_path_list (client
, doc
, target
? NULL
: tmp
,
847 elements
, newpath
->str
, rc
);
850 pop_element_prefix (elements
);
853 string_free (newpath
, 1);
861 xml_free_request (req
);
866 xml_recurse_xpath_nodeset (struct client_s
*client
, xmlDocPtr doc
,
867 xmlNodeSetPtr nodes
, xmlChar
* value
,
868 xmlBufferPtr
* result
, int cmd
, const xmlChar
* attr
)
870 int i
= value
? nodes
->nodeNr
- 1 : 0;
873 buf
= xmlBufferCreate ();
876 return GPG_ERR_ENOMEM
;
878 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++)
880 xmlNodePtr n
= nodes
->nodeTab
[i
];
888 if (xmlNodeDump (buf
, doc
, n
, 0, 0) == -1)
891 return GPG_ERR_BAD_DATA
;
899 xmlNodeSetContent (n
, value
);
900 rc
= xml_update_element_mtime (client
, n
);
908 rc
= xml_add_attribute (client
, n
, (char *) attr
, (char *) value
);
910 rc
= xml_delete_attribute (client
, n
, attr
);
922 xml_delete_attribute (struct client_s
*client
, xmlNodePtr n
,
928 if ((a
= xmlHasProp (n
, name
)) == NULL
)
929 return GPG_ERR_NOT_FOUND
;
931 if (xmlRemoveProp (a
) == -1)
932 return GPG_ERR_BAD_DATA
;
934 if (client
&& xmlStrEqual (name
, (xmlChar
*) "_acl"))
936 char *user
= create_acl_user (client
);
938 rc
= xml_add_attribute (client
, n
, (char *) "_acl", user
);
945 return xml_update_element_mtime (client
, n
);
949 xml_validate_import (struct client_s
*client
, xmlNodePtr node
)
956 for (xmlNodePtr n
= node
; n
; n
= n
->next
)
958 if (n
->type
== XML_ELEMENT_NODE
)
960 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
962 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
966 xmlChar
*t
= xmlGetNodePath (n
);
968 log_write (_("Missing attribute '_name' at %s."), t
);
970 return GPG_ERR_INV_VALUE
;
973 if (!xml_valid_element (a
))
975 xmlChar
*t
= xmlGetNodePath (n
);
977 log_write (_("'%s' is not a valid element name at %s."), a
,
981 return GPG_ERR_INV_VALUE
;
985 a
= xmlGetProp (n
, (xmlChar
*) "_ctime");
987 attr_ctime (client
, n
);
990 a
= xmlGetProp (n
, (xmlChar
*) "_mtime");
992 xml_update_element_mtime (client
, n
);
997 xmlChar
*t
= xmlGetNodePath (n
);
999 // FIXME: unlink unknown node.
1000 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1009 rc
= xml_validate_import (client
, n
->children
);
1019 xml_update_element_mtime (struct client_s
*client
, xmlNodePtr n
)
1021 return xml_add_attribute (client
, n
, NULL
, NULL
);
1025 xml_unlink_node (struct client_s
*client
, xmlNodePtr n
)
1033 rc
= xml_update_element_mtime (client
, n
->parent
);
1036 xmlFreeNodeList (n
);
1041 xml_parse_doc (const char *xml
, size_t len
, xmlDocPtr
*result
)
1045 xmlResetLastError ();
1046 doc
= xmlReadMemory (xml
, len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
1047 if (!doc
&& xmlGetLastError ())
1048 return GPG_ERR_BAD_DATA
;
1051 return !doc
? GPG_ERR_ENOMEM
: 0;
1054 /* Resolves the 'target' attribute found in 'node' and appends 'path' to the
1055 * target. 'path' is any remaining elements in the element path after this
1056 * element 'node' as passed to xml_find_elements() or the initial command. This
1057 * function may be recursive as it calls xml_find_elements().
1060 do_realpath (struct client_s
*client
, struct xml_request_s
*req
,
1061 xmlNodePtr node
, char **path
, const xmlChar
*target
,
1064 char **result
= NULL
;
1065 struct xml_request_s
*nreq
;
1069 result
= str_split ((char *)target
, "\t", 0);
1072 *rc
= GPG_ERR_ENOMEM
;
1076 /* Append the original path to the target path. */
1079 char **p
= strv_catv (result
, path
);
1084 *rc
= GPG_ERR_ENOMEM
;
1091 line
= strv_join ("\t", result
);
1095 *rc
= GPG_ERR_ENOMEM
;
1099 /* To prevent overwriting any original client request flags. We are only
1100 * interested in the path here. */
1101 *rc
= xml_new_request (client
, line
, XML_CMD_REALPATH
, &nreq
);
1108 nreq
->depth
= req
->depth
;
1110 node
= xml_find_elements (client
, nreq
, xmlDocGetRootElement (nreq
->doc
), rc
);
1112 /* Update the original client request path with the resolved one. */
1115 strv_free (req
->args
);
1116 req
->args
= nreq
->args
;
1120 xml_free_request (nreq
);
1126 node_to_element_path (xmlNodePtr node
)
1129 struct string_s
*str
= string_new ("");
1132 for (n
= node
; n
; n
= n
->parent
)
1136 for (child
= n
; child
; child
= child
->next
)
1138 if (child
->type
!= XML_ELEMENT_NODE
)
1141 xmlChar
*name
= xml_attribute_value (n
, (xmlChar
*) "_name");
1144 str
= string_prepend (str
, (char *) name
);
1146 name
= xml_attribute_value (n
, (xmlChar
*) "target");
1148 str
= string_prepend (str
, "\t");
1150 str
= string_prepend (str
, "\t!");
1157 str
= string_erase (str
, 0, 1);
1159 string_free (str
, 0);
1164 /* Tests if 'path' references 'node' somewhere. */
1166 element_related (struct client_s
*client
, xmlDocPtr doc
, const char *path
,
1167 xmlNodePtr node
, unsigned depth
)
1169 gpg_error_t rc
= GPG_ERR_NO_DATA
;
1171 xmlNodePtr n
= xmlDocGetRootElement (doc
);
1173 if (max_recursion_depth
>= 1 && depth
> max_recursion_depth
)
1174 return GPG_ERR_ELOOP
;
1176 p
= str_split (path
, "\t", 0);
1178 return GPG_ERR_ENOMEM
;
1180 for (n
= n
->children
; n
&& *p
; p
++, n
= n
->next
)
1184 struct string_s
*str
= NULL
;
1186 t
= xml_find_element (client
, n
, *p
, NULL
, &rc
);
1189 rc
= GPG_ERR_NO_DATA
;
1199 target
= xml_attribute_value (t
, (xmlChar
*)"target");
1203 str
= string_new ((char *)target
);
1207 rc
= GPG_ERR_ENOMEM
;
1215 struct string_s
*tmp
;
1217 tmp
= string_append_printf (str
, "\t%s", *p
);
1220 string_free (str
, 1);
1222 return GPG_ERR_ENOMEM
;
1229 rc
= element_related (client
, doc
, str
->str
, n
->children
, ++depth
);
1230 if (rc
== GPG_ERR_ELOOP
)
1231 rc
= GPG_ERR_NO_DATA
;
1233 string_free(str
, 1);
1242 * Recurse the element tree beginning at 'node' and find elements who point
1243 * back to 'dst'. Also follows target attributes.
1246 find_child_to_target (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
1247 xmlNodePtr dst
, unsigned depth
, int is_target
)
1252 if (max_recursion_depth
>= 1 && depth
> max_recursion_depth
)
1253 return node
== dst
? GPG_ERR_ELOOP
: 0;
1255 for (n
= node
; n
; n
= n
->next
)
1259 if (n
->type
!= XML_ELEMENT_NODE
)
1262 if (n
== dst
&& depth
)
1263 return GPG_ERR_ELOOP
;
1265 target
= xml_attribute_value (n
, (xmlChar
*) "target");
1269 char **result
= NULL
;
1271 tmp
= xml_resolve_path (client
, doc
, target
, &result
, &rc
);
1275 rc
= find_child_to_target (client
, doc
, tmp
, dst
, ++depth
, 1);
1278 else if (rc
== GPG_ERR_ELOOP
)
1280 gpg_error_t trc
= element_related (client
, doc
, (char *)target
,
1283 if (trc
&& trc
!= GPG_ERR_NO_DATA
)
1285 else if (trc
== GPG_ERR_NO_DATA
)
1291 if (rc
&& rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
1303 rc
= find_child_to_target (client
, doc
, n
->children
, dst
, ++depth
, 0);
1317 find_child_of_parent (xmlDocPtr doc
, xmlNodePtr src
, xmlNodePtr dst
)
1322 for (n
= src
; n
; n
= n
->next
)
1324 if (n
->type
!= XML_ELEMENT_NODE
)
1333 rc
= find_child_of_parent (doc
, n
->children
, dst
);
1340 find_parent_of_child (xmlDocPtr doc
, xmlNodePtr node
, xmlNodePtr dst
)
1345 for (n
= node
; n
; n
= n
->parent
)
1347 if (n
->type
!= XML_ELEMENT_NODE
)
1351 for (tmp
= n
->next
; tmp
; n
= n
->next
)
1353 if (n
->type
!= XML_ELEMENT_NODE
)
1357 return GPG_ERR_ELOOP
;
1362 return GPG_ERR_ELOOP
;
1369 xml_free_element_list (struct element_list_s
*elements
)
1375 int total
= slist_length (elements
->list
);
1378 for (i
= 0; i
< total
; i
++)
1380 char *tmp
= slist_nth_data (elements
->list
, i
);
1384 slist_free (elements
->list
);
1387 string_free (elements
->prefix
, 1);
1388 xfree (elements
->target
);
1393 /* This behaves like the LIST command with a specified path except it returns
1397 xml_check_recursion (struct client_s
*client
, struct xml_request_s
*req
,
1401 struct element_list_s
*elements
;
1404 char **dup
= strv_dup (req
->args
);
1407 return GPG_ERR_ENOMEM
;
1411 tmp
= dup
[strv_length (dup
)-1];
1412 dup
[strv_length (dup
)-1] = NULL
;
1415 elements
= xcalloc (1, sizeof (struct element_list_s
));
1418 rc
= GPG_ERR_ENOMEM
;
1422 path
= strv_join ("\t", dup
);
1425 rc
= GPG_ERR_ENOMEM
;
1429 elements
->flags
|= XML_LIST_CHECK
;
1430 elements
->prefix
= string_new (NULL
);
1431 if (!elements
->prefix
)
1433 rc
= GPG_ERR_ENOMEM
;
1437 rc
= xml_create_path_list (client
, req
->doc
, xmlDocGetRootElement (req
->doc
),
1442 xml_free_element_list (elements
);
1449 xml_validate_target (struct client_s
*client
, xmlDocPtr doc
, const char *src
,
1453 xmlNodePtr src_node
;
1454 char **src_req
= NULL
;
1456 src_node
= xml_resolve_path (client
, doc
, (xmlChar
*) src
, &src_req
, &rc
);
1460 client
->flags
|= FLAG_ACL_IGNORE
;
1461 /* A destination element is a child of the source element. */
1462 rc
= find_child_of_parent (doc
, src_node
->children
, dst
);
1466 /* The destination element is a parent of the source element. */
1467 rc
= find_parent_of_child (doc
, src_node
->parent
, dst
);
1471 /* A destination child element contains a target to the source element. */
1473 rc
= find_child_to_target (client
, doc
,
1474 dst
->children
? dst
->children
: dst
, dst
, 0, 0);
1479 strv_free (src_req
);
1480 client
->flags
&= ~(FLAG_ACL_IGNORE
| FLAG_ACL_ERROR
);
1484 /* The owner of the element is the first user listed in the _acl attribute
1485 * list. acl_check() should be called before calling this function. An empty
1486 * ACL is an error if the client is not an invoking_user.
1489 xml_is_element_owner (struct client_s
*client
, xmlNodePtr n
)
1491 xmlChar
*acl
= xml_attribute_value (n
, (xmlChar
*) "_acl");
1493 gpg_error_t rc
= GPG_ERR_EACCES
;
1498 return peer_is_invoker (client
);
1501 users
= str_split((char *)acl
, ",", 0);
1502 if (users
&& *users
)
1507 if (client
->thd
->remote
)
1508 user
= str_asprintf ("#%s", client
->thd
->tls
->fp
);
1510 user
= get_username (client
->thd
->peer
->uid
);
1512 user
= get_username (client
->thd
->peer
->uid
);
1516 rc
= !strcasecmp (*users
, user
) ? 0 : GPG_ERR_EACCES
;
1518 rc
= !strcmp (*users
, user
) ? 0 : GPG_ERR_EACCES
;
1521 rc
= peer_is_invoker (client
);
1531 /* Find elements by matching element names in req->args starting at 'node'.
1532 * Returns the node of the final element in req->args on success or NULL on
1533 * failure and sets 'rc' to the error code. Some commands may need special
1534 * handling and will return the node of the previous found element.
1537 xml_find_elements (struct client_s
*client
, struct xml_request_s
*req
,
1538 xmlNodePtr node
, gpg_error_t
*rc
)
1541 char **p
= req
->args
;
1546 if (max_recursion_depth
>= 1 && req
->depth
> max_recursion_depth
)
1549 *rc
= GPG_ERR_ELOOP
;
1553 /* Beginning of a command/root element (<pwmd>). */
1554 if (node
== xmlDocGetRootElement (req
->doc
))
1556 if (!node
->children
) // Empty tree
1558 if (req
->cmd
== XML_CMD_STORE
)
1559 return xml_create_element_path (client
, req
, node
, req
->args
, rc
);
1561 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
1566 node
= node
->children
; // Start searching at the first child of the root
1569 for (last
= n
= node
, p
= req
->args
; *p
; p
++)
1571 xmlNodePtr tmp
= NULL
;
1572 struct element_list_s
*elements
= NULL
;
1574 // FIXME should not be reached in this function?
1577 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
1582 n
= xml_find_element (client
, n
, *p
, NULL
, rc
);
1585 if (*rc
!= GPG_ERR_ELEMENT_NOT_FOUND
&& *rc
!= GPG_ERR_EACCES
)
1591 if (*rc
== GPG_ERR_EACCES
1592 && (req
->cmd
== XML_CMD_ATTR_LIST
|| req
->cmd
== XML_CMD_ATTR
1593 || req
->cmd
== XML_CMD_ATTR_EXPIRE
))
1603 /* Fixes ATTR LIST when an element does not exist and the parent
1604 * denies access to children. Fixes leaking information about the
1605 * current elements children. */
1606 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& last
!= n
&& last
!= node
)
1608 gpg_error_t trc
= acl_check (client
, last
);
1613 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
)
1615 if (req
->cmd
== XML_CMD_STORE
|| req
->cmd
== XML_CMD_ATTR_TARGET
)
1618 n
= xml_create_element_path (client
, req
,
1620 && node
->parent
== xmlDocGetRootElement (req
->doc
)
1621 ? node
->parent
: last
, p
, rc
);
1627 if (req
->cmd
!= XML_CMD_LIST
)
1633 // Fall through to let LIST flags be appended.
1638 /* Follow a "target" attribute for each one found in each element. */
1639 xmlChar
*target
= xml_attribute_value (n
, (xmlChar
*) "target");
1640 if (!target
|| !*target
)
1650 /* This is the final element in req->args. Done. */
1661 if (req
->cmd
== XML_CMD_REALPATH
)
1663 n
= do_realpath (client
, req
, n
, p
+1, target
, rc
);
1668 else if (req
->cmd
== XML_CMD_DELETE
|| req
->cmd
== XML_CMD_RENAME
1669 || req
->cmd
== XML_CMD_MOVE
|| req
->cmd
== XML_CMD_ATTR
1670 || req
->cmd
== XML_CMD_ATTR_TARGET
1671 || req
->cmd
== XML_CMD_ATTR_LIST
)
1673 /* No more elements to resolve. Return the node with the target. */
1681 else if (req
->cmd
== XML_CMD_LIST
)
1683 elements
= req
->data
;
1684 if (elements
&& !(elements
->flags
& XML_LIST_CHILD_TARGET
))
1686 /* No further elements. Use this target in the list flags. */
1688 elements
->flags
|= XML_LIST_HAS_TARGET
;
1691 /* Prevent replacing any following target value with the
1692 * current target value. */
1698 struct element_list_s
*e
= xcalloc (1, sizeof (struct element_list_s
));
1700 e
->target
= str_dup ((char *)target
);
1701 e
->flags
|= XML_LIST_CHILD_TARGET
;
1704 e
->flags
|= XML_LIST_HAS_TARGET
;
1706 req
->data
= elements
= e
;
1709 *rc
= xml_validate_target (client
, req
->doc
, (char *)target
, n
);
1714 /* Create a new path based on the value of the current "target"
1716 char **nargs
= str_split ((char *)target
, "\t", 0);
1720 *rc
= GPG_ERR_INV_VALUE
;
1721 req
->data
= req
->cmd
== XML_CMD_LIST
? elements
: req
->data
;
1726 /* Append the remaining elements to the target attributes path. */
1727 char **nnargs
= strv_catv (nargs
, p
+1);
1729 char **orig
= req
->args
;
1731 tmp
= xml_find_elements (client
, req
, xmlDocGetRootElement (req
->doc
),
1737 if (req
->cmd
== XML_CMD_LIST
&& elements
)
1739 /* A child node contained a target. Use this value rather than the
1740 * current target value as the target value for the list flag. */
1741 if (req
->data
&& req
->data
!= elements
)
1743 struct element_list_s
*e
= req
->data
;
1746 target
= xmlStrdup ((xmlChar
*)e
->target
);
1749 if ((e
->flags
& XML_LIST_HAS_TARGET
))
1750 elements
->flags
|= XML_LIST_HAS_TARGET
;
1755 req
->data
= elements
;
1758 if (!(elements
->flags
& XML_LIST_TARGET_ERROR
))
1760 xfree (elements
->target
);
1761 elements
->target
= NULL
;
1763 /* Restore the original target flag. */
1764 if ((elements
->flags
& XML_LIST_HAS_TARGET
))
1765 elements
->target
= str_dup ((char *)target
);
1772 return *rc
? NULL
: tmp
;
1780 xml_new_request (struct client_s
*client
, const char *line
, xml_command_t cmd
,
1781 struct xml_request_s
**result
)
1783 struct xml_request_s
*req
;
1784 char **pp
= str_split ((char *) line
, "\t", 0);
1789 return GPG_ERR_SYNTAX
;
1792 req
= xcalloc (1, sizeof (struct xml_request_s
));
1796 return GPG_ERR_ENOMEM
;
1801 req
->doc
= client
? client
->doc
: NULL
;
1807 xml_free_request (struct xml_request_s
*r
)
1812 strv_free (r
->args
);
1817 xml_reserved_attribute (const char *name
)
1821 for (i
= 0; reserved_attributes
[i
]; i
++)
1823 if (!strcmp (name
, reserved_attributes
[i
]))