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/>.
32 #include <libxml/xmlwriter.h>
34 #include <sys/types.h>
39 #define _(msgid) gettext(msgid)
42 #include "pwmd-error.h"
43 #include "util-misc.h"
48 extern void log_write (const char *fmt
, ...);
51 * 'element' must be allocated.
54 is_literal_element (char **element
)
58 if (!element
|| !*element
)
61 if (*(*element
) == '!')
65 for (p
= *element
, c
= p
+ 1; *c
; c
++)
76 valid_xml_attribute (const char *str
)
78 return valid_xml_element ((xmlChar
*)str
);
82 valid_xml_element (xmlChar
*str
)
87 if (!str
|| !*str
|| *str
== '!')
90 wc
= str_to_wchar ((const char *)str
);
93 for (c
= 0; c
< len
; c
++)
107 valid_element_path (char **path
, int with_content
)
109 char **dup
= NULL
, **p
;
114 /* Save some memory by not duplicating the element 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 *));
130 dup
[i
] = str_dup (path
[i
]);
135 dup
= strv_dup (path
);
140 for (p
= dup
; *p
&& *(*p
); p
++)
142 is_literal_element (&(*p
));
143 if (!valid_xml_element ((xmlChar
*) * p
))
155 attr_ctime (xmlNodePtr n
)
157 char *buf
= str_asprintf ("%li", time (NULL
));
161 return GPG_ERR_ENOMEM
;
163 rc
= add_attribute (n
, "_ctime", buf
);
168 // FIXME add parameter to want RW or RO access to the XML node.
170 acl_check (struct client_s
*client
, xmlNodePtr n
)
172 gpg_error_t rc
= GPG_ERR_EPERM
;
173 xmlChar
*acl
= node_has_attribute (n
, (xmlChar
*) "_acl");
174 char **users
= acl
? str_split((char *)acl
, ",", 0) : NULL
;
178 if (!acl
|| !users
|| !*users
)
181 return peer_is_invoker(client
);
184 if (!peer_is_invoker(client
))
187 for (p
= users
; *p
; p
++)
190 rc
= acl_check_common (client
, *p
,
191 client
->thd
->remote
? 0 : client
->thd
->peer
->uid
,
192 client
->thd
->remote
? 0 : client
->thd
->peer
->gid
,
195 rc
= acl_check_common (client
, *p
, client
->thd
->peer
->uid
,
196 client
->thd
->peer
->gid
, &allowed
);
205 return allowed
? 0 : GPG_ERR_EPERM
;
209 create_acl_user (struct client_s
*client
)
212 if (client
->thd
->remote
)
213 return str_asprintf ("#%s", client
->thd
->tls
->fp
);
216 return get_username (client
->thd
->peer
->uid
);
220 create_new_element (struct client_s
*client
, int verify
, xmlNodePtr parent
,
221 const char *name
, xmlNodePtr
* result
)
226 // Allow any client to create a non-existing root element.
227 if (parent
->parent
->type
!= XML_DOCUMENT_NODE
)
229 rc
= acl_check(client
, parent
);
234 n
= xmlNewNode (NULL
, (xmlChar
*) "element");
236 return GPG_ERR_ENOMEM
;
238 rc
= add_attribute (n
, "_name", name
);
242 if (!rc
&& verify
&& parent
->parent
->type
!= XML_DOCUMENT_NODE
)
244 rc
= peer_is_invoker (client
);
245 if (rc
== GPG_ERR_EPERM
)
246 rc
= is_element_owner (client
, parent
);
251 xmlNodePtr p
= xmlAddChild (parent
, n
);
252 char *user
= create_acl_user (client
);
257 rc
= add_attribute(p
, "_acl", user
);
267 new_root_element (struct client_s
*client
, xmlDocPtr doc
, char *name
)
269 xmlNodePtr root
= xmlDocGetRootElement (doc
);
273 return GPG_ERR_BAD_DATA
;
278 if (!valid_xml_element ((xmlChar
*) p
))
279 return GPG_ERR_INV_VALUE
;
281 return create_new_element (client
, 0, root
, p
, NULL
);
288 xmlTextWriterPtr wr
= xmlNewTextWriterDoc (&doc
, 0);
293 if (xmlTextWriterStartDocument (wr
, NULL
, "UTF-8", "yes"))
296 if (xmlTextWriterStartDTD (wr
, (xmlChar
*) "pwmd", NULL
, NULL
) == -1)
299 if (xmlTextWriterWriteDTDElement (wr
, (xmlChar
*) "pwmd",
300 (xmlChar
*) "(element)") == -1)
303 xmlTextWriterEndDTDElement (wr
);
305 if (xmlTextWriterWriteDTDAttlist (wr
, (xmlChar
*) "element",
306 (xmlChar
*) "_name CDATA #REQUIRED") ==
310 xmlTextWriterEndDTDAttlist (wr
);
311 xmlTextWriterEndDTD (wr
);
313 if (xmlTextWriterStartElement (wr
, (xmlChar
*) "pwmd"))
316 xmlTextWriterEndElement (wr
);
317 xmlTextWriterEndDocument (wr
);
318 xmlFreeTextWriter (wr
);
322 xmlTextWriterEndDocument (wr
);
323 xmlFreeTextWriter (wr
);
331 return create_dtd ();
335 find_element_node (xmlNodePtr node
)
339 if (n
&& n
->type
== XML_ELEMENT_NODE
)
342 for (n
= node
; n
; n
= n
->next
)
344 if (n
->type
== XML_ELEMENT_NODE
)
352 resolve_path (struct client_s
*client
, xmlDocPtr doc
, xmlChar
* path
,
353 char ***result
, gpg_error_t
* rc
)
358 req
= str_split ((char *) path
, "\t", 0);
361 *rc
= GPG_ERR_ENOMEM
;
365 n
= find_root_element (client
, doc
, &req
, rc
, NULL
, 0, 0);
373 n
= find_elements (client
, doc
, n
->children
, req
+ 1, rc
, NULL
, NULL
, NULL
,
385 * Lists root element names; the value of the attribute "_name" of an element
386 * "element". If there's a target attribute both literal and non-literal
387 * element names will be added. This is the primary reason why XML entities
388 * cannot be used. There wouldn't be a way to get the literal an non-literal
392 list_root_elements (struct client_s
*client
, xmlDocPtr doc
,
393 struct string_s
** result
, int verbose
, int with_target
)
396 struct slist_s
*list
= NULL
;
398 struct string_s
*string
;
401 n
= xmlDocGetRootElement (doc
);
402 if (!n
|| !n
->children
)
403 return GPG_ERR_NO_DATA
;
405 for (n
= n
->children
; n
; n
= n
->next
)
408 xmlChar
*val
, *target
;
409 struct slist_s
*tlist
;
412 if (n
->type
!= XML_ELEMENT_NODE
)
415 a
= xmlHasProp (n
, (xmlChar
*) "_name");
416 if (!a
|| !a
->children
->content
)
419 val
= xmlNodeGetContent (a
->children
);
426 tmp
= str_asprintf ("!%s%s", (char *) val
,
427 verbose
? find_element_node (n
->children
) ? " +"
437 tlist
= slist_append (list
, tmp
);
446 target
= node_has_attribute (n
, (xmlChar
*) "target");
454 xmlNodePtr tnode
= resolve_path (client
, doc
, target
, &req
, &rc
);
456 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
457 || rc
== GPG_ERR_EPERM
)
459 t
= str_asprintf ("%s %s", (char *) val
,
460 rc
== GPG_ERR_ELOOP
? "O" :
461 rc
== GPG_ERR_EPERM
? "P" : "E");
466 struct string_s
*realpath
= NULL
;
470 rc
= build_realpath (client
, doc
, (char *) target
,
480 realpath
= string_prepend (realpath
, "T ");
483 t
= str_asprintf ("%s%s%s%s", (char *) val
,
485 && find_element_node (tnode
->children
))
486 || realpath
? " " : "", tnode
487 && find_element_node (tnode
->children
) ?
488 "+" : "", realpath
? realpath
->str
: "");
491 string_free (realpath
, 1);
498 t
= str_dup ((char *) val
);
504 rc
= rc
? rc
: GPG_ERR_ENOMEM
;
508 tlist
= slist_append (list
, t
);
525 total
= slist_length (list
);
527 return GPG_ERR_NO_DATA
;
529 string
= string_new (NULL
);
536 for (i
= 0; i
< total
; i
++)
538 char *val
= slist_nth_data (list
, i
);
540 string_append_printf (string
, "%s\n", val
);
543 string
= string_truncate (string
, string
->len
- 1);
547 total
= slist_length (list
);
548 for (i
= 0; i
< total
; i
++)
549 xfree (slist_nth_data (list
, i
));
556 * Prevents a sibling element past the current element path with the same
560 find_stop_node (xmlNodePtr node
)
564 for (n
= node
->parent
->children
; n
; n
= n
->next
)
574 create_target_elements_cb (struct client_s
*client
, int verify
,
575 xmlNodePtr node
, char **path
, gpg_error_t
*rc
,
580 xmlNodePtr parent
= data
;
582 for (i
= 0; req
[i
] && *req
[i
]; i
++)
586 if (parent
&& node
== parent
)
588 *rc
= GPG_ERR_CONFLICT
;
592 is_literal_element (&req
[i
]);
594 if ((n
= find_element (client
, node
, req
[i
],
595 find_stop_node (node
), rc
)) == NULL
||
596 (n
&& n
->parent
== node
->parent
))
600 *rc
= create_new_element (client
, verify
, node
, req
[i
], &node
);
613 find_text_node (xmlNodePtr node
)
617 if (n
&& n
->type
== XML_TEXT_NODE
)
620 for (n
= node
; n
; n
= n
->next
)
622 if (n
->type
== XML_TEXT_NODE
)
630 create_elements_cb (struct client_s
*client
, int verify
, xmlNodePtr node
,
631 char **elements
, gpg_error_t
* rc
, void *data
)
634 char **req
= elements
;
636 if (node
->type
== XML_TEXT_NODE
)
639 for (i
= 0; req
[i
] && *req
[i
]; i
++)
644 * Strip the first '!' if needed. If there's another, it's an
645 * rc. The syntax has already been checked before calling this
648 is_literal_element (&req
[i
]);
649 n
= find_element (client
, node
, req
[i
], find_stop_node (node
), rc
);
654 * If the found element has the same parent as the current element,
655 * they are siblings and the new element needs to be created as a
656 * child of the current element (node).
658 if (n
&& n
->parent
== node
->parent
)
663 *rc
= create_new_element (client
, 0, node
, req
[i
], &node
);
674 /* The root element is really req[0]. It is need as a pointer in case there is
675 * a target attribute so it can be updated. */
677 find_root_element (struct client_s
*client
, xmlDocPtr doc
, char ***req
,
678 gpg_error_t
* rc
, int *target
, int recursion_depth
,
681 xmlNodePtr n
= xmlDocGetRootElement (doc
);
683 char *root
= str_dup (*req
[0]);
684 int literal
= is_literal_element (&root
);
688 *rc
= GPG_ERR_ENOMEM
;
695 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
697 xmlChar
*t
= xmlGetNodePath (n
);
699 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
708 if (n
->type
== XML_ELEMENT_NODE
)
710 if (depth
== 0 && xmlStrEqual (n
->name
, (xmlChar
*) "pwmd"))
717 if (depth
== 1 && xmlStrEqual (n
->name
, (xmlChar
*) "element"))
719 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "_name");
724 if (xmlStrEqual (content
, (xmlChar
*) root
))
726 char **nreq
, **tmp
= NULL
;
728 *rc
= acl_check(client
, n
);
744 content
= node_has_attribute (n
, (xmlChar
*) "target");
749 if (!content
|| stop
)
758 if (strchr ((char *) content
, '\t'))
760 nreq
= str_split ((char *) content
, "\t", 0);
769 *rc
= GPG_ERR_ENOMEM
;
775 tmp
= strv_catv (nreq
, tmp
+ 1);
781 *rc
= GPG_ERR_ENOMEM
;
790 if (strv_printf (&tmp
, "%s", content
) == 0)
794 *rc
= GPG_ERR_ENOMEM
;
800 nreq
= strv_catv (tmp
, nreq
+ 1);
805 *rc
= GPG_ERR_ENOMEM
;
815 n
= find_root_element (client
, doc
, req
, rc
, target
,
828 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
833 find_element (struct client_s
*client
, xmlNodePtr node
, char *element
,
834 xmlNodePtr stop
, gpg_error_t
*rc
)
840 if (!node
|| !element
)
843 for (n
= node
; n
; n
= n
->next
)
845 if (n
->type
!= XML_ELEMENT_NODE
)
851 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
853 if (a
&& xmlStrEqual (a
, (xmlChar
*) element
))
857 *rc
= acl_check(client
, n
);
871 node_has_attribute (xmlNodePtr n
, xmlChar
* attr
)
873 xmlAttrPtr a
= xmlHasProp (n
, attr
);
878 if (!a
->children
|| !a
->children
->content
)
881 return xmlGetProp (n
, attr
);
885 element_to_literal (char **element
)
887 char *p
= str_asprintf ("!%s", *element
);
897 /* Resolves elements in 'req' one at a time. It's recursive in case of
898 * "target" attributes. */
900 find_elements (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
901 char **req
, gpg_error_t
* rc
, int *target
,
902 xmlNodePtr (*found_fn
) (struct client_s
*, xmlNodePtr
, char **,
903 gpg_error_t
*, char **, void *),
904 xmlNodePtr (*not_found_fn
) (struct client_s
*, int, xmlNodePtr
,
905 char **, gpg_error_t
*, void *),
906 int is_list_command
, int recursion_depth
, void *data
, int stop
)
908 xmlNodePtr n
, last
, last_node
;
915 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
917 xmlChar
*t
= xmlGetNodePath (node
);
919 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
926 for (last_node
= last
= n
= node
, p
= req
; *p
; p
++)
934 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
941 *rc
= GPG_ERR_ENOMEM
;
945 literal
= is_literal_element (&t
);
946 n
= find_element (client
, last
, t
, NULL
, rc
);
949 if (*rc
&& *rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
955 return not_found_fn (client
, 0,
956 found
? last_node
: last_node
->parent
, p
,
960 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
971 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "target");
972 char **nreq
= NULL
, **nnreq
;
976 if (is_list_command
== 1)
978 if (element_to_literal (&(*p
)) == 0)
980 *rc
= GPG_ERR_ENOMEM
;
991 if (!*(p
+ 1) && stop
)
997 if (strchr ((char *) content
, '\t') != NULL
)
999 if ((nreq
= str_split ((char *) content
, "\t", 0)) == NULL
)
1002 *rc
= GPG_ERR_INV_VALUE
;
1008 if ((nreq
= str_split ((char *) content
, " ", 0)) == NULL
)
1011 *rc
= GPG_ERR_INV_VALUE
;
1017 tmp
= find_root_element (client
, doc
, &nreq
, rc
, target
, 0, 0);
1027 found_fn (client
, tmp
, nreq
, rc
, p
+ 1, data
);
1036 if (!*(nreq
+ 1) && !*(p
+ 1))
1042 nnreq
= strv_catv (nreq
+ 1, p
+ 1);
1046 if (!nnreq
|| !*nnreq
)
1055 n
= find_elements (client
, doc
, tmp
->children
, nnreq
, rc
, NULL
,
1056 found_fn
, not_found_fn
, is_list_command
,
1057 recursion_depth
, data
, stop
);
1063 return not_found_fn (client
, 0, tmp
, p
+ 1, rc
, data
);
1065 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
1071 char **zz
= p
+ 1, **qq
= nnreq
;
1073 if (strv_length (nnreq
) > strv_length (p
+ 1))
1076 for (; *qq
&& *zz
; zz
++)
1079 *zz
= str_dup (*qq
++);
1083 *rc
= GPG_ERR_ENOMEM
;
1099 update_element_list (struct element_list_s
*elements
)
1104 if (!elements
|| !elements
->elements
)
1107 line
= strv_join ("\t", elements
->elements
);
1112 strv_free (elements
->elements
);
1113 elements
->elements
= NULL
;
1114 l
= slist_append (elements
->list
, line
);
1124 path_list_recurse (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
1125 struct element_list_s
*elements
)
1129 gpg_error_t error_flag
= 0;
1131 for (n
= node
; n
; n
= n
->next
)
1133 xmlChar
*target
= NULL
;
1134 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
1135 gpg_error_t err
= 0;
1142 if (n
->type
!= XML_ELEMENT_NODE
)
1145 rc
= acl_check(client
, n
);
1147 if (elements
->verbose
)
1150 (&elements
->elements
, "%s\t!%s%s%s", elements
->prefix
, a
,
1151 !rc
&& find_element_node (n
->children
) ? " +" : "",
1152 rc
== GPG_ERR_EPERM
? " P" : "") == 0)
1155 return GPG_ERR_ENOMEM
;
1159 if (strv_printf (&elements
->elements
, "%s\t!%s", elements
->prefix
, a
)
1163 return GPG_ERR_ENOMEM
;
1166 if (update_element_list (elements
) == 0)
1169 return GPG_ERR_ENOMEM
;
1173 if (rc
== GPG_ERR_EPERM
)
1185 target
= node_has_attribute (n
, (xmlChar
*) "target");
1189 char *save
= elements
->prefix
;
1190 int r
= elements
->resolving
;
1193 struct string_s
*realpath
= NULL
;
1195 tnode
= resolve_path (client
, doc
, target
, &req
, &rc
);
1196 if (rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_ELEMENT_NOT_FOUND
1197 || rc
== GPG_ERR_EPERM
)
1199 if (rc
== GPG_ERR_ELOOP
)
1201 xmlChar
*t
= xmlGetNodePath (n
);
1203 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
1207 if (elements
->verbose
)
1209 error_flag
= err
= rc
;
1213 else if (!elements
->verbose
&& rc
)
1220 path
= str_asprintf("%s\t%s", elements
->prefix
, a
);
1221 rc
= validate_target_attribute (client
, client
->doc
, path
, tnode
);
1223 if (rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_EPERM
1224 || rc
== GPG_ERR_ELEMENT_NOT_FOUND
)
1226 if (rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
1227 error_flag
= err
= rc
;
1240 strv_printf (&elements
->elements
, "%s\t%s %s", elements
->prefix
,
1242 err
== GPG_ERR_ELOOP
? "O" :
1243 err
== GPG_ERR_EPERM
? "P" : "E");
1246 if (!err
&& elements
->with_target
)
1248 rc
= build_realpath (client
, doc
, (char *) target
, &realpath
);
1256 realpath
= string_prepend (realpath
, "T ");
1259 if (!err
&& elements
->verbose
)
1261 if (!strv_printf (&elements
->elements
, "%s\t%s%s%s%s",
1262 elements
->prefix
, a
,
1263 (tnode
&& find_element_node (tnode
->children
))
1264 || realpath
? " " : "", tnode
1265 && find_element_node (tnode
->children
) ? "+" :
1266 "", realpath
? realpath
->str
: ""))
1270 return GPG_ERR_ENOMEM
;
1275 (&elements
->elements
, "%s\t%s", elements
->prefix
, a
))
1279 return GPG_ERR_ENOMEM
;
1283 string_free (realpath
, 1);
1285 tmp
= strv_join ("\t", elements
->elements
);
1290 return GPG_ERR_ENOMEM
;
1293 if (update_element_list (elements
) == 0)
1298 return GPG_ERR_ENOMEM
;
1301 if (!err
&& elements
->recurse
)
1303 /* Prune element flags. */
1304 if (elements
->verbose
&& strchr (tmp
, ' '))
1308 for (p
= tmp
; *p
; p
++)
1318 elements
->prefix
= tmp
;
1319 elements
->resolving
= 1;
1320 rc
= create_path_list (client
, doc
, elements
, (char *) target
);
1321 elements
->resolving
= r
;
1322 elements
->prefix
= save
;
1324 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELOOP
1325 && gpg_err_code(rc
) != GPG_ERR_EPERM
)
1333 error_flag
= err
= rc
;
1342 if (n
->children
&& elements
->recurse
&& err
!= GPG_ERR_EPERM
)
1344 char *tmp
= str_asprintf ("%s\t!%s", elements
->prefix
, a
);
1345 char *save
= elements
->prefix
;
1350 return GPG_ERR_ENOMEM
;
1353 elements
->prefix
= tmp
;
1354 rc
= path_list_recurse (client
, doc
, n
->children
, elements
);
1355 xfree (elements
->prefix
);
1356 elements
->prefix
= save
;
1360 if (gpg_err_code(rc
) == GPG_ERR_ELOOP
1361 || gpg_err_code (rc
) == GPG_ERR_EPERM
1362 || gpg_err_code (rc
) == GPG_ERR_ELEMENT_NOT_FOUND
)
1364 error_flag
= err
= rc
;
1378 return error_flag
== GPG_ERR_ELOOP
|| error_flag
== GPG_ERR_EPERM
1383 add_attribute (xmlNodePtr node
, const char *name
, const char *value
)
1388 if (name
&& !xmlSetProp (node
, (xmlChar
*) name
, (xmlChar
*) value
))
1389 return GPG_ERR_BAD_DATA
;
1391 if (name
&& xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_mtime"))
1394 buf
= str_asprintf ("%li", time (NULL
));
1395 rc
= add_attribute (node
, "_mtime", buf
);
1401 * From the element path 'path', find sub-nodes and append them to the list.
1404 create_path_list (struct client_s
*client
, xmlDocPtr doc
,
1405 struct element_list_s
* elements
, char *path
)
1408 char **req
, **req_orig
;
1412 req
= str_split (path
, "\t", 0);
1415 req
= str_split (path
, " ", 0);
1417 return GPG_ERR_SYNTAX
;
1420 req_orig
= strv_dup (req
);
1423 rc
= GPG_ERR_ENOMEM
;
1427 n
= find_root_element (client
, doc
, &req
, &rc
, &a_target
, 0, 0);
1428 if ((rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
1429 || rc
== GPG_ERR_EPERM
)
1430 && elements
->verbose
&& a_target
)
1432 if (rc
!= GPG_ERR_EPERM
)
1438 if (rc
== GPG_ERR_EPERM
)
1441 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1452 *req
= str_dup (*req_orig
);
1460 find_elements (client
, doc
, n
->children
, req
+ 1, &rc
, &e_target
,
1461 NULL
, NULL
, 1, 0, NULL
, 0);
1463 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1473 if (!elements
->prefix
)
1478 * If any req_orig element contains no target the element should be
1479 * prefixed with the literal character. Not really crucial if the
1480 * client isn't human because child elements are prefixed for the
1481 * current path. But may be confusing if editing by hand.
1483 elements
->prefix
= strv_join ("\t", req_orig
);
1485 if (!elements
->prefix
)
1487 rc
= GPG_ERR_ENOMEM
;
1491 if (elements
->verbose
)
1494 struct string_s
*realpath
= NULL
;
1495 gpg_error_t allowed
= rc
;
1499 if (!allowed
&& a_target
&& elements
->with_target
)
1501 rc
= build_realpath (client
, doc
, path
, &realpath
);
1505 realpath
= string_prepend (realpath
, "T ");
1508 ret
= strv_printf (&elements
->elements
, "%s%s%s%s%s",
1510 (!allowed
&& n
&& find_element_node (n
->children
))
1511 || realpath
? " " : "",
1512 (!allowed
&& n
&& find_element_node (n
->children
)) ? "+" : "",
1513 !allowed
&& realpath
? realpath
->str
: "",
1514 allowed
? " P" : "");
1515 string_free (realpath
, 1);
1518 rc
= GPG_ERR_ENOMEM
;
1522 else if (strv_printf (&elements
->elements
, "%s", elements
->prefix
) == 0)
1524 rc
= GPG_ERR_ENOMEM
;
1528 if (update_element_list (elements
) == 0)
1530 rc
= GPG_ERR_ENOMEM
;
1535 rc
= path_list_recurse (client
, doc
, n
? n
->children
: n
, elements
);
1539 strv_free (req_orig
);
1546 recurse_xpath_nodeset (struct client_s
*client
, xmlDocPtr doc
,
1547 xmlNodeSetPtr nodes
, xmlChar
* value
,
1548 xmlBufferPtr
* result
, int cmd
, const xmlChar
* attr
)
1550 int i
= value
? nodes
->nodeNr
- 1 : 0;
1553 buf
= xmlBufferCreate ();
1556 return GPG_ERR_ENOMEM
;
1558 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++)
1560 xmlNodePtr n
= nodes
->nodeTab
[i
];
1566 if (!value
&& !attr
)
1568 if (xmlNodeDump (buf
, doc
, n
, 0, 0) == -1)
1571 return GPG_ERR_BAD_DATA
;
1579 xmlNodeSetContent (n
, value
);
1580 rc
= update_element_mtime (n
);
1588 rc
= add_attribute (n
, (char *) attr
, (char *) value
);
1590 rc
= delete_attribute (client
, n
, attr
);
1602 convert_root_element (struct client_s
*client
, xmlNodePtr n
)
1604 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1610 xmlChar
*t
= xmlGetNodePath (n
);
1613 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1616 return GPG_ERR_AMBIGUOUS_NAME
;
1619 a
= xmlGetProp (n
, (xmlChar
*) "name");
1623 rc
= add_attribute (n
, "_name", (char *) a
);
1629 rc
= delete_attribute (client
, n
, (xmlChar
*) "name");
1634 xmlNodeSetName (n
, (xmlChar
*) "element");
1641 delete_attribute (struct client_s
*client
, xmlNodePtr n
, const xmlChar
* name
)
1646 if ((a
= xmlHasProp (n
, name
)) == NULL
)
1647 return GPG_ERR_NOT_FOUND
;
1649 if (xmlRemoveProp (a
) == -1)
1650 return GPG_ERR_BAD_DATA
;
1652 if (client
&& xmlStrEqual (name
, (xmlChar
*) "_acl"))
1654 char *user
= create_acl_user (client
);
1656 rc
= add_attribute (n
, (char *) "_acl", user
);
1663 return update_element_mtime (n
);
1667 convert_elements_recurse (struct client_s
*client
, xmlDocPtr doc
,
1668 xmlNodePtr n
, unsigned depth
)
1674 for (n
= n
->children
; n
; n
= n
->next
)
1676 if (n
->type
== XML_ELEMENT_NODE
)
1682 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1684 xmlChar
*t
= xmlGetNodePath (n
);
1687 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1690 return GPG_ERR_AMBIGUOUS_NAME
;
1693 a
= xmlGetProp (n
, (xmlChar
*) "_name");
1697 xmlChar
*t
= xmlGetNodePath (n
);
1700 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1703 return GPG_ERR_AMBIGUOUS_NAME
;
1706 xmlChar
*tmp
= xmlStrdup (n
->name
);
1709 return GPG_ERR_ENOMEM
;
1711 xmlNodeSetName (n
, (xmlChar
*) "element");
1712 rc
= add_attribute (n
, "_name", (char *) tmp
);
1720 rc
= convert_root_element (client
, n
);
1729 rc
= convert_elements_recurse (client
, doc
, n
, depth
);
1739 /* Renames ALL elements to the new "element" name. Existing element names are
1740 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1741 * elements can contain common characters that the XML parser barfs on (an
1742 * email address for example. */
1744 convert_pre_212_elements (xmlDocPtr doc
)
1746 xmlNodePtr n
= xmlDocGetRootElement (doc
);
1748 log_write (_("Converting pre 2.12 data file..."));
1749 return convert_elements_recurse (NULL
, doc
, n
, 0);
1753 validate_import (xmlNodePtr node
)
1760 for (xmlNodePtr n
= node
; n
; n
= n
->next
)
1762 if (n
->type
== XML_ELEMENT_NODE
)
1764 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1766 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1770 xmlChar
*t
= xmlGetNodePath (n
);
1772 log_write (_("Missing attribute '_name' at %s."), t
);
1774 return GPG_ERR_INV_VALUE
;
1777 if (!valid_xml_element (a
))
1779 xmlChar
*t
= xmlGetNodePath (n
);
1781 log_write (_("'%s' is not a valid element name at %s."), a
,
1785 return GPG_ERR_INV_VALUE
;
1789 a
= xmlGetProp (n
, (xmlChar
*) "_ctime");
1794 a
= xmlGetProp (n
, (xmlChar
*) "_mtime");
1796 update_element_mtime (n
);
1801 xmlChar
*t
= xmlGetNodePath (n
);
1803 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1812 rc
= validate_import (n
->children
);
1823 update_element_mtime (xmlNodePtr n
)
1825 return add_attribute (n
, NULL
, NULL
);
1829 unlink_node (xmlNodePtr n
)
1837 rc
= update_element_mtime (n
->parent
);
1844 parse_doc (const char *xml
, size_t len
, xmlDocPtr
*result
)
1848 xmlResetLastError ();
1849 doc
= xmlReadMemory (xml
, len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
1850 if (!doc
&& xmlGetLastError ())
1851 return GPG_ERR_BAD_DATA
;
1854 return !doc
? GPG_ERR_ENOMEM
: 0;
1858 realpath_elements_cb (struct client_s
*client
, xmlNodePtr node
, char **target
,
1859 gpg_error_t
* rc
, char **req_orig
, void *data
)
1861 char *path
= *(char **) data
;
1862 char *tmp
= NULL
, *result
;
1867 *(char **) data
= NULL
;
1870 path
= strv_join ("\t", target
);
1874 *rc
= GPG_ERR_ENOMEM
;
1880 tmp
= strv_join ("\t", req_orig
);
1885 *rc
= GPG_ERR_ENOMEM
;
1891 result
= str_asprintf ("%s\t%s", path
, tmp
);
1893 result
= str_dup (path
);
1897 *rc
= GPG_ERR_ENOMEM
;
1905 *(char **) data
= result
;
1910 build_realpath (struct client_s
*client
, xmlDocPtr doc
, char *line
,
1911 struct string_s
** result
)
1918 struct string_s
*string
;
1921 if (strchr (line
, '\t') != NULL
)
1923 if ((req
= str_split (line
, "\t", 0)) == NULL
)
1924 return GPG_ERR_SYNTAX
;
1928 if ((req
= str_split (line
, " ", 0)) == NULL
)
1929 return GPG_ERR_SYNTAX
;
1932 n
= find_root_element (client
, doc
, &req
, &rc
, NULL
, 0, 0);
1939 rp
= strv_join ("\t", req
);
1943 return GPG_ERR_ENOMEM
;
1948 n
= find_elements (client
, doc
, n
->children
, req
+ 1, &rc
, NULL
,
1949 realpath_elements_cb
, NULL
, 0, 0, &rp
, 0);
1958 string
= string_new (rp
);
1962 return GPG_ERR_ENOMEM
;
1965 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++)
1967 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+ 1) && *(t
+ 1) != '!'))
1969 struct string_s
*s
= string_insert_c (string
, !i
? i
++ : ++i
, '!');
1973 string_free (string
, 1);
1974 return GPG_ERR_ENOMEM
;
1988 node_to_element_path (xmlNodePtr node
)
1991 struct string_s
*str
= string_new ("");
1994 for (n
= node
; n
; n
= n
->parent
)
1998 for (child
= n
; child
; child
= child
->next
)
2000 if (child
->type
!= XML_ELEMENT_NODE
)
2003 xmlChar
*name
= node_has_attribute (n
, (xmlChar
*) "_name");
2006 str
= string_prepend (str
, (char *) name
);
2008 name
= node_has_attribute (n
, (xmlChar
*) "target");
2010 str
= string_prepend (str
, "\t");
2012 str
= string_prepend (str
, "\t!");
2019 str
= string_erase (str
, 0, 1);
2021 string_free (str
, 0);
2027 * Recurse the element tree beginning at 'node' and find elements who point
2028 * back to 'src' or 'dst'. Also follows target attributes.
2031 find_child_to_target (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
2032 xmlNodePtr src
, xmlNodePtr dst
, unsigned depth
,
2038 if (max_recursion_depth
>= 1 && depth
> max_recursion_depth
)
2039 return gpg_error (GPG_ERR_ELOOP
);
2041 for (n
= node
; n
; n
= n
->next
)
2045 if (n
->type
!= XML_ELEMENT_NODE
)
2048 if (n
== src
|| n
== dst
)
2049 return GPG_ERR_ELOOP
;
2051 target
= node_has_attribute (n
, (xmlChar
*) "target");
2055 char **result
= NULL
;
2057 tmp
= resolve_path (client
, doc
, target
, &result
, &rc
);
2062 rc
= find_child_to_target (client
, doc
, tmp
, src
, dst
, ++depth
,
2067 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELEMENT_NOT_FOUND
)
2078 rc
= find_child_to_target (client
, doc
, n
->children
, src
, dst
,
2093 find_child_of_parent (xmlDocPtr doc
, xmlNodePtr src
, xmlNodePtr dst
)
2098 for (n
= src
; n
; n
= n
->next
)
2100 if (n
->type
!= XML_ELEMENT_NODE
)
2109 rc
= find_child_of_parent (doc
, n
->children
, dst
);
2116 find_parent_of_child (xmlDocPtr doc
, xmlNodePtr node
, xmlNodePtr dst
)
2121 for (n
= node
; n
; n
= n
->parent
)
2123 if (n
->type
!= XML_ELEMENT_NODE
)
2127 for (tmp
= n
->next
; tmp
; n
= n
->next
)
2129 if (n
->type
!= XML_ELEMENT_NODE
)
2133 return GPG_ERR_ELOOP
;
2138 return GPG_ERR_ELOOP
;
2145 validate_target_attribute (struct client_s
*client
, xmlDocPtr doc
,
2146 const char *src
, xmlNodePtr dst_node
)
2149 xmlNodePtr src_node
;
2150 char **src_req
= NULL
;
2152 src_node
= resolve_path (client
, doc
, (xmlChar
*) src
, &src_req
, &rc
);
2156 /* A destination element is a child of the source element. */
2157 rc
= find_child_of_parent (doc
, src_node
->children
, dst_node
);
2161 /* The destination element is a parent of the source element. */
2162 rc
= find_parent_of_child (doc
, src_node
->parent
, dst_node
);
2166 /* A destination child element contains a target to the source element. */
2167 rc
= find_child_to_target (client
, doc
, dst_node
->children
, src_node
,
2173 strv_free (src_req
);
2177 /* The owner of the element is the first user listed in the _acl attribute
2178 * list. acl_check() should be called before calling this function. An empty
2179 * ACL is an error if the client is not invoking_user.
2182 is_element_owner (struct client_s
*client
, xmlNodePtr n
)
2184 xmlChar
*acl
= node_has_attribute (n
, (xmlChar
*) "_acl");
2186 gpg_error_t rc
= GPG_ERR_EPERM
;
2194 users
= str_split((char *)acl
, ",", 0);
2195 if (users
&& *users
)
2200 if (client
->thd
->remote
)
2201 user
= str_asprintf ("#%s", client
->thd
->tls
->fp
);
2203 user
= get_username (client
->thd
->peer
->uid
);
2205 user
= get_username (client
->thd
->peer
->uid
);
2208 rc
= !strcmp (*users
, user
) ? 0 : GPG_ERR_EPERM
;