Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2026 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_result_helper.c
18 : * @brief functions to initialize parameter arrays
19 : * @author Christian Grothoff
20 : * @author Özgür Kesim
21 : */
22 : #include "taler/platform.h"
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include "pq_common.h"
25 : #include "taler/taler_pq_lib.h"
26 :
27 :
28 : /**
29 : * Extract an amount from a tuple including the currency from a Postgres
30 : * database @a result at row @a row.
31 : *
32 : * @param cls closure; not used
33 : * @param result where to extract data from
34 : * @param row row to extract data from
35 : * @param fname name (or prefix) of the fields to extract from
36 : * @param[in,out] dst_size where to store size of result, may be NULL
37 : * @param[out] dst where to store the result
38 : * @return
39 : * #GNUNET_YES if all results could be extracted
40 : * #GNUNET_NO if at least one result was NULL
41 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
42 : */
43 : static enum GNUNET_GenericReturnValue
44 1 : extract_amount_currency_tuple (void *cls,
45 : PGresult *result,
46 : int row,
47 : const char *fname,
48 : size_t *dst_size,
49 : void *dst)
50 : {
51 1 : struct TALER_Amount *r_amount = dst;
52 : int col;
53 :
54 : (void) cls;
55 1 : if (sizeof (struct TALER_Amount) != *dst_size)
56 : {
57 0 : GNUNET_break (0);
58 0 : return GNUNET_SYSERR;
59 : }
60 :
61 : /* Set return value to invalid in case we don't finish */
62 1 : memset (r_amount,
63 : 0,
64 : sizeof (struct TALER_Amount));
65 1 : col = PQfnumber (result,
66 : fname);
67 1 : if (col < 0)
68 : {
69 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
70 : "Field `%s' does not exist in result\n",
71 : fname);
72 0 : return GNUNET_SYSERR;
73 : }
74 1 : if (PQgetisnull (result,
75 : row,
76 : col))
77 : {
78 0 : return GNUNET_NO;
79 : }
80 :
81 : /* Parse the tuple */
82 : {
83 : struct TALER_PQ_AmountCurrencyP ap;
84 : const char *in;
85 : size_t size;
86 :
87 1 : size = PQgetlength (result,
88 : row,
89 : col);
90 1 : if ( (size >= sizeof (ap)) ||
91 : (size <= sizeof (ap) - TALER_CURRENCY_LEN) )
92 : {
93 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
94 : "Incorrect size of binary field `%s' (got %zu, expected (%zu-%zu))\n",
95 : fname,
96 : size,
97 : sizeof (ap) - TALER_CURRENCY_LEN,
98 : sizeof (ap));
99 0 : return GNUNET_SYSERR;
100 : }
101 :
102 1 : in = PQgetvalue (result,
103 : row,
104 : col);
105 1 : memset (&ap.c,
106 : 0,
107 : TALER_CURRENCY_LEN);
108 1 : memcpy (&ap,
109 : in,
110 : size);
111 1 : if (3 != ntohl (ap.cnt))
112 : {
113 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
114 : "Incorrect number of elements in tuple-field `%s'\n",
115 : fname);
116 0 : return GNUNET_SYSERR;
117 : }
118 : /* FIXME[oec]: OID-checks? */
119 :
120 1 : r_amount->value = GNUNET_ntohll (ap.v);
121 1 : r_amount->fraction = ntohl (ap.f);
122 1 : memcpy (r_amount->currency,
123 : ap.c,
124 : TALER_CURRENCY_LEN);
125 1 : if ('\0' != r_amount->currency[TALER_CURRENCY_LEN - 1])
126 : {
127 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
128 : "Invalid currency (not 0-terminated) in tuple field `%s'\n",
129 : fname);
130 : /* be sure nobody uses this by accident */
131 0 : memset (r_amount,
132 : 0,
133 : sizeof (struct TALER_Amount));
134 0 : return GNUNET_SYSERR;
135 : }
136 : }
137 :
138 1 : if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
139 : {
140 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
141 : "Value in field `%s' exceeds legal range\n",
142 : fname);
143 0 : return GNUNET_SYSERR;
144 : }
145 1 : if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
146 : {
147 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
148 : "Fraction in field `%s' exceeds legal range\n",
149 : fname);
150 0 : return GNUNET_SYSERR;
151 : }
152 1 : return GNUNET_OK;
153 : }
154 :
155 :
156 : struct GNUNET_PQ_ResultSpec
157 1 : TALER_PQ_result_spec_amount_with_currency (const char *name,
158 : struct TALER_Amount *amount)
159 : {
160 1 : struct GNUNET_PQ_ResultSpec res = {
161 : .conv = &extract_amount_currency_tuple,
162 : .dst = (void *) amount,
163 : .dst_size = sizeof (*amount),
164 : .fname = name
165 : };
166 :
167 1 : return res;
168 : }
169 :
170 :
171 : /**
172 : * Extract an amount from a tuple from a Postgres database @a result at row @a row.
173 : *
174 : * @param cls closure, a `const char *` giving the currency
175 : * @param result where to extract data from
176 : * @param row row to extract data from
177 : * @param fname name (or prefix) of the fields to extract from
178 : * @param[in,out] dst_size where to store size of result, may be NULL
179 : * @param[out] dst where to store the result
180 : * @return
181 : * #GNUNET_YES if all results could be extracted
182 : * #GNUNET_NO if at least one result was NULL
183 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
184 : */
185 : static enum GNUNET_GenericReturnValue
186 64998 : extract_amount_tuple (void *cls,
187 : PGresult *result,
188 : int row,
189 : const char *fname,
190 : size_t *dst_size,
191 : void *dst)
192 : {
193 64998 : struct TALER_Amount *r_amount = dst;
194 64998 : const char *currency = cls;
195 : int col;
196 : size_t len;
197 :
198 64998 : if (sizeof (struct TALER_Amount) != *dst_size)
199 : {
200 0 : GNUNET_break (0);
201 0 : return GNUNET_SYSERR;
202 : }
203 :
204 : /* Set return value to invalid in case we don't finish */
205 64998 : memset (r_amount,
206 : 0,
207 : sizeof (struct TALER_Amount));
208 64998 : col = PQfnumber (result,
209 : fname);
210 64998 : if (col < 0)
211 : {
212 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
213 : "Field `%s' does not exist in result\n",
214 : fname);
215 0 : return GNUNET_SYSERR;
216 : }
217 64998 : if (PQgetisnull (result,
218 : row,
219 : col))
220 : {
221 0 : return GNUNET_NO;
222 : }
223 :
224 : /* Parse the tuple */
225 : {
226 : struct TALER_PQ_AmountP ap;
227 : const char *in;
228 : size_t size;
229 :
230 64998 : size = PQgetlength (result,
231 : row,
232 : col);
233 64998 : in = PQgetvalue (result,
234 : row,
235 : col);
236 64998 : if (sizeof(struct TALER_PQ_AmountNullP) == size)
237 : {
238 : struct TALER_PQ_AmountNullP apn;
239 :
240 173 : memcpy (&apn,
241 : in,
242 : size);
243 173 : if ( (2 == ntohl (apn.cnt)) &&
244 173 : (-1 == (int32_t) ntohl (apn.sz_v)) &&
245 173 : (-1 == (int32_t) ntohl (apn.sz_f)) )
246 : {
247 : /* is NULL! */
248 173 : return GNUNET_NO;
249 : }
250 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 : "Incorrect size of binary field `%s' and not NULL (got %zu, expected %zu)\n",
252 : fname,
253 : size,
254 : sizeof(ap));
255 0 : return GNUNET_SYSERR;
256 : }
257 64825 : if (sizeof(ap) != size)
258 : {
259 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
260 : "Incorrect size of binary field `%s' (got %zu, expected %zu)\n",
261 : fname,
262 : size,
263 : sizeof(ap));
264 0 : return GNUNET_SYSERR;
265 : }
266 :
267 64825 : memcpy (&ap,
268 : in,
269 : size);
270 64825 : if (2 != ntohl (ap.cnt))
271 : {
272 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273 : "Incorrect number of elements in tuple-field `%s'\n",
274 : fname);
275 0 : return GNUNET_SYSERR;
276 : }
277 : /* FIXME[oec]: OID-checks? */
278 :
279 64825 : r_amount->value = GNUNET_ntohll (ap.v);
280 64825 : r_amount->fraction = ntohl (ap.f);
281 : }
282 :
283 64825 : if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
284 : {
285 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
286 : "Value in field `%s' exceeds legal range\n",
287 : fname);
288 0 : return GNUNET_SYSERR;
289 : }
290 64825 : if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
291 : {
292 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
293 : "Fraction in field `%s' exceeds legal range\n",
294 : fname);
295 0 : return GNUNET_SYSERR;
296 : }
297 :
298 64825 : len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
299 : strlen (currency));
300 :
301 64825 : GNUNET_memcpy (r_amount->currency,
302 : currency,
303 : len);
304 64825 : return GNUNET_OK;
305 : }
306 :
307 :
308 : struct GNUNET_PQ_ResultSpec
309 92135 : TALER_PQ_result_spec_amount (const char *name,
310 : const char *currency,
311 : struct TALER_Amount *amount)
312 : {
313 92135 : struct GNUNET_PQ_ResultSpec res = {
314 : .conv = &extract_amount_tuple,
315 : .cls = (void *) currency,
316 : .dst = (void *) amount,
317 : .dst_size = sizeof (*amount),
318 : .fname = name
319 : };
320 :
321 92135 : return res;
322 : }
323 :
324 :
325 : /**
326 : * Extract data from a Postgres database @a result at row @a row.
327 : *
328 : * @param cls closure
329 : * @param result where to extract data from
330 : * @param row row to extract data from
331 : * @param fname name (or prefix) of the fields to extract from
332 : * @param[in,out] dst_size where to store size of result, may be NULL
333 : * @param[out] dst where to store the result
334 : * @return
335 : * #GNUNET_YES if all results could be extracted
336 : * #GNUNET_NO if at least one result was NULL
337 : * #GNUNET_SYSERR if a result was invalid (non-existing field)
338 : */
339 : static enum GNUNET_GenericReturnValue
340 255 : extract_json (void *cls,
341 : PGresult *result,
342 : int row,
343 : const char *fname,
344 : size_t *dst_size,
345 : void *dst)
346 : {
347 255 : json_t **j_dst = dst;
348 : const char *res;
349 : int fnum;
350 : json_error_t json_error;
351 : size_t slen;
352 :
353 : (void) cls;
354 : (void) dst_size;
355 255 : fnum = PQfnumber (result,
356 : fname);
357 255 : if (fnum < 0)
358 : {
359 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
360 : "Field `%s' does not exist in result\n",
361 : fname);
362 0 : return GNUNET_SYSERR;
363 : }
364 255 : if (PQgetisnull (result,
365 : row,
366 : fnum))
367 140 : return GNUNET_NO;
368 115 : slen = PQgetlength (result,
369 : row,
370 : fnum);
371 115 : res = (const char *) PQgetvalue (result,
372 : row,
373 : fnum);
374 115 : *j_dst = json_loadb (res,
375 : slen,
376 : JSON_REJECT_DUPLICATES,
377 : &json_error);
378 115 : if (NULL == *j_dst)
379 : {
380 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
381 : "Failed to parse JSON result for field `%s': %s (%s)\n",
382 : fname,
383 : json_error.text,
384 : json_error.source);
385 0 : return GNUNET_SYSERR;
386 : }
387 115 : return GNUNET_OK;
388 : }
389 :
390 :
391 : /**
392 : * Function called to clean up memory allocated
393 : * by a #GNUNET_PQ_ResultConverter.
394 : *
395 : * @param cls closure
396 : * @param rd result data to clean up
397 : */
398 : static void
399 48 : clean_json (void *cls,
400 : void *rd)
401 : {
402 48 : json_t **dst = rd;
403 :
404 : (void) cls;
405 48 : if (NULL != *dst)
406 : {
407 47 : json_decref (*dst);
408 47 : *dst = NULL;
409 : }
410 48 : }
411 :
412 :
413 : struct GNUNET_PQ_ResultSpec
414 267 : TALER_PQ_result_spec_json (const char *name,
415 : json_t **jp)
416 : {
417 267 : struct GNUNET_PQ_ResultSpec res = {
418 : .conv = &extract_json,
419 : .cleaner = &clean_json,
420 : .dst = (void *) jp,
421 : .fname = name
422 : };
423 :
424 267 : return res;
425 : }
426 :
427 :
428 : /**
429 : * Extract data from a Postgres database @a result at row @a row.
430 : *
431 : * @param cls closure
432 : * @param result where to extract data from
433 : * @param row the row to extract data from
434 : * @param fname name (or prefix) of the fields to extract from
435 : * @param[in,out] dst_size where to store size of result, may be NULL
436 : * @param[out] dst where to store the result
437 : * @return
438 : * #GNUNET_YES if all results could be extracted
439 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
440 : */
441 : static enum GNUNET_GenericReturnValue
442 9644 : extract_denom_pub (void *cls,
443 : PGresult *result,
444 : int row,
445 : const char *fname,
446 : size_t *dst_size,
447 : void *dst)
448 : {
449 9644 : struct TALER_DenominationPublicKey *pk = dst;
450 : struct GNUNET_CRYPTO_BlindSignPublicKey *bpk;
451 : size_t len;
452 : const char *res;
453 : int fnum;
454 : uint32_t be[2];
455 :
456 : (void) cls;
457 : (void) dst_size;
458 9644 : fnum = PQfnumber (result,
459 : fname);
460 9644 : if (fnum < 0)
461 : {
462 0 : GNUNET_break (0);
463 0 : return GNUNET_SYSERR;
464 : }
465 9644 : if (PQgetisnull (result,
466 : row,
467 : fnum))
468 0 : return GNUNET_NO;
469 :
470 : /* if a field is null, continue but
471 : * remember that we now return a different result */
472 9644 : len = PQgetlength (result,
473 : row,
474 : fnum);
475 9644 : res = PQgetvalue (result,
476 : row,
477 : fnum);
478 9644 : if (len < sizeof (be))
479 : {
480 0 : GNUNET_break (0);
481 0 : return GNUNET_SYSERR;
482 : }
483 9644 : GNUNET_memcpy (be,
484 : res,
485 : sizeof (be));
486 9644 : res += sizeof (be);
487 9644 : len -= sizeof (be);
488 9644 : bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
489 9644 : bpk->cipher = ntohl (be[0]);
490 9644 : bpk->rc = 1;
491 9644 : pk->age_mask.bits = ntohl (be[1]);
492 9644 : switch (bpk->cipher)
493 : {
494 0 : case GNUNET_CRYPTO_BSA_INVALID:
495 0 : break;
496 4846 : case GNUNET_CRYPTO_BSA_RSA:
497 : bpk->details.rsa_public_key
498 4846 : = GNUNET_CRYPTO_rsa_public_key_decode (res,
499 : len);
500 4846 : if (NULL == bpk->details.rsa_public_key)
501 : {
502 0 : GNUNET_break (0);
503 0 : GNUNET_free (bpk);
504 0 : return GNUNET_SYSERR;
505 : }
506 4846 : pk->bsign_pub_key = bpk;
507 4846 : GNUNET_CRYPTO_hash (res,
508 : len,
509 : &bpk->pub_key_hash);
510 4846 : return GNUNET_OK;
511 4798 : case GNUNET_CRYPTO_BSA_CS:
512 4798 : if (sizeof (bpk->details.cs_public_key) != len)
513 : {
514 0 : GNUNET_break (0);
515 0 : GNUNET_free (bpk);
516 0 : return GNUNET_SYSERR;
517 : }
518 4798 : GNUNET_memcpy (&bpk->details.cs_public_key,
519 : res,
520 : len);
521 4798 : pk->bsign_pub_key = bpk;
522 4798 : GNUNET_CRYPTO_hash (res,
523 : len,
524 : &bpk->pub_key_hash);
525 4798 : return GNUNET_OK;
526 : }
527 0 : GNUNET_break (0);
528 0 : GNUNET_free (bpk);
529 0 : return GNUNET_SYSERR;
530 : }
531 :
532 :
533 : /**
534 : * Function called to clean up memory allocated
535 : * by a #GNUNET_PQ_ResultConverter.
536 : *
537 : * @param cls closure
538 : * @param rd result data to clean up
539 : */
540 : static void
541 7522 : clean_denom_pub (void *cls,
542 : void *rd)
543 : {
544 7522 : struct TALER_DenominationPublicKey *denom_pub = rd;
545 :
546 : (void) cls;
547 7522 : TALER_denom_pub_free (denom_pub);
548 7522 : }
549 :
550 :
551 : struct GNUNET_PQ_ResultSpec
552 9644 : TALER_PQ_result_spec_denom_pub (const char *name,
553 : struct TALER_DenominationPublicKey *denom_pub)
554 : {
555 9644 : struct GNUNET_PQ_ResultSpec res = {
556 : .conv = &extract_denom_pub,
557 : .cleaner = &clean_denom_pub,
558 : .dst = (void *) denom_pub,
559 : .fname = name
560 : };
561 :
562 9644 : return res;
563 : }
564 :
565 :
566 : /**
567 : * Extract data from a Postgres database @a result at row @a row.
568 : *
569 : * @param cls closure
570 : * @param result where to extract data from
571 : * @param row the row to extract data from
572 : * @param fname name (or prefix) of the fields to extract from
573 : * @param[in,out] dst_size where to store size of result, may be NULL
574 : * @param[out] dst where to store the result
575 : * @return
576 : * #GNUNET_YES if all results could be extracted
577 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
578 : */
579 : static enum GNUNET_GenericReturnValue
580 2 : extract_denom_sig (void *cls,
581 : PGresult *result,
582 : int row,
583 : const char *fname,
584 : size_t *dst_size,
585 : void *dst)
586 : {
587 2 : struct TALER_DenominationSignature *sig = dst;
588 : struct GNUNET_CRYPTO_UnblindedSignature *ubs;
589 : size_t len;
590 : const char *res;
591 : int fnum;
592 : uint32_t be[2];
593 :
594 : (void) cls;
595 : (void) dst_size;
596 2 : fnum = PQfnumber (result,
597 : fname);
598 2 : if (fnum < 0)
599 : {
600 0 : GNUNET_break (0);
601 0 : return GNUNET_SYSERR;
602 : }
603 2 : if (PQgetisnull (result,
604 : row,
605 : fnum))
606 0 : return GNUNET_NO;
607 :
608 : /* if a field is null, continue but
609 : * remember that we now return a different result */
610 2 : len = PQgetlength (result,
611 : row,
612 : fnum);
613 2 : res = PQgetvalue (result,
614 : row,
615 : fnum);
616 2 : if (len < sizeof (be))
617 : {
618 0 : GNUNET_break (0);
619 0 : return GNUNET_SYSERR;
620 : }
621 2 : GNUNET_memcpy (&be,
622 : res,
623 : sizeof (be));
624 2 : if (0x00 != ntohl (be[1]))
625 : {
626 0 : GNUNET_break (0);
627 0 : return GNUNET_SYSERR;
628 : }
629 2 : res += sizeof (be);
630 2 : len -= sizeof (be);
631 2 : ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
632 2 : ubs->rc = 1;
633 2 : ubs->cipher = ntohl (be[0]);
634 2 : switch (ubs->cipher)
635 : {
636 0 : case GNUNET_CRYPTO_BSA_INVALID:
637 0 : break;
638 2 : case GNUNET_CRYPTO_BSA_RSA:
639 : ubs->details.rsa_signature
640 2 : = GNUNET_CRYPTO_rsa_signature_decode (res,
641 : len);
642 2 : if (NULL == ubs->details.rsa_signature)
643 : {
644 0 : GNUNET_break (0);
645 0 : GNUNET_free (ubs);
646 0 : return GNUNET_SYSERR;
647 : }
648 2 : sig->unblinded_sig = ubs;
649 2 : return GNUNET_OK;
650 0 : case GNUNET_CRYPTO_BSA_CS:
651 0 : if (sizeof (ubs->details.cs_signature) != len)
652 : {
653 0 : GNUNET_break (0);
654 0 : GNUNET_free (ubs);
655 0 : return GNUNET_SYSERR;
656 : }
657 0 : GNUNET_memcpy (&ubs->details.cs_signature,
658 : res,
659 : len);
660 0 : sig->unblinded_sig = ubs;
661 0 : return GNUNET_OK;
662 : }
663 0 : GNUNET_break (0);
664 0 : GNUNET_free (ubs);
665 0 : return GNUNET_SYSERR;
666 : }
667 :
668 :
669 : /**
670 : * Function called to clean up memory allocated
671 : * by a #GNUNET_PQ_ResultConverter.
672 : *
673 : * @param cls closure
674 : * @param rd result data to clean up
675 : */
676 : static void
677 0 : clean_denom_sig (void *cls,
678 : void *rd)
679 : {
680 0 : struct TALER_DenominationSignature *denom_sig = rd;
681 :
682 : (void) cls;
683 0 : TALER_denom_sig_free (denom_sig);
684 0 : }
685 :
686 :
687 : struct GNUNET_PQ_ResultSpec
688 2 : TALER_PQ_result_spec_denom_sig (const char *name,
689 : struct TALER_DenominationSignature *denom_sig)
690 : {
691 2 : struct GNUNET_PQ_ResultSpec res = {
692 : .conv = &extract_denom_sig,
693 : .cleaner = &clean_denom_sig,
694 : .dst = (void *) denom_sig,
695 : .fname = name
696 : };
697 :
698 2 : return res;
699 : }
700 :
701 :
702 : /**
703 : * Extract data from a Postgres database @a result at row @a row.
704 : *
705 : * @param cls closure
706 : * @param result where to extract data from
707 : * @param row the row to extract data from
708 : * @param fname name (or prefix) of the fields to extract from
709 : * @param[in,out] dst_size where to store size of result, may be NULL
710 : * @param[out] dst where to store the result
711 : * @return
712 : * #GNUNET_YES if all results could be extracted
713 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
714 : */
715 : static enum GNUNET_GenericReturnValue
716 0 : extract_blinded_denom_sig (void *cls,
717 : PGresult *result,
718 : int row,
719 : const char *fname,
720 : size_t *dst_size,
721 : void *dst)
722 : {
723 0 : struct TALER_BlindedDenominationSignature *sig = dst;
724 : struct GNUNET_CRYPTO_BlindedSignature *bs;
725 : size_t len;
726 : const char *res;
727 : int fnum;
728 : uint32_t be[2];
729 :
730 : (void) cls;
731 : (void) dst_size;
732 0 : fnum = PQfnumber (result,
733 : fname);
734 0 : if (fnum < 0)
735 : {
736 0 : GNUNET_break (0);
737 0 : return GNUNET_SYSERR;
738 : }
739 0 : if (PQgetisnull (result,
740 : row,
741 : fnum))
742 0 : return GNUNET_NO;
743 :
744 : /* if a field is null, continue but
745 : * remember that we now return a different result */
746 0 : len = PQgetlength (result,
747 : row,
748 : fnum);
749 0 : res = PQgetvalue (result,
750 : row,
751 : fnum);
752 0 : if (len < sizeof (be))
753 : {
754 0 : GNUNET_break (0);
755 0 : return GNUNET_SYSERR;
756 : }
757 0 : GNUNET_memcpy (&be,
758 : res,
759 : sizeof (be));
760 0 : if (0x01 != ntohl (be[1])) /* magic marker: blinded */
761 : {
762 0 : GNUNET_break (0);
763 0 : return GNUNET_SYSERR;
764 : }
765 0 : res += sizeof (be);
766 0 : len -= sizeof (be);
767 0 : bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
768 0 : bs->rc = 1;
769 0 : bs->cipher = ntohl (be[0]);
770 0 : switch (bs->cipher)
771 : {
772 0 : case GNUNET_CRYPTO_BSA_INVALID:
773 0 : break;
774 0 : case GNUNET_CRYPTO_BSA_RSA:
775 : bs->details.blinded_rsa_signature
776 0 : = GNUNET_CRYPTO_rsa_signature_decode (res,
777 : len);
778 0 : if (NULL == bs->details.blinded_rsa_signature)
779 : {
780 0 : GNUNET_break (0);
781 0 : GNUNET_free (bs);
782 0 : return GNUNET_SYSERR;
783 : }
784 0 : sig->blinded_sig = bs;
785 0 : return GNUNET_OK;
786 0 : case GNUNET_CRYPTO_BSA_CS:
787 0 : if (sizeof (bs->details.blinded_cs_answer) != len)
788 : {
789 0 : GNUNET_break (0);
790 0 : GNUNET_free (bs);
791 0 : return GNUNET_SYSERR;
792 : }
793 0 : GNUNET_memcpy (&bs->details.blinded_cs_answer,
794 : res,
795 : len);
796 0 : sig->blinded_sig = bs;
797 0 : return GNUNET_OK;
798 : }
799 0 : GNUNET_break (0);
800 0 : GNUNET_free (bs);
801 0 : return GNUNET_SYSERR;
802 : }
803 :
804 :
805 : /**
806 : * Function called to clean up memory allocated
807 : * by a #GNUNET_PQ_ResultConverter.
808 : *
809 : * @param cls closure
810 : * @param rd result data to clean up
811 : */
812 : static void
813 0 : clean_blinded_denom_sig (void *cls,
814 : void *rd)
815 : {
816 0 : struct TALER_BlindedDenominationSignature *denom_sig = rd;
817 :
818 : (void) cls;
819 0 : TALER_blinded_denom_sig_free (denom_sig);
820 0 : }
821 :
822 :
823 : struct GNUNET_PQ_ResultSpec
824 0 : TALER_PQ_result_spec_blinded_denom_sig (
825 : const char *name,
826 : struct TALER_BlindedDenominationSignature *denom_sig)
827 : {
828 : // FIXME: use GNUNET_PQ_result_spec_blinded_sig()
829 0 : struct GNUNET_PQ_ResultSpec res = {
830 : .conv = &extract_blinded_denom_sig,
831 : .cleaner = &clean_blinded_denom_sig,
832 : .dst = (void *) denom_sig,
833 : .fname = name
834 : };
835 :
836 0 : return res;
837 : }
838 :
839 :
840 : /**
841 : * Extract data from a Postgres database @a result at row @a row.
842 : *
843 : * @param cls closure
844 : * @param result where to extract data from
845 : * @param row the row to extract data from
846 : * @param fname name (or prefix) of the fields to extract from
847 : * @param[in,out] dst_size where to store size of result, may be NULL
848 : * @param[out] dst where to store the result
849 : * @return
850 : * #GNUNET_YES if all results could be extracted
851 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
852 : */
853 : static enum GNUNET_GenericReturnValue
854 0 : extract_blinded_planchet (void *cls,
855 : PGresult *result,
856 : int row,
857 : const char *fname,
858 : size_t *dst_size,
859 : void *dst)
860 : {
861 0 : struct TALER_BlindedPlanchet *bp = dst;
862 : struct GNUNET_CRYPTO_BlindedMessage *bm;
863 : size_t len;
864 : const char *res;
865 : int fnum;
866 : uint32_t be[2];
867 :
868 : (void) cls;
869 : (void) dst_size;
870 0 : fnum = PQfnumber (result,
871 : fname);
872 0 : if (fnum < 0)
873 : {
874 0 : GNUNET_break (0);
875 0 : return GNUNET_SYSERR;
876 : }
877 0 : if (PQgetisnull (result,
878 : row,
879 : fnum))
880 0 : return GNUNET_NO;
881 :
882 : /* if a field is null, continue but
883 : * remember that we now return a different result */
884 0 : len = PQgetlength (result,
885 : row,
886 : fnum);
887 0 : res = PQgetvalue (result,
888 : row,
889 : fnum);
890 0 : if (len < sizeof (be))
891 : {
892 0 : GNUNET_break (0);
893 0 : return GNUNET_SYSERR;
894 : }
895 0 : GNUNET_memcpy (&be,
896 : res,
897 : sizeof (be));
898 0 : if (0x0100 != ntohl (be[1])) /* magic marker: blinded */
899 : {
900 0 : GNUNET_break (0);
901 0 : return GNUNET_SYSERR;
902 : }
903 0 : res += sizeof (be);
904 0 : len -= sizeof (be);
905 0 : bm = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
906 0 : bm->rc = 1;
907 0 : bm->cipher = ntohl (be[0]);
908 0 : switch (bm->cipher)
909 : {
910 0 : case GNUNET_CRYPTO_BSA_INVALID:
911 0 : break;
912 0 : case GNUNET_CRYPTO_BSA_RSA:
913 : bm->details.rsa_blinded_message.blinded_msg_size
914 0 : = len;
915 : bm->details.rsa_blinded_message.blinded_msg
916 0 : = GNUNET_memdup (res,
917 : len);
918 0 : bp->blinded_message = bm;
919 0 : return GNUNET_OK;
920 0 : case GNUNET_CRYPTO_BSA_CS:
921 0 : if (sizeof (bm->details.cs_blinded_message) != len)
922 : {
923 0 : GNUNET_break (0);
924 0 : GNUNET_free (bm);
925 0 : return GNUNET_SYSERR;
926 : }
927 0 : GNUNET_memcpy (&bm->details.cs_blinded_message,
928 : res,
929 : len);
930 0 : bp->blinded_message = bm;
931 0 : return GNUNET_OK;
932 : }
933 0 : GNUNET_break (0);
934 0 : GNUNET_free (bm);
935 0 : return GNUNET_SYSERR;
936 : }
937 :
938 :
939 : /**
940 : * Function called to clean up memory allocated
941 : * by a #GNUNET_PQ_ResultConverter.
942 : *
943 : * @param cls closure
944 : * @param rd result data to clean up
945 : */
946 : static void
947 0 : clean_blinded_planchet (void *cls,
948 : void *rd)
949 : {
950 0 : struct TALER_BlindedPlanchet *bp = rd;
951 :
952 : (void) cls;
953 0 : TALER_blinded_planchet_free (bp);
954 0 : }
955 :
956 :
957 : struct GNUNET_PQ_ResultSpec
958 0 : TALER_PQ_result_spec_blinded_planchet (
959 : const char *name,
960 : struct TALER_BlindedPlanchet *bp)
961 : {
962 0 : struct GNUNET_PQ_ResultSpec res = {
963 : .conv = &extract_blinded_planchet,
964 : .cleaner = &clean_blinded_planchet,
965 : .dst = (void *) bp,
966 : .fname = name
967 : };
968 :
969 0 : return res;
970 : }
971 :
972 :
973 : /**
974 : * Extract data from a Postgres database @a result at row @a row.
975 : *
976 : * @param cls closure
977 : * @param result where to extract data from
978 : * @param row row to extract data from
979 : * @param fname name (or prefix) of the fields to extract from
980 : * @param[in,out] dst_size where to store size of result, may be NULL
981 : * @param[out] dst where to store the result
982 : * @return
983 : * #GNUNET_YES if all results could be extracted
984 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
985 : */
986 : static enum GNUNET_GenericReturnValue
987 0 : extract_exchange_withdraw_values (void *cls,
988 : PGresult *result,
989 : int row,
990 : const char *fname,
991 : size_t *dst_size,
992 : void *dst)
993 : {
994 0 : struct TALER_ExchangeBlindingValues *alg_values = dst;
995 : struct GNUNET_CRYPTO_BlindingInputValues *bi;
996 : size_t len;
997 : const char *res;
998 : int fnum;
999 : uint32_t be[2];
1000 :
1001 : (void) cls;
1002 : (void) dst_size;
1003 0 : fnum = PQfnumber (result,
1004 : fname);
1005 0 : if (fnum < 0)
1006 : {
1007 0 : GNUNET_break (0);
1008 0 : return GNUNET_SYSERR;
1009 : }
1010 0 : if (PQgetisnull (result,
1011 : row,
1012 : fnum))
1013 0 : return GNUNET_NO;
1014 :
1015 : /* if a field is null, continue but
1016 : * remember that we now return a different result */
1017 0 : len = PQgetlength (result,
1018 : row,
1019 : fnum);
1020 0 : res = PQgetvalue (result,
1021 : row,
1022 : fnum);
1023 0 : if (len < sizeof (be))
1024 : {
1025 0 : GNUNET_break (0);
1026 0 : return GNUNET_SYSERR;
1027 : }
1028 0 : GNUNET_memcpy (&be,
1029 : res,
1030 : sizeof (be));
1031 0 : if (0x010000 != ntohl (be[1])) /* magic marker: EWV */
1032 : {
1033 0 : GNUNET_break (0);
1034 0 : return GNUNET_SYSERR;
1035 : }
1036 0 : res += sizeof (be);
1037 0 : len -= sizeof (be);
1038 0 : bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
1039 0 : bi->rc = 1;
1040 0 : bi->cipher = ntohl (be[0]);
1041 0 : switch (bi->cipher)
1042 : {
1043 0 : case GNUNET_CRYPTO_BSA_INVALID:
1044 0 : break;
1045 0 : case GNUNET_CRYPTO_BSA_RSA:
1046 0 : if (0 != len)
1047 : {
1048 0 : GNUNET_break (0);
1049 0 : GNUNET_free (bi);
1050 0 : return GNUNET_SYSERR;
1051 : }
1052 0 : alg_values->blinding_inputs = bi;
1053 0 : return GNUNET_OK;
1054 0 : case GNUNET_CRYPTO_BSA_CS:
1055 0 : if (sizeof (bi->details.cs_values) != len)
1056 : {
1057 0 : GNUNET_break (0);
1058 0 : GNUNET_free (bi);
1059 0 : return GNUNET_SYSERR;
1060 : }
1061 0 : GNUNET_memcpy (&bi->details.cs_values,
1062 : res,
1063 : len);
1064 0 : alg_values->blinding_inputs = bi;
1065 0 : return GNUNET_OK;
1066 : }
1067 0 : GNUNET_break (0);
1068 0 : GNUNET_free (bi);
1069 0 : return GNUNET_SYSERR;
1070 : }
1071 :
1072 :
1073 : struct GNUNET_PQ_ResultSpec
1074 0 : TALER_PQ_result_spec_exchange_withdraw_values (
1075 : const char *name,
1076 : struct TALER_ExchangeBlindingValues *ewv)
1077 : {
1078 0 : struct GNUNET_PQ_ResultSpec res = {
1079 : .conv = &extract_exchange_withdraw_values,
1080 : .dst = (void *) ewv,
1081 : .fname = name
1082 : };
1083 :
1084 0 : return res;
1085 : }
1086 :
1087 :
1088 : /**
1089 : * Closure for the array result specifications. Contains type information
1090 : * for the generic parser extract_array_generic and out-pointers for the results.
1091 : */
1092 : struct ArrayResultCls
1093 : {
1094 : /**
1095 : * Oid of the expected type, must match the oid in the header of the PQResult struct
1096 : */
1097 : Oid oid;
1098 :
1099 : /**
1100 : * Target type
1101 : */
1102 : enum TALER_PQ_ArrayType typ;
1103 :
1104 : /**
1105 : * If not 0, defines the expected size of each entry
1106 : */
1107 : size_t same_size;
1108 :
1109 : /**
1110 : * Out-pointer to write the number of elements in the array
1111 : */
1112 : size_t *num;
1113 :
1114 : /**
1115 : * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0,
1116 : * allocate and put the array of @a num sizes here. NULL otherwise
1117 : */
1118 : size_t **sizes;
1119 :
1120 : /**
1121 : * DB_connection, needed for OID-lookup for composite types
1122 : */
1123 : const struct GNUNET_PQ_Context *db;
1124 :
1125 : /**
1126 : * Currency information for amount composites
1127 : */
1128 : char currency[TALER_CURRENCY_LEN];
1129 : };
1130 :
1131 :
1132 : /**
1133 : * Extract data from a Postgres database @a result as array of a specific type
1134 : * from row @a row. The type information and optionally additional
1135 : * out-parameters are given in @a cls which is of type array_result_cls.
1136 : *
1137 : * @param cls closure of type array_result_cls
1138 : * @param result where to extract data from
1139 : * @param row row to extract data from
1140 : * @param fname name (or prefix) of the fields to extract from
1141 : * @param[in,out] dst_size where to store size of result, may be NULL
1142 : * @param[out] dst where to store the result
1143 : * @return
1144 : * #GNUNET_YES if all results could be extracted
1145 : * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
1146 : */
1147 : static enum GNUNET_GenericReturnValue
1148 47 : extract_array_generic (
1149 : void *cls,
1150 : PGresult *result,
1151 : int row,
1152 : const char *fname,
1153 : size_t *dst_size,
1154 : void *dst)
1155 : {
1156 47 : const struct ArrayResultCls *info = cls;
1157 : int data_sz;
1158 : char *data;
1159 47 : void *out = NULL;
1160 : struct GNUNET_PQ_ArrayHeader_P header;
1161 : int col_num;
1162 :
1163 47 : GNUNET_assert (NULL != dst);
1164 47 : *((void **) dst) = NULL;
1165 :
1166 : #define FAIL_IF(cond) \
1167 : do { \
1168 : if ((cond)) \
1169 : { \
1170 : GNUNET_break (! (cond)); \
1171 : goto FAIL; \
1172 : } \
1173 : } while (0)
1174 :
1175 47 : col_num = PQfnumber (result, fname);
1176 47 : FAIL_IF (0 > col_num);
1177 :
1178 47 : if (PQgetisnull (result, row, col_num))
1179 : {
1180 9 : return GNUNET_NO;
1181 : }
1182 :
1183 38 : data_sz = PQgetlength (result, row, col_num);
1184 38 : FAIL_IF (0 > data_sz);
1185 :
1186 : /* Report if this field is empty */
1187 38 : if (0 == (size_t) data_sz)
1188 0 : return GNUNET_NO;
1189 :
1190 38 : data = PQgetvalue (result, row, col_num);
1191 :
1192 38 : if (sizeof(header) > (size_t) data_sz)
1193 : {
1194 : uint32_t ndim;
1195 :
1196 : /* data_sz is shorter than header if the
1197 : array length is 0, in which case ndim is 0! */
1198 2 : FAIL_IF (sizeof(uint32_t) > (size_t) data_sz);
1199 2 : memcpy (&ndim,
1200 : data,
1201 : sizeof (ndim));
1202 2 : FAIL_IF (0 != ndim);
1203 2 : *info->num = 0;
1204 2 : return GNUNET_OK;
1205 : }
1206 36 : FAIL_IF (sizeof(header) > (size_t) data_sz);
1207 36 : FAIL_IF (NULL == data);
1208 :
1209 : {
1210 36 : struct GNUNET_PQ_ArrayHeader_P *h =
1211 : (struct GNUNET_PQ_ArrayHeader_P *) data;
1212 :
1213 36 : header.ndim = ntohl (h->ndim);
1214 36 : header.has_null = ntohl (h->has_null);
1215 36 : header.oid = ntohl (h->oid);
1216 36 : header.dim = ntohl (h->dim);
1217 36 : header.lbound = ntohl (h->lbound);
1218 :
1219 36 : FAIL_IF (1 != header.ndim);
1220 36 : FAIL_IF (INT_MAX <= header.dim);
1221 36 : FAIL_IF (0 != header.has_null);
1222 36 : FAIL_IF (1 != header.lbound);
1223 36 : FAIL_IF (info->oid != header.oid);
1224 : }
1225 :
1226 36 : if (NULL != info->num)
1227 36 : *info->num = header.dim;
1228 :
1229 : {
1230 36 : char *in = data + sizeof(header);
1231 :
1232 36 : switch (info->typ)
1233 : {
1234 1 : case TALER_PQ_array_of_amount:
1235 : {
1236 : struct TALER_Amount *amounts;
1237 1 : if (NULL != dst_size)
1238 1 : *dst_size = sizeof(struct TALER_Amount) * (header.dim);
1239 :
1240 1 : amounts = GNUNET_new_array (header.dim,
1241 : struct TALER_Amount);
1242 1 : *((void **) dst) = amounts;
1243 :
1244 4 : for (uint32_t i = 0; i < header.dim; i++)
1245 : {
1246 : struct TALER_PQ_AmountP ap;
1247 3 : struct TALER_Amount *amount = &amounts[i];
1248 : uint32_t val;
1249 : size_t sz;
1250 :
1251 3 : GNUNET_memcpy (&val,
1252 : in,
1253 : sizeof(val));
1254 3 : sz = ntohl (val);
1255 3 : in += sizeof(val);
1256 :
1257 : /* total size for this array-entry */
1258 3 : FAIL_IF (sizeof(ap) != sz);
1259 :
1260 3 : GNUNET_memcpy (&ap,
1261 : in,
1262 : sz);
1263 3 : FAIL_IF (2 != ntohl (ap.cnt));
1264 :
1265 3 : amount->value = GNUNET_ntohll (ap.v);
1266 3 : amount->fraction = ntohl (ap.f);
1267 3 : GNUNET_memcpy (amount->currency,
1268 : info->currency,
1269 : TALER_CURRENCY_LEN);
1270 :
1271 3 : in += sizeof(struct TALER_PQ_AmountP);
1272 : }
1273 1 : return GNUNET_OK;
1274 : }
1275 1 : case TALER_PQ_array_of_amount_currency:
1276 : {
1277 : struct TALER_Amount *amounts;
1278 1 : if (NULL != dst_size)
1279 1 : *dst_size = sizeof(struct TALER_Amount) * (header.dim);
1280 :
1281 1 : amounts = GNUNET_new_array (header.dim,
1282 : struct TALER_Amount);
1283 1 : *((void **) dst) = amounts;
1284 :
1285 3 : for (uint32_t i = 0; i < header.dim; i++)
1286 : {
1287 : struct TALER_PQ_AmountCurrencyP ap;
1288 2 : struct TALER_Amount *amount = &amounts[i];
1289 : uint32_t val;
1290 : size_t sz;
1291 :
1292 2 : GNUNET_memcpy (&val,
1293 : in,
1294 : sizeof(val));
1295 2 : sz = ntohl (val);
1296 2 : in += sizeof(val);
1297 :
1298 2 : FAIL_IF ( (sz >= sizeof(ap)) ||
1299 : (sz <= sizeof(ap) - TALER_CURRENCY_LEN) );
1300 :
1301 2 : memset (&ap,
1302 : 0,
1303 : sizeof(ap));
1304 2 : GNUNET_memcpy (&ap,
1305 : in,
1306 : sz);
1307 2 : FAIL_IF (3 != ntohl (ap.cnt));
1308 :
1309 2 : amount->value = GNUNET_ntohll (ap.v);
1310 2 : amount->fraction = ntohl (ap.f);
1311 2 : GNUNET_memcpy (amount->currency,
1312 : ap.c,
1313 : TALER_CURRENCY_LEN);
1314 :
1315 2 : FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]);
1316 2 : FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE);
1317 2 : FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE);
1318 :
1319 2 : in += sz;
1320 : }
1321 1 : return GNUNET_OK;
1322 : }
1323 7 : case TALER_PQ_array_of_denom_hash:
1324 7 : if (NULL != dst_size)
1325 7 : *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
1326 7 : out = GNUNET_new_array (header.dim,
1327 : struct TALER_DenominationHashP);
1328 7 : *((void **) dst) = out;
1329 16 : for (uint32_t i = 0; i < header.dim; i++)
1330 : {
1331 : uint32_t val;
1332 : size_t sz;
1333 :
1334 9 : GNUNET_memcpy (&val,
1335 : in,
1336 : sizeof(val));
1337 9 : sz = ntohl (val);
1338 9 : FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
1339 9 : in += sizeof(uint32_t);
1340 9 : *(struct TALER_DenominationHashP *) out =
1341 : *(struct TALER_DenominationHashP *) in;
1342 9 : in += sz;
1343 9 : out += sz;
1344 : }
1345 7 : return GNUNET_OK;
1346 :
1347 1 : case TALER_PQ_array_of_hash_code:
1348 1 : if (NULL != dst_size)
1349 1 : *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
1350 1 : out = GNUNET_new_array (header.dim,
1351 : struct GNUNET_HashCode);
1352 1 : *((void **) dst) = out;
1353 3 : for (uint32_t i = 0; i < header.dim; i++)
1354 : {
1355 : uint32_t val;
1356 : size_t sz;
1357 :
1358 2 : GNUNET_memcpy (&val,
1359 : in,
1360 : sizeof(val));
1361 2 : sz = ntohl (val);
1362 2 : FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
1363 2 : in += sizeof(uint32_t);
1364 2 : *(struct GNUNET_HashCode *) out =
1365 : *(struct GNUNET_HashCode *) in;
1366 2 : in += sz;
1367 2 : out += sz;
1368 : }
1369 1 : return GNUNET_OK;
1370 :
1371 0 : case TALER_PQ_array_of_blinded_coin_hash:
1372 0 : if (NULL != dst_size)
1373 0 : *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
1374 0 : out = GNUNET_new_array (header.dim,
1375 : struct TALER_BlindedCoinHashP);
1376 0 : *((void **) dst) = out;
1377 0 : for (uint32_t i = 0; i < header.dim; i++)
1378 : {
1379 : uint32_t val;
1380 : size_t sz;
1381 :
1382 0 : GNUNET_memcpy (&val,
1383 : in,
1384 : sizeof(val));
1385 0 : sz = ntohl (val);
1386 0 : FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
1387 0 : in += sizeof(uint32_t);
1388 0 : *(struct TALER_BlindedCoinHashP *) out =
1389 : *(struct TALER_BlindedCoinHashP *) in;
1390 0 : in += sz;
1391 0 : out += sz;
1392 : }
1393 0 : return GNUNET_OK;
1394 :
1395 9 : case TALER_PQ_array_of_cs_r_pub:
1396 9 : if (NULL != dst_size)
1397 9 : *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim);
1398 9 : out = GNUNET_new_array (header.dim,
1399 : struct GNUNET_CRYPTO_CSPublicRPairP);
1400 9 : *((void **) dst) = out;
1401 45 : for (uint32_t i = 0; i < header.dim; i++)
1402 : {
1403 : uint32_t val;
1404 : size_t sz;
1405 :
1406 36 : GNUNET_memcpy (&val,
1407 : in,
1408 : sizeof(val));
1409 36 : sz = ntohl (val);
1410 36 : FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
1411 36 : in += sizeof(uint32_t);
1412 36 : *(struct GNUNET_CRYPTO_CSPublicRPairP *) out =
1413 : *(struct GNUNET_CRYPTO_CSPublicRPairP *) in;
1414 36 : in += sz;
1415 36 : out += sz;
1416 : }
1417 9 : return GNUNET_OK;
1418 :
1419 17 : case TALER_PQ_array_of_blinded_denom_sig:
1420 : {
1421 : struct TALER_BlindedDenominationSignature *denom_sigs;
1422 17 : if (0 == header.dim)
1423 : {
1424 0 : if (NULL != dst_size)
1425 0 : *dst_size = 0;
1426 0 : break;
1427 : }
1428 :
1429 17 : denom_sigs = GNUNET_new_array (header.dim,
1430 : struct TALER_BlindedDenominationSignature);
1431 17 : *((void **) dst) = denom_sigs;
1432 :
1433 : /* copy data */
1434 80 : for (uint32_t i = 0; i < header.dim; i++)
1435 : {
1436 63 : struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
1437 : struct GNUNET_CRYPTO_BlindedSignature *bs;
1438 : uint32_t be[2];
1439 : uint32_t val;
1440 : size_t sz;
1441 :
1442 63 : GNUNET_memcpy (&val,
1443 : in,
1444 : sizeof(val));
1445 63 : sz = ntohl (val);
1446 63 : FAIL_IF (sizeof(be) > sz);
1447 :
1448 63 : in += sizeof(val);
1449 63 : GNUNET_memcpy (&be,
1450 : in,
1451 : sizeof(be));
1452 63 : FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */
1453 :
1454 63 : in += sizeof(be);
1455 63 : sz -= sizeof(be);
1456 63 : bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
1457 63 : bs->cipher = ntohl (be[0]);
1458 63 : bs->rc = 1;
1459 63 : switch (bs->cipher)
1460 : {
1461 32 : case GNUNET_CRYPTO_BSA_RSA:
1462 : bs->details.blinded_rsa_signature
1463 32 : = GNUNET_CRYPTO_rsa_signature_decode (in,
1464 : sz);
1465 32 : if (NULL == bs->details.blinded_rsa_signature)
1466 : {
1467 0 : GNUNET_free (bs);
1468 0 : FAIL_IF (true);
1469 : }
1470 32 : break;
1471 31 : case GNUNET_CRYPTO_BSA_CS:
1472 31 : if (sizeof(bs->details.blinded_cs_answer) != sz)
1473 : {
1474 0 : GNUNET_free (bs);
1475 0 : FAIL_IF (true);
1476 : }
1477 31 : GNUNET_memcpy (&bs->details.blinded_cs_answer,
1478 : in,
1479 : sz);
1480 31 : break;
1481 0 : default:
1482 0 : GNUNET_free (bs);
1483 0 : FAIL_IF (true);
1484 : }
1485 63 : denom_sig->blinded_sig = bs;
1486 63 : in += sz;
1487 : }
1488 17 : return GNUNET_OK;
1489 : }
1490 0 : default:
1491 0 : FAIL_IF (true);
1492 : }
1493 : }
1494 0 : FAIL:
1495 0 : GNUNET_free (*(void **) dst);
1496 0 : return GNUNET_SYSERR;
1497 : #undef FAIL_IF
1498 : }
1499 :
1500 :
1501 : /**
1502 : * Cleanup of the data and closure of an array spec.
1503 : */
1504 : static void
1505 87 : array_cleanup (void *cls,
1506 : void *rd)
1507 : {
1508 87 : struct ArrayResultCls *info = cls;
1509 87 : void **dst = rd;
1510 :
1511 87 : if ( (0 == info->same_size) &&
1512 87 : (NULL != info->sizes) )
1513 0 : GNUNET_free (*(info->sizes));
1514 :
1515 : /* Clean up signatures, if applicable */
1516 87 : if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
1517 37 : (NULL != *dst))
1518 : {
1519 0 : struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
1520 :
1521 0 : GNUNET_assert (NULL != info->num);
1522 0 : for (size_t i = 0; i < *info->num; i++)
1523 0 : GNUNET_free (denom_sigs[i].blinded_sig);
1524 : }
1525 87 : GNUNET_free (info);
1526 87 : GNUNET_free (*dst);
1527 87 : *dst = NULL;
1528 87 : }
1529 :
1530 :
1531 : struct GNUNET_PQ_ResultSpec
1532 37 : TALER_PQ_result_spec_array_blinded_denom_sig (
1533 : struct GNUNET_PQ_Context *db,
1534 : const char *name,
1535 : size_t *num,
1536 : struct TALER_BlindedDenominationSignature **denom_sigs)
1537 : {
1538 37 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1539 :
1540 37 : info->num = num;
1541 37 : info->typ = TALER_PQ_array_of_blinded_denom_sig;
1542 37 : GNUNET_assert (GNUNET_OK ==
1543 : GNUNET_PQ_get_oid_by_name (db,
1544 : "bytea",
1545 : &info->oid));
1546 : {
1547 37 : struct GNUNET_PQ_ResultSpec res = {
1548 : .conv = extract_array_generic,
1549 : .cleaner = &array_cleanup,
1550 : .dst = (void *) denom_sigs,
1551 : .fname = name,
1552 : .cls = info
1553 : };
1554 :
1555 37 : return res;
1556 : }
1557 : }
1558 :
1559 :
1560 : struct GNUNET_PQ_ResultSpec
1561 0 : TALER_PQ_result_spec_array_blinded_coin_hash (
1562 : struct GNUNET_PQ_Context *db,
1563 : const char *name,
1564 : size_t *num,
1565 : struct TALER_BlindedCoinHashP **h_coin_evs)
1566 : {
1567 0 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1568 :
1569 0 : info->num = num;
1570 0 : info->typ = TALER_PQ_array_of_blinded_coin_hash;
1571 0 : GNUNET_assert (GNUNET_OK ==
1572 : GNUNET_PQ_get_oid_by_name (db,
1573 : "bytea",
1574 : &info->oid));
1575 : {
1576 0 : struct GNUNET_PQ_ResultSpec res = {
1577 : .conv = extract_array_generic,
1578 : .cleaner = &array_cleanup,
1579 : .dst = (void *) h_coin_evs,
1580 : .fname = name,
1581 : .cls = info
1582 : };
1583 :
1584 0 : return res;
1585 : }
1586 : }
1587 :
1588 :
1589 : struct GNUNET_PQ_ResultSpec
1590 7 : TALER_PQ_result_spec_array_denom_hash (
1591 : struct GNUNET_PQ_Context *db,
1592 : const char *name,
1593 : size_t *num,
1594 : struct TALER_DenominationHashP **denom_hs)
1595 : {
1596 7 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1597 :
1598 7 : info->num = num;
1599 7 : info->typ = TALER_PQ_array_of_denom_hash;
1600 7 : GNUNET_assert (GNUNET_OK ==
1601 : GNUNET_PQ_get_oid_by_name (db,
1602 : "bytea",
1603 : &info->oid));
1604 : {
1605 7 : struct GNUNET_PQ_ResultSpec res = {
1606 : .conv = extract_array_generic,
1607 : .cleaner = &array_cleanup,
1608 : .dst = (void *) denom_hs,
1609 : .fname = name,
1610 : .cls = info
1611 : };
1612 :
1613 7 : return res;
1614 : }
1615 : }
1616 :
1617 :
1618 : struct GNUNET_PQ_ResultSpec
1619 2 : TALER_PQ_result_spec_array_amount (
1620 : struct GNUNET_PQ_Context *db,
1621 : const char *name,
1622 : const char *currency,
1623 : size_t *num,
1624 : struct TALER_Amount **amounts)
1625 : {
1626 2 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1627 :
1628 2 : info->num = num;
1629 2 : info->typ = TALER_PQ_array_of_amount;
1630 2 : info->db = db;
1631 2 : GNUNET_assert (GNUNET_OK ==
1632 : GNUNET_PQ_get_oid_by_name (db,
1633 : "taler_amount",
1634 : &info->oid));
1635 :
1636 : {
1637 2 : size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
1638 : strlen (currency));
1639 2 : GNUNET_memcpy (&info->currency,
1640 : currency,
1641 : clen);
1642 : }
1643 : {
1644 2 : struct GNUNET_PQ_ResultSpec res = {
1645 : .conv = extract_array_generic,
1646 : .cleaner = &array_cleanup,
1647 : .dst = (void *) amounts,
1648 : .fname = name,
1649 : .cls = info,
1650 : };
1651 :
1652 2 : return res;
1653 : }
1654 : }
1655 :
1656 :
1657 : struct GNUNET_PQ_ResultSpec
1658 2 : TALER_PQ_result_spec_array_amount_with_currency (
1659 : struct GNUNET_PQ_Context *db,
1660 : const char *name,
1661 : size_t *num,
1662 : struct TALER_Amount **amounts)
1663 : {
1664 2 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1665 :
1666 2 : info->num = num;
1667 2 : info->typ = TALER_PQ_array_of_amount_currency;
1668 2 : info->db = db;
1669 2 : GNUNET_assert (GNUNET_OK ==
1670 : GNUNET_PQ_get_oid_by_name (db,
1671 : "taler_amount_currency",
1672 : &info->oid));
1673 :
1674 : {
1675 2 : struct GNUNET_PQ_ResultSpec res = {
1676 : .conv = extract_array_generic,
1677 : .cleaner = &array_cleanup,
1678 : .dst = (void *) amounts,
1679 : .fname = name,
1680 : .cls = info,
1681 : };
1682 :
1683 2 : return res;
1684 : }
1685 : }
1686 :
1687 :
1688 : struct GNUNET_PQ_ResultSpec
1689 1 : TALER_PQ_result_spec_array_hash_code (
1690 : struct GNUNET_PQ_Context *db,
1691 : const char *name,
1692 : size_t *num,
1693 : struct GNUNET_HashCode **hashes)
1694 : {
1695 1 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1696 :
1697 1 : info->num = num;
1698 1 : info->typ = TALER_PQ_array_of_hash_code;
1699 1 : info->db = db;
1700 1 : GNUNET_assert (GNUNET_OK ==
1701 : GNUNET_PQ_get_oid_by_name (db,
1702 : "gnunet_hashcode",
1703 : &info->oid));
1704 : {
1705 1 : struct GNUNET_PQ_ResultSpec res = {
1706 : .conv = extract_array_generic,
1707 : .cleaner = &array_cleanup,
1708 : .dst = (void *) hashes,
1709 : .fname = name,
1710 : .cls = info,
1711 : };
1712 :
1713 1 : return res;
1714 : }
1715 : }
1716 :
1717 :
1718 : struct GNUNET_PQ_ResultSpec
1719 38 : TALER_PQ_result_spec_array_cs_r_pub (
1720 : struct GNUNET_PQ_Context *db,
1721 : const char *name,
1722 : size_t *num,
1723 : struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs)
1724 : {
1725 38 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1726 :
1727 38 : info->num = num;
1728 38 : info->typ = TALER_PQ_array_of_cs_r_pub;
1729 38 : GNUNET_assert (GNUNET_OK ==
1730 : GNUNET_PQ_get_oid_by_name (db,
1731 : "bytea",
1732 : &info->oid));
1733 : {
1734 38 : struct GNUNET_PQ_ResultSpec res = {
1735 : .conv = extract_array_generic,
1736 : .cleaner = &array_cleanup,
1737 : .dst = (void *) cs_r_pubs,
1738 : .fname = name,
1739 : .cls = info
1740 : };
1741 :
1742 38 : return res;
1743 : }
1744 : }
1745 :
1746 :
1747 : /* end of pq_result_helper.c */
|