| File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_server_cgi.c |
| Location: | line 212, column 38 |
| Description: | Null pointer passed as an argument to a 'nonnull' parameter |
| 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 | } |