xmlrpc_registry.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
  2. ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
  3. ** Copyright (C) 2001 by Luke Howard. All rights reserved.
  4. **
  5. ** Redistribution and use in source and binary forms, with or without
  6. ** modification, are permitted provided that the following conditions
  7. ** are met:
  8. ** 1. Redistributions of source code must retain the above copyright
  9. ** notice, this list of conditions and the following disclaimer.
  10. ** 2. Redistributions in binary form must reproduce the above copyright
  11. ** notice, this list of conditions and the following disclaimer in the
  12. ** documentation and/or other materials provided with the distribution.
  13. ** 3. The name of the author may not be used to endorse or promote products
  14. ** derived from this software without specific prior written permission.
  15. **
  16. ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  17. ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  20. ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22. ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23. ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. ** SUCH DAMAGE. */
  27. #include "xmlrpc_config.h"
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include "xmlrpc.h"
  31. #include "xmlrpc_server.h"
  32. #include "xmlrpc_int.h"
  33. /*=========================================================================
  34. ** XML-RPC Server Method Registry
  35. **=========================================================================
  36. ** A method registry maintains a list of functions, and handles
  37. ** dispatching. To build an XML-RPC server, just add a communications
  38. ** protocol. :-)
  39. */
  40. static void
  41. install_system_methods (xmlrpc_env *env, xmlrpc_registry *registry);
  42. xmlrpc_registry *
  43. xmlrpc_registry_new(xmlrpc_env *env) {
  44. xmlrpc_value *methods;
  45. xmlrpc_registry *registry;
  46. int registry_valid;
  47. XMLRPC_ASSERT_ENV_OK(env);
  48. /* Error-handling preconditions. */
  49. registry = NULL;
  50. registry_valid = 0;
  51. /* Allocate our memory. */
  52. methods = xmlrpc_struct_new(env);
  53. XMLRPC_FAIL_IF_FAULT(env);
  54. registry = (xmlrpc_registry*) malloc(sizeof(xmlrpc_registry));
  55. XMLRPC_FAIL_IF_NULL(registry, env, XMLRPC_INTERNAL_ERROR,
  56. "Could not allocate memory for registry");
  57. /* Set everything up. */
  58. registry->_introspection_enabled = 1;
  59. registry->_methods = methods;
  60. registry->_default_method = NULL;
  61. registry->_preinvoke_method = NULL;
  62. registry_valid = 1;
  63. /* Install our system methods. */
  64. install_system_methods(env, registry);
  65. XMLRPC_FAIL_IF_FAULT(env);
  66. cleanup:
  67. if (env->fault_occurred) {
  68. if (registry_valid) {
  69. xmlrpc_registry_free(registry);
  70. } else {
  71. if (methods)
  72. xmlrpc_DECREF(methods);
  73. if (registry)
  74. free(registry);
  75. }
  76. return NULL;
  77. }
  78. return registry;
  79. }
  80. void
  81. xmlrpc_registry_free(xmlrpc_registry * registry) {
  82. XMLRPC_ASSERT_PTR_OK(registry);
  83. XMLRPC_ASSERT(registry->_methods != XMLRPC_BAD_POINTER);
  84. xmlrpc_DECREF(registry->_methods);
  85. registry->_methods = XMLRPC_BAD_POINTER;
  86. if (registry->_default_method != NULL)
  87. xmlrpc_DECREF(registry->_default_method);
  88. if (registry->_preinvoke_method != NULL)
  89. xmlrpc_DECREF(registry->_preinvoke_method);
  90. free(registry);
  91. }
  92. /*=========================================================================
  93. ** xmlrpc_registry_disable_introspection
  94. **=========================================================================
  95. ** See xmlrpc.h for more documentation.
  96. */
  97. void
  98. xmlrpc_registry_disable_introspection(xmlrpc_registry * registry) {
  99. XMLRPC_ASSERT_PTR_OK(registry);
  100. registry->_introspection_enabled = 0;
  101. }
  102. /*=========================================================================
  103. ** xmlrpc_registry_add_method
  104. **=========================================================================
  105. ** See xmlrpc.h for more documentation.
  106. */
  107. void
  108. xmlrpc_registry_add_method(xmlrpc_env *env,
  109. xmlrpc_registry *registry,
  110. const char *host,
  111. const char *method_name,
  112. xmlrpc_method method,
  113. void *user_data) {
  114. xmlrpc_registry_add_method_w_doc (env, registry, host, method_name,
  115. method, user_data, "?",
  116. "No help is available for this method.");
  117. }
  118. void
  119. xmlrpc_registry_add_method_w_doc(xmlrpc_env *env,
  120. xmlrpc_registry *registry,
  121. const char *host,
  122. const char *method_name,
  123. xmlrpc_method method,
  124. void *user_data,
  125. const char *signature,
  126. const char *help) {
  127. xmlrpc_value *method_info;
  128. XMLRPC_ASSERT_ENV_OK(env);
  129. XMLRPC_ASSERT_PTR_OK(registry);
  130. XMLRPC_ASSERT(host == NULL);
  131. XMLRPC_ASSERT_PTR_OK(method_name);
  132. XMLRPC_ASSERT_PTR_OK(method);
  133. /* Store our method and user data into our hash table. */
  134. method_info = xmlrpc_build_value(env, "(ppss)", (void*) method, user_data,
  135. signature, help);
  136. XMLRPC_FAIL_IF_FAULT(env);
  137. xmlrpc_struct_set_value(env, registry->_methods, method_name, method_info);
  138. XMLRPC_FAIL_IF_FAULT(env);
  139. cleanup:
  140. if (method_info)
  141. xmlrpc_DECREF(method_info);
  142. }
  143. /*=========================================================================
  144. ** xmlrpc_registry_set_default_method
  145. **=========================================================================
  146. ** See xmlrpc.h for more documentation.
  147. */
  148. void
  149. xmlrpc_registry_set_default_method(xmlrpc_env *env,
  150. xmlrpc_registry *registry,
  151. xmlrpc_default_method handler,
  152. void *user_data) {
  153. xmlrpc_value *method_info;
  154. XMLRPC_ASSERT_ENV_OK(env);
  155. XMLRPC_ASSERT_PTR_OK(registry);
  156. XMLRPC_ASSERT_PTR_OK(handler);
  157. /* Store our method and user data into our hash table. */
  158. method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data);
  159. XMLRPC_FAIL_IF_FAULT(env);
  160. /* Dispose of any pre-existing default method and install ours. */
  161. if (registry->_default_method)
  162. xmlrpc_DECREF(registry->_default_method);
  163. registry->_default_method = method_info;
  164. cleanup:
  165. if (env->fault_occurred) {
  166. if (method_info)
  167. xmlrpc_DECREF(method_info);
  168. }
  169. }
  170. /*=========================================================================
  171. ** xmlrpc_registry_set_preinvoke_method
  172. **=========================================================================
  173. ** See xmlrpc.h for more documentation.
  174. */
  175. void
  176. xmlrpc_registry_set_preinvoke_method(xmlrpc_env *env,
  177. xmlrpc_registry *registry,
  178. xmlrpc_preinvoke_method handler,
  179. void *user_data) {
  180. xmlrpc_value *method_info;
  181. XMLRPC_ASSERT_ENV_OK(env);
  182. XMLRPC_ASSERT_PTR_OK(registry);
  183. XMLRPC_ASSERT_PTR_OK(handler);
  184. /* Store our method and user data into our hash table. */
  185. method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data);
  186. XMLRPC_FAIL_IF_FAULT(env);
  187. /* Dispose of any pre-existing preinvoke method and install ours. */
  188. if (registry->_preinvoke_method)
  189. xmlrpc_DECREF(registry->_preinvoke_method);
  190. registry->_preinvoke_method = method_info;
  191. cleanup:
  192. if (env->fault_occurred) {
  193. if (method_info)
  194. xmlrpc_DECREF(method_info);
  195. }
  196. }
  197. /*=========================================================================
  198. ** dispatch_call
  199. **=========================================================================
  200. ** An internal method which actually does the dispatch. This may get
  201. ** prettified and exported at some point in the future.
  202. */
  203. static void
  204. callPreinvokeMethodIfAny(xmlrpc_env * const envP,
  205. xmlrpc_registry * const registryP,
  206. const char * const methodName,
  207. xmlrpc_value * const paramArrayP) {
  208. /* Get the preinvoke method, if it is set. */
  209. if (registryP->_preinvoke_method) {
  210. xmlrpc_preinvoke_method preinvoke_method;
  211. void * user_data;
  212. xmlrpc_parse_value(envP, registryP->_preinvoke_method, "(pp)",
  213. &preinvoke_method, &user_data);
  214. if (!envP->fault_occurred)
  215. (*preinvoke_method)(envP, methodName,
  216. paramArrayP, user_data);
  217. }
  218. }
  219. static void
  220. callDefaultMethod(xmlrpc_env * const envP,
  221. xmlrpc_value * const defaultMethodInfo,
  222. const char * const methodName,
  223. xmlrpc_value * const paramArrayP,
  224. xmlrpc_value ** const resultPP) {
  225. xmlrpc_default_method default_method;
  226. void * user_data;
  227. xmlrpc_parse_value(envP, defaultMethodInfo, "(pp)",
  228. &default_method, &user_data);
  229. if (!envP->fault_occurred)
  230. *resultPP = (*default_method)(envP, NULL, methodName,
  231. paramArrayP, user_data);
  232. }
  233. static void
  234. callNamedMethod(xmlrpc_env * const envP,
  235. xmlrpc_value * const methodInfo,
  236. xmlrpc_value * const paramArrayP,
  237. xmlrpc_value ** const resultPP) {
  238. xmlrpc_method method;
  239. void * user_data;
  240. xmlrpc_parse_value(envP, methodInfo, "(pp*)", &method, &user_data);
  241. if (!envP->fault_occurred)
  242. *resultPP = (*method)(envP, paramArrayP, user_data);
  243. }
  244. static void
  245. dispatch_call(xmlrpc_env * const envP,
  246. xmlrpc_registry * const registryP,
  247. const char * const methodName,
  248. xmlrpc_value * const paramArrayP,
  249. xmlrpc_value ** const resultPP) {
  250. callPreinvokeMethodIfAny(envP, registryP, methodName, paramArrayP);
  251. if (!envP->fault_occurred) {
  252. xmlrpc_value * method_info;
  253. /* Look up the method info for the named method. */
  254. xmlrpc_struct_find_value(envP, registryP->_methods,
  255. methodName, &method_info);
  256. if (!envP->fault_occurred) {
  257. if (method_info)
  258. callNamedMethod(envP, method_info, paramArrayP, resultPP);
  259. else {
  260. if (registryP->_default_method)
  261. callDefaultMethod(envP, registryP->_default_method,
  262. methodName, paramArrayP,
  263. resultPP);
  264. else {
  265. /* No matching method, and no default. */
  266. xmlrpc_env_set_fault_formatted(
  267. envP, XMLRPC_NO_SUCH_METHOD_ERROR,
  268. "Method '%s' not defined", methodName);
  269. }
  270. }
  271. }
  272. }
  273. /* For backward compatibility, for sloppy users: */
  274. if (envP->fault_occurred)
  275. *resultPP = NULL;
  276. }
  277. /*=========================================================================
  278. ** xmlrpc_registry_process_call
  279. **=========================================================================
  280. **
  281. */
  282. xmlrpc_mem_block *
  283. xmlrpc_registry_process_call(xmlrpc_env * const envP,
  284. xmlrpc_registry * const registryP,
  285. const char * const host ATTR_UNUSED,
  286. const char * const xml_data,
  287. size_t const xml_len) {
  288. xmlrpc_mem_block * output;
  289. XMLRPC_ASSERT_ENV_OK(envP);
  290. XMLRPC_ASSERT_PTR_OK(xml_data);
  291. xmlrpc_traceXml("XML-RPC CALL", xml_data, xml_len);
  292. /* Allocate our output buffer.
  293. ** If this fails, we need to die in a special fashion. */
  294. output = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
  295. if (!envP->fault_occurred) {
  296. const char * methodName;
  297. xmlrpc_value * paramArray;
  298. xmlrpc_env fault;
  299. xmlrpc_env_init(&fault);
  300. xmlrpc_parse_call(&fault, xml_data, xml_len,
  301. &methodName, &paramArray);
  302. if (!fault.fault_occurred) {
  303. xmlrpc_value * result;
  304. dispatch_call(&fault, registryP, methodName, paramArray, &result);
  305. if (!fault.fault_occurred) {
  306. xmlrpc_serialize_response(envP, output, result);
  307. /* A comment here used to say that
  308. xmlrpc_serialize_response() could fail and "leave
  309. stuff in the buffer." Don't know what that means,
  310. but it sounds like something that needs to be
  311. fixed. The old code aborted the program here if
  312. xmlrpc_serialize_repsonse() failed. 04.11.17
  313. */
  314. xmlrpc_DECREF(result);
  315. }
  316. xmlrpc_strfree(methodName);
  317. xmlrpc_DECREF(paramArray);
  318. }
  319. if (!envP->fault_occurred && fault.fault_occurred)
  320. xmlrpc_serialize_fault(envP, output, &fault);
  321. xmlrpc_env_clean(&fault);
  322. if (envP->fault_occurred)
  323. XMLRPC_MEMBLOCK_FREE(char, output);
  324. else
  325. xmlrpc_traceXml("XML-RPC RESPONSE",
  326. XMLRPC_MEMBLOCK_CONTENTS(char, output),
  327. XMLRPC_MEMBLOCK_SIZE(char, output));
  328. }
  329. return output;
  330. }
  331. /*=========================================================================
  332. ** system.multicall
  333. **=========================================================================
  334. ** Low-tech support for transparent, boxed methods.
  335. */
  336. static char *multicall_help =
  337. "Process an array of calls, and return an array of results. Calls should "
  338. "be structs of the form {'methodName': string, 'params': array}. Each "
  339. "result will either be a single-item array containg the result value, or "
  340. "a struct of the form {'faultCode': int, 'faultString': string}. This "
  341. "is useful when you need to make lots of small calls without lots of "
  342. "round trips.";
  343. static xmlrpc_value *
  344. call_one_method(xmlrpc_env *env, xmlrpc_registry *registry,
  345. xmlrpc_value *method_info) {
  346. xmlrpc_value *result_val, *result;
  347. char *method_name;
  348. xmlrpc_value *param_array;
  349. /* Error-handling preconditions. */
  350. result = result_val = NULL;
  351. /* Extract our method name and parameters. */
  352. xmlrpc_parse_value(env, method_info, "{s:s,s:A,*}",
  353. "methodName", &method_name,
  354. "params", &param_array);
  355. XMLRPC_FAIL_IF_FAULT(env);
  356. /* Watch out for a deep recursion attack. */
  357. if (strcmp(method_name, "system.multicall") == 0)
  358. XMLRPC_FAIL(env, XMLRPC_REQUEST_REFUSED_ERROR,
  359. "Recursive system.multicall strictly forbidden");
  360. /* Perform the call. */
  361. dispatch_call(env, registry, method_name, param_array, &result_val);
  362. XMLRPC_FAIL_IF_FAULT(env);
  363. /* Build our one-item result array. */
  364. result = xmlrpc_build_value(env, "(V)", result_val);
  365. XMLRPC_FAIL_IF_FAULT(env);
  366. cleanup:
  367. if (result_val)
  368. xmlrpc_DECREF(result_val);
  369. if (env->fault_occurred) {
  370. if (result)
  371. xmlrpc_DECREF(result);
  372. return NULL;
  373. }
  374. return result;
  375. }
  376. static xmlrpc_value *
  377. system_multicall(xmlrpc_env *env,
  378. xmlrpc_value *param_array,
  379. void *user_data) {
  380. xmlrpc_registry *registry;
  381. xmlrpc_value *methlist, *methinfo, *results, *result;
  382. size_t size, i;
  383. xmlrpc_env env2;
  384. XMLRPC_ASSERT_ENV_OK(env);
  385. XMLRPC_ASSERT_VALUE_OK(param_array);
  386. XMLRPC_ASSERT_PTR_OK(user_data);
  387. /* Error-handling preconditions. */
  388. results = result = NULL;
  389. xmlrpc_env_init(&env2);
  390. /* Turn our arguments into something more useful. */
  391. registry = (xmlrpc_registry*) user_data;
  392. xmlrpc_parse_value(env, param_array, "(A)", &methlist);
  393. XMLRPC_FAIL_IF_FAULT(env);
  394. /* Create an empty result list. */
  395. results = xmlrpc_build_value(env, "()");
  396. XMLRPC_FAIL_IF_FAULT(env);
  397. /* Loop over our input list, calling each method in turn. */
  398. size = xmlrpc_array_size(env, methlist);
  399. XMLRPC_ASSERT_ENV_OK(env);
  400. for (i = 0; i < size; i++) {
  401. methinfo = xmlrpc_array_get_item(env, methlist, i);
  402. XMLRPC_ASSERT_ENV_OK(env);
  403. /* Call our method. */
  404. xmlrpc_env_clean(&env2);
  405. xmlrpc_env_init(&env2);
  406. result = call_one_method(&env2, registry, methinfo);
  407. /* Turn any fault into a structure. */
  408. if (env2.fault_occurred) {
  409. XMLRPC_ASSERT(result == NULL);
  410. result =
  411. xmlrpc_build_value(env, "{s:i,s:s}",
  412. "faultCode", (xmlrpc_int32) env2.fault_code,
  413. "faultString", env2.fault_string);
  414. XMLRPC_FAIL_IF_FAULT(env);
  415. }
  416. /* Append this method result to our master array. */
  417. xmlrpc_array_append_item(env, results, result);
  418. xmlrpc_DECREF(result);
  419. result = NULL;
  420. XMLRPC_FAIL_IF_FAULT(env);
  421. }
  422. cleanup:
  423. xmlrpc_env_clean(&env2);
  424. if (result)
  425. xmlrpc_DECREF(result);
  426. if (env->fault_occurred) {
  427. if (results)
  428. xmlrpc_DECREF(results);
  429. return NULL;
  430. }
  431. return results;
  432. }
  433. /*=========================================================================
  434. ** system.listMethods
  435. **=========================================================================
  436. ** List all available methods by name.
  437. */
  438. static char *listMethods_help =
  439. "Return an array of all available XML-RPC methods on this server.";
  440. static xmlrpc_value *
  441. system_listMethods(xmlrpc_env *env,
  442. xmlrpc_value *param_array,
  443. void *user_data) {
  444. xmlrpc_registry *registry;
  445. xmlrpc_value *method_names, *method_name, *method_info;
  446. size_t size, i;
  447. XMLRPC_ASSERT_ENV_OK(env);
  448. XMLRPC_ASSERT_VALUE_OK(param_array);
  449. XMLRPC_ASSERT_PTR_OK(user_data);
  450. /* Error-handling preconditions. */
  451. method_names = NULL;
  452. /* Turn our arguments into something more useful. */
  453. registry = (xmlrpc_registry*) user_data;
  454. xmlrpc_parse_value(env, param_array, "()");
  455. XMLRPC_FAIL_IF_FAULT(env);
  456. /* Make sure we're allowed to introspect. */
  457. if (!registry->_introspection_enabled)
  458. XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
  459. "Introspection disabled for security reasons");
  460. /* Iterate over all the methods in the registry, adding their names
  461. ** to a list. */
  462. method_names = xmlrpc_build_value(env, "()");
  463. XMLRPC_FAIL_IF_FAULT(env);
  464. size = xmlrpc_struct_size(env, registry->_methods);
  465. XMLRPC_FAIL_IF_FAULT(env);
  466. for (i = 0; i < size; i++) {
  467. xmlrpc_struct_get_key_and_value(env, registry->_methods, i,
  468. &method_name, &method_info);
  469. XMLRPC_FAIL_IF_FAULT(env);
  470. xmlrpc_array_append_item(env, method_names, method_name);
  471. XMLRPC_FAIL_IF_FAULT(env);
  472. }
  473. cleanup:
  474. if (env->fault_occurred) {
  475. if (method_names)
  476. xmlrpc_DECREF(method_names);
  477. return NULL;
  478. }
  479. return method_names;
  480. }
  481. /*=========================================================================
  482. ** system.methodHelp
  483. **=========================================================================
  484. ** Get the help string for a particular method.
  485. */
  486. static char *methodHelp_help =
  487. "Given the name of a method, return a help string.";
  488. static xmlrpc_value *
  489. system_methodHelp(xmlrpc_env *env,
  490. xmlrpc_value *param_array,
  491. void *user_data) {
  492. xmlrpc_registry *registry;
  493. char *method_name;
  494. xmlrpc_value *ignored1, *ignored2, *ignored3, *help;
  495. XMLRPC_ASSERT_ENV_OK(env);
  496. XMLRPC_ASSERT_VALUE_OK(param_array);
  497. XMLRPC_ASSERT_PTR_OK(user_data);
  498. /* Turn our arguments into something more useful. */
  499. registry = (xmlrpc_registry*) user_data;
  500. xmlrpc_parse_value(env, param_array, "(s)", &method_name);
  501. XMLRPC_FAIL_IF_FAULT(env);
  502. /* Make sure we're allowed to introspect. */
  503. if (!registry->_introspection_enabled)
  504. XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
  505. "Introspection disabled for security reasons");
  506. /* Get our documentation string. */
  507. xmlrpc_parse_value(env, registry->_methods, "{s:(VVVV*),*}",
  508. method_name, &ignored1, &ignored2, &ignored3, &help);
  509. XMLRPC_FAIL_IF_FAULT(env);
  510. cleanup:
  511. if (env->fault_occurred)
  512. return NULL;
  513. xmlrpc_INCREF(help);
  514. return help;
  515. }
  516. /*=========================================================================
  517. ** system.methodSignature
  518. **=========================================================================
  519. ** Return an array of arrays describing possible signatures for this
  520. ** method.
  521. **
  522. ** XXX - This is the ugliest function in the entire library.
  523. */
  524. static char *methodSignature_help =
  525. "Given the name of a method, return an array of legal signatures. "
  526. "Each signature is an array of strings. The first item of each signature "
  527. "is the return type, and any others items are parameter types.";
  528. static char *bad_sig_str =
  529. "Application has incorrect method signature information";
  530. #define BAD_SIG(env) \
  531. XMLRPC_FAIL((env), XMLRPC_INTERNAL_ERROR, bad_sig_str);
  532. static xmlrpc_value *
  533. system_methodSignature(xmlrpc_env *env,
  534. xmlrpc_value *param_array,
  535. void *user_data) {
  536. xmlrpc_registry *registry;
  537. char *method_name;
  538. xmlrpc_value *ignored1, *ignored2, *ignored3;
  539. xmlrpc_value *item, *current, *result;
  540. int at_sig_start;
  541. char *sig, *code = 0;
  542. XMLRPC_ASSERT_ENV_OK(env);
  543. XMLRPC_ASSERT_VALUE_OK(param_array);
  544. XMLRPC_ASSERT_PTR_OK(user_data);
  545. /* Error-handling preconditions. */
  546. item = current = result = NULL;
  547. /* Turn our arguments into something more useful. */
  548. registry = (xmlrpc_registry*) user_data;
  549. xmlrpc_parse_value(env, param_array, "(s)", &method_name);
  550. XMLRPC_FAIL_IF_FAULT(env);
  551. /* Make sure we're allowed to introspect. */
  552. if (!registry->_introspection_enabled)
  553. XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
  554. "Introspection disabled for security reasons");
  555. /* Get our signature string. */
  556. xmlrpc_parse_value(env, registry->_methods, "{s:(VVsV*),*}",
  557. method_name, &ignored1, &ignored2, &sig, &ignored3);
  558. XMLRPC_FAIL_IF_FAULT(env);
  559. if (sig[0] == '?' && sig[1] == '\0') {
  560. /* No signature supplied. */
  561. result = xmlrpc_build_value(env, "s", "undef");
  562. XMLRPC_FAIL_IF_FAULT(env);
  563. } else {
  564. /* Build an array of arrays. */
  565. current = xmlrpc_build_value(env, "()");
  566. XMLRPC_FAIL_IF_FAULT(env);
  567. result = xmlrpc_build_value(env, "(V)", current);
  568. XMLRPC_FAIL_IF_FAULT(env);
  569. at_sig_start = 1;
  570. do {
  571. next_loop:
  572. /* Process the current code. */
  573. switch (*(sig++)) {
  574. case 'i': code = "int"; break;
  575. case 'b': code = "boolean"; break;
  576. case 'd': code = "double"; break;
  577. case 's': code = "string"; break;
  578. case '8': code = "dateTime.iso8601"; break;
  579. case '6': code = "base64"; break;
  580. case 'S': code = "struct"; break;
  581. case 'A': code = "array"; break;
  582. case ',':
  583. /* Start a new signature array. */
  584. if (at_sig_start)
  585. BAD_SIG(env);
  586. xmlrpc_DECREF(current);
  587. current = xmlrpc_build_value(env, "()");
  588. XMLRPC_FAIL_IF_FAULT(env);
  589. xmlrpc_array_append_item(env, result, current);
  590. XMLRPC_FAIL_IF_FAULT(env);
  591. at_sig_start = 1;
  592. goto next_loop;
  593. default:
  594. BAD_SIG(env);
  595. }
  596. /* Append the appropriate string to our current signature. */
  597. item = xmlrpc_build_value(env, "s", code);
  598. XMLRPC_FAIL_IF_FAULT(env);
  599. xmlrpc_array_append_item(env, current, item);
  600. xmlrpc_DECREF(item);
  601. item = NULL;
  602. XMLRPC_FAIL_IF_FAULT(env);
  603. /* Advance to the next code, and skip over ':' if necessary. */
  604. if (at_sig_start) {
  605. if (*sig != ':')
  606. BAD_SIG(env);
  607. sig++;
  608. at_sig_start = 0;
  609. }
  610. } while (*sig != '\0');
  611. }
  612. cleanup:
  613. if (item)
  614. xmlrpc_DECREF(item);
  615. if (current)
  616. xmlrpc_DECREF(current);
  617. if (env->fault_occurred) {
  618. if (result)
  619. xmlrpc_DECREF(result);
  620. return NULL;
  621. }
  622. return result;
  623. }
  624. /*=========================================================================
  625. ** install_system_methods
  626. **=========================================================================
  627. ** Install the standard methods under system.*.
  628. ** This particular function is highly experimental, and may disappear
  629. ** without warning.
  630. */
  631. static void
  632. install_system_methods(xmlrpc_env *env, xmlrpc_registry *registry) {
  633. xmlrpc_registry_add_method_w_doc(env, registry, NULL,
  634. "system.listMethods",
  635. &system_listMethods, registry,
  636. "A:", listMethods_help);
  637. XMLRPC_FAIL_IF_FAULT(env);
  638. xmlrpc_registry_add_method_w_doc(env, registry, NULL,
  639. "system.methodSignature",
  640. &system_methodSignature, registry,
  641. "A:s", methodSignature_help);
  642. XMLRPC_FAIL_IF_FAULT(env);
  643. xmlrpc_registry_add_method_w_doc(env, registry, NULL,
  644. "system.methodHelp",
  645. &system_methodHelp, registry,
  646. "s:s", methodHelp_help);
  647. XMLRPC_FAIL_IF_FAULT(env);
  648. xmlrpc_registry_add_method_w_doc(env, registry, NULL,
  649. "system.multicall",
  650. &system_multicall, registry,
  651. "A:A", multicall_help);
  652. XMLRPC_FAIL_IF_FAULT(env);
  653. cleanup:
  654. return;
  655. }