/src/httpd/srclib/apr/xml/apr_xml_expat.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include "apr.h" |
18 | | |
19 | | #if APU_USE_EXPAT |
20 | | #include "apr_xml.h" |
21 | | |
22 | | #if defined(HAVE_XMLPARSE_XMLPARSE_H) |
23 | | #include <xmlparse/xmlparse.h> |
24 | | #elif defined(HAVE_XMLTOK_XMLPARSE_H) |
25 | | #include <xmltok/xmlparse.h> |
26 | | #elif defined(HAVE_XML_XMLPARSE_H) |
27 | | #include <xml/xmlparse.h> |
28 | | #else |
29 | | #include <expat.h> |
30 | | #endif |
31 | | |
32 | | typedef enum XML_Error XML_Error; |
33 | | |
34 | | #include "apr_xml_internal.h" |
35 | | |
36 | | static apr_status_t cleanup_parser(void *ctx) |
37 | 0 | { |
38 | 0 | apr_xml_parser *parser = ctx; |
39 | |
|
40 | 0 | XML_ParserFree(parser->xp); |
41 | 0 | parser->xp = NULL; |
42 | |
|
43 | 0 | return APR_SUCCESS; |
44 | 0 | } |
45 | | static apr_status_t do_parse(apr_xml_parser *parser, |
46 | | const char *data, apr_size_t len, |
47 | | int is_final) |
48 | 0 | { |
49 | 0 | if (parser->xp == NULL) { |
50 | 0 | parser->error = APR_XML_ERROR_PARSE_DONE; |
51 | 0 | } |
52 | 0 | else { |
53 | 0 | int rv = XML_Parse(parser->xp, data, (int)len, is_final); |
54 | |
|
55 | 0 | if (rv == 0) { |
56 | 0 | parser->error = APR_XML_ERROR_EXPAT; |
57 | 0 | parser->xp_err = XML_GetErrorCode(parser->xp); |
58 | 0 | parser->xp_msg = XML_ErrorString(parser->xp_err); |
59 | 0 | } |
60 | 0 | } |
61 | | |
62 | | /* ### better error code? */ |
63 | 0 | return parser->error ? APR_EGENERAL : APR_SUCCESS; |
64 | 0 | } |
65 | | |
66 | | |
67 | | static XMLParserImpl xml_parser_expat = { |
68 | | do_parse, |
69 | | cleanup_parser |
70 | | }; |
71 | | |
72 | 0 | XMLParserImpl* apr_xml_get_parser_impl(void) { return &xml_parser_expat; } |
73 | | static const char APR_KW_DAV[] = { 0x44, 0x41, 0x56, 0x3A, '\0' }; |
74 | | |
75 | | #if XML_MAJOR_VERSION > 1 |
76 | | /* Stop the parser if an entity declaration is hit. */ |
77 | | static void entity_declaration(void *userData, const XML_Char *entityName, |
78 | | int is_parameter_entity, const XML_Char *value, |
79 | | int value_length, const XML_Char *base, |
80 | | const XML_Char *systemId, const XML_Char *publicId, |
81 | | const XML_Char *notationName) |
82 | 0 | { |
83 | 0 | apr_xml_parser *parser = userData; |
84 | |
|
85 | 0 | XML_StopParser(parser->xp, XML_FALSE); |
86 | 0 | } |
87 | | #else |
88 | | /* A noop default_handler. */ |
89 | | static void default_handler(void *userData, const XML_Char *s, int len) |
90 | | { |
91 | | } |
92 | | #endif |
93 | | |
94 | | apr_xml_parser* apr_xml_parser_create_internal(apr_pool_t *pool, |
95 | | void *start_func, void *end_func, void *cdata_func) |
96 | 0 | { |
97 | 0 | apr_xml_parser *parser = apr_pcalloc(pool, sizeof(*parser)); |
98 | |
|
99 | 0 | parser->impl = apr_xml_get_parser_impl(); |
100 | |
|
101 | 0 | parser->p = pool; |
102 | 0 | parser->doc = apr_pcalloc(pool, sizeof(*parser->doc)); |
103 | |
|
104 | 0 | parser->doc->namespaces = apr_array_make(pool, 5, sizeof(const char *)); |
105 | | |
106 | | /* ### is there a way to avoid hard-coding this? */ |
107 | 0 | apr_xml_insert_uri(parser->doc->namespaces, APR_KW_DAV); |
108 | |
|
109 | 0 | parser->xp = XML_ParserCreate(NULL); |
110 | 0 | if (parser->xp == NULL) { |
111 | 0 | (*apr_pool_abort_get(pool))(APR_ENOMEM); |
112 | 0 | return NULL; |
113 | 0 | } |
114 | | |
115 | 0 | apr_pool_cleanup_register(pool, parser, cleanup_parser, |
116 | 0 | apr_pool_cleanup_null); |
117 | |
|
118 | 0 | XML_SetUserData(parser->xp, parser); |
119 | 0 | XML_SetElementHandler(parser->xp, start_func, end_func); |
120 | 0 | XML_SetCharacterDataHandler(parser->xp, cdata_func); |
121 | | |
122 | | /* Prevent the "billion laughs" attack against expat by disabling |
123 | | * internal entity expansion. With 2.x, forcibly stop the parser |
124 | | * if an entity is declared - this is safer and a more obvious |
125 | | * failure mode. With older versions, installing a noop |
126 | | * DefaultHandler means that internal entities will be expanded as |
127 | | * the empty string, which is also sufficient to prevent the |
128 | | * attack. */ |
129 | 0 | #if XML_MAJOR_VERSION > 1 |
130 | 0 | XML_SetEntityDeclHandler(parser->xp, entity_declaration); |
131 | | #else |
132 | | XML_SetDefaultHandler(parser->xp, default_handler); |
133 | | #endif |
134 | |
|
135 | 0 | return parser; |
136 | 0 | } |
137 | | #endif |