commit 54e746873cd7358219b93a6ba83189bfe3b707d7
parent 8eb3464d70f61342965f27db47e0725da3258257
Author: lash <dev@holbrook.no>
Date: Sun, 30 Mar 2025 22:45:57 +0100
Elimiate memory leaks
Diffstat:
11 files changed, 188 insertions(+), 35 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -9,3 +9,5 @@ build/
*.tar.gz
*.so
*.a
+vgcore.*
+a.out
diff --git a/src/cli/Makefile b/src/cli/Makefile
@@ -0,0 +1,10 @@
+INCLUDES := -I.. -I../lq -I../aux/include
+CFLAGS += $(INCLUDES) -Wall
+OBJFILES += ../asn1/*.o ../*.o ../lq/*.o ../store/file.o ../mem/std.o ../io/std.o ../crypto/gcrypt.o
+LIBS := `pkg-config --libs libtasn1 libgcrypt libxdg-basedir` -L../aux/lib -llash -lcwalk
+LDFLAGS += -L../aux/lib -L../ $(LIBS)
+
+all:
+ gcc $(CFLAGS) main.c -o a.out $(OBJFILES) $(LDFLAGS)
+
+.PHONY: clean asn1 aux
diff --git a/src/cli/main.c b/src/cli/main.c
@@ -0,0 +1,72 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <basedir.h>
+#include <cwalk.h>
+
+#include <lq/base.h>
+#include <lq/crypto.h>
+#include <lq/config.h>
+#include <lq/io.h>
+#include <lq/err.h>
+
+static xdgHandle xdg;
+static LQPrivKey *pk;
+
+
+int lq_ui_init() {
+ int r;
+ char *path[8];
+ char outpath[LQ_PATH_MAX];
+
+ xdgInitHandle(&xdg);
+ lq_init();
+
+ path[0] = (char*)xdgCacheHome(&xdg);
+ path[1] = "libqaeda";
+ path[2] = NULL;
+ cwk_path_join_multiple((const char**)path, outpath, LQ_PATH_MAX);
+ ensuredir(outpath);
+
+ r = lq_config_set(LQ_CFG_DIR_BASE, outpath);
+ if (r) {
+ return ERR_FAIL;
+ }
+ r = lq_config_set(LQ_CFG_DIR_DATA, outpath);
+ if (r) {
+ return ERR_FAIL;
+ }
+ r = lq_crypto_init(outpath);
+ if (r) {
+ return ERR_FAIL;
+ }
+
+ return ERR_OK;
+}
+
+void lq_ui_free() {
+ xdgWipeHandle(&xdg);
+ lq_crypto_free();
+ lq_finish();
+}
+
+static LQPrivKey *get_key(const char *passphrase) {
+ return lq_privatekey_load(passphrase, strlen(passphrase), NULL);
+}
+
+int main(int argc, char **argv) {
+ int r;
+
+ r = lq_ui_init();
+ if (r) {
+ return 1;
+ }
+ pk = get_key(*(argv+1));
+ if (pk == NULL) {
+ lq_ui_free();
+ return 1;
+ }
+
+ lq_privatekey_free(pk);
+ lq_ui_free();
+}
diff --git a/src/crypto/gcrypt.c b/src/crypto/gcrypt.c
@@ -41,7 +41,7 @@ struct gpg_store {
};
/// store gpg library version.
-static const char *gpg_version = NULL;
+static char *gpg_version = NULL;
/// directory holding crypto keys.
static int gpg_cfg_idx_dir;
@@ -67,30 +67,33 @@ static LQStore *gpg_key_store;
*/
int lq_crypto_init(const char *base) {
int r;
- int l;
- char *v;
+ int l = 0;
+ char *p = NULL;
char path[LQ_PATH_MAX];
if (gpg_version == NULL) {
- v = (char*)gcry_check_version(GPG_MIN_VERSION);
- if (v == NULL) {
- return ERR_NOCRYPTO;
+ gpg_version = (char*)gcry_check_version(GPG_MIN_VERSION);
+ if (gpg_version == NULL) {
+ return debug_logerr(LLOG_ERROR, ERR_NOCRYPTO, "broken");
+ }
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
+ return debug_logerr(LLOG_ERROR, ERR_NOCRYPTO, "init gcrypt");
}
}
- gpg_version = v;
debug_x(LLOG_DEBUG, "gpg", "using gpg", 1, MORGEL_TYP_STR, 0, "version", gpg_version);
//gpg_passphrase_digest_len = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
gpg_passphrase_digest_len = gcry_md_get_algo_dlen(GCRY_MD_SHA512);
gpg_cfg_idx_dir = lq_config_register(LQ_TYP_STR, "CRYPTODIR");
- v = path;
+ p = path;
l = strlen(base);
- lq_cpy(v, base, l);
- v += l;
- if (*v != '/') {
- *v = '/';
- *(v+1) = 0;
+ lq_cpy(p, base, l);
+ p += l;
+ if (*p != '/') {
+ *p = '/';
+ *(p+1) = 0;
}
r = lq_config_set(gpg_cfg_idx_dir, path);
@@ -291,27 +294,33 @@ int lq_digest(const char *in, size_t in_len, char *out) {
/// Apply public key to the gpg_store struct.
-static int key_apply_public(struct gpg_store *gpg, gcry_sexp_t key) {
+static int key_apply_public(struct gpg_store *gpg) {
char *p;
size_t c;
- gcry_sexp_t pubkey;
+ gcry_sexp_t one;
+ gcry_sexp_t two;
- pubkey = gcry_sexp_find_token(key, "public-key", 10);
- if (pubkey == NULL) {
+ one = gcry_sexp_find_token(gpg->k, "public-key", 10);
+ if (one == NULL) {
return debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "sexp pubkey");
}
- pubkey = gcry_sexp_find_token(pubkey, "q", 1);
- if (pubkey == NULL) {
+ two = gcry_sexp_find_token(one, "q", 1);
+ if (two == NULL) {
+ gcry_sexp_release(one);
return debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "sexp q");
}
c = LQ_PUBKEY_LEN;
- p = (char*)gcry_sexp_nth_data(pubkey, 1, &c);
+ p = (char*)gcry_sexp_nth_data(two, 1, &c);
if (p == NULL) {
+ gcry_sexp_release(two);
+ gcry_sexp_release(one);
return debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "sexp first data");
}
+
lq_cpy(gpg->public_key, p, LQ_PUBKEY_LEN);
-
- p = (char*)gcry_pk_get_keygrip(key, (unsigned char*)gpg->fingerprint);
+ gcry_sexp_release(two);
+ gcry_sexp_release(one);
+ p = (char*)gcry_pk_get_keygrip(gpg->k, (unsigned char*)gpg->fingerprint);
if (p == NULL) {
return debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "pubkey fingerprint");
}
@@ -342,7 +351,7 @@ static int key_create(struct gpg_store *gpg) {
}
// Apply the public part of the key to the underlying key structure.
- r = key_apply_public(gpg, gpg->k);
+ r = key_apply_public(gpg);
if (r) {
return debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "private create apply public");
}
@@ -627,7 +636,7 @@ static int gpg_key_load(struct gpg_store *gpg, const char *passphrase, size_t pa
return debug_logerr(LLOG_WARNING, ERR_FAIL, NULL);
}
- r = key_apply_public(gpg, gpg->k);
+ r = key_apply_public(gpg);
if (r) {
return debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "apply public key");
}
@@ -644,8 +653,19 @@ LQPrivKey* lq_privatekey_load(const char *passphrase, size_t passphrase_len, con
struct gpg_store *gpg;
int r;
- gpg = lq_alloc(sizeof(struct gpg_store));
- lq_zero(gpg, sizeof(struct gpg_store));
+ pk = lq_alloc(sizeof(LQPrivKey));
+ if (pk == NULL) {
+ debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "allocate object");
+ return NULL;
+ }
+ pk->impl = (struct gpg_store*)lq_alloc(sizeof(struct gpg_store));
+ if (pk->impl == NULL) {
+ lq_free(pk);
+ debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "allocate internal structure");
+ return NULL;
+ }
+ lq_zero(pk->impl, sizeof(struct gpg_store));
+ gpg = (struct gpg_store*)pk->impl;
m = GPG_FIND_ORCREATE;
if (fingerprint != NULL) {
lq_cpy(gpg->fingerprint, fingerprint, LQ_FP_LEN);
@@ -653,12 +673,13 @@ LQPrivKey* lq_privatekey_load(const char *passphrase, size_t passphrase_len, con
}
r = gpg_key_load(gpg, passphrase, passphrase_len, m, NULL);
if (r) {
+ lq_free(pk->impl);
+ lq_free(pk);
+ debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "key load fail");
return NULL;
}
- pk = lq_alloc(sizeof(LQPrivKey));
pk->key_typ = GPG_KEY_TYP;
pk->key_state = LQ_KEY_INIT;
- pk->impl = gpg;
return pk;
}
@@ -882,11 +903,20 @@ int lq_signature_verify(LQSig *sig, const char *data, size_t data_len) {
}
void lq_privatekey_free(LQPrivKey *pk) {
+ struct gpg_store *gpg;
+
+ gpg = (struct gpg_store*)pk->impl;
+ gcry_sexp_release(gpg->k);
lq_free(pk->impl);
lq_free(pk);
}
void lq_publickey_free(LQPubKey *pubk) {
+ struct gpg_store *gpg;
+
+ gpg = (struct gpg_store*)pubk->impl;
+ gcry_sexp_release(gpg->k);
+ lq_free(pubk->impl);
lq_free(pubk);
}
@@ -906,6 +936,7 @@ LQPubKey* lq_publickey_from_privatekey(LQPrivKey *pk) {
}
LQPubKey* lq_publickey_new(const char *full) {
+ const char *p;
const char *r;
gcry_error_t e;
size_t c;
@@ -919,12 +950,15 @@ LQPubKey* lq_publickey_new(const char *full) {
c = 0;
e = gcry_sexp_build(&gpg->k, &c, "(key-data(public-key(ecc(curve Ed25519)(q %b))))", LQ_PUBKEY_LEN, full);
if (e != GPG_ERR_NO_ERROR) {
+ p = gcry_strerror(e);
+ debug_logerr(LLOG_DEBUG, ERR_KEYFAIL, (char*)p);
return NULL;
}
lq_cpy(gpg->public_key, full, LQ_PUBKEY_LEN);
r = (char*)gcry_pk_get_keygrip(gpg->k, (unsigned char*)gpg->fingerprint);
if (r == NULL) {
+ debug_logerr(LLOG_ERROR, ERR_KEYFAIL, "fingerprint fail");
return NULL;
}
@@ -944,7 +978,9 @@ size_t lq_publickey_fingerprint(LQPubKey* pubk, char **out) {
}
void lq_crypto_free() {
- lq_free((void*)gpg_key_store);
+ lq_store_free((void*)gpg_key_store);
+ gpg_key_store = NULL;
+ gpg_version = NULL;
}
#endif
diff --git a/src/io/std.c b/src/io/std.c
@@ -4,6 +4,8 @@
#include <unistd.h>
#include <dirent.h>
#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
#include "lq/mem.h"
@@ -12,6 +14,16 @@ char *mktempdir(char *s) {
return mkdtemp(s);
}
+char *ensuredir(char *s) {
+ int r;
+
+ r = mkdir(s, S_IRWXU);
+ if (r && r != EEXIST) {
+ return NULL;
+ }
+ return s;
+}
+
int lq_open(const char *pathname, int flags, int mode) {
return open(pathname, flags, (mode_t)mode);
}
diff --git a/src/lq/base.c b/src/lq/base.c
@@ -10,3 +10,6 @@ int lq_init() {
return r;
}
+void lq_finish() {
+ lq_config_free();
+}
diff --git a/src/lq/base.h b/src/lq/base.h
@@ -2,6 +2,7 @@
#define LQ_BASE_H_
int lq_init();
+void lq_finish();
#endif // LQ_BASE_H_
diff --git a/src/lq/err.c b/src/lq/err.c
@@ -13,7 +13,7 @@ static char *_rerr[3] = {
static char *_rerr_crypto[10] = {
"",
"Crypto backend",
- "Auth fail",
+ "Key fail",
"Key storage fail",
"Sign reject",
"Resource fail",
diff --git a/src/lq/io.h b/src/lq/io.h
@@ -16,6 +16,7 @@
* @return Pointer to valid path string. NULL if directory could not be created.
*/
char* mktempdir(char *s);
+char* ensuredir(char *s);
int lq_open(const char *pathname, int flags, int mode);
int lq_read(int f, char *buf, int c);
int lq_files(const char *path, char **files, size_t files_len);
diff --git a/src/test/Makefile b/src/test/Makefile
@@ -22,11 +22,6 @@ build:
$(CC) $(CFLAGS) test_test.c -o test_test_bin $(COMMONOBJS) ../io/dummy.o ../store/mem.o $(LDFLAGS)
$(CC) $(CFLAGS) test_debug.c -o test_debug_bin $(COMMONOBJS) $(LDFLAGS)
$(CC) $(CFLAGS) test_config.c -o test_config_bin $(COMMONOBJS) $(LDFLAGS)
-# $(CC) $(CFLAGS) test_crypto.c -o test_crypto_bin ../crypto/dummy.o ../mem/std.o $(LDFLAGS)
-# $(CC) $(CFLAGS) test_msg.c -o test_msg_bin ../crypto/dummy.o ../mem/std.o ../store/dummy.o ../store/file.o ../io/std.o ../lq/msg.o $(LDFLAGS)
- #$(CC) $(CFLAGS) test_cert.c -o test_cert_bin ../crypto/dummy.o ../mem/std.o ../store/dummy.o ../store/file.o ../io/std.o ../lq/msg.o ../lq/cert.o $(LDFLAGS)
- #$(CC) $(CFLAGS) test_trust.c -o test_trust_bin ../crypto/dummy.o ../mem/std.o ../store/mem.o ../lq/trust.o -lhashmap $(LDFLAGS)
- #$(CC) $(CFLAGS) test_crypto.c -o test_crypto_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o $(LDFLAGS) -lgcrypt
$(CC) $(CFLAGS) test_crypto.c -o test_crypto_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o $(LDFLAGS) -lgcrypt
$(CC) $(CFLAGS) test_msg.c -o test_msg_bin $(COMMONOBJS) ../store/file.o ../store/dummy.o ../io/std.o ../crypto/gcrypt.o ../lq/msg.o $(LDFLAGS)
$(CC) $(CFLAGS) test_cert.c -o test_cert_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o ../store/dummy.o ../lq/msg.o ../lq/cert.o $(LDFLAGS)
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
@@ -153,6 +153,26 @@ START_TEST(check_load_specific) {
}
END_TEST
+START_TEST(check_many) {
+ LQPrivKey *pk;
+ LQPubKey *pubk;
+ LQPubKey *pubk_manual;
+ char *keydata;
+ char *keydata_manual;
+
+ pk = lq_privatekey_new(passphrase, passphrase_len);
+ ck_assert_ptr_nonnull(pk);
+ pubk = lq_publickey_from_privatekey(pk);
+ lq_publickey_bytes(pubk, &keydata);
+ pubk_manual = lq_publickey_new(keydata);
+ lq_publickey_bytes(pubk_manual, &keydata_manual);
+ ck_assert_mem_eq(keydata_manual, keydata, 65);
+ lq_publickey_free(pubk_manual);
+ lq_publickey_free(pubk);
+ lq_privatekey_free(pk);
+}
+END_TEST
+
Suite * common_suite(void) {
Suite *s;
TCase *tc;
@@ -166,6 +186,7 @@ Suite * common_suite(void) {
tcase_add_test(tc, check_verify);
tcase_add_test(tc, check_create_load);
tcase_add_test(tc, check_load_specific);
+ tcase_add_test(tc, check_many);
suite_add_tcase(s, tc);
return s;