Bug Summary

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'

Annotated Source Code

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
51static void
52send_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
73static void
74send_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
105static void
106die_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
122static xmlrpc_registry * globalRegistryP;
123
124/*=========================================================================
125** get_body
126**=========================================================================
127** Slurp the body of the request into an xmlrpc_mem_block.
128*/
129
130static xmlrpc_mem_block *
131get_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
177void
178xmlrpc_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")) {
2
Assuming 'method' is non-null
3
Taking false branch
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"))) {
4
Assuming 'type' is non-null
5
Taking true branch
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);
6
Memory is allocated
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)
7
Potential leak of memory pointed to by 'err'
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
270void
271xmlrpc_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
282void
283xmlrpc_cgi_cleanup(void) {
284 xmlrpc_registry_free(globalRegistryP);
285}
286
287
288
289xmlrpc_registry *
290xmlrpc_cgi_registry(void) {
291 return globalRegistryP;
292}
293
294
295
296void
297xmlrpc_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
310void
311xmlrpc_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
326void
327xmlrpc_cgi_process_call(void) {
328
329 xmlrpc_server_cgi_process_call(globalRegistryP);
1
Calling 'xmlrpc_server_cgi_process_call'
330}