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