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 extract results from a query result
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 6874 : 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 6874 : struct TALER_Amount *r_amount = dst;
193 6874 : const char *currency = cls;
194 : int col;
195 : size_t len;
196 :
197 6874 : 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 6874 : memset (r_amount,
205 : 0,
206 : sizeof (struct TALER_Amount));
207 6874 : col = PQfnumber (result,
208 : fname);
209 6874 : 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 6874 : 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 6870 : size = PQgetlength (result,
230 : row,
231 : col);
232 6870 : in = PQgetvalue (result,
233 : row,
234 : col);
235 6870 : if (sizeof(struct TALER_PQ_AmountNullP) == size)
236 : {
237 : struct TALER_PQ_AmountNullP apn;
238 :
239 246 : memcpy (&apn,
240 : in,
241 : size);
242 246 : if ( (2 == ntohl (apn.cnt)) &&
243 246 : (-1 == (int32_t) ntohl (apn.sz_v)) &&
244 246 : (-1 == (int32_t) ntohl (apn.sz_f)) )
245 : {
246 : /* is NULL! */
247 246 : 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 6624 : 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 6624 : memcpy (&ap,
267 : in,
268 : size);
269 6624 : 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 6624 : r_amount->value = GNUNET_ntohll (ap.v);
279 6624 : r_amount->fraction = ntohl (ap.f);
280 : }
281 :
282 6624 : 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 6624 : 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 6624 : len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
298 : strlen (currency));
299 :
300 6624 : GNUNET_memcpy (r_amount->currency,
301 : currency,
302 : len);
303 6624 : return GNUNET_OK;
304 : }
305 :
306 :
307 : struct GNUNET_PQ_ResultSpec
308 9721 : TALER_PQ_result_spec_amount (const char *name,
309 : const char *currency,
310 : struct TALER_Amount *amount)
311 : {
312 9721 : 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 9721 : 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 325 : extract_json (void *cls,
340 : PGresult *result,
341 : int row,
342 : const char *fname,
343 : size_t *dst_size,
344 : void *dst)
345 : {
346 325 : 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 325 : fnum = PQfnumber (result,
355 : fname);
356 325 : 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 325 : if (PQgetisnull (result,
364 : row,
365 : fnum))
366 162 : return GNUNET_NO;
367 163 : slen = PQgetlength (result,
368 : row,
369 : fnum);
370 163 : res = (const char *) PQgetvalue (result,
371 : row,
372 : fnum);
373 163 : *j_dst = json_loadb (res,
374 : slen,
375 : JSON_REJECT_DUPLICATES,
376 : &json_error);
377 163 : 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 163 : 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 107 : clean_json (void *cls,
399 : void *rd)
400 : {
401 107 : json_t **dst = rd;
402 :
403 : (void) cls;
404 107 : if (NULL != *dst)
405 : {
406 85 : json_decref (*dst);
407 85 : *dst = NULL;
408 : }
409 107 : }
410 :
411 :
412 : struct GNUNET_PQ_ResultSpec
413 345 : TALER_PQ_result_spec_json (const char *name,
414 : json_t **jp)
415 : {
416 345 : struct GNUNET_PQ_ResultSpec res = {
417 : .conv = &extract_json,
418 : .cleaner = &clean_json,
419 : .dst = (void *) jp,
420 : .fname = name
421 : };
422 :
423 345 : 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 853 : 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 853 : 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 853 : fnum = PQfnumber (result,
458 : fname);
459 853 : if (fnum < 0)
460 : {
461 0 : GNUNET_break (0);
462 0 : return GNUNET_SYSERR;
463 : }
464 853 : 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 853 : len = PQgetlength (result,
472 : row,
473 : fnum);
474 853 : res = PQgetvalue (result,
475 : row,
476 : fnum);
477 853 : if (len < sizeof (be))
478 : {
479 0 : GNUNET_break (0);
480 0 : return GNUNET_SYSERR;
481 : }
482 853 : GNUNET_memcpy (be,
483 : res,
484 : sizeof (be));
485 853 : res += sizeof (be);
486 853 : len -= sizeof (be);
487 853 : bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
488 853 : bpk->cipher = ntohl (be[0]);
489 853 : bpk->rc = 1;
490 853 : pk->age_mask.bits = ntohl (be[1]);
491 853 : 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 420 : case GNUNET_CRYPTO_BSA_CS:
511 420 : 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 420 : GNUNET_memcpy (&bpk->details.cs_public_key,
518 : res,
519 : len);
520 420 : pk->bsign_pub_key = bpk;
521 420 : GNUNET_CRYPTO_hash (res,
522 : len,
523 : &bpk->pub_key_hash);
524 420 : 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 687 : clean_denom_pub (void *cls,
541 : void *rd)
542 : {
543 687 : struct TALER_DenominationPublicKey *denom_pub = rd;
544 :
545 : (void) cls;
546 687 : TALER_denom_pub_free (denom_pub);
547 687 : }
548 :
549 :
550 : struct GNUNET_PQ_ResultSpec
551 854 : TALER_PQ_result_spec_denom_pub (const char *name,
552 : struct TALER_DenominationPublicKey *denom_pub)
553 : {
554 854 : 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 854 : 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 9 : 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 9 : 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 9 : fnum = PQfnumber (result,
596 : fname);
597 9 : if (fnum < 0)
598 : {
599 0 : GNUNET_break (0);
600 0 : return GNUNET_SYSERR;
601 : }
602 9 : 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 9 : len = PQgetlength (result,
610 : row,
611 : fnum);
612 9 : res = PQgetvalue (result,
613 : row,
614 : fnum);
615 9 : if (len < sizeof (be))
616 : {
617 0 : GNUNET_break (0);
618 0 : return GNUNET_SYSERR;
619 : }
620 9 : GNUNET_memcpy (&be,
621 : res,
622 : sizeof (be));
623 9 : if (0x00 != ntohl (be[1]))
624 : {
625 0 : GNUNET_break (0);
626 0 : return GNUNET_SYSERR;
627 : }
628 9 : res += sizeof (be);
629 9 : len -= sizeof (be);
630 9 : ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
631 9 : ubs->rc = 1;
632 9 : ubs->cipher = ntohl (be[0]);
633 9 : 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 7 : case GNUNET_CRYPTO_BSA_CS:
650 7 : 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 7 : GNUNET_memcpy (&ubs->details.cs_signature,
657 : res,
658 : len);
659 7 : sig->unblinded_sig = ubs;
660 7 : 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 3 : clean_denom_sig (void *cls,
677 : void *rd)
678 : {
679 3 : struct TALER_DenominationSignature *denom_sig = rd;
680 :
681 : (void) cls;
682 3 : TALER_denom_sig_free (denom_sig);
683 3 : }
684 :
685 :
686 : struct GNUNET_PQ_ResultSpec
687 11 : TALER_PQ_result_spec_denom_sig (const char *name,
688 : struct TALER_DenominationSignature *denom_sig)
689 : {
690 11 : 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 11 : 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 59 : 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 59 : const struct ArrayResultCls *info = cls;
1156 : int data_sz;
1157 : char *data;
1158 59 : void *out = NULL;
1159 : struct GNUNET_PQ_ArrayHeader_P header;
1160 : int col_num;
1161 :
1162 59 : GNUNET_assert (NULL != dst);
1163 59 : *((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 59 : col_num = PQfnumber (result, fname);
1175 59 : FAIL_IF (0 > col_num);
1176 :
1177 59 : if (PQgetisnull (result, row, col_num))
1178 : {
1179 9 : if (NULL != info->num)
1180 9 : *info->num = 0;
1181 9 : return GNUNET_NO;
1182 : }
1183 :
1184 50 : data_sz = PQgetlength (result, row, col_num);
1185 50 : FAIL_IF (0 > data_sz);
1186 :
1187 : /* Report if this field is empty */
1188 50 : if (0 == (size_t) data_sz)
1189 : {
1190 0 : if (NULL != info->num)
1191 0 : *info->num = 0;
1192 0 : return GNUNET_NO;
1193 : }
1194 :
1195 50 : data = PQgetvalue (result, row, col_num);
1196 :
1197 50 : if (sizeof(header) > (size_t) data_sz)
1198 : {
1199 : uint32_t ndim;
1200 :
1201 : /* data_sz is shorter than header if the
1202 : array length is 0, in which case ndim is 0! */
1203 3 : FAIL_IF (sizeof(uint32_t) > (size_t) data_sz);
1204 3 : memcpy (&ndim,
1205 : data,
1206 : sizeof (ndim));
1207 3 : FAIL_IF (0 != ndim);
1208 3 : if (NULL != info->num)
1209 3 : *info->num = 0;
1210 3 : return GNUNET_OK;
1211 : }
1212 47 : FAIL_IF (sizeof(header) > (size_t) data_sz);
1213 47 : FAIL_IF (NULL == data);
1214 :
1215 : {
1216 47 : struct GNUNET_PQ_ArrayHeader_P *h =
1217 : (struct GNUNET_PQ_ArrayHeader_P *) data;
1218 :
1219 47 : header.ndim = ntohl (h->ndim);
1220 47 : header.has_null = ntohl (h->has_null);
1221 47 : header.oid = ntohl (h->oid);
1222 47 : header.dim = ntohl (h->dim);
1223 47 : header.lbound = ntohl (h->lbound);
1224 :
1225 47 : FAIL_IF (1 != header.ndim);
1226 47 : FAIL_IF (INT_MAX <= header.dim);
1227 47 : FAIL_IF (0 != header.has_null);
1228 47 : FAIL_IF (1 != header.lbound);
1229 47 : FAIL_IF (info->oid != header.oid);
1230 : /* Cross-check the claimed number of elements against the
1231 : size of the payload: each element is at least prefixed by
1232 : its own 32-bit length. Without this, a corrupted row can
1233 : make us allocate an absurd amount of memory. */
1234 47 : FAIL_IF (header.dim >
1235 : ((size_t) data_sz - sizeof (header)) / sizeof (uint32_t));
1236 : }
1237 :
1238 47 : if (NULL != info->num)
1239 47 : *info->num = header.dim;
1240 47 : if (0 == header.dim)
1241 : {
1242 0 : if (NULL != dst_size)
1243 0 : *dst_size = 0;
1244 0 : return GNUNET_OK;
1245 : }
1246 :
1247 : {
1248 47 : char *in = data + sizeof(header);
1249 47 : const char *const data_end = data + (size_t) data_sz;
1250 :
1251 47 : switch (info->typ)
1252 : {
1253 1 : case TALER_PQ_array_of_amount:
1254 : {
1255 : struct TALER_Amount *amounts;
1256 :
1257 1 : if (NULL != dst_size)
1258 1 : *dst_size = sizeof(struct TALER_Amount) * (header.dim);
1259 :
1260 1 : amounts = GNUNET_new_array (header.dim,
1261 : struct TALER_Amount);
1262 1 : *((void **) dst) = amounts;
1263 :
1264 4 : for (uint32_t i = 0; i < header.dim; i++)
1265 : {
1266 : struct TALER_PQ_AmountP ap;
1267 3 : struct TALER_Amount *amount = &amounts[i];
1268 : uint32_t val;
1269 : size_t sz;
1270 :
1271 3 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1272 3 : GNUNET_memcpy (&val,
1273 : in,
1274 : sizeof(val));
1275 3 : sz = ntohl (val);
1276 3 : in += sizeof(val);
1277 3 : FAIL_IF (sz > (size_t) (data_end - in));
1278 :
1279 : /* total size for this array-entry */
1280 3 : FAIL_IF (sizeof(ap) != sz);
1281 :
1282 3 : GNUNET_memcpy (&ap,
1283 : in,
1284 : sz);
1285 3 : FAIL_IF (2 != ntohl (ap.cnt));
1286 :
1287 3 : amount->value = GNUNET_ntohll (ap.v);
1288 3 : amount->fraction = ntohl (ap.f);
1289 3 : GNUNET_memcpy (amount->currency,
1290 : info->currency,
1291 : TALER_CURRENCY_LEN);
1292 :
1293 3 : FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE);
1294 3 : FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE);
1295 :
1296 3 : in += sizeof(struct TALER_PQ_AmountP);
1297 : }
1298 1 : return GNUNET_OK;
1299 : }
1300 1 : case TALER_PQ_array_of_amount_currency:
1301 : {
1302 : struct TALER_Amount *amounts;
1303 :
1304 1 : if (NULL != dst_size)
1305 1 : *dst_size = sizeof(struct TALER_Amount) * (header.dim);
1306 :
1307 1 : amounts = GNUNET_new_array (header.dim,
1308 : struct TALER_Amount);
1309 1 : *((void **) dst) = amounts;
1310 :
1311 3 : for (uint32_t i = 0; i < header.dim; i++)
1312 : {
1313 : struct TALER_PQ_AmountCurrencyP ap;
1314 2 : struct TALER_Amount *amount = &amounts[i];
1315 : uint32_t val;
1316 : size_t sz;
1317 :
1318 2 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1319 2 : GNUNET_memcpy (&val,
1320 : in,
1321 : sizeof(val));
1322 2 : sz = ntohl (val);
1323 2 : in += sizeof(val);
1324 2 : FAIL_IF (sz > (size_t) (data_end - in));
1325 :
1326 2 : FAIL_IF ( (sz >= sizeof(ap)) ||
1327 : (sz <= sizeof(ap) - TALER_CURRENCY_LEN) );
1328 :
1329 2 : memset (&ap,
1330 : 0,
1331 : sizeof(ap));
1332 2 : GNUNET_memcpy (&ap,
1333 : in,
1334 : sz);
1335 2 : FAIL_IF (3 != ntohl (ap.cnt));
1336 :
1337 2 : amount->value = GNUNET_ntohll (ap.v);
1338 2 : amount->fraction = ntohl (ap.f);
1339 2 : GNUNET_memcpy (amount->currency,
1340 : ap.c,
1341 : TALER_CURRENCY_LEN);
1342 :
1343 2 : FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]);
1344 2 : FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE);
1345 2 : FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE);
1346 :
1347 2 : in += sz;
1348 : }
1349 1 : return GNUNET_OK;
1350 : }
1351 13 : case TALER_PQ_array_of_denom_hash:
1352 13 : if (NULL != dst_size)
1353 13 : *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
1354 13 : out = GNUNET_new_array (header.dim,
1355 : struct TALER_DenominationHashP);
1356 13 : *((void **) dst) = out;
1357 38 : for (uint32_t i = 0; i < header.dim; i++)
1358 : {
1359 : uint32_t val;
1360 : size_t sz;
1361 :
1362 25 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1363 25 : GNUNET_memcpy (&val,
1364 : in,
1365 : sizeof(val));
1366 25 : sz = ntohl (val);
1367 25 : FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
1368 25 : in += sizeof(uint32_t);
1369 25 : FAIL_IF (sz > (size_t) (data_end - in));
1370 25 : *(struct TALER_DenominationHashP *) out =
1371 : *(struct TALER_DenominationHashP *) in;
1372 25 : in += sz;
1373 25 : out += sz;
1374 : }
1375 13 : return GNUNET_OK;
1376 :
1377 1 : case TALER_PQ_array_of_hash_code:
1378 1 : if (NULL != dst_size)
1379 1 : *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
1380 1 : out = GNUNET_new_array (header.dim,
1381 : struct GNUNET_HashCode);
1382 1 : *((void **) dst) = out;
1383 3 : for (uint32_t i = 0; i < header.dim; i++)
1384 : {
1385 : uint32_t val;
1386 : size_t sz;
1387 :
1388 2 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1389 2 : GNUNET_memcpy (&val,
1390 : in,
1391 : sizeof(val));
1392 2 : sz = ntohl (val);
1393 2 : FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
1394 2 : in += sizeof(uint32_t);
1395 2 : FAIL_IF (sz > (size_t) (data_end - in));
1396 2 : *(struct GNUNET_HashCode *) out =
1397 : *(struct GNUNET_HashCode *) in;
1398 2 : in += sz;
1399 2 : out += sz;
1400 : }
1401 1 : return GNUNET_OK;
1402 :
1403 0 : case TALER_PQ_array_of_blinded_coin_hash:
1404 0 : if (NULL != dst_size)
1405 0 : *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
1406 0 : out = GNUNET_new_array (header.dim,
1407 : struct TALER_BlindedCoinHashP);
1408 0 : *((void **) dst) = out;
1409 0 : for (uint32_t i = 0; i < header.dim; i++)
1410 : {
1411 : uint32_t val;
1412 : size_t sz;
1413 :
1414 0 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1415 0 : GNUNET_memcpy (&val,
1416 : in,
1417 : sizeof(val));
1418 0 : sz = ntohl (val);
1419 0 : FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
1420 0 : in += sizeof(uint32_t);
1421 0 : FAIL_IF (sz > (size_t) (data_end - in));
1422 0 : *(struct TALER_BlindedCoinHashP *) out =
1423 : *(struct TALER_BlindedCoinHashP *) in;
1424 0 : in += sz;
1425 0 : out += sz;
1426 : }
1427 0 : return GNUNET_OK;
1428 :
1429 11 : case TALER_PQ_array_of_cs_r_pub:
1430 11 : if (NULL != dst_size)
1431 11 : *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim);
1432 11 : out = GNUNET_new_array (header.dim,
1433 : struct GNUNET_CRYPTO_CSPublicRPairP);
1434 11 : *((void **) dst) = out;
1435 49 : for (uint32_t i = 0; i < header.dim; i++)
1436 : {
1437 : uint32_t val;
1438 : size_t sz;
1439 :
1440 38 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1441 38 : GNUNET_memcpy (&val,
1442 : in,
1443 : sizeof(val));
1444 38 : sz = ntohl (val);
1445 38 : FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
1446 38 : in += sizeof(uint32_t);
1447 38 : FAIL_IF (sz > (size_t) (data_end - in));
1448 38 : *(struct GNUNET_CRYPTO_CSPublicRPairP *) out =
1449 : *(struct GNUNET_CRYPTO_CSPublicRPairP *) in;
1450 38 : in += sz;
1451 38 : out += sz;
1452 : }
1453 11 : return GNUNET_OK;
1454 :
1455 20 : case TALER_PQ_array_of_blinded_denom_sig:
1456 : {
1457 : struct TALER_BlindedDenominationSignature *denom_sigs;
1458 :
1459 20 : denom_sigs = GNUNET_new_array (header.dim,
1460 : struct TALER_BlindedDenominationSignature);
1461 20 : *((void **) dst) = denom_sigs;
1462 :
1463 : /* copy data */
1464 86 : for (uint32_t i = 0; i < header.dim; i++)
1465 : {
1466 66 : struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
1467 : struct GNUNET_CRYPTO_BlindedSignature *bs;
1468 : uint32_t be[2];
1469 : uint32_t val;
1470 : size_t sz;
1471 :
1472 66 : FAIL_IF (sizeof(val) > (size_t) (data_end - in));
1473 66 : GNUNET_memcpy (&val,
1474 : in,
1475 : sizeof(val));
1476 66 : sz = ntohl (val);
1477 66 : FAIL_IF (sizeof(be) > sz);
1478 :
1479 66 : in += sizeof(val);
1480 66 : FAIL_IF (sz > (size_t) (data_end - in));
1481 66 : GNUNET_memcpy (&be,
1482 : in,
1483 : sizeof(be));
1484 66 : FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */
1485 :
1486 66 : in += sizeof(be);
1487 66 : sz -= sizeof(be);
1488 66 : bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
1489 66 : bs->cipher = ntohl (be[0]);
1490 66 : bs->rc = 1;
1491 66 : switch (bs->cipher)
1492 : {
1493 32 : case GNUNET_CRYPTO_BSA_RSA:
1494 : bs->details.blinded_rsa_signature
1495 32 : = GNUNET_CRYPTO_rsa_signature_decode (in,
1496 : sz);
1497 32 : if (NULL == bs->details.blinded_rsa_signature)
1498 : {
1499 0 : GNUNET_free (bs);
1500 0 : FAIL_IF (true);
1501 : }
1502 32 : break;
1503 34 : case GNUNET_CRYPTO_BSA_CS:
1504 34 : if (sizeof(bs->details.blinded_cs_answer) != sz)
1505 : {
1506 0 : GNUNET_free (bs);
1507 0 : FAIL_IF (true);
1508 : }
1509 34 : GNUNET_memcpy (&bs->details.blinded_cs_answer,
1510 : in,
1511 : sz);
1512 34 : break;
1513 0 : default:
1514 0 : GNUNET_free (bs);
1515 0 : FAIL_IF (true);
1516 : }
1517 66 : denom_sig->blinded_sig = bs;
1518 66 : in += sz;
1519 : }
1520 20 : return GNUNET_OK;
1521 : }
1522 0 : default:
1523 0 : FAIL_IF (true);
1524 : }
1525 : }
1526 0 : FAIL:
1527 0 : if ( (TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
1528 0 : (NULL != *(void **) dst) )
1529 : {
1530 0 : struct TALER_BlindedDenominationSignature *denom_sigs = *(void **) dst;
1531 :
1532 0 : for (uint32_t i = 0; i < header.dim; i++)
1533 0 : TALER_blinded_denom_sig_free (&denom_sigs[i]);
1534 : }
1535 0 : GNUNET_free (*(void **) dst);
1536 0 : if (NULL != info->num)
1537 0 : *info->num = 0;
1538 0 : return GNUNET_SYSERR;
1539 : #undef FAIL_IF
1540 : }
1541 :
1542 :
1543 : /**
1544 : * Cleanup of the data and closure of an array spec.
1545 : */
1546 : static void
1547 103 : array_cleanup (void *cls,
1548 : void *rd)
1549 : {
1550 103 : struct ArrayResultCls *info = cls;
1551 103 : void **dst = rd;
1552 :
1553 103 : if ( (0 == info->same_size) &&
1554 103 : (NULL != info->sizes) )
1555 0 : GNUNET_free (*(info->sizes));
1556 :
1557 : /* Clean up signatures, if applicable */
1558 103 : if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
1559 42 : (NULL != *dst))
1560 : {
1561 0 : struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
1562 :
1563 0 : GNUNET_assert (NULL != info->num);
1564 0 : for (size_t i = 0; i < *info->num; i++)
1565 0 : TALER_blinded_denom_sig_free (&denom_sigs[i]);
1566 : }
1567 103 : GNUNET_free (info);
1568 103 : GNUNET_free (*dst);
1569 103 : *dst = NULL;
1570 103 : }
1571 :
1572 :
1573 : struct GNUNET_PQ_ResultSpec
1574 42 : TALER_PQ_result_spec_array_blinded_denom_sig (
1575 : struct GNUNET_PQ_Context *db,
1576 : const char *name,
1577 : size_t *num,
1578 : struct TALER_BlindedDenominationSignature **denom_sigs)
1579 : {
1580 42 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1581 :
1582 42 : info->num = num;
1583 42 : info->typ = TALER_PQ_array_of_blinded_denom_sig;
1584 42 : GNUNET_assert (GNUNET_OK ==
1585 : GNUNET_PQ_get_oid_by_name (db,
1586 : "bytea",
1587 : &info->oid));
1588 : {
1589 42 : struct GNUNET_PQ_ResultSpec res = {
1590 : .conv = extract_array_generic,
1591 : .cleaner = &array_cleanup,
1592 : .dst = (void *) denom_sigs,
1593 : .fname = name,
1594 : .cls = info
1595 : };
1596 :
1597 42 : return res;
1598 : }
1599 : }
1600 :
1601 :
1602 : struct GNUNET_PQ_ResultSpec
1603 0 : TALER_PQ_result_spec_array_blinded_coin_hash (
1604 : struct GNUNET_PQ_Context *db,
1605 : const char *name,
1606 : size_t *num,
1607 : struct TALER_BlindedCoinHashP **h_coin_evs)
1608 : {
1609 0 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1610 :
1611 0 : info->num = num;
1612 0 : info->typ = TALER_PQ_array_of_blinded_coin_hash;
1613 0 : GNUNET_assert (GNUNET_OK ==
1614 : GNUNET_PQ_get_oid_by_name (db,
1615 : "bytea",
1616 : &info->oid));
1617 : {
1618 0 : struct GNUNET_PQ_ResultSpec res = {
1619 : .conv = extract_array_generic,
1620 : .cleaner = &array_cleanup,
1621 : .dst = (void *) h_coin_evs,
1622 : .fname = name,
1623 : .cls = info
1624 : };
1625 :
1626 0 : return res;
1627 : }
1628 : }
1629 :
1630 :
1631 : struct GNUNET_PQ_ResultSpec
1632 13 : TALER_PQ_result_spec_array_denom_hash (
1633 : struct GNUNET_PQ_Context *db,
1634 : const char *name,
1635 : size_t *num,
1636 : struct TALER_DenominationHashP **denom_hs)
1637 : {
1638 13 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1639 :
1640 13 : info->num = num;
1641 13 : info->typ = TALER_PQ_array_of_denom_hash;
1642 13 : GNUNET_assert (GNUNET_OK ==
1643 : GNUNET_PQ_get_oid_by_name (db,
1644 : "bytea",
1645 : &info->oid));
1646 : {
1647 13 : struct GNUNET_PQ_ResultSpec res = {
1648 : .conv = extract_array_generic,
1649 : .cleaner = &array_cleanup,
1650 : .dst = (void *) denom_hs,
1651 : .fname = name,
1652 : .cls = info
1653 : };
1654 :
1655 13 : return res;
1656 : }
1657 : }
1658 :
1659 :
1660 : struct GNUNET_PQ_ResultSpec
1661 2 : TALER_PQ_result_spec_array_amount (
1662 : struct GNUNET_PQ_Context *db,
1663 : const char *name,
1664 : const char *currency,
1665 : size_t *num,
1666 : struct TALER_Amount **amounts)
1667 : {
1668 2 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1669 :
1670 2 : info->num = num;
1671 2 : info->typ = TALER_PQ_array_of_amount;
1672 2 : info->db = db;
1673 2 : GNUNET_assert (GNUNET_OK ==
1674 : GNUNET_PQ_get_oid_by_name (db,
1675 : "taler_amount",
1676 : &info->oid));
1677 :
1678 : {
1679 2 : size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
1680 : strlen (currency));
1681 2 : GNUNET_memcpy (&info->currency,
1682 : currency,
1683 : clen);
1684 : }
1685 : {
1686 2 : struct GNUNET_PQ_ResultSpec res = {
1687 : .conv = extract_array_generic,
1688 : .cleaner = &array_cleanup,
1689 : .dst = (void *) amounts,
1690 : .fname = name,
1691 : .cls = info,
1692 : };
1693 :
1694 2 : return res;
1695 : }
1696 : }
1697 :
1698 :
1699 : struct GNUNET_PQ_ResultSpec
1700 2 : TALER_PQ_result_spec_array_amount_with_currency (
1701 : struct GNUNET_PQ_Context *db,
1702 : const char *schema,
1703 : const char *name,
1704 : size_t *num,
1705 : struct TALER_Amount **amounts)
1706 : {
1707 2 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1708 : char *tn;
1709 :
1710 2 : if (NULL != schema)
1711 2 : GNUNET_asprintf (&tn,
1712 : "%s.taler_amount_currency",
1713 : schema);
1714 : else
1715 0 : GNUNET_asprintf (&tn,
1716 : "taler_amount_currency");
1717 2 : info->num = num;
1718 2 : info->typ = TALER_PQ_array_of_amount_currency;
1719 2 : info->db = db;
1720 2 : GNUNET_assert (GNUNET_OK ==
1721 : GNUNET_PQ_get_oid_by_name (db,
1722 : tn,
1723 : &info->oid));
1724 2 : GNUNET_free (tn);
1725 : {
1726 2 : struct GNUNET_PQ_ResultSpec res = {
1727 : .conv = extract_array_generic,
1728 : .cleaner = &array_cleanup,
1729 : .dst = (void *) amounts,
1730 : .fname = name,
1731 : .cls = info,
1732 : };
1733 :
1734 2 : return res;
1735 : }
1736 : }
1737 :
1738 :
1739 : struct GNUNET_PQ_ResultSpec
1740 1 : TALER_PQ_result_spec_array_hash_code (
1741 : struct GNUNET_PQ_Context *db,
1742 : const char *name,
1743 : size_t *num,
1744 : struct GNUNET_HashCode **hashes)
1745 : {
1746 1 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1747 :
1748 1 : info->num = num;
1749 1 : info->typ = TALER_PQ_array_of_hash_code;
1750 1 : info->db = db;
1751 1 : GNUNET_assert (GNUNET_OK ==
1752 : GNUNET_PQ_get_oid_by_name (db,
1753 : "gnunet_hashcode",
1754 : &info->oid));
1755 : {
1756 1 : struct GNUNET_PQ_ResultSpec res = {
1757 : .conv = extract_array_generic,
1758 : .cleaner = &array_cleanup,
1759 : .dst = (void *) hashes,
1760 : .fname = name,
1761 : .cls = info,
1762 : };
1763 :
1764 1 : return res;
1765 : }
1766 : }
1767 :
1768 :
1769 : struct GNUNET_PQ_ResultSpec
1770 43 : TALER_PQ_result_spec_array_cs_r_pub (
1771 : struct GNUNET_PQ_Context *db,
1772 : const char *name,
1773 : size_t *num,
1774 : struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs)
1775 : {
1776 43 : struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
1777 :
1778 43 : info->num = num;
1779 43 : info->typ = TALER_PQ_array_of_cs_r_pub;
1780 43 : GNUNET_assert (GNUNET_OK ==
1781 : GNUNET_PQ_get_oid_by_name (db,
1782 : "bytea",
1783 : &info->oid));
1784 : {
1785 43 : struct GNUNET_PQ_ResultSpec res = {
1786 : .conv = extract_array_generic,
1787 : .cleaner = &array_cleanup,
1788 : .dst = (void *) cs_r_pubs,
1789 : .fname = name,
1790 : .cls = info
1791 : };
1792 :
1793 43 : return res;
1794 : }
1795 : }
1796 :
1797 :
1798 : /* end of pq_result_helper.c */
|