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