File: | src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/system_method.c |
Location: | line 786, column 5 |
Description: | Undefined or garbage value returned to caller |
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 |