donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

pq_query_helper.c (23111B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 Taler Systems SA
      4 
      5   TALER 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   TALER 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   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file pq/pq_query_helper.c
     18  * @brief helper functions for Taler-specific libpq (PostGres) interactions
     19  * @author Johannes Casaburi
     20  */
     21 #include <gnunet/gnunet_common.h>
     22 #include <gnunet/gnunet_util_lib.h>
     23 #include <gnunet/gnunet_pq_lib.h>
     24 #include <taler/taler_pq_lib.h>
     25 #include "donau_util.h"
     26 #include "donau_pq_lib.h"
     27 #include "pq_common.h"
     28 
     29 
     30 /**
     31  * Function called to convert input argument into SQL parameters.
     32  *
     33  * @param cls closure
     34  * @param data pointer to input argument
     35  * @param data_len number of bytes in @a data (if applicable)
     36  * @param[out] param_values SQL data to set
     37  * @param[out] param_lengths SQL length data to set
     38  * @param[out] param_formats SQL format data to set
     39  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
     40  * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
     41  * @param scratch_length number of entries left in @a scratch
     42  * @return -1 on error, number of offsets used in @a scratch otherwise
     43  */
     44 static int
     45 qconv_donation_unit_pub (void *cls,
     46                          const void *data,
     47                          size_t data_len,
     48                          void *param_values[],
     49                          int param_lengths[],
     50                          int param_formats[],
     51                          unsigned int param_length,
     52                          void *scratch[],
     53                          unsigned int scratch_length)
     54 {
     55   const struct DONAU_DonationUnitPublicKey *donation_unit_pub = data;
     56   const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp = donation_unit_pub->
     57                                                        bsign_pub_key;
     58   size_t tlen;
     59   size_t len;
     60   uint32_t be[1];
     61   char *buf;
     62   void *tbuf;
     63 
     64   (void) cls;
     65   (void) data_len;
     66   GNUNET_assert (1 == param_length);
     67   GNUNET_assert (scratch_length > 0);
     68   GNUNET_break (NULL == cls);
     69   be[0] = htonl ((uint32_t) bsp->cipher);
     70   switch (bsp->cipher)
     71   {
     72   case GNUNET_CRYPTO_BSA_RSA:
     73     tlen = GNUNET_CRYPTO_rsa_public_key_encode (
     74       bsp->details.rsa_public_key,
     75       &tbuf);
     76     break;
     77   case GNUNET_CRYPTO_BSA_CS:
     78     tlen = sizeof (bsp->details.cs_public_key);
     79     break;
     80   default:
     81     GNUNET_assert (0);
     82   }
     83   len = tlen + sizeof (be);
     84   buf = GNUNET_malloc (len);
     85   GNUNET_memcpy (buf,
     86                  be,
     87                  sizeof (be));
     88   switch (bsp->cipher)
     89   {
     90   case GNUNET_CRYPTO_BSA_RSA:
     91     GNUNET_memcpy (&buf[sizeof (be)],
     92                    tbuf,
     93                    tlen);
     94     GNUNET_free (tbuf);
     95     break;
     96   case GNUNET_CRYPTO_BSA_CS:
     97     GNUNET_memcpy (&buf[sizeof (be)],
     98                    &bsp->details.cs_public_key,
     99                    tlen);
    100     break;
    101   default:
    102     GNUNET_assert (0);
    103   }
    104 
    105   scratch[0] = buf;
    106   param_values[0] = (void *) buf;
    107   param_lengths[0] = len;
    108   param_formats[0] = 1;
    109   return 1;
    110 }
    111 
    112 
    113 struct GNUNET_PQ_QueryParam
    114 DONAU_PQ_query_param_donation_unit_pub (
    115   const struct DONAU_DonationUnitPublicKey *donation_unit_pub)
    116 {
    117   struct GNUNET_PQ_QueryParam res = {
    118     .conv = &qconv_donation_unit_pub,
    119     .data = donation_unit_pub,
    120     .num_params = 1
    121   };
    122 
    123   return res;
    124 }
    125 
    126 
    127 /**
    128  * Closure for the array result specifications.  Contains type information
    129  * for the generic parser extract_array_generic and out-pointers for the results.
    130  */
    131 struct ArrayResultCls
    132 {
    133   /**
    134    * Oid of the expected type, must match the oid in the header of the PQResult struct
    135    */
    136   Oid oid;
    137 
    138   /**
    139    * Target type
    140    */
    141   // enum TALER_PQ_ArrayType typ;
    142 
    143   /**
    144    * If not 0, defines the expected size of each entry
    145    */
    146   size_t same_size;
    147 
    148   /**
    149    * Out-pointer to write the number of elements in the array
    150    */
    151   size_t *num;
    152 
    153   /**
    154    * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0,
    155    * allocate and put the array of @a num sizes here. NULL otherwise
    156    */
    157   size_t **sizes;
    158 
    159   /**
    160    * DB_connection, needed for OID-lookup for composite types
    161    */
    162   const struct GNUNET_PQ_Context *db;
    163 
    164   /**
    165    * Currency information for amount composites
    166    */
    167   char currency[TALER_CURRENCY_LEN];
    168 };
    169 
    170 /**
    171  * Closure for the array type handlers.
    172  *
    173  * May contain sizes information for the data, given (and handled) by the
    174  * caller.
    175  */
    176 struct qconv_array_cls
    177 {
    178   /**
    179    * If not null, contains the array of sizes (the size of the array is the
    180    * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free
    181    * this memory.
    182    *
    183    * If not null, this value has precedence over @a sizes, which MUST be NULL */
    184   const size_t *sizes;
    185 
    186   /**
    187    * If @a size and @a c_sizes are NULL, this field defines the same size
    188    * for each element in the array.
    189    */
    190   size_t same_size;
    191 
    192   /**
    193    * If true, the array parameter to the data pointer to the qconv_array is a
    194    * continuous byte array of data, either with @a same_size each or sizes
    195    * provided bytes by @a sizes;
    196    */
    197   bool continuous;
    198 
    199   /**
    200    * Type of the array elements
    201    */
    202   enum DONAU_PQ_ArrayType typ;
    203 
    204   /**
    205    * Oid of the array elements
    206    */
    207   Oid oid;
    208 
    209   /**
    210    * db context, needed for OID-lookup of basis-types
    211    */
    212   struct GNUNET_PQ_Context *db;
    213 };
    214 
    215 /**
    216  * Function called to convert input argument into SQL parameters for arrays
    217  *
    218  * Note: the format for the encoding of arrays for libpq is not very well
    219  * documented.  We peeked into various sources (postgresql and libpqtypes) for
    220  * guidance.
    221  *
    222  * @param cls Closure of type struct qconv_array_cls*
    223  * @param data Pointer to first element in the array
    224  * @param data_len Number of _elements_ in array @a data (if applicable)
    225  * @param[out] param_values SQL data to set
    226  * @param[out] param_lengths SQL length data to set
    227  * @param[out] param_formats SQL format data to set
    228  * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
    229  * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
    230  * @param scratch_length number of entries left in @a scratch
    231  * @return -1 on error, number of offsets used in @a scratch otherwise
    232  */
    233 static int
    234 qconv_array (
    235   void *cls,
    236   const void *data,
    237   size_t data_len,
    238   void *param_values[],
    239   int param_lengths[],
    240   int param_formats[],
    241   unsigned int param_length,
    242   void *scratch[],
    243   unsigned int scratch_length)
    244 {
    245   struct qconv_array_cls *meta = cls;
    246   size_t num = data_len;
    247   size_t total_size;
    248   const size_t *sizes;
    249   bool same_sized;
    250   void *elements = NULL;
    251   bool noerror = true;
    252   /* needed to capture the encoded rsa signatures */
    253   void **buffers = NULL;
    254   size_t *buffer_lengths = NULL;
    255 
    256   (void) (param_length);
    257   (void) (scratch_length);
    258 
    259   GNUNET_assert (NULL != meta);
    260   GNUNET_assert (num < INT_MAX);
    261 
    262   sizes = meta->sizes;
    263   same_sized = (0 != meta->same_size);
    264 
    265 #define RETURN_UNLESS(cond) \
    266         do { \
    267           if (! (cond)) \
    268           { \
    269             GNUNET_break ((cond)); \
    270             noerror = false; \
    271             goto DONE; \
    272           } \
    273         } while (0)
    274 
    275   /* Calculate sizes and check bounds */
    276   {
    277     /* num * length-field */
    278     size_t x = sizeof(uint32_t);
    279     size_t y = x * num;
    280     RETURN_UNLESS ((0 == num) || (y / num == x));
    281 
    282     /* size of header */
    283     total_size  = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
    284     total_size += y;
    285     RETURN_UNLESS (total_size >= x);
    286 
    287     /* sizes of elements */
    288     if (same_sized)
    289     {
    290       x = num * meta->same_size;
    291       RETURN_UNLESS ((0 == num) || (x / num == meta->same_size));
    292 
    293       y = total_size;
    294       total_size += x;
    295       RETURN_UNLESS (total_size >= y);
    296     }
    297     else  /* sizes are different per element */
    298     {
    299       switch (meta->typ)
    300       {
    301       case DONAU_PQ_array_of_blinded_du_sig:
    302         {
    303           const struct DONAU_BlindedDonationUnitSignature *du_sigs = data;
    304           size_t len;
    305 
    306           buffers  = GNUNET_new_array (num, void *);
    307           buffer_lengths  = GNUNET_new_array (num, size_t);
    308 
    309           for (size_t i = 0; i<num; i++)
    310           {
    311             const struct GNUNET_CRYPTO_BlindedSignature *bs =
    312               du_sigs[i].blinded_sig;
    313 
    314             switch (bs->cipher)
    315             {
    316             case GNUNET_CRYPTO_BSA_RSA:
    317               len = GNUNET_CRYPTO_rsa_signature_encode (
    318                 bs->details.blinded_rsa_signature,
    319                 &buffers[i]);
    320               RETURN_UNLESS (len != 0);
    321               break;
    322             case GNUNET_CRYPTO_BSA_CS:
    323               len = sizeof (bs->details.blinded_cs_answer);
    324               break;
    325             default:
    326               GNUNET_assert (0);
    327               break;
    328             }
    329 
    330             /* for the cipher and marker */
    331             len += 2 * sizeof(uint32_t);
    332             buffer_lengths[i] = len;
    333 
    334             y = total_size;
    335             total_size += len;
    336             RETURN_UNLESS (total_size >= y);
    337           }
    338           sizes = buffer_lengths;
    339           break;
    340         }
    341       case DONAU_PQ_array_of_unblinded_du_sig:
    342         {
    343           const struct DONAU_DonationUnitSignature *du_sigs = data;
    344           size_t len;
    345 
    346           buffers  = GNUNET_new_array (num,
    347                                        void *);
    348           buffer_lengths  = GNUNET_new_array (num,
    349                                               size_t);
    350           for (size_t i = 0; i<num; i++)
    351           {
    352             const struct GNUNET_CRYPTO_UnblindedSignature *ubs =
    353               du_sigs[i].unblinded_sig;
    354 
    355             switch (ubs->cipher)
    356             {
    357             case GNUNET_CRYPTO_BSA_RSA:
    358               len = GNUNET_CRYPTO_rsa_signature_encode (
    359                 ubs->details.rsa_signature,
    360                 &buffers[i]);
    361               RETURN_UNLESS (len != 0);
    362               break;
    363             case GNUNET_CRYPTO_BSA_CS:
    364               len = sizeof (ubs->details.cs_signature);
    365               break;
    366             default:
    367               GNUNET_assert (0);
    368               break;
    369             }
    370 
    371             /* for the cipher and marker */
    372             len += 2 * sizeof(uint32_t);
    373             buffer_lengths[i] = len;
    374 
    375             y = total_size;
    376             total_size += len;
    377             RETURN_UNLESS (total_size >= y);
    378           }
    379           sizes = buffer_lengths;
    380           break;
    381         }
    382       default:
    383         {
    384           GNUNET_assert (0);
    385           break;
    386         }
    387       }
    388     }
    389 
    390     RETURN_UNLESS (INT_MAX > total_size);
    391     RETURN_UNLESS (0 != total_size);
    392 
    393     elements = GNUNET_malloc (total_size);
    394   }
    395 
    396   /* Write data */
    397   {
    398     char *out = elements;
    399     struct GNUNET_PQ_ArrayHeader_P h = {
    400       .ndim = htonl (1),        /* We only support one-dimensional arrays */
    401       .has_null = htonl (0),    /* We do not support NULL entries in arrays */
    402       .lbound = htonl (1),      /* Default start index value */
    403       .dim = htonl (num),
    404       .oid = htonl (meta->oid),
    405     };
    406 
    407     /* Write header */
    408     GNUNET_memcpy (out,
    409                    &h,
    410                    sizeof(h));
    411     out += sizeof(h);
    412 
    413     /* Write elements */
    414     for (size_t i = 0; i < num; i++)
    415     {
    416       size_t sz = same_sized ? meta->same_size : sizes[i];
    417 
    418       *(uint32_t *) out = htonl (sz);
    419       out += sizeof(uint32_t);
    420       switch (meta->typ)
    421       {
    422       case DONAU_PQ_array_of_blinded_du_sig:
    423         {
    424           const struct DONAU_BlindedDonationUnitSignature *denom_sigs = data;
    425           const struct GNUNET_CRYPTO_BlindedSignature *bs =
    426             denom_sigs[i].blinded_sig;
    427           uint32_t be[2];
    428 
    429           be[0] = htonl ((uint32_t) bs->cipher);
    430           be[1] = htonl (0x01);         /* magic margker: blinded */
    431           GNUNET_memcpy (out,
    432                          &be,
    433                          sizeof(be));
    434           out += sizeof(be);
    435           sz -= sizeof(be);
    436 
    437           switch (bs->cipher)
    438           {
    439           case GNUNET_CRYPTO_BSA_RSA:
    440             /* For RSA, 'same_sized' must have been false */
    441             GNUNET_assert (NULL != buffers);
    442             GNUNET_memcpy (out,
    443                            buffers[i],
    444                            sz);
    445             break;
    446           case GNUNET_CRYPTO_BSA_CS:
    447             GNUNET_memcpy (out,
    448                            &bs->details.blinded_cs_answer,
    449                            sz);
    450             break;
    451           default:
    452             GNUNET_assert (0);
    453           }
    454           break;
    455         }
    456       case DONAU_PQ_array_of_unblinded_du_sig:
    457         {
    458           const struct DONAU_DonationUnitSignature *du_sigs = data;
    459           const struct GNUNET_CRYPTO_UnblindedSignature *ubs =
    460             du_sigs[i].unblinded_sig;
    461           uint32_t be[2];
    462 
    463           be[0] = htonl ((uint32_t) ubs->cipher);
    464           be[1] = htonl (0x00);         /* magic margker: unblinded */
    465           GNUNET_memcpy (out,
    466                          &be,
    467                          sizeof(be));
    468           out += sizeof(be);
    469           sz -= sizeof(be);
    470 
    471           switch (ubs->cipher)
    472           {
    473           case GNUNET_CRYPTO_BSA_RSA:
    474             /* For RSA, 'same_sized' must have been false */
    475             GNUNET_assert (NULL != buffers);
    476             GNUNET_memcpy (out,
    477                            buffers[i],
    478                            sz);
    479             break;
    480           case GNUNET_CRYPTO_BSA_CS:
    481             GNUNET_memcpy (out,
    482                            &ubs->details.cs_signature,
    483                            sz);
    484             break;
    485           default:
    486             GNUNET_assert (0);
    487           }
    488           break;
    489         }
    490       default:
    491         {
    492           GNUNET_assert (0);
    493           break;
    494         }
    495       }
    496       out += sz;
    497     }
    498   }
    499   param_values[0] = elements;
    500   param_lengths[0] = total_size;
    501   param_formats[0] = 1;
    502   scratch[0] = elements;
    503 
    504 DONE:
    505   if (NULL != buffers)
    506   {
    507     for (size_t i = 0; i<num; i++)
    508       GNUNET_free (buffers[i]);
    509     GNUNET_free (buffers);
    510   }
    511   GNUNET_free (buffer_lengths);
    512   if (noerror)
    513     return 1;
    514   return -1;
    515 }
    516 
    517 
    518 /**
    519  * Callback to cleanup a qconv_array_cls to be used during
    520  * GNUNET_PQ_cleanup_query_params_closures
    521  */
    522 static void
    523 qconv_array_cls_cleanup (void *cls)
    524 {
    525   GNUNET_free (cls);
    526 }
    527 
    528 
    529 /**
    530  * Function to generate a typ specific query parameter and corresponding closure
    531  *
    532  * @param num Number of elements in @a elements
    533  * @param continuous If true, @a elements is an continuous array of data
    534  * @param elements Array of @a num elements, either continuous or pointers
    535  * @param sizes Array of @a num sizes, one per element, may be NULL
    536  * @param same_size If not 0, all elements in @a elements have this size
    537  * @param typ Supported internal type of each element in @a elements
    538  * @param oid Oid of the type to be used in Postgres
    539  * @param[in,out] db our database handle for looking up OIDs
    540  * @return Query parameter
    541  */
    542 static struct GNUNET_PQ_QueryParam
    543 query_param_array_generic (
    544   unsigned int num,
    545   bool continuous,
    546   const void *elements,
    547   const size_t *sizes,
    548   size_t same_size,
    549   enum DONAU_PQ_ArrayType typ,
    550   Oid oid,
    551   struct GNUNET_PQ_Context *db)
    552 {
    553   struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
    554 
    555   meta->typ = typ;
    556   meta->oid = oid;
    557   meta->sizes = sizes;
    558   meta->same_size = same_size;
    559   meta->continuous = continuous;
    560   meta->db = db;
    561 
    562   {
    563     struct GNUNET_PQ_QueryParam res = {
    564       .conv = qconv_array,
    565       .conv_cls = meta,
    566       .conv_cls_cleanup = qconv_array_cls_cleanup,
    567       .data = elements,
    568       .size = num,
    569       .num_params = 1,
    570     };
    571 
    572     return res;
    573   }
    574 }
    575 
    576 
    577 struct GNUNET_PQ_QueryParam
    578 DONAU_PQ_query_param_array_blinded_donation_unit_sig (
    579   size_t num,
    580   const struct DONAU_BlindedDonationUnitSignature *du_sigs,
    581   struct GNUNET_PQ_Context *db)
    582 {
    583   Oid oid;
    584 
    585   GNUNET_assert (GNUNET_OK ==
    586                  GNUNET_PQ_get_oid_by_name (db,
    587                                             "bytea",
    588                                             &oid));
    589   return query_param_array_generic (num,
    590                                     true,
    591                                     du_sigs,
    592                                     NULL,
    593                                     0,
    594                                     DONAU_PQ_array_of_blinded_du_sig,
    595                                     oid,
    596                                     NULL);
    597 }
    598 
    599 
    600 struct GNUNET_PQ_QueryParam
    601 DONAU_PQ_query_param_array_donation_unit_sig (
    602   size_t num,
    603   const struct DONAU_DonationUnitSignature *du_sigs,
    604   struct GNUNET_PQ_Context *db)
    605 {
    606   Oid oid;
    607 
    608   GNUNET_assert (GNUNET_OK ==
    609                  GNUNET_PQ_get_oid_by_name (db,
    610                                             "bytea",
    611                                             &oid));
    612   return query_param_array_generic (num,
    613                                     true,
    614                                     du_sigs,
    615                                     NULL,
    616                                     0,
    617                                     DONAU_PQ_array_of_unblinded_du_sig,
    618                                     oid,
    619                                     NULL);
    620 }
    621 
    622 
    623 /**
    624  * Extract data from a Postgres database @a result as array of a specific type
    625  * from row @a row.  The type information and optionally additional
    626  * out-parameters are given in @a cls which is of type array_result_cls.
    627  *
    628  * @param cls closure of type array_result_cls
    629  * @param result where to extract data from
    630  * @param row row to extract data from
    631  * @param fname name (or prefix) of the fields to extract from
    632  * @param[in,out] dst_size where to store size of result, may be NULL
    633  * @param[out] dst where to store the result
    634  * @return
    635  *   #GNUNET_YES if all results could be extracted
    636  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    637  */
    638 static enum GNUNET_GenericReturnValue
    639 extract_array_generic (
    640   void *cls,
    641   PGresult *result,
    642   int row,
    643   const char *fname,
    644   size_t *dst_size,
    645   void *dst)
    646 {
    647   const struct ArrayResultCls *info = cls;
    648   int data_sz;
    649   char *data;
    650   // void *out = NULL;
    651   struct DONAU_BlindedDonationUnitSignature *du_sigs = NULL;
    652   struct GNUNET_PQ_ArrayHeader_P header;
    653   int col_num;
    654 
    655   GNUNET_assert (NULL != dst);
    656   *((void **) dst) = NULL;
    657 
    658   #define FAIL_IF(cond) \
    659           do { \
    660             if ((cond)) \
    661             { \
    662               GNUNET_break (! (cond)); \
    663               goto FAIL; \
    664             } \
    665           } while (0)
    666 
    667   col_num = PQfnumber (result,
    668                        fname);
    669   FAIL_IF (0 > col_num);
    670   data_sz = PQgetlength (result,
    671                          row,
    672                          col_num);
    673   FAIL_IF (0 > data_sz);
    674   FAIL_IF (sizeof(header) > (size_t) data_sz);
    675 
    676   data = PQgetvalue (result, row, col_num);
    677   FAIL_IF (NULL == data);
    678 
    679   {
    680     struct GNUNET_PQ_ArrayHeader_P *h =
    681       (struct GNUNET_PQ_ArrayHeader_P *) data;
    682 
    683     header.ndim = ntohl (h->ndim);
    684     header.has_null = ntohl (h->has_null);
    685     header.oid = ntohl (h->oid);
    686     header.dim = ntohl (h->dim);
    687     header.lbound = ntohl (h->lbound);
    688 
    689     FAIL_IF (1 != header.ndim);
    690     FAIL_IF (INT_MAX <= header.dim);
    691     FAIL_IF (0 != header.has_null);
    692     FAIL_IF (1 != header.lbound);
    693     FAIL_IF (info->oid != header.oid);
    694   }
    695 
    696   if (NULL != info->num)
    697     *info->num = header.dim;
    698 
    699   {
    700     char *in = data + sizeof(header);
    701 
    702     if (0 == header.dim)
    703     {
    704       if (NULL != dst_size)
    705         *dst_size = 0;
    706       goto FAIL;
    707     }
    708     du_sigs = GNUNET_new_array (header.dim,
    709                                 struct DONAU_BlindedDonationUnitSignature);
    710     *((void **) dst) = du_sigs;
    711 
    712     /* copy data */
    713     for (uint32_t i = 0; i < header.dim; i++)
    714     {
    715       struct DONAU_BlindedDonationUnitSignature *du_sig = &du_sigs[i];
    716       struct GNUNET_CRYPTO_BlindedSignature *bs;
    717       uint32_t be[2];
    718       uint32_t val;
    719       size_t sz;
    720 
    721       GNUNET_memcpy (&val,
    722                      in,
    723                      sizeof(val));
    724       sz = ntohl (val);
    725       FAIL_IF (sizeof(be) > sz);
    726       in += sizeof(val);
    727       GNUNET_memcpy (&be,
    728                      in,
    729                      sizeof(be));
    730       FAIL_IF (0x01 != ntohl (be[1]));      /* magic marker: blinded */
    731 
    732       in += sizeof(be);
    733       sz -= sizeof(be);
    734       bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    735       bs->cipher = ntohl (be[0]);
    736       bs->rc = 1;
    737       switch (bs->cipher)
    738       {
    739       case GNUNET_CRYPTO_BSA_RSA:
    740         bs->details.blinded_rsa_signature
    741           = GNUNET_CRYPTO_rsa_signature_decode (in,
    742                                                 sz);
    743         if (NULL == bs->details.blinded_rsa_signature)
    744         {
    745           GNUNET_free (bs);
    746           FAIL_IF (true);
    747         }
    748         break;
    749       case GNUNET_CRYPTO_BSA_CS:
    750         if (sizeof(bs->details.blinded_cs_answer) != sz)
    751         {
    752           GNUNET_free (bs);
    753           FAIL_IF (true);
    754         }
    755         GNUNET_memcpy (&bs->details.blinded_cs_answer,
    756                        in,
    757                        sz);
    758         break;
    759       default:
    760         GNUNET_free (bs);
    761         FAIL_IF (true);
    762       }
    763       du_sig->blinded_sig = bs;
    764       in += sz;
    765     }
    766     return GNUNET_OK;
    767   }
    768 FAIL:
    769   if (NULL != du_sigs)
    770   {
    771     for (size_t i = 0; i < *info->num; i++)
    772       if (NULL != du_sigs[i].blinded_sig)
    773         GNUNET_CRYPTO_blinded_sig_decref (du_sigs[i].blinded_sig);
    774     GNUNET_free (du_sigs);
    775     *((void **) dst) = NULL;
    776   }
    777   return GNUNET_SYSERR;
    778 #undef FAIL_IF
    779 }
    780 
    781 
    782 /**
    783  * Cleanup of the data and closure of an array spec.
    784  */
    785 static void
    786 array_cleanup (void *cls,
    787                void *rd)
    788 {
    789   struct ArrayResultCls *info = cls;
    790   void **dst = rd;
    791   struct DONAU_BlindedDonationUnitSignature *du_sigs = *dst;
    792 
    793   if ( (0 == info->same_size) &&
    794        (NULL != info->sizes) )
    795     GNUNET_free (*(info->sizes));
    796 
    797   GNUNET_assert (NULL != info->num);
    798   for (size_t i = 0; i < *info->num; i++)
    799     if (NULL != du_sigs[i].blinded_sig)
    800       GNUNET_CRYPTO_blinded_sig_decref (du_sigs[i].blinded_sig);
    801   GNUNET_free (info);
    802   GNUNET_free (du_sigs);
    803   *dst = NULL;
    804 }
    805 
    806 
    807 struct GNUNET_PQ_ResultSpec
    808 DONAU_PQ_result_spec_array_blinded_donation_unit_sig (
    809   struct GNUNET_PQ_Context *db,
    810   const char *name,
    811   size_t *num,
    812   struct DONAU_BlindedDonationUnitSignature **du_sigs)
    813 {
    814   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
    815 
    816   *num = 0;
    817   *du_sigs = NULL;
    818   info->num = num;
    819   // info->typ = TALER_PQ_array_of_blinded_denom_sig;
    820   GNUNET_assert (GNUNET_OK ==
    821                  GNUNET_PQ_get_oid_by_name (db,
    822                                             "bytea",
    823                                             &info->oid));
    824   {
    825     struct GNUNET_PQ_ResultSpec res = {
    826       .conv = extract_array_generic,
    827       .cleaner = array_cleanup,
    828       .dst = (void *) du_sigs,
    829       .fname = name,
    830       .cls = info
    831     };
    832 
    833     return res;
    834   }
    835 }
    836 
    837 
    838 /* end of pq/pq_query_helper.c */