File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_server_cgi.c |
Location: | line 257, column 9 |
Description: | Potential leak of memory pointed to by 'err' |
1 | /* Copyright (C) 2001 by Eric Kidd. All rights reserved. | |||
2 | ** | |||
3 | ** Redistribution and use in source and binary forms, with or without | |||
4 | ** modification, are permitted provided that the following conditions | |||
5 | ** are met: | |||
6 | ** 1. Redistributions of source code must retain the above copyright | |||
7 | ** notice, this list of conditions and the following disclaimer. | |||
8 | ** 2. Redistributions in binary form must reproduce the above copyright | |||
9 | ** notice, this list of conditions and the following disclaimer in the | |||
10 | ** documentation and/or other materials provided with the distribution. | |||
11 | ** 3. The name of the author may not be used to endorse or promote products | |||
12 | ** derived from this software without specific prior written permission. | |||
13 | ** | |||
14 | ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||
15 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
16 | ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
17 | ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||
18 | ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
19 | ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
20 | ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
21 | ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
22 | ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
23 | ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
24 | ** SUCH DAMAGE. */ | |||
25 | ||||
26 | ||||
27 | #include "xmlrpc_config.h" | |||
28 | ||||
29 | #include <stdlib.h> | |||
30 | #include <stdio.h> | |||
31 | #include <string.h> | |||
32 | ||||
33 | /* Windows NT stdout binary mode fix. */ | |||
34 | #ifdef _WIN32 | |||
35 | #include <io.h> | |||
36 | #include <fcntl.h> | |||
37 | #endif | |||
38 | ||||
39 | #include "xmlrpc-c/base.h" | |||
40 | #include "xmlrpc-c/server.h" | |||
41 | #include "xmlrpc-c/string_int.h" | |||
42 | #include "xmlrpc-c/server_cgi.h" | |||
43 | ||||
44 | ||||
45 | /*========================================================================= | |||
46 | ** Output Routines | |||
47 | **========================================================================= | |||
48 | ** These routines send various kinds of responses to the server. | |||
49 | */ | |||
50 | ||||
51 | static void | |||
52 | send_xml(const char * const xml_data, | |||
53 | size_t const xml_len) { | |||
54 | #ifdef _WIN32 | |||
55 | _setmode(_fileno(stdoutstdout), _O_BINARY); | |||
56 | #endif | |||
57 | /* Send our CGI headers back to the server. | |||
58 | ** XXX - Coercing 'size_t' to 'unsigned long' might be unsafe under | |||
59 | ** really weird circumstances. */ | |||
60 | fprintf(stdoutstdout, "Status: 200 OK\n"); | |||
61 | /* Handle authentication cookie being sent back. */ | |||
62 | if (getenv("HTTP_COOKIE_AUTH") != NULL((void*)0)) | |||
63 | fprintf(stdoutstdout, "Set-Cookie: auth=%s\n", getenv("HTTP_COOKIE_AUTH")); | |||
64 | fprintf(stdoutstdout, "Content-type: text/xml; charset=\"utf-8\"\n"); | |||
65 | fprintf(stdoutstdout, "Content-length: %ld\n\n", (unsigned long) xml_len); | |||
66 | ||||
67 | /* Blast out our data. */ | |||
68 | fwrite(xml_data, sizeof(char), xml_len, stdoutstdout); | |||
69 | } | |||
70 | ||||
71 | ||||
72 | ||||
73 | static void | |||
74 | send_error(int const code, | |||
75 | const char * const message, | |||
76 | xmlrpc_env * const env) { | |||
77 | ||||
78 | #ifdef _WIN32 | |||
79 | _setmode(_fileno(stdoutstdout), _O_BINARY); | |||
80 | #endif | |||
81 | /* Send an error header. */ | |||
82 | fprintf(stdoutstdout, "Status: %d %s\n", code, message); | |||
83 | fprintf(stdoutstdout, "Content-type: text/html\n\n"); | |||
84 | ||||
85 | /* Send an error message. */ | |||
86 | fprintf(stdoutstdout, "<title>%d %s</title>\n", code, message); | |||
87 | fprintf(stdoutstdout, "<h1>%d %s</h1>\n", code, message); | |||
88 | fprintf(stdoutstdout, "<p>An error occurred processing your request.</p>\n"); | |||
89 | ||||
90 | /* Print out the XML-RPC fault, if present. */ | |||
91 | if (env && env->fault_occurred) | |||
92 | fprintf(stdoutstdout, "<p>XML-RPC Fault #%d: %s</p>\n", | |||
93 | env->fault_code, env->fault_string); | |||
94 | } | |||
95 | ||||
96 | ||||
97 | /*========================================================================= | |||
98 | ** die_if_fault_occurred | |||
99 | **========================================================================= | |||
100 | ** Certain kinds of errors aren't worth the trouble of generating | |||
101 | ** an XML-RPC fault. For these, we just send status 500 to our web server | |||
102 | ** and log the fault to our server log. | |||
103 | */ | |||
104 | ||||
105 | static void | |||
106 | die_if_fault_occurred(xmlrpc_env * const env) { | |||
107 | if (env->fault_occurred) { | |||
108 | fprintf(stderrstderr, "Unexpected XML-RPC fault: %s (%d)\n", | |||
109 | env->fault_string, env->fault_code); | |||
110 | send_error(500, "Internal Server Error", env); | |||
111 | exit(1); | |||
112 | } | |||
113 | } | |||
114 | ||||
115 | ||||
116 | /*========================================================================= | |||
117 | ** Initialization, Cleanup & Method Registry | |||
118 | **========================================================================= | |||
119 | ** These are all related, so we group them together. | |||
120 | */ | |||
121 | ||||
122 | static xmlrpc_registry * globalRegistryP; | |||
123 | ||||
124 | /*========================================================================= | |||
125 | ** get_body | |||
126 | **========================================================================= | |||
127 | ** Slurp the body of the request into an xmlrpc_mem_block. | |||
128 | */ | |||
129 | ||||
130 | static xmlrpc_mem_block * | |||
131 | get_body(xmlrpc_env * const env, | |||
132 | size_t const length) { | |||
133 | ||||
134 | xmlrpc_mem_block *result; | |||
135 | char *contents; | |||
136 | size_t count; | |||
137 | ||||
138 | XMLRPC_ASSERT_ENV_OK(env)do if (!((env) != ((void*)0) && (env->fault_string == ((void*)0)) && !(env)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/xmlrpc_server_cgi.c", 138); while (0); | |||
139 | ||||
140 | /* Error-handling preconditions. */ | |||
141 | result = NULL((void*)0); | |||
142 | ||||
143 | #ifdef _WIN32 | |||
144 | /* Fix from Jeff Stewart: NT opens stdin and stdout in text mode | |||
145 | by default, badly confusing our length calculations. So we need | |||
146 | to set the file handle to binary. | |||
147 | */ | |||
148 | _setmode(_fileno(stdinstdin), _O_BINARY); | |||
149 | #endif | |||
150 | /* XXX - Puke if length is too big. */ | |||
151 | ||||
152 | /* Allocate our memory block. */ | |||
153 | result = xmlrpc_mem_block_new(env, length); | |||
154 | XMLRPC_FAIL_IF_FAULT(env)do { if ((env)->fault_occurred) goto cleanup; } while (0); | |||
155 | contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result)((char*) xmlrpc_mem_block_contents(result)); | |||
156 | ||||
157 | /* Get our data off the network. | |||
158 | ** XXX - Coercing 'size_t' to 'unsigned long' might be unsafe under | |||
159 | ** really weird circumstances. */ | |||
160 | count = fread(contents, sizeof(char), length, stdinstdin); | |||
161 | if (count < length) | |||
162 | XMLRPC_FAIL2(env, XMLRPC_INTERNAL_ERROR,do { xmlrpc_env_set_fault_formatted((env),((-500)),("Expected %ld bytes, received %ld" ),((unsigned long) length),((unsigned long) count)); goto cleanup ; } while (0) | |||
163 | "Expected %ld bytes, received %ld",do { xmlrpc_env_set_fault_formatted((env),((-500)),("Expected %ld bytes, received %ld" ),((unsigned long) length),((unsigned long) count)); goto cleanup ; } while (0) | |||
164 | (unsigned long) length, (unsigned long) count)do { xmlrpc_env_set_fault_formatted((env),((-500)),("Expected %ld bytes, received %ld" ),((unsigned long) length),((unsigned long) count)); goto cleanup ; } while (0); | |||
165 | ||||
166 | cleanup: | |||
167 | if (env->fault_occurred) { | |||
168 | if (result) | |||
169 | xmlrpc_mem_block_free(result); | |||
170 | return NULL((void*)0); | |||
171 | } | |||
172 | return result; | |||
173 | } | |||
174 | ||||
175 | ||||
176 | ||||
177 | void | |||
178 | xmlrpc_server_cgi_process_call(xmlrpc_registry * const registryP) { | |||
179 | /*---------------------------------------------------------------------------- | |||
180 | Get the XML-RPC call from Standard Input and environment variables, | |||
181 | parse it, find the right method, call it, prepare an XML-RPC | |||
182 | response with the result, and write it to Standard Output. | |||
183 | -----------------------------------------------------------------------------*/ | |||
184 | xmlrpc_env env; | |||
185 | char *method, *type, *length_str; | |||
186 | int length; | |||
187 | xmlrpc_mem_block *input, *output; | |||
188 | char *input_data, *output_data; | |||
189 | size_t input_size, output_size; | |||
190 | int code; | |||
191 | char *message; | |||
192 | ||||
193 | /* Error-handling preconditions. */ | |||
194 | xmlrpc_env_init(&env); | |||
195 | input = output = NULL((void*)0); | |||
196 | ||||
197 | /* Set up a default error message. */ | |||
198 | code = 500; message = "Internal Server Error"; | |||
199 | ||||
200 | /* Get our HTTP information from the environment. */ | |||
201 | method = getenv("REQUEST_METHOD"); | |||
202 | type = getenv("CONTENT_TYPE"); | |||
203 | length_str = getenv("CONTENT_LENGTH"); | |||
204 | ||||
205 | /* Perform some sanity checks. */ | |||
206 | if (!method || !xmlrpc_streq(method, "POST")) { | |||
207 | code = 405; message = "Method Not Allowed"; | |||
208 | XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Expected HTTP method POST")do { xmlrpc_env_set_fault((&env),((-500)),("Expected HTTP method POST" )); goto cleanup; } while (0); | |||
209 | } | |||
210 | if (!type || !xmlrpc_strneq(type, "text/xml", strlen("text/xml"))) { | |||
211 | char *template = "Expected content type: \"text/xml\", received: \"%s\""; | |||
212 | size_t err_len = strlen(template) + strlen(type) + 1; | |||
213 | char *err = malloc(err_len); | |||
214 | ||||
215 | (void)snprintf(err, err_len, template, type); | |||
216 | code = 400; message = "Bad Request"; | |||
217 | XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, err)do { xmlrpc_env_set_fault((&env),((-500)),(err)); goto cleanup ; } while (0); | |||
218 | free(err); | |||
219 | } | |||
220 | if (!length_str) { | |||
221 | code = 411; message = "Length Required"; | |||
222 | XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Content-length required")do { xmlrpc_env_set_fault((&env),((-500)),("Content-length required" )); goto cleanup; } while (0); | |||
223 | } | |||
224 | ||||
225 | /* Get our content length. */ | |||
226 | length = atoi(length_str); | |||
227 | if (length <= 0) { | |||
228 | code = 400; message = "Bad Request"; | |||
229 | XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Content-length must be > 0")do { xmlrpc_env_set_fault((&env),((-500)),("Content-length must be > 0" )); goto cleanup; } while (0); | |||
230 | } | |||
231 | ||||
232 | /* SECURITY: Make sure our content length is legal. | |||
233 | ** XXX - We can cast 'input_len' because we know it's >= 0, yes? */ | |||
234 | if ((size_t) length > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID(1))) { | |||
235 | code = 400; message = "Bad Request"; | |||
236 | XMLRPC_FAIL(&env, XMLRPC_LIMIT_EXCEEDED_ERROR,do { xmlrpc_env_set_fault((&env),((-509)),("XML-RPC request too large" )); goto cleanup; } while (0) | |||
237 | "XML-RPC request too large")do { xmlrpc_env_set_fault((&env),((-509)),("XML-RPC request too large" )); goto cleanup; } while (0); | |||
238 | } | |||
239 | ||||
240 | /* Get our body. */ | |||
241 | input = get_body(&env, length); | |||
242 | XMLRPC_FAIL_IF_FAULT(&env)do { if ((&env)->fault_occurred) goto cleanup; } while (0); | |||
243 | input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input)((char*) xmlrpc_mem_block_contents(input)); | |||
244 | input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input)(xmlrpc_mem_block_size(input) / sizeof(char)); | |||
245 | ||||
246 | /* Process our call. */ | |||
247 | xmlrpc_registry_process_call2(&env, registryP, | |||
248 | input_data, input_size, NULL((void*)0), &output); | |||
249 | XMLRPC_FAIL_IF_FAULT(&env)do { if ((&env)->fault_occurred) goto cleanup; } while (0); | |||
250 | output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output)((char*) xmlrpc_mem_block_contents(output)); | |||
251 | output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output)(xmlrpc_mem_block_size(output) / sizeof(char)); | |||
252 | ||||
253 | /* Send our data. */ | |||
254 | send_xml(output_data, output_size); | |||
255 | ||||
256 | cleanup: | |||
257 | if (input) | |||
| ||||
258 | xmlrpc_mem_block_free(input); | |||
259 | if (output) | |||
260 | xmlrpc_mem_block_free(output); | |||
261 | ||||
262 | if (env.fault_occurred) | |||
263 | send_error(code, message, &env); | |||
264 | ||||
265 | xmlrpc_env_clean(&env); | |||
266 | } | |||
267 | ||||
268 | ||||
269 | ||||
270 | void | |||
271 | xmlrpc_cgi_init(int const flags ATTR_UNUSED__attribute__((__unused__))) { | |||
272 | xmlrpc_env env; | |||
273 | ||||
274 | xmlrpc_env_init(&env); | |||
275 | globalRegistryP = xmlrpc_registry_new(&env); | |||
276 | die_if_fault_occurred(&env); | |||
277 | xmlrpc_env_clean(&env); | |||
278 | } | |||
279 | ||||
280 | ||||
281 | ||||
282 | void | |||
283 | xmlrpc_cgi_cleanup(void) { | |||
284 | xmlrpc_registry_free(globalRegistryP); | |||
285 | } | |||
286 | ||||
287 | ||||
288 | ||||
289 | xmlrpc_registry * | |||
290 | xmlrpc_cgi_registry(void) { | |||
291 | return globalRegistryP; | |||
292 | } | |||
293 | ||||
294 | ||||
295 | ||||
296 | void | |||
297 | xmlrpc_cgi_add_method(const char * const method_name, | |||
298 | xmlrpc_method const method, | |||
299 | void * const user_data) { | |||
300 | xmlrpc_env env; | |||
301 | xmlrpc_env_init(&env); | |||
302 | xmlrpc_registry_add_method(&env, globalRegistryP, NULL((void*)0), method_name, | |||
303 | method, user_data); | |||
304 | die_if_fault_occurred(&env); | |||
305 | xmlrpc_env_clean(&env); | |||
306 | } | |||
307 | ||||
308 | ||||
309 | ||||
310 | void | |||
311 | xmlrpc_cgi_add_method_w_doc(const char * const method_name, | |||
312 | xmlrpc_method const method, | |||
313 | void * const user_data, | |||
314 | const char * const signature, | |||
315 | const char * const help) { | |||
316 | xmlrpc_env env; | |||
317 | xmlrpc_env_init(&env); | |||
318 | xmlrpc_registry_add_method_w_doc(&env, globalRegistryP, NULL((void*)0), method_name, | |||
319 | method, user_data, signature, help); | |||
320 | die_if_fault_occurred(&env); | |||
321 | xmlrpc_env_clean(&env); | |||
322 | } | |||
323 | ||||
324 | ||||
325 | ||||
326 | void | |||
327 | xmlrpc_cgi_process_call(void) { | |||
328 | ||||
329 | xmlrpc_server_cgi_process_call(globalRegistryP); | |||
| ||||
330 | } |