Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * pgp-pgsql.c
3 : : * PostgreSQL wrappers for pgp.
4 : : *
5 : : * Copyright (c) 2005 Marko Kreen
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : : * SUCH DAMAGE.
28 : : *
29 : : * contrib/pgcrypto/pgp-pgsql.c
30 : : */
31 : :
32 : : #include "postgres.h"
33 : :
34 : : #include "catalog/pg_type.h"
35 : : #include "common/string.h"
36 : : #include "funcapi.h"
37 : : #include "lib/stringinfo.h"
38 : : #include "mb/pg_wchar.h"
39 : : #include "mbuf.h"
40 : : #include "pgp.h"
41 : : #include "px.h"
42 : : #include "utils/array.h"
43 : : #include "utils/builtins.h"
44 : :
45 : : /*
46 : : * public functions
47 : : */
6853 bruce@momjian.us 48 :CBC 5 : PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
49 : 7 : PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
50 : 4 : PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
51 : 8 : PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
52 : :
53 : 3 : PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
54 : 3 : PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
55 : 4 : PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
56 : 6 : PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
57 : :
58 : 2 : PG_FUNCTION_INFO_V1(pgp_key_id_w);
59 : :
60 : 4 : PG_FUNCTION_INFO_V1(pg_armor);
61 : 7 : PG_FUNCTION_INFO_V1(pg_dearmor);
3483 heikki.linnakangas@i 62 : 2 : PG_FUNCTION_INFO_V1(pgp_armor_headers);
63 : :
64 : : /*
65 : : * returns src in case of no conversion or error
66 : : */
67 : : static text *
6756 bruce@momjian.us 68 :UBC 0 : convert_charset(text *src, int cset_from, int cset_to)
69 : : {
2590 noah@leadboat.com 70 [ # # # # : 0 : int src_len = VARSIZE_ANY_EXHDR(src);
# # # # #
# ]
71 : : unsigned char *dst;
72 [ # # ]: 0 : unsigned char *csrc = (unsigned char *) VARDATA_ANY(src);
73 : : text *res;
74 : :
6853 bruce@momjian.us 75 : 0 : dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to);
76 [ # # ]: 0 : if (dst == csrc)
77 : 0 : return src;
78 : :
5824 tgl@sss.pgh.pa.us 79 : 0 : res = cstring_to_text((char *) dst);
6853 bruce@momjian.us 80 : 0 : pfree(dst);
81 : 0 : return res;
82 : : }
83 : :
84 : : static text *
6756 85 : 0 : convert_from_utf8(text *src)
86 : : {
6853 87 : 0 : return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
88 : : }
89 : :
90 : : static text *
6756 91 : 0 : convert_to_utf8(text *src)
92 : : {
6853 93 : 0 : return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
94 : : }
95 : :
96 : : static void
97 : 0 : clear_and_pfree(text *p)
98 : : {
2590 noah@leadboat.com 99 [ # # # # : 0 : px_memset(p, 0, VARSIZE_ANY(p));
# # # # #
# ]
6853 bruce@momjian.us 100 : 0 : pfree(p);
101 : 0 : }
102 : :
103 : : /*
104 : : * expect-* arguments storage
105 : : */
106 : : struct debug_expect
107 : : {
108 : : int debug;
109 : : int expect;
110 : : int cipher_algo;
111 : : int s2k_mode;
112 : : int s2k_count;
113 : : int s2k_cipher_algo;
114 : : int s2k_digest_algo;
115 : : int compress_algo;
116 : : int use_sess_key;
117 : : int disable_mdc;
118 : : int unicode_mode;
119 : : };
120 : :
121 : : static void
2489 tgl@sss.pgh.pa.us 122 :CBC 115 : fill_expect(struct debug_expect *ex, int text_mode)
123 : : {
6853 bruce@momjian.us 124 : 115 : ex->debug = 0;
125 : 115 : ex->expect = 0;
126 : 115 : ex->cipher_algo = -1;
127 : 115 : ex->s2k_mode = -1;
2958 alvherre@alvh.no-ip. 128 : 115 : ex->s2k_count = -1;
6853 bruce@momjian.us 129 : 115 : ex->s2k_cipher_algo = -1;
130 : 115 : ex->s2k_digest_algo = -1;
131 : 115 : ex->compress_algo = -1;
132 : 115 : ex->use_sess_key = -1;
133 : 115 : ex->disable_mdc = -1;
134 : 115 : ex->unicode_mode = -1;
135 : 115 : }
136 : :
137 : : #define EX_MSG(arg) \
138 : : ereport(NOTICE, (errmsg( \
139 : : "pgp_decrypt: unexpected %s: expected %d got %d", \
140 : : CppAsString(arg), ex->arg, ctx->arg)))
141 : :
142 : : #define EX_CHECK(arg) do { \
143 : : if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
144 : : } while (0)
145 : :
146 : : static void
2489 tgl@sss.pgh.pa.us 147 : 24 : check_expect(PGP_Context *ctx, struct debug_expect *ex)
148 : : {
6853 bruce@momjian.us 149 [ + + + + : 24 : EX_CHECK(cipher_algo);
+ - ]
150 [ + + + + : 24 : EX_CHECK(s2k_mode);
+ - ]
2958 alvherre@alvh.no-ip. 151 [ + + + + : 24 : EX_CHECK(s2k_count);
+ - ]
6853 bruce@momjian.us 152 [ + + + + : 24 : EX_CHECK(s2k_digest_algo);
+ - ]
153 [ + + + + : 24 : EX_CHECK(use_sess_key);
+ - ]
154 [ + + ]: 24 : if (ctx->use_sess_key)
155 [ - + - - : 4 : EX_CHECK(s2k_cipher_algo);
- - ]
156 [ + + + + : 24 : EX_CHECK(disable_mdc);
+ - ]
157 [ + + + + : 24 : EX_CHECK(compress_algo);
+ - ]
158 [ - + - - : 24 : EX_CHECK(unicode_mode);
- - ]
159 : 24 : }
160 : :
161 : : static void
6756 162 : 8 : show_debug(const char *msg)
163 : : {
6853 164 [ + - ]: 8 : ereport(NOTICE, (errmsg("dbg: %s", msg)));
165 : 8 : }
166 : :
167 : : static int
5421 168 : 72 : set_arg(PGP_Context *ctx, char *key, char *val,
169 : : struct debug_expect *ex)
170 : : {
6756 171 : 72 : int res = 0;
172 : :
6853 173 [ + + ]: 72 : if (strcmp(key, "cipher-algo") == 0)
174 : 6 : res = pgp_set_cipher_algo(ctx, val);
175 [ + + ]: 66 : else if (strcmp(key, "disable-mdc") == 0)
176 : 1 : res = pgp_disable_mdc(ctx, atoi(val));
177 [ + + ]: 65 : else if (strcmp(key, "sess-key") == 0)
178 : 5 : res = pgp_set_sess_key(ctx, atoi(val));
179 [ + + ]: 60 : else if (strcmp(key, "s2k-mode") == 0)
180 : 3 : res = pgp_set_s2k_mode(ctx, atoi(val));
2958 alvherre@alvh.no-ip. 181 [ + + ]: 57 : else if (strcmp(key, "s2k-count") == 0)
182 : 2 : res = pgp_set_s2k_count(ctx, atoi(val));
6853 bruce@momjian.us 183 [ + + ]: 55 : else if (strcmp(key, "s2k-digest-algo") == 0)
184 : 2 : res = pgp_set_s2k_digest_algo(ctx, val);
185 [ - + ]: 53 : else if (strcmp(key, "s2k-cipher-algo") == 0)
6853 bruce@momjian.us 186 :UBC 0 : res = pgp_set_s2k_cipher_algo(ctx, val);
6853 bruce@momjian.us 187 [ + + ]:CBC 53 : else if (strcmp(key, "compress-algo") == 0)
188 : 5 : res = pgp_set_compress_algo(ctx, atoi(val));
189 [ + + ]: 48 : else if (strcmp(key, "compress-level") == 0)
190 : 2 : res = pgp_set_compress_level(ctx, atoi(val));
191 [ + + ]: 46 : else if (strcmp(key, "convert-crlf") == 0)
192 : 5 : res = pgp_set_convert_crlf(ctx, atoi(val));
193 [ - + ]: 41 : else if (strcmp(key, "unicode-mode") == 0)
6853 bruce@momjian.us 194 :UBC 0 : res = pgp_set_unicode_mode(ctx, atoi(val));
195 : :
196 : : /*
197 : : * The remaining options are for debugging/testing and are therefore not
198 : : * documented in the user-facing docs.
199 : : */
6853 bruce@momjian.us 200 [ + - + + ]:CBC 41 : else if (ex != NULL && strcmp(key, "debug") == 0)
201 : 4 : ex->debug = atoi(val);
202 [ + - + + ]: 37 : else if (ex != NULL && strcmp(key, "expect-cipher-algo") == 0)
203 : : {
204 : 8 : ex->expect = 1;
205 : 8 : ex->cipher_algo = pgp_get_cipher_code(val);
206 : : }
207 [ + - + + ]: 29 : else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
208 : : {
209 : 3 : ex->expect = 1;
210 : 3 : ex->disable_mdc = atoi(val);
211 : : }
212 [ + - + + ]: 26 : else if (ex != NULL && strcmp(key, "expect-sess-key") == 0)
213 : : {
214 : 7 : ex->expect = 1;
215 : 7 : ex->use_sess_key = atoi(val);
216 : : }
217 [ + - + + ]: 19 : else if (ex != NULL && strcmp(key, "expect-s2k-mode") == 0)
218 : : {
219 : 5 : ex->expect = 1;
220 : 5 : ex->s2k_mode = atoi(val);
221 : : }
2958 alvherre@alvh.no-ip. 222 [ + - + + ]: 14 : else if (ex != NULL && strcmp(key, "expect-s2k-count") == 0)
223 : : {
224 : 2 : ex->expect = 1;
225 : 2 : ex->s2k_count = atoi(val);
226 : : }
6853 bruce@momjian.us 227 [ + - + + ]: 12 : else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0)
228 : : {
229 : 4 : ex->expect = 1;
230 : 4 : ex->s2k_digest_algo = pgp_get_digest_code(val);
231 : : }
232 [ + - - + ]: 8 : else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo") == 0)
233 : : {
6853 bruce@momjian.us 234 :UBC 0 : ex->expect = 1;
235 : 0 : ex->s2k_cipher_algo = pgp_get_cipher_code(val);
236 : : }
6853 bruce@momjian.us 237 [ + - + - ]:CBC 8 : else if (ex != NULL && strcmp(key, "expect-compress-algo") == 0)
238 : : {
239 : 8 : ex->expect = 1;
240 : 8 : ex->compress_algo = atoi(val);
241 : : }
6853 bruce@momjian.us 242 [ # # # # ]:UBC 0 : else if (ex != NULL && strcmp(key, "expect-unicode-mode") == 0)
243 : : {
244 : 0 : ex->expect = 1;
245 : 0 : ex->unicode_mode = atoi(val);
246 : : }
247 : : else
248 : 0 : res = PXE_ARGUMENT_ERROR;
249 : :
6853 bruce@momjian.us 250 :CBC 72 : return res;
251 : : }
252 : :
253 : : /*
254 : : * Find next word. Handle ',' and '=' as words. Skip whitespace.
255 : : * Put word info into res_p, res_len.
256 : : * Returns ptr to next word.
257 : : */
258 : : static char *
6756 259 : 144 : getword(char *p, char **res_p, int *res_len)
260 : : {
261 : : /* whitespace at start */
6853 262 [ + - + + : 181 : while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
+ + + + ]
263 : 37 : p++;
264 : :
265 : : /* word data */
266 : 144 : *res_p = p;
267 [ + - - + ]: 144 : if (*p == '=' || *p == ',')
6853 bruce@momjian.us 268 :UBC 0 : p++;
269 : : else
6853 bruce@momjian.us 270 [ + + + - :CBC 1318 : while (*p && !(*p == ' ' || *p == '\t' || *p == '\n'
+ - + + ]
6756 271 [ + + + + ]: 1264 : || *p == '=' || *p == ','))
6853 272 : 1174 : p++;
273 : :
274 : : /* word end */
275 : 144 : *res_len = p - *res_p;
276 : :
277 : : /* whitespace at end */
278 [ + + - + : 150 : while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
+ + + + ]
279 : 6 : p++;
280 : :
281 : 144 : return p;
282 : : }
283 : :
284 : : /*
285 : : * Convert to lowercase asciiz string.
286 : : */
287 : : static char *
6756 288 : 54 : downcase_convert(const uint8 *s, int len)
289 : : {
290 : : int c,
291 : : i;
292 : 54 : char *res = palloc(len + 1);
293 : :
294 [ + + ]: 1361 : for (i = 0; i < len; i++)
295 : : {
6853 296 : 1307 : c = s[i];
297 [ + + - + ]: 1307 : if (c >= 'A' && c <= 'Z')
6853 bruce@momjian.us 298 :UBC 0 : c += 'a' - 'A';
6853 bruce@momjian.us 299 :CBC 1307 : res[i] = c;
300 : : }
301 : 54 : res[len] = 0;
302 : 54 : return res;
303 : : }
304 : :
305 : : static int
5421 306 : 54 : parse_args(PGP_Context *ctx, uint8 *args, int arg_len,
307 : : struct debug_expect *ex)
308 : : {
6756 309 : 54 : char *str = downcase_convert(args, arg_len);
310 : : char *key,
311 : : *val;
312 : : int key_len,
313 : : val_len;
314 : 54 : int res = 0;
315 : 54 : char *p = str;
316 : :
6853 317 [ + + ]: 126 : while (*p)
318 : : {
319 : 72 : res = PXE_ARGUMENT_ERROR;
320 : 72 : p = getword(p, &key, &key_len);
321 [ - + ]: 72 : if (*p++ != '=')
6853 bruce@momjian.us 322 :UBC 0 : break;
6853 bruce@momjian.us 323 :CBC 72 : p = getword(p, &val, &val_len);
324 [ + + ]: 72 : if (*p == '\0')
325 : : ;
326 [ - + ]: 18 : else if (*p++ != ',')
6853 bruce@momjian.us 327 :UBC 0 : break;
328 : :
6853 bruce@momjian.us 329 [ + - + - :CBC 72 : if (*key == 0 || *val == 0 || val_len == 0)
+ - ]
330 : : break;
331 : :
332 : 72 : key[key_len] = 0;
333 : 72 : val[val_len] = 0;
334 : :
335 : 72 : res = set_arg(ctx, key, val, ex);
336 [ - + ]: 72 : if (res < 0)
6853 bruce@momjian.us 337 :UBC 0 : break;
338 : : }
6853 bruce@momjian.us 339 :CBC 54 : pfree(str);
340 : 54 : return res;
341 : : }
342 : :
343 : : static MBuf *
344 : 81 : create_mbuf_from_vardata(text *data)
345 : : {
2590 noah@leadboat.com 346 [ - + ]: 81 : return mbuf_create_from_data((uint8 *) VARDATA_ANY(data),
347 [ - + - - : 81 : VARSIZE_ANY_EXHDR(data));
- - - - -
+ ]
348 : : }
349 : :
350 : : static void
5421 bruce@momjian.us 351 : 115 : init_work(PGP_Context **ctx_p, int is_text,
352 : : text *args, struct debug_expect *ex)
353 : : {
6756 354 : 115 : int err = pgp_init(ctx_p);
355 : :
6853 356 : 115 : fill_expect(ex, is_text);
357 : :
358 [ + - + + ]: 115 : if (err == 0 && args != NULL)
2590 noah@leadboat.com 359 [ - + ]: 54 : err = parse_args(*ctx_p, (uint8 *) VARDATA_ANY(args),
360 [ - + - - : 54 : VARSIZE_ANY_EXHDR(args), ex);
- - - - -
+ ]
361 : :
6853 bruce@momjian.us 362 [ - + ]: 115 : if (err)
2687 heikki.linnakangas@i 363 :UBC 0 : px_THROW_ERROR(err);
364 : :
6853 bruce@momjian.us 365 [ + + ]:CBC 115 : if (ex->debug)
366 : 4 : px_set_debug_handler(show_debug);
367 : :
368 : 115 : pgp_set_text_mode(*ctx_p, is_text);
369 : 115 : }
370 : :
371 : : static bytea *
372 : 38 : encrypt_internal(int is_pubenc, int is_text,
373 : : text *data, text *key, text *args)
374 : : {
375 : : MBuf *src,
376 : : *dst;
377 : : uint8 tmp[VARHDRSZ];
378 : : uint8 *restmp;
379 : : bytea *res;
380 : : int res_len;
381 : : PGP_Context *ctx;
382 : : int err;
383 : : struct debug_expect ex;
6756 384 : 38 : text *tmp_data = NULL;
385 : :
6853 386 : 38 : init_work(&ctx, is_text, args, &ex);
387 : :
388 [ + + - + ]: 38 : if (is_text && pgp_get_unicode_mode(ctx))
389 : : {
6853 bruce@momjian.us 390 :UBC 0 : tmp_data = convert_to_utf8(data);
391 [ # # ]: 0 : if (tmp_data == data)
392 : 0 : tmp_data = NULL;
393 : : else
394 : 0 : data = tmp_data;
395 : : }
396 : :
6853 bruce@momjian.us 397 :CBC 38 : src = create_mbuf_from_vardata(data);
2590 noah@leadboat.com 398 [ - + - - : 38 : dst = mbuf_create(VARSIZE_ANY(data) + 128);
- - - - -
+ ]
399 : :
400 : : /*
401 : : * reserve room for header
402 : : */
6853 bruce@momjian.us 403 : 38 : mbuf_append(dst, tmp, VARHDRSZ);
404 : :
405 : : /*
406 : : * set key
407 : : */
408 [ + + ]: 38 : if (is_pubenc)
409 : : {
6756 410 : 8 : MBuf *kbuf = create_mbuf_from_vardata(key);
411 : :
6853 412 : 8 : err = pgp_set_pubkey(ctx, kbuf,
413 : : NULL, 0, 0);
414 : 8 : mbuf_free(kbuf);
415 : : }
416 : : else
2590 noah@leadboat.com 417 [ - + ]: 30 : err = pgp_set_symkey(ctx, (uint8 *) VARDATA_ANY(key),
418 [ - + - - : 30 : VARSIZE_ANY_EXHDR(key));
- - - - -
+ ]
419 : :
420 : : /*
421 : : * encrypt
422 : : */
6853 bruce@momjian.us 423 [ + + ]: 38 : if (err >= 0)
424 : 36 : err = pgp_encrypt(ctx, src, dst);
425 : :
426 : : /*
427 : : * check for error
428 : : */
429 [ + + ]: 38 : if (err)
430 : : {
431 [ - + ]: 2 : if (ex.debug)
6853 bruce@momjian.us 432 :UBC 0 : px_set_debug_handler(NULL);
6853 bruce@momjian.us 433 [ - + ]:CBC 2 : if (tmp_data)
6853 bruce@momjian.us 434 :UBC 0 : clear_and_pfree(tmp_data);
6853 bruce@momjian.us 435 :CBC 2 : pgp_free(ctx);
436 : 2 : mbuf_free(src);
437 : 2 : mbuf_free(dst);
2687 heikki.linnakangas@i 438 : 2 : px_THROW_ERROR(err);
439 : : }
440 : :
441 : : /* res_len includes VARHDRSZ */
6853 bruce@momjian.us 442 : 36 : res_len = mbuf_steal_data(dst, &restmp);
443 : 36 : res = (bytea *) restmp;
6256 tgl@sss.pgh.pa.us 444 : 36 : SET_VARSIZE(res, res_len);
445 : :
6853 bruce@momjian.us 446 [ - + ]: 36 : if (tmp_data)
6853 bruce@momjian.us 447 :UBC 0 : clear_and_pfree(tmp_data);
6853 bruce@momjian.us 448 :CBC 36 : pgp_free(ctx);
449 : 36 : mbuf_free(src);
450 : 36 : mbuf_free(dst);
451 : :
452 : 36 : px_set_debug_handler(NULL);
453 : :
454 : 36 : return res;
455 : : }
456 : :
457 : : static bytea *
458 : 77 : decrypt_internal(int is_pubenc, int need_text, text *data,
459 : : text *key, text *keypsw, text *args)
460 : : {
461 : : int err;
6756 462 : 77 : MBuf *src = NULL,
463 : 77 : *dst = NULL;
464 : : uint8 tmp[VARHDRSZ];
465 : : uint8 *restmp;
466 : : bytea *res;
467 : : int res_len;
6853 468 : 77 : PGP_Context *ctx = NULL;
469 : : struct debug_expect ex;
6756 470 : 77 : int got_unicode = 0;
471 : :
472 : :
6853 473 : 77 : init_work(&ctx, need_text, args, &ex);
474 : :
2590 noah@leadboat.com 475 [ - + ]: 77 : src = mbuf_create_from_data((uint8 *) VARDATA_ANY(data),
476 [ - + - - : 77 : VARSIZE_ANY_EXHDR(data));
- - - - -
+ ]
477 [ - + - - : 77 : dst = mbuf_create(VARSIZE_ANY(data) + 2048);
- - - - -
+ ]
478 : :
479 : : /*
480 : : * reserve room for header
481 : : */
6853 bruce@momjian.us 482 : 77 : mbuf_append(dst, tmp, VARHDRSZ);
483 : :
484 : : /*
485 : : * set key
486 : : */
487 [ + + ]: 77 : if (is_pubenc)
488 : : {
6756 489 : 18 : uint8 *psw = NULL;
490 : 18 : int psw_len = 0;
491 : : MBuf *kbuf;
492 : :
6853 493 [ + + ]: 18 : if (keypsw)
494 : : {
2590 noah@leadboat.com 495 [ - + ]: 4 : psw = (uint8 *) VARDATA_ANY(keypsw);
496 [ - + - - : 4 : psw_len = VARSIZE_ANY_EXHDR(keypsw);
- - - - -
+ ]
497 : : }
6853 bruce@momjian.us 498 : 18 : kbuf = create_mbuf_from_vardata(key);
499 : 18 : err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
500 : 18 : mbuf_free(kbuf);
501 : : }
502 : : else
2590 noah@leadboat.com 503 [ - + ]: 59 : err = pgp_set_symkey(ctx, (uint8 *) VARDATA_ANY(key),
504 [ - + - - : 59 : VARSIZE_ANY_EXHDR(key));
- - - - -
+ ]
505 : :
506 : : /* decrypt */
6853 bruce@momjian.us 507 [ + + ]: 77 : if (err >= 0)
508 : : {
509 : 73 : err = pgp_decrypt(ctx, src, dst);
510 : :
3357 rhaas@postgresql.org 511 [ + + ]: 73 : if (ex.expect)
512 : 24 : check_expect(ctx, &ex);
513 : :
514 : : /* remember the setting */
515 : 73 : got_unicode = pgp_get_unicode_mode(ctx);
516 : : }
517 : :
518 : 77 : mbuf_free(src);
519 : 77 : pgp_free(ctx);
520 : :
6853 bruce@momjian.us 521 [ + + ]: 77 : if (err)
522 : : {
523 : 14 : px_set_debug_handler(NULL);
3357 rhaas@postgresql.org 524 : 14 : mbuf_free(dst);
2687 heikki.linnakangas@i 525 : 14 : px_THROW_ERROR(err);
526 : : }
527 : :
6853 bruce@momjian.us 528 : 63 : res_len = mbuf_steal_data(dst, &restmp);
529 : 63 : mbuf_free(dst);
530 : :
531 : : /* res_len includes VARHDRSZ */
532 : 63 : res = (bytea *) restmp;
6256 tgl@sss.pgh.pa.us 533 : 63 : SET_VARSIZE(res, res_len);
534 : :
6853 bruce@momjian.us 535 [ + + - + ]: 63 : if (need_text && got_unicode)
536 : : {
6756 bruce@momjian.us 537 :UBC 0 : text *utf = convert_from_utf8(res);
538 : :
6853 539 [ # # ]: 0 : if (utf != res)
540 : : {
541 : 0 : clear_and_pfree(res);
542 : 0 : res = utf;
543 : : }
544 : : }
6853 bruce@momjian.us 545 :CBC 63 : px_set_debug_handler(NULL);
546 : :
547 : 63 : return res;
548 : : }
549 : :
550 : : /*
551 : : * Wrappers for symmetric-key functions
552 : : */
553 : : Datum
554 : 3 : pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
555 : : {
556 : : bytea *data;
557 : 3 : text *arg = NULL;
558 : : text *res,
559 : : *key;
560 : :
2590 noah@leadboat.com 561 : 3 : data = PG_GETARG_BYTEA_PP(0);
60 michael@paquier.xyz 562 :GNC 3 : key = PG_GETARG_TEXT_PP(1);
6853 bruce@momjian.us 563 [ + + ]:CBC 3 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 564 :GNC 1 : arg = PG_GETARG_TEXT_PP(2);
565 : :
6853 bruce@momjian.us 566 :CBC 3 : res = encrypt_internal(0, 0, data, key, arg);
567 : :
568 [ - + ]: 3 : PG_FREE_IF_COPY(data, 0);
569 [ - + ]: 3 : PG_FREE_IF_COPY(key, 1);
570 [ + + ]: 3 : if (PG_NARGS() > 2)
571 [ - + ]: 1 : PG_FREE_IF_COPY(arg, 2);
572 : 3 : PG_RETURN_TEXT_P(res);
573 : : }
574 : :
575 : : Datum
576 : 27 : pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
577 : : {
578 : : text *data,
579 : : *key;
580 : 27 : text *arg = NULL;
581 : : text *res;
582 : :
60 michael@paquier.xyz 583 :GNC 27 : data = PG_GETARG_TEXT_PP(0);
584 : 27 : key = PG_GETARG_TEXT_PP(1);
6853 bruce@momjian.us 585 [ + + ]:CBC 27 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 586 :GNC 22 : arg = PG_GETARG_TEXT_PP(2);
587 : :
6853 bruce@momjian.us 588 :CBC 27 : res = encrypt_internal(0, 1, data, key, arg);
589 : :
590 [ - + ]: 27 : PG_FREE_IF_COPY(data, 0);
591 [ - + ]: 27 : PG_FREE_IF_COPY(key, 1);
592 [ + + ]: 27 : if (PG_NARGS() > 2)
593 [ - + ]: 22 : PG_FREE_IF_COPY(arg, 2);
594 : 27 : PG_RETURN_TEXT_P(res);
595 : : }
596 : :
597 : :
598 : : Datum
599 : 3 : pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
600 : : {
601 : : bytea *data;
602 : 3 : text *arg = NULL;
603 : : text *res,
604 : : *key;
605 : :
2590 noah@leadboat.com 606 : 3 : data = PG_GETARG_BYTEA_PP(0);
60 michael@paquier.xyz 607 :GNC 3 : key = PG_GETARG_TEXT_PP(1);
6853 bruce@momjian.us 608 [ + + ]:CBC 3 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 609 :GNC 1 : arg = PG_GETARG_TEXT_PP(2);
610 : :
6853 bruce@momjian.us 611 :CBC 3 : res = decrypt_internal(0, 0, data, key, NULL, arg);
612 : :
613 [ - + ]: 3 : PG_FREE_IF_COPY(data, 0);
614 [ - + ]: 3 : PG_FREE_IF_COPY(key, 1);
615 [ + + ]: 3 : if (PG_NARGS() > 2)
616 [ - + ]: 1 : PG_FREE_IF_COPY(arg, 2);
617 : 3 : PG_RETURN_TEXT_P(res);
618 : : }
619 : :
620 : : Datum
621 : 56 : pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
622 : : {
623 : : bytea *data;
624 : 56 : text *arg = NULL;
625 : : text *res,
626 : : *key;
627 : :
2590 noah@leadboat.com 628 : 56 : data = PG_GETARG_BYTEA_PP(0);
60 michael@paquier.xyz 629 :GNC 56 : key = PG_GETARG_TEXT_PP(1);
6853 bruce@momjian.us 630 [ + + ]:CBC 56 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 631 :GNC 30 : arg = PG_GETARG_TEXT_PP(2);
632 : :
6853 bruce@momjian.us 633 :CBC 56 : res = decrypt_internal(0, 1, data, key, NULL, arg);
634 : :
635 [ - + ]: 50 : PG_FREE_IF_COPY(data, 0);
636 [ - + ]: 50 : PG_FREE_IF_COPY(key, 1);
637 [ + + ]: 50 : if (PG_NARGS() > 2)
638 [ - + ]: 26 : PG_FREE_IF_COPY(arg, 2);
639 : 50 : PG_RETURN_TEXT_P(res);
640 : : }
641 : :
642 : : /*
643 : : * Wrappers for public-key functions
644 : : */
645 : :
646 : : Datum
647 : 1 : pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
648 : : {
649 : : bytea *data,
650 : : *key;
651 : 1 : text *arg = NULL;
652 : : text *res;
653 : :
2590 noah@leadboat.com 654 : 1 : data = PG_GETARG_BYTEA_PP(0);
655 : 1 : key = PG_GETARG_BYTEA_PP(1);
6853 bruce@momjian.us 656 [ - + ]: 1 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 657 :UNC 0 : arg = PG_GETARG_TEXT_PP(2);
658 : :
6853 bruce@momjian.us 659 :CBC 1 : res = encrypt_internal(1, 0, data, key, arg);
660 : :
661 [ - + ]: 1 : PG_FREE_IF_COPY(data, 0);
662 [ - + ]: 1 : PG_FREE_IF_COPY(key, 1);
663 [ - + ]: 1 : if (PG_NARGS() > 2)
6853 bruce@momjian.us 664 [ # # ]:UBC 0 : PG_FREE_IF_COPY(arg, 2);
6853 bruce@momjian.us 665 :CBC 1 : PG_RETURN_TEXT_P(res);
666 : : }
667 : :
668 : : Datum
669 : 7 : pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
670 : : {
671 : : bytea *key;
672 : 7 : text *arg = NULL;
673 : : text *res,
674 : : *data;
675 : :
60 michael@paquier.xyz 676 :GNC 7 : data = PG_GETARG_TEXT_PP(0);
2590 noah@leadboat.com 677 :CBC 7 : key = PG_GETARG_BYTEA_PP(1);
6853 bruce@momjian.us 678 [ - + ]: 7 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 679 :UNC 0 : arg = PG_GETARG_TEXT_PP(2);
680 : :
6853 bruce@momjian.us 681 :CBC 7 : res = encrypt_internal(1, 1, data, key, arg);
682 : :
683 [ - + ]: 5 : PG_FREE_IF_COPY(data, 0);
684 [ - + ]: 5 : PG_FREE_IF_COPY(key, 1);
685 [ - + ]: 5 : if (PG_NARGS() > 2)
6853 bruce@momjian.us 686 [ # # ]:UBC 0 : PG_FREE_IF_COPY(arg, 2);
6853 bruce@momjian.us 687 :CBC 5 : PG_RETURN_TEXT_P(res);
688 : : }
689 : :
690 : :
691 : : Datum
692 : 1 : pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
693 : : {
694 : : bytea *data,
695 : : *key;
696 : 1 : text *psw = NULL,
697 : 1 : *arg = NULL;
698 : : text *res;
699 : :
2590 noah@leadboat.com 700 : 1 : data = PG_GETARG_BYTEA_PP(0);
701 : 1 : key = PG_GETARG_BYTEA_PP(1);
6853 bruce@momjian.us 702 [ - + ]: 1 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 703 :UNC 0 : psw = PG_GETARG_TEXT_PP(2);
6853 bruce@momjian.us 704 [ - + ]:CBC 1 : if (PG_NARGS() > 3)
60 michael@paquier.xyz 705 :UNC 0 : arg = PG_GETARG_TEXT_PP(3);
706 : :
6853 bruce@momjian.us 707 :CBC 1 : res = decrypt_internal(1, 0, data, key, psw, arg);
708 : :
709 [ - + ]: 1 : PG_FREE_IF_COPY(data, 0);
710 [ - + ]: 1 : PG_FREE_IF_COPY(key, 1);
711 [ - + ]: 1 : if (PG_NARGS() > 2)
6853 bruce@momjian.us 712 [ # # ]:UBC 0 : PG_FREE_IF_COPY(psw, 2);
6853 bruce@momjian.us 713 [ - + ]:CBC 1 : if (PG_NARGS() > 3)
6853 bruce@momjian.us 714 [ # # ]:UBC 0 : PG_FREE_IF_COPY(arg, 3);
6853 bruce@momjian.us 715 :CBC 1 : PG_RETURN_TEXT_P(res);
716 : : }
717 : :
718 : : Datum
719 : 17 : pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
720 : : {
721 : : bytea *data,
722 : : *key;
723 : 17 : text *psw = NULL,
724 : 17 : *arg = NULL;
725 : : text *res;
726 : :
2590 noah@leadboat.com 727 : 17 : data = PG_GETARG_BYTEA_PP(0);
728 : 17 : key = PG_GETARG_BYTEA_PP(1);
6853 bruce@momjian.us 729 [ + + ]: 17 : if (PG_NARGS() > 2)
60 michael@paquier.xyz 730 :GNC 4 : psw = PG_GETARG_TEXT_PP(2);
6853 bruce@momjian.us 731 [ - + ]:CBC 17 : if (PG_NARGS() > 3)
60 michael@paquier.xyz 732 :UNC 0 : arg = PG_GETARG_TEXT_PP(3);
733 : :
6853 bruce@momjian.us 734 :CBC 17 : res = decrypt_internal(1, 1, data, key, psw, arg);
735 : :
736 [ - + ]: 9 : PG_FREE_IF_COPY(data, 0);
737 [ - + ]: 9 : PG_FREE_IF_COPY(key, 1);
738 [ + + ]: 9 : if (PG_NARGS() > 2)
739 [ - + ]: 2 : PG_FREE_IF_COPY(psw, 2);
740 [ - + ]: 9 : if (PG_NARGS() > 3)
6853 bruce@momjian.us 741 [ # # ]:UBC 0 : PG_FREE_IF_COPY(arg, 3);
6853 bruce@momjian.us 742 :CBC 9 : PG_RETURN_TEXT_P(res);
743 : : }
744 : :
745 : :
746 : : /*
747 : : * Wrappers for PGP ascii armor
748 : : */
749 : :
750 : : /*
751 : : * Helper function for pg_armor. Converts arrays of keys and values into
752 : : * plain C arrays, and checks that they don't contain invalid characters.
753 : : */
754 : : static int
3483 heikki.linnakangas@i 755 : 14 : parse_key_value_arrays(ArrayType *key_array, ArrayType *val_array,
756 : : char ***p_keys, char ***p_values)
757 : : {
3249 bruce@momjian.us 758 : 14 : int nkdims = ARR_NDIM(key_array);
759 : 14 : int nvdims = ARR_NDIM(val_array);
760 : : char **keys,
761 : : **values;
762 : : Datum *key_datums,
763 : : *val_datums;
764 : : bool *key_nulls,
765 : : *val_nulls;
766 : : int key_count,
767 : : val_count;
768 : : int i;
769 : :
3483 heikki.linnakangas@i 770 [ + + + + ]: 14 : if (nkdims > 1 || nkdims != nvdims)
771 [ + - ]: 2 : ereport(ERROR,
772 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
773 : : errmsg("wrong number of array subscripts")));
774 [ - + ]: 12 : if (nkdims == 0)
3483 heikki.linnakangas@i 775 :UBC 0 : return 0;
776 : :
653 peter@eisentraut.org 777 :CBC 12 : deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
778 : 12 : deconstruct_array_builtin(val_array, TEXTOID, &val_datums, &val_nulls, &val_count);
779 : :
3483 heikki.linnakangas@i 780 [ + + ]: 12 : if (key_count != val_count)
781 [ + - ]: 2 : ereport(ERROR,
782 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
783 : : errmsg("mismatched array dimensions")));
784 : :
785 : 10 : keys = (char **) palloc(sizeof(char *) * key_count);
786 : 10 : values = (char **) palloc(sizeof(char *) * val_count);
787 : :
788 [ + + ]: 17 : for (i = 0; i < key_count; i++)
789 : : {
790 : : char *v;
791 : :
792 : : /* Check that the key doesn't contain anything funny */
793 [ + + ]: 12 : if (key_nulls[i])
794 [ + - ]: 1 : ereport(ERROR,
795 : : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
796 : : errmsg("null value not allowed for header key")));
797 : :
798 : 11 : v = TextDatumGetCString(key_datums[i]);
799 : :
1210 michael@paquier.xyz 800 [ - + ]: 11 : if (!pg_is_ascii(v))
3483 heikki.linnakangas@i 801 [ # # ]:UBC 0 : ereport(ERROR,
802 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
803 : : errmsg("header key must not contain non-ASCII characters")));
3483 heikki.linnakangas@i 804 [ + + ]:CBC 11 : if (strstr(v, ": "))
805 [ + - ]: 1 : ereport(ERROR,
806 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
807 : : errmsg("header key must not contain \": \"")));
808 [ + + ]: 10 : if (strchr(v, '\n'))
809 [ + - ]: 1 : ereport(ERROR,
810 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
811 : : errmsg("header key must not contain newlines")));
812 : 9 : keys[i] = v;
813 : :
814 : : /* And the same for the value */
815 [ + + ]: 9 : if (val_nulls[i])
816 [ + - ]: 1 : ereport(ERROR,
817 : : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
818 : : errmsg("null value not allowed for header value")));
819 : :
820 : 8 : v = TextDatumGetCString(val_datums[i]);
821 : :
1210 michael@paquier.xyz 822 [ - + ]: 8 : if (!pg_is_ascii(v))
3483 heikki.linnakangas@i 823 [ # # ]:UBC 0 : ereport(ERROR,
824 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
825 : : errmsg("header value must not contain non-ASCII characters")));
3483 heikki.linnakangas@i 826 [ + + ]:CBC 8 : if (strchr(v, '\n'))
827 [ + - ]: 1 : ereport(ERROR,
828 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
829 : : errmsg("header value must not contain newlines")));
830 : :
831 : 7 : values[i] = v;
832 : : }
833 : :
834 : 5 : *p_keys = keys;
835 : 5 : *p_values = values;
836 : 5 : return key_count;
837 : : }
838 : :
839 : : Datum
6853 bruce@momjian.us 840 : 19 : pg_armor(PG_FUNCTION_ARGS)
841 : : {
842 : : bytea *data;
843 : : text *res;
844 : : int data_len;
845 : : StringInfoData buf;
846 : : int num_headers;
3483 heikki.linnakangas@i 847 : 19 : char **keys = NULL,
848 : 19 : **values = NULL;
849 : :
2590 noah@leadboat.com 850 : 19 : data = PG_GETARG_BYTEA_PP(0);
851 [ - + - - : 19 : data_len = VARSIZE_ANY_EXHDR(data);
- - - - -
+ ]
3483 heikki.linnakangas@i 852 [ + + ]: 19 : if (PG_NARGS() == 3)
853 : : {
854 : 14 : num_headers = parse_key_value_arrays(PG_GETARG_ARRAYTYPE_P(1),
855 : 14 : PG_GETARG_ARRAYTYPE_P(2),
856 : : &keys, &values);
857 : : }
858 [ + - ]: 5 : else if (PG_NARGS() == 1)
859 : 5 : num_headers = 0;
860 : : else
3483 heikki.linnakangas@i 861 [ # # ]:UBC 0 : elog(ERROR, "unexpected number of arguments %d", PG_NARGS());
862 : :
3489 heikki.linnakangas@i 863 :CBC 10 : initStringInfo(&buf);
864 : :
2590 noah@leadboat.com 865 [ - + ]: 10 : pgp_armor_encode((uint8 *) VARDATA_ANY(data), data_len, &buf,
866 : : num_headers, keys, values);
867 : :
3489 heikki.linnakangas@i 868 : 10 : res = palloc(VARHDRSZ + buf.len);
869 : 10 : SET_VARSIZE(res, VARHDRSZ + buf.len);
870 : 10 : memcpy(VARDATA(res), buf.data, buf.len);
871 : 10 : pfree(buf.data);
872 : :
6853 bruce@momjian.us 873 [ - + ]: 10 : PG_FREE_IF_COPY(data, 0);
874 : 10 : PG_RETURN_TEXT_P(res);
875 : : }
876 : :
877 : : Datum
878 : 89 : pg_dearmor(PG_FUNCTION_ARGS)
879 : : {
880 : : text *data;
881 : : bytea *res;
882 : : int data_len;
883 : : int ret;
884 : : StringInfoData buf;
885 : :
2590 noah@leadboat.com 886 : 89 : data = PG_GETARG_TEXT_PP(0);
887 [ - + - - : 89 : data_len = VARSIZE_ANY_EXHDR(data);
- - - - -
+ ]
888 : :
3489 heikki.linnakangas@i 889 : 89 : initStringInfo(&buf);
890 : :
2590 noah@leadboat.com 891 [ - + ]: 89 : ret = pgp_armor_decode((uint8 *) VARDATA_ANY(data), data_len, &buf);
3489 heikki.linnakangas@i 892 [ + + ]: 89 : if (ret < 0)
2687 893 : 1 : px_THROW_ERROR(ret);
3489 894 : 88 : res = palloc(VARHDRSZ + buf.len);
895 : 88 : SET_VARSIZE(res, VARHDRSZ + buf.len);
896 : 88 : memcpy(VARDATA(res), buf.data, buf.len);
897 : 88 : pfree(buf.data);
898 : :
6853 bruce@momjian.us 899 [ + + ]: 88 : PG_FREE_IF_COPY(data, 0);
900 : 88 : PG_RETURN_TEXT_P(res);
901 : : }
902 : :
903 : : /* cross-call state for pgp_armor_headers */
904 : : typedef struct
905 : : {
906 : : int nheaders;
907 : : char **keys;
908 : : char **values;
909 : : } pgp_armor_headers_state;
910 : :
911 : : Datum
3483 heikki.linnakangas@i 912 : 37 : pgp_armor_headers(PG_FUNCTION_ARGS)
913 : : {
914 : : FuncCallContext *funcctx;
915 : : pgp_armor_headers_state *state;
916 : : char *utf8key;
917 : : char *utf8val;
918 : : HeapTuple tuple;
919 : : TupleDesc tupdesc;
920 : : AttInMetadata *attinmeta;
921 : :
922 [ + + ]: 37 : if (SRF_IS_FIRSTCALL())
923 : : {
924 : 14 : text *data = PG_GETARG_TEXT_PP(0);
925 : : int res;
926 : : MemoryContext oldcontext;
927 : :
928 : 14 : funcctx = SRF_FIRSTCALL_INIT();
929 : :
930 : : /* we need the state allocated in the multi call context */
931 : 14 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
932 : :
933 : : /* Build a tuple descriptor for our result type */
934 [ - + ]: 14 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3483 heikki.linnakangas@i 935 [ # # ]:UBC 0 : elog(ERROR, "return type must be a row type");
936 : :
3483 heikki.linnakangas@i 937 :CBC 14 : attinmeta = TupleDescGetAttInMetadata(tupdesc);
938 : 14 : funcctx->attinmeta = attinmeta;
939 : :
940 : 14 : state = (pgp_armor_headers_state *) palloc(sizeof(pgp_armor_headers_state));
941 : :
942 [ - + ]: 14 : res = pgp_extract_armor_headers((uint8 *) VARDATA_ANY(data),
943 [ - + - - : 14 : VARSIZE_ANY_EXHDR(data),
- - - - -
+ ]
944 : : &state->nheaders, &state->keys,
945 : : &state->values);
946 [ + + ]: 14 : if (res < 0)
2687 947 : 2 : px_THROW_ERROR(res);
948 : :
3483 949 : 12 : MemoryContextSwitchTo(oldcontext);
950 : 12 : funcctx->user_fctx = state;
951 : : }
952 : :
953 : 35 : funcctx = SRF_PERCALL_SETUP();
954 : 35 : state = (pgp_armor_headers_state *) funcctx->user_fctx;
955 : :
956 [ + + ]: 35 : if (funcctx->call_cntr >= state->nheaders)
957 : 12 : SRF_RETURN_DONE(funcctx);
958 : : else
959 : : {
960 : : char *values[2];
961 : :
962 : : /* we assume that the keys (and values) are in UTF-8. */
963 : 23 : utf8key = state->keys[funcctx->call_cntr];
964 : 23 : utf8val = state->values[funcctx->call_cntr];
965 : :
966 : 23 : values[0] = pg_any_to_server(utf8key, strlen(utf8key), PG_UTF8);
967 : 23 : values[1] = pg_any_to_server(utf8val, strlen(utf8val), PG_UTF8);
968 : :
969 : : /* build a tuple */
970 : 23 : tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
971 : 23 : SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
972 : : }
973 : : }
974 : :
975 : :
976 : :
977 : : /*
978 : : * Wrappers for PGP key id
979 : : */
980 : :
981 : : Datum
6853 bruce@momjian.us 982 : 17 : pgp_key_id_w(PG_FUNCTION_ARGS)
983 : : {
984 : : bytea *data;
985 : : text *res;
986 : : int res_len;
987 : : MBuf *buf;
988 : :
2590 noah@leadboat.com 989 : 17 : data = PG_GETARG_BYTEA_PP(0);
6853 bruce@momjian.us 990 : 17 : buf = create_mbuf_from_vardata(data);
991 : 17 : res = palloc(VARHDRSZ + 17);
992 : :
993 : 17 : res_len = pgp_get_keyid(buf, VARDATA(res));
994 : 17 : mbuf_free(buf);
995 [ + + ]: 17 : if (res_len < 0)
2687 heikki.linnakangas@i 996 : 2 : px_THROW_ERROR(res_len);
6256 tgl@sss.pgh.pa.us 997 : 15 : SET_VARSIZE(res, VARHDRSZ + res_len);
998 : :
6853 bruce@momjian.us 999 [ - + ]: 15 : PG_FREE_IF_COPY(data, 0);
1000 : 15 : PG_RETURN_TEXT_P(res);
1001 : : }
|