| File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/system_method.c |
| Location: | line 327, column 10 |
| Description: | Access to field 'fault_occurred' results in a dereference of a null pointer (loaded from variable 'envP') |
| 1 | /* Copyright information is at end of file */ | |||||
| 2 | ||||||
| 3 | #include "xmlrpc_config.h" | |||||
| 4 | ||||||
| 5 | #include <assert.h> | |||||
| 6 | #include <stdlib.h> | |||||
| 7 | #include <string.h> | |||||
| 8 | ||||||
| 9 | #include "xmlrpc-c/base_int.h" | |||||
| 10 | #include "xmlrpc-c/string_int.h" | |||||
| 11 | #include "xmlrpc-c/base.h" | |||||
| 12 | #include "xmlrpc-c/server.h" | |||||
| 13 | #include "version.h" | |||||
| 14 | #include "registry.h" | |||||
| 15 | #include "method.h" | |||||
| 16 | ||||||
| 17 | #include "system_method.h" | |||||
| 18 | ||||||
| 19 | ||||||
| 20 | struct systemMethodReg { | |||||
| 21 | /*---------------------------------------------------------------------------- | |||||
| 22 | Information needed to register a system method | |||||
| 23 | -----------------------------------------------------------------------------*/ | |||||
| 24 | const char * const methodName; | |||||
| 25 | xmlrpc_method2 const methodFunction; | |||||
| 26 | const char * const signatureString; | |||||
| 27 | const char * const helpText; | |||||
| 28 | }; | |||||
| 29 | ||||||
| 30 | ||||||
| 31 | ||||||
| 32 | void | |||||
| 33 | xmlrpc_registry_disable_introspection(xmlrpc_registry * const registryP) { | |||||
| 34 | ||||||
| 35 | XMLRPC_ASSERT_PTR_OK(registryP)do if (!((registryP) != ((void*)0))) xmlrpc_assertion_failed( "../../../../libs/xmlrpc-c/src/system_method.c", 35); while ( 0); | |||||
| 36 | ||||||
| 37 | registryP->introspectionEnabled = false; | |||||
| 38 | } | |||||
| 39 | ||||||
| 40 | ||||||
| 41 | ||||||
| 42 | /*========================================================================= | |||||
| 43 | system.multicall | |||||
| 44 | =========================================================================*/ | |||||
| 45 | ||||||
| 46 | static void | |||||
| 47 | callOneMethod(xmlrpc_env * const envP, | |||||
| 48 | xmlrpc_registry * const registryP, | |||||
| 49 | xmlrpc_value * const rpcDescP, | |||||
| 50 | void * const callInfo, | |||||
| 51 | xmlrpc_value ** const resultPP) { | |||||
| 52 | ||||||
| 53 | const char * methodName; | |||||
| 54 | xmlrpc_value * paramArrayP; | |||||
| 55 | ||||||
| 56 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 56); while ( 0); | |||||
| 57 | ||||||
| 58 | if (xmlrpc_value_type(rpcDescP) != XMLRPC_TYPE_STRUCT) | |||||
| 59 | xmlrpc_env_set_fault_formatted( | |||||
| 60 | envP, XMLRPC_TYPE_ERROR(-501), | |||||
| 61 | "An element of the multicall array is type %u, but should " | |||||
| 62 | "be a struct (with members 'methodName' and 'params')", | |||||
| 63 | xmlrpc_value_type(rpcDescP)); | |||||
| 64 | else { | |||||
| 65 | xmlrpc_decompose_value(envP, rpcDescP, "{s:s,s:A,*}", | |||||
| 66 | "methodName", &methodName, | |||||
| 67 | "params", ¶mArrayP); | |||||
| 68 | if (!envP->fault_occurred) { | |||||
| 69 | /* Watch out for a deep recursion attack. */ | |||||
| 70 | if (xmlrpc_streq(methodName, "system.multicall")) | |||||
| 71 | xmlrpc_env_set_fault_formatted( | |||||
| 72 | envP, | |||||
| 73 | XMLRPC_REQUEST_REFUSED_ERROR(-507), | |||||
| 74 | "Recursive system.multicall forbidden"); | |||||
| 75 | else { | |||||
| 76 | xmlrpc_env env; | |||||
| 77 | xmlrpc_value * resultValP; | |||||
| 78 | ||||||
| 79 | xmlrpc_env_init(&env); | |||||
| 80 | xmlrpc_dispatchCall(&env, registryP, methodName, paramArrayP, | |||||
| 81 | callInfo, | |||||
| 82 | &resultValP); | |||||
| 83 | if (env.fault_occurred) { | |||||
| 84 | /* Method failed, so result is a fault structure */ | |||||
| 85 | *resultPP = | |||||
| 86 | xmlrpc_build_value( | |||||
| 87 | envP, "{s:i,s:s}", | |||||
| 88 | "faultCode", (xmlrpc_int32) env.fault_code, | |||||
| 89 | "faultString", env.fault_string); | |||||
| 90 | } else { | |||||
| 91 | *resultPP = xmlrpc_build_value(envP, "(V)", resultValP); | |||||
| 92 | ||||||
| 93 | xmlrpc_DECREF(resultValP); | |||||
| 94 | } | |||||
| 95 | xmlrpc_env_clean(&env); | |||||
| 96 | } | |||||
| 97 | xmlrpc_DECREF(paramArrayP); | |||||
| 98 | xmlrpc_strfree(methodName); | |||||
| 99 | } | |||||
| 100 | } | |||||
| 101 | } | |||||
| 102 | ||||||
| 103 | ||||||
| 104 | ||||||
| 105 | static void | |||||
| 106 | getMethListFromMulticallPlist(xmlrpc_env * const envP, | |||||
| 107 | xmlrpc_value * const paramArrayP, | |||||
| 108 | xmlrpc_value ** const methlistPP) { | |||||
| 109 | ||||||
| 110 | if (xmlrpc_array_size(envP, paramArrayP) != 1) | |||||
| 111 | xmlrpc_env_set_fault_formatted( | |||||
| 112 | envP, XMLRPC_PARSE_ERROR(-503), | |||||
| 113 | "system.multicall takes one parameter, which is an " | |||||
| 114 | "array, each element describing one RPC. You " | |||||
| 115 | "supplied %u arguments", | |||||
| 116 | xmlrpc_array_size(envP, paramArrayP)); | |||||
| 117 | else { | |||||
| 118 | xmlrpc_value * methlistP; | |||||
| 119 | ||||||
| 120 | xmlrpc_array_read_item(envP, paramArrayP, 0, &methlistP); | |||||
| 121 | ||||||
| 122 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 122); while (0); | |||||
| 123 | ||||||
| 124 | if (xmlrpc_value_type(methlistP) != XMLRPC_TYPE_ARRAY) | |||||
| 125 | xmlrpc_env_set_fault_formatted( | |||||
| 126 | envP, XMLRPC_TYPE_ERROR(-501), | |||||
| 127 | "system.multicall's parameter should be an array, " | |||||
| 128 | "each element describing one RPC. But it is type " | |||||
| 129 | "%u instead.", xmlrpc_value_type(methlistP)); | |||||
| 130 | else | |||||
| 131 | *methlistPP = methlistP; | |||||
| 132 | ||||||
| 133 | if (envP->fault_occurred) | |||||
| 134 | xmlrpc_DECREF(methlistP); | |||||
| 135 | } | |||||
| 136 | } | |||||
| 137 | ||||||
| 138 | ||||||
| 139 | ||||||
| 140 | static xmlrpc_value * | |||||
| 141 | system_multicall(xmlrpc_env * const envP, | |||||
| 142 | xmlrpc_value * const paramArrayP, | |||||
| 143 | void * const serverInfo, | |||||
| 144 | void * const callInfo) { | |||||
| 145 | ||||||
| 146 | xmlrpc_registry * registryP; | |||||
| 147 | xmlrpc_value * resultsP; | |||||
| 148 | xmlrpc_value * methlistP; | |||||
| 149 | ||||||
| 150 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 150); while (0); | |||||
| 151 | XMLRPC_ASSERT_ARRAY_OK(paramArrayP)xmlrpc_abort_if_array_bad(paramArrayP); | |||||
| 152 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 152); while (0); | |||||
| 153 | ||||||
| 154 | resultsP = NULL((void*)0); /* defeat compiler warning */ | |||||
| 155 | ||||||
| 156 | /* Turn our arguments into something more useful. */ | |||||
| 157 | registryP = (xmlrpc_registry*) serverInfo; | |||||
| 158 | ||||||
| 159 | getMethListFromMulticallPlist(envP, paramArrayP, &methlistP); | |||||
| 160 | if (!envP->fault_occurred) { | |||||
| 161 | /* Create an initially empty result list. */ | |||||
| 162 | resultsP = xmlrpc_array_new(envP); | |||||
| 163 | if (!envP->fault_occurred) { | |||||
| 164 | /* Loop over our input list, calling each method in turn. */ | |||||
| 165 | unsigned int const methodCount = | |||||
| 166 | xmlrpc_array_size(envP, methlistP); | |||||
| 167 | unsigned int i; | |||||
| 168 | for (i = 0; i < methodCount && !envP->fault_occurred; ++i) { | |||||
| 169 | xmlrpc_value * const methinfoP = | |||||
| 170 | xmlrpc_array_get_item(envP, methlistP, i); | |||||
| 171 | ||||||
| 172 | xmlrpc_value * resultP; | |||||
| 173 | ||||||
| 174 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 174); while (0); | |||||
| 175 | ||||||
| 176 | callOneMethod(envP, registryP, methinfoP, callInfo, &resultP); | |||||
| 177 | ||||||
| 178 | if (!envP->fault_occurred) { | |||||
| 179 | /* Append this method result to our master array. */ | |||||
| 180 | xmlrpc_array_append_item(envP, resultsP, resultP); | |||||
| 181 | xmlrpc_DECREF(resultP); | |||||
| 182 | } | |||||
| 183 | } | |||||
| 184 | if (envP->fault_occurred) | |||||
| 185 | xmlrpc_DECREF(resultsP); | |||||
| 186 | xmlrpc_DECREF(methlistP); | |||||
| 187 | } | |||||
| 188 | } | |||||
| 189 | return resultsP; | |||||
| 190 | } | |||||
| 191 | ||||||
| 192 | ||||||
| 193 | ||||||
| 194 | static struct systemMethodReg const methodMulticall = { | |||||
| 195 | "system.multicall", | |||||
| 196 | &system_multicall, | |||||
| 197 | "A:A", | |||||
| 198 | "Process an array of calls, and return an array of results. Calls should " | |||||
| 199 | "be structs of the form {'methodName': string, 'params': array}. Each " | |||||
| 200 | "result will either be a single-item array containg the result value, or " | |||||
| 201 | "a struct of the form {'faultCode': int, 'faultString': string}. This " | |||||
| 202 | "is useful when you need to make lots of small calls without lots of " | |||||
| 203 | "round trips.", | |||||
| 204 | }; | |||||
| 205 | ||||||
| 206 | ||||||
| 207 | /*========================================================================= | |||||
| 208 | system.listMethods | |||||
| 209 | =========================================================================*/ | |||||
| 210 | ||||||
| 211 | ||||||
| 212 | static void | |||||
| 213 | createMethodListArray(xmlrpc_env * const envP, | |||||
| 214 | xmlrpc_registry * const registryP, | |||||
| 215 | xmlrpc_value ** const methodListPP) { | |||||
| 216 | /*---------------------------------------------------------------------------- | |||||
| 217 | Create as an XML-RPC array value a list of names of methods registered | |||||
| 218 | in registry 'registryP'. | |||||
| 219 | ||||||
| 220 | This is the type of value that the system.listMethods method is supposed | |||||
| 221 | to return. | |||||
| 222 | -----------------------------------------------------------------------------*/ | |||||
| 223 | xmlrpc_value * methodListP; | |||||
| 224 | ||||||
| 225 | methodListP = xmlrpc_array_new(envP); | |||||
| 226 | ||||||
| 227 | if (!envP->fault_occurred) { | |||||
| 228 | xmlrpc_methodNode * methodNodeP; | |||||
| 229 | for (methodNodeP = registryP->methodListP->firstMethodP; | |||||
| 230 | methodNodeP && !envP->fault_occurred; | |||||
| 231 | methodNodeP = methodNodeP->nextP) { | |||||
| 232 | ||||||
| 233 | xmlrpc_value * methodNameVP; | |||||
| 234 | ||||||
| 235 | methodNameVP = xmlrpc_string_new(envP, methodNodeP->methodName); | |||||
| 236 | ||||||
| 237 | if (!envP->fault_occurred) { | |||||
| 238 | xmlrpc_array_append_item(envP, methodListP, methodNameVP); | |||||
| 239 | ||||||
| 240 | xmlrpc_DECREF(methodNameVP); | |||||
| 241 | } | |||||
| 242 | } | |||||
| 243 | if (envP->fault_occurred) | |||||
| 244 | xmlrpc_DECREF(methodListP); | |||||
| 245 | } | |||||
| 246 | *methodListPP = methodListP; | |||||
| 247 | } | |||||
| 248 | ||||||
| 249 | ||||||
| 250 | ||||||
| 251 | static xmlrpc_value * | |||||
| 252 | system_listMethods(xmlrpc_env * const envP, | |||||
| 253 | xmlrpc_value * const paramArrayP, | |||||
| 254 | void * const serverInfo, | |||||
| 255 | void * const callInfo ATTR_UNUSED__attribute__((__unused__))) { | |||||
| 256 | ||||||
| 257 | xmlrpc_registry * const registryP = serverInfo; | |||||
| 258 | ||||||
| 259 | xmlrpc_value * retvalP; | |||||
| 260 | ||||||
| 261 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 261); while (0); | |||||
| 262 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 262); while (0); | |||||
| 263 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 263); while (0); | |||||
| 264 | ||||||
| 265 | xmlrpc_decompose_value(envP, paramArrayP, "()"); | |||||
| 266 | if (!envP->fault_occurred) { | |||||
| 267 | if (!registryP->introspectionEnabled) | |||||
| 268 | xmlrpc_env_set_fault_formatted( | |||||
| 269 | envP, XMLRPC_INTROSPECTION_DISABLED_ERROR(-508), | |||||
| 270 | "Introspection is disabled in this server " | |||||
| 271 | "for security reasons"); | |||||
| 272 | else | |||||
| 273 | createMethodListArray(envP, registryP, &retvalP); | |||||
| 274 | } | |||||
| 275 | return retvalP; | |||||
| 276 | } | |||||
| 277 | ||||||
| 278 | ||||||
| 279 | ||||||
| 280 | static struct systemMethodReg const methodListMethods = { | |||||
| 281 | "system.listMethods", | |||||
| 282 | &system_listMethods, | |||||
| 283 | "A:", | |||||
| 284 | "Return an array of all available XML-RPC methods on this server.", | |||||
| 285 | }; | |||||
| 286 | ||||||
| 287 | ||||||
| 288 | ||||||
| 289 | /*========================================================================= | |||||
| 290 | system.methodExist | |||||
| 291 | ==========================================================================*/ | |||||
| 292 | ||||||
| 293 | static void | |||||
| 294 | determineMethodExistence(xmlrpc_env * const envP, | |||||
| 295 | const char * const methodName, | |||||
| 296 | xmlrpc_registry * const registryP, | |||||
| 297 | xmlrpc_value ** const existsPP) { | |||||
| 298 | ||||||
| 299 | xmlrpc_methodInfo * methodP; | |||||
| 300 | ||||||
| 301 | xmlrpc_methodListLookupByName(registryP->methodListP, methodName, | |||||
| 302 | &methodP); | |||||
| 303 | ||||||
| 304 | *existsPP = xmlrpc_bool_new(envP, !!methodP); | |||||
| 305 | } | |||||
| 306 | ||||||
| 307 | ||||||
| 308 | ||||||
| 309 | static xmlrpc_value * | |||||
| 310 | system_methodExist(xmlrpc_env * const envP, | |||||
| 311 | xmlrpc_value * const paramArrayP, | |||||
| 312 | void * const serverInfo, | |||||
| 313 | void * const callInfo ATTR_UNUSED__attribute__((__unused__))) { | |||||
| 314 | ||||||
| 315 | xmlrpc_registry * const registryP = serverInfo; | |||||
| 316 | ||||||
| 317 | xmlrpc_value * retvalP; | |||||
| 318 | ||||||
| 319 | const char * methodName; | |||||
| 320 | ||||||
| 321 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 321); while (0); | |||||
| ||||||
| 322 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 322); while (0); | |||||
| 323 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 323); while (0); | |||||
| 324 | ||||||
| 325 | xmlrpc_decompose_value(envP, paramArrayP, "(s)", &methodName); | |||||
| 326 | ||||||
| 327 | if (!envP->fault_occurred) { | |||||
| ||||||
| 328 | determineMethodExistence(envP, methodName, registryP, &retvalP); | |||||
| 329 | ||||||
| 330 | xmlrpc_strfree(methodName); | |||||
| 331 | } | |||||
| 332 | ||||||
| 333 | return retvalP; | |||||
| 334 | } | |||||
| 335 | ||||||
| 336 | ||||||
| 337 | ||||||
| 338 | static struct systemMethodReg const methodMethodExist = { | |||||
| 339 | "system.methodExist", | |||||
| 340 | &system_methodExist, | |||||
| 341 | "s:b", | |||||
| 342 | "Tell whether a method by a specified name exists on this server", | |||||
| 343 | }; | |||||
| 344 | ||||||
| 345 | ||||||
| 346 | ||||||
| 347 | /*========================================================================= | |||||
| 348 | system.methodHelp | |||||
| 349 | =========================================================================*/ | |||||
| 350 | ||||||
| 351 | ||||||
| 352 | static void | |||||
| 353 | getHelpString(xmlrpc_env * const envP, | |||||
| 354 | const char * const methodName, | |||||
| 355 | xmlrpc_registry * const registryP, | |||||
| 356 | xmlrpc_value ** const helpStringPP) { | |||||
| 357 | ||||||
| 358 | xmlrpc_methodInfo * methodP; | |||||
| 359 | ||||||
| 360 | xmlrpc_methodListLookupByName(registryP->methodListP, methodName, | |||||
| 361 | &methodP); | |||||
| 362 | ||||||
| 363 | if (!methodP) | |||||
| 364 | xmlrpc_env_set_fault_formatted( | |||||
| 365 | envP, XMLRPC_NO_SUCH_METHOD_ERROR(-506), | |||||
| 366 | "Method '%s' does not exist", methodName); | |||||
| 367 | else | |||||
| 368 | *helpStringPP = xmlrpc_string_new(envP, methodP->helpText); | |||||
| 369 | } | |||||
| 370 | ||||||
| 371 | ||||||
| 372 | ||||||
| 373 | static xmlrpc_value * | |||||
| 374 | system_methodHelp(xmlrpc_env * const envP, | |||||
| 375 | xmlrpc_value * const paramArrayP, | |||||
| 376 | void * const serverInfo, | |||||
| 377 | void * const callInfo ATTR_UNUSED__attribute__((__unused__))) { | |||||
| 378 | ||||||
| 379 | xmlrpc_registry * const registryP = serverInfo; | |||||
| 380 | ||||||
| 381 | xmlrpc_value * retvalP; | |||||
| 382 | ||||||
| 383 | const char * methodName; | |||||
| 384 | ||||||
| 385 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 385); while (0); | |||||
| 386 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 386); while (0); | |||||
| 387 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 387); while (0); | |||||
| 388 | ||||||
| 389 | xmlrpc_decompose_value(envP, paramArrayP, "(s)", &methodName); | |||||
| 390 | ||||||
| 391 | if (!envP->fault_occurred) { | |||||
| 392 | if (!registryP->introspectionEnabled) | |||||
| 393 | xmlrpc_env_set_fault_formatted( | |||||
| 394 | envP, XMLRPC_INTROSPECTION_DISABLED_ERROR(-508), | |||||
| 395 | "Introspection is disabled in this server " | |||||
| 396 | "for security reasons"); | |||||
| 397 | else | |||||
| 398 | getHelpString(envP, methodName, registryP, &retvalP); | |||||
| 399 | ||||||
| 400 | xmlrpc_strfree(methodName); | |||||
| 401 | } | |||||
| 402 | ||||||
| 403 | return retvalP; | |||||
| 404 | } | |||||
| 405 | ||||||
| 406 | ||||||
| 407 | static struct systemMethodReg const methodMethodHelp = { | |||||
| 408 | "system.methodHelp", | |||||
| 409 | &system_methodHelp, | |||||
| 410 | "s:s", | |||||
| 411 | "Given the name of a method, return a help string.", | |||||
| 412 | }; | |||||
| 413 | ||||||
| 414 | ||||||
| 415 | ||||||
| 416 | /*========================================================================= | |||||
| 417 | system.methodSignature | |||||
| 418 | ==========================================================================*/ | |||||
| 419 | ||||||
| 420 | static void | |||||
| 421 | buildNoSigSuppliedResult(xmlrpc_env * const envP, | |||||
| 422 | xmlrpc_value ** const resultPP) { | |||||
| 423 | ||||||
| 424 | xmlrpc_env env; | |||||
| 425 | ||||||
| 426 | xmlrpc_env_init(&env); | |||||
| 427 | ||||||
| 428 | *resultPP = xmlrpc_string_new(&env, "undef"); | |||||
| 429 | if (env.fault_occurred) | |||||
| 430 | xmlrpc_faultf(envP, "Unable to construct 'undef'. %s", | |||||
| 431 | env.fault_string); | |||||
| 432 | ||||||
| 433 | xmlrpc_env_clean(&env); | |||||
| 434 | } | |||||
| 435 | ||||||
| 436 | ||||||
| 437 | ||||||
| 438 | static void | |||||
| 439 | buildSignatureValue(xmlrpc_env * const envP, | |||||
| 440 | struct xmlrpc_signature * const signatureP, | |||||
| 441 | xmlrpc_value ** const sigValuePP) { | |||||
| 442 | ||||||
| 443 | xmlrpc_value * sigValueP; | |||||
| 444 | unsigned int i; | |||||
| 445 | ||||||
| 446 | sigValueP = xmlrpc_array_new(envP); | |||||
| 447 | ||||||
| 448 | { | |||||
| 449 | xmlrpc_value * retTypeVP; | |||||
| 450 | ||||||
| 451 | retTypeVP = xmlrpc_string_new(envP, signatureP->retType); | |||||
| 452 | ||||||
| 453 | xmlrpc_array_append_item(envP, sigValueP, retTypeVP); | |||||
| 454 | ||||||
| 455 | xmlrpc_DECREF(retTypeVP); | |||||
| 456 | } | |||||
| 457 | for (i = 0; i < signatureP->argCount && !envP->fault_occurred; ++i) { | |||||
| 458 | xmlrpc_value * argTypeVP; | |||||
| 459 | ||||||
| 460 | argTypeVP = xmlrpc_string_new(envP, signatureP->argList[i]); | |||||
| 461 | if (!envP->fault_occurred) { | |||||
| 462 | xmlrpc_array_append_item(envP, sigValueP, argTypeVP); | |||||
| 463 | ||||||
| 464 | xmlrpc_DECREF(argTypeVP); | |||||
| 465 | } | |||||
| 466 | } | |||||
| 467 | ||||||
| 468 | if (envP->fault_occurred) | |||||
| 469 | xmlrpc_DECREF(sigValueP); | |||||
| 470 | ||||||
| 471 | *sigValuePP = sigValueP; | |||||
| 472 | } | |||||
| 473 | ||||||
| 474 | ||||||
| 475 | ||||||
| 476 | static void | |||||
| 477 | getSignatureList(xmlrpc_env * const envP, | |||||
| 478 | xmlrpc_registry * const registryP, | |||||
| 479 | const char * const methodName, | |||||
| 480 | xmlrpc_value ** const signatureListPP) { | |||||
| 481 | /*---------------------------------------------------------------------------- | |||||
| 482 | Get the signature list array for method named 'methodName' from registry | |||||
| 483 | 'registryP'. | |||||
| 484 | ||||||
| 485 | If there is no signature information for the method in the registry, | |||||
| 486 | return *signatureListPP == NULL. | |||||
| 487 | ||||||
| 488 | Nonexistent method is considered a failure. | |||||
| 489 | -----------------------------------------------------------------------------*/ | |||||
| 490 | xmlrpc_methodInfo * methodP; | |||||
| 491 | ||||||
| 492 | xmlrpc_methodListLookupByName(registryP->methodListP, methodName, | |||||
| 493 | &methodP); | |||||
| 494 | ||||||
| 495 | if (!methodP) | |||||
| 496 | xmlrpc_env_set_fault_formatted( | |||||
| 497 | envP, XMLRPC_NO_SUCH_METHOD_ERROR(-506), | |||||
| 498 | "Method '%s' does not exist", methodName); | |||||
| 499 | else { | |||||
| 500 | if (!methodP->signatureListP->firstSignatureP) | |||||
| 501 | *signatureListPP = NULL((void*)0); | |||||
| 502 | else { | |||||
| 503 | xmlrpc_value * signatureListP; | |||||
| 504 | ||||||
| 505 | signatureListP = xmlrpc_array_new(envP); | |||||
| 506 | ||||||
| 507 | if (!envP->fault_occurred) { | |||||
| 508 | struct xmlrpc_signature * signatureP; | |||||
| 509 | for (signatureP = methodP->signatureListP->firstSignatureP; | |||||
| 510 | signatureP && !envP->fault_occurred; | |||||
| 511 | signatureP = signatureP->nextP) { | |||||
| 512 | ||||||
| 513 | xmlrpc_value * signatureVP = NULL((void*)0); | |||||
| 514 | ||||||
| 515 | buildSignatureValue(envP, signatureP, &signatureVP); | |||||
| 516 | ||||||
| 517 | xmlrpc_array_append_item(envP, | |||||
| 518 | signatureListP, signatureVP); | |||||
| 519 | ||||||
| 520 | xmlrpc_DECREF(signatureVP); | |||||
| 521 | } | |||||
| 522 | if (envP->fault_occurred) | |||||
| 523 | xmlrpc_DECREF(signatureListP); | |||||
| 524 | } | |||||
| 525 | *signatureListPP = signatureListP; | |||||
| 526 | } | |||||
| 527 | } | |||||
| 528 | } | |||||
| 529 | ||||||
| 530 | ||||||
| 531 | ||||||
| 532 | /* Microsoft Visual C in debug mode produces code that complains about | |||||
| 533 | returning an undefined value from system_methodSignature(). It's a bogus | |||||
| 534 | complaint, because this function is defined to return nothing meaningful | |||||
| 535 | those cases. So we disable the check. | |||||
| 536 | */ | |||||
| 537 | #pragma runtime_checks("u", off) | |||||
| 538 | ||||||
| 539 | ||||||
| 540 | ||||||
| 541 | static xmlrpc_value * | |||||
| 542 | system_methodSignature(xmlrpc_env * const envP, | |||||
| 543 | xmlrpc_value * const paramArrayP, | |||||
| 544 | void * const serverInfo, | |||||
| 545 | void * const callInfo ATTR_UNUSED__attribute__((__unused__))) { | |||||
| 546 | ||||||
| 547 | xmlrpc_registry * const registryP = (xmlrpc_registry *) serverInfo; | |||||
| 548 | ||||||
| 549 | xmlrpc_value * retvalP; | |||||
| 550 | const char * methodName; | |||||
| 551 | xmlrpc_env env; | |||||
| 552 | ||||||
| 553 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 553); while (0); | |||||
| 554 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 554); while (0); | |||||
| 555 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 555); while (0); | |||||
| 556 | ||||||
| 557 | xmlrpc_env_init(&env); | |||||
| 558 | ||||||
| 559 | /* Turn our arguments into something more useful. */ | |||||
| 560 | xmlrpc_decompose_value(&env, paramArrayP, "(s)", &methodName); | |||||
| 561 | if (env.fault_occurred) | |||||
| 562 | xmlrpc_env_set_fault_formatted( | |||||
| 563 | envP, env.fault_code, | |||||
| 564 | "Invalid parameter list. %s", env.fault_string); | |||||
| 565 | else { | |||||
| 566 | if (!registryP->introspectionEnabled) | |||||
| 567 | xmlrpc_env_set_fault(envP, XMLRPC_INTROSPECTION_DISABLED_ERROR(-508), | |||||
| 568 | "Introspection disabled on this server"); | |||||
| 569 | else { | |||||
| 570 | xmlrpc_value * signatureListP; | |||||
| 571 | ||||||
| 572 | getSignatureList(envP, registryP, methodName, &signatureListP); | |||||
| 573 | ||||||
| 574 | if (!envP->fault_occurred) { | |||||
| 575 | if (signatureListP) | |||||
| 576 | retvalP = signatureListP; | |||||
| 577 | else | |||||
| 578 | buildNoSigSuppliedResult(envP, &retvalP); | |||||
| 579 | } | |||||
| 580 | } | |||||
| 581 | xmlrpc_strfree(methodName); | |||||
| 582 | } | |||||
| 583 | xmlrpc_env_clean(&env); | |||||
| 584 | ||||||
| 585 | return retvalP; | |||||
| 586 | } | |||||
| 587 | ||||||
| 588 | ||||||
| 589 | ||||||
| 590 | #pragma runtime_checks("u", restore) | |||||
| 591 | ||||||
| 592 | ||||||
| 593 | ||||||
| 594 | static struct systemMethodReg const methodMethodSignature = { | |||||
| 595 | "system.methodSignature", | |||||
| 596 | &system_methodSignature, | |||||
| 597 | "A:s", | |||||
| 598 | "Given the name of a method, return an array of legal signatures. " | |||||
| 599 | "Each signature is an array of strings. The first item of each signature " | |||||
| 600 | "is the return type, and any others items are parameter types.", | |||||
| 601 | }; | |||||
| 602 | ||||||
| 603 | ||||||
| 604 | ||||||
| 605 | ||||||
| 606 | /*========================================================================= | |||||
| 607 | system.shutdown | |||||
| 608 | ==========================================================================*/ | |||||
| 609 | ||||||
| 610 | static xmlrpc_value * | |||||
| 611 | system_shutdown(xmlrpc_env * const envP, | |||||
| 612 | xmlrpc_value * const paramArrayP, | |||||
| 613 | void * const serverInfo, | |||||
| 614 | void * const callInfo) { | |||||
| 615 | ||||||
| 616 | xmlrpc_registry * const registryP = (xmlrpc_registry *) serverInfo; | |||||
| 617 | ||||||
| 618 | xmlrpc_value * retvalP; | |||||
| 619 | const char * comment; | |||||
| 620 | xmlrpc_env env; | |||||
| 621 | ||||||
| 622 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 622); while (0); | |||||
| 623 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 623); while (0); | |||||
| 624 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 624); while (0); | |||||
| 625 | ||||||
| 626 | xmlrpc_env_init(&env); | |||||
| 627 | ||||||
| 628 | /* Turn our arguments into something more useful. */ | |||||
| 629 | xmlrpc_decompose_value(&env, paramArrayP, "(s)", &comment); | |||||
| 630 | if (env.fault_occurred) | |||||
| 631 | xmlrpc_env_set_fault_formatted( | |||||
| 632 | envP, env.fault_code, | |||||
| 633 | "Invalid parameter list. %s", env.fault_string); | |||||
| 634 | else { | |||||
| 635 | if (!registryP->shutdownServerFn) | |||||
| 636 | xmlrpc_env_set_fault( | |||||
| 637 | envP, 0, "This server program is not capable of " | |||||
| 638 | "shutting down"); | |||||
| 639 | else { | |||||
| 640 | registryP->shutdownServerFn( | |||||
| 641 | &env, registryP->shutdownContext, comment, callInfo); | |||||
| 642 | ||||||
| 643 | if (env.fault_occurred) | |||||
| 644 | xmlrpc_env_set_fault(envP, env.fault_code, env.fault_string); | |||||
| 645 | else { | |||||
| 646 | retvalP = xmlrpc_int_new(&env, 0); | |||||
| 647 | ||||||
| 648 | if (env.fault_occurred) | |||||
| 649 | xmlrpc_faultf(envP, | |||||
| 650 | "Failed to construct return value. %s", | |||||
| 651 | env.fault_string); | |||||
| 652 | } | |||||
| 653 | } | |||||
| 654 | xmlrpc_strfree(comment); | |||||
| 655 | } | |||||
| 656 | xmlrpc_env_clean(&env); | |||||
| 657 | ||||||
| 658 | return retvalP; | |||||
| 659 | } | |||||
| 660 | ||||||
| 661 | ||||||
| 662 | ||||||
| 663 | static struct systemMethodReg const methodShutdown = { | |||||
| 664 | "system.shutdown", | |||||
| 665 | &system_shutdown, | |||||
| 666 | "i:s", | |||||
| 667 | "Shut down the server. Return code is always zero.", | |||||
| 668 | }; | |||||
| 669 | ||||||
| 670 | ||||||
| 671 | ||||||
| 672 | /*========================================================================= | |||||
| 673 | system.capabilities | |||||
| 674 | =========================================================================*/ | |||||
| 675 | ||||||
| 676 | static void | |||||
| 677 | constructCapabilities(xmlrpc_env * const envP, | |||||
| 678 | xmlrpc_registry * const registryP ATTR_UNUSED__attribute__((__unused__)), | |||||
| 679 | xmlrpc_value ** const capabilitiesPP) { | |||||
| 680 | ||||||
| 681 | *capabilitiesPP = | |||||
| 682 | xmlrpc_build_value( | |||||
| 683 | envP, "{s:s,s:i,s:i,s:i,s:i}", | |||||
| 684 | "facility", "xmlrpc-c", | |||||
| 685 | "version_major", XMLRPC_VERSION_MAJOR1, | |||||
| 686 | "version_minor", XMLRPC_VERSION_MINOR26, | |||||
| 687 | "version_point", XMLRPC_VERSION_POINT0, | |||||
| 688 | "protocol_version", 2 | |||||
| 689 | ); | |||||
| 690 | ||||||
| 691 | } | |||||
| 692 | ||||||
| 693 | ||||||
| 694 | ||||||
| 695 | static xmlrpc_value * | |||||
| 696 | system_capabilities(xmlrpc_env * const envP, | |||||
| 697 | xmlrpc_value * const paramArrayP, | |||||
| 698 | void * const serverInfo, | |||||
| 699 | void * const callInfo ATTR_UNUSED__attribute__((__unused__))) { | |||||
| 700 | ||||||
| 701 | xmlrpc_registry * const registryP = serverInfo; | |||||
| 702 | ||||||
| 703 | xmlrpc_value * retvalP; | |||||
| 704 | ||||||
| 705 | unsigned int paramCount; | |||||
| 706 | ||||||
| 707 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 707); while (0); | |||||
| 708 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 708); while (0); | |||||
| 709 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 709); while (0); | |||||
| 710 | ||||||
| 711 | paramCount = xmlrpc_array_size(envP, paramArrayP); | |||||
| 712 | ||||||
| 713 | if (paramCount > 0) | |||||
| 714 | xmlrpc_env_set_fault_formatted( | |||||
| 715 | envP, XMLRPC_INDEX_ERROR(-502), | |||||
| 716 | "There are no parameters. You supplied %u", paramCount); | |||||
| 717 | else | |||||
| 718 | constructCapabilities(envP, registryP, &retvalP); | |||||
| 719 | ||||||
| 720 | return retvalP; | |||||
| 721 | } | |||||
| 722 | ||||||
| 723 | ||||||
| 724 | ||||||
| 725 | static struct systemMethodReg const methodCapabilities = { | |||||
| 726 | "system.capabilities", | |||||
| 727 | &system_capabilities, | |||||
| 728 | "S:", | |||||
| 729 | "Return the capabilities of XML-RPC server. This includes the " | |||||
| 730 | "version number of the XML-RPC For C/C++ software" | |||||
| 731 | }; | |||||
| 732 | ||||||
| 733 | ||||||
| 734 | ||||||
| 735 | /*========================================================================= | |||||
| 736 | system.getCapabilities | |||||
| 737 | =========================================================================*/ | |||||
| 738 | ||||||
| 739 | /* This implements a standard. | |||||
| 740 | See http://tech.groups.yahoo.com/group/xml-rpc/message/2897 . | |||||
| 741 | */ | |||||
| 742 | ||||||
| 743 | static void | |||||
| 744 | listCapabilities(xmlrpc_env * const envP, | |||||
| 745 | xmlrpc_registry * const registryP ATTR_UNUSED__attribute__((__unused__)), | |||||
| 746 | xmlrpc_value ** const capabilitiesPP) { | |||||
| 747 | ||||||
| 748 | *capabilitiesPP = | |||||
| 749 | xmlrpc_build_value( | |||||
| 750 | envP, "{s:{s:s,s:i}}", | |||||
| 751 | "introspect", | |||||
| 752 | "specUrl", | |||||
| 753 | "http://xmlrpc-c.sourceforge.net/xmlrpc-c/introspection.html", | |||||
| 754 | "specVersion", | |||||
| 755 | 1 | |||||
| 756 | ); | |||||
| 757 | } | |||||
| 758 | ||||||
| 759 | ||||||
| 760 | ||||||
| 761 | static xmlrpc_value * | |||||
| 762 | system_getCapabilities(xmlrpc_env * const envP, | |||||
| 763 | xmlrpc_value * const paramArrayP, | |||||
| 764 | void * const serverInfo, | |||||
| 765 | void * const callInfo ATTR_UNUSED__attribute__((__unused__))) { | |||||
| 766 | ||||||
| 767 | xmlrpc_registry * const registryP = serverInfo; | |||||
| 768 | ||||||
| 769 | xmlrpc_value * retvalP; | |||||
| 770 | ||||||
| 771 | unsigned int paramCount; | |||||
| 772 | ||||||
| 773 | XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string == ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 773); while (0); | |||||
| 774 | XMLRPC_ASSERT_VALUE_OK(paramArrayP)do if (!((paramArrayP) != ((void*)0) && (paramArrayP) ->_type != XMLRPC_TYPE_DEAD)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/system_method.c" , 774); while (0); | |||||
| 775 | XMLRPC_ASSERT_PTR_OK(serverInfo)do if (!((serverInfo) != ((void*)0))) xmlrpc_assertion_failed ("../../../../libs/xmlrpc-c/src/system_method.c", 775); while (0); | |||||
| 776 | ||||||
| 777 | paramCount = xmlrpc_array_size(envP, paramArrayP); | |||||
| 778 | ||||||
| 779 | if (paramCount > 0) | |||||
| 780 | xmlrpc_env_set_fault_formatted( | |||||
| 781 | envP, XMLRPC_INDEX_ERROR(-502), | |||||
| 782 | "There are no parameters. You supplied %u", paramCount); | |||||
| 783 | else | |||||
| 784 | listCapabilities(envP, registryP, &retvalP); | |||||
| 785 | ||||||
| 786 | return retvalP; | |||||
| 787 | } | |||||
| 788 | ||||||
| 789 | ||||||
| 790 | ||||||
| 791 | static struct systemMethodReg const methodGetCapabilities = { | |||||
| 792 | "system.getCapabilities", | |||||
| 793 | &system_getCapabilities, | |||||
| 794 | "S:", | |||||
| 795 | "Return the list of standard capabilities of XML-RPC server. " | |||||
| 796 | "See http://tech.groups.yahoo.com/group/xml-rpc/message/2897" | |||||
| 797 | }; | |||||
| 798 | ||||||
| 799 | ||||||
| 800 | ||||||
| 801 | /*============================================================================ | |||||
| 802 | Installer of system methods | |||||
| 803 | ============================================================================*/ | |||||
| 804 | ||||||
| 805 | static void | |||||
| 806 | registerSystemMethod(xmlrpc_env * const envP, | |||||
| 807 | xmlrpc_registry * const registryP, | |||||
| 808 | struct systemMethodReg const methodReg) { | |||||
| 809 | ||||||
| 810 | xmlrpc_env env; | |||||
| 811 | xmlrpc_env_init(&env); | |||||
| 812 | ||||||
| 813 | xmlrpc_registry_add_method2( | |||||
| 814 | &env, registryP, methodReg.methodName, | |||||
| 815 | methodReg.methodFunction, | |||||
| 816 | methodReg.signatureString, methodReg.helpText, registryP); | |||||
| 817 | ||||||
| 818 | if (env.fault_occurred) | |||||
| 819 | xmlrpc_faultf(envP, "Failed to register '%s' system method. %s", | |||||
| 820 | methodReg.methodName, env.fault_string); | |||||
| 821 | ||||||
| 822 | xmlrpc_env_clean(&env); | |||||
| 823 | } | |||||
| 824 | ||||||
| 825 | ||||||
| 826 | ||||||
| 827 | void | |||||
| 828 | xmlrpc_installSystemMethods(xmlrpc_env * const envP, | |||||
| 829 | xmlrpc_registry * const registryP) { | |||||
| 830 | /*---------------------------------------------------------------------------- | |||||
| 831 | Install the built-in methods (system.*) into registry 'registryP'. | |||||
| 832 | -----------------------------------------------------------------------------*/ | |||||
| 833 | if (!envP->fault_occurred) | |||||
| 834 | registerSystemMethod(envP, registryP, methodListMethods); | |||||
| 835 | ||||||
| 836 | if (!envP->fault_occurred) | |||||
| 837 | registerSystemMethod(envP, registryP, methodMethodExist); | |||||
| 838 | ||||||
| 839 | if (!envP->fault_occurred) | |||||
| 840 | registerSystemMethod(envP, registryP, methodMethodHelp); | |||||
| 841 | ||||||
| 842 | if (!envP->fault_occurred) | |||||
| 843 | registerSystemMethod(envP, registryP, methodMethodSignature); | |||||
| 844 | ||||||
| 845 | if (!envP->fault_occurred) | |||||
| 846 | registerSystemMethod(envP, registryP, methodMulticall); | |||||
| 847 | ||||||
| 848 | if (!envP->fault_occurred) | |||||
| 849 | registerSystemMethod(envP, registryP, methodShutdown); | |||||
| 850 | ||||||
| 851 | if (!envP->fault_occurred) | |||||
| 852 | registerSystemMethod(envP, registryP, methodCapabilities); | |||||
| 853 | ||||||
| 854 | if (!envP->fault_occurred) | |||||
| 855 | registerSystemMethod(envP, registryP, methodGetCapabilities); | |||||
| 856 | } | |||||
| 857 | ||||||
| 858 | ||||||
| 859 | ||||||
| 860 | /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. | |||||
| 861 | ** Copyright (C) 2001 by Eric Kidd. All rights reserved. | |||||
| 862 | ** Copyright (C) 2001 by Luke Howard. All rights reserved. | |||||
| 863 | ** | |||||
| 864 | ** Redistribution and use in source and binary forms, with or without | |||||
| 865 | ** modification, are permitted provided that the following conditions | |||||
| 866 | ** are met: | |||||
| 867 | ** 1. Redistributions of source code must retain the above copyright | |||||
| 868 | ** notice, this list of conditions and the following disclaimer. | |||||
| 869 | ** 2. Redistributions in binary form must reproduce the above copyright | |||||
| 870 | ** notice, this list of conditions and the following disclaimer in the | |||||
| 871 | ** documentation and/or other materials provided with the distribution. | |||||
| 872 | ** 3. The name of the author may not be used to endorse or promote products | |||||
| 873 | ** derived from this software without specific prior written permission. | |||||
| 874 | ** | |||||
| 875 | ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
| 876 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| 877 | ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| 878 | ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
| 879 | ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
| 880 | ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
| 881 | ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
| 882 | ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
| 883 | ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
| 884 | ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
| 885 | ** SUCH DAMAGE. */ | |||||
| 886 |