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 extern void log_write (const char *fmt
, ...);
53 * 'element' must be allocated.
56 is_literal_element (char **element
)
60 if (!element
|| !*element
)
63 if (*(*element
) == '!')
67 for (p
= *element
, c
= p
+ 1; *c
; c
++)
78 valid_xml_attribute_value (const char *str
)
95 valid_xml_attribute (const char *str
)
99 int ret
= valid_xml_element ((xmlChar
*)str
);
104 wc
= str_to_wchar ((const char *)str
);
109 for (c
= 0; c
< len
; c
++)
117 case 0x0300 ... 0x036F:
118 case 0x203F ... 0x2040:
126 case 'A' ... 'Z': break;
127 case 'a' ... 'z': break;
128 case 0xC0 ... 0xD6: break;
129 case 0xD8 ... 0xF6: break;
130 case 0xF8 ... 0x2FF: break;
131 case 0x370 ... 0x37D: break;
132 case 0x37F ... 0x1FFF: break;
133 case 0x200C ... 0x200D: break;
134 case 0x2070 ... 0x218F: break;
135 case 0x2C00 ... 0x2FEF: break;
136 case 0x3001 ... 0xD7FF: break;
137 case 0xF900 ... 0xFDCF: break;
138 case 0xFDF0 ... 0xFFFD: break;
139 case 0x10000 ... 0xEFFFF: break;
151 valid_xml_element (xmlChar
*str
)
156 if (!str
|| !*str
|| *str
== '!')
159 wc
= str_to_wchar ((const char *)str
);
164 for (c
= 0; c
< len
; c
++)
178 valid_element_path (char **path
, int with_content
)
180 char **dup
= NULL
, **p
;
185 /* Save some memory by not duplicating the element content. */
188 int i
, t
= strv_length (path
);
190 for (i
= 0; i
< t
- 1; i
++)
192 char **tmp
= xrealloc (dup
, (i
+ 2) * sizeof (char *));
201 dup
[i
] = str_dup (path
[i
]);
206 dup
= strv_dup (path
);
211 for (p
= dup
; *p
&& *(*p
); p
++)
213 is_literal_element (&(*p
));
214 if (!valid_xml_element ((xmlChar
*) * p
))
226 attr_ctime (struct client_s
*client
, xmlNodePtr n
)
228 char *buf
= str_asprintf ("%li", time (NULL
));
232 return GPG_ERR_ENOMEM
;
234 rc
= add_attribute (client
, n
, "_ctime", buf
);
240 acl_check (struct client_s
*client
, xmlNodePtr n
)
242 gpg_error_t rc
= GPG_ERR_EACCES
;
243 xmlChar
*acl
= node_has_attribute (n
, (xmlChar
*) "_acl");
244 char **users
= acl
? str_split((char *)acl
, ",", 0) : NULL
;
248 if (!acl
|| !*acl
|| !users
|| !*users
)
252 return peer_is_invoker(client
);
255 if (!peer_is_invoker(client
))
262 for (p
= users
; p
&& *p
; p
++)
265 rc
= acl_check_common (client
, *p
,
266 client
->thd
->remote
? 0 : client
->thd
->peer
->uid
,
267 client
->thd
->remote
? 0 : client
->thd
->peer
->gid
,
270 rc
= acl_check_common (client
, *p
, client
->thd
->peer
->uid
,
271 client
->thd
->peer
->gid
, &allowed
);
278 // ATTR LIST makes use of FLAG_ACL_IGNORE to allow listing of element
279 // attributes that the client is not normally allowed access to.
280 if ((rc
== GPG_ERR_EACCES
|| !allowed
) && client
->flags
& FLAG_ACL_IGNORE
)
283 client
->flags
&= ~FLAG_ACL_IGNORE
;
285 // This flag is used in ATTR LIST to prevent listing attributes of
286 // children whose parent ACL does not allow access to the client.
287 client
->flags
|= FLAG_ACL_ERROR
;
294 return allowed
? 0 : GPG_ERR_EACCES
;
298 create_acl_user (struct client_s
*client
)
301 if (client
->thd
->remote
)
302 return str_asprintf ("#%s", client
->thd
->tls
->fp
);
305 return get_username (client
->thd
->peer
->uid
);
309 create_new_element (struct client_s
*client
, int verify
, xmlNodePtr parent
,
310 const char *name
, xmlNodePtr
* result
)
315 // Allow any client to create a non-existing root element.
316 if (parent
->parent
->type
!= XML_DOCUMENT_NODE
)
318 rc
= acl_check(client
, parent
);
323 n
= xmlNewNode (NULL
, (xmlChar
*) "element");
325 return GPG_ERR_ENOMEM
;
327 rc
= add_attribute (client
, n
, "_name", name
);
329 rc
= attr_ctime (client
, n
);
331 if (!rc
&& verify
&& parent
->parent
->type
!= XML_DOCUMENT_NODE
)
332 rc
= is_element_owner (client
, parent
);
336 xmlNodePtr p
= xmlAddChild (parent
, n
);
337 char *user
= create_acl_user (client
);
342 rc
= add_attribute(client
, p
, "_acl", user
);
352 new_root_element (struct client_s
*client
, xmlDocPtr doc
, char *name
)
354 xmlNodePtr root
= xmlDocGetRootElement (doc
);
358 return GPG_ERR_BAD_DATA
;
363 if (!valid_xml_element ((xmlChar
*) p
))
364 return GPG_ERR_INV_VALUE
;
366 return create_new_element (client
, 0, root
, p
, NULL
);
373 xmlTextWriterPtr wr
= xmlNewTextWriterDoc (&doc
, 0);
378 if (xmlTextWriterStartDocument (wr
, NULL
, "UTF-8", "yes"))
381 if (xmlTextWriterStartDTD (wr
, (xmlChar
*) "pwmd", NULL
, NULL
) == -1)
384 if (xmlTextWriterWriteDTDElement (wr
, (xmlChar
*) "pwmd",
385 (xmlChar
*) "(element)") == -1)
388 xmlTextWriterEndDTDElement (wr
);
390 if (xmlTextWriterWriteDTDAttlist (wr
, (xmlChar
*) "element",
391 (xmlChar
*) "_name CDATA #REQUIRED") ==
395 xmlTextWriterEndDTDAttlist (wr
);
396 xmlTextWriterEndDTD (wr
);
398 if (xmlTextWriterStartElement (wr
, (xmlChar
*) "pwmd"))
401 xmlTextWriterEndElement (wr
);
402 xmlTextWriterEndDocument (wr
);
403 xmlFreeTextWriter (wr
);
407 xmlTextWriterEndDocument (wr
);
408 xmlFreeTextWriter (wr
);
416 return create_dtd ();
420 find_element_node (xmlNodePtr node
)
424 if (n
&& n
->type
== XML_ELEMENT_NODE
)
427 for (n
= node
; n
; n
= n
->next
)
429 if (n
->type
== XML_ELEMENT_NODE
)
437 resolve_path (struct client_s
*client
, xmlDocPtr doc
, xmlChar
* path
,
438 char ***result
, gpg_error_t
* rc
)
443 req
= str_split ((char *) path
, "\t", 0);
446 *rc
= GPG_ERR_ENOMEM
;
450 n
= find_root_element (client
, doc
, &req
, rc
, NULL
, 0, 0);
458 n
= find_elements (client
, doc
, n
->children
, req
+ 1, rc
, NULL
, NULL
, NULL
,
470 * Lists root element names; the value of the attribute "_name" of an element
471 * "element". If there's a target attribute both literal and non-literal
472 * element names will be added. This is the primary reason why XML entities
473 * cannot be used. There wouldn't be a way to get the literal an non-literal
477 list_root_elements (struct client_s
*client
, xmlDocPtr doc
,
478 struct string_s
** result
, int verbose
, int with_target
)
481 struct slist_s
*list
= NULL
;
483 struct string_s
*string
;
486 n
= xmlDocGetRootElement (doc
);
487 if (!n
|| !n
->children
)
488 return GPG_ERR_NO_DATA
;
490 for (n
= n
->children
; n
; n
= n
->next
)
493 xmlChar
*val
, *target
;
494 struct slist_s
*tlist
;
497 if (n
->type
!= XML_ELEMENT_NODE
)
500 a
= xmlHasProp (n
, (xmlChar
*) "_name");
501 if (!a
|| !a
->children
->content
)
504 val
= xmlNodeGetContent (a
->children
);
511 tmp
= str_asprintf ("!%s%s", (char *) val
,
512 verbose
? find_element_node (n
->children
) ? " +"
522 tlist
= slist_append (list
, tmp
);
531 target
= node_has_attribute (n
, (xmlChar
*) "target");
539 xmlNodePtr tnode
= resolve_path (client
, doc
, target
, &req
, &rc
);
541 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
542 || rc
== GPG_ERR_EACCES
)
544 t
= str_asprintf ("%s %s%s%s", (char *) val
,
545 rc
== GPG_ERR_ELOOP
? "O" :
546 rc
== GPG_ERR_EACCES
? "P" : "E",
547 with_target
? "T " : "",
548 with_target
? (char *)target
: "");
553 struct string_s
*realpath
= NULL
;
557 rc
= build_realpath (client
, doc
, (char *) target
,
567 realpath
= string_prepend (realpath
, "T ");
570 t
= str_asprintf ("%s%s%s%s", (char *) val
,
572 && find_element_node (tnode
->children
))
573 || realpath
? " " : "", tnode
574 && find_element_node (tnode
->children
) ?
575 "+" : "", realpath
? realpath
->str
: "");
578 string_free (realpath
, 1);
585 t
= str_dup ((char *) val
);
591 rc
= rc
? rc
: GPG_ERR_ENOMEM
;
595 tlist
= slist_append (list
, t
);
612 total
= slist_length (list
);
614 return GPG_ERR_NO_DATA
;
616 string
= string_new (NULL
);
623 for (i
= 0; i
< total
; i
++)
625 char *val
= slist_nth_data (list
, i
);
627 string_append_printf (string
, "%s\n", val
);
630 string
= string_truncate (string
, string
->len
- 1);
634 total
= slist_length (list
);
635 for (i
= 0; i
< total
; i
++)
636 xfree (slist_nth_data (list
, i
));
643 * Prevents a sibling element past the current element path with the same
647 find_stop_node (xmlNodePtr node
)
651 for (n
= node
->parent
->children
; n
; n
= n
->next
)
661 create_target_elements_cb (struct client_s
*client
, int verify
,
662 xmlNodePtr node
, char **path
, gpg_error_t
*rc
,
667 xmlNodePtr parent
= data
;
669 for (i
= 0; req
[i
] && *req
[i
]; i
++)
673 if (parent
&& node
== parent
)
675 *rc
= GPG_ERR_CONFLICT
;
679 is_literal_element (&req
[i
]);
681 if ((n
= find_element (client
, node
, req
[i
],
682 find_stop_node (node
), rc
)) == NULL
||
683 (n
&& n
->parent
== node
->parent
))
687 *rc
= create_new_element (client
, verify
, node
, req
[i
], &node
);
700 find_text_node (xmlNodePtr node
)
704 if (n
&& n
->type
== XML_TEXT_NODE
)
707 for (n
= node
; n
; n
= n
->next
)
709 if (n
->type
== XML_TEXT_NODE
)
717 create_elements_cb (struct client_s
*client
, int verify
, xmlNodePtr node
,
718 char **elements
, gpg_error_t
* rc
, void *data
)
721 char **req
= elements
;
723 if (*rc
&& *rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
726 if (node
->type
== XML_TEXT_NODE
)
729 for (i
= 0; req
[i
] && *req
[i
]; i
++)
734 * Strip the first '!' if needed. If there's another, it's an
735 * rc. The syntax has already been checked before calling this
738 is_literal_element (&req
[i
]);
739 n
= find_element (client
, node
, req
[i
], find_stop_node (node
), rc
);
744 * If the found element has the same parent as the current element,
745 * they are siblings and the new element needs to be created as a
746 * child of the current element (node).
748 if (n
&& n
->parent
== node
->parent
)
753 *rc
= create_new_element (client
, 0, node
, req
[i
], &node
);
764 /* The root element is really req[0]. It is need as a pointer in case there is
765 * a target attribute so it can be updated. */
767 find_root_element (struct client_s
*client
, xmlDocPtr doc
, char ***req
,
768 gpg_error_t
* rc
, int *target
, int recursion_depth
,
771 xmlNodePtr n
= xmlDocGetRootElement (doc
);
773 char *root
= str_dup (*req
[0]);
774 int literal
= is_literal_element (&root
);
778 *rc
= GPG_ERR_ENOMEM
;
785 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
787 xmlChar
*t
= xmlGetNodePath (n
);
789 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
798 if (n
->type
== XML_ELEMENT_NODE
)
800 if (depth
== 0 && xmlStrEqual (n
->name
, (xmlChar
*) "pwmd"))
807 if (depth
== 1 && xmlStrEqual (n
->name
, (xmlChar
*) "element"))
809 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "_name");
814 if (xmlStrEqual (content
, (xmlChar
*) root
))
816 char **nreq
, **tmp
= NULL
;
817 int acl
= client
->flags
& FLAG_ACL_IGNORE
;
819 *rc
= acl_check(client
, n
);
820 if ((*rc
&& *rc
!= GPG_ERR_EACCES
)
821 || (*rc
== GPG_ERR_EACCES
&& !acl
))
831 // This flag is cleared in acl_check() but we always
832 // allow ATTR LIST of root elements.
833 client
->flags
|= FLAG_ACL_IGNORE
;
844 content
= node_has_attribute (n
, (xmlChar
*) "target");
846 if (content
&& target
)
849 if (!content
|| stop
)
858 if (strchr ((char *) content
, '\t'))
860 nreq
= str_split ((char *) content
, "\t", 0);
869 *rc
= GPG_ERR_ENOMEM
;
875 tmp
= strv_catv (nreq
, tmp
+ 1);
881 *rc
= GPG_ERR_ENOMEM
;
890 if (strv_printf (&tmp
, "%s", content
) == 0)
894 *rc
= GPG_ERR_ENOMEM
;
900 nreq
= strv_catv (tmp
, nreq
+ 1);
905 *rc
= GPG_ERR_ENOMEM
;
915 return find_root_element (client
, doc
, req
, rc
, target
,
927 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
932 find_element (struct client_s
*client
, xmlNodePtr node
, char *element
,
933 xmlNodePtr stop
, gpg_error_t
*rc
)
939 if (!node
|| !element
)
942 for (n
= node
; n
; n
= n
->next
)
944 if (n
->type
!= XML_ELEMENT_NODE
)
950 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
952 if (a
&& xmlStrEqual (a
, (xmlChar
*) element
))
956 // Prevent ATTR LIST showing child element attributes for a parent
957 // whos ACL denies the client.
958 if (client
->flags
& FLAG_ACL_ERROR
)
960 *rc
= GPG_ERR_EACCES
;
964 *rc
= acl_check(client
, n
);
978 node_has_attribute (xmlNodePtr n
, xmlChar
* attr
)
980 xmlAttrPtr a
= xmlHasProp (n
, attr
);
985 if (!a
->children
|| !a
->children
->content
)
988 return xmlGetProp (n
, attr
);
992 element_to_literal (char **element
)
994 char *p
= str_asprintf ("!%s", *element
);
1004 /* Resolves elements in 'req' one at a time. It's recursive in case of
1005 * "target" attributes. */
1007 find_elements (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
1008 char **req
, gpg_error_t
* rc
, int *target
,
1009 xmlNodePtr (*found_fn
) (struct client_s
*, xmlNodePtr
, char **,
1010 gpg_error_t
*, char **, void *),
1011 xmlNodePtr (*not_found_fn
) (struct client_s
*, int, xmlNodePtr
,
1012 char **, gpg_error_t
*, void *),
1013 int is_list_command
, int recursion_depth
, void *data
, int stop
)
1015 xmlNodePtr n
, last
, last_node
;
1022 if (max_recursion_depth
>= 1 && recursion_depth
> max_recursion_depth
)
1024 xmlChar
*t
= xmlGetNodePath (node
);
1026 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
1029 *rc
= GPG_ERR_ELOOP
;
1033 for (last_node
= last
= n
= node
, p
= req
; *p
; p
++)
1041 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
1048 *rc
= GPG_ERR_ENOMEM
;
1052 literal
= is_literal_element (&t
);
1053 n
= find_element (client
, last
, t
, NULL
, rc
);
1058 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
1060 /* Fixes ATTR LIST when an element does not exist and the parent
1061 * denies access to children. Fixes leaking information about the
1062 * current elements children. */
1063 if (*rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& last_node
!= n
)
1065 gpg_error_t trc
= acl_check (client
, last_node
);
1071 return not_found_fn (client
, 0,
1072 found
? last_node
: last_node
->parent
, p
,
1083 xmlChar
*content
= node_has_attribute (n
, (xmlChar
*) "target");
1084 char **nreq
= NULL
, **nnreq
;
1088 if (is_list_command
== 1)
1090 if (element_to_literal (&(*p
)) == 0)
1092 *rc
= GPG_ERR_ENOMEM
;
1103 if (!*(p
+ 1) && stop
)
1109 if (strchr ((char *) content
, '\t') != NULL
)
1111 if ((nreq
= str_split ((char *) content
, "\t", 0)) == NULL
)
1114 *rc
= GPG_ERR_INV_VALUE
;
1120 if ((nreq
= str_split ((char *) content
, " ", 0)) == NULL
)
1123 *rc
= GPG_ERR_INV_VALUE
;
1129 tmp
= find_root_element (client
, doc
, &nreq
, rc
, target
, 0, 0);
1133 if (not_found_fn
&& *rc
== GPG_ERR_EACCES
)
1134 return not_found_fn (client
, 0, NULL
, p
, rc
, data
);
1140 found_fn (client
, tmp
, nreq
, rc
, p
+ 1, data
);
1149 if (!*(nreq
+ 1) && !*(p
+ 1))
1155 nnreq
= strv_catv (nreq
+ 1, p
+ 1);
1159 if (!nnreq
|| !*nnreq
)
1167 n
= find_elements (client
, doc
, tmp
->children
, nnreq
, rc
, NULL
,
1168 found_fn
, not_found_fn
, is_list_command
,
1169 recursion_depth
, data
, stop
);
1180 return not_found_fn (client
, 0, tmp
, p
, rc
, data
);
1182 *rc
= GPG_ERR_ELEMENT_NOT_FOUND
;
1188 char **zz
= p
+ 1, **qq
= nnreq
;
1190 if (strv_length (nnreq
) > strv_length (p
+ 1))
1193 for (; *qq
&& *zz
; zz
++)
1196 *zz
= str_dup (*qq
++);
1200 *rc
= GPG_ERR_ENOMEM
;
1216 update_element_list (struct element_list_s
*elements
)
1221 if (!elements
|| !elements
->elements
)
1224 line
= strv_join ("\t", elements
->elements
);
1229 strv_free (elements
->elements
);
1230 elements
->elements
= NULL
;
1231 l
= slist_append (elements
->list
, line
);
1241 path_list_recurse (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
1242 struct element_list_s
*elements
)
1246 gpg_error_t error_flag
= 0;
1248 for (n
= node
; n
; n
= n
->next
)
1250 xmlChar
*target
= NULL
;
1251 xmlChar
*a
= node_has_attribute (n
, (xmlChar
*) "_name");
1252 gpg_error_t err
= 0;
1259 if (n
->type
!= XML_ELEMENT_NODE
)
1262 rc
= acl_check(client
, n
);
1264 if (elements
->verbose
)
1267 (&elements
->elements
, "%s\t!%s%s%s", elements
->prefix
, a
,
1268 !rc
&& find_element_node (n
->children
) ? " +" : "",
1269 rc
== GPG_ERR_EACCES
? " P" : rc
? " E" : "") == 0)
1272 return GPG_ERR_ENOMEM
;
1276 if (strv_printf (&elements
->elements
, "%s\t!%s", elements
->prefix
, a
)
1280 return GPG_ERR_ENOMEM
;
1283 if (update_element_list (elements
) == 0)
1286 return GPG_ERR_ENOMEM
;
1289 if (rc
== GPG_ERR_EACCES
)
1301 target
= node_has_attribute (n
, (xmlChar
*) "target");
1305 char *save
= elements
->prefix
;
1306 int r
= elements
->resolving
;
1309 struct string_s
*realpath
= NULL
;
1311 tnode
= resolve_path (client
, doc
, target
, &req
, &rc
);
1312 if (rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_ELEMENT_NOT_FOUND
1313 || rc
== GPG_ERR_EACCES
)
1315 if (rc
== GPG_ERR_ELOOP
)
1317 xmlChar
*t
= xmlGetNodePath (n
);
1319 log_write ("%s: %s", pwmd_strerror (GPG_ERR_ELOOP
), t
);
1323 if (elements
->verbose
)
1325 error_flag
= err
= rc
;
1329 else if (!elements
->verbose
&& rc
)
1336 path
= str_asprintf("%s\t%s", elements
->prefix
, a
);
1337 rc
= validate_target_attribute (client
, client
->doc
, path
, tnode
);
1339 if (rc
== GPG_ERR_ELOOP
|| rc
== GPG_ERR_EACCES
1340 || rc
== GPG_ERR_ELEMENT_NOT_FOUND
)
1342 if (rc
!= GPG_ERR_ELEMENT_NOT_FOUND
)
1343 error_flag
= err
= rc
;
1356 strv_printf (&elements
->elements
, "%s\t%s %s%s%s",
1357 elements
->prefix
, a
,
1358 err
== GPG_ERR_ELOOP
? "O" :
1359 err
== GPG_ERR_EACCES
? "P" : "E",
1360 elements
->with_target
? "T " : "",
1361 elements
->with_target
? (char *)target
: "");
1363 else if (!err
&& elements
->with_target
)
1365 rc
= build_realpath (client
, doc
, (char *) target
, &realpath
);
1373 realpath
= string_prepend (realpath
, "T ");
1376 if (!err
&& elements
->verbose
)
1378 if (!strv_printf (&elements
->elements
, "%s\t%s%s%s%s",
1379 elements
->prefix
, a
,
1380 (tnode
&& find_element_node (tnode
->children
))
1381 || realpath
? " " : "", tnode
1382 && find_element_node (tnode
->children
) ? "+" :
1383 "", realpath
? realpath
->str
: ""))
1387 return GPG_ERR_ENOMEM
;
1392 (&elements
->elements
, "%s\t%s", elements
->prefix
, a
))
1396 return GPG_ERR_ENOMEM
;
1400 string_free (realpath
, 1);
1402 tmp
= strv_join ("\t", elements
->elements
);
1407 return GPG_ERR_ENOMEM
;
1410 if (update_element_list (elements
) == 0)
1415 return GPG_ERR_ENOMEM
;
1418 if (!err
&& elements
->recurse
)
1420 /* Prune element flags. */
1421 if (elements
->verbose
&& strchr (tmp
, ' '))
1425 for (p
= tmp
; *p
; p
++)
1435 elements
->prefix
= tmp
;
1436 elements
->resolving
= 1;
1437 rc
= create_path_list (client
, doc
, elements
, (char *) target
);
1438 elements
->resolving
= r
;
1439 elements
->prefix
= save
;
1441 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELOOP
1442 && gpg_err_code(rc
) != GPG_ERR_EACCES
)
1450 error_flag
= err
= rc
;
1459 if (n
->children
&& elements
->recurse
)
1461 char *tmp
= str_asprintf ("%s\t!%s", elements
->prefix
, a
);
1462 char *save
= elements
->prefix
;
1467 return GPG_ERR_ENOMEM
;
1470 elements
->prefix
= tmp
;
1471 rc
= path_list_recurse (client
, doc
, n
->children
, elements
);
1472 xfree (elements
->prefix
);
1473 elements
->prefix
= save
;
1477 if (gpg_err_code(rc
) == GPG_ERR_ELOOP
1478 || gpg_err_code (rc
) == GPG_ERR_EACCES
1479 || gpg_err_code (rc
) == GPG_ERR_ELEMENT_NOT_FOUND
)
1481 error_flag
= err
= rc
;
1495 return error_flag
== GPG_ERR_ELOOP
|| error_flag
== GPG_ERR_EACCES
1500 add_attribute (struct client_s
*client
, xmlNodePtr node
, const char *name
,
1506 if (client
&& name
&& !strcmp (name
, "target"))
1508 rc
= is_element_owner (client
, node
);
1513 if (name
&& !xmlSetProp (node
, (xmlChar
*) name
, (xmlChar
*) value
))
1514 return GPG_ERR_BAD_DATA
;
1516 if (client
&& name
&& !xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_acl"))
1518 xmlChar
*acl
= node_has_attribute (node
, (xmlChar
*) "_acl");
1522 char *user
= create_acl_user (client
);
1526 rc
= add_attribute (client
, node
, (char *) "_acl", user
);
1536 if (name
&& xmlStrEqual ((xmlChar
*) name
, (xmlChar
*) "_mtime"))
1539 buf
= str_asprintf ("%li", time (NULL
));
1540 rc
= add_attribute (client
, node
, "_mtime", buf
);
1546 list_not_found_cb (struct client_s
*client
, int i
, xmlNodePtr node
,
1547 char **req
, gpg_error_t
*rc
, void *data
)
1549 struct element_list_s
*elements
= data
;
1551 if (*rc
!= GPG_ERR_EACCES
)
1554 elements
->data
= strv_dup (req
);
1559 * From the element path 'path', find sub-nodes and append them to the list.
1562 create_path_list (struct client_s
*client
, xmlDocPtr doc
,
1563 struct element_list_s
* elements
, char *path
)
1566 char **req
, **req_orig
;
1572 req
= str_split (path
, "\t", 0);
1575 req
= str_split (path
, " ", 0);
1577 return GPG_ERR_SYNTAX
;
1580 req_orig
= strv_dup (req
);
1583 rc
= GPG_ERR_ENOMEM
;
1587 n
= find_root_element (client
, doc
, &req
, &rc
, &a_target
, 0, 0);
1588 if ((rc
== GPG_ERR_ELEMENT_NOT_FOUND
|| rc
== GPG_ERR_ELOOP
1589 || rc
== GPG_ERR_EACCES
) && elements
->verbose
&& a_target
)
1591 if (rc
== GPG_ERR_EACCES
)
1598 if (rc
== GPG_ERR_EACCES
)
1605 if (!n
&& rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1616 *req
= str_dup (*req_orig
);
1623 n
= find_elements (client
, doc
, n
->children
, req
+ 1, &rc
, &e_target
,
1624 NULL
, list_not_found_cb
, 1, 0, elements
, 0);
1625 if (rc
== GPG_ERR_ELEMENT_NOT_FOUND
&& elements
->resolving
== 1)
1630 else if (rc
&& rc
!= GPG_ERR_EACCES
)
1637 if (!elements
->prefix
)
1642 * If any req_orig element contains no target the element should be
1643 * prefixed with the literal character. Not really crucial if the
1644 * client isn't human because child elements are prefixed for the
1645 * current path. But may be confusing if editing by hand.
1649 /* This is needed to prune the original requested element path to the
1650 * length of the failed element in the path. */
1651 int x
= strv_length (req_orig
)-strv_length ((char **)elements
->data
);
1655 for (i
= 0; i
<= x
; i
++)
1656 tmp
= strv_cat (tmp
, str_dup (req_orig
[i
]));
1658 elements
->prefix
= strv_join ("\t", tmp
);
1660 strv_free (elements
->data
);
1661 elements
->data
= NULL
;
1666 elements
->prefix
= str_dup (*req_orig
);
1668 elements
->prefix
= strv_join ("\t", req_orig
);
1671 if (!elements
->prefix
)
1673 rc
= GPG_ERR_ENOMEM
;
1677 if (elements
->verbose
)
1680 struct string_s
*realpath
= NULL
;
1682 if (!rc
&& allowed
&& a_target
&& elements
->with_target
)
1684 rc
= build_realpath (client
, doc
, path
, &realpath
);
1688 realpath
= string_prepend (realpath
, "T ");
1691 ret
= strv_printf (&elements
->elements
, "%s%s%s%s%s%s%s",
1693 (allowed
&& n
&& find_element_node (n
->children
))
1694 || realpath
? " " : "",
1695 (allowed
&& n
&& find_element_node (n
->children
)) ? "+" : "",
1696 allowed
&& realpath
? realpath
->str
: "",
1697 rc
== GPG_ERR_ELOOP
? " O" : "",
1698 rc
== GPG_ERR_ELEMENT_NOT_FOUND
? " E" : "",
1699 !allowed
? " P" : "");
1700 string_free (realpath
, 1);
1703 rc
= GPG_ERR_ENOMEM
;
1709 if (strv_printf (&elements
->elements
, "%s", elements
->prefix
) == 0)
1711 rc
= GPG_ERR_ENOMEM
;
1716 if (update_element_list (elements
) == 0)
1718 rc
= GPG_ERR_ENOMEM
;
1724 rc
= path_list_recurse (client
, doc
, n
? n
->children
: n
, elements
);
1727 strv_free (req_orig
);
1733 recurse_xpath_nodeset (struct client_s
*client
, xmlDocPtr doc
,
1734 xmlNodeSetPtr nodes
, xmlChar
* value
,
1735 xmlBufferPtr
* result
, int cmd
, const xmlChar
* attr
)
1737 int i
= value
? nodes
->nodeNr
- 1 : 0;
1740 buf
= xmlBufferCreate ();
1743 return GPG_ERR_ENOMEM
;
1745 for (; value
? i
>= 0 : i
< nodes
->nodeNr
; value
? i
-- : i
++)
1747 xmlNodePtr n
= nodes
->nodeTab
[i
];
1753 if (!value
&& !attr
)
1755 if (xmlNodeDump (buf
, doc
, n
, 0, 0) == -1)
1758 return GPG_ERR_BAD_DATA
;
1766 xmlNodeSetContent (n
, value
);
1767 rc
= update_element_mtime (client
, n
);
1775 rc
= add_attribute (client
, n
, (char *) attr
, (char *) value
);
1777 rc
= delete_attribute (client
, n
, attr
);
1789 convert_root_element (struct client_s
*client
, xmlNodePtr n
)
1791 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1797 xmlChar
*t
= xmlGetNodePath (n
);
1800 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1803 return GPG_ERR_AMBIGUOUS_NAME
;
1806 a
= xmlGetProp (n
, (xmlChar
*) "name");
1810 rc
= add_attribute (client
, n
, "_name", (char *) a
);
1816 rc
= delete_attribute (client
, n
, (xmlChar
*) "name");
1821 xmlNodeSetName (n
, (xmlChar
*) "element");
1828 delete_attribute (struct client_s
*client
, xmlNodePtr n
, const xmlChar
* name
)
1833 if ((a
= xmlHasProp (n
, name
)) == NULL
)
1834 return GPG_ERR_NOT_FOUND
;
1836 if (xmlRemoveProp (a
) == -1)
1837 return GPG_ERR_BAD_DATA
;
1839 if (client
&& xmlStrEqual (name
, (xmlChar
*) "_acl"))
1841 char *user
= create_acl_user (client
);
1843 rc
= add_attribute (client
, n
, (char *) "_acl", user
);
1850 return update_element_mtime (client
, n
);
1854 convert_elements_recurse (struct client_s
*client
, xmlDocPtr doc
,
1855 xmlNodePtr n
, unsigned depth
)
1861 for (n
= n
->children
; n
; n
= n
->next
)
1863 if (n
->type
== XML_ELEMENT_NODE
)
1869 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1871 xmlChar
*t
= xmlGetNodePath (n
);
1874 ("An existing \"element\" already exists. Please rename this element before converting. Path is: %s"),
1877 return GPG_ERR_AMBIGUOUS_NAME
;
1880 a
= xmlGetProp (n
, (xmlChar
*) "_name");
1884 xmlChar
*t
= xmlGetNodePath (n
);
1887 ("An existing \"_name\" attribute already exists. Please rename this attribute before converting. Path is: %s"),
1890 return GPG_ERR_AMBIGUOUS_NAME
;
1893 xmlChar
*tmp
= xmlStrdup (n
->name
);
1896 return GPG_ERR_ENOMEM
;
1898 xmlNodeSetName (n
, (xmlChar
*) "element");
1899 rc
= add_attribute (client
, n
, "_name", (char *) tmp
);
1907 rc
= convert_root_element (client
, n
);
1916 rc
= convert_elements_recurse (client
, doc
, n
, depth
);
1926 /* Renames ALL elements to the new "element" name. Existing element names are
1927 * stored as an attribute "_name". This was introduced in pwmd 2.12 so
1928 * elements can contain common characters that the XML parser barfs on (an
1929 * email address for example. */
1931 convert_pre_212_elements (xmlDocPtr doc
)
1933 xmlNodePtr n
= xmlDocGetRootElement (doc
);
1935 log_write (_("Converting pre 2.12 data file..."));
1936 return convert_elements_recurse (NULL
, doc
, n
, 0);
1940 validate_import (struct client_s
*client
, xmlNodePtr node
)
1947 for (xmlNodePtr n
= node
; n
; n
= n
->next
)
1949 if (n
->type
== XML_ELEMENT_NODE
)
1951 if (xmlStrEqual (n
->name
, (xmlChar
*) "element"))
1953 xmlChar
*a
= xmlGetProp (n
, (xmlChar
*) "_name");
1957 xmlChar
*t
= xmlGetNodePath (n
);
1959 log_write (_("Missing attribute '_name' at %s."), t
);
1961 return GPG_ERR_INV_VALUE
;
1964 if (!valid_xml_element (a
))
1966 xmlChar
*t
= xmlGetNodePath (n
);
1968 log_write (_("'%s' is not a valid element name at %s."), a
,
1972 return GPG_ERR_INV_VALUE
;
1976 a
= xmlGetProp (n
, (xmlChar
*) "_ctime");
1978 attr_ctime (client
, n
);
1981 a
= xmlGetProp (n
, (xmlChar
*) "_mtime");
1983 update_element_mtime (client
, n
);
1988 xmlChar
*t
= xmlGetNodePath (n
);
1990 log_write (_("Warning: unknown element '%s' at %s. Ignoring."),
1999 rc
= validate_import (client
, n
->children
);
2010 update_element_mtime (struct client_s
*client
, xmlNodePtr n
)
2012 return add_attribute (client
, n
, NULL
, NULL
);
2016 unlink_node (struct client_s
*client
, xmlNodePtr n
)
2024 rc
= update_element_mtime (client
, n
->parent
);
2031 parse_doc (const char *xml
, size_t len
, xmlDocPtr
*result
)
2035 xmlResetLastError ();
2036 doc
= xmlReadMemory (xml
, len
, NULL
, "UTF-8", XML_PARSE_NOBLANKS
);
2037 if (!doc
&& xmlGetLastError ())
2038 return GPG_ERR_BAD_DATA
;
2041 return !doc
? GPG_ERR_ENOMEM
: 0;
2045 realpath_elements_cb (struct client_s
*client
, xmlNodePtr node
, char **target
,
2046 gpg_error_t
* rc
, char **req_orig
, void *data
)
2048 char *path
= *(char **) data
;
2049 char *tmp
= NULL
, *result
;
2054 *(char **) data
= NULL
;
2057 path
= strv_join ("\t", target
);
2061 *rc
= GPG_ERR_ENOMEM
;
2067 tmp
= strv_join ("\t", req_orig
);
2072 *rc
= GPG_ERR_ENOMEM
;
2078 result
= str_asprintf ("%s\t%s", path
, tmp
);
2080 result
= str_dup (path
);
2084 *rc
= GPG_ERR_ENOMEM
;
2092 *(char **) data
= result
;
2097 build_realpath (struct client_s
*client
, xmlDocPtr doc
, char *line
,
2098 struct string_s
** result
)
2105 struct string_s
*string
;
2108 if (strchr (line
, '\t') != NULL
)
2110 if ((req
= str_split (line
, "\t", 0)) == NULL
)
2111 return GPG_ERR_SYNTAX
;
2115 if ((req
= str_split (line
, " ", 0)) == NULL
)
2116 return GPG_ERR_SYNTAX
;
2119 n
= find_root_element (client
, doc
, &req
, &rc
, NULL
, 0, 0);
2126 rp
= strv_join ("\t", req
);
2130 return GPG_ERR_ENOMEM
;
2135 n
= find_elements (client
, doc
, n
->children
, req
+ 1, &rc
, NULL
,
2136 realpath_elements_cb
, NULL
, 0, 0, &rp
, 0);
2145 string
= string_new (rp
);
2149 return GPG_ERR_ENOMEM
;
2152 for (i
= 0, t
= string
->str
+ i
; *t
; t
++, i
++)
2154 if ((!i
&& *t
!= '!') || (*t
== '\t' && *(t
+ 1) && *(t
+ 1) != '!'))
2156 struct string_s
*s
= string_insert_c (string
, !i
? i
++ : ++i
, '!');
2160 string_free (string
, 1);
2161 return GPG_ERR_ENOMEM
;
2175 node_to_element_path (xmlNodePtr node
)
2178 struct string_s
*str
= string_new ("");
2181 for (n
= node
; n
; n
= n
->parent
)
2185 for (child
= n
; child
; child
= child
->next
)
2187 if (child
->type
!= XML_ELEMENT_NODE
)
2190 xmlChar
*name
= node_has_attribute (n
, (xmlChar
*) "_name");
2193 str
= string_prepend (str
, (char *) name
);
2195 name
= node_has_attribute (n
, (xmlChar
*) "target");
2197 str
= string_prepend (str
, "\t");
2199 str
= string_prepend (str
, "\t!");
2206 str
= string_erase (str
, 0, 1);
2208 string_free (str
, 0);
2214 * Recurse the element tree beginning at 'node' and find elements who point
2215 * back to 'src' or 'dst'. Also follows target attributes.
2218 find_child_to_target (struct client_s
*client
, xmlDocPtr doc
, xmlNodePtr node
,
2219 xmlNodePtr src
, xmlNodePtr dst
, unsigned depth
,
2225 if (max_recursion_depth
>= 1 && depth
> max_recursion_depth
)
2226 return gpg_error (GPG_ERR_ELOOP
);
2228 for (n
= node
; n
; n
= n
->next
)
2232 if (n
->type
!= XML_ELEMENT_NODE
)
2235 if (n
== src
|| n
== dst
)
2236 return GPG_ERR_ELOOP
;
2238 target
= node_has_attribute (n
, (xmlChar
*) "target");
2242 char **result
= NULL
;
2244 tmp
= resolve_path (client
, doc
, target
, &result
, &rc
);
2249 rc
= find_child_to_target (client
, doc
, tmp
, src
, dst
, ++depth
,
2254 if (rc
&& gpg_err_code (rc
) != GPG_ERR_ELEMENT_NOT_FOUND
)
2265 rc
= find_child_to_target (client
, doc
, n
->children
, src
, dst
,
2280 find_child_of_parent (xmlDocPtr doc
, xmlNodePtr src
, xmlNodePtr dst
)
2285 for (n
= src
; n
; n
= n
->next
)
2287 if (n
->type
!= XML_ELEMENT_NODE
)
2296 rc
= find_child_of_parent (doc
, n
->children
, dst
);
2303 find_parent_of_child (xmlDocPtr doc
, xmlNodePtr node
, xmlNodePtr dst
)
2308 for (n
= node
; n
; n
= n
->parent
)
2310 if (n
->type
!= XML_ELEMENT_NODE
)
2314 for (tmp
= n
->next
; tmp
; n
= n
->next
)
2316 if (n
->type
!= XML_ELEMENT_NODE
)
2320 return GPG_ERR_ELOOP
;
2325 return GPG_ERR_ELOOP
;
2332 validate_target_attribute (struct client_s
*client
, xmlDocPtr doc
,
2333 const char *src
, xmlNodePtr dst_node
)
2336 xmlNodePtr src_node
;
2337 char **src_req
= NULL
;
2339 src_node
= resolve_path (client
, doc
, (xmlChar
*) src
, &src_req
, &rc
);
2343 client
->flags
|= FLAG_ACL_IGNORE
;
2344 /* A destination element is a child of the source element. */
2345 rc
= find_child_of_parent (doc
, src_node
->children
, dst_node
);
2349 /* The destination element is a parent of the source element. */
2350 rc
= find_parent_of_child (doc
, src_node
->parent
, dst_node
);
2354 /* A destination child element contains a target to the source element. */
2356 rc
= find_child_to_target (client
, doc
, dst_node
->children
, src_node
,
2362 strv_free (src_req
);
2363 client
->flags
&= ~(FLAG_ACL_IGNORE
| FLAG_ACL_ERROR
);
2367 /* The owner of the element is the first user listed in the _acl attribute
2368 * list. acl_check() should be called before calling this function. An empty
2369 * ACL is an error if the client is not invoking_user.
2372 is_element_owner (struct client_s
*client
, xmlNodePtr n
)
2374 xmlChar
*acl
= node_has_attribute (n
, (xmlChar
*) "_acl");
2376 gpg_error_t rc
= GPG_ERR_EACCES
;
2381 return peer_is_invoker (client
);
2384 users
= str_split((char *)acl
, ",", 0);
2385 if (users
&& *users
)
2390 if (client
->thd
->remote
)
2391 user
= str_asprintf ("#%s", client
->thd
->tls
->fp
);
2393 user
= get_username (client
->thd
->peer
->uid
);
2395 user
= get_username (client
->thd
->peer
->uid
);
2399 rc
= !strcasecmp (*users
, user
) ? 0 : GPG_ERR_EACCES
;
2401 rc
= !strcmp (*users
, user
) ? 0 : GPG_ERR_EACCES
;
2404 rc
= peer_is_invoker (client
);