pq_query_helper.c (34984B)
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 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 struct GNUNET_PQ_Context *db = cls; 56 const struct TALER_Amount *amount = data; 57 size_t sz; 58 59 GNUNET_assert (NULL != db); 60 GNUNET_assert (NULL != amount); 61 GNUNET_assert (1 == param_length); 62 GNUNET_assert (1 <= scratch_length); 63 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 GNUNET_assert (GNUNET_OK == 73 GNUNET_PQ_get_oid_by_name (db, 74 "int8", 75 &oid_v)); 76 GNUNET_assert (GNUNET_OK == 77 GNUNET_PQ_get_oid_by_name (db, 78 "int4", 79 &oid_f)); 80 GNUNET_assert (GNUNET_OK == 81 GNUNET_PQ_get_oid_by_name (db, 82 "varchar", 83 &oid_c)); 84 sz = TALER_PQ_make_taler_pq_amount_currency_ (amount, 85 oid_v, 86 oid_f, 87 oid_c, 88 &d); 89 out = GNUNET_malloc (sz); 90 memcpy (out, 91 &d, 92 sz); 93 scratch[0] = out; 94 } 95 96 param_values[0] = scratch[0]; 97 param_lengths[0] = sz; 98 param_formats[0] = 1; 99 100 return 1; 101 } 102 103 104 struct GNUNET_PQ_QueryParam 105 TALER_PQ_query_param_amount_with_currency ( 106 const struct GNUNET_PQ_Context *db, 107 const struct TALER_Amount *amount) 108 { 109 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 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 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 struct GNUNET_PQ_Context *db = cls; 147 const struct TALER_Amount *amount = data; 148 size_t sz; 149 150 GNUNET_assert (NULL != db); 151 GNUNET_assert (NULL != amount); 152 GNUNET_assert (1 == param_length); 153 GNUNET_assert (1 <= scratch_length); 154 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 GNUNET_assert (GNUNET_OK == 162 GNUNET_PQ_get_oid_by_name (db, 163 "int8", 164 &oid_v)); 165 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 = TALER_PQ_make_taler_pq_amount_ (amount, 173 oid_v, 174 oid_f); 175 176 sz = sizeof(d); 177 out = GNUNET_malloc (sz); 178 scratch[0] = out; 179 GNUNET_memcpy (out, 180 &d, 181 sizeof(d)); 182 } 183 } 184 185 param_values[0] = scratch[0]; 186 param_lengths[0] = sz; 187 param_formats[0] = 1; 188 189 return 1; 190 } 191 192 193 struct GNUNET_PQ_QueryParam 194 TALER_PQ_query_param_amount ( 195 const struct GNUNET_PQ_Context *db, 196 const struct TALER_Amount *amount) 197 { 198 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 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 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 const struct TALER_DenominationPublicKey *denom_pub = data; 236 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 GNUNET_assert (1 == param_length); 246 GNUNET_assert (scratch_length > 0); 247 GNUNET_break (NULL == cls); 248 be[0] = htonl ((uint32_t) bsp->cipher); 249 be[1] = htonl (denom_pub->age_mask.bits); 250 switch (bsp->cipher) 251 { 252 case GNUNET_CRYPTO_BSA_RSA: 253 tlen = GNUNET_CRYPTO_rsa_public_key_encode ( 254 bsp->details.rsa_public_key, 255 &tbuf); 256 break; 257 case GNUNET_CRYPTO_BSA_CS: 258 tlen = sizeof (bsp->details.cs_public_key); 259 break; 260 default: 261 GNUNET_assert (0); 262 } 263 len = tlen + sizeof (be); 264 buf = GNUNET_malloc (len); 265 GNUNET_memcpy (buf, 266 be, 267 sizeof (be)); 268 switch (bsp->cipher) 269 { 270 case GNUNET_CRYPTO_BSA_RSA: 271 GNUNET_memcpy (&buf[sizeof (be)], 272 tbuf, 273 tlen); 274 GNUNET_free (tbuf); 275 break; 276 case GNUNET_CRYPTO_BSA_CS: 277 GNUNET_memcpy (&buf[sizeof (be)], 278 &bsp->details.cs_public_key, 279 tlen); 280 break; 281 default: 282 GNUNET_assert (0); 283 } 284 285 scratch[0] = buf; 286 param_values[0] = (void *) buf; 287 param_lengths[0] = len; 288 param_formats[0] = 1; 289 return 1; 290 } 291 292 293 struct GNUNET_PQ_QueryParam 294 TALER_PQ_query_param_denom_pub ( 295 const struct TALER_DenominationPublicKey *denom_pub) 296 { 297 struct GNUNET_PQ_QueryParam res = { 298 .conv = &qconv_denom_pub, 299 .data = denom_pub, 300 .num_params = 1 301 }; 302 303 return res; 304 } 305 306 307 struct GNUNET_PQ_QueryParam 308 TALER_PQ_query_param_denom_sig ( 309 const struct TALER_DenominationSignature *denom_sig) 310 { 311 return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig); 312 } 313 314 315 struct GNUNET_PQ_QueryParam 316 TALER_PQ_query_param_blinded_denom_sig ( 317 const struct TALER_BlindedDenominationSignature *denom_sig) 318 { 319 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 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 const struct TALER_BlindedPlanchet *bp = data; 349 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 GNUNET_assert (1 == param_length); 358 GNUNET_assert (scratch_length > 0); 359 GNUNET_break (NULL == cls); 360 be[0] = htonl ((uint32_t) bm->cipher); 361 be[1] = htonl (0x0100); /* magic marker: blinded */ 362 switch (bm->cipher) 363 { 364 case GNUNET_CRYPTO_BSA_RSA: 365 tlen = bm->details.rsa_blinded_message.blinded_msg_size; 366 break; 367 case GNUNET_CRYPTO_BSA_CS: 368 tlen = sizeof (bm->details.cs_blinded_message); 369 break; 370 default: 371 GNUNET_assert (0); 372 } 373 len = tlen + sizeof (be); 374 buf = GNUNET_malloc (len); 375 GNUNET_memcpy (buf, 376 &be, 377 sizeof (be)); 378 switch (bm->cipher) 379 { 380 case GNUNET_CRYPTO_BSA_RSA: 381 GNUNET_memcpy (&buf[sizeof (be)], 382 bm->details.rsa_blinded_message.blinded_msg, 383 tlen); 384 break; 385 case GNUNET_CRYPTO_BSA_CS: 386 GNUNET_memcpy (&buf[sizeof (be)], 387 &bm->details.cs_blinded_message, 388 tlen); 389 break; 390 default: 391 GNUNET_assert (0); 392 } 393 scratch[0] = buf; 394 param_values[0] = (void *) buf; 395 param_lengths[0] = len; 396 param_formats[0] = 1; 397 return 1; 398 } 399 400 401 struct GNUNET_PQ_QueryParam 402 TALER_PQ_query_param_blinded_planchet ( 403 const struct TALER_BlindedPlanchet *bp) 404 { 405 struct GNUNET_PQ_QueryParam res = { 406 .conv = &qconv_blinded_planchet, 407 .data = bp, 408 .num_params = 1 409 }; 410 411 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 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 const struct TALER_ExchangeBlindingValues *blinding_values = data; 441 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 GNUNET_assert (1 == param_length); 451 GNUNET_assert (scratch_length > 0); 452 GNUNET_break (NULL == cls); 453 be[0] = htonl ((uint32_t) bi->cipher); 454 be[1] = htonl (0x010000); /* magic marker: EWV */ 455 switch (bi->cipher) 456 { 457 case GNUNET_CRYPTO_BSA_RSA: 458 tlen = 0; 459 break; 460 case GNUNET_CRYPTO_BSA_CS: 461 tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP); 462 break; 463 default: 464 GNUNET_assert (0); 465 } 466 len = tlen + sizeof (be); 467 buf = GNUNET_malloc (len); 468 GNUNET_memcpy (buf, 469 &be, 470 sizeof (be)); 471 switch (bi->cipher) 472 { 473 case GNUNET_CRYPTO_BSA_RSA: 474 break; 475 case GNUNET_CRYPTO_BSA_CS: 476 GNUNET_memcpy (&buf[sizeof (be)], 477 &bi->details.cs_values, 478 tlen); 479 break; 480 default: 481 GNUNET_assert (0); 482 } 483 scratch[0] = buf; 484 param_values[0] = (void *) buf; 485 param_lengths[0] = len; 486 param_formats[0] = 1; 487 return 1; 488 } 489 490 491 struct GNUNET_PQ_QueryParam 492 TALER_PQ_query_param_exchange_blinding_values ( 493 const struct TALER_ExchangeBlindingValues *blinding_values) 494 { 495 struct GNUNET_PQ_QueryParam res = { 496 .conv = &qconv_exchange_blinding_values, 497 .data = blinding_values, 498 .num_params = 1 499 }; 500 501 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 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 const json_t *json = data; 531 char *str; 532 533 (void) cls; 534 (void) data_len; 535 GNUNET_assert (1 == param_length); 536 GNUNET_assert (scratch_length > 0); 537 str = json_dumps (json, 538 JSON_COMPACT); 539 if (NULL == str) 540 { 541 GNUNET_break (0); 542 return -1; 543 } 544 scratch[0] = str; 545 param_values[0] = (void *) str; 546 param_lengths[0] = strlen (str); 547 param_formats[0] = 1; 548 return 1; 549 } 550 551 552 struct GNUNET_PQ_QueryParam 553 TALER_PQ_query_param_json (const json_t *x) 554 { 555 struct GNUNET_PQ_QueryParam res = { 556 .conv = &qconv_json, 557 .data = x, 558 .num_params = 1 559 }; 560 561 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 qconv_array_cls_cleanup (void *cls) 618 { 619 GNUNET_free (cls); 620 } 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 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 struct qconv_array_cls *meta = cls; 654 size_t num = data_len; 655 size_t total_size; 656 const size_t *sizes; 657 bool same_sized; 658 void *elements = NULL; 659 bool noerror = true; 660 /* needed to capture the encoded rsa signatures */ 661 void **buffers = NULL; 662 size_t *buffer_lengths = NULL; 663 664 (void) (param_length); 665 (void) (scratch_length); 666 667 GNUNET_assert (NULL != meta); 668 GNUNET_assert (num < INT_MAX); 669 670 sizes = meta->sizes; 671 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 size_t x = sizeof(uint32_t); 687 size_t y = x * num; 688 RETURN_UNLESS ((0 == num) || (y / num == x)); 689 690 /* size of header */ 691 total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P); 692 total_size += y; 693 RETURN_UNLESS (total_size >= x); 694 695 /* sizes of elements */ 696 if (same_sized) 697 { 698 x = num * meta->same_size; 699 RETURN_UNLESS ((0 == num) || (x / num == meta->same_size)); 700 701 y = total_size; 702 total_size += x; 703 RETURN_UNLESS (total_size >= y); 704 } 705 else /* sizes are different per element */ 706 { 707 switch (meta->typ) 708 { 709 case TALER_PQ_array_of_amount_currency: 710 { 711 const struct TALER_Amount *amounts = data; 712 Oid oid_v; 713 Oid oid_f; 714 Oid oid_c; 715 716 buffer_lengths = GNUNET_new_array (num, size_t); 717 /* hoist out of loop? */ 718 GNUNET_assert (GNUNET_OK == 719 GNUNET_PQ_get_oid_by_name (meta->db, 720 "int8", 721 &oid_v)); 722 GNUNET_assert (GNUNET_OK == 723 GNUNET_PQ_get_oid_by_name (meta->db, 724 "int4", 725 &oid_f)); 726 GNUNET_assert (GNUNET_OK == 727 GNUNET_PQ_get_oid_by_name (meta->db, 728 "varchar", 729 &oid_c)); 730 for (size_t i = 0; i<num; i++) 731 { 732 struct TALER_PQ_AmountCurrencyP am; 733 size_t len; 734 735 len = TALER_PQ_make_taler_pq_amount_currency_ ( 736 &amounts[i], 737 oid_v, 738 oid_f, 739 oid_c, 740 &am); 741 buffer_lengths[i] = len; 742 y = total_size; 743 total_size += len; 744 RETURN_UNLESS (total_size >= y); 745 } 746 sizes = buffer_lengths; 747 break; 748 } 749 case TALER_PQ_array_of_blinded_denom_sig: 750 { 751 const struct TALER_BlindedDenominationSignature *denom_sigs = data; 752 size_t len; 753 754 buffers = GNUNET_new_array (num, void *); 755 buffer_lengths = GNUNET_new_array (num, size_t); 756 757 for (size_t i = 0; i<num; i++) 758 { 759 const struct GNUNET_CRYPTO_BlindedSignature *bs = 760 denom_sigs[i].blinded_sig; 761 762 switch (bs->cipher) 763 { 764 case GNUNET_CRYPTO_BSA_RSA: 765 len = GNUNET_CRYPTO_rsa_signature_encode ( 766 bs->details.blinded_rsa_signature, 767 &buffers[i]); 768 RETURN_UNLESS (len != 0); 769 break; 770 case GNUNET_CRYPTO_BSA_CS: 771 len = sizeof (bs->details.blinded_cs_answer); 772 break; 773 default: 774 GNUNET_assert (0); 775 } 776 777 /* for the cipher and marker */ 778 len += 2 * sizeof(uint32_t); 779 buffer_lengths[i] = len; 780 781 y = total_size; 782 total_size += len; 783 RETURN_UNLESS (total_size >= y); 784 } 785 sizes = buffer_lengths; 786 break; 787 } 788 default: 789 GNUNET_assert (0); 790 } 791 } 792 793 RETURN_UNLESS (INT_MAX > total_size); 794 RETURN_UNLESS (0 != total_size); 795 796 elements = GNUNET_malloc (total_size); 797 } 798 799 /* Write data */ 800 { 801 char *out = elements; 802 struct GNUNET_PQ_ArrayHeader_P h = { 803 .ndim = htonl (1), /* We only support one-dimensional arrays */ 804 .has_null = htonl (0), /* We do not support NULL entries in arrays */ 805 .lbound = htonl (1), /* Default start index value */ 806 .dim = htonl (num), 807 .oid = htonl (meta->oid), 808 }; 809 810 /* Write header */ 811 GNUNET_memcpy (out, 812 &h, 813 sizeof(h)); 814 out += sizeof(h); 815 816 /* Write elements */ 817 for (size_t i = 0; i < num; i++) 818 { 819 size_t sz = same_sized ? meta->same_size : sizes[i]; 820 821 *(uint32_t *) out = htonl (sz); 822 out += sizeof(uint32_t); 823 switch (meta->typ) 824 { 825 case TALER_PQ_array_of_amount: 826 { 827 const struct TALER_Amount *amounts = data; 828 Oid oid_v; 829 Oid oid_f; 830 831 /* hoist out of loop? */ 832 GNUNET_assert (GNUNET_OK == 833 GNUNET_PQ_get_oid_by_name (meta->db, 834 "int8", 835 &oid_v)); 836 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 = TALER_PQ_make_taler_pq_amount_ ( 843 &amounts[i], 844 oid_v, 845 oid_f); 846 847 GNUNET_memcpy (out, 848 &am, 849 sizeof(am)); 850 } 851 break; 852 } 853 case TALER_PQ_array_of_amount_currency: 854 { 855 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 GNUNET_assert (GNUNET_OK == 862 GNUNET_PQ_get_oid_by_name (meta->db, 863 "int8", 864 &oid_v)); 865 GNUNET_assert (GNUNET_OK == 866 GNUNET_PQ_get_oid_by_name (meta->db, 867 "int4", 868 &oid_f)); 869 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 len = TALER_PQ_make_taler_pq_amount_currency_ ( 878 &amounts[i], 879 oid_v, 880 oid_f, 881 oid_c, 882 &am); 883 GNUNET_memcpy (out, 884 &am, 885 len); 886 } 887 break; 888 } 889 case TALER_PQ_array_of_blinded_denom_sig: 890 { 891 const struct TALER_BlindedDenominationSignature *denom_sigs = data; 892 const struct GNUNET_CRYPTO_BlindedSignature *bs = 893 denom_sigs[i].blinded_sig; 894 uint32_t be[2]; 895 896 be[0] = htonl ((uint32_t) bs->cipher); 897 be[1] = htonl (0x01); /* magic margker: blinded */ 898 GNUNET_memcpy (out, 899 &be, 900 sizeof(be)); 901 out += sizeof(be); 902 sz -= sizeof(be); 903 904 switch (bs->cipher) 905 { 906 case GNUNET_CRYPTO_BSA_RSA: 907 /* For RSA, 'same_sized' must have been false */ 908 GNUNET_assert (NULL != buffers); 909 GNUNET_memcpy (out, 910 buffers[i], 911 sz); 912 break; 913 case GNUNET_CRYPTO_BSA_CS: 914 GNUNET_memcpy (out, 915 &bs->details.blinded_cs_answer, 916 sz); 917 break; 918 default: 919 GNUNET_assert (0); 920 } 921 break; 922 } 923 case TALER_PQ_array_of_blinded_coin_hash: 924 { 925 const struct TALER_BlindedCoinHashP *coin_hs = data; 926 927 GNUNET_memcpy (out, 928 &coin_hs[i], 929 sizeof(struct TALER_BlindedCoinHashP)); 930 931 break; 932 } 933 case TALER_PQ_array_of_denom_hash: 934 { 935 const struct TALER_DenominationHashP *denom_hs = data; 936 937 GNUNET_memcpy (out, 938 &denom_hs[i], 939 sizeof(struct TALER_DenominationHashP)); 940 break; 941 } 942 case TALER_PQ_array_of_hash_code: 943 { 944 const struct GNUNET_HashCode *hashes = data; 945 946 GNUNET_memcpy (out, 947 &hashes[i], 948 sizeof(struct GNUNET_HashCode)); 949 break; 950 } 951 case TALER_PQ_array_of_cs_r_pub: 952 { 953 const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data; 954 955 GNUNET_memcpy (out, 956 &cs_r_pubs[i], 957 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP)); 958 break; 959 } 960 default: 961 { 962 GNUNET_assert (0); 963 break; 964 } 965 } 966 out += sz; 967 } 968 } 969 param_values[0] = elements; 970 param_lengths[0] = total_size; 971 param_formats[0] = 1; 972 scratch[0] = elements; 973 974 DONE: 975 if (NULL != buffers) 976 { 977 for (size_t i = 0; i<num; i++) 978 GNUNET_free (buffers[i]); 979 GNUNET_free (buffers); 980 } 981 GNUNET_free (buffer_lengths); 982 if (noerror) 983 return 1; 984 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 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 struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls); 1013 1014 meta->typ = typ; 1015 meta->oid = oid; 1016 meta->sizes = sizes; 1017 meta->same_size = same_size; 1018 meta->continuous = continuous; 1019 meta->db = db; 1020 1021 { 1022 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 return res; 1032 } 1033 } 1034 1035 1036 struct GNUNET_PQ_QueryParam 1037 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 GNUNET_assert (GNUNET_OK == 1045 GNUNET_PQ_get_oid_by_name (db, 1046 "bytea", 1047 &oid)); 1048 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 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 GNUNET_assert (GNUNET_OK == 1068 GNUNET_PQ_get_oid_by_name (db, 1069 "bytea", 1070 &oid)); 1071 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 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 GNUNET_assert (GNUNET_OK == 1091 GNUNET_PQ_get_oid_by_name (db, 1092 "bytea", 1093 &oid)); 1094 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 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 GNUNET_assert (GNUNET_OK == 1113 GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid)); 1114 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 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 GNUNET_assert (GNUNET_OK == 1134 GNUNET_PQ_get_oid_by_name (db, 1135 "taler_amount", 1136 &oid)); 1137 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 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 GNUNET_assert (GNUNET_OK == 1158 GNUNET_PQ_get_oid_by_name (db, 1159 "taler_amount_currency", 1160 &oid)); 1161 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 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 GNUNET_assert (GNUNET_OK == 1182 GNUNET_PQ_get_oid_by_name (db, 1183 "bytea", 1184 &oid)); 1185 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 */