From 75f75c4a51c4700da9bde18cc9a9b5d9df1e8457 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 30 Apr 2023 16:21:07 +0200 Subject: breaking protocol changes towards fixing #7810 (incomplete, taler-exchange-offline still unfinished) --- src/lib/exchange_api_wire.c | 383 ++++++++++++++++++++++++++++---------------- 1 file changed, 245 insertions(+), 138 deletions(-) (limited to 'src/lib/exchange_api_wire.c') diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c index c23ea62d..49826528 100644 --- a/src/lib/exchange_api_wire.c +++ b/src/lib/exchange_api_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -66,82 +66,65 @@ struct TALER_EXCHANGE_WireHandle /** - * List of wire fees by method. - */ -struct FeeMap -{ - /** - * Next entry in list. - */ - struct FeeMap *next; - - /** - * Wire method this fee structure is for. - */ - char *method; - - /** - * Array of wire fees, also linked list, but allocated - * only once. - */ - struct TALER_EXCHANGE_WireAggregateFees *fee_list; -}; - - -/** - * Frees @a fm. + * Frees @a wfm array. * - * @param fm memory to release + * @param wfm fee array to release + * @param wfm_len length of the @a wfm array */ static void -free_fees (struct FeeMap *fm) +free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm, + unsigned int wfm_len) { - while (NULL != fm) + for (unsigned int i = 0; inext; + struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i]; - GNUNET_free (fm->fee_list); - GNUNET_free (fm->method); - GNUNET_free (fm); - fm = fe; + while (NULL != wfmi->fees_head) + { + struct TALER_EXCHANGE_WireAggregateFees *fe + = wfmi->fees_head; + + wfmi->fees_head = fe->next; + GNUNET_free (fe); + } } + GNUNET_free (wfm); } /** - * Parse wire @a fees and return map. + * Parse wire @a fees and return array. * * @param master_pub master public key to use to check signatures * @param fees json AggregateTransferFee to parse + * @param[out] fees_len set to length of returned array * @return NULL on error */ -static struct FeeMap * +static struct TALER_EXCHANGE_WireFeesByMethod * parse_fees (const struct TALER_MasterPublicKeyP *master_pub, - json_t *fees) + const json_t *fees, + unsigned int *fees_len) { - struct FeeMap *fm = NULL; + struct TALER_EXCHANGE_WireFeesByMethod *fbm; + unsigned int fbml = json_object_size (fees); + unsigned int i = 0; const char *key; - json_t *fee_array; + const json_t *fee_array; - json_object_foreach (fees, key, fee_array) { - struct FeeMap *fe = GNUNET_new (struct FeeMap); - unsigned int len; + fbm = GNUNET_new_array (fbml, + struct TALER_EXCHANGE_WireFeesByMethod); + *fees_len = fbml; + json_object_foreach ((json_t *) fees, key, fee_array) { + struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++]; unsigned int idx; json_t *fee; - if (0 == (len = json_array_size (fee_array))) - { - GNUNET_free (fe); - continue; /* skip */ - } - fe->method = GNUNET_strdup (key); - fe->next = fm; - fe->fee_list = GNUNET_new_array (len, - struct TALER_EXCHANGE_WireAggregateFees); - fm = fe; + fe->method = key; + fe->fees_head = NULL; json_array_foreach (fee_array, idx, fee) { - struct TALER_EXCHANGE_WireAggregateFees *wa = &fe->fee_list[idx]; + struct TALER_EXCHANGE_WireAggregateFees *wa + = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees); struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("sig", &wa->master_sig), @@ -156,6 +139,8 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, GNUNET_JSON_spec_end () }; + wa->next = fe->fees_head; + fe->fees_head = wa; if (GNUNET_OK != GNUNET_JSON_parse (fee, spec, @@ -163,7 +148,8 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, NULL)) { GNUNET_break_op (0); - free_fees (fm); + free_fees (fbm, + i); return NULL; } if (GNUNET_OK != @@ -176,35 +162,122 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, &wa->master_sig)) { GNUNET_break_op (0); - free_fees (fm); + free_fees (fbm, + i); return NULL; } - if (idx + 1 < len) - wa->next = &fe->fee_list[idx + 1]; - else - wa->next = NULL; + } /* for all fees over time */ + } /* for all methods */ + GNUNET_assert (i == fbml); + return fbm; +} + + +/** + * Parse account restriction in @a jrest into @a rest. + * + * @param jrest array of account restrictions in JSON + * @param[out] resta_len set to length of @a resta + * @param[out] resta account restriction array to set + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parse_restrictions (const json_t *jresta, + unsigned int *resta_len, + struct TALER_EXCHANGE_AccountRestriction **resta) +{ + if (! json_is_array (jresta)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + *resta_len = json_array_size (jresta); + if (0 == *resta_len) + { + /* no restrictions, perfectly OK */ + *resta = NULL; + return GNUNET_OK; + } + *resta = GNUNET_new_array (*resta_len, + struct TALER_EXCHANGE_AccountRestriction); + for (unsigned int i = 0; i<*resta_len; i++) + { + const json_t *jr = json_array_get (jresta, + i); + struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i]; + const char *type = json_string_value (json_object_get (jr, + "type")); + + if (NULL == type) + { + GNUNET_break (0); + goto fail; + } + if (0 == strcmp (type, + "deny")) + { + ar->type = TALER_EXCHANGE_AR_DENY; + continue; + } + if (0 == strcmp (type, + "regex")) + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ( + "payto_regex", + &ar->details.regex.posix_egrep), + GNUNET_JSON_spec_string ( + "human_hint", + &ar->details.regex.human_hint), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_object_const ( + "human_hint_i18n", + &ar->details.regex.human_hint_i18n), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (jr, + spec, + NULL, NULL)) + { + /* bogus reply */ + GNUNET_break_op (0); + goto fail; + } + ar->type = TALER_EXCHANGE_AR_REGEX; + continue; } + /* unsupported type */ + GNUNET_break (0); + return GNUNET_SYSERR; } - return fm; + return GNUNET_OK; +fail: + GNUNET_free (*resta); + *resta_len = 0; + return GNUNET_SYSERR; } /** - * Find fee by @a method. + * Free data within @a was, but not @a was itself. * - * @param fm map to look in - * @param method key to look for - * @return NULL if fee is not specified in @a fm + * @param was array of wire account data + * @param was_len length of the @a was array */ -static const struct TALER_EXCHANGE_WireAggregateFees * -lookup_fee (const struct FeeMap *fm, - const char *method) +static void +free_accounts (struct TALER_EXCHANGE_WireAccount *was, + unsigned int was_len) { - for (; NULL != fm; fm = fm->next) - if (0 == strcasecmp (fm->method, - method)) - return fm->fee_list; - return NULL; + for (unsigned int i = 0; icredit_restrictions); + GNUNET_free (wa->debit_restrictions); + } } @@ -223,9 +296,9 @@ handle_wire_finished (void *cls, { struct TALER_EXCHANGE_WireHandle *wh = cls; const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code + struct TALER_EXCHANGE_WireResponse wr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code }; TALER_LOG_DEBUG ("Checking raw /wire response\n"); @@ -233,28 +306,29 @@ handle_wire_finished (void *cls, switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + wr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; wh->exchange->wire_error_count++; break; case MHD_HTTP_OK: { - json_t *accounts; - json_t *fees; - unsigned int num_accounts; - struct FeeMap *fm; + const json_t *accounts; + const json_t *fees; + const json_t *wads; + struct TALER_EXCHANGE_WireFeesByMethod *fbm; struct TALER_MasterPublicKeyP master_pub; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_public_key", &master_pub), - GNUNET_JSON_spec_json ("accounts", - &accounts), - GNUNET_JSON_spec_json ("fees", - &fees), + GNUNET_JSON_spec_array_const ("accounts", + &accounts), + GNUNET_JSON_spec_object_const ("fees", + &fees), + GNUNET_JSON_spec_array_const ("wads", + &wads), GNUNET_JSON_spec_end () }; wh->exchange->wire_error_count = 0; - if (GNUNET_OK != GNUNET_JSON_parse (j, spec, @@ -262,8 +336,8 @@ handle_wire_finished (void *cls, { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } { @@ -275,61 +349,70 @@ handle_wire_finished (void *cls, { /* bogus reply: master public key in /wire differs from that in /keys */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } } - if (0 == (num_accounts = json_array_size (accounts))) + wr.details.ok.accounts_len + = json_array_size (accounts); + if (0 == wr.details.ok.accounts_len) { /* bogus reply */ GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - if (NULL == (fm = parse_fees (&master_pub, - fees))) + fbm = parse_fees (&master_pub, + fees, + &wr.details.ok.fees_len); + if (NULL == fbm) { /* bogus reply */ GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } /* parse accounts */ { - struct TALER_EXCHANGE_WireAccount was[num_accounts]; - - for (unsigned int i = 0; ipayto_uri), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("conversion_url", + &wa->conversion_url), + NULL), + GNUNET_JSON_spec_json ("credit_restrictions", + &credit_restrictions), + GNUNET_JSON_spec_json ("debit_restrictions", + &debit_restrictions), GNUNET_JSON_spec_fixed_auto ("master_sig", &wa->master_sig), GNUNET_JSON_spec_end () }; - char *method; + json_t *account; account = json_array_get (accounts, i); - if (GNUNET_OK != - TALER_JSON_exchange_wire_signature_check (account, - &master_pub)) - { - /* bogus reply */ - GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID; - break; - } if (GNUNET_OK != GNUNET_JSON_parse (account, spec_account, @@ -337,80 +420,104 @@ handle_wire_finished (void *cls, { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - if (NULL == (method = TALER_payto_get_method (wa->payto_uri))) + { + char *err; + + err = TALER_payto_validate (wa->payto_uri); + if (NULL != err) + { + GNUNET_break_op (0); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + GNUNET_free (err); + break; + } + } + + if (GNUNET_OK != + TALER_exchange_wire_signature_check (wa->payto_uri, + wa->conversion_url, + debit_restrictions, + credit_restrictions, + &master_pub, + &wa->master_sig)) { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID; break; } - if (NULL == (wa->fees = lookup_fee (fm, - method))) + if ( (GNUNET_OK != + parse_restrictions (credit_restrictions, + &wa->credit_restrictions_length, + &wa->credit_restrictions)) || + (GNUNET_OK != + parse_restrictions (debit_restrictions, + &wa->debit_restrictions_length, + &wa->debit_restrictions)) ) { /* bogus reply */ GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - GNUNET_free (method); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - GNUNET_free (method); + GNUNET_JSON_parse_free (spec_account); } /* end 'for all accounts */ - if ( (0 != response_code) && + if ( (0 != wr.hr.http_status) && (NULL != wh->cb) ) { wh->cb (wh->cb_cls, - &hr, - num_accounts, - was); + &wr); wh->cb = NULL; } + free_accounts (was, + wr.details.ok.accounts_len); } /* end of 'parse accounts */ - free_fees (fm); + free_fees (fbm, + wr.details.ok.fees_len); GNUNET_JSON_parse_free (spec); } /* end of MHD_HTTP_OK */ break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); break; default: /* unexpected response code */ if (MHD_HTTP_GATEWAY_TIMEOUT == response_code) wh->exchange->wire_error_count++; GNUNET_break_op (0); - hr.ec = TALER_JSON_get_error_code (j); - hr.hint = TALER_JSON_get_error_hint (j); + wr.hr.ec = TALER_JSON_get_error_code (j); + wr.hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange wire\n", (unsigned int) response_code, - (int) hr.ec); + (int) wr.hr.ec); break; } if (NULL != wh->cb) wh->cb (wh->cb_cls, - &hr, - 0, - NULL); + &wr); TALER_EXCHANGE_wire_cancel (wh); } -- cgit v1.2.3 From faca037018820ba3c21724c7f6ab41a72206e4ff Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 30 Apr 2023 23:37:01 +0200 Subject: expose TALER_EXCHANGE_parse_accounts() in external API --- contrib/gana | 2 +- src/include/taler_exchange_service.h | 27 +++++ src/lib/exchange_api_common.c | 192 ++++++++++++++++++++++++++++++++ src/lib/exchange_api_wire.c | 208 ++--------------------------------- 4 files changed, 232 insertions(+), 197 deletions(-) (limited to 'src/lib/exchange_api_wire.c') diff --git a/contrib/gana b/contrib/gana index 5cfe18c5..d831c7f7 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 5cfe18c5bbfd404a5f7cf27a78577c881ddb9ebd +Subproject commit d831c7f72a5030e20efb4ada7babc103ccd01fab diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index f9330ec5..fc5fb284 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -909,6 +909,33 @@ struct TALER_EXCHANGE_WireAccount }; +/** + * Parse array of @a accounts of the exchange into @a was. + * + * @param master_pub master public key of the exchange, NULL to not verify signatures + * @param accounts array of accounts to parse + * @param[out] was where to write the result (already allocated) + * @param was_length length of the @a was array, must match the length of @a accounts + * @return #GNUNET_OK if parsing @a accounts succeeded + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_parse_accounts (const struct TALER_MasterPublicKeyP *master_pub, + const json_t *accounts, + struct TALER_EXCHANGE_WireAccount was[], + unsigned int was_length); + + +/** + * Free data within @a was, but not @a was itself. + * + * @param was array of wire account data + * @param was_len length of the @a was array + */ +void +TALER_EXCHANGE_free_accounts (struct TALER_EXCHANGE_WireAccount *was, + unsigned int was_len); + + /** * Response to a /wire request. */ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index b895bf9a..285a5292 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -2194,4 +2194,196 @@ TALER_EXCHANGE_verify_deposit_signature_ ( } +/** + * Parse account restriction in @a jrest into @a rest. + * + * @param jrest array of account restrictions in JSON + * @param[out] resta_len set to length of @a resta + * @param[out] resta account restriction array to set + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +parse_restrictions (const json_t *jresta, + unsigned int *resta_len, + struct TALER_EXCHANGE_AccountRestriction **resta) +{ + if (! json_is_array (jresta)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + *resta_len = json_array_size (jresta); + if (0 == *resta_len) + { + /* no restrictions, perfectly OK */ + *resta = NULL; + return GNUNET_OK; + } + *resta = GNUNET_new_array (*resta_len, + struct TALER_EXCHANGE_AccountRestriction); + for (unsigned int i = 0; i<*resta_len; i++) + { + const json_t *jr = json_array_get (jresta, + i); + struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i]; + const char *type = json_string_value (json_object_get (jr, + "type")); + + if (NULL == type) + { + GNUNET_break (0); + goto fail; + } + if (0 == strcmp (type, + "deny")) + { + ar->type = TALER_EXCHANGE_AR_DENY; + continue; + } + if (0 == strcmp (type, + "regex")) + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ( + "payto_regex", + &ar->details.regex.posix_egrep), + GNUNET_JSON_spec_string ( + "human_hint", + &ar->details.regex.human_hint), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_object_const ( + "human_hint_i18n", + &ar->details.regex.human_hint_i18n), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (jr, + spec, + NULL, NULL)) + { + /* bogus reply */ + GNUNET_break_op (0); + goto fail; + } + ar->type = TALER_EXCHANGE_AR_REGEX; + continue; + } + /* unsupported type */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +fail: + GNUNET_free (*resta); + *resta_len = 0; + return GNUNET_SYSERR; +} + + +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_parse_accounts (const struct TALER_MasterPublicKeyP *master_pub, + const json_t *accounts, + struct TALER_EXCHANGE_WireAccount was[], + unsigned int was_length) +{ + memset (was, + 0, + sizeof (struct TALER_EXCHANGE_WireAccount) * was_length); + GNUNET_assert (was_length == + json_array_size (accounts)); + for (unsigned int i = 0; + ipayto_uri), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("conversion_url", + &wa->conversion_url), + NULL), + GNUNET_JSON_spec_json ("credit_restrictions", + &credit_restrictions), + GNUNET_JSON_spec_json ("debit_restrictions", + &debit_restrictions), + GNUNET_JSON_spec_fixed_auto ("master_sig", + &wa->master_sig), + GNUNET_JSON_spec_end () + }; + json_t *account; + + account = json_array_get (accounts, + i); + if (GNUNET_OK != + GNUNET_JSON_parse (account, + spec_account, + NULL, NULL)) + { + /* bogus reply */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + char *err; + + err = TALER_payto_validate (wa->payto_uri); + if (NULL != err) + { + GNUNET_break_op (0); + GNUNET_free (err); + return GNUNET_SYSERR; + } + } + + if ( (NULL != master_pub) && + (GNUNET_OK != + TALER_exchange_wire_signature_check (wa->payto_uri, + wa->conversion_url, + debit_restrictions, + credit_restrictions, + master_pub, + &wa->master_sig)) ) + { + /* bogus reply */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if ( (GNUNET_OK != + parse_restrictions (credit_restrictions, + &wa->credit_restrictions_length, + &wa->credit_restrictions)) || + (GNUNET_OK != + parse_restrictions (debit_restrictions, + &wa->debit_restrictions_length, + &wa->debit_restrictions)) ) + { + /* bogus reply */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_JSON_parse_free (spec_account); + } /* end 'for all accounts */ + return GNUNET_OK; +} + + +void +TALER_EXCHANGE_free_accounts (struct TALER_EXCHANGE_WireAccount *was, + unsigned int was_len) +{ + for (unsigned int i = 0; icredit_restrictions); + GNUNET_free (wa->debit_restrictions); + } +} + + /* end of exchange_api_common.c */ diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c index 49826528..f38ca86b 100644 --- a/src/lib/exchange_api_wire.c +++ b/src/lib/exchange_api_wire.c @@ -173,114 +173,6 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, } -/** - * Parse account restriction in @a jrest into @a rest. - * - * @param jrest array of account restrictions in JSON - * @param[out] resta_len set to length of @a resta - * @param[out] resta account restriction array to set - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -parse_restrictions (const json_t *jresta, - unsigned int *resta_len, - struct TALER_EXCHANGE_AccountRestriction **resta) -{ - if (! json_is_array (jresta)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - *resta_len = json_array_size (jresta); - if (0 == *resta_len) - { - /* no restrictions, perfectly OK */ - *resta = NULL; - return GNUNET_OK; - } - *resta = GNUNET_new_array (*resta_len, - struct TALER_EXCHANGE_AccountRestriction); - for (unsigned int i = 0; i<*resta_len; i++) - { - const json_t *jr = json_array_get (jresta, - i); - struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i]; - const char *type = json_string_value (json_object_get (jr, - "type")); - - if (NULL == type) - { - GNUNET_break (0); - goto fail; - } - if (0 == strcmp (type, - "deny")) - { - ar->type = TALER_EXCHANGE_AR_DENY; - continue; - } - if (0 == strcmp (type, - "regex")) - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ( - "payto_regex", - &ar->details.regex.posix_egrep), - GNUNET_JSON_spec_string ( - "human_hint", - &ar->details.regex.human_hint), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_object_const ( - "human_hint_i18n", - &ar->details.regex.human_hint_i18n), - NULL), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (jr, - spec, - NULL, NULL)) - { - /* bogus reply */ - GNUNET_break_op (0); - goto fail; - } - ar->type = TALER_EXCHANGE_AR_REGEX; - continue; - } - /* unsupported type */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -fail: - GNUNET_free (*resta); - *resta_len = 0; - return GNUNET_SYSERR; -} - - -/** - * Free data within @a was, but not @a was itself. - * - * @param was array of wire account data - * @param was_len length of the @a was array - */ -static void -free_accounts (struct TALER_EXCHANGE_WireAccount *was, - unsigned int was_len) -{ - for (unsigned int i = 0; icredit_restrictions); - GNUNET_free (wa->debit_restrictions); - } -} - - /** * Function called when we're done processing the * HTTP /wire request. @@ -383,101 +275,25 @@ handle_wire_finished (void *cls, { struct TALER_EXCHANGE_WireAccount was[wr.details.ok.accounts_len]; - memset (was, - 0, - sizeof (was)); wr.details.ok.accounts = was; - for (unsigned int i = 0; - ipayto_uri), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("conversion_url", - &wa->conversion_url), - NULL), - GNUNET_JSON_spec_json ("credit_restrictions", - &credit_restrictions), - GNUNET_JSON_spec_json ("debit_restrictions", - &debit_restrictions), - GNUNET_JSON_spec_fixed_auto ("master_sig", - &wa->master_sig), - GNUNET_JSON_spec_end () - }; - json_t *account; - - account = json_array_get (accounts, - i); - if (GNUNET_OK != - GNUNET_JSON_parse (account, - spec_account, - NULL, NULL)) - { - /* bogus reply */ - GNUNET_break_op (0); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - { - char *err; - - err = TALER_payto_validate (wa->payto_uri); - if (NULL != err) - { - GNUNET_break_op (0); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - GNUNET_free (err); - break; - } - } - - if (GNUNET_OK != - TALER_exchange_wire_signature_check (wa->payto_uri, - wa->conversion_url, - debit_restrictions, - credit_restrictions, - &master_pub, - &wa->master_sig)) - { - /* bogus reply */ - GNUNET_break_op (0); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_EXCHANGE_WIRE_SIGNATURE_INVALID; - break; - } - if ( (GNUNET_OK != - parse_restrictions (credit_restrictions, - &wa->credit_restrictions_length, - &wa->credit_restrictions)) || - (GNUNET_OK != - parse_restrictions (debit_restrictions, - &wa->debit_restrictions_length, - &wa->debit_restrictions)) ) - { - /* bogus reply */ - GNUNET_break_op (0); - wr.hr.http_status = 0; - wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - GNUNET_JSON_parse_free (spec_account); - } /* end 'for all accounts */ - if ( (0 != wr.hr.http_status) && - (NULL != wh->cb) ) + GNUNET_break_op (0); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + } + else if (NULL != wh->cb) { wh->cb (wh->cb_cls, &wr); wh->cb = NULL; } - free_accounts (was, - wr.details.ok.accounts_len); + TALER_EXCHANGE_free_accounts (was, + wr.details.ok.accounts_len); } /* end of 'parse accounts */ free_fees (fbm, wr.details.ok.fees_len); -- cgit v1.2.3 From 647ae694cc9f1aef44e792b96676b115231e8898 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 1 May 2023 19:37:29 +0200 Subject: -fix uninitialized variable and memory leak --- src/kyclogic/plugin_kyclogic_oauth2.c | 120 ++++++++++++++++++---------------- src/lib/exchange_api_wire.c | 1 + src/testing/testing_api_cmd_oauth.c | 1 + 3 files changed, 67 insertions(+), 55 deletions(-) (limited to 'src/lib/exchange_api_wire.c') diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index 228525e2..c72b04b7 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -490,8 +490,6 @@ initiate_task (void *cls) struct PluginState *ps = pd->ps; char *hps; char *url; - char *redirect_uri; - char *redirect_uri_encoded; char legi_s[42]; ih->task = NULL; @@ -501,19 +499,27 @@ initiate_task (void *cls) (unsigned long long) ih->legitimization_uuid); hps = GNUNET_STRINGS_data_to_string_alloc (&ih->h_payto, sizeof (ih->h_payto)); - GNUNET_asprintf (&redirect_uri, - "%skyc-proof/%s?state=%s", - ps->exchange_base_url, - pd->section, - hps); - redirect_uri_encoded = TALER_urlencode (redirect_uri); - GNUNET_free (redirect_uri); - GNUNET_asprintf (&url, - "%s?response_type=code&client_id=%s&redirect_uri=%s", - pd->login_url, - pd->client_id, - redirect_uri_encoded); - GNUNET_free (redirect_uri_encoded); + { + char *redirect_uri_encoded; + + { + char *redirect_uri; + + GNUNET_asprintf (&redirect_uri, + "%skyc-proof/%s?state=%s", + ps->exchange_base_url, + pd->section, + hps); + redirect_uri_encoded = TALER_urlencode (redirect_uri); + GNUNET_free (redirect_uri); + } + GNUNET_asprintf (&url, + "%s?response_type=code&client_id=%s&redirect_uri=%s", + pd->login_url, + pd->client_id, + redirect_uri_encoded); + GNUNET_free (redirect_uri_encoded); + } /* FIXME-API: why do we *redirect* the client here, instead of making the HTTP request *ourselves* and forwarding the response? This prevents us @@ -582,6 +588,37 @@ oauth2_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih) } +/** + * Cancel KYC proof. + * + * @param[in] ph handle of operation to cancel + */ +static void +oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) +{ + if (NULL != ph->task) + { + GNUNET_SCHEDULER_cancel (ph->task); + ph->task = NULL; + } + if (NULL != ph->job) + { + GNUNET_CURL_job_cancel (ph->job); + ph->job = NULL; + } + if (NULL != ph->response) + { + MHD_destroy_response (ph->response); + ph->response = NULL; + } + GNUNET_free (ph->provider_user_id); + if (NULL != ph->attributes) + json_decref (ph->attributes); + GNUNET_free (ph->post_body); + GNUNET_free (ph); +} + + /** * Function called to asynchronously return the final * result to the callback. @@ -602,10 +639,8 @@ return_proof_response (void *cls) ph->attributes, ph->http_status, ph->response); - GNUNET_free (ph->provider_user_id); - if (NULL != ph->attributes) - json_decref (ph->attributes); - GNUNET_free (ph); + ph->response = NULL; /*Ownership passed to 'ph->cb'!*/ + oauth2_proof_cancel (ph); } @@ -1101,7 +1136,6 @@ oauth2_proof (void *cls, 1)); { char *client_id; - char *redirect_uri; char *client_secret; char *authorization_code; char *redirect_uri_encoded; @@ -1109,13 +1143,17 @@ oauth2_proof (void *cls, hps = GNUNET_STRINGS_data_to_string_alloc (&ph->h_payto, sizeof (ph->h_payto)); - GNUNET_asprintf (&redirect_uri, - "%skyc-proof/%s?state=%s", - ps->exchange_base_url, - pd->section, - hps); - redirect_uri_encoded = TALER_urlencode (redirect_uri); - GNUNET_free (redirect_uri); + { + char *redirect_uri; + + GNUNET_asprintf (&redirect_uri, + "%skyc-proof/%s?state=%s", + ps->exchange_base_url, + pd->section, + hps); + redirect_uri_encoded = TALER_urlencode (redirect_uri); + GNUNET_free (redirect_uri); + } GNUNET_assert (NULL != redirect_uri_encoded); client_id = curl_easy_escape (ph->eh, pd->client_id, @@ -1164,34 +1202,6 @@ oauth2_proof (void *cls, } -/** - * Cancel KYC proof. - * - * @param[in] ph handle of operation to cancel - */ -static void -oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) -{ - if (NULL != ph->task) - { - GNUNET_SCHEDULER_cancel (ph->task); - ph->task = NULL; - } - if (NULL != ph->job) - { - GNUNET_CURL_job_cancel (ph->job); - ph->job = NULL; - } - if (NULL != ph->response) - { - MHD_destroy_response (ph->response); - ph->response = NULL; - } - GNUNET_free (ph->post_body); - GNUNET_free (ph); -} - - /** * Function to asynchronously return the 404 not found * page for the webhook. diff --git a/src/lib/exchange_api_wire.c b/src/lib/exchange_api_wire.c index f38ca86b..08498805 100644 --- a/src/lib/exchange_api_wire.c +++ b/src/lib/exchange_api_wire.c @@ -261,6 +261,7 @@ handle_wire_finished (void *cls, fbm = parse_fees (&master_pub, fees, &wr.details.ok.fees_len); + wr.details.ok.fees = fbm; if (NULL == fbm) { /* bogus reply */ diff --git a/src/testing/testing_api_cmd_oauth.c b/src/testing/testing_api_cmd_oauth.c index 514b4ac8..0bcf2f68 100644 --- a/src/testing/testing_api_cmd_oauth.c +++ b/src/testing/testing_api_cmd_oauth.c @@ -310,6 +310,7 @@ cleanup (void *cls, (void) toe; if (NULL == rc) return; + MHD_destroy_post_processor (rc->pp); GNUNET_free (rc->code); GNUNET_free (rc->client_id); GNUNET_free (rc->redirect_uri); -- cgit v1.2.3