2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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>
36 #define _(msgid) gettext(msgid)
39 #include "pwmd-error.h"
40 #include "util-misc.h"
45 extern void log_write (const char *fmt
, ...);
48 * 'element' must be allocated.
51 is_literal_element (char **element
)
55 if (!element
|| !*element
)
58 if (*(*element
) == '!')
62 for (p
= *element
, c
= p
+ 1; *c
; c
++)
73 valid_xml_attribute (const char *str
)
77 for (p
= str
; *p
; p
++)
87 valid_xml_element (xmlChar
* element
)
89 char *p
= (char *) element
;
91 if (!element
|| !*element
|| *element
== '!')
104 valid_element_path (char **path
, int with_content
)
106 char **dup
= NULL
, **p
;
112 /* Save some memory by not duplicating the element content. */
115 t
= strv_length (path
);
116 for (i
= 0; i
< t
- 1; i
++)
118 char **tmp
= xrealloc (dup
, (i
+ 2) * sizeof (char *));
127 dup
[i
] = str_dup (path
[i
]);
132 dup
= strv_dup (path
);
137 for (p
= dup
; *p
&& *(*p
); p
++)
139 is_literal_element (&(*p
));
140 if (!valid_xml_element ((xmlChar
*) * p
))
152 attr_ctime (xmlNodePtr n
)
154 char *buf
= str_asprintf ("%li", time (NULL
));
158 return GPG_ERR_ENOMEM
;
160 rc
= add_attribute (n
, "_ctime", buf
);
166 create_new_element (xmlNodePtr parent
, const char *name
, xmlNodePtr
* result
)
168 xmlNodePtr n
= xmlNewNode (NULL
, (xmlChar
*) "element");
172 return GPG_ERR_ENOMEM
;
174 rc
= add_attribute (n
, "_name", name
);
181 *result
= xmlAddChild (parent
, n
);
183 (void) xmlAddChild (parent
, n
);
192 new_root_element (xmlDocPtr doc
, char *name
)
194 xmlNodePtr root
= xmlDocGetRootElement (doc
);
198 return GPG_ERR_BAD_DATA
;
203 if (!valid_xml_element ((xmlChar
*) p
))
204 return GPG_ERR_INV_VALUE
;
206 return create_new_element (root
, p
, NULL
);
213 xmlTextWriterPtr wr
= xmlNewTextWriterDoc (&doc
, 0);
218 if (xmlTextWriterStartDocument (wr
, NULL
, "UTF-8", "yes"))
221 if (xmlTextWriterStartDTD (wr
, (xmlChar
*) "pwmd", NULL
, NULL
) == -1)
224 if (xmlTextWriterWriteDTDElement (wr
, (xmlChar
*) "pwmd",
225 (xmlChar
*) "(element)") == -1)
228 xmlTextWriterEndDTDElement (wr
);
230 if (xmlTextWriterWriteDTDAttlist (wr
, (xmlChar
*) "element",
231 (xmlChar
*) "_name CDATA #REQUIRED") ==
235 xmlTextWriterEndDTDAttlist (wr
);
236 xmlTextWriterEndDTD (wr
);
238 if (xmlTextWriterStartElement (wr
, (xmlChar
*) "pwmd"))
241 xmlTextWriterEndElement (wr
);
242 xmlTextWriterEndDocument (wr
);
243 xmlFreeTextWriter (wr
);
247 xmlTextWriterEndDocument (wr
);
248 xmlFreeTextWriter (wr
);
256 return create_dtd ();
260 find_element_node (xmlNodePtr node
)
264 if (n
&& n
->type
== XML_ELEMENT_NODE
)
267 for (n
= node
; n
; n
= n
->next
)
269 if (n
->type
== XML_ELEMENT_NODE
)
277 resolve_path (xmlDocPtr doc
, xmlChar
* path
, char ***result
, gpg_error_t
* rc
)
282 req
= str_split ((char *) path
, "\t", 0);
285 *rc
= GPG_ERR_ENOMEM
;
289 n
= find_root_element (doc
, &req
, rc
, NULL
, 0, 0);
297 n
= find_elements (doc
, n
->children
, req
+ 1, rc
, NULL
, NULL
, NULL
,
309 * Lists root element names; the value of the attribute "_name" of an element
310 * "element". If there's a target attribute both literal and non-literal
311 * element names will be added. This is the primary reason why XML entities
312 * cannot be used. There wouldn't be a way to get the literal an non-literal
316 list_root_elements (xmlDocPtr doc
, struct string_s
** result
,
317 int verbose
, int with_target
)
320 struct slist_s
*list
= NULL
;
322 struct string_s
*string
;
325 n
= xmlDocGetRootElement (doc
);
326 if (!n
|| !n
->children
)
327 return GPG_ERR_NO_DATA
;
329 for (n
= n
->children
; n
; n
= n
->next
)
332 xmlChar
*val
, *target
;
333 struct slist_s
*tlist
;
336 if (n
->type
!= XML_ELEMENT_NODE
)
339 a
= xmlHasProp (n
, (xmlChar
*) "_name");
340 if (!a
|| !a
->children
->content
)
343 val
= xmlNodeGetContent (a
->children
);
351 str_asprintf ("!%s%s", (char *) val
,
352 verbose
? find_element_node (n
->children
) ? " +" : "" :
362 tlist
= slist_append (list
, tmp
);
371 target
= node_has_attribute (n
, (xmlChar
*) "target");
379 xmlNodePtr tnode
= resolve_path (doc
, target
, &req
, &rc
);
381 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
)
383 t
= str_asprintf ("%s %s", (char *) val
,
384 rc
== GPG_ERR_ELOOP
? "O" : "E");
389 struct string_s
*realpath
= NULL
;
393 rc
= build_realpath (doc
, (char *) target
, &realpath
);
402 realpath
= string_prepend (realpath
, "T ");
405 t
= str_asprintf ("%s%s%s%s", (char *) val
,
407 && find_element_node (tnode
->children
))
408 || realpath
? " " : "", tnode
409 && find_element_node (tnode
->children
) ?
410 "+" : "", realpath
? realpath
->str
: "");
413 string_free (realpath
, 1);
420 t
= str_dup ((char *) val
);
426 rc
= rc
? rc
: GPG_ERR_ENOMEM
;
430 tlist
= slist_append (list
, t
);
447 total
= slist_length (list
);
449 return GPG_ERR_NO_DATA
;
451 string
= string_new (NULL
);
458 for (i
= 0; i
< total
; i
++)
460 char *val
= slist_nth_data (list
, i
);
462 string_append_printf (string
, "%s\n", val
);
465 string
= string_truncate (string
, string
->len
- 1);
469 total
= slist_length (list
);
470 for (i
= 0; i
< total
; i
++)
471 xfree (slist_nth_data (list
, i
));
478 * Prevents a sibling element past the current element path with the same
482 find_stop_node (xmlNodePtr node
)
486 for (n
= node
->parent
->children
; n
; n
= n
->next
)
496 create_target_elements_cb (xmlNodePtr node
, char **path
,
497 gpg_error_t
* rc
, void *data
)
501 xmlNodePtr parent
= data
;
503 for (i
= 0; req
[i
] && *req
[i
]; i
++)
507 if (parent
&& node
== parent
)
509 *rc
= GPG_ERR_CONFLICT
;
513 is_literal_element (&req
[i
]);
515 if ((n
= find_element (node
, req
[i
], find_stop_node (node
))) == NULL
||
516 (n
&& n
->parent
== node
->parent
))
519 *rc
= create_new_element (node
, req
[i
], &node
);
531 find_text_node (xmlNodePtr node
)
535 if (n
&& n
->type
== XML_TEXT_NODE
)
538 for (n
= node
; n
; n
= n
->next
)
540 if (n
->type
== XML_TEXT_NODE
)
548 create_elements_cb (xmlNodePtr node
, char **elements
,
549 gpg_error_t
* rc
, void *data
)
552 char **req
= elements
;
554 if (node
->type
== XML_TEXT_NODE
)
557 for (i
= 0; req
[i
] && *req
[i
]; i
++)
562 * Strip the first '!' if needed. If there's another, it's an
563 * rc. The syntax has already been checked before calling this
566 is_literal_element (&req
[i
]);
567 n
= find_element (node
, req
[i
], find_stop_node (node
));
570 * If the found element has the same parent as the current element,
571 * they are siblings and the new element needs to be created as a
572 * child of the current element (node).
574 if (n
&& n
->parent
== node
->parent
)
579 *rc
= create_new_element (node
, req
[i
], &node
);
590 /* The root element is really req[0]. It is need as a pointer in case there is
591 * a target attribute so it can be updated. */
593 find_root_element (xmlDocPtr doc
, char ***req
, gpg_error_t
* rc
,
594 int *target
, int recursion_depth
, int stop
)
596 xmlNodePtr n
= xmlDocGetRootElement (doc
);
598 char *root
= str_dup (*req
[0]);
599 int literal
= is_literal_element (&root
);
603 *rc
= GPG_ERR_ENOMEM
;
610 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
612 xmlChar
*t
= xmlGetNodePath (n
);
614 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
623 if (n
->type
== XML_ELEMENT_NODE
)
625 if (depth
== 0 && xmlStrEqual (n
->name
, (xmlChar
*) "pwmd"))
632 if (depth
== 1 && xmlStrEqual (n
->name
, (xmlChar
*) "element"))
634 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "_name");
639 if (xmlStrEqual (content
, (xmlChar
*) root
))
641 char **nreq
, **tmp
= NULL
;
651 content
= node_has_attribute (n
, (xmlChar
*) "target");
656 if (!content
|| stop
)
665 if (strchr ((char *) content
, '\t'))
667 nreq
= str_split ((char *) content
, "\t", 0);
676 *rc
= GPG_ERR_ENOMEM
;
682 tmp
= strv_catv (nreq
, tmp
+ 1);
688 *rc
= GPG_ERR_ENOMEM
;
697 if (strv_printf (&tmp
, "%s", content
) == 0)
701 *rc
= GPG_ERR_ENOMEM
;
707 nreq
= strv_catv (tmp
, nreq
+ 1);
712 *rc
= GPG_ERR_ENOMEM
;
723 find_root_element (doc
, req
, rc
, target
, recursion_depth
,
736 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
741 find_element (xmlNodePtr node
, char *element
, xmlNodePtr stop
)
745 if (!node
|| !element
)
748 for (n
= node
; n
; n
= n
->next
)
750 if (n
->type
!= XML_ELEMENT_NODE
)
756 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
758 if (a
&& xmlStrEqual (a
, (xmlChar
*) element
))
771 node_has_attribute (xmlNodePtr n
, xmlChar
* attr
)
773 xmlAttrPtr a
= xmlHasProp (n
, attr
);
778 if (!a
->children
|| !a
->children
->content
)
781 return xmlGetProp (n
, attr
);
785 element_to_literal (char **element
)
787 char *p
= str_asprintf ("!%s", *element
);
797 /* Resolves elements in 'req' one at a time. It's recursive in case of
798 * "target" attributes. */
800 find_elements (xmlDocPtr doc
, xmlNodePtr node
,
801 char **req
, gpg_error_t
* rc
, int *target
,
802 xmlNodePtr (*found_fn
) (xmlNodePtr
, char **, gpg_error_t
*,
804 xmlNodePtr (*not_found_fn
) (xmlNodePtr
, char **, gpg_error_t
*,
805 void *), int is_list_command
,
806 int recursion_depth
, void *data
, int stop
)
808 xmlNodePtr n
, last
, last_node
;
815 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
817 xmlChar
*t
= xmlGetNodePath (node
);
819 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
826 for (last_node
= last
= n
= node
, p
= req
; *p
; p
++)
834 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
841 *rc
= GPG_ERR_ENOMEM
;
845 literal
= is_literal_element (&t
);
846 n
= find_element (last
, t
, NULL
);
852 return not_found_fn (found
? last_node
: last_node
->parent
, p
, rc
,
855 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
865 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "target");
866 char **nreq
= NULL
, **nnreq
;
870 if (is_list_command
== 1)
872 if (element_to_literal (&(*p
)) == 0)
874 *rc
= GPG_ERR_ENOMEM
;
885 if (!*(p
+ 1) && stop
)
891 if (strchr ((char *) content
, '\t') != NULL
)
893 if ((nreq
= str_split ((char *) content
, "\t", 0)) == NULL
)
896 *rc
= GPG_ERR_INV_VALUE
;
902 if ((nreq
= str_split ((char *) content
, " ", 0)) == NULL
)
905 *rc
= GPG_ERR_INV_VALUE
;
911 tmp
= find_root_element (doc
, &nreq
, rc
, target
, 0, 0);
921 found_fn (tmp
, nreq
, rc
, p
+ 1, data
);
930 if (!*(nreq
+ 1) && !*(p
+ 1))
936 nnreq
= strv_catv (nreq
+ 1, p
+ 1);
940 if (!nnreq
|| !*nnreq
)
949 n
= find_elements (doc
, tmp
->children
, nnreq
, rc
, NULL
, found_fn
,
950 not_found_fn
, is_list_command
, recursion_depth
,
957 return not_found_fn (tmp
, p
+ 1, rc
, data
);
959 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
965 char **zz
= p
+ 1, **qq
= nnreq
;
967 if (strv_length (nnreq
) > strv_length (p
+ 1))
970 for (; *qq
&& *zz
; zz
++)
973 *zz
= str_dup (*qq
++);
977 *rc
= GPG_ERR_ENOMEM
;
993 update_element_list (struct element_list_s
*elements
)
998 if (!elements
|| !elements
->elements
)
1001 line
= strv_join ("\t", elements
->elements
);
1006 strv_free (elements
->elements
);
1007 elements
->elements
= NULL
;
1008 l
= slist_append (elements
->list
, line
);
1018 path_list_recurse (xmlDocPtr doc
, xmlNodePtr node
,
1019 struct element_list_s
*elements
)
1023 gpg_error_t error_flag
= 0;
1025 for (n
= node
; n
; n
= n
->next
)
1027 xmlChar
*target
= NULL
;
1028 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
1034 if (n
->type
!= XML_ELEMENT_NODE
)
1037 if (elements
->verbose
)
1040 (&elements
->elements
, "%s\t!%s%s", elements
->prefix
, a
,
1041 find_element_node (n
->children
) ? " +" : "") == 0)
1044 return GPG_ERR_ENOMEM
;
1048 if (strv_printf (&elements
->elements
, "%s\t!%s", elements
->prefix
, a
)
1052 return GPG_ERR_ENOMEM
;
1055 if (update_element_list (elements
) == 0)
1058 return GPG_ERR_ENOMEM
;
1061 target
= node_has_attribute (n
, (xmlChar
*) "target");
1066 char *save
= elements
->prefix
;
1067 int r
= elements
->resolving
;
1070 struct string_s
*realpath
= NULL
;
1072 tnode
= resolve_path (doc
, target
, &req
, &rc
);
1073 if (rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_ELEMENT_NOT_FOUND
)
1075 if (rc
== GPG_ERR_ELOOP
)
1077 xmlChar
*t
= xmlGetNodePath (n
);
1079 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
1083 if (elements
->verbose
)
1085 strv_printf (&elements
->elements
, "%s\t%s %s",
1086 elements
->prefix
, a
,
1087 rc
== GPG_ERR_ELOOP
? "O" : "E");
1088 error_flag
= err
= rc
;
1094 if (!elements
->verbose
&& rc
)
1101 if (elements
->with_target
)
1103 rc
= build_realpath (doc
, (char *) target
, &realpath
);
1111 realpath
= string_prepend (realpath
, "T ");
1114 if (elements
->verbose
)
1116 if (!strv_printf (&elements
->elements
, "%s\t%s%s%s%s",
1117 elements
->prefix
, a
,
1118 (tnode
&& find_element_node (tnode
->children
))
1119 || realpath
? " " : "", tnode
1120 && find_element_node (tnode
->children
) ? "+" :
1121 "", realpath
? realpath
->str
: ""))
1125 return GPG_ERR_ENOMEM
;
1130 (&elements
->elements
, "%s\t%s", elements
->prefix
, a
))
1134 return GPG_ERR_ENOMEM
;
1139 string_free (realpath
, 1);
1141 tmp
= strv_join ("\t", elements
->elements
);
1147 return GPG_ERR_ENOMEM
;
1150 if (update_element_list (elements
) == 0)
1155 return GPG_ERR_ENOMEM
;
1158 if (!err
&& elements
->recurse
)
1160 /* Prune element flags. */
1161 if (elements
->verbose
&& strchr (tmp
, ' '))
1165 for (p
= tmp
; *p
; p
++)
1175 elements
->prefix
= tmp
;
1176 elements
->resolving
= 1;
1177 rc
= create_path_list (doc
, elements
, (char *) target
);
1178 elements
->resolving
= r
;
1179 elements
->prefix
= save
;
1181 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELOOP
)
1189 error_flag
= err
= rc
;
1198 if (n
->children
&& elements
->recurse
&& err
!= GPG_ERR_ELOOP
)
1200 char *tmp
= str_asprintf ("%s\t!%s", elements
->prefix
, a
);
1201 char *save
= elements
->prefix
;
1206 return GPG_ERR_ENOMEM
;
1209 elements
->prefix
= tmp
;
1210 rc
= path_list_recurse (doc
, n
->children
, elements
);
1211 xfree (elements
->prefix
);
1212 elements
->prefix
= save
;
1224 return error_flag
== GPG_ERR_ELOOP
? error_flag
: rc
;
1228 add_attribute (xmlNodePtr node
, const char *name
, const char *value
)
1233 if (name
&& !xmlSetProp (node
, (xmlChar
*) name
, (xmlChar
*) value
))
1234 return GPG_ERR_BAD_DATA
;
1236 if (name
&& xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_mtime"))
1239 buf
= str_asprintf ("%li", time (NULL
));
1240 rc
= add_attribute (node
, "_mtime", buf
);
1246 * From the element path 'path', find sub-nodes and append them to the list.
1249 create_path_list (xmlDocPtr doc
, struct element_list_s
* elements
, char *path
)
1252 char **req
, **req_orig
;
1256 req
= str_split (path
, "\t", 0);
1259 req
= str_split (path
, " ", 0);
1261 return GPG_ERR_SYNTAX
;
1264 req_orig
= strv_dup (req
);
1267 rc
= GPG_ERR_ENOMEM
;
1271 n
= find_root_element (doc
, &req
, &rc
, &a_target
, 0, 0);
1272 if ((rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
)
1273 && elements
->verbose
&& a_target
)
1279 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1290 *req
= str_dup (*req_orig
);
1298 find_elements (doc
, n
->children
, req
+ 1, &rc
, &e_target
, NULL
, NULL
,
1301 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1311 if (!elements
->prefix
)
1316 * If any req_orig element contains no target the element should be
1317 * prefixed with the literal character. Not really crucial if the
1318 * client isn't human because child elements are prefixed for the
1319 * current path. But may be confusing if editing by hand.
1321 elements
->prefix
= strv_join ("\t", req_orig
);
1323 if (!elements
->prefix
)
1325 rc
= GPG_ERR_ENOMEM
;
1329 if (elements
->verbose
)
1332 struct string_s
*realpath
= NULL
;
1334 if (a_target
&& elements
->with_target
)
1336 rc
= build_realpath (doc
, path
, &realpath
);
1340 realpath
= string_prepend (realpath
, "T ");
1343 ret
= strv_printf (&elements
->elements
, "%s%s%s%s",
1345 find_element_node (n
->children
)
1346 || realpath
? " " : "",
1347 find_element_node (n
->children
) ? "+" : "",
1348 realpath
? realpath
->str
: "");
1349 string_free (realpath
, 1);
1352 rc
= GPG_ERR_ENOMEM
;
1356 else if (strv_printf (&elements
->elements
, "%s", elements
->prefix
) == 0)
1358 rc
= GPG_ERR_ENOMEM
;
1362 if (update_element_list (elements
) == 0)
1364 rc
= GPG_ERR_ENOMEM
;
1369 rc
= path_list_recurse (doc
, n
->children
, elements
);
1373 strv_free (req_orig
);
1380 recurse_xpath_nodeset (xmlDocPtr doc
, xmlNodeSetPtr nodes
,
1381 xmlChar
* value
, xmlBufferPtr
* result
, int cmd
,
1382 const xmlChar
* attr
)
1384 int i
= value
? nodes
->nodeNr
- 1 : 0;
1387 buf
= xmlBufferCreate ();
1390 return GPG_ERR_ENOMEM
;
1392 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++)
1394 xmlNodePtr n
= nodes
->nodeTab
[i
];
1400 if (!value
&& !attr
)
1402 if (xmlNodeDump (buf
, doc
, n
, 0, 0) == -1)
1405 return GPG_ERR_BAD_DATA
;
1413 xmlNodeSetContent (n
, value
);
1414 rc
= update_element_mtime (n
);
1422 rc
= add_attribute (n
, (char *) attr
, (char *) value
);
1424 rc
= delete_attribute (n
, attr
);
1436 convert_root_element (xmlNodePtr n
)
1438 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1444 xmlChar
*t
= xmlGetNodePath (n
);
1447 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1450 return GPG_ERR_AMBIGUOUS_NAME
;
1453 a
= xmlGetProp (n
, (xmlChar
*) "name");
1457 rc
= add_attribute (n
, "_name", (char *) a
);
1463 rc
= delete_attribute (n
, (xmlChar
*) "name");
1468 xmlNodeSetName (n
, (xmlChar
*) "element");
1475 delete_attribute (xmlNodePtr n
, const xmlChar
* name
)
1479 if ((a
= xmlHasProp (n
, name
)) == NULL
)
1480 return GPG_ERR_NOT_FOUND
;
1482 if (xmlRemoveProp (a
) == -1)
1483 return GPG_ERR_BAD_DATA
;
1485 return update_element_mtime (n
);
1489 convert_elements_recurse (xmlDocPtr doc
, xmlNodePtr n
, unsigned depth
)
1495 for (n
= n
->children
; n
; n
= n
->next
)
1497 if (n
->type
== XML_ELEMENT_NODE
)
1503 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1505 xmlChar
*t
= xmlGetNodePath (n
);
1508 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1511 return GPG_ERR_AMBIGUOUS_NAME
;
1514 a
= xmlGetProp (n
, (xmlChar
*) "_name");
1519 xmlChar
*t
= xmlGetNodePath (n
);
1522 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1525 return GPG_ERR_AMBIGUOUS_NAME
;
1528 xmlChar
*tmp
= xmlStrdup (n
->name
);
1531 return GPG_ERR_ENOMEM
;
1533 xmlNodeSetName (n
, (xmlChar
*) "element");
1534 rc
= add_attribute (n
, "_name", (char *) tmp
);
1542 rc
= convert_root_element (n
);
1551 rc
= convert_elements_recurse (doc
, n
, depth
);
1561 /* Renames ALL elements to the new "element" name. Existing element names are
1562 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1563 * elements can contain common characters that the XML parser barfs on (an
1564 * email address for example. */
1566 convert_pre_212_elements (xmlDocPtr doc
)
1568 xmlNodePtr n
= xmlDocGetRootElement (doc
);
1570 log_write (_("Converting pre 2.12 data file..."));
1571 return convert_elements_recurse (doc
, n
, 0);
1575 validate_import (xmlNodePtr node
)
1582 for (xmlNodePtr n
= node
; n
; n
= n
->next
)
1584 if (n
->type
== XML_ELEMENT_NODE
)
1586 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1588 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1592 xmlChar
*t
= xmlGetNodePath (n
);
1594 log_write (_("Missing attribute '_name' at %s."), t
);
1596 return GPG_ERR_INV_VALUE
;
1599 if (!valid_xml_element (a
))
1601 xmlChar
*t
= xmlGetNodePath (n
);
1603 log_write (_("'%s' is not a valid element name at %s."), a
,
1607 return GPG_ERR_INV_VALUE
;
1611 a
= xmlGetProp (n
, (xmlChar
*) "_ctime");
1616 a
= xmlGetProp (n
, (xmlChar
*) "_mtime");
1618 update_element_mtime (n
);
1623 xmlChar
*t
= xmlGetNodePath (n
);
1625 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1634 rc
= validate_import (n
->children
);
1645 update_element_mtime (xmlNodePtr n
)
1647 return add_attribute (n
, NULL
, NULL
);
1651 unlink_node (xmlNodePtr n
)
1659 rc
= update_element_mtime (n
->parent
);
1666 parse_doc (const char *xml
, size_t len
, xmlDocPtr
*result
)
1670 xmlResetLastError ();
1671 doc
= xmlReadMemory (xml
, len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
1672 if (!doc
&& xmlGetLastError ())
1673 return GPG_ERR_BAD_DATA
;
1676 return !doc
? GPG_ERR_ENOMEM
: 0;
1680 realpath_elements_cb (xmlNodePtr node
, char **target
,
1681 gpg_error_t
* rc
, char **req_orig
, void *data
)
1683 char *path
= *(char **) data
;
1684 char *tmp
= NULL
, *result
;
1689 *(char **) data
= NULL
;
1692 path
= strv_join ("\t", target
);
1696 *rc
= GPG_ERR_ENOMEM
;
1702 tmp
= strv_join ("\t", req_orig
);
1707 *rc
= GPG_ERR_ENOMEM
;
1713 result
= str_asprintf ("%s\t%s", path
, tmp
);
1715 result
= str_dup (path
);
1719 *rc
= GPG_ERR_ENOMEM
;
1727 *(char **) data
= result
;
1732 build_realpath (xmlDocPtr doc
, char *line
, struct string_s
** result
)
1739 struct string_s
*string
;
1742 if (strchr (line
, '\t') != NULL
)
1744 if ((req
= str_split (line
, "\t", 0)) == NULL
)
1745 return GPG_ERR_SYNTAX
;
1749 if ((req
= str_split (line
, " ", 0)) == NULL
)
1750 return GPG_ERR_SYNTAX
;
1753 n
= find_root_element (doc
, &req
, &rc
, NULL
, 0, 0);
1760 rp
= strv_join ("\t", req
);
1764 return GPG_ERR_ENOMEM
;
1769 n
= find_elements (doc
, n
->children
, req
+ 1, &rc
,
1770 NULL
, realpath_elements_cb
, NULL
, 0, 0, &rp
, 0);
1779 string
= string_new (rp
);
1783 return GPG_ERR_ENOMEM
;
1786 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++)
1788 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+ 1) && *(t
+ 1) != '!'))
1790 struct string_s
*s
= string_insert_c (string
, !i
? i
++ : ++i
, '!');
1794 string_free (string
, 1);
1795 return GPG_ERR_ENOMEM
;
1809 node_to_element_path (xmlNodePtr node
)
1812 struct string_s
*str
= string_new ("");
1815 for (n
= node
; n
; n
= n
->parent
)
1819 for (child
= n
; child
; child
= child
->next
)
1821 if (child
->type
!= XML_ELEMENT_NODE
)
1824 xmlChar
*name
= node_has_attribute (n
, (xmlChar
*) "_name");
1827 str
= string_prepend (str
, (char *) name
);
1829 name
= node_has_attribute (n
, (xmlChar
*) "target");
1831 str
= string_prepend (str
, "\t");
1833 str
= string_prepend (str
, "\t!");
1840 str
= string_erase (str
, 0, 1);
1842 string_free (str
, 0);
1848 * Recurse the element tree beginning at 'node' and find elements who point
1849 * back to 'src' or 'dst'. Also follows target attributes.
1852 find_child_to_target (xmlDocPtr doc
, xmlNodePtr node
,
1853 xmlNodePtr src
, xmlNodePtr dst
, unsigned depth
,
1859 if (max_recursion_depth
>= 1 && depth
> max_recursion_depth
)
1860 return gpg_error (GPG_ERR_ELOOP
);
1862 for (n
= node
; n
; n
= n
->next
)
1866 if (n
->type
!= XML_ELEMENT_NODE
)
1869 if (n
== src
|| n
== dst
)
1870 return GPG_ERR_ELOOP
;
1872 target
= node_has_attribute (n
, (xmlChar
*) "target");
1876 char **result
= NULL
;
1878 tmp
= resolve_path (doc
, target
, &result
, &rc
);
1883 rc
= find_child_to_target (doc
, tmp
, src
, dst
, ++depth
, 1);
1887 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELEMENT_NOT_FOUND
)
1898 rc
= find_child_to_target (doc
, n
->children
, src
, dst
, ++depth
,0);
1912 find_child_of_parent (xmlDocPtr doc
, xmlNodePtr src
, xmlNodePtr dst
)
1917 for (n
= src
; n
; n
= n
->next
)
1919 if (n
->type
!= XML_ELEMENT_NODE
)
1928 rc
= find_child_of_parent (doc
, n
->children
, dst
);
1935 find_parent_of_child (xmlDocPtr doc
, xmlNodePtr node
, xmlNodePtr dst
)
1940 for (n
= node
; n
; n
= n
->parent
)
1942 if (n
->type
!= XML_ELEMENT_NODE
)
1946 for (tmp
= n
->next
; tmp
; n
= n
->next
)
1948 if (n
->type
!= XML_ELEMENT_NODE
)
1952 return GPG_ERR_ELOOP
;
1957 return GPG_ERR_ELOOP
;
1964 validate_target_attribute (xmlDocPtr doc
, const char *src
,
1965 xmlNodePtr dst_node
)
1968 xmlNodePtr src_node
;
1969 char **src_req
= NULL
;
1971 src_node
= resolve_path (doc
, (xmlChar
*) src
, &src_req
, &rc
);
1975 /* A destination element is a child of the source element. */
1976 rc
= find_child_of_parent (doc
, src_node
->children
, dst_node
);
1980 /* The destination element is a parent of the source element. */
1981 rc
= find_parent_of_child (doc
, src_node
->parent
, dst_node
);
1985 /* A destination child element contains a target to the source element. */
1986 rc
= find_child_to_target (doc
, dst_node
->children
, src_node
, dst_node
, 0, 0);
1991 strv_free (src_req
);