Fix some error handling, json support, keyring handling.

This commit is contained in:
mlelstv 2018-11-13 14:52:30 +00:00
parent 9f7f145236
commit 3118701f5e
9 changed files with 356 additions and 172 deletions

View File

@ -57,7 +57,7 @@
#if defined(__NetBSD__)
__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: keyring.c,v 1.55 2017/03/27 21:19:12 khorben Exp $");
__RCSID("$NetBSD: keyring.c,v 1.56 2018/11/13 14:52:30 mlelstv Exp $");
#endif
#ifdef HAVE_FCNTL_H
@ -456,10 +456,12 @@ copy_packet(pgp_subpacket_t *dst, const pgp_subpacket_t *src)
}
if ((dst->raw = calloc(1, src->length)) == NULL) {
(void) fprintf(stderr, "copy_packet: bad alloc\n");
dst->length = 0;
} else {
dst->length = src->length;
(void) memcpy(dst->raw, src->raw, src->length);
}
dst->tag = src->tag;
return dst;
}
@ -500,7 +502,6 @@ pgp_add_subpacket(pgp_key_t *keydata, const pgp_subpacket_t *packet)
EXPAND_ARRAY(keydata, packet);
/* initialise new entry in array */
subpktp = &keydata->packets[keydata->packetc++];
subpktp->length = 0;
subpktp->raw = NULL;
/* now copy it */
return copy_packet(subpktp, packet);
@ -545,6 +546,7 @@ pgp_add_selfsigned_userid(pgp_key_t *key, uint8_t *userid)
/* add this packet to key */
sigpacket.length = pgp_mem_len(mem_sig);
sigpacket.raw = pgp_mem_data(mem_sig);
sigpacket.tag = PGP_PTAG_CT_SIGNATURE;
/* add userid to key */
(void) pgp_add_userid(key, userid);
@ -596,13 +598,14 @@ cb_keyring_read(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
cb = pgp_callback_arg(cbinfo);
keyring = cb->keyring;
key = keyring->keyc > 0 ? &keyring->keys[keyring->keyc - 1] : NULL;
switch (pkt->tag) {
case PGP_PARSER_PTAG:
case PGP_PTAG_CT_ENCRYPTED_SECRET_KEY:
/* we get these because we didn't prompt */
break;
case PGP_PTAG_CT_SIGNATURE_HEADER:
key = &keyring->keys[keyring->keyc - 1];
EXPAND_ARRAY(key, subsig);
key->subsigs[key->subsigc].uid = key->uidc - 1;
(void) memcpy(&key->subsigs[key->subsigc].sig, &pkt->u.sig,
@ -610,7 +613,6 @@ cb_keyring_read(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
key->subsigc += 1;
break;
case PGP_PTAG_CT_SIGNATURE:
key = &keyring->keys[keyring->keyc - 1];
EXPAND_ARRAY(key, subsig);
key->subsigs[key->subsigc].uid = key->uidc - 1;
(void) memcpy(&key->subsigs[key->subsigc].sig, &pkt->u.sig,
@ -618,7 +620,6 @@ cb_keyring_read(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
key->subsigc += 1;
break;
case PGP_PTAG_CT_TRUST:
key = &keyring->keys[keyring->keyc - 1];
key->subsigs[key->subsigc - 1].trustlevel = pkt->u.ss_trust.level;
key->subsigs[key->subsigc - 1].trustamount = pkt->u.ss_trust.amount;
break;
@ -629,28 +630,23 @@ cb_keyring_read(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
}
break;
case PGP_PTAG_SS_ISSUER_KEY_ID:
key = &keyring->keys[keyring->keyc - 1];
(void) memcpy(&key->subsigs[key->subsigc - 1].sig.info.signer_id,
pkt->u.ss_issuer,
sizeof(pkt->u.ss_issuer));
key->subsigs[key->subsigc - 1].sig.info.signer_id_set = 1;
break;
case PGP_PTAG_SS_CREATION_TIME:
key = &keyring->keys[keyring->keyc - 1];
key->subsigs[key->subsigc - 1].sig.info.birthtime = pkt->u.ss_time;
key->subsigs[key->subsigc - 1].sig.info.birthtime_set = 1;
break;
case PGP_PTAG_SS_EXPIRATION_TIME:
key = &keyring->keys[keyring->keyc - 1];
key->subsigs[key->subsigc - 1].sig.info.duration = pkt->u.ss_time;
key->subsigs[key->subsigc - 1].sig.info.duration_set = 1;
break;
case PGP_PTAG_SS_PRIMARY_USER_ID:
key = &keyring->keys[keyring->keyc - 1];
key->uid0 = key->uidc - 1;
break;
case PGP_PTAG_SS_REVOCATION_REASON:
key = &keyring->keys[keyring->keyc - 1];
if (key->uidc == 0) {
/* revoke whole key */
key->revoked = 1;
@ -668,7 +664,6 @@ cb_keyring_read(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
case PGP_PTAG_CT_SIGNATURE_FOOTER:
case PGP_PARSER_ERRCODE:
break;
default:
break;
}
@ -812,6 +807,77 @@ pgp_keyring_read_from_mem(pgp_io_t *io,
return res;
}
/**
\ingroup HighLevel_KeyringWrite
\brief Writes a keyring to a file
\param keyring Pointer to an existing pgp_keyring_t struct
\param armour 1 if file is armoured; else 0
\param filename Filename of keyring to be written
\return pgp 1 if OK; 0 on error
\note Keyring struct must already exist.
\note Can be used with either a public or secret keyring.
*/
unsigned
pgp_keyring_filewrite(pgp_keyring_t *keyring,
unsigned armour,
const char *filename,
uint8_t *passphrase)
{
pgp_output_t *output;
int fd;
unsigned res = 1;
pgp_key_t *key;
unsigned n;
unsigned keyc = (keyring != NULL) ? keyring->keyc : 0;
char *cp;
pgp_content_enum type;
pgp_armor_type_t atype;
char keyid[PGP_KEY_ID_SIZE * 3];
fd = pgp_setup_file_write(&output, filename, 1);
if (fd < 0) {
perror(filename);
return 0;
}
type = keyring->keyc > 0 ? keyring->keys->type : PGP_PTAG_CT_PUBLIC_KEY;
if (armour) {
if (type == PGP_PTAG_CT_PUBLIC_KEY)
atype = PGP_PGP_PUBLIC_KEY_BLOCK;
else
atype = PGP_PGP_PRIVATE_KEY_BLOCK;
pgp_writer_push_armoured(output, atype);
}
for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) {
/* write only keys of a single type */
if (key->type != type) {
(void) fprintf(stderr, "ERROR: skip key %d\n", n);
continue;
}
if (key->type == PGP_PTAG_CT_PUBLIC_KEY) {
pgp_write_xfer_pubkey(output, key, 0);
} else {
pgp_write_xfer_seckey(output, key, passphrase,
strlen((char *)passphrase), 0);
}
}
if (armour) {
pgp_writer_info_finalise(&output->errors, &output->writer);
pgp_writer_pop(output);
}
pgp_teardown_file_write(output, fd);
return res;
}
/**
\ingroup HighLevel_KeyringRead
@ -1030,7 +1096,8 @@ pgp_keyring_list(pgp_io_t *io, const pgp_keyring_t *keyring, const int psigs)
pgp_print_keydata(io, keyring, key, "sec",
&key->key.seckey.pubkey, 0);
} else {
pgp_print_keydata(io, keyring, key, "signature ", &key->key.pubkey, psigs);
pgp_print_keydata(io, keyring, key, "pub",
&key->key.pubkey, psigs);
}
(void) fputc('\n', io->res);
}
@ -1059,7 +1126,7 @@ pgp_keyring_json(pgp_io_t *io, const pgp_keyring_t *keyring, mj_t *obj, const in
"sec", &key->key.seckey.pubkey, psigs);
} else {
pgp_sprint_mj(io, keyring, key, &obj->value.v[obj->c],
"signature ", &key->key.pubkey, psigs);
"pub", &key->key.pubkey, psigs);
}
if (obj->value.v[obj->c].type != 0) {
obj->c += 1;

View File

@ -96,6 +96,8 @@ pgp_seckey_t *pgp_decrypt_seckey(const pgp_key_t *, FILE *);
unsigned pgp_keyring_fileread(pgp_keyring_t *, const unsigned,
const char *);
unsigned pgp_keyring_filewrite(pgp_keyring_t *, const unsigned,
const char *, uint8_t *);
int pgp_keyring_list(pgp_io_t *, const pgp_keyring_t *, const int);
int pgp_keyring_json(pgp_io_t *, const pgp_keyring_t *, mj_t *, const int);
@ -110,7 +112,7 @@ unsigned pgp_is_key_supported(const pgp_key_t *);
uint8_t *pgp_add_userid(pgp_key_t *, const uint8_t *);
pgp_subpacket_t *pgp_add_subpacket(pgp_key_t *,
const pgp_subpacket_t *);
const pgp_subpacket_t *);
unsigned pgp_add_selfsigned_userid(pgp_key_t *, uint8_t *);

View File

@ -57,7 +57,7 @@
#if defined(__NetBSD__)
__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: misc.c,v 1.41 2012/03/05 02:20:18 christos Exp $");
__RCSID("$NetBSD: misc.c,v 1.42 2018/11/13 14:52:30 mlelstv Exp $");
#endif
#include <sys/types.h>
@ -110,12 +110,14 @@ accumulate_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
const pgp_contents_t *content = &pkt->u;
pgp_keyring_t *keyring;
accumulate_t *accumulate;
pgp_key_t *key;
if (pgp_get_debug_level(__FILE__)) {
(void) fprintf(stderr, "accumulate callback: packet tag %u\n", pkt->tag);
}
accumulate = pgp_callback_arg(cbinfo);
keyring = accumulate->keyring;
key = keyring->keyc > 0 ? &keyring->keys[keyring->keyc - 1] : NULL;
switch (pkt->tag) {
case PGP_PTAG_CT_PUBLIC_KEY:
case PGP_PTAG_CT_PUBLIC_SUBKEY:
@ -131,17 +133,26 @@ accumulate_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
content->userid,
keyring->keyc - 1);
}
if (keyring->keyc == 0) {
PGP_ERROR_1(cbinfo->errors, PGP_E_P_NO_USERID, "%s",
"No userid found");
if (key != NULL) {
pgp_add_userid(key, content->userid);
} else {
pgp_add_userid(&keyring->keys[keyring->keyc - 1], content->userid);
PGP_ERROR_1(cbinfo->errors, PGP_E_P_NO_USERID, "%s",
"No key for userid found");
}
return PGP_KEEP_MEMORY;
case PGP_PARSER_PACKET_END:
if (keyring->keyc > 0) {
pgp_add_subpacket(&keyring->keys[keyring->keyc - 1],
&content->packet);
if (key != NULL) {
switch (content->packet.tag) {
case PGP_PTAG_CT_RESERVED:
(void) fprintf(stderr, "Invalid packet tag\n");
break;
case PGP_PTAG_CT_PUBLIC_KEY:
case PGP_PTAG_CT_USER_ID:
break;
default:
pgp_add_subpacket(key, &content->packet);
break;
}
return PGP_KEEP_MEMORY;
}
return PGP_RELEASE_MEMORY;

View File

@ -34,7 +34,7 @@
#if defined(__NetBSD__)
__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: netpgp.c,v 1.101 2017/03/27 20:55:13 khorben Exp $");
__RCSID("$NetBSD: netpgp.c,v 1.102 2018/11/13 14:52:30 mlelstv Exp $");
#endif
#include <sys/types.h>
@ -222,34 +222,125 @@ findvar(netpgp_t *netpgp, const char *name)
return (i == netpgp->c) ? -1 : (int)i;
}
/* append a key to a keyring */
static int
appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
{
pgp_output_t *create;
const unsigned noarmor = 0;
int fd;
if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
fd = pgp_setup_file_write(&create, ringfile, 0);
}
if (fd < 0) {
(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
return 0;
}
if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
(void) fprintf(io->errs, "Cannot write pubkey\n");
return 0;
}
pgp_teardown_file_write(create, fd);
return 1;
}
/* return filename of a keyring */
static char *
keyringfile(netpgp_t *netpgp, const char *name)
{
char f[MAXPATHLEN];
char *homedir;
char *filename;
homedir = netpgp_getvar(netpgp, "homedir");
filename = netpgp_getvar(netpgp, name);
if (filename == NULL || filename[0] == '\0') {
(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
filename = f;
}
return netpgp_strdup(filename);
}
/* return an empty keyring */
static void *
newkeyring(netpgp_t *netpgp, const char *name)
{
pgp_keyring_t *keyring;
char *filename;
if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
(void) fprintf(stderr, "newkeyring: bad alloc\n");
return NULL;
}
filename = keyringfile(netpgp, name);
netpgp_setvar(netpgp, name, filename);
free(filename);
return keyring;
}
/* read a keyring and return it */
static void *
readkeyring(netpgp_t *netpgp, const char *name)
{
pgp_keyring_t *keyring;
const unsigned noarmor = 0;
char f[MAXPATHLEN];
char *filename;
char *homedir;
homedir = netpgp_getvar(netpgp, "homedir");
if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
filename = f;
}
if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
(void) fprintf(stderr, "readkeyring: bad alloc\n");
return NULL;
}
filename = keyringfile(netpgp, name);
if (!pgp_keyring_fileread(keyring, noarmor, filename)) {
free(filename);
free(keyring);
(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
return NULL;
}
netpgp_setvar(netpgp, name, filename);
free(filename);
return keyring;
}
/* write a keyring */
static int
writekeyring(netpgp_t *netpgp, const char *name, pgp_keyring_t *keyring, uint8_t *passphrase)
{
const unsigned noarmor = 0;
char *filename;
filename = keyringfile(netpgp, name);
if (!pgp_keyring_filewrite(keyring, noarmor, filename, passphrase)) {
free(filename);
(void) fprintf(stderr, "Can't write %s %s\n", name, filename);
return 0;
}
netpgp_setvar(netpgp, name, filename);
free(filename);
return 1;
}
/* append key to a keyring */
static int
appendtokeyring(netpgp_t *netpgp, const char *name, pgp_key_t *key)
{
char *filename;
int ret;
filename = keyringfile(netpgp, name);
ret = appendkey(netpgp->io, key, filename);
free(filename);
return ret;
}
/* read keys from ssh key files */
static int
readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey)
@ -442,29 +533,6 @@ resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *useri
return key;
}
/* append a key to a keyring */
static int
appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
{
pgp_output_t *create;
const unsigned noarmor = 0;
int fd;
if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
fd = pgp_setup_file_write(&create, ringfile, 0);
}
if (fd < 0) {
(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
return 0;
}
if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
(void) fprintf(io->errs, "Cannot write pubkey\n");
return 0;
}
pgp_teardown_file_write(create, fd);
return 1;
}
/* return 1 if the file contains ascii-armoured text */
static unsigned
isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
@ -523,47 +591,8 @@ pobj(FILE *fp, mj_t *obj, int depth)
(void) fprintf(stderr, "No object found\n");
return;
}
for (i = 0 ; i < (unsigned)depth ; i++) {
p(fp, " ", NULL);
}
switch(obj->type) {
case MJ_NULL:
case MJ_FALSE:
case MJ_TRUE:
p(fp, (obj->type == MJ_NULL) ? "null" : (obj->type == MJ_FALSE) ? "false" : "true", NULL);
break;
case MJ_NUMBER:
p(fp, obj->value.s, NULL);
break;
case MJ_STRING:
if ((i = mj_asprint(&s, obj, MJ_HUMAN)) > 2) {
(void) fprintf(fp, "%.*s", (int)i - 2, &s[1]);
free(s);
}
break;
case MJ_ARRAY:
for (i = 0 ; i < obj->c ; i++) {
pobj(fp, &obj->value.v[i], depth + 1);
if (i < obj->c - 1) {
(void) fprintf(fp, ", ");
}
}
(void) fprintf(fp, "\n");
break;
case MJ_OBJECT:
for (i = 0 ; i < obj->c ; i += 2) {
pobj(fp, &obj->value.v[i], depth + 1);
p(fp, ": ", NULL);
pobj(fp, &obj->value.v[i + 1], 0);
if (i < obj->c - 1) {
p(fp, ", ", NULL);
}
}
p(fp, "\n", NULL);
break;
default:
break;
}
mj_pretty(obj, fp, depth, "");
}
/* return the time as a string */
@ -843,7 +872,6 @@ netpgp_init(netpgp_t *netpgp)
/* read from ordinary pgp keyrings */
netpgp->pubring = readkeyring(netpgp, "pubring");
if (netpgp->pubring == NULL) {
(void) fprintf(io->errs, "Can't read pub keyring\n");
return 0;
}
/* if a userid has been given, we'll use it */
@ -860,7 +888,6 @@ netpgp_init(netpgp_t *netpgp)
/* read the secret ring */
netpgp->secring = readkeyring(netpgp, "secring");
if (netpgp->secring == NULL) {
(void) fprintf(io->errs, "Can't read sec keyring\n");
return 0;
}
/* now, if we don't have a valid user, use the first in secring */
@ -886,7 +913,6 @@ netpgp_init(netpgp_t *netpgp)
/* read from ssh keys */
last = (netpgp->pubring != NULL);
if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
(void) fprintf(io->errs, "Can't read ssh keys\n");
return 0;
}
if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
@ -1060,7 +1086,7 @@ netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fm
id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
pgp_sprint_mj(netpgp->io, netpgp->pubring,
key, &id_array.value.v[id_array.c++],
"signature ",
"signature",
&key->key.pubkey, psigs);
}
k += 1;
@ -1153,15 +1179,52 @@ netpgp_import_key(netpgp_t *netpgp, char *f)
pgp_io_t *io;
unsigned realarmor;
int done;
pgp_keyring_t *keyring;
pgp_key_t *key;
const char *ringname;
int rv;
io = netpgp->io;
realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
done = pgp_keyring_fileread(netpgp->pubring, realarmor, f);
if (!done) {
(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
if (f == NULL) {
(void) fprintf(io->errs, "No input file given\n");
return 0;
}
return pgp_keyring_list(io, netpgp->pubring, 0);
if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
(void) fprintf(io->errs, "netpgp_import_key: bad alloc\n");
return 0;
}
realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
done = pgp_keyring_fileread(keyring, realarmor, f);
if (!done || keyring->keyc == 0) {
(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
pgp_keyring_free(keyring);
return 0;
}
done = pgp_keyring_list(io, keyring, 0);
if (!done)
return 0;
key = keyring->keys;
if (key->type == PGP_PTAG_CT_PUBLIC_KEY) {
ringname = "pubring";
} else {
ringname = "secring";
}
if (!done) {
pgp_keyring_free(keyring);
(void) fprintf(io->errs, "Bad append\n");
return 0;
}
rv = appendtokeyring(netpgp, ringname, key);
pgp_keyring_free(keyring);
return rv;
}
#define ID_OFFSET 38

View File

@ -58,7 +58,7 @@
#if defined(__NetBSD__)
__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: packet-parse.c,v 1.51 2012/03/05 02:20:18 christos Exp $");
__RCSID("$NetBSD: packet-parse.c,v 1.52 2018/11/13 14:52:30 mlelstv Exp $");
#endif
#include <sys/types.h>
@ -866,6 +866,7 @@ pgp_subpacket_free(pgp_subpacket_t *packet)
{
free(packet->raw);
packet->raw = NULL;
packet->tag = PGP_PTAG_CT_RESERVED;
}
/**
@ -3066,11 +3067,12 @@ parse_mdc(pgp_region_t *region, pgp_stream_t *stream)
static int
parse_packet(pgp_stream_t *stream, uint32_t *pktlen)
{
pgp_packet_t pkt;
pgp_region_t region;
uint8_t ptag;
unsigned indeterminate = 0;
int ret;
pgp_packet_t pkt;
pgp_region_t region;
pgp_content_enum tag;
uint8_t ptag;
unsigned indeterminate = 0;
int ret;
pkt.u.ptag.position = stream->readinfo.position;
@ -3142,6 +3144,9 @@ parse_packet(pgp_stream_t *stream, uint32_t *pktlen)
(void) fprintf(stderr, "parse_packet: type %u\n",
pkt.u.ptag.type);
}
/* save tag for accumulator */
tag = pkt.u.ptag.type;
switch (pkt.u.ptag.type) {
case PGP_PTAG_CT_SIGNATURE:
ret = parse_sig(&region, stream);
@ -3232,6 +3237,7 @@ parse_packet(pgp_stream_t *stream, uint32_t *pktlen)
if (ret > 0 && stream->readinfo.accumulate) {
pkt.u.packet.length = stream->readinfo.alength;
pkt.u.packet.raw = stream->readinfo.accumulated;
pkt.u.packet.tag = tag;
stream->readinfo.accumulated = NULL;
stream->readinfo.asize = 0;
CALLBACK(PGP_PARSER_PACKET_END, &stream->cbinfo, &pkt);

View File

@ -675,6 +675,7 @@ typedef struct pgp_ss_sig_target_t {
/** pgp_subpacket_t */
typedef struct pgp_subpacket_t {
pgp_content_enum tag;
size_t length;
uint8_t *raw;
} pgp_subpacket_t;

View File

@ -1,4 +1,4 @@
.\" $NetBSD: libmj.3,v 1.9 2018/04/04 21:39:35 sevan Exp $
.\" $NetBSD: libmj.3,v 1.10 2018/11/13 14:52:30 mlelstv Exp $
.\"
.\" Copyright (c) 2010 Alistair Crooks <agc@NetBSD.org>
.\" All rights reserved.
@ -161,7 +161,7 @@ function is used.
The calling interface gives the ability to indent the
output to a given
.Fa depth
and for the formatted output to be followed by a
in characters and for the formatted output to be followed by a
.Fa trailer
string, which is usually
.Dv NULL

View File

@ -35,9 +35,16 @@
#include "mj.h"
#include "defs.h"
/* save 'n' chars of 's' in malloc'd memory */
#define JSON_ESCAPE '\xac'
#define JSON_INDENT 4
/*
* save 'n' chars of 's' in malloc'd memory
*
* optionally encode embedded quotes and null bytes
*/
static char *
strnsave(const char *s, int n, unsigned encoded)
strnsave(const char *s, int n, int encoded)
{
char *newc;
char *cp;
@ -47,19 +54,20 @@ strnsave(const char *s, int n, unsigned encoded)
n = (int)strlen(s);
}
NEWARRAY(char, cp, n + n + 1, "strnsave", return NULL);
if (encoded) {
switch (encoded) {
case MJ_JSON_ENCODE:
newc = cp;
for (i = 0 ; i < n ; i++) {
if ((uint8_t)*s == 0xac) {
*newc++ = (char)0xac;
if (*s == JSON_ESCAPE) {
*newc++ = JSON_ESCAPE;
*newc++ = '1';
s += 1;
} else if (*s == '"') {
*newc++ = (char)0xac;
*newc++ = JSON_ESCAPE;
*newc++ = '2';
s += 1;
} else if (*s == 0x0) {
*newc++ = (char)0xac;
*newc++ = JSON_ESCAPE;
*newc++ = '0';
s += 1;
} else {
@ -67,9 +75,11 @@ strnsave(const char *s, int n, unsigned encoded)
}
}
*newc = 0x0;
} else {
break;
default:
(void) memcpy(cp, s, (unsigned)n);
cp[n] = 0x0;
break;
}
return cp;
}
@ -168,7 +178,7 @@ indent(FILE *fp, unsigned depth, const char *trailer)
unsigned i;
for (i = 0 ; i < depth ; i++) {
(void) fprintf(fp, " ");
(void) fprintf(fp, " ");
}
if (trailer) {
(void) fprintf(fp, "%s", trailer);
@ -225,7 +235,11 @@ mj_create(mj_t *atom, const char *type, ...)
return 1;
}
/* put a JSON tree into a text string */
/*
* put a JSON tree into a text string
*
* optionally keep encoded quotes and null bytes
*/
int
mj_snprint(char *buf, size_t size, mj_t *atom, int encoded)
{
@ -244,55 +258,66 @@ mj_snprint(char *buf, size_t size, mj_t *atom, int encoded)
case MJ_NUMBER:
return snprintf(buf, size, "%s", atom->value.s);
case MJ_STRING:
if (encoded) {
if (size < 3)
return 0;
switch (encoded) {
case MJ_JSON_ENCODE:
return snprintf(buf, size, "\"%s\"", atom->value.s);
}
for (bp = buf, *bp++ = '"', s = atom->value.s ;
(size_t)(bp - buf) < size && (unsigned)(s - atom->value.s) < atom->c ; ) {
if ((uint8_t)*s == 0xac) {
switch(s[1]) {
case '0':
*bp++ = 0x0;
s += 2;
break;
case '1':
*bp++ = (char)0xac;
s += 2;
break;
case '2':
*bp++ = '"';
s += 2;
break;
default:
(void) fprintf(stderr, "unrecognised character '%02x'\n", (uint8_t)s[1]);
s += 1;
break;
default:
for (bp = buf, *bp++ = '"', s = atom->value.s ;
(size_t)(bp - buf) < size - 2 && (unsigned)(s - atom->value.s) < atom->c ; ) {
if (*s == JSON_ESCAPE) {
switch(s[1]) {
case '0':
if ((size_t)(bp - buf) < size - 3)
break;
*bp++ = '\\';
*bp++ = '0';
s += 2;
break;
case '1':
*bp++ = JSON_ESCAPE;
s += 2;
break;
case '2':
if ((size_t)(bp - buf) < size - 3)
break;
*bp++ = '\\';
*bp++ = '"';
s += 2;
break;
default:
(void) fprintf(stderr, "unrecognised character '%02x'\n", (uint8_t)s[1]);
s += 1;
break;
}
} else {
*bp++ = *s++;
}
} else {
*bp++ = *s++;
}
*bp++ = '"';
*bp = 0x0;
return bp - buf;
}
*bp++ = '"';
*bp = 0x0;
return (int)(bp - buf) - 1;
break;
case MJ_ARRAY:
cc = snprintf(buf, size, "[ ");
for (i = 0 ; i < atom->c ; i++) {
const char *sep = i+1 < atom->c ? ", " : " ";
cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i], encoded);
if (i < atom->c - 1) {
cc += snprintf(&buf[cc], size - cc, ", ");
}
cc += snprintf(&buf[cc], size - cc, "%s", sep);
}
return cc + snprintf(&buf[cc], size - cc, "]\n");
case MJ_OBJECT:
cc = snprintf(buf, size, "{ ");
for (i = 0 ; i < atom->c ; i += 2) {
for (i = 0 ; i < atom->c - 1; i += 2) {
const char *sep = i+2 < atom->c ? ", " : " ";
cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i], encoded);
cc += snprintf(&buf[cc], size - cc, ":");
cc += mj_snprint(&buf[cc], size - cc, &atom->value.v[i + 1], encoded);
if (i + 1 < atom->c - 1) {
cc += snprintf(&buf[cc], size - cc, ", ");
}
cc += snprintf(&buf[cc], size - cc, "%s", sep);
}
return cc + snprintf(&buf[cc], size - cc, "}\n");
default:
@ -305,13 +330,13 @@ mj_snprint(char *buf, size_t size, mj_t *atom, int encoded)
int
mj_asprint(char **buf, mj_t *atom, int encoded)
{
int size;
size_t size;
size = mj_string_size(atom);
if ((*buf = calloc(1, (unsigned)(size + 1))) == NULL) {
size = mj_string_size(atom) + 1;
if ((*buf = calloc(1, size)) == NULL) {
return -1;
}
return mj_snprint(*buf, (unsigned)(size + 1), atom, encoded) + 1;
return mj_snprint(*buf, size, atom, encoded);
}
/* read into a JSON tree from a string */
@ -322,11 +347,11 @@ mj_parse(mj_t *atom, const char *s, int *from, int *to, int *tok)
switch(atom->type = *tok = gettok(s, from, to, tok)) {
case MJ_NUMBER:
atom->value.s = strnsave(&s[*from], *to - *from, MJ_JSON_ENCODE);
atom->value.s = strnsave(&s[*from], *to - *from, MJ_HUMAN);
atom->c = atom->size = (unsigned)strlen(atom->value.s);
return gettok(s, from, to, tok);
case MJ_STRING:
atom->value.s = strnsave(&s[*from + 1], *to - *from - 2, MJ_HUMAN);
atom->value.s = strnsave(&s[*from + 1], *to - *from - 2, MJ_JSON_ENCODE);
atom->c = atom->size = (unsigned)strlen(atom->value.s);
return gettok(s, from, to, tok);
case MJ_NULL:
@ -460,29 +485,35 @@ mj_string_size(mj_t *atom)
switch(atom->type) {
case MJ_NULL:
case MJ_TRUE:
/* true */
return 4;
case MJ_FALSE:
/* false */
return 5;
case MJ_NUMBER:
return atom->c;
case MJ_STRING:
/* "string" */
return atom->c + 2;
case MJ_ARRAY:
/* start '[ ' */
for (cc = 2, i = 0 ; i < atom->c ; i++) {
cc += mj_string_size(&atom->value.v[i]);
if (i < atom->c - 1) {
cc += 2;
}
/* separator ', ' or ' ' */
cc += (i < atom->c - 1) ? 2 : 1;
}
return cc + 1 + 1;
/* end ']' */
return cc + 1;
case MJ_OBJECT:
/* start '{ ' */
for (cc = 2, i = 0 ; i < atom->c ; i += 2) {
/* key:value */
cc += mj_string_size(&atom->value.v[i]) + 1 + mj_string_size(&atom->value.v[i + 1]);
if (i + 1 < atom->c - 1) {
cc += 2;
}
/* separator ', ' or ' ' */
cc += (i < atom->c - 1) ? 2 : 1;
}
return cc + 1 + 1;
/* end '}' */
return cc + 1;
default:
(void) fprintf(stderr, "mj_string_size: weird type %d\n", atom->type);
return 0;
@ -607,20 +638,20 @@ mj_pretty(mj_t *mj, void *vp, unsigned depth, const char *trailer)
case MJ_STRING:
indent(fp, depth, NULL);
mj_asprint(&s, mj, MJ_HUMAN);
(void) fprintf(fp, "\"%s\"", s);
(void) fprintf(fp, "%s", s);
free(s);
break;
case MJ_ARRAY:
indent(fp, depth, "[\n");
for (i = 0 ; i < mj->c ; i++) {
mj_pretty(&mj->value.v[i], fp, depth + 1, (i < mj->c - 1) ? ",\n" : "\n");
mj_pretty(&mj->value.v[i], fp, depth + JSON_INDENT, (i < mj->c - 1) ? ",\n" : "\n");
}
indent(fp, depth, "]");
break;
case MJ_OBJECT:
indent(fp, depth, "{\n");
for (i = 0 ; i < mj->c ; i += 2) {
mj_pretty(&mj->value.v[i], fp, depth + 1, " : ");
mj_pretty(&mj->value.v[i], fp, depth + JSON_INDENT, " : ");
mj_pretty(&mj->value.v[i + 1], fp, 0, (i < mj->c - 2) ? ",\n" : "\n");
}
indent(fp, depth, "}");

View File

@ -454,6 +454,9 @@ main(int argc, char **argv)
netpgp_set_homedir(&netpgp, getenv("HOME"),
netpgp_getvar(&netpgp, "ssh keys") ? "/.ssh" : "/.gnupg", 1);
}
if (p.keyring[0] != '\0') {
netpgp_setvar(&netpgp, "pubring", p.keyring);
}
/* initialise, and read keys from file */
if (!netpgp_init(&netpgp)) {
if (stat(netpgp_getvar(&netpgp, "homedir"), &st) < 0) {