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
)
75 return valid_xml_element ((xmlChar
*)str
);
79 valid_xml_element (xmlChar
*str
)
84 if (!str
|| !*str
|| *str
== '!')
87 wc
= str_to_wchar ((const char *)str
);
90 for (c
= 0; c
< len
; c
++)
98 case 0x0300 ... 0x036F:
99 case 0x203F ... 0x2040:
107 case 'A' ... 'Z': break;
108 case 'a' ... 'z': break;
109 case 0xC0 ... 0xD6: break;
110 case 0xD8 ... 0xF6: break;
111 case 0xF8 ... 0x2FF: break;
112 case 0x370 ... 0x37D: break;
113 case 0x37F ... 0x1FFF: break;
114 case 0x200C ... 0x200D: break;
115 case 0x2070 ... 0x218F: break;
116 case 0x2C00 ... 0x2FEF: break;
117 case 0x3001 ... 0xD7FF: break;
118 case 0xF900 ... 0xFDCF: break;
119 case 0xFDF0 ... 0xFFFD: break;
120 case 0x10000 ... 0xEFFFF: break;
132 valid_element_path (char **path
, int with_content
)
134 char **dup
= NULL
, **p
;
140 /* Save some memory by not duplicating the element content. */
143 t
= strv_length (path
);
144 for (i
= 0; i
< t
- 1; i
++)
146 char **tmp
= xrealloc (dup
, (i
+ 2) * sizeof (char *));
155 dup
[i
] = str_dup (path
[i
]);
160 dup
= strv_dup (path
);
165 for (p
= dup
; *p
&& *(*p
); p
++)
167 is_literal_element (&(*p
));
168 if (!valid_xml_element ((xmlChar
*) * p
))
180 attr_ctime (xmlNodePtr n
)
182 char *buf
= str_asprintf ("%li", time (NULL
));
186 return GPG_ERR_ENOMEM
;
188 rc
= add_attribute (n
, "_ctime", buf
);
194 create_new_element (xmlNodePtr parent
, const char *name
, xmlNodePtr
* result
)
196 xmlNodePtr n
= xmlNewNode (NULL
, (xmlChar
*) "element");
200 return GPG_ERR_ENOMEM
;
202 rc
= add_attribute (n
, "_name", name
);
209 *result
= xmlAddChild (parent
, n
);
211 (void) xmlAddChild (parent
, n
);
220 new_root_element (xmlDocPtr doc
, char *name
)
222 xmlNodePtr root
= xmlDocGetRootElement (doc
);
226 return GPG_ERR_BAD_DATA
;
231 if (!valid_xml_element ((xmlChar
*) p
))
232 return GPG_ERR_INV_VALUE
;
234 return create_new_element (root
, p
, NULL
);
241 xmlTextWriterPtr wr
= xmlNewTextWriterDoc (&doc
, 0);
246 if (xmlTextWriterStartDocument (wr
, NULL
, "UTF-8", "yes"))
249 if (xmlTextWriterStartDTD (wr
, (xmlChar
*) "pwmd", NULL
, NULL
) == -1)
252 if (xmlTextWriterWriteDTDElement (wr
, (xmlChar
*) "pwmd",
253 (xmlChar
*) "(element)") == -1)
256 xmlTextWriterEndDTDElement (wr
);
258 if (xmlTextWriterWriteDTDAttlist (wr
, (xmlChar
*) "element",
259 (xmlChar
*) "_name CDATA #REQUIRED") ==
263 xmlTextWriterEndDTDAttlist (wr
);
264 xmlTextWriterEndDTD (wr
);
266 if (xmlTextWriterStartElement (wr
, (xmlChar
*) "pwmd"))
269 xmlTextWriterEndElement (wr
);
270 xmlTextWriterEndDocument (wr
);
271 xmlFreeTextWriter (wr
);
275 xmlTextWriterEndDocument (wr
);
276 xmlFreeTextWriter (wr
);
284 return create_dtd ();
288 find_element_node (xmlNodePtr node
)
292 if (n
&& n
->type
== XML_ELEMENT_NODE
)
295 for (n
= node
; n
; n
= n
->next
)
297 if (n
->type
== XML_ELEMENT_NODE
)
305 resolve_path (xmlDocPtr doc
, xmlChar
* path
, char ***result
, gpg_error_t
* rc
)
310 req
= str_split ((char *) path
, "\t", 0);
313 *rc
= GPG_ERR_ENOMEM
;
317 n
= find_root_element (doc
, &req
, rc
, NULL
, 0, 0);
325 n
= find_elements (doc
, n
->children
, req
+ 1, rc
, NULL
, NULL
, NULL
,
337 * Lists root element names; the value of the attribute "_name" of an element
338 * "element". If there's a target attribute both literal and non-literal
339 * element names will be added. This is the primary reason why XML entities
340 * cannot be used. There wouldn't be a way to get the literal an non-literal
344 list_root_elements (xmlDocPtr doc
, struct string_s
** result
,
345 int verbose
, int with_target
)
348 struct slist_s
*list
= NULL
;
350 struct string_s
*string
;
353 n
= xmlDocGetRootElement (doc
);
354 if (!n
|| !n
->children
)
355 return GPG_ERR_NO_DATA
;
357 for (n
= n
->children
; n
; n
= n
->next
)
360 xmlChar
*val
, *target
;
361 struct slist_s
*tlist
;
364 if (n
->type
!= XML_ELEMENT_NODE
)
367 a
= xmlHasProp (n
, (xmlChar
*) "_name");
368 if (!a
|| !a
->children
->content
)
371 val
= xmlNodeGetContent (a
->children
);
379 str_asprintf ("!%s%s", (char *) val
,
380 verbose
? find_element_node (n
->children
) ? " +" : "" :
390 tlist
= slist_append (list
, tmp
);
399 target
= node_has_attribute (n
, (xmlChar
*) "target");
407 xmlNodePtr tnode
= resolve_path (doc
, target
, &req
, &rc
);
409 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
)
411 t
= str_asprintf ("%s %s", (char *) val
,
412 rc
== GPG_ERR_ELOOP
? "O" : "E");
417 struct string_s
*realpath
= NULL
;
421 rc
= build_realpath (doc
, (char *) target
, &realpath
);
430 realpath
= string_prepend (realpath
, "T ");
433 t
= str_asprintf ("%s%s%s%s", (char *) val
,
435 && find_element_node (tnode
->children
))
436 || realpath
? " " : "", tnode
437 && find_element_node (tnode
->children
) ?
438 "+" : "", realpath
? realpath
->str
: "");
441 string_free (realpath
, 1);
448 t
= str_dup ((char *) val
);
454 rc
= rc
? rc
: GPG_ERR_ENOMEM
;
458 tlist
= slist_append (list
, t
);
475 total
= slist_length (list
);
477 return GPG_ERR_NO_DATA
;
479 string
= string_new (NULL
);
486 for (i
= 0; i
< total
; i
++)
488 char *val
= slist_nth_data (list
, i
);
490 string_append_printf (string
, "%s\n", val
);
493 string
= string_truncate (string
, string
->len
- 1);
497 total
= slist_length (list
);
498 for (i
= 0; i
< total
; i
++)
499 xfree (slist_nth_data (list
, i
));
506 * Prevents a sibling element past the current element path with the same
510 find_stop_node (xmlNodePtr node
)
514 for (n
= node
->parent
->children
; n
; n
= n
->next
)
524 create_target_elements_cb (xmlNodePtr node
, char **path
,
525 gpg_error_t
* rc
, void *data
)
529 xmlNodePtr parent
= data
;
531 for (i
= 0; req
[i
] && *req
[i
]; i
++)
535 if (parent
&& node
== parent
)
537 *rc
= GPG_ERR_CONFLICT
;
541 is_literal_element (&req
[i
]);
543 if ((n
= find_element (node
, req
[i
], find_stop_node (node
))) == NULL
||
544 (n
&& n
->parent
== node
->parent
))
547 *rc
= create_new_element (node
, req
[i
], &node
);
559 find_text_node (xmlNodePtr node
)
563 if (n
&& n
->type
== XML_TEXT_NODE
)
566 for (n
= node
; n
; n
= n
->next
)
568 if (n
->type
== XML_TEXT_NODE
)
576 create_elements_cb (xmlNodePtr node
, char **elements
,
577 gpg_error_t
* rc
, void *data
)
580 char **req
= elements
;
582 if (node
->type
== XML_TEXT_NODE
)
585 for (i
= 0; req
[i
] && *req
[i
]; i
++)
590 * Strip the first '!' if needed. If there's another, it's an
591 * rc. The syntax has already been checked before calling this
594 is_literal_element (&req
[i
]);
595 n
= find_element (node
, req
[i
], find_stop_node (node
));
598 * If the found element has the same parent as the current element,
599 * they are siblings and the new element needs to be created as a
600 * child of the current element (node).
602 if (n
&& n
->parent
== node
->parent
)
607 *rc
= create_new_element (node
, req
[i
], &node
);
618 /* The root element is really req[0]. It is need as a pointer in case there is
619 * a target attribute so it can be updated. */
621 find_root_element (xmlDocPtr doc
, char ***req
, gpg_error_t
* rc
,
622 int *target
, int recursion_depth
, int stop
)
624 xmlNodePtr n
= xmlDocGetRootElement (doc
);
626 char *root
= str_dup (*req
[0]);
627 int literal
= is_literal_element (&root
);
631 *rc
= GPG_ERR_ENOMEM
;
638 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
640 xmlChar
*t
= xmlGetNodePath (n
);
642 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
651 if (n
->type
== XML_ELEMENT_NODE
)
653 if (depth
== 0 && xmlStrEqual (n
->name
, (xmlChar
*) "pwmd"))
660 if (depth
== 1 && xmlStrEqual (n
->name
, (xmlChar
*) "element"))
662 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "_name");
667 if (xmlStrEqual (content
, (xmlChar
*) root
))
669 char **nreq
, **tmp
= NULL
;
679 content
= node_has_attribute (n
, (xmlChar
*) "target");
684 if (!content
|| stop
)
693 if (strchr ((char *) content
, '\t'))
695 nreq
= str_split ((char *) content
, "\t", 0);
704 *rc
= GPG_ERR_ENOMEM
;
710 tmp
= strv_catv (nreq
, tmp
+ 1);
716 *rc
= GPG_ERR_ENOMEM
;
725 if (strv_printf (&tmp
, "%s", content
) == 0)
729 *rc
= GPG_ERR_ENOMEM
;
735 nreq
= strv_catv (tmp
, nreq
+ 1);
740 *rc
= GPG_ERR_ENOMEM
;
751 find_root_element (doc
, req
, rc
, target
, recursion_depth
,
764 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
769 find_element (xmlNodePtr node
, char *element
, xmlNodePtr stop
)
773 if (!node
|| !element
)
776 for (n
= node
; n
; n
= n
->next
)
778 if (n
->type
!= XML_ELEMENT_NODE
)
784 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
786 if (a
&& xmlStrEqual (a
, (xmlChar
*) element
))
799 node_has_attribute (xmlNodePtr n
, xmlChar
* attr
)
801 xmlAttrPtr a
= xmlHasProp (n
, attr
);
806 if (!a
->children
|| !a
->children
->content
)
809 return xmlGetProp (n
, attr
);
813 element_to_literal (char **element
)
815 char *p
= str_asprintf ("!%s", *element
);
825 /* Resolves elements in 'req' one at a time. It's recursive in case of
826 * "target" attributes. */
828 find_elements (xmlDocPtr doc
, xmlNodePtr node
,
829 char **req
, gpg_error_t
* rc
, int *target
,
830 xmlNodePtr (*found_fn
) (xmlNodePtr
, char **, gpg_error_t
*,
832 xmlNodePtr (*not_found_fn
) (xmlNodePtr
, char **, gpg_error_t
*,
833 void *), int is_list_command
,
834 int recursion_depth
, void *data
, int stop
)
836 xmlNodePtr n
, last
, last_node
;
843 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
845 xmlChar
*t
= xmlGetNodePath (node
);
847 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
854 for (last_node
= last
= n
= node
, p
= req
; *p
; p
++)
862 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
869 *rc
= GPG_ERR_ENOMEM
;
873 literal
= is_literal_element (&t
);
874 n
= find_element (last
, t
, NULL
);
880 return not_found_fn (found
? last_node
: last_node
->parent
, p
, rc
,
883 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
893 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "target");
894 char **nreq
= NULL
, **nnreq
;
898 if (is_list_command
== 1)
900 if (element_to_literal (&(*p
)) == 0)
902 *rc
= GPG_ERR_ENOMEM
;
913 if (!*(p
+ 1) && stop
)
919 if (strchr ((char *) content
, '\t') != NULL
)
921 if ((nreq
= str_split ((char *) content
, "\t", 0)) == NULL
)
924 *rc
= GPG_ERR_INV_VALUE
;
930 if ((nreq
= str_split ((char *) content
, " ", 0)) == NULL
)
933 *rc
= GPG_ERR_INV_VALUE
;
939 tmp
= find_root_element (doc
, &nreq
, rc
, target
, 0, 0);
949 found_fn (tmp
, nreq
, rc
, p
+ 1, data
);
958 if (!*(nreq
+ 1) && !*(p
+ 1))
964 nnreq
= strv_catv (nreq
+ 1, p
+ 1);
968 if (!nnreq
|| !*nnreq
)
977 n
= find_elements (doc
, tmp
->children
, nnreq
, rc
, NULL
, found_fn
,
978 not_found_fn
, is_list_command
, recursion_depth
,
985 return not_found_fn (tmp
, p
+ 1, rc
, data
);
987 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
993 char **zz
= p
+ 1, **qq
= nnreq
;
995 if (strv_length (nnreq
) > strv_length (p
+ 1))
998 for (; *qq
&& *zz
; zz
++)
1001 *zz
= str_dup (*qq
++);
1005 *rc
= GPG_ERR_ENOMEM
;
1021 update_element_list (struct element_list_s
*elements
)
1026 if (!elements
|| !elements
->elements
)
1029 line
= strv_join ("\t", elements
->elements
);
1034 strv_free (elements
->elements
);
1035 elements
->elements
= NULL
;
1036 l
= slist_append (elements
->list
, line
);
1046 path_list_recurse (xmlDocPtr doc
, xmlNodePtr node
,
1047 struct element_list_s
*elements
)
1051 gpg_error_t error_flag
= 0;
1053 for (n
= node
; n
; n
= n
->next
)
1055 xmlChar
*target
= NULL
;
1056 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
1062 if (n
->type
!= XML_ELEMENT_NODE
)
1065 if (elements
->verbose
)
1068 (&elements
->elements
, "%s\t!%s%s", elements
->prefix
, a
,
1069 find_element_node (n
->children
) ? " +" : "") == 0)
1072 return GPG_ERR_ENOMEM
;
1076 if (strv_printf (&elements
->elements
, "%s\t!%s", elements
->prefix
, a
)
1080 return GPG_ERR_ENOMEM
;
1083 if (update_element_list (elements
) == 0)
1086 return GPG_ERR_ENOMEM
;
1089 target
= node_has_attribute (n
, (xmlChar
*) "target");
1094 char *save
= elements
->prefix
;
1095 int r
= elements
->resolving
;
1098 struct string_s
*realpath
= NULL
;
1100 tnode
= resolve_path (doc
, target
, &req
, &rc
);
1101 if (rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_ELEMENT_NOT_FOUND
)
1103 if (rc
== GPG_ERR_ELOOP
)
1105 xmlChar
*t
= xmlGetNodePath (n
);
1107 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
1111 if (elements
->verbose
)
1113 strv_printf (&elements
->elements
, "%s\t%s %s",
1114 elements
->prefix
, a
,
1115 rc
== GPG_ERR_ELOOP
? "O" : "E");
1116 error_flag
= err
= rc
;
1122 if (!elements
->verbose
&& rc
)
1129 if (elements
->with_target
)
1131 rc
= build_realpath (doc
, (char *) target
, &realpath
);
1139 realpath
= string_prepend (realpath
, "T ");
1142 if (elements
->verbose
)
1144 if (!strv_printf (&elements
->elements
, "%s\t%s%s%s%s",
1145 elements
->prefix
, a
,
1146 (tnode
&& find_element_node (tnode
->children
))
1147 || realpath
? " " : "", tnode
1148 && find_element_node (tnode
->children
) ? "+" :
1149 "", realpath
? realpath
->str
: ""))
1153 return GPG_ERR_ENOMEM
;
1158 (&elements
->elements
, "%s\t%s", elements
->prefix
, a
))
1162 return GPG_ERR_ENOMEM
;
1167 string_free (realpath
, 1);
1169 tmp
= strv_join ("\t", elements
->elements
);
1175 return GPG_ERR_ENOMEM
;
1178 if (update_element_list (elements
) == 0)
1183 return GPG_ERR_ENOMEM
;
1186 if (!err
&& elements
->recurse
)
1188 /* Prune element flags. */
1189 if (elements
->verbose
&& strchr (tmp
, ' '))
1193 for (p
= tmp
; *p
; p
++)
1203 elements
->prefix
= tmp
;
1204 elements
->resolving
= 1;
1205 rc
= create_path_list (doc
, elements
, (char *) target
);
1206 elements
->resolving
= r
;
1207 elements
->prefix
= save
;
1209 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELOOP
)
1217 error_flag
= err
= rc
;
1226 if (n
->children
&& elements
->recurse
&& err
!= GPG_ERR_ELOOP
)
1228 char *tmp
= str_asprintf ("%s\t!%s", elements
->prefix
, a
);
1229 char *save
= elements
->prefix
;
1234 return GPG_ERR_ENOMEM
;
1237 elements
->prefix
= tmp
;
1238 rc
= path_list_recurse (doc
, n
->children
, elements
);
1239 xfree (elements
->prefix
);
1240 elements
->prefix
= save
;
1252 return error_flag
== GPG_ERR_ELOOP
? error_flag
: rc
;
1256 add_attribute (xmlNodePtr node
, const char *name
, const char *value
)
1261 if (name
&& !xmlSetProp (node
, (xmlChar
*) name
, (xmlChar
*) value
))
1262 return GPG_ERR_BAD_DATA
;
1264 if (name
&& xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_mtime"))
1267 buf
= str_asprintf ("%li", time (NULL
));
1268 rc
= add_attribute (node
, "_mtime", buf
);
1274 * From the element path 'path', find sub-nodes and append them to the list.
1277 create_path_list (xmlDocPtr doc
, struct element_list_s
* elements
, char *path
)
1280 char **req
, **req_orig
;
1284 req
= str_split (path
, "\t", 0);
1287 req
= str_split (path
, " ", 0);
1289 return GPG_ERR_SYNTAX
;
1292 req_orig
= strv_dup (req
);
1295 rc
= GPG_ERR_ENOMEM
;
1299 n
= find_root_element (doc
, &req
, &rc
, &a_target
, 0, 0);
1300 if ((rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
)
1301 && elements
->verbose
&& a_target
)
1307 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1318 *req
= str_dup (*req_orig
);
1326 find_elements (doc
, n
->children
, req
+ 1, &rc
, &e_target
, NULL
, NULL
,
1329 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1339 if (!elements
->prefix
)
1344 * If any req_orig element contains no target the element should be
1345 * prefixed with the literal character. Not really crucial if the
1346 * client isn't human because child elements are prefixed for the
1347 * current path. But may be confusing if editing by hand.
1349 elements
->prefix
= strv_join ("\t", req_orig
);
1351 if (!elements
->prefix
)
1353 rc
= GPG_ERR_ENOMEM
;
1357 if (elements
->verbose
)
1360 struct string_s
*realpath
= NULL
;
1362 if (a_target
&& elements
->with_target
)
1364 rc
= build_realpath (doc
, path
, &realpath
);
1368 realpath
= string_prepend (realpath
, "T ");
1371 ret
= strv_printf (&elements
->elements
, "%s%s%s%s",
1373 find_element_node (n
->children
)
1374 || realpath
? " " : "",
1375 find_element_node (n
->children
) ? "+" : "",
1376 realpath
? realpath
->str
: "");
1377 string_free (realpath
, 1);
1380 rc
= GPG_ERR_ENOMEM
;
1384 else if (strv_printf (&elements
->elements
, "%s", elements
->prefix
) == 0)
1386 rc
= GPG_ERR_ENOMEM
;
1390 if (update_element_list (elements
) == 0)
1392 rc
= GPG_ERR_ENOMEM
;
1397 rc
= path_list_recurse (doc
, n
->children
, elements
);
1401 strv_free (req_orig
);
1408 recurse_xpath_nodeset (xmlDocPtr doc
, xmlNodeSetPtr nodes
,
1409 xmlChar
* value
, xmlBufferPtr
* result
, int cmd
,
1410 const xmlChar
* attr
)
1412 int i
= value
? nodes
->nodeNr
- 1 : 0;
1415 buf
= xmlBufferCreate ();
1418 return GPG_ERR_ENOMEM
;
1420 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++)
1422 xmlNodePtr n
= nodes
->nodeTab
[i
];
1428 if (!value
&& !attr
)
1430 if (xmlNodeDump (buf
, doc
, n
, 0, 0) == -1)
1433 return GPG_ERR_BAD_DATA
;
1441 xmlNodeSetContent (n
, value
);
1442 rc
= update_element_mtime (n
);
1450 rc
= add_attribute (n
, (char *) attr
, (char *) value
);
1452 rc
= delete_attribute (n
, attr
);
1464 convert_root_element (xmlNodePtr n
)
1466 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1472 xmlChar
*t
= xmlGetNodePath (n
);
1475 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1478 return GPG_ERR_AMBIGUOUS_NAME
;
1481 a
= xmlGetProp (n
, (xmlChar
*) "name");
1485 rc
= add_attribute (n
, "_name", (char *) a
);
1491 rc
= delete_attribute (n
, (xmlChar
*) "name");
1496 xmlNodeSetName (n
, (xmlChar
*) "element");
1503 delete_attribute (xmlNodePtr n
, const xmlChar
* name
)
1507 if ((a
= xmlHasProp (n
, name
)) == NULL
)
1508 return GPG_ERR_NOT_FOUND
;
1510 if (xmlRemoveProp (a
) == -1)
1511 return GPG_ERR_BAD_DATA
;
1513 return update_element_mtime (n
);
1517 convert_elements_recurse (xmlDocPtr doc
, xmlNodePtr n
, unsigned depth
)
1523 for (n
= n
->children
; n
; n
= n
->next
)
1525 if (n
->type
== XML_ELEMENT_NODE
)
1531 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1533 xmlChar
*t
= xmlGetNodePath (n
);
1536 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1539 return GPG_ERR_AMBIGUOUS_NAME
;
1542 a
= xmlGetProp (n
, (xmlChar
*) "_name");
1547 xmlChar
*t
= xmlGetNodePath (n
);
1550 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1553 return GPG_ERR_AMBIGUOUS_NAME
;
1556 xmlChar
*tmp
= xmlStrdup (n
->name
);
1559 return GPG_ERR_ENOMEM
;
1561 xmlNodeSetName (n
, (xmlChar
*) "element");
1562 rc
= add_attribute (n
, "_name", (char *) tmp
);
1570 rc
= convert_root_element (n
);
1579 rc
= convert_elements_recurse (doc
, n
, depth
);
1589 /* Renames ALL elements to the new "element" name. Existing element names are
1590 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1591 * elements can contain common characters that the XML parser barfs on (an
1592 * email address for example. */
1594 convert_pre_212_elements (xmlDocPtr doc
)
1596 xmlNodePtr n
= xmlDocGetRootElement (doc
);
1598 log_write (_("Converting pre 2.12 data file..."));
1599 return convert_elements_recurse (doc
, n
, 0);
1603 validate_import (xmlNodePtr node
)
1610 for (xmlNodePtr n
= node
; n
; n
= n
->next
)
1612 if (n
->type
== XML_ELEMENT_NODE
)
1614 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1616 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1620 xmlChar
*t
= xmlGetNodePath (n
);
1622 log_write (_("Missing attribute '_name' at %s."), t
);
1624 return GPG_ERR_INV_VALUE
;
1627 if (!valid_xml_element (a
))
1629 xmlChar
*t
= xmlGetNodePath (n
);
1631 log_write (_("'%s' is not a valid element name at %s."), a
,
1635 return GPG_ERR_INV_VALUE
;
1639 a
= xmlGetProp (n
, (xmlChar
*) "_ctime");
1644 a
= xmlGetProp (n
, (xmlChar
*) "_mtime");
1646 update_element_mtime (n
);
1651 xmlChar
*t
= xmlGetNodePath (n
);
1653 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1662 rc
= validate_import (n
->children
);
1673 update_element_mtime (xmlNodePtr n
)
1675 return add_attribute (n
, NULL
, NULL
);
1679 unlink_node (xmlNodePtr n
)
1687 rc
= update_element_mtime (n
->parent
);
1694 parse_doc (const char *xml
, size_t len
, xmlDocPtr
*result
)
1698 xmlResetLastError ();
1699 doc
= xmlReadMemory (xml
, len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
1700 if (!doc
&& xmlGetLastError ())
1701 return GPG_ERR_BAD_DATA
;
1704 return !doc
? GPG_ERR_ENOMEM
: 0;
1708 realpath_elements_cb (xmlNodePtr node
, char **target
,
1709 gpg_error_t
* rc
, char **req_orig
, void *data
)
1711 char *path
= *(char **) data
;
1712 char *tmp
= NULL
, *result
;
1717 *(char **) data
= NULL
;
1720 path
= strv_join ("\t", target
);
1724 *rc
= GPG_ERR_ENOMEM
;
1730 tmp
= strv_join ("\t", req_orig
);
1735 *rc
= GPG_ERR_ENOMEM
;
1741 result
= str_asprintf ("%s\t%s", path
, tmp
);
1743 result
= str_dup (path
);
1747 *rc
= GPG_ERR_ENOMEM
;
1755 *(char **) data
= result
;
1760 build_realpath (xmlDocPtr doc
, char *line
, struct string_s
** result
)
1767 struct string_s
*string
;
1770 if (strchr (line
, '\t') != NULL
)
1772 if ((req
= str_split (line
, "\t", 0)) == NULL
)
1773 return GPG_ERR_SYNTAX
;
1777 if ((req
= str_split (line
, " ", 0)) == NULL
)
1778 return GPG_ERR_SYNTAX
;
1781 n
= find_root_element (doc
, &req
, &rc
, NULL
, 0, 0);
1788 rp
= strv_join ("\t", req
);
1792 return GPG_ERR_ENOMEM
;
1797 n
= find_elements (doc
, n
->children
, req
+ 1, &rc
,
1798 NULL
, realpath_elements_cb
, NULL
, 0, 0, &rp
, 0);
1807 string
= string_new (rp
);
1811 return GPG_ERR_ENOMEM
;
1814 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++)
1816 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+ 1) && *(t
+ 1) != '!'))
1818 struct string_s
*s
= string_insert_c (string
, !i
? i
++ : ++i
, '!');
1822 string_free (string
, 1);
1823 return GPG_ERR_ENOMEM
;
1837 node_to_element_path (xmlNodePtr node
)
1840 struct string_s
*str
= string_new ("");
1843 for (n
= node
; n
; n
= n
->parent
)
1847 for (child
= n
; child
; child
= child
->next
)
1849 if (child
->type
!= XML_ELEMENT_NODE
)
1852 xmlChar
*name
= node_has_attribute (n
, (xmlChar
*) "_name");
1855 str
= string_prepend (str
, (char *) name
);
1857 name
= node_has_attribute (n
, (xmlChar
*) "target");
1859 str
= string_prepend (str
, "\t");
1861 str
= string_prepend (str
, "\t!");
1868 str
= string_erase (str
, 0, 1);
1870 string_free (str
, 0);
1876 * Recurse the element tree beginning at 'node' and find elements who point
1877 * back to 'src' or 'dst'. Also follows target attributes.
1880 find_child_to_target (xmlDocPtr doc
, xmlNodePtr node
,
1881 xmlNodePtr src
, xmlNodePtr dst
, unsigned depth
,
1887 if (max_recursion_depth
>= 1 && depth
> max_recursion_depth
)
1888 return gpg_error (GPG_ERR_ELOOP
);
1890 for (n
= node
; n
; n
= n
->next
)
1894 if (n
->type
!= XML_ELEMENT_NODE
)
1897 if (n
== src
|| n
== dst
)
1898 return GPG_ERR_ELOOP
;
1900 target
= node_has_attribute (n
, (xmlChar
*) "target");
1904 char **result
= NULL
;
1906 tmp
= resolve_path (doc
, target
, &result
, &rc
);
1911 rc
= find_child_to_target (doc
, tmp
, src
, dst
, ++depth
, 1);
1915 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELEMENT_NOT_FOUND
)
1926 rc
= find_child_to_target (doc
, n
->children
, src
, dst
, ++depth
,0);
1940 find_child_of_parent (xmlDocPtr doc
, xmlNodePtr src
, xmlNodePtr dst
)
1945 for (n
= src
; n
; n
= n
->next
)
1947 if (n
->type
!= XML_ELEMENT_NODE
)
1956 rc
= find_child_of_parent (doc
, n
->children
, dst
);
1963 find_parent_of_child (xmlDocPtr doc
, xmlNodePtr node
, xmlNodePtr dst
)
1968 for (n
= node
; n
; n
= n
->parent
)
1970 if (n
->type
!= XML_ELEMENT_NODE
)
1974 for (tmp
= n
->next
; tmp
; n
= n
->next
)
1976 if (n
->type
!= XML_ELEMENT_NODE
)
1980 return GPG_ERR_ELOOP
;
1985 return GPG_ERR_ELOOP
;
1992 validate_target_attribute (xmlDocPtr doc
, const char *src
,
1993 xmlNodePtr dst_node
)
1996 xmlNodePtr src_node
;
1997 char **src_req
= NULL
;
1999 src_node
= resolve_path (doc
, (xmlChar
*) src
, &src_req
, &rc
);
2003 /* A destination element is a child of the source element. */
2004 rc
= find_child_of_parent (doc
, src_node
->children
, dst_node
);
2008 /* The destination element is a parent of the source element. */
2009 rc
= find_parent_of_child (doc
, src_node
->parent
, dst_node
);
2013 /* A destination child element contains a target to the source element. */
2014 rc
= find_child_to_target (doc
, dst_node
->children
, src_node
, dst_node
, 0, 0);
2019 strv_free (src_req
);