/*
* pgp - pgsql . c
* PostgreSQL wrappers for pgp .
*
* Copyright ( c ) 2005 Marko Kreen
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1 . Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2 . Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* contrib / pgcrypto / pgp - pgsql . c
*/
#include "postgres.h"
#include "catalog/pg_type.h"
#include "common/string.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "mbuf.h"
#include "pgp.h"
#include "px.h"
#include "utils/array.h"
#include "utils/builtins.h"
/*
* public functions
*/
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
PG_FUNCTION_INFO_V1(pgp_key_id_w);
PG_FUNCTION_INFO_V1(pg_armor);
PG_FUNCTION_INFO_V1(pg_dearmor);
PG_FUNCTION_INFO_V1(pgp_armor_headers);
/*
* returns src in case of no conversion or error
*/
static text *
convert_charset(text *src, int cset_from, int cset_to)
{
int src_len = VARSIZE_ANY_EXHDR(src);
unsigned char *dst;
unsigned char *csrc = (unsigned char *) VARDATA_ANY(src);
text *res;
dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to);
if (dst == csrc)
return src;
res = cstring_to_text((char *) dst);
pfree(dst);
return res;
}
static text *
convert_from_utf8(text *src)
{
return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
}
static text *
convert_to_utf8(text *src)
{
return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
}
static void
clear_and_pfree(text *p)
{
px_memset(p, 0 , VARSIZE_ANY(p));
pfree(p);
}
/*
* expect - * arguments storage
*/
struct debug_expect
{
int debug;
int expect;
int cipher_algo;
int s2k_mode;
int s2k_count;
int s2k_cipher_algo;
int s2k_digest_algo;
int compress_algo;
int use_sess_key;
int disable_mdc;
int unicode_mode;
};
static void
fill_expect(struct debug_expect *ex, int text_mode)
{
ex->debug = 0 ;
ex->expect = 0 ;
ex->cipher_algo = -1 ;
ex->s2k_mode = -1 ;
ex->s2k_count = -1 ;
ex->s2k_cipher_algo = -1 ;
ex->s2k_digest_algo = -1 ;
ex->compress_algo = -1 ;
ex->use_sess_key = -1 ;
ex->disable_mdc = -1 ;
ex->unicode_mode = -1 ;
}
#define EX_MSG(arg) \
ereport(NOTICE, (errmsg( \
"pgp_decrypt: unexpected %s: expected %d got %d" , \
CppAsString(arg), ex->arg, ctx->arg)))
#define EX_CHECK(arg) do { \
if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
} while (0 )
static void
check_expect(PGP_Context *ctx, struct debug_expect *ex)
{
EX_CHECK(cipher_algo);
EX_CHECK(s2k_mode);
EX_CHECK(s2k_count);
EX_CHECK(s2k_digest_algo);
EX_CHECK(use_sess_key);
if (ctx->use_sess_key)
EX_CHECK(s2k_cipher_algo);
EX_CHECK(disable_mdc);
EX_CHECK(compress_algo);
EX_CHECK(unicode_mode);
}
static void
show_debug(const char *msg)
{
ereport(NOTICE, (errmsg("dbg: %s" , msg)));
}
static int
set_arg(PGP_Context *ctx, char *key, char *val,
struct debug_expect *ex)
{
int res = 0 ;
if (strcmp(key, "cipher-algo" ) == 0 )
res = pgp_set_cipher_algo(ctx, val);
else if (strcmp(key, "disable-mdc" ) == 0 )
res = pgp_disable_mdc(ctx, atoi(val));
else if (strcmp(key, "sess-key" ) == 0 )
res = pgp_set_sess_key(ctx, atoi(val));
else if (strcmp(key, "s2k-mode" ) == 0 )
res = pgp_set_s2k_mode(ctx, atoi(val));
else if (strcmp(key, "s2k-count" ) == 0 )
res = pgp_set_s2k_count(ctx, atoi(val));
else if (strcmp(key, "s2k-digest-algo" ) == 0 )
res = pgp_set_s2k_digest_algo(ctx, val);
else if (strcmp(key, "s2k-cipher-algo" ) == 0 )
res = pgp_set_s2k_cipher_algo(ctx, val);
else if (strcmp(key, "compress-algo" ) == 0 )
res = pgp_set_compress_algo(ctx, atoi(val));
else if (strcmp(key, "compress-level" ) == 0 )
res = pgp_set_compress_level(ctx, atoi(val));
else if (strcmp(key, "convert-crlf" ) == 0 )
res = pgp_set_convert_crlf(ctx, atoi(val));
else if (strcmp(key, "unicode-mode" ) == 0 )
res = pgp_set_unicode_mode(ctx, atoi(val));
/*
* The remaining options are for debugging / testing and are therefore not
* documented in the user - facing docs .
*/
else if (ex != NULL && strcmp(key, "debug" ) == 0 )
ex->debug = atoi(val);
else if (ex != NULL && strcmp(key, "expect-cipher-algo" ) == 0 )
{
ex->expect = 1 ;
ex->cipher_algo = pgp_get_cipher_code(val);
}
else if (ex != NULL && strcmp(key, "expect-disable-mdc" ) == 0 )
{
ex->expect = 1 ;
ex->disable_mdc = atoi(val);
}
else if (ex != NULL && strcmp(key, "expect-sess-key" ) == 0 )
{
ex->expect = 1 ;
ex->use_sess_key = atoi(val);
}
else if (ex != NULL && strcmp(key, "expect-s2k-mode" ) == 0 )
{
ex->expect = 1 ;
ex->s2k_mode = atoi(val);
}
else if (ex != NULL && strcmp(key, "expect-s2k-count" ) == 0 )
{
ex->expect = 1 ;
ex->s2k_count = atoi(val);
}
else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo" ) == 0 )
{
ex->expect = 1 ;
ex->s2k_digest_algo = pgp_get_digest_code(val);
}
else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo" ) == 0 )
{
ex->expect = 1 ;
ex->s2k_cipher_algo = pgp_get_cipher_code(val);
}
else if (ex != NULL && strcmp(key, "expect-compress-algo" ) == 0 )
{
ex->expect = 1 ;
ex->compress_algo = atoi(val);
}
else if (ex != NULL && strcmp(key, "expect-unicode-mode" ) == 0 )
{
ex->expect = 1 ;
ex->unicode_mode = atoi(val);
}
else
res = PXE_ARGUMENT_ERROR;
return res;
}
/*
* Find next word . Handle ' , ' and ' = ' as words . Skip whitespace .
* Put word info into res_p , res_len .
* Returns ptr to next word .
*/
static char *
getword(char *p, char **res_p, int *res_len)
{
/* whitespace at start */
while (*p && (*p == ' ' || *p == '\t' || *p == '\n' ))
p++;
/* word data */
*res_p = p;
if (*p == '=' || *p == ',' )
p++;
else
while (*p && !(*p == ' ' || *p == '\t' || *p == '\n'
|| *p == '=' || *p == ',' ))
p++;
/* word end */
*res_len = p - *res_p;
/* whitespace at end */
while (*p && (*p == ' ' || *p == '\t' || *p == '\n' ))
p++;
return p;
}
/*
* Convert to lowercase asciiz string .
*/
static char *
downcase_convert(const uint8 *s, int len)
{
int c,
i;
char *res = palloc(len + 1 );
for (i = 0 ; i < len; i++)
{
c = s[i];
if (c >= 'A' && c <= 'Z' )
c += 'a' - 'A' ;
res[i] = c;
}
res[len] = 0 ;
return res;
}
static int
parse_args(PGP_Context *ctx, uint8 *args, int arg_len,
struct debug_expect *ex)
{
char *str = downcase_convert(args, arg_len);
char *key,
*val;
int key_len,
val_len;
int res = 0 ;
char *p = str;
while (*p)
{
res = PXE_ARGUMENT_ERROR;
p = getword(p, &key, &key_len);
if (*p++ != '=' )
break ;
p = getword(p, &val, &val_len);
if (*p == '\0' )
;
else if (*p++ != ',' )
break ;
if (*key == 0 || *val == 0 || val_len == 0 )
break ;
key[key_len] = 0 ;
val[val_len] = 0 ;
res = set_arg(ctx, key, val, ex);
if (res < 0 )
break ;
}
pfree(str);
return res;
}
static MBuf *
create_mbuf_from_vardata(text *data)
{
return mbuf_create_from_data((uint8 *) VARDATA_ANY(data),
VARSIZE_ANY_EXHDR(data));
}
static void
init_work(PGP_Context **ctx_p, int is_text,
text *args, struct debug_expect *ex)
{
int err = pgp_init(ctx_p);
fill_expect(ex, is_text);
if (err == 0 && args != NULL)
err = parse_args(*ctx_p, (uint8 *) VARDATA_ANY(args),
VARSIZE_ANY_EXHDR(args), ex);
if (err)
px_THROW_ERROR(err);
if (ex->debug)
px_set_debug_handler(show_debug);
pgp_set_text_mode(*ctx_p, is_text);
}
static bytea *
encrypt_internal(int is_pubenc, int is_text,
text *data, text *key, text *args)
{
MBuf *src,
*dst;
uint8 tmp[VARHDRSZ];
uint8 *restmp;
bytea *res;
int res_len;
PGP_Context *ctx;
int err;
struct debug_expect ex;
text *tmp_data = NULL;
init_work(&ctx, is_text, args, &ex);
if (is_text && pgp_get_unicode_mode(ctx))
{
tmp_data = convert_to_utf8(data);
if (tmp_data == data)
tmp_data = NULL;
else
data = tmp_data;
}
src = create_mbuf_from_vardata(data);
dst = mbuf_create(VARSIZE_ANY(data) + 128 );
/*
* reserve room for header
*/
mbuf_append(dst, tmp, VARHDRSZ);
/*
* set key
*/
if (is_pubenc)
{
MBuf *kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf,
NULL, 0 , 0 );
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA_ANY(key),
VARSIZE_ANY_EXHDR(key));
/*
* encrypt
*/
if (err >= 0 )
err = pgp_encrypt(ctx, src, dst);
/*
* check for error
*/
if (err)
{
if (ex.debug)
px_set_debug_handler(NULL);
if (tmp_data)
clear_and_pfree(tmp_data);
pgp_free(ctx);
mbuf_free(src);
mbuf_free(dst);
px_THROW_ERROR(err);
}
/* res_len includes VARHDRSZ */
res_len = mbuf_steal_data(dst, &restmp);
res = (bytea *) restmp;
SET_VARSIZE(res, res_len);
if (tmp_data)
clear_and_pfree(tmp_data);
pgp_free(ctx);
mbuf_free(src);
mbuf_free(dst);
px_set_debug_handler(NULL);
return res;
}
static bytea *
decrypt_internal(int is_pubenc, int need_text, text *data,
text *key, text *keypsw, text *args)
{
int err;
MBuf *src = NULL,
*dst = NULL;
uint8 tmp[VARHDRSZ];
uint8 *restmp;
bytea *res;
int res_len;
PGP_Context *ctx = NULL;
struct debug_expect ex;
int got_unicode = 0 ;
init_work(&ctx, need_text, args, &ex);
src = mbuf_create_from_data((uint8 *) VARDATA_ANY(data),
VARSIZE_ANY_EXHDR(data));
dst = mbuf_create(VARSIZE_ANY(data) + 2048 );
/*
* reserve room for header
*/
mbuf_append(dst, tmp, VARHDRSZ);
/*
* set key
*/
if (is_pubenc)
{
uint8 *psw = NULL;
int psw_len = 0 ;
MBuf *kbuf;
if (keypsw)
{
psw = (uint8 *) VARDATA_ANY(keypsw);
psw_len = VARSIZE_ANY_EXHDR(keypsw);
}
kbuf = create_mbuf_from_vardata(key);
err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1 );
mbuf_free(kbuf);
}
else
err = pgp_set_symkey(ctx, (uint8 *) VARDATA_ANY(key),
VARSIZE_ANY_EXHDR(key));
/* decrypt */
if (err >= 0 )
{
err = pgp_decrypt(ctx, src, dst);
if (ex.expect)
check_expect(ctx, &ex);
/* remember the setting */
got_unicode = pgp_get_unicode_mode(ctx);
}
mbuf_free(src);
pgp_free(ctx);
if (err)
{
px_set_debug_handler(NULL);
mbuf_free(dst);
px_THROW_ERROR(err);
}
res_len = mbuf_steal_data(dst, &restmp);
mbuf_free(dst);
/* res_len includes VARHDRSZ */
res = (bytea *) restmp;
SET_VARSIZE(res, res_len);
if (need_text && got_unicode)
{
text *utf = convert_from_utf8(res);
if (utf != res)
{
clear_and_pfree(res);
res = utf;
}
}
px_set_debug_handler(NULL);
return res;
}
/*
* Wrappers for symmetric - key functions
*/
Datum
pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data;
text *arg = NULL;
text *res,
*key;
data = PG_GETARG_BYTEA_PP(0 );
key = PG_GETARG_TEXT_PP(1 );
if (PG_NARGS() > 2 )
arg = PG_GETARG_TEXT_PP(2 );
res = encrypt_internal(0 , 0 , data, key, arg);
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(arg, 2 );
PG_RETURN_TEXT_P(res);
}
Datum
pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
{
text *data,
*key;
text *arg = NULL;
text *res;
data = PG_GETARG_TEXT_PP(0 );
key = PG_GETARG_TEXT_PP(1 );
if (PG_NARGS() > 2 )
arg = PG_GETARG_TEXT_PP(2 );
res = encrypt_internal(0 , 1 , data, key, arg);
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(arg, 2 );
PG_RETURN_TEXT_P(res);
}
Datum
pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data;
text *arg = NULL;
text *res,
*key;
data = PG_GETARG_BYTEA_PP(0 );
key = PG_GETARG_TEXT_PP(1 );
if (PG_NARGS() > 2 )
arg = PG_GETARG_TEXT_PP(2 );
res = decrypt_internal(0 , 0 , data, key, NULL, arg);
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(arg, 2 );
PG_RETURN_TEXT_P(res);
}
Datum
pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
{
bytea *data;
text *arg = NULL;
text *res,
*key;
data = PG_GETARG_BYTEA_PP(0 );
key = PG_GETARG_TEXT_PP(1 );
if (PG_NARGS() > 2 )
arg = PG_GETARG_TEXT_PP(2 );
res = decrypt_internal(0 , 1 , data, key, NULL, arg);
pg_verifymbstr(VARDATA_ANY(res), VARSIZE_ANY_EXHDR(res), false );
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(arg, 2 );
PG_RETURN_TEXT_P(res);
}
/*
* Wrappers for public - key functions
*/
Datum
pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data,
*key;
text *arg = NULL;
text *res;
data = PG_GETARG_BYTEA_PP(0 );
key = PG_GETARG_BYTEA_PP(1 );
if (PG_NARGS() > 2 )
arg = PG_GETARG_TEXT_PP(2 );
res = encrypt_internal(1 , 0 , data, key, arg);
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(arg, 2 );
PG_RETURN_TEXT_P(res);
}
Datum
pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
{
bytea *key;
text *arg = NULL;
text *res,
*data;
data = PG_GETARG_TEXT_PP(0 );
key = PG_GETARG_BYTEA_PP(1 );
if (PG_NARGS() > 2 )
arg = PG_GETARG_TEXT_PP(2 );
res = encrypt_internal(1 , 1 , data, key, arg);
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(arg, 2 );
PG_RETURN_TEXT_P(res);
}
Datum
pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
{
bytea *data,
*key;
text *psw = NULL,
*arg = NULL;
text *res;
data = PG_GETARG_BYTEA_PP(0 );
key = PG_GETARG_BYTEA_PP(1 );
if (PG_NARGS() > 2 )
psw = PG_GETARG_TEXT_PP(2 );
if (PG_NARGS() > 3 )
arg = PG_GETARG_TEXT_PP(3 );
res = decrypt_internal(1 , 0 , data, key, psw, arg);
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(psw, 2 );
if (PG_NARGS() > 3 )
PG_FREE_IF_COPY(arg, 3 );
PG_RETURN_TEXT_P(res);
}
Datum
pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
{
bytea *data,
*key;
text *psw = NULL,
*arg = NULL;
text *res;
data = PG_GETARG_BYTEA_PP(0 );
key = PG_GETARG_BYTEA_PP(1 );
if (PG_NARGS() > 2 )
psw = PG_GETARG_TEXT_PP(2 );
if (PG_NARGS() > 3 )
arg = PG_GETARG_TEXT_PP(3 );
res = decrypt_internal(1 , 1 , data, key, psw, arg);
pg_verifymbstr(VARDATA_ANY(res), VARSIZE_ANY_EXHDR(res), false );
PG_FREE_IF_COPY(data, 0 );
PG_FREE_IF_COPY(key, 1 );
if (PG_NARGS() > 2 )
PG_FREE_IF_COPY(psw, 2 );
if (PG_NARGS() > 3 )
PG_FREE_IF_COPY(arg, 3 );
PG_RETURN_TEXT_P(res);
}
/*
* Wrappers for PGP ascii armor
*/
/*
* Helper function for pg_armor . Converts arrays of keys and values into
* plain C arrays , and checks that they don ' t contain invalid characters .
*/
static int
parse_key_value_arrays(ArrayType *key_array, ArrayType *val_array,
char ***p_keys, char ***p_values)
{
int nkdims = ARR_NDIM(key_array);
int nvdims = ARR_NDIM(val_array);
char **keys,
**values;
Datum *key_datums,
*val_datums;
bool *key_nulls,
*val_nulls;
int key_count,
val_count;
int i;
if (nkdims > 1 || nkdims != nvdims)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("wrong number of array subscripts" )));
if (nkdims == 0 )
return 0 ;
deconstruct_array_builtin(key_array, TEXTOID, &key_datums, &key_nulls, &key_count);
deconstruct_array_builtin(val_array, TEXTOID, &val_datums, &val_nulls, &val_count);
if (key_count != val_count)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("mismatched array dimensions" )));
keys = (char **) palloc(sizeof (char *) * key_count);
values = (char **) palloc(sizeof (char *) * val_count);
for (i = 0 ; i < key_count; i++)
{
char *v;
/* Check that the key doesn't contain anything funny */
if (key_nulls[i])
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("null value not allowed for header key" )));
v = TextDatumGetCString(key_datums[i]);
if (!pg_is_ascii(v))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("header key must not contain non-ASCII characters" )));
if (strstr(v, ": " ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("header key must not contain \" : \"" )));
if (strchr(v, '\n' ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("header key must not contain newlines" )));
keys[i] = v;
/* And the same for the value */
if (val_nulls[i])
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("null value not allowed for header value" )));
v = TextDatumGetCString(val_datums[i]);
if (!pg_is_ascii(v))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("header value must not contain non-ASCII characters" )));
if (strchr(v, '\n' ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("header value must not contain newlines" )));
values[i] = v;
}
*p_keys = keys;
*p_values = values;
return key_count;
}
Datum
pg_armor(PG_FUNCTION_ARGS)
{
bytea *data;
text *res;
int data_len;
StringInfoData buf;
int num_headers;
char **keys = NULL,
**values = NULL;
data = PG_GETARG_BYTEA_PP(0 );
data_len = VARSIZE_ANY_EXHDR(data);
if (PG_NARGS() == 3 )
{
num_headers = parse_key_value_arrays(PG_GETARG_ARRAYTYPE_P(1 ),
PG_GETARG_ARRAYTYPE_P(2 ),
&keys, &values);
}
else if (PG_NARGS() == 1 )
num_headers = 0 ;
else
elog(ERROR, "unexpected number of arguments %d" , PG_NARGS());
initStringInfo(&buf);
pgp_armor_encode((uint8 *) VARDATA_ANY(data), data_len, &buf,
num_headers, keys, values);
res = palloc(VARHDRSZ + buf.len);
SET_VARSIZE(res, VARHDRSZ + buf.len);
memcpy(VARDATA(res), buf.data, buf.len);
pfree(buf.data);
PG_FREE_IF_COPY(data, 0 );
PG_RETURN_TEXT_P(res);
}
Datum
pg_dearmor(PG_FUNCTION_ARGS)
{
text *data;
bytea *res;
int data_len;
int ret;
StringInfoData buf;
data = PG_GETARG_TEXT_PP(0 );
data_len = VARSIZE_ANY_EXHDR(data);
initStringInfo(&buf);
ret = pgp_armor_decode((uint8 *) VARDATA_ANY(data), data_len, &buf);
if (ret < 0 )
px_THROW_ERROR(ret);
res = palloc(VARHDRSZ + buf.len);
SET_VARSIZE(res, VARHDRSZ + buf.len);
memcpy(VARDATA(res), buf.data, buf.len);
pfree(buf.data);
PG_FREE_IF_COPY(data, 0 );
PG_RETURN_TEXT_P(res);
}
/* cross-call state for pgp_armor_headers */
typedef struct
{
int nheaders;
char **keys;
char **values;
} pgp_armor_headers_state;
Datum
pgp_armor_headers(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
pgp_armor_headers_state *state;
char *utf8key;
char *utf8val;
HeapTuple tuple;
TupleDesc tupdesc;
AttInMetadata *attinmeta;
if (SRF_IS_FIRSTCALL())
{
text *data = PG_GETARG_TEXT_PP(0 );
int res;
MemoryContext oldcontext;
funcctx = SRF_FIRSTCALL_INIT();
/* we need the state allocated in the multi call context */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type" );
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx->attinmeta = attinmeta;
state = (pgp_armor_headers_state *) palloc(sizeof (pgp_armor_headers_state));
res = pgp_extract_armor_headers((uint8 *) VARDATA_ANY(data),
VARSIZE_ANY_EXHDR(data),
&state->nheaders, &state->keys,
&state->values);
if (res < 0 )
px_THROW_ERROR(res);
MemoryContextSwitchTo(oldcontext);
funcctx->user_fctx = state;
}
funcctx = SRF_PERCALL_SETUP();
state = (pgp_armor_headers_state *) funcctx->user_fctx;
if (funcctx->call_cntr >= state->nheaders)
SRF_RETURN_DONE(funcctx);
else
{
char *values[2 ];
/* we assume that the keys (and values) are in UTF-8. */
utf8key = state->keys[funcctx->call_cntr];
utf8val = state->values[funcctx->call_cntr];
values[0 ] = pg_any_to_server(utf8key, strlen(utf8key), PG_UTF8);
values[1 ] = pg_any_to_server(utf8val, strlen(utf8val), PG_UTF8);
/* build a tuple */
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
}
}
/*
* Wrappers for PGP key id
*/
Datum
pgp_key_id_w(PG_FUNCTION_ARGS)
{
bytea *data;
text *res;
int res_len;
MBuf *buf;
data = PG_GETARG_BYTEA_PP(0 );
buf = create_mbuf_from_vardata(data);
res = palloc(VARHDRSZ + 17 );
res_len = pgp_get_keyid(buf, VARDATA(res));
mbuf_free(buf);
if (res_len < 0 )
px_THROW_ERROR(res_len);
SET_VARSIZE(res, VARHDRSZ + res_len);
PG_FREE_IF_COPY(data, 0 );
PG_RETURN_TEXT_P(res);
}
Messung V0.5 in Prozent C=97 H=94 G=95
¤ Dauer der Verarbeitung: 0.26 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland