Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2023 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file pq/pq_query_helper.c
18 : * @brief helper functions for Taler-specific libpq (PostGres) interactions
19 : * @author Sree Harsha Totakura <sreeharsha@totakura.in>
20 : * @author Florian Dold
21 : * @author Christian Grothoff
22 : */
23 : #include "platform.h"
24 : #include <gnunet/gnunet_common.h>
25 : #include <gnunet/gnunet_util_lib.h>
26 : #include <gnunet/gnunet_pq_lib.h>
27 : #include "taler_pq_lib.h"
28 : #include "pq_common.h"
29 :
30 :
31 : /**
32 : * Function called to convert input amount into SQL parameter as tuple.
33 : *
34 : * @param cls closure
35 : * @param data pointer to input argument, here a `struct TALER_Amount`
36 : * @param data_len number of bytes in @a data (if applicable)
37 : * @param[out] param_values SQL data to set
38 : * @param[out] param_lengths SQL length data to set
39 : * @param[out] param_formats SQL format data to set
40 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
41 : * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
42 : * @param scratch_length number of entries left in @a scratch
43 : * @return -1 on error, number of offsets used in @a scratch otherwise
44 : */
45 : static int
46 49 : qconv_amount_currency_tuple (void *cls,
47 : const void *data,
48 : size_t data_len,
49 : void *param_values[],
50 : int param_lengths[],
51 : int param_formats[],
52 : unsigned int param_length,
53 : void *scratch[],
54 : unsigned int scratch_length)
55 : {
56 49 : struct GNUNET_PQ_Context *db = cls;
57 49 : const struct TALER_Amount *amount = data;
58 : size_t sz;
59 :
60 49 : GNUNET_assert (NULL != db);
61 49 : GNUNET_assert (NULL != amount);
62 49 : GNUNET_assert (1 == param_length);
63 49 : GNUNET_assert (1 <= scratch_length);
64 49 : GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
65 : GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
66 : {
67 : char *out;
68 : Oid oid_v;
69 : Oid oid_f;
70 : Oid oid_c;
71 : struct TALER_PQ_AmountCurrencyP d;
72 :
73 49 : GNUNET_assert (GNUNET_OK ==
74 : GNUNET_PQ_get_oid_by_name (db,
75 : "int8",
76 : &oid_v));
77 49 : GNUNET_assert (GNUNET_OK ==
78 : GNUNET_PQ_get_oid_by_name (db,
79 : "int4",
80 : &oid_f));
81 49 : GNUNET_assert (GNUNET_OK ==
82 : GNUNET_PQ_get_oid_by_name (db,
83 : "varchar",
84 : &oid_c));
85 49 : sz = TALER_PQ_make_taler_pq_amount_currency_ (amount,
86 : oid_v,
87 : oid_f,
88 : oid_c,
89 : &d);
90 49 : out = GNUNET_malloc (sz);
91 49 : memcpy (out,
92 : &d,
93 : sz);
94 49 : scratch[0] = out;
95 : }
96 :
97 49 : param_values[0] = scratch[0];
98 49 : param_lengths[0] = sz;
99 49 : param_formats[0] = 1;
100 :
101 49 : return 1;
102 : }
103 :
104 :
105 : struct GNUNET_PQ_QueryParam
106 49 : TALER_PQ_query_param_amount_with_currency (
107 : const struct GNUNET_PQ_Context *db,
108 : const struct TALER_Amount *amount)
109 : {
110 49 : struct GNUNET_PQ_QueryParam res = {
111 : .conv_cls = (void *) db,
112 : .conv = &qconv_amount_currency_tuple,
113 : .data = amount,
114 : .size = sizeof (*amount),
115 : .num_params = 1,
116 : };
117 :
118 49 : return res;
119 : }
120 :
121 :
122 : /**
123 : * Function called to convert input amount into SQL parameter as tuple.
124 : *
125 : * @param cls closure
126 : * @param data pointer to input argument, here a `struct TALER_Amount`
127 : * @param data_len number of bytes in @a data (if applicable)
128 : * @param[out] param_values SQL data to set
129 : * @param[out] param_lengths SQL length data to set
130 : * @param[out] param_formats SQL format data to set
131 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
132 : * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
133 : * @param scratch_length number of entries left in @a scratch
134 : * @return -1 on error, number of offsets used in @a scratch otherwise
135 : */
136 : static int
137 35848 : qconv_amount_tuple (void *cls,
138 : const void *data,
139 : size_t data_len,
140 : void *param_values[],
141 : int param_lengths[],
142 : int param_formats[],
143 : unsigned int param_length,
144 : void *scratch[],
145 : unsigned int scratch_length)
146 : {
147 35848 : struct GNUNET_PQ_Context *db = cls;
148 35848 : const struct TALER_Amount *amount = data;
149 : size_t sz;
150 :
151 35848 : GNUNET_assert (NULL != db);
152 35848 : GNUNET_assert (NULL != amount);
153 35848 : GNUNET_assert (1 == param_length);
154 35848 : GNUNET_assert (1 <= scratch_length);
155 35848 : GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
156 : GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid));
157 : {
158 : char *out;
159 : Oid oid_v;
160 : Oid oid_f;
161 :
162 35848 : GNUNET_assert (GNUNET_OK ==
163 : GNUNET_PQ_get_oid_by_name (db,
164 : "int8",
165 : &oid_v));
166 35848 : GNUNET_assert (GNUNET_OK ==
167 : GNUNET_PQ_get_oid_by_name (db,
168 : "int4",
169 : &oid_f));
170 :
171 : {
172 : struct TALER_PQ_AmountP d
173 35848 : = TALER_PQ_make_taler_pq_amount_ (amount,
174 : oid_v,
175 : oid_f);
176 :
177 35848 : sz = sizeof(d);
178 35848 : out = GNUNET_malloc (sz);
179 35848 : scratch[0] = out;
180 35848 : GNUNET_memcpy (out,
181 : &d,
182 : sizeof(d));
183 : }
184 : }
185 :
186 35848 : param_values[0] = scratch[0];
187 35848 : param_lengths[0] = sz;
188 35848 : param_formats[0] = 1;
189 :
190 35848 : return 1;
191 : }
192 :
193 :
194 : struct GNUNET_PQ_QueryParam
195 35848 : TALER_PQ_query_param_amount (
196 : const struct GNUNET_PQ_Context *db,
197 : const struct TALER_Amount *amount)
198 : {
199 35848 : struct GNUNET_PQ_QueryParam res = {
200 : .conv_cls = (void *) db,
201 : .conv = &qconv_amount_tuple,
202 : .data = amount,
203 : .size = sizeof (*amount),
204 : .num_params = 1,
205 : };
206 :
207 35848 : return res;
208 : }
209 :
210 :
211 : /**
212 : * Function called to convert input argument into SQL parameters.
213 : *
214 : * @param cls closure
215 : * @param data pointer to input argument
216 : * @param data_len number of bytes in @a data (if applicable)
217 : * @param[out] param_values SQL data to set
218 : * @param[out] param_lengths SQL length data to set
219 : * @param[out] param_formats SQL format data to set
220 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
221 : * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
222 : * @param scratch_length number of entries left in @a scratch
223 : * @return -1 on error, number of offsets used in @a scratch otherwise
224 : */
225 : static int
226 6668 : qconv_denom_pub (void *cls,
227 : const void *data,
228 : size_t data_len,
229 : void *param_values[],
230 : int param_lengths[],
231 : int param_formats[],
232 : unsigned int param_length,
233 : void *scratch[],
234 : unsigned int scratch_length)
235 : {
236 6668 : const struct TALER_DenominationPublicKey *denom_pub = data;
237 6668 : const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp = denom_pub->bsign_pub_key;
238 : size_t tlen;
239 : size_t len;
240 : uint32_t be[2];
241 : char *buf;
242 : void *tbuf;
243 :
244 : (void) cls;
245 : (void) data_len;
246 6668 : GNUNET_assert (1 == param_length);
247 6668 : GNUNET_assert (scratch_length > 0);
248 6668 : GNUNET_break (NULL == cls);
249 6668 : be[0] = htonl ((uint32_t) bsp->cipher);
250 6668 : be[1] = htonl (denom_pub->age_mask.bits);
251 6668 : switch (bsp->cipher)
252 : {
253 4006 : case GNUNET_CRYPTO_BSA_RSA:
254 4006 : tlen = GNUNET_CRYPTO_rsa_public_key_encode (
255 4006 : bsp->details.rsa_public_key,
256 : &tbuf);
257 4006 : break;
258 2662 : case GNUNET_CRYPTO_BSA_CS:
259 2662 : tlen = sizeof (bsp->details.cs_public_key);
260 2662 : break;
261 0 : default:
262 0 : GNUNET_assert (0);
263 : }
264 6668 : len = tlen + sizeof (be);
265 6668 : buf = GNUNET_malloc (len);
266 6668 : GNUNET_memcpy (buf,
267 : be,
268 : sizeof (be));
269 6668 : switch (bsp->cipher)
270 : {
271 4006 : case GNUNET_CRYPTO_BSA_RSA:
272 4006 : GNUNET_memcpy (&buf[sizeof (be)],
273 : tbuf,
274 : tlen);
275 4006 : GNUNET_free (tbuf);
276 4006 : break;
277 2662 : case GNUNET_CRYPTO_BSA_CS:
278 2662 : GNUNET_memcpy (&buf[sizeof (be)],
279 : &bsp->details.cs_public_key,
280 : tlen);
281 2662 : break;
282 0 : default:
283 0 : GNUNET_assert (0);
284 : }
285 :
286 6668 : scratch[0] = buf;
287 6668 : param_values[0] = (void *) buf;
288 6668 : param_lengths[0] = len;
289 6668 : param_formats[0] = 1;
290 6668 : return 1;
291 : }
292 :
293 :
294 : struct GNUNET_PQ_QueryParam
295 6668 : TALER_PQ_query_param_denom_pub (
296 : const struct TALER_DenominationPublicKey *denom_pub)
297 : {
298 6668 : struct GNUNET_PQ_QueryParam res = {
299 : .conv = &qconv_denom_pub,
300 : .data = denom_pub,
301 : .num_params = 1
302 : };
303 :
304 6668 : return res;
305 : }
306 :
307 :
308 : struct GNUNET_PQ_QueryParam
309 186 : TALER_PQ_query_param_denom_sig (
310 : const struct TALER_DenominationSignature *denom_sig)
311 : {
312 186 : return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig);
313 : }
314 :
315 :
316 : struct GNUNET_PQ_QueryParam
317 0 : TALER_PQ_query_param_blinded_denom_sig (
318 : const struct TALER_BlindedDenominationSignature *denom_sig)
319 : {
320 0 : return GNUNET_PQ_query_param_blinded_sig (denom_sig->blinded_sig);
321 : }
322 :
323 :
324 : /**
325 : * Function called to convert input argument into SQL parameters.
326 : *
327 : * @param cls closure
328 : * @param data pointer to input argument
329 : * @param data_len number of bytes in @a data (if applicable)
330 : * @param[out] param_values SQL data to set
331 : * @param[out] param_lengths SQL length data to set
332 : * @param[out] param_formats SQL format data to set
333 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
334 : * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
335 : * @param scratch_length number of entries left in @a scratch
336 : * @return -1 on error, number of offsets used in @a scratch otherwise
337 : */
338 : static int
339 0 : qconv_blinded_planchet (void *cls,
340 : const void *data,
341 : size_t data_len,
342 : void *param_values[],
343 : int param_lengths[],
344 : int param_formats[],
345 : unsigned int param_length,
346 : void *scratch[],
347 : unsigned int scratch_length)
348 : {
349 0 : const struct TALER_BlindedPlanchet *bp = data;
350 0 : const struct GNUNET_CRYPTO_BlindedMessage *bm = bp->blinded_message;
351 : size_t tlen;
352 : size_t len;
353 : uint32_t be[2];
354 : char *buf;
355 :
356 : (void) cls;
357 : (void) data_len;
358 0 : GNUNET_assert (1 == param_length);
359 0 : GNUNET_assert (scratch_length > 0);
360 0 : GNUNET_break (NULL == cls);
361 0 : be[0] = htonl ((uint32_t) bm->cipher);
362 0 : be[1] = htonl (0x0100); /* magic marker: blinded */
363 0 : switch (bm->cipher)
364 : {
365 0 : case GNUNET_CRYPTO_BSA_RSA:
366 0 : tlen = bm->details.rsa_blinded_message.blinded_msg_size;
367 0 : break;
368 0 : case GNUNET_CRYPTO_BSA_CS:
369 0 : tlen = sizeof (bm->details.cs_blinded_message);
370 0 : break;
371 0 : default:
372 0 : GNUNET_assert (0);
373 : }
374 0 : len = tlen + sizeof (be);
375 0 : buf = GNUNET_malloc (len);
376 0 : GNUNET_memcpy (buf,
377 : &be,
378 : sizeof (be));
379 0 : switch (bm->cipher)
380 : {
381 0 : case GNUNET_CRYPTO_BSA_RSA:
382 0 : GNUNET_memcpy (&buf[sizeof (be)],
383 : bm->details.rsa_blinded_message.blinded_msg,
384 : tlen);
385 0 : break;
386 0 : case GNUNET_CRYPTO_BSA_CS:
387 0 : GNUNET_memcpy (&buf[sizeof (be)],
388 : &bm->details.cs_blinded_message,
389 : tlen);
390 0 : break;
391 0 : default:
392 0 : GNUNET_assert (0);
393 : }
394 0 : scratch[0] = buf;
395 0 : param_values[0] = (void *) buf;
396 0 : param_lengths[0] = len;
397 0 : param_formats[0] = 1;
398 0 : return 1;
399 : }
400 :
401 :
402 : struct GNUNET_PQ_QueryParam
403 0 : TALER_PQ_query_param_blinded_planchet (
404 : const struct TALER_BlindedPlanchet *bp)
405 : {
406 0 : struct GNUNET_PQ_QueryParam res = {
407 : .conv = &qconv_blinded_planchet,
408 : .data = bp,
409 : .num_params = 1
410 : };
411 :
412 0 : return res;
413 : }
414 :
415 :
416 : /**
417 : * Function called to convert input argument into SQL parameters.
418 : *
419 : * @param cls closure
420 : * @param data pointer to input argument
421 : * @param data_len number of bytes in @a data (if applicable)
422 : * @param[out] param_values SQL data to set
423 : * @param[out] param_lengths SQL length data to set
424 : * @param[out] param_formats SQL format data to set
425 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
426 : * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
427 : * @param scratch_length number of entries left in @a scratch
428 : * @return -1 on error, number of offsets used in @a scratch otherwise
429 : */
430 : static int
431 0 : qconv_exchange_blinding_values (void *cls,
432 : const void *data,
433 : size_t data_len,
434 : void *param_values[],
435 : int param_lengths[],
436 : int param_formats[],
437 : unsigned int param_length,
438 : void *scratch[],
439 : unsigned int scratch_length)
440 : {
441 0 : const struct TALER_ExchangeBlindingValues *blinding_values = data;
442 0 : const struct GNUNET_CRYPTO_BlindingInputValues *bi =
443 : blinding_values->blinding_inputs;
444 : size_t tlen;
445 : size_t len;
446 : uint32_t be[2];
447 : char *buf;
448 :
449 : (void) cls;
450 : (void) data_len;
451 0 : GNUNET_assert (1 == param_length);
452 0 : GNUNET_assert (scratch_length > 0);
453 0 : GNUNET_break (NULL == cls);
454 0 : be[0] = htonl ((uint32_t) bi->cipher);
455 0 : be[1] = htonl (0x010000); /* magic marker: EWV */
456 0 : switch (bi->cipher)
457 : {
458 0 : case GNUNET_CRYPTO_BSA_RSA:
459 0 : tlen = 0;
460 0 : break;
461 0 : case GNUNET_CRYPTO_BSA_CS:
462 0 : tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP);
463 0 : break;
464 0 : default:
465 0 : GNUNET_assert (0);
466 : }
467 0 : len = tlen + sizeof (be);
468 0 : buf = GNUNET_malloc (len);
469 0 : GNUNET_memcpy (buf,
470 : &be,
471 : sizeof (be));
472 0 : switch (bi->cipher)
473 : {
474 0 : case GNUNET_CRYPTO_BSA_RSA:
475 0 : break;
476 0 : case GNUNET_CRYPTO_BSA_CS:
477 0 : GNUNET_memcpy (&buf[sizeof (be)],
478 : &bi->details.cs_values,
479 : tlen);
480 0 : break;
481 0 : default:
482 0 : GNUNET_assert (0);
483 : }
484 0 : scratch[0] = buf;
485 0 : param_values[0] = (void *) buf;
486 0 : param_lengths[0] = len;
487 0 : param_formats[0] = 1;
488 0 : return 1;
489 : }
490 :
491 :
492 : struct GNUNET_PQ_QueryParam
493 0 : TALER_PQ_query_param_exchange_blinding_values (
494 : const struct TALER_ExchangeBlindingValues *blinding_values)
495 : {
496 0 : struct GNUNET_PQ_QueryParam res = {
497 : .conv = &qconv_exchange_blinding_values,
498 : .data = blinding_values,
499 : .num_params = 1
500 : };
501 :
502 0 : return res;
503 : }
504 :
505 :
506 : /**
507 : * Function called to convert input argument into SQL parameters.
508 : *
509 : * @param cls closure
510 : * @param data pointer to input argument, here a `json_t *`
511 : * @param data_len number of bytes in @a data (if applicable)
512 : * @param[out] param_values SQL data to set
513 : * @param[out] param_lengths SQL length data to set
514 : * @param[out] param_formats SQL format data to set
515 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
516 : * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc()
517 : * @param scratch_length number of entries left in @a scratch
518 : * @return -1 on error, number of offsets used in @a scratch otherwise
519 : */
520 : static int
521 122 : qconv_json (void *cls,
522 : const void *data,
523 : size_t data_len,
524 : void *param_values[],
525 : int param_lengths[],
526 : int param_formats[],
527 : unsigned int param_length,
528 : void *scratch[],
529 : unsigned int scratch_length)
530 : {
531 122 : const json_t *json = data;
532 : char *str;
533 :
534 : (void) cls;
535 : (void) data_len;
536 122 : GNUNET_assert (1 == param_length);
537 122 : GNUNET_assert (scratch_length > 0);
538 122 : str = json_dumps (json,
539 : JSON_COMPACT);
540 122 : if (NULL == str)
541 : {
542 0 : GNUNET_break (0);
543 0 : return -1;
544 : }
545 122 : scratch[0] = str;
546 122 : param_values[0] = (void *) str;
547 122 : param_lengths[0] = strlen (str);
548 122 : param_formats[0] = 1;
549 122 : return 1;
550 : }
551 :
552 :
553 : struct GNUNET_PQ_QueryParam
554 116 : TALER_PQ_query_param_json (const json_t *x)
555 : {
556 116 : struct GNUNET_PQ_QueryParam res = {
557 : .conv = &qconv_json,
558 : .data = x,
559 : .num_params = 1
560 : };
561 :
562 116 : return res;
563 : }
564 :
565 :
566 : /** ------------------- Array support -----------------------------------**/
567 :
568 : /**
569 : * Closure for the array type handlers.
570 : *
571 : * May contain sizes information for the data, given (and handled) by the
572 : * caller.
573 : */
574 : struct qconv_array_cls
575 : {
576 : /**
577 : * If not null, contains the array of sizes (the size of the array is the
578 : * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free
579 : * this memory.
580 : *
581 : * If not null, this value has precedence over @a sizes, which MUST be NULL */
582 : const size_t *sizes;
583 :
584 : /**
585 : * If @a size and @a c_sizes are NULL, this field defines the same size
586 : * for each element in the array.
587 : */
588 : size_t same_size;
589 :
590 : /**
591 : * If true, the array parameter to the data pointer to the qconv_array is a
592 : * continuous byte array of data, either with @a same_size each or sizes
593 : * provided bytes by @a sizes;
594 : */
595 : bool continuous;
596 :
597 : /**
598 : * Type of the array elements
599 : */
600 : enum TALER_PQ_ArrayType typ;
601 :
602 : /**
603 : * Oid of the array elements
604 : */
605 : Oid oid;
606 :
607 : /**
608 : * db context, needed for OID-lookup of basis-types
609 : */
610 : struct GNUNET_PQ_Context *db;
611 : };
612 :
613 : /**
614 : * Callback to cleanup a qconv_array_cls to be used during
615 : * GNUNET_PQ_cleanup_query_params_closures
616 : */
617 : static void
618 1233 : qconv_array_cls_cleanup (void *cls)
619 : {
620 1233 : GNUNET_free (cls);
621 1233 : }
622 :
623 :
624 : /**
625 : * Function called to convert input argument into SQL parameters for arrays
626 : *
627 : * Note: the format for the encoding of arrays for libpq is not very well
628 : * documented. We peeked into various sources (postgresql and libpqtypes) for
629 : * guidance.
630 : *
631 : * @param cls Closure of type struct qconv_array_cls*
632 : * @param data Pointer to first element in the array
633 : * @param data_len Number of _elements_ in array @a data (if applicable)
634 : * @param[out] param_values SQL data to set
635 : * @param[out] param_lengths SQL length data to set
636 : * @param[out] param_formats SQL format data to set
637 : * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
638 : * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
639 : * @param scratch_length number of entries left in @a scratch
640 : * @return -1 on error, number of offsets used in @a scratch otherwise
641 : */
642 : static int
643 1240 : qconv_array (
644 : void *cls,
645 : const void *data,
646 : size_t data_len,
647 : void *param_values[],
648 : int param_lengths[],
649 : int param_formats[],
650 : unsigned int param_length,
651 : void *scratch[],
652 : unsigned int scratch_length)
653 : {
654 1240 : struct qconv_array_cls *meta = cls;
655 1240 : size_t num = data_len;
656 : size_t total_size;
657 : const size_t *sizes;
658 : bool same_sized;
659 1240 : void *elements = NULL;
660 1240 : bool noerror = true;
661 : /* needed to capture the encoded rsa signatures */
662 1240 : void **buffers = NULL;
663 1240 : size_t *buffer_lengths = NULL;
664 :
665 : (void) (param_length);
666 : (void) (scratch_length);
667 :
668 1240 : GNUNET_assert (NULL != meta);
669 1240 : GNUNET_assert (num < INT_MAX);
670 :
671 1240 : sizes = meta->sizes;
672 1240 : same_sized = (0 != meta->same_size);
673 :
674 : #define RETURN_UNLESS(cond) \
675 : do { \
676 : if (! (cond)) \
677 : { \
678 : GNUNET_break ((cond)); \
679 : noerror = false; \
680 : goto DONE; \
681 : } \
682 : } while (0)
683 :
684 : /* Calculate sizes and check bounds */
685 : {
686 : /* num * length-field */
687 1240 : size_t x = sizeof(uint32_t);
688 1240 : size_t y = x * num;
689 1240 : RETURN_UNLESS ((0 == num) || (y / num == x));
690 :
691 : /* size of header */
692 1240 : total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P);
693 1240 : total_size += y;
694 1240 : RETURN_UNLESS (total_size >= x);
695 :
696 : /* sizes of elements */
697 1240 : if (same_sized)
698 : {
699 1122 : x = num * meta->same_size;
700 1122 : RETURN_UNLESS ((0 == num) || (x / num == meta->same_size));
701 :
702 1122 : y = total_size;
703 1122 : total_size += x;
704 1122 : RETURN_UNLESS (total_size >= y);
705 : }
706 : else /* sizes are different per element */
707 : {
708 118 : switch (meta->typ)
709 : {
710 0 : case TALER_PQ_array_of_amount_currency:
711 : {
712 0 : const struct TALER_Amount *amounts = data;
713 : Oid oid_v;
714 : Oid oid_f;
715 : Oid oid_c;
716 :
717 0 : buffer_lengths = GNUNET_new_array (num, size_t);
718 : /* hoist out of loop? */
719 0 : GNUNET_assert (GNUNET_OK ==
720 : GNUNET_PQ_get_oid_by_name (meta->db,
721 : "int8",
722 : &oid_v));
723 0 : GNUNET_assert (GNUNET_OK ==
724 : GNUNET_PQ_get_oid_by_name (meta->db,
725 : "int4",
726 : &oid_f));
727 0 : GNUNET_assert (GNUNET_OK ==
728 : GNUNET_PQ_get_oid_by_name (meta->db,
729 : "varchar",
730 : &oid_c));
731 0 : for (size_t i = 0; i<num; i++)
732 : {
733 : struct TALER_PQ_AmountCurrencyP am;
734 : size_t len;
735 :
736 0 : len = TALER_PQ_make_taler_pq_amount_currency_ (
737 0 : &amounts[i],
738 : oid_v,
739 : oid_f,
740 : oid_c,
741 : &am);
742 0 : buffer_lengths[i] = len;
743 0 : y = total_size;
744 0 : total_size += len;
745 0 : RETURN_UNLESS (total_size >= y);
746 : }
747 0 : sizes = buffer_lengths;
748 0 : break;
749 : }
750 118 : case TALER_PQ_array_of_blinded_denom_sig:
751 : {
752 118 : const struct TALER_BlindedDenominationSignature *denom_sigs = data;
753 : size_t len;
754 :
755 118 : buffers = GNUNET_new_array (num, void *);
756 118 : buffer_lengths = GNUNET_new_array (num, size_t);
757 :
758 521 : for (size_t i = 0; i<num; i++)
759 : {
760 403 : const struct GNUNET_CRYPTO_BlindedSignature *bs =
761 403 : denom_sigs[i].blinded_sig;
762 :
763 403 : switch (bs->cipher)
764 : {
765 306 : case GNUNET_CRYPTO_BSA_RSA:
766 306 : len = GNUNET_CRYPTO_rsa_signature_encode (
767 306 : bs->details.blinded_rsa_signature,
768 306 : &buffers[i]);
769 306 : RETURN_UNLESS (len != 0);
770 306 : break;
771 97 : case GNUNET_CRYPTO_BSA_CS:
772 97 : len = sizeof (bs->details.blinded_cs_answer);
773 97 : break;
774 0 : default:
775 0 : GNUNET_assert (0);
776 : }
777 :
778 : /* for the cipher and marker */
779 403 : len += 2 * sizeof(uint32_t);
780 403 : buffer_lengths[i] = len;
781 :
782 403 : y = total_size;
783 403 : total_size += len;
784 403 : RETURN_UNLESS (total_size >= y);
785 : }
786 118 : sizes = buffer_lengths;
787 118 : break;
788 : }
789 0 : default:
790 0 : GNUNET_assert (0);
791 : }
792 : }
793 :
794 1240 : RETURN_UNLESS (INT_MAX > total_size);
795 1240 : RETURN_UNLESS (0 != total_size);
796 :
797 1240 : elements = GNUNET_malloc (total_size);
798 : }
799 :
800 : /* Write data */
801 : {
802 1240 : char *out = elements;
803 1240 : struct GNUNET_PQ_ArrayHeader_P h = {
804 1240 : .ndim = htonl (1), /* We only support one-dimensional arrays */
805 1240 : .has_null = htonl (0), /* We do not support NULL entries in arrays */
806 1240 : .lbound = htonl (1), /* Default start index value */
807 1240 : .dim = htonl (num),
808 1240 : .oid = htonl (meta->oid),
809 : };
810 :
811 : /* Write header */
812 1240 : GNUNET_memcpy (out,
813 : &h,
814 : sizeof(h));
815 1240 : out += sizeof(h);
816 :
817 : /* Write elements */
818 8784 : for (size_t i = 0; i < num; i++)
819 : {
820 7544 : size_t sz = same_sized ? meta->same_size : sizes[i];
821 :
822 7544 : *(uint32_t *) out = htonl (sz);
823 7544 : out += sizeof(uint32_t);
824 7544 : switch (meta->typ)
825 : {
826 7037 : case TALER_PQ_array_of_amount:
827 : {
828 7037 : const struct TALER_Amount *amounts = data;
829 : Oid oid_v;
830 : Oid oid_f;
831 :
832 : /* hoist out of loop? */
833 7037 : GNUNET_assert (GNUNET_OK ==
834 : GNUNET_PQ_get_oid_by_name (meta->db,
835 : "int8",
836 : &oid_v));
837 7037 : GNUNET_assert (GNUNET_OK ==
838 : GNUNET_PQ_get_oid_by_name (meta->db,
839 : "int4",
840 : &oid_f));
841 : {
842 : struct TALER_PQ_AmountP am
843 7037 : = TALER_PQ_make_taler_pq_amount_ (
844 7037 : &amounts[i],
845 : oid_v,
846 : oid_f);
847 :
848 7037 : GNUNET_memcpy (out,
849 : &am,
850 : sizeof(am));
851 : }
852 7037 : break;
853 : }
854 0 : case TALER_PQ_array_of_amount_currency:
855 : {
856 0 : const struct TALER_Amount *amounts = data;
857 : Oid oid_v;
858 : Oid oid_f;
859 : Oid oid_c;
860 :
861 : /* hoist out of loop? */
862 0 : GNUNET_assert (GNUNET_OK ==
863 : GNUNET_PQ_get_oid_by_name (meta->db,
864 : "int8",
865 : &oid_v));
866 0 : GNUNET_assert (GNUNET_OK ==
867 : GNUNET_PQ_get_oid_by_name (meta->db,
868 : "int4",
869 : &oid_f));
870 0 : GNUNET_assert (GNUNET_OK ==
871 : GNUNET_PQ_get_oid_by_name (meta->db,
872 : "varchar",
873 : &oid_c));
874 : {
875 : struct TALER_PQ_AmountCurrencyP am;
876 : size_t len;
877 :
878 0 : len = TALER_PQ_make_taler_pq_amount_currency_ (
879 0 : &amounts[i],
880 : oid_v,
881 : oid_f,
882 : oid_c,
883 : &am);
884 0 : GNUNET_memcpy (out,
885 : &am,
886 : len);
887 : }
888 0 : break;
889 : }
890 403 : case TALER_PQ_array_of_blinded_denom_sig:
891 : {
892 403 : const struct TALER_BlindedDenominationSignature *denom_sigs = data;
893 403 : const struct GNUNET_CRYPTO_BlindedSignature *bs =
894 403 : denom_sigs[i].blinded_sig;
895 : uint32_t be[2];
896 :
897 403 : be[0] = htonl ((uint32_t) bs->cipher);
898 403 : be[1] = htonl (0x01); /* magic margker: blinded */
899 403 : GNUNET_memcpy (out,
900 : &be,
901 : sizeof(be));
902 403 : out += sizeof(be);
903 403 : sz -= sizeof(be);
904 :
905 403 : switch (bs->cipher)
906 : {
907 306 : case GNUNET_CRYPTO_BSA_RSA:
908 : /* For RSA, 'same_sized' must have been false */
909 306 : GNUNET_assert (NULL != buffers);
910 306 : GNUNET_memcpy (out,
911 : buffers[i],
912 : sz);
913 306 : break;
914 97 : case GNUNET_CRYPTO_BSA_CS:
915 97 : GNUNET_memcpy (out,
916 : &bs->details.blinded_cs_answer,
917 : sz);
918 97 : break;
919 0 : default:
920 0 : GNUNET_assert (0);
921 : }
922 403 : break;
923 : }
924 0 : case TALER_PQ_array_of_blinded_coin_hash:
925 : {
926 0 : const struct TALER_BlindedCoinHashP *coin_hs = data;
927 :
928 0 : GNUNET_memcpy (out,
929 : &coin_hs[i],
930 : sizeof(struct TALER_BlindedCoinHashP));
931 :
932 0 : break;
933 : }
934 0 : case TALER_PQ_array_of_denom_hash:
935 : {
936 0 : const struct TALER_DenominationHashP *denom_hs = data;
937 :
938 0 : GNUNET_memcpy (out,
939 : &denom_hs[i],
940 : sizeof(struct TALER_DenominationHashP));
941 0 : break;
942 : }
943 2 : case TALER_PQ_array_of_hash_code:
944 : {
945 2 : const struct GNUNET_HashCode *hashes = data;
946 :
947 2 : GNUNET_memcpy (out,
948 : &hashes[i],
949 : sizeof(struct GNUNET_HashCode));
950 2 : break;
951 : }
952 102 : case TALER_PQ_array_of_cs_r_pub:
953 : {
954 102 : const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data;
955 :
956 102 : GNUNET_memcpy (out,
957 : &cs_r_pubs[i],
958 : sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
959 102 : break;
960 : }
961 0 : default:
962 : {
963 0 : GNUNET_assert (0);
964 : break;
965 : }
966 : }
967 7544 : out += sz;
968 : }
969 : }
970 1240 : param_values[0] = elements;
971 1240 : param_lengths[0] = total_size;
972 1240 : param_formats[0] = 1;
973 1240 : scratch[0] = elements;
974 :
975 1240 : DONE:
976 1240 : if (NULL != buffers)
977 : {
978 521 : for (size_t i = 0; i<num; i++)
979 403 : GNUNET_free (buffers[i]);
980 118 : GNUNET_free (buffers);
981 : }
982 1240 : GNUNET_free (buffer_lengths);
983 1240 : if (noerror)
984 1240 : return 1;
985 0 : return -1;
986 : }
987 :
988 :
989 : /**
990 : * Function to generate a typ specific query parameter and corresponding closure
991 : *
992 : * @param num Number of elements in @a elements
993 : * @param continuous If true, @a elements is an continuous array of data
994 : * @param elements Array of @a num elements, either continuous or pointers
995 : * @param sizes Array of @a num sizes, one per element, may be NULL
996 : * @param same_size If not 0, all elements in @a elements have this size
997 : * @param typ Supported internal type of each element in @a elements
998 : * @param oid Oid of the type to be used in Postgres
999 : * @param[in,out] db our database handle for looking up OIDs
1000 : * @return Query parameter
1001 : */
1002 : static struct GNUNET_PQ_QueryParam
1003 1240 : query_param_array_generic (
1004 : unsigned int num,
1005 : bool continuous,
1006 : const void *elements,
1007 : const size_t *sizes,
1008 : size_t same_size,
1009 : enum TALER_PQ_ArrayType typ,
1010 : Oid oid,
1011 : struct GNUNET_PQ_Context *db)
1012 : {
1013 1240 : struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls);
1014 :
1015 1240 : meta->typ = typ;
1016 1240 : meta->oid = oid;
1017 1240 : meta->sizes = sizes;
1018 1240 : meta->same_size = same_size;
1019 1240 : meta->continuous = continuous;
1020 1240 : meta->db = db;
1021 :
1022 : {
1023 1240 : struct GNUNET_PQ_QueryParam res = {
1024 : .conv = qconv_array,
1025 : .conv_cls = meta,
1026 : .conv_cls_cleanup = qconv_array_cls_cleanup,
1027 : .data = elements,
1028 : .size = num,
1029 : .num_params = 1,
1030 : };
1031 :
1032 1240 : return res;
1033 : }
1034 : }
1035 :
1036 :
1037 : struct GNUNET_PQ_QueryParam
1038 118 : TALER_PQ_query_param_array_blinded_denom_sig (
1039 : size_t num,
1040 : const struct TALER_BlindedDenominationSignature *denom_sigs,
1041 : struct GNUNET_PQ_Context *db)
1042 : {
1043 : Oid oid;
1044 :
1045 118 : GNUNET_assert (GNUNET_OK ==
1046 : GNUNET_PQ_get_oid_by_name (db,
1047 : "bytea",
1048 : &oid));
1049 118 : return query_param_array_generic (num,
1050 : true,
1051 : denom_sigs,
1052 : NULL,
1053 : 0,
1054 : TALER_PQ_array_of_blinded_denom_sig,
1055 : oid,
1056 : NULL);
1057 : }
1058 :
1059 :
1060 : struct GNUNET_PQ_QueryParam
1061 0 : TALER_PQ_query_param_array_blinded_coin_hash (
1062 : size_t num,
1063 : const struct TALER_BlindedCoinHashP *coin_hs,
1064 : struct GNUNET_PQ_Context *db)
1065 : {
1066 : Oid oid;
1067 :
1068 0 : GNUNET_assert (GNUNET_OK ==
1069 : GNUNET_PQ_get_oid_by_name (db,
1070 : "bytea",
1071 : &oid));
1072 0 : return query_param_array_generic (num,
1073 : true,
1074 : coin_hs,
1075 : NULL,
1076 : sizeof(struct TALER_BlindedCoinHashP),
1077 : TALER_PQ_array_of_blinded_coin_hash,
1078 : oid,
1079 : NULL);
1080 : }
1081 :
1082 :
1083 : struct GNUNET_PQ_QueryParam
1084 0 : TALER_PQ_query_param_array_denom_hash (
1085 : size_t num,
1086 : const struct TALER_DenominationHashP *denom_hs,
1087 : struct GNUNET_PQ_Context *db)
1088 : {
1089 : Oid oid;
1090 :
1091 0 : GNUNET_assert (GNUNET_OK ==
1092 : GNUNET_PQ_get_oid_by_name (db,
1093 : "bytea",
1094 : &oid));
1095 0 : return query_param_array_generic (num,
1096 : true,
1097 : denom_hs,
1098 : NULL,
1099 : sizeof(struct TALER_DenominationHashP),
1100 : TALER_PQ_array_of_denom_hash,
1101 : oid,
1102 : NULL);
1103 : }
1104 :
1105 :
1106 : struct GNUNET_PQ_QueryParam
1107 1 : TALER_PQ_query_param_array_hash_code (
1108 : size_t num,
1109 : const struct GNUNET_HashCode *hashes,
1110 : struct GNUNET_PQ_Context *db)
1111 : {
1112 : Oid oid;
1113 1 : GNUNET_assert (GNUNET_OK ==
1114 : GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid));
1115 1 : return query_param_array_generic (num,
1116 : true,
1117 : hashes,
1118 : NULL,
1119 : sizeof(struct GNUNET_HashCode),
1120 : TALER_PQ_array_of_hash_code,
1121 : oid,
1122 : NULL);
1123 : }
1124 :
1125 :
1126 : struct GNUNET_PQ_QueryParam
1127 1071 : TALER_PQ_query_param_array_amount (
1128 : size_t num,
1129 : const struct TALER_Amount *amounts,
1130 : struct GNUNET_PQ_Context *db)
1131 : {
1132 : Oid oid;
1133 :
1134 1071 : GNUNET_assert (GNUNET_OK ==
1135 : GNUNET_PQ_get_oid_by_name (db,
1136 : "taler_amount",
1137 : &oid));
1138 1071 : return query_param_array_generic (
1139 : num,
1140 : true,
1141 : amounts,
1142 : NULL,
1143 : sizeof(struct TALER_PQ_AmountP),
1144 : TALER_PQ_array_of_amount,
1145 : oid,
1146 : db);
1147 : }
1148 :
1149 :
1150 : struct GNUNET_PQ_QueryParam
1151 0 : TALER_PQ_query_param_array_amount_with_currency (
1152 : size_t num,
1153 : const struct TALER_Amount *amounts,
1154 : struct GNUNET_PQ_Context *db)
1155 : {
1156 : Oid oid;
1157 :
1158 0 : GNUNET_assert (GNUNET_OK ==
1159 : GNUNET_PQ_get_oid_by_name (db,
1160 : "taler_amount_currency",
1161 : &oid));
1162 0 : return query_param_array_generic (
1163 : num,
1164 : true,
1165 : amounts,
1166 : NULL,
1167 : 0, /* currency is technically variable length */
1168 : TALER_PQ_array_of_amount_currency,
1169 : oid,
1170 : db);
1171 : }
1172 :
1173 :
1174 : struct GNUNET_PQ_QueryParam
1175 50 : TALER_PQ_query_param_array_cs_r_pub (
1176 : size_t num,
1177 : const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs,
1178 : struct GNUNET_PQ_Context *db)
1179 : {
1180 : Oid oid;
1181 :
1182 50 : GNUNET_assert (GNUNET_OK ==
1183 : GNUNET_PQ_get_oid_by_name (db,
1184 : "bytea",
1185 : &oid));
1186 50 : return query_param_array_generic (
1187 : num,
1188 : true,
1189 : cs_r_pubs,
1190 : NULL,
1191 : sizeof(struct GNUNET_CRYPTO_CSPublicRPairP),
1192 : TALER_PQ_array_of_cs_r_pub,
1193 : oid,
1194 : db);
1195 : }
1196 :
1197 :
1198 : /* end of pq/pq_query_helper.c */
|