diff options
Diffstat (limited to 'src/pq/pq_result_helper.c')
-rw-r--r-- | src/pq/pq_result_helper.c | 1007 |
1 files changed, 803 insertions, 204 deletions
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c index 9441412d4..384200cfb 100644 --- a/src/pq/pq_result_helper.c +++ b/src/pq/pq_result_helper.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 @@ -20,164 +20,144 @@ */ #include "platform.h" #include <gnunet/gnunet_util_lib.h> +#include "pq_common.h" #include "taler_pq_lib.h" /** - * Extract a currency amount from a query result according to the - * given specification. + * Extract an amount from a tuple including the currency from a Postgres + * database @a result at row @a row. * - * @param result the result to extract the amount from - * @param row which row of the result to extract the amount from (needed as results can have multiple rows) - * @param currency currency to use for @a r_amount_nbo - * @param val_name name of the column with the amount's "value", must include the substring "_val". - * @param frac_name name of the column with the amount's "fractional" value, must include the substring "_frac". - * @param[out] r_amount_nbo where to store the amount, in network byte order + * @param cls closure; not used + * @param result where to extract data from + * @param row row to extract data from + * @param fname name (or prefix) of the fields to extract from + * @param[in,out] dst_size where to store size of result, may be NULL + * @param[out] dst where to store the result * @return * #GNUNET_YES if all results could be extracted * #GNUNET_NO if at least one result was NULL * #GNUNET_SYSERR if a result was invalid (non-existing field) */ static enum GNUNET_GenericReturnValue -extract_amount_nbo_helper (PGresult *result, - int row, - const char *currency, - const char *val_name, - const char *frac_name, - struct TALER_AmountNBO *r_amount_nbo) +extract_amount_currency_tuple (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) { - int val_num; - int frac_num; - int len; - - /* These checks are simply to check that clients obey by our naming - conventions, and not for any functional reason */ - GNUNET_assert (NULL != - strstr (val_name, - "_val")); - GNUNET_assert (NULL != - strstr (frac_name, - "_frac")); - /* Set return value to invalid in case we don't finish */ - memset (r_amount_nbo, - 0, - sizeof (struct TALER_AmountNBO)); - val_num = PQfnumber (result, - val_name); - frac_num = PQfnumber (result, - frac_name); - if (val_num < 0) + struct TALER_Amount *r_amount = dst; + int col; + + (void) cls; + if (sizeof (struct TALER_Amount) != *dst_size) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' does not exist in result\n", - val_name); + GNUNET_break (0); return GNUNET_SYSERR; } - if (frac_num < 0) + + /* Set return value to invalid in case we don't finish */ + memset (r_amount, + 0, + sizeof (struct TALER_Amount)); + col = PQfnumber (result, + fname); + if (col < 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Field `%s' does not exist in result\n", - frac_name); + fname); return GNUNET_SYSERR; } - if ( (PQgetisnull (result, - row, - val_num)) || - (PQgetisnull (result, - row, - frac_num)) ) + if (PQgetisnull (result, + row, + col)) { return GNUNET_NO; } - /* Note that Postgres stores value in NBO internally, - so no conversion needed in this case */ - r_amount_nbo->value = *(uint64_t *) PQgetvalue (result, - row, - val_num); - r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, - row, - frac_num); - if (GNUNET_ntohll (r_amount_nbo->value) >= TALER_AMOUNT_MAX_VALUE) + + /* Parse the tuple */ { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' exceeds legal range\n", - val_name); - return GNUNET_SYSERR; + struct TALER_PQ_AmountCurrencyP ap; + const char *in; + size_t size; + + size = PQgetlength (result, + row, + col); + if ( (size >= sizeof (ap)) || + (size <= sizeof (ap) - TALER_CURRENCY_LEN) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Incorrect size of binary field `%s' (got %zu, expected (%zu-%zu))\n", + fname, + size, + sizeof (ap) - TALER_CURRENCY_LEN, + sizeof (ap)); + return GNUNET_SYSERR; + } + + in = PQgetvalue (result, + row, + col); + memset (&ap.c, + 0, + TALER_CURRENCY_LEN); + memcpy (&ap, + in, + size); + if (3 != ntohl (ap.cnt)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Incorrect number of elements in tuple-field `%s'\n", + fname); + return GNUNET_SYSERR; + } + /* TODO[oec]: OID-checks? */ + + r_amount->value = GNUNET_ntohll (ap.v); + r_amount->fraction = ntohl (ap.f); + memcpy (r_amount->currency, + ap.c, + TALER_CURRENCY_LEN); + if ('\0' != r_amount->currency[TALER_CURRENCY_LEN - 1]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid currency (not 0-terminated) in tuple field `%s'\n", + fname); + /* be sure nobody uses this by accident */ + memset (r_amount, + 0, + sizeof (struct TALER_Amount)); + return GNUNET_SYSERR; + } } - if (ntohl (r_amount_nbo->fraction) >= TALER_AMOUNT_FRAC_BASE) + + if (r_amount->value >= TALER_AMOUNT_MAX_VALUE) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Field `%s' exceeds legal range\n", - frac_name); + "Value in field `%s' exceeds legal range\n", + fname); return GNUNET_SYSERR; } - len = GNUNET_MIN (TALER_CURRENCY_LEN - 1, - strlen (currency)); - GNUNET_memcpy (r_amount_nbo->currency, - currency, - len); - return GNUNET_OK; -} - - -/** - * Extract data from a Postgres database @a result at row @a row. - * - * @param cls closure, a `const char *` giving the currency - * @param result where to extract data from - * @param row row to extract data from - * @param fname name (or prefix) of the fields to extract from - * @param[in,out] dst_size where to store size of result, may be NULL - * @param[out] dst where to store the result - * @return - * #GNUNET_YES if all results could be extracted - * #GNUNET_NO if at least one result was NULL - * #GNUNET_SYSERR if a result was invalid (non-existing field) - */ -static enum GNUNET_GenericReturnValue -extract_amount_nbo (void *cls, - PGresult *result, - int row, - const char *fname, - size_t *dst_size, - void *dst) -{ - const char *currency = cls; - char *val_name; - char *frac_name; - enum GNUNET_GenericReturnValue ret; - - if (sizeof (struct TALER_AmountNBO) != *dst_size) + if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE) { - GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fraction in field `%s' exceeds legal range\n", + fname); return GNUNET_SYSERR; } - GNUNET_asprintf (&val_name, - "%s_val", - fname); - GNUNET_asprintf (&frac_name, - "%s_frac", - fname); - ret = extract_amount_nbo_helper (result, - row, - currency, - val_name, - frac_name, - dst); - GNUNET_free (val_name); - GNUNET_free (frac_name); - return ret; + return GNUNET_OK; } struct GNUNET_PQ_ResultSpec -TALER_PQ_result_spec_amount_nbo (const char *name, - const char *currency, - struct TALER_AmountNBO *amount) +TALER_PQ_result_spec_amount_with_currency (const char *name, + struct TALER_Amount *amount) { struct GNUNET_PQ_ResultSpec res = { - .conv = &extract_amount_nbo, - .cls = (void *) currency, + .conv = &extract_amount_currency_tuple, .dst = (void *) amount, .dst_size = sizeof (*amount), .fname = name @@ -188,7 +168,7 @@ TALER_PQ_result_spec_amount_nbo (const char *name, /** - * Extract data from a Postgres database @a result at row @a row. + * Extract an amount from a tuple from a Postgres database @a result at row @a row. * * @param cls closure, a `const char *` giving the currency * @param result where to extract data from @@ -202,47 +182,125 @@ TALER_PQ_result_spec_amount_nbo (const char *name, * #GNUNET_SYSERR if a result was invalid (non-existing field) */ static enum GNUNET_GenericReturnValue -extract_amount (void *cls, - PGresult *result, - int row, - const char *fname, - size_t *dst_size, - void *dst) +extract_amount_tuple (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) { - const char *currency = cls; struct TALER_Amount *r_amount = dst; - char *val_name; - char *frac_name; - struct TALER_AmountNBO amount_nbo; - enum GNUNET_GenericReturnValue ret; + const char *currency = cls; + int col; + size_t len; - if (sizeof (struct TALER_AmountNBO) != *dst_size) + if (sizeof (struct TALER_Amount) != *dst_size) { GNUNET_break (0); return GNUNET_SYSERR; } - GNUNET_asprintf (&val_name, - "%s_val", - fname); - GNUNET_asprintf (&frac_name, - "%s_frac", + + /* Set return value to invalid in case we don't finish */ + memset (r_amount, + 0, + sizeof (struct TALER_Amount)); + col = PQfnumber (result, fname); - ret = extract_amount_nbo_helper (result, - row, - currency, - val_name, - frac_name, - &amount_nbo); - if (GNUNET_OK == ret) - TALER_amount_ntoh (r_amount, - &amount_nbo); - else - memset (r_amount, - 0, - sizeof (struct TALER_Amount)); - GNUNET_free (val_name); - GNUNET_free (frac_name); - return ret; + if (col < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Field `%s' does not exist in result\n", + fname); + return GNUNET_SYSERR; + } + if (PQgetisnull (result, + row, + col)) + { + return GNUNET_NO; + } + + /* Parse the tuple */ + { + struct TALER_PQ_AmountP ap; + const char *in; + size_t size; + + size = PQgetlength (result, + row, + col); + in = PQgetvalue (result, + row, + col); + if (sizeof(struct TALER_PQ_AmountNullP) == size) + { + struct TALER_PQ_AmountNullP apn; + + memcpy (&apn, + in, + size); + if ( (2 == ntohl (apn.cnt)) && + (-1 == (int32_t) ntohl (apn.sz_v)) && + (-1 == (int32_t) ntohl (apn.sz_f)) ) + { + /* is NULL! */ + return GNUNET_NO; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Incorrect size of binary field `%s' and not NULL (got %zu, expected %zu)\n", + fname, + size, + sizeof(ap)); + return GNUNET_SYSERR; + } + if (sizeof(ap) != size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Incorrect size of binary field `%s' (got %zu, expected %zu)\n", + fname, + size, + sizeof(ap)); + return GNUNET_SYSERR; + } + + memcpy (&ap, + in, + size); + if (2 != ntohl (ap.cnt)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Incorrect number of elements in tuple-field `%s'\n", + fname); + return GNUNET_SYSERR; + } + /* TODO[oec]: OID-checks? */ + + r_amount->value = GNUNET_ntohll (ap.v); + r_amount->fraction = ntohl (ap.f); + } + + if (r_amount->value >= TALER_AMOUNT_MAX_VALUE) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Value in field `%s' exceeds legal range\n", + fname); + return GNUNET_SYSERR; + } + if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fraction in field `%s' exceeds legal range\n", + fname); + return GNUNET_SYSERR; + } + + len = GNUNET_MIN (TALER_CURRENCY_LEN - 1, + strlen (currency)); + + GNUNET_memcpy (r_amount->currency, + currency, + len); + return GNUNET_OK; } @@ -252,7 +310,7 @@ TALER_PQ_result_spec_amount (const char *name, struct TALER_Amount *amount) { struct GNUNET_PQ_ResultSpec res = { - .conv = &extract_amount, + .conv = &extract_amount_tuple, .cls = (void *) currency, .dst = (void *) amount, .dst_size = sizeof (*amount), @@ -388,6 +446,7 @@ extract_denom_pub (void *cls, void *dst) { struct TALER_DenominationPublicKey *pk = dst; + struct GNUNET_CRYPTO_BlindSignPublicKey *bpk; size_t len; const char *res; int fnum; @@ -425,33 +484,47 @@ extract_denom_pub (void *cls, sizeof (be)); res += sizeof (be); len -= sizeof (be); - pk->cipher = ntohl (be[0]); + bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bpk->cipher = ntohl (be[0]); + bpk->rc = 1; pk->age_mask.bits = ntohl (be[1]); - switch (pk->cipher) + switch (bpk->cipher) { - case TALER_DENOMINATION_RSA: - pk->details.rsa_public_key + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + bpk->details.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (res, len); - if (NULL == pk->details.rsa_public_key) + if (NULL == bpk->details.rsa_public_key) { GNUNET_break (0); + GNUNET_free (bpk); return GNUNET_SYSERR; } + pk->bsign_pub_key = bpk; + GNUNET_CRYPTO_hash (res, + len, + &bpk->pub_key_hash); return GNUNET_OK; - case TALER_DENOMINATION_CS: - if (sizeof (pk->details.cs_public_key) != len) + case GNUNET_CRYPTO_BSA_CS: + if (sizeof (bpk->details.cs_public_key) != len) { GNUNET_break (0); + GNUNET_free (bpk); return GNUNET_SYSERR; } - GNUNET_memcpy (&pk->details.cs_public_key, + GNUNET_memcpy (&bpk->details.cs_public_key, res, len); + pk->bsign_pub_key = bpk; + GNUNET_CRYPTO_hash (res, + len, + &bpk->pub_key_hash); return GNUNET_OK; - default: - GNUNET_break (0); } + GNUNET_break (0); + GNUNET_free (bpk); return GNUNET_SYSERR; } @@ -511,6 +584,7 @@ extract_denom_sig (void *cls, void *dst) { struct TALER_DenominationSignature *sig = dst; + struct GNUNET_CRYPTO_UnblindedSignature *ubs; size_t len; const char *res; int fnum; @@ -553,32 +627,40 @@ extract_denom_sig (void *cls, } res += sizeof (be); len -= sizeof (be); - sig->cipher = ntohl (be[0]); - switch (sig->cipher) + ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature); + ubs->rc = 1; + ubs->cipher = ntohl (be[0]); + switch (ubs->cipher) { - case TALER_DENOMINATION_RSA: - sig->details.rsa_signature + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + ubs->details.rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (res, len); - if (NULL == sig->details.rsa_signature) + if (NULL == ubs->details.rsa_signature) { GNUNET_break (0); + GNUNET_free (ubs); return GNUNET_SYSERR; } + sig->unblinded_sig = ubs; return GNUNET_OK; - case TALER_DENOMINATION_CS: - if (sizeof (sig->details.cs_signature) != len) + case GNUNET_CRYPTO_BSA_CS: + if (sizeof (ubs->details.cs_signature) != len) { GNUNET_break (0); + GNUNET_free (ubs); return GNUNET_SYSERR; } - GNUNET_memcpy (&sig->details.cs_signature, + GNUNET_memcpy (&ubs->details.cs_signature, res, len); + sig->unblinded_sig = ubs; return GNUNET_OK; - default: - GNUNET_break (0); } + GNUNET_break (0); + GNUNET_free (ubs); return GNUNET_SYSERR; } @@ -638,6 +720,7 @@ extract_blinded_denom_sig (void *cls, void *dst) { struct TALER_BlindedDenominationSignature *sig = dst; + struct GNUNET_CRYPTO_BlindedSignature *bs; size_t len; const char *res; int fnum; @@ -680,32 +763,40 @@ extract_blinded_denom_sig (void *cls, } res += sizeof (be); len -= sizeof (be); - sig->cipher = ntohl (be[0]); - switch (sig->cipher) + bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + bs->rc = 1; + bs->cipher = ntohl (be[0]); + switch (bs->cipher) { - case TALER_DENOMINATION_RSA: - sig->details.blinded_rsa_signature + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + bs->details.blinded_rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (res, len); - if (NULL == sig->details.blinded_rsa_signature) + if (NULL == bs->details.blinded_rsa_signature) { GNUNET_break (0); + GNUNET_free (bs); return GNUNET_SYSERR; } + sig->blinded_sig = bs; return GNUNET_OK; - case TALER_DENOMINATION_CS: - if (sizeof (sig->details.blinded_cs_answer) != len) + case GNUNET_CRYPTO_BSA_CS: + if (sizeof (bs->details.blinded_cs_answer) != len) { GNUNET_break (0); + GNUNET_free (bs); return GNUNET_SYSERR; } - GNUNET_memcpy (&sig->details.blinded_cs_answer, + GNUNET_memcpy (&bs->details.blinded_cs_answer, res, len); + sig->blinded_sig = bs; return GNUNET_OK; - default: - GNUNET_break (0); } + GNUNET_break (0); + GNUNET_free (bs); return GNUNET_SYSERR; } @@ -766,6 +857,7 @@ extract_blinded_planchet (void *cls, void *dst) { struct TALER_BlindedPlanchet *bp = dst; + struct GNUNET_CRYPTO_BlindedMessage *bm; size_t len; const char *res; int fnum; @@ -808,29 +900,36 @@ extract_blinded_planchet (void *cls, } res += sizeof (be); len -= sizeof (be); - bp->cipher = ntohl (be[0]); - switch (bp->cipher) + bm = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); + bm->rc = 1; + bm->cipher = ntohl (be[0]); + switch (bm->cipher) { - case TALER_DENOMINATION_RSA: - bp->details.rsa_blinded_planchet.blinded_msg_size + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: + bm->details.rsa_blinded_message.blinded_msg_size = len; - bp->details.rsa_blinded_planchet.blinded_msg + bm->details.rsa_blinded_message.blinded_msg = GNUNET_memdup (res, len); + bp->blinded_message = bm; return GNUNET_OK; - case TALER_DENOMINATION_CS: - if (sizeof (bp->details.cs_blinded_planchet) != len) + case GNUNET_CRYPTO_BSA_CS: + if (sizeof (bm->details.cs_blinded_message) != len) { GNUNET_break (0); + GNUNET_free (bm); return GNUNET_SYSERR; } - GNUNET_memcpy (&bp->details.cs_blinded_planchet, + GNUNET_memcpy (&bm->details.cs_blinded_message, res, len); + bp->blinded_message = bm; return GNUNET_OK; - default: - GNUNET_break (0); } + GNUNET_break (0); + GNUNET_free (bm); return GNUNET_SYSERR; } @@ -891,6 +990,7 @@ extract_exchange_withdraw_values (void *cls, void *dst) { struct TALER_ExchangeWithdrawValues *alg_values = dst; + struct GNUNET_CRYPTO_BlindingInputValues *bi; size_t len; const char *res; int fnum; @@ -933,29 +1033,37 @@ extract_exchange_withdraw_values (void *cls, } res += sizeof (be); len -= sizeof (be); - alg_values->cipher = ntohl (be[0]); - switch (alg_values->cipher) + bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues); + bi->rc = 1; + bi->cipher = ntohl (be[0]); + switch (bi->cipher) { - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_INVALID: + break; + case GNUNET_CRYPTO_BSA_RSA: if (0 != len) { GNUNET_break (0); + GNUNET_free (bi); return GNUNET_SYSERR; } + alg_values->blinding_inputs = bi; return GNUNET_OK; - case TALER_DENOMINATION_CS: - if (sizeof (struct TALER_DenominationCSPublicRPairP) != len) + case GNUNET_CRYPTO_BSA_CS: + if (sizeof (bi->details.cs_values) != len) { GNUNET_break (0); + GNUNET_free (bi); return GNUNET_SYSERR; } - GNUNET_memcpy (&alg_values->details.cs_values, + GNUNET_memcpy (&bi->details.cs_values, res, len); + alg_values->blinding_inputs = bi; return GNUNET_OK; - default: - GNUNET_break (0); } + GNUNET_break (0); + GNUNET_free (bi); return GNUNET_SYSERR; } @@ -975,4 +1083,495 @@ TALER_PQ_result_spec_exchange_withdraw_values ( } +/** + * Closure for the array result specifications. Contains type information + * for the generic parser extract_array_generic and out-pointers for the results. + */ +struct ArrayResultCls +{ + /** + * Oid of the expected type, must match the oid in the header of the PQResult struct + */ + Oid oid; + + /** + * Target type + */ + enum TALER_PQ_ArrayType typ; + + /** + * If not 0, defines the expected size of each entry + */ + size_t same_size; + + /** + * Out-pointer to write the number of elements in the array + */ + size_t *num; + + /** + * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0, + * allocate and put the array of @a num sizes here. NULL otherwise + */ + size_t **sizes; + + /** + * DB_connection, needed for OID-lookup for composite types + */ + const struct GNUNET_PQ_Context *db; + + /** + * Currency information for amount composites + */ + char currency[TALER_CURRENCY_LEN]; +}; + + +/** + * Extract data from a Postgres database @a result as array of a specific type + * from row @a row. The type information and optionally additional + * out-parameters are given in @a cls which is of type array_result_cls. + * + * @param cls closure of type array_result_cls + * @param result where to extract data from + * @param row row to extract data from + * @param fname name (or prefix) of the fields to extract from + * @param[in,out] dst_size where to store size of result, may be NULL + * @param[out] dst where to store the result + * @return + * #GNUNET_YES if all results could be extracted + * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) + */ +static enum GNUNET_GenericReturnValue +extract_array_generic ( + void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + const struct ArrayResultCls *info = cls; + int data_sz; + char *data; + void *out = NULL; + struct GNUNET_PQ_ArrayHeader_P header; + int col_num; + + GNUNET_assert (NULL != dst); + *((void **) dst) = NULL; + + #define FAIL_IF(cond) \ + do { \ + if ((cond)) \ + { \ + GNUNET_break (! (cond)); \ + goto FAIL; \ + } \ + } while (0) + + col_num = PQfnumber (result, fname); + FAIL_IF (0 > col_num); + + data_sz = PQgetlength (result, row, col_num); + FAIL_IF (0 > data_sz); + FAIL_IF (sizeof(header) > (size_t) data_sz); + + data = PQgetvalue (result, row, col_num); + FAIL_IF (NULL == data); + + { + struct GNUNET_PQ_ArrayHeader_P *h = + (struct GNUNET_PQ_ArrayHeader_P *) data; + + header.ndim = ntohl (h->ndim); + header.has_null = ntohl (h->has_null); + header.oid = ntohl (h->oid); + header.dim = ntohl (h->dim); + header.lbound = ntohl (h->lbound); + + FAIL_IF (1 != header.ndim); + FAIL_IF (INT_MAX <= header.dim); + FAIL_IF (0 != header.has_null); + FAIL_IF (1 != header.lbound); + FAIL_IF (info->oid != header.oid); + } + + if (NULL != info->num) + *info->num = header.dim; + + { + char *in = data + sizeof(header); + + switch (info->typ) + { + case TALER_PQ_array_of_amount: + { + struct TALER_Amount *amounts; + if (NULL != dst_size) + *dst_size = sizeof(struct TALER_Amount) * (header.dim); + + amounts = GNUNET_new_array (header.dim, + struct TALER_Amount); + *((void **) dst) = amounts; + + for (uint32_t i = 0; i < header.dim; i++) + { + struct TALER_PQ_AmountP ap; + struct TALER_Amount *amount = &amounts[i]; + uint32_t val; + size_t sz; + + GNUNET_memcpy (&val, + in, + sizeof(val)); + sz = ntohl (val); + in += sizeof(val); + + /* total size for this array-entry */ + FAIL_IF (sizeof(ap) != sz); + + GNUNET_memcpy (&ap, + in, + sz); + FAIL_IF (2 != ntohl (ap.cnt)); + + amount->value = GNUNET_ntohll (ap.v); + amount->fraction = ntohl (ap.f); + GNUNET_memcpy (amount->currency, + info->currency, + TALER_CURRENCY_LEN); + + in += sizeof(struct TALER_PQ_AmountP); + } + return GNUNET_OK; + } + case TALER_PQ_array_of_denom_hash: + if (NULL != dst_size) + *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim); + out = GNUNET_new_array (header.dim, + struct TALER_DenominationHashP); + *((void **) dst) = out; + for (uint32_t i = 0; i < header.dim; i++) + { + uint32_t val; + size_t sz; + + GNUNET_memcpy (&val, + in, + sizeof(val)); + sz = ntohl (val); + FAIL_IF (sz != sizeof(struct TALER_DenominationHashP)); + in += sizeof(uint32_t); + *(struct TALER_DenominationHashP *) out = + *(struct TALER_DenominationHashP *) in; + in += sz; + out += sz; + } + return GNUNET_OK; + + case TALER_PQ_array_of_hash_code: + if (NULL != dst_size) + *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim); + out = GNUNET_new_array (header.dim, + struct GNUNET_HashCode); + *((void **) dst) = out; + for (uint32_t i = 0; i < header.dim; i++) + { + uint32_t val; + size_t sz; + + GNUNET_memcpy (&val, + in, + sizeof(val)); + sz = ntohl (val); + FAIL_IF (sz != sizeof(struct GNUNET_HashCode)); + in += sizeof(uint32_t); + *(struct GNUNET_HashCode *) out = + *(struct GNUNET_HashCode *) in; + in += sz; + out += sz; + } + return GNUNET_OK; + + case TALER_PQ_array_of_blinded_coin_hash: + if (NULL != dst_size) + *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim); + out = GNUNET_new_array (header.dim, + struct TALER_BlindedCoinHashP); + *((void **) dst) = out; + for (uint32_t i = 0; i < header.dim; i++) + { + uint32_t val; + size_t sz; + + GNUNET_memcpy (&val, + in, + sizeof(val)); + sz = ntohl (val); + FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP)); + in += sizeof(uint32_t); + *(struct TALER_BlindedCoinHashP *) out = + *(struct TALER_BlindedCoinHashP *) in; + in += sz; + out += sz; + } + return GNUNET_OK; + + case TALER_PQ_array_of_blinded_denom_sig: + { + struct TALER_BlindedDenominationSignature *denom_sigs; + if (0 == header.dim) + { + if (NULL != dst_size) + *dst_size = 0; + break; + } + + denom_sigs = GNUNET_new_array (header.dim, + struct TALER_BlindedDenominationSignature); + *((void **) dst) = denom_sigs; + + /* copy data */ + for (uint32_t i = 0; i < header.dim; i++) + { + struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i]; + struct GNUNET_CRYPTO_BlindedSignature *bs; + uint32_t be[2]; + uint32_t val; + size_t sz; + + GNUNET_memcpy (&val, + in, + sizeof(val)); + sz = ntohl (val); + FAIL_IF (sizeof(be) > sz); + + in += sizeof(val); + GNUNET_memcpy (&be, + in, + sizeof(be)); + FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */ + + in += sizeof(be); + sz -= sizeof(be); + bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + bs->cipher = ntohl (be[0]); + bs->rc = 1; + switch (bs->cipher) + { + case GNUNET_CRYPTO_BSA_RSA: + bs->details.blinded_rsa_signature + = GNUNET_CRYPTO_rsa_signature_decode (in, + sz); + if (NULL == bs->details.blinded_rsa_signature) + { + GNUNET_free (bs); + FAIL_IF (true); + } + break; + case GNUNET_CRYPTO_BSA_CS: + if (sizeof(bs->details.blinded_cs_answer) != sz) + { + GNUNET_free (bs); + FAIL_IF (true); + } + GNUNET_memcpy (&bs->details.blinded_cs_answer, + in, + sz); + break; + default: + GNUNET_free (bs); + FAIL_IF (true); + } + denom_sig->blinded_sig = bs; + in += sz; + } + return GNUNET_OK; + } + default: + FAIL_IF (true); + } + } +FAIL: + GNUNET_free (*(void **) dst); + return GNUNET_SYSERR; +#undef FAIL_IF +} + + +/** + * Cleanup of the data and closure of an array spec. + */ +static void +array_cleanup (void *cls, + void *rd) +{ + struct ArrayResultCls *info = cls; + void **dst = rd; + + if ((0 == info->same_size) && + (NULL != info->sizes)) + GNUNET_free (*(info->sizes)); + + /* Clean up signatures, if applicable */ + if (TALER_PQ_array_of_blinded_denom_sig == info->typ) + { + struct TALER_BlindedDenominationSignature *denom_sigs = *dst; + GNUNET_assert (NULL != info->num); + for (size_t i = 0; i < *info->num; i++) + GNUNET_free (denom_sigs[i].blinded_sig); + } + + GNUNET_free (cls); + GNUNET_free (*dst); + *dst = NULL; +} + + +struct GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_array_blinded_denom_sig ( + struct GNUNET_PQ_Context *db, + const char *name, + size_t *num, + struct TALER_BlindedDenominationSignature **denom_sigs) +{ + struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); + + info->num = num; + info->typ = TALER_PQ_array_of_blinded_denom_sig; + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "bytea", + &info->oid)); + + struct GNUNET_PQ_ResultSpec res = { + .conv = extract_array_generic, + .cleaner = array_cleanup, + .dst = (void *) denom_sigs, + .fname = name, + .cls = info + }; + return res; + +}; + +struct GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_array_blinded_coin_hash ( + struct GNUNET_PQ_Context *db, + const char *name, + size_t *num, + struct TALER_BlindedCoinHashP **h_coin_evs) +{ + struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); + + info->num = num; + info->typ = TALER_PQ_array_of_blinded_coin_hash; + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "bytea", + &info->oid)); + + struct GNUNET_PQ_ResultSpec res = { + .conv = extract_array_generic, + .cleaner = array_cleanup, + .dst = (void *) h_coin_evs, + .fname = name, + .cls = info + }; + return res; + +}; + +struct GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_array_denom_hash ( + struct GNUNET_PQ_Context *db, + const char *name, + size_t *num, + struct TALER_DenominationHashP **denom_hs) +{ + struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); + + info->num = num; + info->typ = TALER_PQ_array_of_denom_hash; + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "bytea", + &info->oid)); + + struct GNUNET_PQ_ResultSpec res = { + .conv = extract_array_generic, + .cleaner = array_cleanup, + .dst = (void *) denom_hs, + .fname = name, + .cls = info + }; + return res; + +}; + +struct GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_array_amount ( + struct GNUNET_PQ_Context *db, + const char *name, + const char *currency, + size_t *num, + struct TALER_Amount **amounts) +{ + struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); + + info->num = num; + info->typ = TALER_PQ_array_of_amount; + info->db = db; + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "taler_amount", + &info->oid)); + + { + size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1, + strlen (currency)); + GNUNET_memcpy (&info->currency, + currency, + clen); + } + + struct GNUNET_PQ_ResultSpec res = { + .conv = extract_array_generic, + .cleaner = array_cleanup, + .dst = (void *) amounts, + .fname = name, + .cls = info, + }; + return res; +} + + +struct GNUNET_PQ_ResultSpec +TALER_PQ_result_spec_array_hash_code ( + struct GNUNET_PQ_Context *db, + const char *name, + size_t *num, + struct GNUNET_HashCode **hashes) +{ + struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); + + info->num = num; + info->typ = TALER_PQ_array_of_hash_code; + info->db = db; + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "gnunet_hashcode", + &info->oid)); + + struct GNUNET_PQ_ResultSpec res = { + .conv = extract_array_generic, + .cleaner = array_cleanup, + .dst = (void *) hashes, + .fname = name, + .cls = info, + }; + return res; +} + /* end of pq_result_helper.c */ |