anastasis_api_redux_parse.c (68458B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020, 2021, 2022 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file reducer/anastasis_api_redux_parse.c 18 * @brief parse a reducer state from its JSON encoding 19 * @author Christian Grothoff 20 * 21 * Parsing is strict: every object is checked against the closed set of 22 * fields declared for it, so a typo or a field from a foreign reducer 23 * implementation is an error rather than something silently carried along. 24 * 25 * On any failure the partially built state is handed to 26 * ANASTASIS_REDUX_state_free_(), which is safe because every array length is 27 * assigned before the array is populated. 28 */ 29 #include "platform.h" 30 #include "anastasis_redux.h" 31 #include "anastasis_api_redux.h" 32 #include "anastasis_api_redux_state.h" 33 #include "validation.h" 34 #include <taler/taler_json_lib.h> 35 36 37 /** 38 * Buffer for the error detail returned by 39 * ANASTASIS_REDUX_state_parse_(). The reducer is single-threaded (it 40 * runs off the GNUnet scheduler), and the caller copies the detail into 41 * its error state immediately, so one static buffer is enough. 42 */ 43 static char parse_detail[256]; 44 45 46 /** 47 * Record @a field as the location of a parse error. 48 * 49 * @param where name of the enclosing object 50 * @param field offending field, may be NULL 51 * @return pointer to the formatted detail 52 */ 53 static const char * 54 set_detail (const char *where, 55 const char *field) 56 { 57 if (NULL == field) 58 GNUNET_snprintf (parse_detail, 59 sizeof (parse_detail), 60 "%s", 61 where); 62 else 63 GNUNET_snprintf (parse_detail, 64 sizeof (parse_detail), 65 "%s.%s", 66 where, 67 field); 68 return parse_detail; 69 } 70 71 72 /** 73 * Check that @a obj is an object and has no members beyond those listed 74 * in @a allowed. 75 * 76 * @param obj object to check 77 * @param where name of @a obj, for error reporting 78 * @param allowed NULL-terminated array of permitted field names 79 * @param[out] detail set to the offending field on failure 80 * @return #GNUNET_OK if @a obj is acceptable 81 */ 82 static enum GNUNET_GenericReturnValue 83 check_fields (const json_t *obj, 84 const char *where, 85 const char *const*allowed, 86 const char **detail) 87 { 88 const char *key; 89 json_t *val; 90 91 if (! json_is_object (obj)) 92 { 93 *detail = set_detail (where, 94 NULL); 95 return GNUNET_SYSERR; 96 } 97 json_object_foreach ((json_t *) obj, key, val) 98 { 99 bool found = false; 100 101 for (unsigned int i = 0; NULL != allowed[i]; i++) 102 if (0 == strcmp (key, 103 allowed[i])) 104 { 105 found = true; 106 break; 107 } 108 if (! found) 109 { 110 *detail = set_detail (where, 111 key); 112 return GNUNET_SYSERR; 113 } 114 } 115 return GNUNET_OK; 116 } 117 118 119 /** 120 * Duplicate @a s, or return NULL if @a s is NULL. 121 * 122 * @param s string to duplicate 123 * @return copy of @a s 124 */ 125 static char * 126 dup_or_null (const char *s) 127 { 128 if (NULL == s) 129 return NULL; 130 return GNUNET_strdup (s); 131 } 132 133 134 /** 135 * Take a reference to the i18n map @a obj, or return NULL. 136 * 137 * The reducer never looks inside a translation map; it only ever carries 138 * it from the resource files to the user interface. So there is nothing 139 * to type here, and the object is kept verbatim. 140 * 141 * @param obj object mapping language tags to strings, may be NULL 142 * @return new reference to @a obj, or NULL 143 */ 144 static json_t * 145 incref_or_null (const json_t *obj) 146 { 147 if (NULL == obj) 148 return NULL; 149 return json_incref ((json_t *) obj); 150 } 151 152 153 /** 154 * Parse the `continents` array. 155 * 156 * @param arr the array, may be NULL 157 * @param[out] common state to fill in 158 * @param[out] detail set to the offending field on failure 159 * @return #GNUNET_OK on success 160 */ 161 static enum GNUNET_GenericReturnValue 162 parse_continents (const json_t *arr, 163 struct ANASTASIS_ReduxCommon *common, 164 const char **detail) 165 { 166 static const char *const allowed[] = { 167 "name", 168 "name_i18n", 169 NULL 170 }; 171 size_t index; 172 json_t *val; 173 174 if (NULL == arr) 175 return GNUNET_OK; 176 if (! json_is_array (arr)) 177 { 178 *detail = set_detail ("continents", 179 NULL); 180 return GNUNET_SYSERR; 181 } 182 common->have_continents = true; 183 common->continents_len = (unsigned int) json_array_size (arr); 184 common->continents = GNUNET_new_array (common->continents_len, 185 struct ANASTASIS_ReduxContinent); 186 json_array_foreach (arr, index, val) 187 { 188 struct ANASTASIS_ReduxContinent *c = &common->continents[index]; 189 const char *name; 190 const json_t *i18n = NULL; 191 struct GNUNET_JSON_Specification spec[] = { 192 GNUNET_JSON_spec_string ("name", 193 &name), 194 GNUNET_JSON_spec_mark_optional ( 195 GNUNET_JSON_spec_object_const ("name_i18n", 196 &i18n), 197 NULL), 198 GNUNET_JSON_spec_end () 199 }; 200 201 if (json_is_string (val)) 202 { 203 /* hand-written states name continents directly */ 204 c->name = GNUNET_strdup (json_string_value (val)); 205 c->bare = true; 206 continue; 207 } 208 if (GNUNET_OK != 209 check_fields (val, 210 "continents", 211 allowed, 212 detail)) 213 return GNUNET_SYSERR; 214 if (GNUNET_OK != 215 GNUNET_JSON_parse (val, 216 spec, 217 NULL, NULL)) 218 { 219 *detail = set_detail ("continents", 220 "name"); 221 return GNUNET_SYSERR; 222 } 223 c->name = GNUNET_strdup (name); 224 c->name_i18n = incref_or_null (i18n); 225 } 226 return GNUNET_OK; 227 } 228 229 230 /** 231 * Parse the `countries` array. 232 * 233 * @param arr the array, may be NULL 234 * @param[out] common state to fill in 235 * @param[out] detail set to the offending field on failure 236 * @return #GNUNET_OK on success 237 */ 238 static enum GNUNET_GenericReturnValue 239 parse_countries (const json_t *arr, 240 struct ANASTASIS_ReduxCommon *common, 241 const char **detail) 242 { 243 static const char *const allowed[] = { 244 "code", 245 "name", 246 "continent", 247 "call_code", 248 "name_i18n", 249 "continent_i18n", 250 "currency", 251 NULL 252 }; 253 size_t index; 254 json_t *val; 255 256 if (NULL == arr) 257 return GNUNET_OK; 258 if (! json_is_array (arr)) 259 { 260 *detail = set_detail ("countries", 261 NULL); 262 return GNUNET_SYSERR; 263 } 264 common->have_countries = true; 265 common->countries_len = (unsigned int) json_array_size (arr); 266 common->countries = GNUNET_new_array (common->countries_len, 267 struct ANASTASIS_ReduxCountry); 268 json_array_foreach (arr, index, val) 269 { 270 struct ANASTASIS_ReduxCountry *c = &common->countries[index]; 271 const char *code; 272 const char *name; 273 const char *continent; 274 const char *call_code = NULL; 275 const char *currency = NULL; 276 const json_t *name_i18n = NULL; 277 const json_t *continent_i18n = NULL; 278 struct GNUNET_JSON_Specification spec[] = { 279 GNUNET_JSON_spec_string ("code", 280 &code), 281 GNUNET_JSON_spec_string ("name", 282 &name), 283 GNUNET_JSON_spec_string ("continent", 284 &continent), 285 GNUNET_JSON_spec_mark_optional ( 286 GNUNET_JSON_spec_string ("call_code", 287 &call_code), 288 NULL), 289 GNUNET_JSON_spec_mark_optional ( 290 GNUNET_JSON_spec_object_const ("name_i18n", 291 &name_i18n), 292 NULL), 293 GNUNET_JSON_spec_mark_optional ( 294 GNUNET_JSON_spec_object_const ("continent_i18n", 295 &continent_i18n), 296 NULL), 297 GNUNET_JSON_spec_mark_optional ( 298 GNUNET_JSON_spec_string ("currency", 299 ¤cy), 300 NULL), 301 GNUNET_JSON_spec_end () 302 }; 303 304 if (GNUNET_OK != 305 check_fields (val, 306 "countries", 307 allowed, 308 detail)) 309 return GNUNET_SYSERR; 310 if (GNUNET_OK != 311 GNUNET_JSON_parse (val, 312 spec, 313 NULL, NULL)) 314 { 315 *detail = set_detail ("countries", 316 NULL); 317 return GNUNET_SYSERR; 318 } 319 c->code = GNUNET_strdup (code); 320 c->name = GNUNET_strdup (name); 321 c->continent = GNUNET_strdup (continent); 322 c->call_code = dup_or_null (call_code); 323 c->currency = dup_or_null (currency); 324 c->name_i18n = incref_or_null (name_i18n); 325 c->continent_i18n = incref_or_null (continent_i18n); 326 } 327 return GNUNET_OK; 328 } 329 330 331 /** 332 * Parse the `required_attributes` array. 333 * 334 * @param arr the array, may be NULL 335 * @param[out] common state to fill in 336 * @param[out] detail set to the offending field on failure 337 * @return #GNUNET_OK on success 338 */ 339 static enum GNUNET_GenericReturnValue 340 parse_required_attributes (const json_t *arr, 341 struct ANASTASIS_ReduxCommon *common, 342 const char **detail) 343 { 344 static const char *const allowed[] = { 345 "type", 346 "name", 347 "label", 348 "widget", 349 "uuid", 350 "tooltip", 351 "label_i18n", 352 "validation-regex", 353 "validation-logic", 354 "autocomplete", 355 "optional", 356 NULL 357 }; 358 size_t index; 359 json_t *val; 360 361 if (NULL == arr) 362 return GNUNET_OK; 363 if (! json_is_array (arr)) 364 { 365 *detail = set_detail ("required_attributes", 366 NULL); 367 return GNUNET_SYSERR; 368 } 369 common->have_required_attributes = true; 370 common->required_attributes_len = (unsigned int) json_array_size (arr); 371 common->required_attributes 372 = GNUNET_new_array (common->required_attributes_len, 373 struct ANASTASIS_ReduxAttributeSpec); 374 json_array_foreach (arr, index, val) 375 { 376 struct ANASTASIS_ReduxAttributeSpec *a 377 = &common->required_attributes[index]; 378 const char *type; 379 const char *name; 380 const char *label; 381 const char *widget; 382 const char *uuid = NULL; 383 const char *tooltip = NULL; 384 const char *regex = NULL; 385 const char *logic = NULL; 386 const char *autocomplete = NULL; 387 const json_t *label_i18n = NULL; 388 bool no_optional; 389 struct GNUNET_JSON_Specification spec[] = { 390 GNUNET_JSON_spec_string ("type", 391 &type), 392 GNUNET_JSON_spec_string ("name", 393 &name), 394 GNUNET_JSON_spec_string ("label", 395 &label), 396 GNUNET_JSON_spec_string ("widget", 397 &widget), 398 GNUNET_JSON_spec_mark_optional ( 399 GNUNET_JSON_spec_string ("uuid", 400 &uuid), 401 NULL), 402 GNUNET_JSON_spec_mark_optional ( 403 GNUNET_JSON_spec_string ("tooltip", 404 &tooltip), 405 NULL), 406 GNUNET_JSON_spec_mark_optional ( 407 GNUNET_JSON_spec_string ("validation-regex", 408 ®ex), 409 NULL), 410 GNUNET_JSON_spec_mark_optional ( 411 GNUNET_JSON_spec_string ("validation-logic", 412 &logic), 413 NULL), 414 GNUNET_JSON_spec_mark_optional ( 415 GNUNET_JSON_spec_string ("autocomplete", 416 &autocomplete), 417 NULL), 418 GNUNET_JSON_spec_mark_optional ( 419 GNUNET_JSON_spec_object_const ("label_i18n", 420 &label_i18n), 421 NULL), 422 GNUNET_JSON_spec_mark_optional ( 423 GNUNET_JSON_spec_bool ("optional", 424 &a->optional), 425 &no_optional), 426 GNUNET_JSON_spec_end () 427 }; 428 429 if (GNUNET_OK != 430 check_fields (val, 431 "required_attributes", 432 allowed, 433 detail)) 434 return GNUNET_SYSERR; 435 if (GNUNET_OK != 436 GNUNET_JSON_parse (val, 437 spec, 438 NULL, NULL)) 439 { 440 *detail = set_detail ("required_attributes", 441 NULL); 442 return GNUNET_SYSERR; 443 } 444 a->type = GNUNET_strdup (type); 445 a->name = GNUNET_strdup (name); 446 a->label = GNUNET_strdup (label); 447 a->widget = GNUNET_strdup (widget); 448 a->uuid = dup_or_null (uuid); 449 a->tooltip = dup_or_null (tooltip); 450 a->validation_regex = dup_or_null (regex); 451 if ( (NULL != logic) && 452 (NULL == ANASTASIS_REDUX_validation_lookup_ (logic)) ) 453 { 454 /* reject unknown validation logic already here, so that it cannot even 455 be round-tripped through a state we hand back to the application */ 456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 457 "Validation function `%s' is not known\n", 458 logic); 459 *detail = set_detail ("required_attributes", 460 "validation-logic"); 461 return GNUNET_SYSERR; 462 } 463 a->validation_logic = dup_or_null (logic); 464 a->autocomplete = dup_or_null (autocomplete); 465 a->have_optional = ! no_optional; 466 a->label_i18n = incref_or_null (label_i18n); 467 } 468 return GNUNET_OK; 469 } 470 471 472 /** 473 * Parse one entry of the `authentication_providers` object. 474 * 475 * @param url the provider URL (the key) 476 * @param val the provider details (the value) 477 * @param[out] p provider entry to fill in 478 * @param[out] detail set to the offending field on failure 479 * @return #GNUNET_OK on success 480 */ 481 static enum GNUNET_GenericReturnValue 482 parse_provider (const char *url, 483 const json_t *val, 484 struct ANASTASIS_ReduxProvider *p, 485 const char **detail) 486 { 487 static const char *const allowed[] = { 488 "status", 489 "methods", 490 "annual_fee", 491 "truth_upload_fee", 492 "liability_limit", 493 "business_name", 494 "storage_limit_in_megabytes", 495 "provider_salt", 496 "http_status", 497 "error_code", 498 "currency", 499 NULL 500 }; 501 const char *status; 502 struct GNUNET_JSON_Specification sspec[] = { 503 GNUNET_JSON_spec_string ("status", 504 &status), 505 GNUNET_JSON_spec_end () 506 }; 507 508 ANASTASIS_REDUX_provider_url_set_ (&p->url, 509 url); 510 if (GNUNET_OK != 511 check_fields (val, 512 "authentication_providers", 513 allowed, 514 detail)) 515 return GNUNET_SYSERR; 516 if (GNUNET_OK != 517 GNUNET_JSON_parse (val, 518 sspec, 519 NULL, NULL)) 520 { 521 *detail = set_detail ("authentication_providers", 522 "status"); 523 return GNUNET_SYSERR; 524 } 525 if (0 == strcmp (status, 526 "not-contacted")) 527 { 528 p->status = ANASTASIS_RPS_NOT_CONTACTED; 529 return GNUNET_OK; 530 } 531 if (0 == strcmp (status, 532 "error")) 533 { 534 uint64_t ec = 0; 535 struct GNUNET_JSON_Specification espec[] = { 536 GNUNET_JSON_spec_mark_optional ( 537 GNUNET_JSON_spec_uint64 ("error_code", 538 &ec), 539 NULL), 540 GNUNET_JSON_spec_mark_optional ( 541 GNUNET_JSON_spec_uint32 ("http_status", 542 &p->error.http_status), 543 NULL), 544 GNUNET_JSON_spec_end () 545 }; 546 547 p->status = ANASTASIS_RPS_ERROR; 548 if (GNUNET_OK != 549 GNUNET_JSON_parse (val, 550 espec, 551 NULL, NULL)) 552 { 553 *detail = set_detail ("authentication_providers", 554 "error_code"); 555 return GNUNET_SYSERR; 556 } 557 p->error.ec = (enum TALER_ErrorCode) ec; 558 return GNUNET_OK; 559 } 560 if (0 == strcmp (status, 561 "ok")) 562 p->status = ANASTASIS_RPS_OK; 563 else if (0 == strcmp (status, 564 "disabled")) 565 p->status = ANASTASIS_RPS_DISABLED; 566 else 567 { 568 *detail = set_detail ("authentication_providers", 569 "status"); 570 return GNUNET_SYSERR; 571 } 572 573 /* Both "ok" and (usually) "disabled" carry the /config we obtained 574 earlier; a provider that was disabled before we ever talked to it 575 does not. */ 576 { 577 struct ANASTASIS_ReduxProviderConfig *cfg = &p->config; 578 const char *business_name; 579 const char *currency = NULL; 580 const json_t *methods; 581 bool no_config = false; 582 struct GNUNET_JSON_Specification cspec[] = { 583 GNUNET_JSON_spec_array_const ("methods", 584 &methods), 585 TALER_JSON_spec_amount_any ("annual_fee", 586 &cfg->annual_fee), 587 TALER_JSON_spec_amount_any ("truth_upload_fee", 588 &cfg->truth_upload_fee), 589 TALER_JSON_spec_amount_any ("liability_limit", 590 &cfg->liability_limit), 591 GNUNET_JSON_spec_string ("business_name", 592 &business_name), 593 GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", 594 &cfg->storage_limit_in_megabytes), 595 GNUNET_JSON_spec_fixed_auto ("provider_salt", 596 &cfg->provider_salt), 597 GNUNET_JSON_spec_uint32 ("http_status", 598 &cfg->http_status), 599 GNUNET_JSON_spec_mark_optional ( 600 GNUNET_JSON_spec_string ("currency", 601 ¤cy), 602 NULL), 603 GNUNET_JSON_spec_end () 604 }; 605 size_t index; 606 json_t *m; 607 608 if (NULL == json_object_get (val, 609 "methods")) 610 no_config = true; 611 if (no_config) 612 { 613 if (ANASTASIS_RPS_OK == p->status) 614 { 615 *detail = set_detail ("authentication_providers", 616 "methods"); 617 return GNUNET_SYSERR; 618 } 619 return GNUNET_OK; 620 } 621 if (GNUNET_OK != 622 GNUNET_JSON_parse (val, 623 cspec, 624 NULL, NULL)) 625 { 626 *detail = set_detail ("authentication_providers", 627 NULL); 628 return GNUNET_SYSERR; 629 } 630 p->have_config = true; 631 cfg->business_name = GNUNET_strdup (business_name); 632 cfg->currency = dup_or_null (currency); 633 cfg->methods_len = (unsigned int) json_array_size (methods); 634 cfg->methods = GNUNET_new_array (cfg->methods_len, 635 struct ANASTASIS_ReduxMethodSpec); 636 json_array_foreach (methods, index, m) 637 { 638 static const char *const mallowed[] = { 639 "type", 640 "usage_fee", 641 NULL 642 }; 643 struct ANASTASIS_ReduxMethodSpec *ms = &cfg->methods[index]; 644 const char *type; 645 struct GNUNET_JSON_Specification mspec[] = { 646 GNUNET_JSON_spec_string ("type", 647 &type), 648 TALER_JSON_spec_amount_any ("usage_fee", 649 &ms->usage_fee), 650 GNUNET_JSON_spec_end () 651 }; 652 653 if (GNUNET_OK != 654 check_fields (m, 655 "authentication_providers.methods", 656 mallowed, 657 detail)) 658 return GNUNET_SYSERR; 659 if (GNUNET_OK != 660 GNUNET_JSON_parse (m, 661 mspec, 662 NULL, NULL)) 663 { 664 *detail = set_detail ("authentication_providers.methods", 665 NULL); 666 return GNUNET_SYSERR; 667 } 668 ms->type = GNUNET_strdup (type); 669 } 670 } 671 return GNUNET_OK; 672 } 673 674 675 /** 676 * Parse the `authentication_providers` object. 677 * 678 * @param obj the object, may be NULL 679 * @param[out] common state to fill in 680 * @param[out] detail set to the offending field on failure 681 * @return #GNUNET_OK on success 682 */ 683 static enum GNUNET_GenericReturnValue 684 parse_providers (const json_t *obj, 685 struct ANASTASIS_ReduxCommon *common, 686 const char **detail) 687 { 688 const char *url; 689 json_t *val; 690 unsigned int off = 0; 691 692 if (NULL == obj) 693 return GNUNET_OK; 694 if (! json_is_object (obj)) 695 { 696 *detail = set_detail ("authentication_providers", 697 NULL); 698 return GNUNET_SYSERR; 699 } 700 common->have_providers = true; 701 common->providers_len = (unsigned int) json_object_size (obj); 702 common->providers = GNUNET_new_array (common->providers_len, 703 struct ANASTASIS_ReduxProvider); 704 json_object_foreach ((json_t *) obj, url, val) 705 { 706 if (GNUNET_OK != 707 parse_provider (url, 708 val, 709 &common->providers[off], 710 detail)) 711 return GNUNET_SYSERR; 712 off++; 713 } 714 return GNUNET_OK; 715 } 716 717 718 /** 719 * Parse the fields shared by the backup and recovery variants. 720 * 721 * @param json the state 722 * @param[out] common state to fill in 723 * @param[out] detail set to the offending field on failure 724 * @return #GNUNET_OK on success 725 */ 726 static enum GNUNET_GenericReturnValue 727 parse_common (const json_t *json, 728 struct ANASTASIS_ReduxCommon *common, 729 const char **detail) 730 { 731 const json_t *continents = NULL; 732 const json_t *countries = NULL; 733 const json_t *required_attributes = NULL; 734 const json_t *providers = NULL; 735 const json_t *identity_attributes = NULL; 736 const json_t *currencies = NULL; 737 const char *selected_continent = NULL; 738 const char *selected_country = NULL; 739 struct GNUNET_JSON_Specification spec[] = { 740 GNUNET_JSON_spec_mark_optional ( 741 GNUNET_JSON_spec_array_const ("continents", 742 &continents), 743 NULL), 744 GNUNET_JSON_spec_mark_optional ( 745 GNUNET_JSON_spec_array_const ("countries", 746 &countries), 747 NULL), 748 GNUNET_JSON_spec_mark_optional ( 749 GNUNET_JSON_spec_array_const ("required_attributes", 750 &required_attributes), 751 NULL), 752 GNUNET_JSON_spec_mark_optional ( 753 GNUNET_JSON_spec_object_const ("authentication_providers", 754 &providers), 755 NULL), 756 GNUNET_JSON_spec_mark_optional ( 757 GNUNET_JSON_spec_object_const ("identity_attributes", 758 &identity_attributes), 759 NULL), 760 GNUNET_JSON_spec_mark_optional ( 761 GNUNET_JSON_spec_array_const ("currencies", 762 ¤cies), 763 NULL), 764 GNUNET_JSON_spec_mark_optional ( 765 GNUNET_JSON_spec_string ("selected_continent", 766 &selected_continent), 767 NULL), 768 GNUNET_JSON_spec_mark_optional ( 769 GNUNET_JSON_spec_string ("selected_country", 770 &selected_country), 771 NULL), 772 GNUNET_JSON_spec_end () 773 }; 774 775 if (GNUNET_OK != 776 GNUNET_JSON_parse (json, 777 spec, 778 NULL, NULL)) 779 { 780 *detail = set_detail ("state", 781 NULL); 782 return GNUNET_SYSERR; 783 } 784 common->selected_continent = dup_or_null (selected_continent); 785 common->selected_country = dup_or_null (selected_country); 786 common->identity_attributes = json_incref ((json_t *) identity_attributes); 787 if (NULL != currencies) 788 { 789 size_t index; 790 json_t *val; 791 792 common->have_currencies = true; 793 common->currencies_len = (unsigned int) json_array_size (currencies); 794 common->currencies = GNUNET_new_array (common->currencies_len, 795 char *); 796 json_array_foreach (currencies, index, val) 797 { 798 if (! json_is_string (val)) 799 { 800 *detail = set_detail ("currencies", 801 NULL); 802 return GNUNET_SYSERR; 803 } 804 common->currencies[index] = GNUNET_strdup (json_string_value (val)); 805 } 806 } 807 if ( (GNUNET_OK != 808 parse_continents (continents, 809 common, 810 detail)) || 811 (GNUNET_OK != 812 parse_countries (countries, 813 common, 814 detail)) || 815 (GNUNET_OK != 816 parse_required_attributes (required_attributes, 817 common, 818 detail)) || 819 (GNUNET_OK != 820 parse_providers (providers, 821 common, 822 detail)) ) 823 return GNUNET_SYSERR; 824 return GNUNET_OK; 825 } 826 827 828 /** 829 * Parse the `authentication_methods` array. 830 * 831 * @param arr the array, may be NULL 832 * @param[out] b backup state to fill in 833 * @param[out] detail set to the offending field on failure 834 * @return #GNUNET_OK on success 835 */ 836 static enum GNUNET_GenericReturnValue 837 parse_auth_methods (const json_t *arr, 838 struct ANASTASIS_ReduxBackup *b, 839 const char **detail) 840 { 841 static const char *const allowed[] = { 842 "type", 843 "instructions", 844 "challenge", 845 "mime_type", 846 NULL 847 }; 848 size_t index; 849 json_t *val; 850 851 if (NULL == arr) 852 return GNUNET_OK; 853 b->have_authentication_methods = true; 854 b->authentication_methods_len = (unsigned int) json_array_size (arr); 855 b->authentication_methods 856 = GNUNET_new_array (b->authentication_methods_len, 857 struct ANASTASIS_ReduxAuthMethod); 858 json_array_foreach (arr, index, val) 859 { 860 struct ANASTASIS_ReduxAuthMethod *am = &b->authentication_methods[index]; 861 const char *type; 862 const char *instructions; 863 const char *mime_type = NULL; 864 void *challenge; 865 size_t challenge_size; 866 struct GNUNET_JSON_Specification spec[] = { 867 GNUNET_JSON_spec_string ("type", 868 &type), 869 GNUNET_JSON_spec_string ("instructions", 870 &instructions), 871 GNUNET_JSON_spec_varsize ("challenge", 872 &challenge, 873 &challenge_size), 874 GNUNET_JSON_spec_mark_optional ( 875 GNUNET_JSON_spec_string ("mime_type", 876 &mime_type), 877 NULL), 878 GNUNET_JSON_spec_end () 879 }; 880 881 if (GNUNET_OK != 882 check_fields (val, 883 "authentication_methods", 884 allowed, 885 detail)) 886 return GNUNET_SYSERR; 887 if (GNUNET_OK != 888 GNUNET_JSON_parse (val, 889 spec, 890 NULL, NULL)) 891 { 892 *detail = set_detail ("authentication_methods", 893 NULL); 894 return GNUNET_SYSERR; 895 } 896 am->type = GNUNET_strdup (type); 897 am->instructions = GNUNET_strdup (instructions); 898 am->mime_type = dup_or_null (mime_type); 899 am->challenge = GNUNET_memdup (challenge, 900 challenge_size); 901 am->challenge_size = challenge_size; 902 GNUNET_JSON_parse_free (spec); 903 } 904 return GNUNET_OK; 905 } 906 907 908 /** 909 * Parse the `policies` array. 910 * 911 * @param arr the array, may be NULL 912 * @param[out] b backup state to fill in 913 * @param[out] detail set to the offending field on failure 914 * @return #GNUNET_OK on success 915 */ 916 static enum GNUNET_GenericReturnValue 917 parse_policies (const json_t *arr, 918 struct ANASTASIS_ReduxBackup *b, 919 const char **detail) 920 { 921 static const char *const pallowed[] = { 922 "methods", 923 "recovery_cost", 924 NULL 925 }; 926 static const char *const mallowed[] = { 927 "authentication_method", 928 "provider", 929 "truth", 930 NULL 931 }; 932 size_t index; 933 json_t *val; 934 935 if (NULL == arr) 936 return GNUNET_OK; 937 b->have_policies = true; 938 b->policies_len = (unsigned int) json_array_size (arr); 939 b->policies = GNUNET_new_array (b->policies_len, 940 struct ANASTASIS_ReduxPolicy); 941 json_array_foreach (arr, index, val) 942 { 943 struct ANASTASIS_ReduxPolicy *p = &b->policies[index]; 944 const json_t *methods; 945 size_t mindex; 946 json_t *m; 947 bool no_cost; 948 struct GNUNET_JSON_Specification spec[] = { 949 GNUNET_JSON_spec_array_const ("methods", 950 &methods), 951 GNUNET_JSON_spec_mark_optional ( 952 TALER_JSON_spec_amount_any ("recovery_cost", 953 &p->recovery_cost), 954 &no_cost), 955 GNUNET_JSON_spec_end () 956 }; 957 958 if (GNUNET_OK != 959 check_fields (val, 960 "policies", 961 pallowed, 962 detail)) 963 return GNUNET_SYSERR; 964 if (GNUNET_OK != 965 GNUNET_JSON_parse (val, 966 spec, 967 NULL, NULL)) 968 { 969 *detail = set_detail ("policies", 970 "methods"); 971 return GNUNET_SYSERR; 972 } 973 p->have_recovery_cost = ! no_cost; 974 p->methods_len = (unsigned int) json_array_size (methods); 975 p->methods = GNUNET_new_array (p->methods_len, 976 struct ANASTASIS_ReduxPolicyMethod); 977 json_array_foreach (methods, mindex, m) 978 { 979 struct ANASTASIS_ReduxPolicyMethod *pm = &p->methods[mindex]; 980 const char *provider; 981 const json_t *truth = NULL; 982 struct GNUNET_JSON_Specification mspec[] = { 983 GNUNET_JSON_spec_uint32 ("authentication_method", 984 &pm->authentication_method.idx), 985 GNUNET_JSON_spec_string ("provider", 986 &provider), 987 GNUNET_JSON_spec_mark_optional ( 988 GNUNET_JSON_spec_object_const ("truth", 989 &truth), 990 NULL), 991 GNUNET_JSON_spec_end () 992 }; 993 994 if (GNUNET_OK != 995 check_fields (m, 996 "policies.methods", 997 mallowed, 998 detail)) 999 return GNUNET_SYSERR; 1000 if (GNUNET_OK != 1001 GNUNET_JSON_parse (m, 1002 mspec, 1003 NULL, NULL)) 1004 { 1005 *detail = set_detail ("policies.methods", 1006 NULL); 1007 return GNUNET_SYSERR; 1008 } 1009 ANASTASIS_REDUX_provider_url_set_ (&pm->provider, 1010 provider); 1011 if (NULL != truth) 1012 { 1013 uint32_t us; 1014 struct GNUNET_JSON_Specification tspec[] = { 1015 GNUNET_JSON_spec_uint32 ("upload_status", 1016 &us), 1017 GNUNET_JSON_spec_end () 1018 }; 1019 1020 if (GNUNET_OK != 1021 GNUNET_JSON_parse (truth, 1022 tspec, 1023 NULL, NULL)) 1024 { 1025 *detail = set_detail ("policies.methods.truth", 1026 "upload_status"); 1027 return GNUNET_SYSERR; 1028 } 1029 pm->upload_status = (enum ANASTASIS_UploadStatus) us; 1030 pm->truth = ANASTASIS_truth_from_json (truth); 1031 if (NULL == pm->truth) 1032 { 1033 *detail = set_detail ("policies.methods", 1034 "truth"); 1035 return GNUNET_SYSERR; 1036 } 1037 } 1038 } 1039 } 1040 return GNUNET_OK; 1041 } 1042 1043 1044 /** 1045 * Parse the `policy_providers` array. 1046 * 1047 * @param arr the array, may be NULL 1048 * @param[out] b backup state to fill in 1049 * @param[out] detail set to the offending field on failure 1050 * @return #GNUNET_OK on success 1051 */ 1052 static enum GNUNET_GenericReturnValue 1053 parse_policy_providers (const json_t *arr, 1054 struct ANASTASIS_ReduxBackup *b, 1055 const char **detail) 1056 { 1057 static const char *const allowed[] = { 1058 "provider_url", 1059 "payment_secret", 1060 NULL 1061 }; 1062 size_t index; 1063 json_t *val; 1064 1065 if (NULL == arr) 1066 return GNUNET_OK; 1067 b->have_policy_providers = true; 1068 b->policy_providers_len = (unsigned int) json_array_size (arr); 1069 b->policy_providers = GNUNET_new_array (b->policy_providers_len, 1070 struct 1071 ANASTASIS_ReduxPolicyProvider); 1072 json_array_foreach (arr, index, val) 1073 { 1074 struct ANASTASIS_ReduxPolicyProvider *pp = &b->policy_providers[index]; 1075 const char *url; 1076 bool no_ps; 1077 struct GNUNET_JSON_Specification spec[] = { 1078 GNUNET_JSON_spec_string ("provider_url", 1079 &url), 1080 GNUNET_JSON_spec_mark_optional ( 1081 GNUNET_JSON_spec_fixed_auto ("payment_secret", 1082 &pp->payment_secret), 1083 &no_ps), 1084 GNUNET_JSON_spec_end () 1085 }; 1086 1087 if (GNUNET_OK != 1088 check_fields (val, 1089 "policy_providers", 1090 allowed, 1091 detail)) 1092 return GNUNET_SYSERR; 1093 if (GNUNET_OK != 1094 GNUNET_JSON_parse (val, 1095 spec, 1096 NULL, NULL)) 1097 { 1098 *detail = set_detail ("policy_providers", 1099 NULL); 1100 return GNUNET_SYSERR; 1101 } 1102 ANASTASIS_REDUX_provider_url_set_ (&pp->provider_url, 1103 url); 1104 pp->have_payment_secret = ! no_ps; 1105 } 1106 return GNUNET_OK; 1107 } 1108 1109 1110 /** 1111 * Parse the `success_details` object. 1112 * 1113 * @param obj the object, may be NULL 1114 * @param[out] b backup state to fill in 1115 * @param[out] detail set to the offending field on failure 1116 * @return #GNUNET_OK on success 1117 */ 1118 static enum GNUNET_GenericReturnValue 1119 parse_success_details (const json_t *obj, 1120 struct ANASTASIS_ReduxBackup *b, 1121 const char **detail) 1122 { 1123 static const char *const allowed[] = { 1124 "policy_version", 1125 "policy_expiration", 1126 NULL 1127 }; 1128 const char *url; 1129 json_t *val; 1130 unsigned int off = 0; 1131 1132 if (NULL == obj) 1133 return GNUNET_OK; 1134 b->have_success_details = true; 1135 b->success_details_len = (unsigned int) json_object_size (obj); 1136 b->success_details = GNUNET_new_array (b->success_details_len, 1137 struct ANASTASIS_ReduxSuccessDetail); 1138 json_object_foreach ((json_t *) obj, url, val) 1139 { 1140 struct ANASTASIS_ReduxSuccessDetail *sd = &b->success_details[off]; 1141 struct GNUNET_JSON_Specification spec[] = { 1142 GNUNET_JSON_spec_uint32 ("policy_version", 1143 &sd->policy_version), 1144 GNUNET_JSON_spec_timestamp ("policy_expiration", 1145 &sd->policy_expiration), 1146 GNUNET_JSON_spec_end () 1147 }; 1148 1149 if (GNUNET_OK != 1150 check_fields (val, 1151 "success_details", 1152 allowed, 1153 detail)) 1154 return GNUNET_SYSERR; 1155 if (GNUNET_OK != 1156 GNUNET_JSON_parse (val, 1157 spec, 1158 NULL, NULL)) 1159 { 1160 *detail = set_detail ("success_details", 1161 NULL); 1162 return GNUNET_SYSERR; 1163 } 1164 ANASTASIS_REDUX_provider_url_set_ (&sd->provider_url, 1165 url); 1166 off++; 1167 } 1168 return GNUNET_OK; 1169 } 1170 1171 1172 /** 1173 * Parse the backup-specific parts of @a json. 1174 * 1175 * @param json the state 1176 * @param[out] b backup state to fill in 1177 * @param[out] detail set to the offending field on failure 1178 * @return #GNUNET_OK on success 1179 */ 1180 static enum GNUNET_GenericReturnValue 1181 parse_backup (const json_t *json, 1182 struct ANASTASIS_ReduxBackup *b, 1183 const char **detail) 1184 { 1185 const char *state_str; 1186 const json_t *auth_methods = NULL; 1187 const json_t *policies = NULL; 1188 const json_t *policy_providers = NULL; 1189 const json_t *upload_fees = NULL; 1190 const json_t *payments = NULL; 1191 const json_t *policy_payment_requests = NULL; 1192 const json_t *success_details = NULL; 1193 const json_t *core_secret = NULL; 1194 const json_t *pay_arguments = NULL; 1195 const char *secret_name = NULL; 1196 bool no_expiration; 1197 struct GNUNET_JSON_Specification spec[] = { 1198 GNUNET_JSON_spec_string ("backup_state", 1199 &state_str), 1200 GNUNET_JSON_spec_mark_optional ( 1201 GNUNET_JSON_spec_array_const ("authentication_methods", 1202 &auth_methods), 1203 NULL), 1204 GNUNET_JSON_spec_mark_optional ( 1205 GNUNET_JSON_spec_array_const ("policies", 1206 &policies), 1207 NULL), 1208 GNUNET_JSON_spec_mark_optional ( 1209 GNUNET_JSON_spec_array_const ("policy_providers", 1210 &policy_providers), 1211 NULL), 1212 GNUNET_JSON_spec_mark_optional ( 1213 GNUNET_JSON_spec_array_const ("upload_fees", 1214 &upload_fees), 1215 NULL), 1216 GNUNET_JSON_spec_mark_optional ( 1217 GNUNET_JSON_spec_array_const ("payments", 1218 &payments), 1219 NULL), 1220 GNUNET_JSON_spec_mark_optional ( 1221 GNUNET_JSON_spec_array_const ("policy_payment_requests", 1222 &policy_payment_requests), 1223 NULL), 1224 GNUNET_JSON_spec_mark_optional ( 1225 GNUNET_JSON_spec_object_const ("success_details", 1226 &success_details), 1227 NULL), 1228 GNUNET_JSON_spec_mark_optional ( 1229 GNUNET_JSON_spec_object_const ("core_secret", 1230 &core_secret), 1231 NULL), 1232 GNUNET_JSON_spec_mark_optional ( 1233 GNUNET_JSON_spec_object_const ("pay_arguments", 1234 &pay_arguments), 1235 NULL), 1236 GNUNET_JSON_spec_mark_optional ( 1237 GNUNET_JSON_spec_string ("secret_name", 1238 &secret_name), 1239 NULL), 1240 GNUNET_JSON_spec_mark_optional ( 1241 GNUNET_JSON_spec_timestamp ("expiration", 1242 &b->expiration), 1243 &no_expiration), 1244 GNUNET_JSON_spec_end () 1245 }; 1246 1247 if (GNUNET_OK != 1248 GNUNET_JSON_parse (json, 1249 spec, 1250 NULL, NULL)) 1251 { 1252 *detail = set_detail ("state", 1253 "backup_state"); 1254 return GNUNET_SYSERR; 1255 } 1256 b->state = ANASTASIS_backup_state_from_string_ (state_str); 1257 if (ANASTASIS_BACKUP_STATE_INVALID == b->state) 1258 { 1259 *detail = set_detail ("state", 1260 "backup_state"); 1261 return GNUNET_SYSERR; 1262 } 1263 b->have_expiration = ! no_expiration; 1264 b->secret_name = dup_or_null (secret_name); 1265 b->core_secret = json_incref ((json_t *) core_secret); 1266 if ( (GNUNET_OK != 1267 parse_auth_methods (auth_methods, 1268 b, 1269 detail)) || 1270 (GNUNET_OK != 1271 parse_policies (policies, 1272 b, 1273 detail)) || 1274 (GNUNET_OK != 1275 parse_policy_providers (policy_providers, 1276 b, 1277 detail)) || 1278 (GNUNET_OK != 1279 parse_success_details (success_details, 1280 b, 1281 detail)) ) 1282 return GNUNET_SYSERR; 1283 if (NULL != upload_fees) 1284 { 1285 static const char *const allowed[] = { 1286 "fee", 1287 NULL 1288 }; 1289 size_t index; 1290 json_t *val; 1291 1292 b->have_upload_fees = true; 1293 b->upload_fees_len = (unsigned int) json_array_size (upload_fees); 1294 b->upload_fees = GNUNET_new_array (b->upload_fees_len, 1295 struct TALER_Amount); 1296 json_array_foreach (upload_fees, index, val) 1297 { 1298 struct GNUNET_JSON_Specification fspec[] = { 1299 TALER_JSON_spec_amount_any ("fee", 1300 &b->upload_fees[index]), 1301 GNUNET_JSON_spec_end () 1302 }; 1303 1304 if ( (GNUNET_OK != 1305 check_fields (val, 1306 "upload_fees", 1307 allowed, 1308 detail)) || 1309 (GNUNET_OK != 1310 GNUNET_JSON_parse (val, 1311 fspec, 1312 NULL, NULL)) ) 1313 { 1314 *detail = set_detail ("upload_fees", 1315 "fee"); 1316 return GNUNET_SYSERR; 1317 } 1318 } 1319 } 1320 if (NULL != payments) 1321 { 1322 size_t index; 1323 json_t *val; 1324 1325 b->have_payments = true; 1326 b->payments_len = (unsigned int) json_array_size (payments); 1327 b->payments = GNUNET_new_array (b->payments_len, 1328 char *); 1329 json_array_foreach (payments, index, val) 1330 { 1331 if (! json_is_string (val)) 1332 { 1333 *detail = set_detail ("payments", 1334 NULL); 1335 return GNUNET_SYSERR; 1336 } 1337 b->payments[index] = GNUNET_strdup (json_string_value (val)); 1338 } 1339 } 1340 if (NULL != policy_payment_requests) 1341 { 1342 static const char *const allowed[] = { 1343 "payto", 1344 "provider", 1345 NULL 1346 }; 1347 size_t index; 1348 json_t *val; 1349 1350 b->have_policy_payment_requests = true; 1351 b->policy_payment_requests_len 1352 = (unsigned int) json_array_size (policy_payment_requests); 1353 b->policy_payment_requests 1354 = GNUNET_new_array (b->policy_payment_requests_len, 1355 struct ANASTASIS_ReduxPolicyPaymentRequest); 1356 json_array_foreach (policy_payment_requests, index, val) 1357 { 1358 struct ANASTASIS_ReduxPolicyPaymentRequest *ppr 1359 = &b->policy_payment_requests[index]; 1360 const char *payto; 1361 const char *provider; 1362 struct GNUNET_JSON_Specification pspec[] = { 1363 GNUNET_JSON_spec_string ("payto", 1364 &payto), 1365 GNUNET_JSON_spec_string ("provider", 1366 &provider), 1367 GNUNET_JSON_spec_end () 1368 }; 1369 1370 if ( (GNUNET_OK != 1371 check_fields (val, 1372 "policy_payment_requests", 1373 allowed, 1374 detail)) || 1375 (GNUNET_OK != 1376 GNUNET_JSON_parse (val, 1377 pspec, 1378 NULL, NULL)) ) 1379 { 1380 *detail = set_detail ("policy_payment_requests", 1381 NULL); 1382 return GNUNET_SYSERR; 1383 } 1384 ppr->payto = GNUNET_strdup (payto); 1385 ANASTASIS_REDUX_provider_url_set_ (&ppr->provider, 1386 provider); 1387 } 1388 } 1389 if (NULL != pay_arguments) 1390 { 1391 static const char *const allowed[] = { 1392 "timeout", 1393 NULL 1394 }; 1395 bool no_timeout; 1396 struct GNUNET_JSON_Specification pspec[] = { 1397 GNUNET_JSON_spec_mark_optional ( 1398 GNUNET_JSON_spec_relative_time ("timeout", 1399 &b->pay_arguments.timeout), 1400 &no_timeout), 1401 GNUNET_JSON_spec_end () 1402 }; 1403 1404 if ( (GNUNET_OK != 1405 check_fields (pay_arguments, 1406 "pay_arguments", 1407 allowed, 1408 detail)) || 1409 (GNUNET_OK != 1410 GNUNET_JSON_parse (pay_arguments, 1411 pspec, 1412 NULL, NULL)) ) 1413 { 1414 *detail = set_detail ("pay_arguments", 1415 "timeout"); 1416 return GNUNET_SYSERR; 1417 } 1418 b->have_pay_arguments = true; 1419 b->pay_arguments.have_timeout = ! no_timeout; 1420 } 1421 return GNUNET_OK; 1422 } 1423 1424 1425 /** 1426 * Parse the `recovery_information` object. 1427 * 1428 * @param obj the object 1429 * @param[out] rr recovery state to fill in 1430 * @param[out] detail set to the offending field on failure 1431 * @return #GNUNET_OK on success 1432 */ 1433 static enum GNUNET_GenericReturnValue 1434 parse_recovery_info (const json_t *obj, 1435 struct ANASTASIS_ReduxRecovery *rr, 1436 const char **detail) 1437 { 1438 static const char *const allowed[] = { 1439 "challenges", 1440 "policies", 1441 "secret_name", 1442 "provider_url", 1443 "version", 1444 NULL 1445 }; 1446 static const char *const callowed[] = { 1447 "uuid", 1448 "uuid-display", 1449 "type", 1450 "instructions", 1451 "answer", 1452 "payment_secret", 1453 NULL 1454 }; 1455 static const char *const pallowed[] = { 1456 "uuid", 1457 NULL 1458 }; 1459 struct ANASTASIS_ReduxRecoveryInfo *ri; 1460 const json_t *challenges; 1461 const json_t *policies; 1462 const char *secret_name = NULL; 1463 const char *provider_url; 1464 size_t index; 1465 json_t *val; 1466 struct GNUNET_JSON_Specification spec[] = { 1467 GNUNET_JSON_spec_array_const ("challenges", 1468 &challenges), 1469 GNUNET_JSON_spec_array_const ("policies", 1470 &policies), 1471 GNUNET_JSON_spec_mark_optional ( 1472 GNUNET_JSON_spec_string ("secret_name", 1473 &secret_name), 1474 NULL), 1475 GNUNET_JSON_spec_string ("provider_url", 1476 &provider_url), 1477 GNUNET_JSON_spec_end () 1478 }; 1479 1480 ri = GNUNET_new (struct ANASTASIS_ReduxRecoveryInfo); 1481 rr->ri = ri; 1482 if (GNUNET_OK != 1483 check_fields (obj, 1484 "recovery_information", 1485 allowed, 1486 detail)) 1487 return GNUNET_SYSERR; 1488 { 1489 struct GNUNET_JSON_Specification vspec[] = { 1490 GNUNET_JSON_spec_uint32 ("version", 1491 &ri->version), 1492 GNUNET_JSON_spec_end () 1493 }; 1494 1495 if (GNUNET_OK != 1496 GNUNET_JSON_parse (obj, 1497 vspec, 1498 NULL, NULL)) 1499 { 1500 *detail = set_detail ("recovery_information", 1501 "version"); 1502 return GNUNET_SYSERR; 1503 } 1504 } 1505 if (GNUNET_OK != 1506 GNUNET_JSON_parse (obj, 1507 spec, 1508 NULL, NULL)) 1509 { 1510 *detail = set_detail ("recovery_information", 1511 NULL); 1512 return GNUNET_SYSERR; 1513 } 1514 ri->secret_name = dup_or_null (secret_name); 1515 ANASTASIS_REDUX_provider_url_set_ (&ri->provider_url, 1516 provider_url); 1517 ri->challenges_len = (unsigned int) json_array_size (challenges); 1518 ri->challenges = GNUNET_new_array (ri->challenges_len, 1519 struct ANASTASIS_ReduxChallengeInfo); 1520 json_array_foreach (challenges, index, val) 1521 { 1522 struct ANASTASIS_ReduxChallengeInfo *ci = &ri->challenges[index]; 1523 const char *type; 1524 const char *instructions; 1525 const char *answer = NULL; 1526 bool no_ps; 1527 struct GNUNET_JSON_Specification cspec[] = { 1528 GNUNET_JSON_spec_fixed_auto ("uuid", 1529 &ci->uuid), 1530 GNUNET_JSON_spec_string ("type", 1531 &type), 1532 GNUNET_JSON_spec_string ("instructions", 1533 &instructions), 1534 GNUNET_JSON_spec_mark_optional ( 1535 GNUNET_JSON_spec_string ("answer", 1536 &answer), 1537 NULL), 1538 GNUNET_JSON_spec_mark_optional ( 1539 GNUNET_JSON_spec_fixed_auto ("payment_secret", 1540 &ci->payment_secret), 1541 &no_ps), 1542 GNUNET_JSON_spec_end () 1543 }; 1544 1545 if (GNUNET_OK != 1546 check_fields (val, 1547 "recovery_information.challenges", 1548 callowed, 1549 detail)) 1550 return GNUNET_SYSERR; 1551 if (GNUNET_OK != 1552 GNUNET_JSON_parse (val, 1553 cspec, 1554 NULL, NULL)) 1555 { 1556 *detail = set_detail ("recovery_information.challenges", 1557 NULL); 1558 return GNUNET_SYSERR; 1559 } 1560 ci->type = GNUNET_strdup (type); 1561 ci->instructions = GNUNET_strdup (instructions); 1562 ci->answer = dup_or_null (answer); 1563 ci->have_payment_secret = ! no_ps; 1564 } 1565 ri->policies_len = (unsigned int) json_array_size (policies); 1566 ri->policies = GNUNET_new_array (ri->policies_len, 1567 struct ANASTASIS_ReduxRecoveryPolicy); 1568 json_array_foreach (policies, index, val) 1569 { 1570 struct ANASTASIS_ReduxRecoveryPolicy *p = &ri->policies[index]; 1571 size_t uindex; 1572 json_t *u; 1573 1574 if (! json_is_array (val)) 1575 { 1576 *detail = set_detail ("recovery_information", 1577 "policies"); 1578 return GNUNET_SYSERR; 1579 } 1580 p->uuids_len = (unsigned int) json_array_size (val); 1581 p->uuids = GNUNET_new_array (p->uuids_len, 1582 struct ANASTASIS_CRYPTO_TruthUUIDP); 1583 json_array_foreach (val, uindex, u) 1584 { 1585 struct GNUNET_JSON_Specification uspec[] = { 1586 GNUNET_JSON_spec_fixed_auto ("uuid", 1587 &p->uuids[uindex]), 1588 GNUNET_JSON_spec_end () 1589 }; 1590 1591 if ( (GNUNET_OK != 1592 check_fields (u, 1593 "recovery_information.policies", 1594 pallowed, 1595 detail)) || 1596 (GNUNET_OK != 1597 GNUNET_JSON_parse (u, 1598 uspec, 1599 NULL, NULL)) ) 1600 { 1601 *detail = set_detail ("recovery_information.policies", 1602 "uuid"); 1603 return GNUNET_SYSERR; 1604 } 1605 } 1606 } 1607 return GNUNET_OK; 1608 } 1609 1610 1611 /** 1612 * Parse one entry of the `challenge_feedback` object. 1613 * 1614 * @param val the feedback details 1615 * @param[out] fb feedback entry to fill in 1616 * @param[out] detail set to the offending field on failure 1617 * @return #GNUNET_OK on success 1618 */ 1619 static enum GNUNET_GenericReturnValue 1620 parse_feedback_details (const json_t *val, 1621 struct ANASTASIS_ReduxFeedback *fb, 1622 const char **detail) 1623 { 1624 static const char *const allowed[] = { 1625 "state", 1626 "display_hint", 1627 "filename", 1628 "address_hint", 1629 "taler_pay_uri", 1630 "provider", 1631 "payment_secret", 1632 "http_status", 1633 "error_code", 1634 "target_iban", 1635 "target_business_name", 1636 "wire_transfer_subject", 1637 "challenge_amount", 1638 "request_limit", 1639 "request_frequency", 1640 NULL 1641 }; 1642 const char *state; 1643 const char *display_hint = NULL; 1644 struct GNUNET_JSON_Specification spec[] = { 1645 GNUNET_JSON_spec_string ("state", 1646 &state), 1647 GNUNET_JSON_spec_mark_optional ( 1648 GNUNET_JSON_spec_string ("display_hint", 1649 &display_hint), 1650 NULL), 1651 GNUNET_JSON_spec_end () 1652 }; 1653 1654 if (GNUNET_OK != 1655 check_fields (val, 1656 "challenge_feedback", 1657 allowed, 1658 detail)) 1659 return GNUNET_SYSERR; 1660 if (GNUNET_OK != 1661 GNUNET_JSON_parse (val, 1662 spec, 1663 NULL, NULL)) 1664 { 1665 *detail = set_detail ("challenge_feedback", 1666 "state"); 1667 return GNUNET_SYSERR; 1668 } 1669 fb->display_hint = dup_or_null (display_hint); 1670 if (0 == strcmp (state, 1671 "code-in-file")) 1672 { 1673 const char *filename; 1674 struct GNUNET_JSON_Specification dspec[] = { 1675 GNUNET_JSON_spec_string ("filename", 1676 &filename), 1677 GNUNET_JSON_spec_end () 1678 }; 1679 1680 fb->status = ANASTASIS_RFS_CODE_IN_FILE; 1681 if (GNUNET_OK != 1682 GNUNET_JSON_parse (val, 1683 dspec, 1684 NULL, NULL)) 1685 { 1686 *detail = set_detail ("challenge_feedback", 1687 "filename"); 1688 return GNUNET_SYSERR; 1689 } 1690 fb->details.code_in_file.filename = GNUNET_strdup (filename); 1691 return GNUNET_OK; 1692 } 1693 if (0 == strcmp (state, 1694 "send-to-address")) 1695 { 1696 const char *address_hint = NULL; 1697 struct GNUNET_JSON_Specification dspec[] = { 1698 GNUNET_JSON_spec_mark_optional ( 1699 GNUNET_JSON_spec_string ("address_hint", 1700 &address_hint), 1701 NULL), 1702 GNUNET_JSON_spec_end () 1703 }; 1704 1705 fb->status = ANASTASIS_RFS_SEND_TO_ADDRESS; 1706 if (GNUNET_OK != 1707 GNUNET_JSON_parse (val, 1708 dspec, 1709 NULL, NULL)) 1710 { 1711 *detail = set_detail ("challenge_feedback", 1712 "address_hint"); 1713 return GNUNET_SYSERR; 1714 } 1715 fb->details.send_to_address.address_hint = dup_or_null (address_hint); 1716 return GNUNET_OK; 1717 } 1718 if (0 == strcmp (state, 1719 "taler-payment")) 1720 { 1721 const char *uri; 1722 const char *provider; 1723 struct GNUNET_JSON_Specification dspec[] = { 1724 GNUNET_JSON_spec_string ("taler_pay_uri", 1725 &uri), 1726 GNUNET_JSON_spec_string ("provider", 1727 &provider), 1728 GNUNET_JSON_spec_fixed_auto ("payment_secret", 1729 &fb->details.taler_payment.payment_secret), 1730 GNUNET_JSON_spec_end () 1731 }; 1732 1733 fb->status = ANASTASIS_RFS_TALER_PAYMENT; 1734 if (GNUNET_OK != 1735 GNUNET_JSON_parse (val, 1736 dspec, 1737 NULL, NULL)) 1738 { 1739 *detail = set_detail ("challenge_feedback", 1740 "taler_pay_uri"); 1741 return GNUNET_SYSERR; 1742 } 1743 fb->details.taler_payment.taler_pay_uri = GNUNET_strdup (uri); 1744 ANASTASIS_REDUX_provider_url_set_ (&fb->details.taler_payment.provider, 1745 provider); 1746 return GNUNET_OK; 1747 } 1748 if ( (0 == strcmp (state, 1749 "server-failure")) || 1750 (0 == strcmp (state, 1751 "truth-unknown")) ) 1752 { 1753 uint64_t ec; 1754 struct GNUNET_JSON_Specification dspec[] = { 1755 GNUNET_JSON_spec_uint64 ("error_code", 1756 &ec), 1757 GNUNET_JSON_spec_uint32 ("http_status", 1758 &fb->details.server_failure.http_status), 1759 GNUNET_JSON_spec_end () 1760 }; 1761 1762 fb->status = (0 == strcmp (state, 1763 "server-failure")) 1764 ? ANASTASIS_RFS_SERVER_FAILURE 1765 : ANASTASIS_RFS_TRUTH_UNKNOWN; 1766 if (GNUNET_OK != 1767 GNUNET_JSON_parse (val, 1768 dspec, 1769 NULL, NULL)) 1770 { 1771 *detail = set_detail ("challenge_feedback", 1772 "error_code"); 1773 return GNUNET_SYSERR; 1774 } 1775 fb->details.server_failure.ec = (enum TALER_ErrorCode) ec; 1776 return GNUNET_OK; 1777 } 1778 if (0 == strcmp (state, 1779 "iban-instructions")) 1780 { 1781 const char *iban; 1782 const char *business_name; 1783 const char *subject; 1784 struct GNUNET_JSON_Specification dspec[] = { 1785 GNUNET_JSON_spec_string ("target_iban", 1786 &iban), 1787 GNUNET_JSON_spec_string ("target_business_name", 1788 &business_name), 1789 GNUNET_JSON_spec_string ("wire_transfer_subject", 1790 &subject), 1791 TALER_JSON_spec_amount_any ("challenge_amount", 1792 &fb->details.iban_instructions.amount), 1793 GNUNET_JSON_spec_end () 1794 }; 1795 1796 fb->status = ANASTASIS_RFS_IBAN_INSTRUCTIONS; 1797 if (GNUNET_OK != 1798 GNUNET_JSON_parse (val, 1799 dspec, 1800 NULL, NULL)) 1801 { 1802 *detail = set_detail ("challenge_feedback", 1803 "target_iban"); 1804 return GNUNET_SYSERR; 1805 } 1806 fb->details.iban_instructions.target_iban = GNUNET_strdup (iban); 1807 fb->details.iban_instructions.target_business_name 1808 = GNUNET_strdup (business_name); 1809 fb->details.iban_instructions.wire_transfer_subject 1810 = GNUNET_strdup (subject); 1811 return GNUNET_OK; 1812 } 1813 if (0 == strcmp (state, 1814 "solved")) 1815 { 1816 fb->status = ANASTASIS_RFS_SOLVED; 1817 return GNUNET_OK; 1818 } 1819 if (0 == strcmp (state, 1820 "incorrect-answer")) 1821 { 1822 uint64_t ec; 1823 struct GNUNET_JSON_Specification dspec[] = { 1824 GNUNET_JSON_spec_uint64 ("error_code", 1825 &ec), 1826 GNUNET_JSON_spec_end () 1827 }; 1828 1829 fb->status = ANASTASIS_RFS_INCORRECT_ANSWER; 1830 if (GNUNET_OK != 1831 GNUNET_JSON_parse (val, 1832 dspec, 1833 NULL, NULL)) 1834 { 1835 *detail = set_detail ("challenge_feedback", 1836 "error_code"); 1837 return GNUNET_SYSERR; 1838 } 1839 fb->details.incorrect_answer.ec = (enum TALER_ErrorCode) ec; 1840 return GNUNET_OK; 1841 } 1842 if (0 == strcmp (state, 1843 "rate-limit-exceeded")) 1844 { 1845 uint64_t ec; 1846 struct GNUNET_JSON_Specification dspec[] = { 1847 GNUNET_JSON_spec_uint64 ("error_code", 1848 &ec), 1849 GNUNET_JSON_spec_uint64 ("request_limit", 1850 &fb->details.rate_limit_exceeded.request_limit), 1851 GNUNET_JSON_spec_relative_time ( 1852 "request_frequency", 1853 &fb->details.rate_limit_exceeded.request_frequency), 1854 GNUNET_JSON_spec_end () 1855 }; 1856 1857 fb->status = ANASTASIS_RFS_RATE_LIMIT_EXCEEDED; 1858 if (GNUNET_OK != 1859 GNUNET_JSON_parse (val, 1860 dspec, 1861 NULL, NULL)) 1862 { 1863 *detail = set_detail ("challenge_feedback", 1864 "request_limit"); 1865 return GNUNET_SYSERR; 1866 } 1867 fb->details.rate_limit_exceeded.ec = (enum TALER_ErrorCode) ec; 1868 return GNUNET_OK; 1869 } 1870 *detail = set_detail ("challenge_feedback", 1871 "state"); 1872 return GNUNET_SYSERR; 1873 } 1874 1875 1876 /** 1877 * Parse the recovery-specific parts of @a json. 1878 * 1879 * @param json the state 1880 * @param[out] rr recovery state to fill in 1881 * @param[out] detail set to the offending field on failure 1882 * @return #GNUNET_OK on success 1883 */ 1884 static enum GNUNET_GenericReturnValue 1885 parse_recovery (const json_t *json, 1886 struct ANASTASIS_ReduxRecovery *rr, 1887 const char **detail) 1888 { 1889 const char *state_str; 1890 const json_t *recovery_information = NULL; 1891 const json_t *recovery_document = NULL; 1892 const json_t *challenge_feedback = NULL; 1893 const json_t *core_secret = NULL; 1894 bool no_selected; 1895 struct GNUNET_JSON_Specification spec[] = { 1896 GNUNET_JSON_spec_string ("recovery_state", 1897 &state_str), 1898 GNUNET_JSON_spec_mark_optional ( 1899 GNUNET_JSON_spec_object_const ("recovery_information", 1900 &recovery_information), 1901 NULL), 1902 GNUNET_JSON_spec_mark_optional ( 1903 GNUNET_JSON_spec_object_const ("recovery_document", 1904 &recovery_document), 1905 NULL), 1906 GNUNET_JSON_spec_mark_optional ( 1907 GNUNET_JSON_spec_object_const ("challenge_feedback", 1908 &challenge_feedback), 1909 NULL), 1910 GNUNET_JSON_spec_mark_optional ( 1911 GNUNET_JSON_spec_object_const ("core_secret", 1912 &core_secret), 1913 NULL), 1914 GNUNET_JSON_spec_mark_optional ( 1915 GNUNET_JSON_spec_fixed_auto ("selected_challenge_uuid", 1916 &rr->selected_challenge), 1917 &no_selected), 1918 GNUNET_JSON_spec_end () 1919 }; 1920 1921 if (GNUNET_OK != 1922 GNUNET_JSON_parse (json, 1923 spec, 1924 NULL, NULL)) 1925 { 1926 *detail = set_detail ("state", 1927 "recovery_state"); 1928 return GNUNET_SYSERR; 1929 } 1930 rr->state = ANASTASIS_recovery_state_from_string_ (state_str); 1931 if (ANASTASIS_RECOVERY_STATE_INVALID == rr->state) 1932 { 1933 *detail = set_detail ("state", 1934 "recovery_state"); 1935 return GNUNET_SYSERR; 1936 } 1937 rr->have_selected_challenge = ! no_selected; 1938 rr->core_secret = json_incref ((json_t *) core_secret); 1939 if (NULL != recovery_information) 1940 { 1941 if (GNUNET_OK != 1942 parse_recovery_info (recovery_information, 1943 rr, 1944 detail)) 1945 return GNUNET_SYSERR; 1946 } 1947 if (NULL != recovery_document) 1948 { 1949 /* Hand the blob straight to src/lib: it owns that schema. The 1950 handle comes back inert -- no callbacks, no network activity -- 1951 until a handler calls ANASTASIS_recovery_resume(). */ 1952 rr->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_, 1953 recovery_document); 1954 if (NULL == rr->r) 1955 { 1956 *detail = set_detail ("state", 1957 "recovery_document"); 1958 return GNUNET_SYSERR; 1959 } 1960 } 1961 if (NULL != challenge_feedback) 1962 { 1963 const char *uuid_str; 1964 json_t *val; 1965 unsigned int off = 0; 1966 1967 rr->have_challenge_feedback = true; 1968 rr->challenge_feedback_len 1969 = (unsigned int) json_object_size (challenge_feedback); 1970 rr->challenge_feedback 1971 = GNUNET_new_array (rr->challenge_feedback_len, 1972 struct ANASTASIS_ReduxFeedback); 1973 json_object_foreach ((json_t *) challenge_feedback, uuid_str, val) 1974 { 1975 struct ANASTASIS_ReduxFeedback *fb = &rr->challenge_feedback[off]; 1976 1977 if (GNUNET_OK != 1978 GNUNET_STRINGS_string_to_data (uuid_str, 1979 strlen (uuid_str), 1980 &fb->uuid, 1981 sizeof (fb->uuid))) 1982 { 1983 *detail = set_detail ("challenge_feedback", 1984 uuid_str); 1985 return GNUNET_SYSERR; 1986 } 1987 if (GNUNET_OK != 1988 parse_feedback_details (val, 1989 fb, 1990 detail)) 1991 return GNUNET_SYSERR; 1992 off++; 1993 } 1994 } 1995 return GNUNET_OK; 1996 } 1997 1998 1999 /** 2000 * Parse an `error` state. 2001 * 2002 * @param json the state 2003 * @param[out] e error state to fill in 2004 * @param[out] detail set to the offending field on failure 2005 * @return #GNUNET_OK on success 2006 */ 2007 static enum GNUNET_GenericReturnValue 2008 parse_error (const json_t *json, 2009 struct ANASTASIS_ReduxError *e, 2010 const char **detail) 2011 { 2012 static const char *const allowed[] = { 2013 "reducer_type", 2014 "code", 2015 "hint", 2016 "detail", 2017 NULL 2018 }; 2019 uint64_t code; 2020 const char *hint = NULL; 2021 const char *dtl = NULL; 2022 struct GNUNET_JSON_Specification spec[] = { 2023 GNUNET_JSON_spec_uint64 ("code", 2024 &code), 2025 GNUNET_JSON_spec_mark_optional ( 2026 GNUNET_JSON_spec_string ("hint", 2027 &hint), 2028 NULL), 2029 GNUNET_JSON_spec_mark_optional ( 2030 GNUNET_JSON_spec_string ("detail", 2031 &dtl), 2032 NULL), 2033 GNUNET_JSON_spec_end () 2034 }; 2035 2036 if ( (GNUNET_OK != 2037 check_fields (json, 2038 "state", 2039 allowed, 2040 detail)) || 2041 (GNUNET_OK != 2042 GNUNET_JSON_parse (json, 2043 spec, 2044 NULL, NULL)) ) 2045 { 2046 *detail = set_detail ("state", 2047 "code"); 2048 return GNUNET_SYSERR; 2049 } 2050 e->code = (enum TALER_ErrorCode) code; 2051 e->hint = dup_or_null (hint); 2052 e->detail = dup_or_null (dtl); 2053 return GNUNET_OK; 2054 } 2055 2056 2057 /** 2058 * Field names permitted at the top level of a backup state. 2059 */ 2060 static const char *const backup_allowed[] = { 2061 "reducer_type", 2062 "backup_state", 2063 "continents", 2064 "countries", 2065 "required_attributes", 2066 "authentication_providers", 2067 "identity_attributes", 2068 "currencies", 2069 "selected_continent", 2070 "selected_country", 2071 "authentication_methods", 2072 "policies", 2073 "policy_providers", 2074 "upload_fees", 2075 "payments", 2076 "policy_payment_requests", 2077 "success_details", 2078 "core_secret", 2079 "secret_name", 2080 "expiration", 2081 "pay_arguments", 2082 NULL 2083 }; 2084 2085 2086 /** 2087 * Field names permitted at the top level of a recovery state. 2088 */ 2089 static const char *const recovery_allowed[] = { 2090 "reducer_type", 2091 "recovery_state", 2092 "continents", 2093 "countries", 2094 "required_attributes", 2095 "authentication_providers", 2096 "identity_attributes", 2097 "currencies", 2098 "selected_continent", 2099 "selected_country", 2100 "recovery_information", 2101 "recovery_document", 2102 "challenge_feedback", 2103 "selected_challenge_uuid", 2104 "core_secret", 2105 NULL 2106 }; 2107 2108 2109 struct ANASTASIS_ReduxState * 2110 ANASTASIS_REDUX_state_parse_ (const json_t *json, 2111 enum TALER_ErrorCode *ec, 2112 const char **detail) 2113 { 2114 struct ANASTASIS_ReduxState *rs; 2115 const char *type; 2116 2117 *ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID; 2118 *detail = NULL; 2119 if (! json_is_object (json)) 2120 { 2121 *detail = set_detail ("state", 2122 NULL); 2123 return NULL; 2124 } 2125 /* The reducer type is not always given explicitly: states written by 2126 older versions (and the initial states of the CLI tests) are 2127 identified by which of the two state fields is present. */ 2128 type = json_string_value (json_object_get (json, 2129 "reducer_type")); 2130 if (NULL == type) 2131 { 2132 if (NULL != json_object_get (json, 2133 "backup_state")) 2134 type = "backup"; 2135 else if (NULL != json_object_get (json, 2136 "recovery_state")) 2137 type = "recovery"; 2138 else 2139 { 2140 *detail = set_detail ("state", 2141 "reducer_type"); 2142 return NULL; 2143 } 2144 } 2145 rs = GNUNET_new (struct ANASTASIS_ReduxState); 2146 if (0 == strcmp (type, 2147 "backup")) 2148 { 2149 rs->type = ANASTASIS_RT_BACKUP; 2150 if ( (GNUNET_OK != 2151 check_fields (json, 2152 "state", 2153 backup_allowed, 2154 detail)) || 2155 (GNUNET_OK != 2156 parse_common (json, 2157 &rs->common, 2158 detail)) || 2159 (GNUNET_OK != 2160 parse_backup (json, 2161 &rs->details.backup, 2162 detail)) ) 2163 { 2164 ANASTASIS_REDUX_state_free_ (rs); 2165 return NULL; 2166 } 2167 return rs; 2168 } 2169 if (0 == strcmp (type, 2170 "recovery")) 2171 { 2172 rs->type = ANASTASIS_RT_RECOVERY; 2173 if ( (GNUNET_OK != 2174 check_fields (json, 2175 "state", 2176 recovery_allowed, 2177 detail)) || 2178 (GNUNET_OK != 2179 parse_common (json, 2180 &rs->common, 2181 detail)) || 2182 (GNUNET_OK != 2183 parse_recovery (json, 2184 &rs->details.recovery, 2185 detail)) ) 2186 { 2187 ANASTASIS_REDUX_state_free_ (rs); 2188 return NULL; 2189 } 2190 return rs; 2191 } 2192 if (0 == strcmp (type, 2193 "error")) 2194 { 2195 rs->type = ANASTASIS_RT_ERROR; 2196 if (GNUNET_OK != 2197 parse_error (json, 2198 &rs->details.error, 2199 detail)) 2200 { 2201 ANASTASIS_REDUX_state_free_ (rs); 2202 return NULL; 2203 } 2204 return rs; 2205 } 2206 *detail = set_detail ("state", 2207 "reducer_type"); 2208 ANASTASIS_REDUX_state_free_ (rs); 2209 return NULL; 2210 } 2211 2212 2213 enum GNUNET_GenericReturnValue 2214 ANASTASIS_REDUX_countries_set_ (struct ANASTASIS_ReduxCommon *common, 2215 const json_t *arr, 2216 const char **detail) 2217 { 2218 ANASTASIS_REDUX_countries_clear_ (common); 2219 if (GNUNET_OK != 2220 parse_countries (arr, 2221 common, 2222 detail)) 2223 { 2224 ANASTASIS_REDUX_countries_clear_ (common); 2225 return GNUNET_SYSERR; 2226 } 2227 return GNUNET_OK; 2228 } 2229 2230 2231 enum GNUNET_GenericReturnValue 2232 ANASTASIS_REDUX_required_attributes_set_ (struct ANASTASIS_ReduxCommon *common, 2233 const json_t *arr, 2234 const char **detail) 2235 { 2236 ANASTASIS_REDUX_required_attributes_clear_ (common); 2237 if (GNUNET_OK != 2238 parse_required_attributes (arr, 2239 common, 2240 detail)) 2241 { 2242 ANASTASIS_REDUX_required_attributes_clear_ (common); 2243 return GNUNET_SYSERR; 2244 } 2245 return GNUNET_OK; 2246 } 2247 2248 2249 enum GNUNET_GenericReturnValue 2250 ANASTASIS_REDUX_provider_set_ (struct ANASTASIS_ReduxCommon *common, 2251 const char *url, 2252 const json_t *val, 2253 const char **detail) 2254 { 2255 struct ANASTASIS_ReduxProvider *p; 2256 2257 p = ANASTASIS_REDUX_provider_get_ (common, 2258 url); 2259 if (p->have_config) 2260 ANASTASIS_REDUX_provider_config_clear_ (&p->config); 2261 p->have_config = false; 2262 p->status = ANASTASIS_RPS_NOT_CONTACTED; 2263 memset (&p->error, 2264 0, 2265 sizeof (p->error)); 2266 if (GNUNET_OK != 2267 parse_provider (url, 2268 val, 2269 p, 2270 detail)) 2271 { 2272 /* Leave a well-defined, if uninformative, entry behind: the caller 2273 reports the error, but the state must stay consistent. */ 2274 if (p->have_config) 2275 ANASTASIS_REDUX_provider_config_clear_ (&p->config); 2276 p->have_config = false; 2277 p->status = ANASTASIS_RPS_NOT_CONTACTED; 2278 return GNUNET_SYSERR; 2279 } 2280 return GNUNET_OK; 2281 } 2282 2283 2284 /* end of anastasis_api_redux_parse.c */