summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2021-07-26 16:25:03 +0300
committerTimo Teräs <timo.teras@iki.fi>2021-07-27 14:09:38 +0300
commit9c843e4ecdfee916ec835b5d35c10b3818aba9e3 (patch)
treed2c703035bbdaa1f21ce0e8ed0cf121b7388f656
parent2d4e88aeb1690220ce57420e8d1d9de327ae901d (diff)
downloadapk-tools-9c843e4ecdfee916ec835b5d35c10b3818aba9e3.tar.gz
apk-tools-9c843e4ecdfee916ec835b5d35c10b3818aba9e3.tar.bz2
apk-tools-9c843e4ecdfee916ec835b5d35c10b3818aba9e3.tar.xz
apk-tools-9c843e4ecdfee916ec835b5d35c10b3818aba9e3.zip
Refactor .apk extraction code
This moves and isolates the tar code to tar.c. And the actual file extraction to disk is moved to extract.c. A new API is introduced and used for v2 file extraction. This essentially moves and isolates the apk_sign_ctx_* beast into extract_v2.c and offers a saner interface to handling packages. A place holder is added for v3 extraction.
-rw-r--r--src/Makefile2
-rw-r--r--src/apk_archive.h35
-rw-r--r--src/apk_database.h3
-rw-r--r--src/apk_defines.h1
-rw-r--r--src/apk_extract.h64
-rw-r--r--src/apk_package.h42
-rw-r--r--src/apk_tar.h22
-rw-r--r--src/app_add.c7
-rw-r--r--src/app_cache.c3
-rw-r--r--src/app_convdb.c1
-rw-r--r--src/app_convndx.c24
-rw-r--r--src/app_extract.c17
-rw-r--r--src/app_index.c60
-rw-r--r--src/app_manifest.c35
-rw-r--r--src/app_mkndx.c34
-rw-r--r--src/app_mkpkg.c3
-rw-r--r--src/app_verify.c30
-rw-r--r--src/database.c121
-rw-r--r--src/extract.c147
-rw-r--r--src/extract_v2.c347
-rw-r--r--src/extract_v3.c16
-rw-r--r--src/meson.build8
-rw-r--r--src/package.c330
-rw-r--r--src/print.c1
-rw-r--r--src/tar.c (renamed from src/io_archive.c)140
25 files changed, 744 insertions, 749 deletions
diff --git a/src/Makefile b/src/Makefile
index 970354b..f7ebb66 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -21,7 +21,7 @@ libapk_so := $(obj)/libapk.so.$(libapk_soname)
libapk.so.$(libapk_soname)-objs := \
adb.o adb_comp.o adb_walk_adb.o adb_walk_genadb.o adb_walk_gentext.o adb_walk_text.o apk_adb.o \
atom.o blob.o commit.o common.o context.o crypto_openssl.o database.o hash.o \
- io.o io_archive.o io_gunzip.o io_url.o \
+ extract.o extract_v2.o extract_v3.o io.o io_gunzip.o io_url.o tar.o \
package.o pathbuilder.o print.o solver.o trust.o version.o
libapk.so.$(libapk_soname)-libs := libfetch/libfetch.a
diff --git a/src/apk_archive.h b/src/apk_archive.h
deleted file mode 100644
index 3dbd284..0000000
--- a/src/apk_archive.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* apk_archive.c - Alpine Package Keeper (APK)
- *
- * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
- * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
- * All rights reserved.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- */
-
-#ifndef APK_ARCHIVE
-#define APK_ARCHIVE
-
-#include <sys/types.h>
-#include "apk_blob.h"
-#include "apk_print.h"
-#include "apk_io.h"
-
-int apk_tar_parse(struct apk_istream *,
- apk_archive_entry_parser parser, void *ctx,
- struct apk_id_cache *);
-int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae,
- const char *data);
-int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
-
-#define APK_EXTRACTF_NO_CHOWN 0x0001
-#define APK_EXTRACTF_NO_OVERWRITE 0x0002
-
-int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
- const char *extract_name, const char *hardlink_name,
- struct apk_istream *is,
- apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
- unsigned int extract_flags,
- struct apk_out *out);
-
-#endif
diff --git a/src/apk_database.h b/src/apk_database.h
index 94507bc..e65a1de 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -13,7 +13,6 @@
#include "apk_version.h"
#include "apk_hash.h"
#include "apk_atom.h"
-#include "apk_archive.h"
#include "apk_package.h"
#include "apk_io.h"
#include "apk_context.h"
@@ -221,7 +220,7 @@ unsigned int apk_db_get_pinning_mask_repos(struct apk_database *db, unsigned sho
int apk_db_cache_active(struct apk_database *db);
int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
- struct apk_package *pkg, int verify, int autoupdate,
+ struct apk_package *pkg, int autoupdate,
apk_progress_cb cb, void *cb_ctx);
typedef void (*apk_cache_item_cb)(struct apk_database *db,
diff --git a/src/apk_defines.h b/src/apk_defines.h
index 3716802..52fef0d 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -43,6 +43,7 @@ enum {
APKE_SIGNATURE_FAIL,
APKE_SIGNATURE_UNTRUSTED,
APKE_SIGNATURE_INVALID,
+ APKE_FORMAT_NOT_SUPPORTED,
APKE_ADB_COMPRESSION,
APKE_ADB_HEADER,
APKE_ADB_VERSION,
diff --git a/src/apk_extract.h b/src/apk_extract.h
new file mode 100644
index 0000000..cc8bae7
--- /dev/null
+++ b/src/apk_extract.h
@@ -0,0 +1,64 @@
+/* apk_extract.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2021 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#ifndef APK_EXTRACT
+#define APK_EXTRACT
+
+#include "apk_crypto.h"
+#include "apk_print.h"
+#include "apk_io.h"
+
+struct apk_ctx;
+struct apk_extract_ctx;
+
+#define APK_EXTRACTF_NO_CHOWN 0x0001
+#define APK_EXTRACTF_NO_OVERWRITE 0x0002
+
+int apk_extract_file(int atfd, const struct apk_file_info *ae,
+ const char *extract_name, const char *hardlink_name,
+ struct apk_istream *is,
+ apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
+ unsigned int extract_flags, struct apk_out *out);
+
+
+typedef int (*apk_extract_cb)(struct apk_extract_ctx *,
+ const struct apk_file_info *ae,
+ struct apk_istream *istream);
+
+struct apk_extract_ctx {
+ struct apk_ctx *ac;
+ apk_extract_cb cb;
+ struct apk_checksum *identity;
+ unsigned generate_identity : 1;
+ unsigned metadata : 1;
+ unsigned metadata_verified : 1;
+ void *pctx;
+};
+
+static inline void apk_extract_init(struct apk_extract_ctx *ectx, struct apk_ctx *ac, apk_extract_cb cb) {
+ *ectx = (struct apk_extract_ctx){.ac = ac, .cb = cb};
+}
+static inline void apk_extract_reset(struct apk_extract_ctx *ectx) {
+ apk_extract_init(ectx, ectx->ac, ectx->cb);
+}
+static inline void apk_extract_generate_identity(struct apk_extract_ctx *ctx, struct apk_checksum *id) {
+ ctx->identity = id;
+ ctx->generate_identity = 1;
+}
+static inline void apk_extract_verify_identity(struct apk_extract_ctx *ctx, struct apk_checksum *id) {
+ ctx->identity = id;
+}
+int apk_extract(struct apk_extract_ctx *, struct apk_istream *is);
+
+int apk_extract_v2(struct apk_extract_ctx *, struct apk_istream *is);
+void apk_extract_v2_control(struct apk_extract_ctx *, apk_blob_t, apk_blob_t);
+
+int apk_extract_v3(struct apk_extract_ctx *, struct apk_istream *is);
+
+#endif
diff --git a/src/apk_package.h b/src/apk_package.h
index 0f7542c..c6545c2 100644
--- a/src/apk_package.h
+++ b/src/apk_package.h
@@ -30,12 +30,6 @@ struct apk_trust;
#define APK_SCRIPT_TRIGGER 6
#define APK_SCRIPT_MAX 7
-#define APK_SIGN_NONE 0
-#define APK_SIGN_VERIFY 1
-#define APK_SIGN_VERIFY_IDENTITY 2
-#define APK_SIGN_GENERATE 4
-#define APK_SIGN_VERIFY_AND_GENERATE 5
-
#define APK_DEP_IRRELEVANT 0x01
#define APK_DEP_SATISFIES 0x02
#define APK_DEP_CONFLICTS 0x04
@@ -45,28 +39,6 @@ struct apk_trust;
#define APK_FOREACH_DEP 0x80
#define APK_FOREACH_GENID_MASK 0xffffff00
-struct apk_sign_ctx {
- struct apk_trust *trust;
- int action;
- const EVP_MD *md;
- int num_signatures;
- int control_started : 1;
- int data_started : 1;
- int has_data_checksum : 1;
- int control_verified : 1;
- int data_verified : 1;
- int allow_untrusted : 1;
- char data_checksum[EVP_MAX_MD_SIZE];
- struct apk_checksum identity;
- EVP_MD_CTX *mdctx;
-
- struct {
- apk_blob_t data;
- EVP_PKEY *pkey;
- char *identity;
- } signature;
-};
-
struct apk_dependency {
struct apk_name *name;
apk_blob_t *version;
@@ -132,17 +104,6 @@ APK_ARRAY(apk_package_array, struct apk_package *);
extern const char *apk_script_types[];
-void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
- struct apk_checksum *identity, struct apk_trust *trust);
-void apk_sign_ctx_free(struct apk_sign_ctx *ctx);
-int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
- const struct apk_file_info *fi,
- struct apk_istream *is);
-int apk_sign_ctx_parse_pkginfo_line(void *ctx, apk_blob_t line);
-int apk_sign_ctx_verify_tar(void *ctx, const struct apk_file_info *fi,
- struct apk_istream *is);
-int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t blob);
-
void apk_dep_from_pkg(struct apk_dependency *dep, struct apk_database *db,
struct apk_package *pkg);
int apk_dep_is_materialized(struct apk_dependency *dep, struct apk_package *pkg);
@@ -165,8 +126,7 @@ int apk_script_type(const char *name);
struct apk_package *apk_pkg_get_installed(struct apk_name *name);
struct apk_package *apk_pkg_new(void);
-int apk_pkg_read(struct apk_database *db, const char *name,
- struct apk_sign_ctx *ctx, struct apk_package **pkg);
+int apk_pkg_read(struct apk_database *db, const char *name, struct apk_package **pkg);
void apk_pkg_free(struct apk_package *pkg);
int apk_pkg_parse_name(apk_blob_t apkname, apk_blob_t *name, apk_blob_t *version);
diff --git a/src/apk_tar.h b/src/apk_tar.h
new file mode 100644
index 0000000..c3d951c
--- /dev/null
+++ b/src/apk_tar.h
@@ -0,0 +1,22 @@
+/* apk_tar.h - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#ifndef APK_TAR
+#define APK_TAR
+
+#include "apk_io.h"
+
+int apk_tar_parse(struct apk_istream *,
+ apk_archive_entry_parser parser, void *ctx,
+ struct apk_id_cache *);
+int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae,
+ const char *data);
+int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
+
+#endif
diff --git a/src/app_add.c b/src/app_add.c
index b4fb356..345fd7a 100644
--- a/src/app_add.c
+++ b/src/app_add.c
@@ -14,6 +14,7 @@
#include "apk_database.h"
#include "apk_print.h"
#include "apk_solver.h"
+#include "apk_extract.h"
struct add_ctx {
const char *virtpkg;
@@ -153,15 +154,11 @@ static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args
if (strstr(*parg, ".apk") != NULL) {
struct apk_package *pkg = NULL;
- struct apk_sign_ctx sctx;
if (non_repository_check(db))
return -1;
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE,
- NULL, apk_ctx_get_trust(ac));
- r = apk_pkg_read(db, *parg, &sctx, &pkg);
- apk_sign_ctx_free(&sctx);
+ r = apk_pkg_read(db, *parg, &pkg);
if (r != 0) {
apk_err(out, "%s: %s", *parg, apk_error_str(r));
return -1;
diff --git a/src/app_cache.c b/src/app_cache.c
index db562cb..b744f25 100644
--- a/src/app_cache.c
+++ b/src/app_cache.c
@@ -98,8 +98,7 @@ static int cache_download(struct cache_ctx *cctx, struct apk_database *db)
if (repo == NULL)
continue;
- r = apk_cache_download(db, repo, pkg, APK_SIGN_VERIFY_IDENTITY, 0,
- progress_cb, &prog);
+ r = apk_cache_download(db, repo, pkg, 0, progress_cb, &prog);
if (r && r != -EALREADY) {
apk_err(out, PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r));
ret++;
diff --git a/src/app_convdb.c b/src/app_convdb.c
index f30d0f7..5e60115 100644
--- a/src/app_convdb.c
+++ b/src/app_convdb.c
@@ -5,6 +5,7 @@
#include "apk_adb.h"
#include "apk_applet.h"
+#include "apk_tar.h"
struct conv_script {
struct list_head script_node;
diff --git a/src/app_convndx.c b/src/app_convndx.c
index 21015cb..d405b03 100644
--- a/src/app_convndx.c
+++ b/src/app_convndx.c
@@ -4,12 +4,13 @@
#include "apk_adb.h"
#include "apk_applet.h"
+#include "apk_extract.h"
struct conv_ctx {
struct apk_ctx *ac;
struct adb_obj pkgs;
struct adb dbi;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
int found;
};
@@ -31,38 +32,27 @@ static void convert_index(struct conv_ctx *ctx, struct apk_istream *is)
}
}
-static int load_apkindex(void *sctx, const struct apk_file_info *fi,
+static int load_apkindex(struct apk_extract_ctx *ectx, const struct apk_file_info *fi,
struct apk_istream *is)
{
- struct conv_ctx *ctx = sctx;
- int r;
-
- r = apk_sign_ctx_process_file(&ctx->sctx, fi, is);
- if (r <= 0) return r;
+ struct conv_ctx *ctx = container_of(ectx, struct conv_ctx, ectx);
if (strcmp(fi->name, "APKINDEX") == 0) {
ctx->found = 1;
convert_index(ctx, is);
return apk_istream_close(is);
}
-
return 0;
}
static int load_index(struct conv_ctx *ctx, struct apk_istream *is)
{
int r = 0;
-
- if (IS_ERR_OR_NULL(is)) return is ? PTR_ERR(is) : -EINVAL;
-
+ if (IS_ERR(is)) return PTR_ERR(is);
ctx->found = 0;
- apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(ctx->ac));
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx->sctx),
- load_apkindex, ctx, apk_ctx_get_id_cache(ctx->ac));
- apk_sign_ctx_free(&ctx->sctx);
+ apk_extract_init(&ctx->ectx, ctx->ac, load_apkindex);
+ r = apk_extract(&ctx->ectx, is);
if (r >= 0 && ctx->found == 0) r = -APKE_V2NDX_FORMAT;
-
return r;
}
diff --git a/src/app_extract.c b/src/app_extract.c
index 89f3f5c..dd410e5 100644
--- a/src/app_extract.c
+++ b/src/app_extract.c
@@ -18,6 +18,7 @@
#include "apk_print.h"
#include "apk_adb.h"
#include "apk_pathbuilder.h"
+#include "apk_extract.h"
struct extract_ctx {
const char *destination;
@@ -151,7 +152,7 @@ static int apk_extract_volume(struct apk_ctx *ac, struct apk_file_info *fi, stru
return uvol_extract(ac, fi->uvol_name, size, fi->size, is, dctx);
}
-static int apk_extract_file(struct extract_ctx *ctx, off_t sz, struct apk_istream *is)
+static int apk_extract_adb_file(struct extract_ctx *ctx, off_t sz, struct apk_istream *is)
{
struct apk_ctx *ac = ctx->ac;
struct apk_out *out = &ac->out;
@@ -199,7 +200,7 @@ static int apk_extract_file(struct extract_ctx *ctx, off_t sz, struct apk_istrea
return -APKE_ADB_SCHEMA;
}
fi.mode |= mode;
- return apk_archive_entry_extract(
+ return apk_extract_file(
ctx->root_fd, &fi, 0, 0, is, 0, 0, 0,
ctx->extract_flags, out);
}
@@ -212,7 +213,7 @@ static int apk_extract_file(struct extract_ctx *ctx, off_t sz, struct apk_istrea
if (fi.uvol_name) {
r = apk_extract_volume(ac, &fi, is, &dctx);
} else {
- r = apk_archive_entry_extract(
+ r = apk_extract_file(
ctx->root_fd, &fi, 0, 0, is, 0, 0, &dctx,
ctx->extract_flags, out);
if (r < 0) return r;
@@ -245,7 +246,7 @@ static int apk_extract_directory(struct extract_ctx *ctx)
apk_extract_acl(&fi, adb_ro_obj(&ctx->path, ADBI_DI_ACL, &acl), apk_ctx_get_id_cache(ctx->ac));
fi.mode |= S_IFDIR;
- return apk_archive_entry_extract(
+ return apk_extract_file(
ctx->root_fd, &fi, 0, 0, 0, 0, 0, 0,
ctx->extract_flags, out);
}
@@ -285,7 +286,7 @@ static int apk_extract_next_file(struct extract_ctx *ctx)
APK_BLOB_IS_NULL(target)) {
return 0;
}
- r = apk_extract_file(ctx, 0, 0);
+ r = apk_extract_adb_file(ctx, 0, 0);
if (r != 0) return r;
} while (1);
}
@@ -316,7 +317,7 @@ static int apk_extract_data_block(struct adb *db, struct adb_block *b, struct ap
return -APKE_ADB_BLOCK;
}
- return apk_extract_file(ctx, sz, is);
+ return apk_extract_adb_file(ctx, sz, is);
}
static int apk_extract_pkg(struct extract_ctx *ctx, const char *fn)
@@ -367,12 +368,12 @@ static int extract_main(void *pctx, struct apk_ctx *ac, struct apk_string_array
return r;
}
-static struct apk_applet apk_extract = {
+static struct apk_applet app_extract = {
.name = "extract",
.context_size = sizeof(struct extract_ctx),
.optgroups = { &optgroup_global, &optgroup_applet },
.main = extract_main,
};
-APK_DEFINE_APPLET(apk_extract);
+APK_DEFINE_APPLET(app_extract);
diff --git a/src/app_index.c b/src/app_index.c
index cc37fa4..b614283 100644
--- a/src/app_index.c
+++ b/src/app_index.c
@@ -16,6 +16,7 @@
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_print.h"
+#include "apk_tar.h"
#define APK_INDEXF_NO_WARNINGS 0x0001
@@ -30,7 +31,6 @@ struct index_ctx {
const char *description;
const char *rewrite_arch;
time_t index_mtime;
- int method;
unsigned short index_flags;
};
@@ -110,7 +110,7 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
struct apk_out *out = &ac->out;
struct apk_database *db = ac->db;
struct counts counts = { .out = out };
- struct apk_ostream *os;
+ struct apk_ostream *os, *counter;
struct apk_file_info fi;
int total, r, found, newpkgs = 0, errors = 0;
struct index_ctx *ictx = (struct index_ctx *) ctx;
@@ -126,9 +126,6 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
return -1;
}
- if (ictx->method == 0)
- ictx->method = APK_SIGN_GENERATE;
-
if ((r = index_read_file(db, ictx)) < 0) {
apk_err(out, "%s: %s", ictx->index, apk_error_str(r));
return r;
@@ -185,9 +182,7 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
} while (0);
if (!found) {
- struct apk_sign_ctx sctx;
- apk_sign_ctx_init(&sctx, ictx->method, NULL, apk_ctx_get_trust(ac));
- r = apk_pkg_read(db, *parg, &sctx, &pkg);
+ r = apk_pkg_read(db, *parg, &pkg);
if (r < 0) {
apk_err(out, "%s: %s", *parg, apk_error_str(r));
errors++;
@@ -195,7 +190,6 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
newpkgs++;
if (rewrite_arch) pkg->arch = rewrite_arch;
}
- apk_sign_ctx_free(&sctx);
}
}
if (errors)
@@ -207,35 +201,29 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
os = apk_ostream_to_fd(STDOUT_FILENO);
if (IS_ERR_OR_NULL(os)) return -1;
- if (ictx->method == APK_SIGN_GENERATE) {
- struct apk_ostream *counter;
-
- memset(&fi, 0, sizeof(fi));
- fi.mode = 0644 | S_IFREG;
- fi.name = "APKINDEX";
- counter = apk_ostream_counter(&fi.size);
- r = apk_db_index_write(db, counter);
- apk_ostream_close(counter);
-
- if (r >= 0) {
- os = apk_ostream_gzip(os);
- if (ictx->description != NULL) {
- struct apk_file_info fi_desc;
- memset(&fi_desc, 0, sizeof(fi));
- fi_desc.mode = 0644 | S_IFREG;
- fi_desc.name = "DESCRIPTION";
- fi_desc.size = strlen(ictx->description);
- apk_tar_write_entry(os, &fi_desc, ictx->description);
- }
-
- apk_tar_write_entry(os, &fi, NULL);
- r = apk_db_index_write(db, os);
- apk_tar_write_padding(os, &fi);
-
- apk_tar_write_entry(os, NULL, NULL);
+ memset(&fi, 0, sizeof(fi));
+ fi.mode = 0644 | S_IFREG;
+ fi.name = "APKINDEX";
+ counter = apk_ostream_counter(&fi.size);
+ r = apk_db_index_write(db, counter);
+ apk_ostream_close(counter);
+
+ if (r >= 0) {
+ os = apk_ostream_gzip(os);
+ if (ictx->description != NULL) {
+ struct apk_file_info fi_desc;
+ memset(&fi_desc, 0, sizeof(fi));
+ fi_desc.mode = 0644 | S_IFREG;
+ fi_desc.name = "DESCRIPTION";
+ fi_desc.size = strlen(ictx->description);
+ apk_tar_write_entry(os, &fi_desc, ictx->description);
}
- } else {
+
+ apk_tar_write_entry(os, &fi, NULL);
r = apk_db_index_write(db, os);
+ apk_tar_write_padding(os, &fi);
+
+ apk_tar_write_entry(os, NULL, NULL);
}
apk_ostream_close(os);
diff --git a/src/app_manifest.c b/src/app_manifest.c
index 86164f6..ff63d7c 100644
--- a/src/app_manifest.c
+++ b/src/app_manifest.c
@@ -14,6 +14,7 @@
#include "apk_defines.h"
#include "apk_applet.h"
#include "apk_database.h"
+#include "apk_extract.h"
#include "apk_version.h"
#include "apk_print.h"
@@ -60,62 +61,48 @@ static void process_package(struct apk_database *db, struct apk_package *pkg)
struct manifest_file_ctx {
struct apk_out *out;
- struct apk_sign_ctx *sctx;
+ struct apk_extract_ctx ectx;
const char *prefix1, *prefix2;
};
-static int read_file_entry(void *ctx, const struct apk_file_info *ae, struct apk_istream *is)
+static int read_file_entry(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
{
- struct manifest_file_ctx *mctx = ctx;
+ struct manifest_file_ctx *mctx = container_of(ectx, struct manifest_file_ctx, ectx);
struct apk_out *out = mctx->out;
char csum_buf[APK_BLOB_CHECKSUM_BUF];
apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf);
- int r;
-
- r = apk_sign_ctx_verify_tar(mctx->sctx, ae, is);
- if (r != 0)
- return r;
-
- if (!mctx->sctx->data_started)
- return 0;
- if ((ae->mode & S_IFMT) != S_IFREG)
- return 0;
+ if (ectx->metadata) return 0;
+ if ((fi->mode & S_IFMT) != S_IFREG) return 0;
memset(csum_buf, '\0', sizeof(csum_buf));
- apk_blob_push_hexdump(&csum_blob, APK_DIGEST_BLOB(ae->digest));
+ apk_blob_push_hexdump(&csum_blob, APK_DIGEST_BLOB(fi->digest));
apk_out(out, "%s%s%s:%s %s",
mctx->prefix1, mctx->prefix2,
- apk_digest_alg_str(ae->digest.alg), csum_buf,
- ae->name);
+ apk_digest_alg_str(fi->digest.alg), csum_buf,
+ fi->name);
return 0;
}
static void process_file(struct apk_database *db, const char *match)
{
- struct apk_id_cache *idc = apk_ctx_get_id_cache(db->ctx);
struct apk_out *out = &db->ctx->out;
- struct apk_sign_ctx sctx;
struct manifest_file_ctx ctx = {
.out = out,
- .sctx = &sctx,
.prefix1 = "",
.prefix2 = "",
};
int r;
+ apk_extract_init(&ctx.ectx, db->ctx, read_file_entry);
if (apk_out_verbosity(out) > 1) {
ctx.prefix1 = match;
ctx.prefix2 = ": ";
}
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, match), apk_sign_ctx_mpart_cb, &sctx),
- read_file_entry, &ctx, idc);
- apk_sign_ctx_free(&sctx);
+ r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, match));
if (r < 0) apk_err(out, "%s: %s", match, apk_error_str(r));
}
diff --git a/src/app_mkndx.c b/src/app_mkndx.c
index 3316de5..c95c494 100644
--- a/src/app_mkndx.c
+++ b/src/app_mkndx.c
@@ -18,6 +18,7 @@
#include "apk_adb.h"
#include "apk_applet.h"
#include "apk_database.h"
+#include "apk_extract.h"
#include "apk_print.h"
struct mkndx_ctx {
@@ -31,7 +32,7 @@ struct mkndx_ctx {
struct adb_obj pkgs;
time_t index_mtime;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
size_t file_size;
};
@@ -83,7 +84,7 @@ static int cmpfield(const void *pa, const void *pb)
return apk_blob_sort(a->str, b->str);
}
-static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, size_t file_size, struct apk_sign_ctx *sctx, apk_blob_t rewrite_arch)
+static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, size_t file_size, struct apk_extract_ctx *ectx, apk_blob_t rewrite_arch)
{
static struct field fields[] = {
FIELD("arch", ADBI_PI_ARCH),
@@ -118,9 +119,9 @@ static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, s
adb_wo_alloca(&deps[2], &schema_dependency_array, db);
while ((r = apk_istream_get_delim(is, token, &line)) == 0) {
- if (sctx) apk_sign_ctx_parse_pkginfo_line(sctx, line);
if (line.len < 1 || line.ptr[0] == '#') continue;
if (!apk_blob_split(line, APK_BLOB_STR(" = "), &k, &v)) continue;
+ apk_extract_v2_control(ectx, k, v);
key.str = k;
f = bsearch(&key, fields, ARRAY_SIZE(fields), sizeof(fields[0]), cmpfield);
@@ -163,22 +164,16 @@ static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, s
return adb_w_obj(&pkginfo);
}
-static int mkndx_parse_v2_tar(void *pctx, const struct apk_file_info *ae, struct apk_istream *is)
+static int mkndx_parse_v2_tar(struct apk_extract_ctx *ectx, const struct apk_file_info *ae, struct apk_istream *is)
{
- struct mkndx_ctx *ctx = pctx;
- adb_val_t o;
- int r;
-
- r = apk_sign_ctx_process_file(&ctx->sctx, ae, is);
- if (r <= 0) return r;
- if (ctx->sctx.control_verified) return -ECANCELED;
- if (!ctx->sctx.control_started || ctx->sctx.data_started) return 0;
+ struct mkndx_ctx *ctx = container_of(ectx, struct mkndx_ctx, ectx);
- if (strcmp(ae->name, ".PKGINFO") == 0) {
- o = adb_wa_append(
+ if (ectx->metadata_verified) return -ECANCELED;
+ if (ectx->metadata && strcmp(ae->name, ".PKGINFO") == 0) {
+ adb_val_t o = adb_wa_append(
&ctx->pkgs,
mkndx_read_v2_pkginfo(
- &ctx->db, is, ctx->file_size, &ctx->sctx,
+ &ctx->db, is, ctx->file_size, &ctx->ectx,
ctx->rewrite_arch));
if (ADB_IS_ERROR(o)) return -ADB_VAL_VALUE(o);
}
@@ -189,7 +184,6 @@ static int mkndx_parse_v2_tar(void *pctx, const struct apk_file_info *ae, struct
static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
- struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
struct apk_trust *trust = apk_ctx_get_trust(ac);
struct adb odb, tmpdb;
struct adb_obj oroot, opkgs, ndx, tmpl;
@@ -205,6 +199,8 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
return -1;
}
+ apk_extract_init(&ctx->ectx, ac, mkndx_parse_v2_tar);
+
adb_init(&odb);
adb_w_init_tmp(&tmpdb, 200);
adb_wo_alloca(&tmpl, &schema_pkginfo, &tmpdb);
@@ -278,11 +274,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
}
if (!found) {
do_file:
- apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, trust);
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg), apk_sign_ctx_mpart_cb, &ctx->sctx),
- mkndx_parse_v2_tar, ctx, idc);
- apk_sign_ctx_free(&ctx->sctx);
+ r = apk_extract(&ctx->ectx, apk_istream_from_file(AT_FDCWD, *parg));
if (r < 0 && r != -ECANCELED) goto err_pkg;
newpkgs++;
}
diff --git a/src/app_mkpkg.c b/src/app_mkpkg.c
index e68a426..b16ec2f 100644
--- a/src/app_mkpkg.c
+++ b/src/app_mkpkg.c
@@ -20,6 +20,7 @@
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_pathbuilder.h"
+#include "apk_extract.h"
#include "apk_print.h"
#define BLOCK_SIZE 4096
@@ -29,7 +30,7 @@ struct mkpkg_ctx {
const char *files_dir, *output;
struct adb db;
struct adb_obj paths, *files;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
apk_blob_t info[ADBI_PI_MAX];
uint64_t installed_size;
struct apk_pathbuilder pb;
diff --git a/src/app_verify.c b/src/app_verify.c
index adfe0ec..fd1a148 100644
--- a/src/app_verify.c
+++ b/src/app_verify.c
@@ -12,38 +12,26 @@
#include <unistd.h>
#include "apk_applet.h"
-#include "apk_database.h"
#include "apk_print.h"
+#include "apk_extract.h"
static int verify_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
- struct apk_sign_ctx sctx;
- struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
- struct apk_trust *trust = apk_ctx_get_trust(ac);
+ struct apk_extract_ctx ectx;
char **parg;
- int r, ok, rc = 0;
+ int r, rc = 0;
- trust->allow_untrusted = 1;
+ apk_extract_init(&ectx, ac, 0);
foreach_array_item(parg, args) {
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, trust);
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg),
- apk_sign_ctx_mpart_cb, &sctx),
- apk_sign_ctx_verify_tar, &sctx, idc);
- ok = sctx.control_verified && sctx.data_verified;
+ r = apk_extract(&ectx, apk_istream_from_file(AT_FDCWD, *parg));
if (apk_out_verbosity(out) >= 1)
- apk_msg(out, "%s: %d - %s", *parg, r,
- r < 0 ? apk_error_str(r) :
- ok ? "OK" :
- !sctx.control_verified ? "UNTRUSTED" : "FAILED");
- else if (!ok)
+ apk_msg(out, "%s: %s", *parg,
+ r < 0 ? apk_error_str(r) : "OK");
+ else if (r < 0)
apk_out(out, "%s", *parg);
- if (!ok)
- rc++;
-
- apk_sign_ctx_free(&sctx);
+ if (r < 0) rc++;
}
return rc;
diff --git a/src/database.c b/src/database.c
index 2a18a47..9ed0085 100644
--- a/src/database.c
+++ b/src/database.c
@@ -32,9 +32,10 @@
#include "apk_package.h"
#include "apk_database.h"
#include "apk_applet.h"
-#include "apk_archive.h"
+#include "apk_extract.h"
#include "apk_print.h"
#include "apk_openssl.h"
+#include "apk_tar.h"
static const apk_spn_match_def apk_spn_repo_separators = {
[1] = (1<<1) /* tab */,
@@ -70,7 +71,7 @@ struct install_ctx {
struct apk_db_dir_instance *diri;
struct apk_checksum data_csum;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
apk_progress_cb cb;
void *cb_ctx;
@@ -621,7 +622,7 @@ int apk_repo_format_item(struct apk_database *db, struct apk_repository *repo, s
}
int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
- struct apk_package *pkg, int verify, int autoupdate,
+ struct apk_package *pkg, int autoupdate,
apk_progress_cb cb, void *cb_ctx)
{
struct apk_out *out = &db->ctx->out;
@@ -629,7 +630,7 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
struct apk_url_print urlp;
struct apk_istream *is;
struct apk_ostream *os;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
char url[PATH_MAX];
char cacheitem[128];
int r;
@@ -658,29 +659,16 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
if (cb) cb(cb_ctx, 0);
- if (verify != APK_SIGN_NONE) {
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
- is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
- is = apk_istream_tee(is, os, autoupdate ? 0 : APK_ISTREAM_TEE_COPY_META, cb, cb_ctx);
- is = apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx);
- r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, db->id_cache);
- apk_sign_ctx_free(&sctx);
- } else {
- is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
- if (!IS_ERR(is)) {
- apk_stream_copy(is, os, APK_IO_ALL, cb, cb_ctx, 0);
- if (!autoupdate) apk_ostream_copy_meta(os, is);
- apk_istream_close(is);
- } else {
- apk_ostream_cancel(os, PTR_ERR(is));
- }
- r = apk_ostream_close(os);
- }
+ is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
+ is = apk_istream_tee(is, os, autoupdate ? 0 : APK_ISTREAM_TEE_COPY_META, cb, cb_ctx);
+ apk_extract_init(&ectx, db->ctx, 0);
+ if (pkg) apk_extract_verify_identity(&ectx, &pkg->csum);
+ r = apk_extract(&ectx, is);
if (r == -EALREADY) {
if (autoupdate) utimensat(db->cache_fd, cacheitem, NULL, 0);
return r;
}
- return 0;
+ return r;
}
static struct apk_db_dir_instance *find_diri(struct apk_installed_package *ipkg,
@@ -2154,9 +2142,9 @@ static int apk_repository_update(struct apk_database *db, struct apk_repository
{
struct apk_out *out = &db->ctx->out;
struct apk_url_print urlp;
- int r, verify = (db->ctx->flags & APK_ALLOW_UNTRUSTED) ? APK_SIGN_NONE : APK_SIGN_VERIFY;
+ int r;
- r = apk_cache_download(db, repo, NULL, verify, 1, NULL, NULL);
+ r = apk_cache_download(db, repo, NULL, 1, NULL, NULL);
if (r == -EALREADY) return 0;
if (r != 0) {
apk_url_parse(&urlp, repo->url);
@@ -2171,67 +2159,46 @@ static int apk_repository_update(struct apk_database *db, struct apk_repository
struct apkindex_ctx {
struct apk_database *db;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
int repo, found;
};
-static int load_apkindex(void *sctx, const struct apk_file_info *fi,
+static int load_apkindex(struct apk_extract_ctx *ectx, const struct apk_file_info *fi,
struct apk_istream *is)
{
- struct apkindex_ctx *ctx = (struct apkindex_ctx *) sctx;
+ struct apkindex_ctx *ctx = container_of(ectx, struct apkindex_ctx, ectx);
struct apk_repository *repo;
- int r;
-
- r = apk_sign_ctx_process_file(&ctx->sctx, fi, is);
- if (r <= 0)
- return r;
- r = 0;
repo = &ctx->db->repos[ctx->repo];
-
if (strcmp(fi->name, "DESCRIPTION") == 0) {
repo->description = apk_blob_from_istream(is, fi->size);
} else if (strcmp(fi->name, "APKINDEX") == 0) {
ctx->found = 1;
- r = apk_db_index_read(ctx->db, is, ctx->repo);
+ return apk_db_index_read(ctx->db, is, ctx->repo);
}
-
- return r;
+ return 0;
}
-static int load_index(struct apk_database *db, struct apk_istream *is,
- int targz, int repo)
+static int load_index(struct apk_database *db, struct apk_istream *is, int repo)
{
+ struct apkindex_ctx ctx;
int r = 0;
- if (IS_ERR_OR_NULL(is)) return is ? PTR_ERR(is) : -EINVAL;
-
- if (targz) {
- struct apkindex_ctx ctx;
-
- ctx.db = db;
- ctx.repo = repo;
- ctx.found = 0;
- apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
- r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), load_apkindex, &ctx, db->id_cache);
- apk_sign_ctx_free(&ctx.sctx);
+ if (IS_ERR(is)) return PTR_ERR(is);
- if (r >= 0 && ctx.found == 0)
- r = -APKE_V2NDX_FORMAT;
- } else {
- apk_db_index_read(db, apk_istream_gunzip(is), repo);
- }
+ ctx.db = db;
+ ctx.repo = repo;
+ ctx.found = 0;
+ apk_extract_init(&ctx.ectx, db->ctx, load_apkindex);
+ r = apk_extract(&ctx.ectx, is);
+ if (r >= 0 && ctx.found == 0)
+ r = -APKE_V2NDX_FORMAT;
return r;
}
int apk_db_index_read_file(struct apk_database *db, const char *file, int repo)
{
- int targz = 1;
-
- if (strstr(file, ".tar.gz") == NULL && strstr(file, ".gz") != NULL)
- targz = 0;
-
- return load_index(db, apk_istream_from_file(AT_FDCWD, file), targz, repo);
+ return load_index(db, apk_istream_from_file(AT_FDCWD, file), repo);
}
int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository)
@@ -2241,7 +2208,7 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository)
struct apk_repository *repo;
struct apk_url_print urlp;
apk_blob_t brepo, btag;
- int repo_num, r, targz = 1, tag_id = 0;
+ int repo_num, r, tag_id = 0;
char buf[PATH_MAX], *url;
brepo = _repository;
@@ -2294,7 +2261,7 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository)
r = apk_repo_format_real_url(db->arch, repo, NULL, buf, sizeof(buf), &urlp);
}
if (r == 0) {
- r = load_index(db, apk_istream_from_fd_url(db->cache_fd, buf, apk_db_url_since(db, 0)), targz, repo_num);
+ r = load_index(db, apk_istream_from_fd_url(db->cache_fd, buf, apk_db_url_since(db, 0)), repo_num);
}
if (r != 0) {
@@ -2318,7 +2285,7 @@ static void extract_cb(void *_ctx, size_t bytes_done)
static void apk_db_run_pending_script(struct install_ctx *ctx)
{
- if (ctx->script_pending && ctx->sctx.control_verified) {
+ if (ctx->script_pending && ctx->ectx.metadata_verified) {
ctx->script_pending = FALSE;
apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args);
}
@@ -2350,7 +2317,7 @@ static int read_info_line(void *_ctx, apk_blob_t line)
list_add_tail(&ipkg->trigger_pkgs_list,
&db->installed.triggers);
} else {
- apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line);
+ apk_extract_v2_control(&ctx->ectx, l, r);
}
return 0;
}
@@ -2409,12 +2376,12 @@ static int contains_control_character(const char *str)
return 0;
}
-static int apk_db_install_archive_entry(void *_ctx,
+static int apk_db_install_archive_entry(struct apk_extract_ctx *ectx,
const struct apk_file_info *ae,
struct apk_istream *is)
{
+ struct install_ctx *ctx = container_of(ectx, struct install_ctx, ectx);
static const char dot1[] = "/./", dot2[] = "/../";
- struct install_ctx *ctx = (struct install_ctx *) _ctx;
struct apk_database *db = ctx->db;
struct apk_out *out = &db->ctx->out;
struct apk_package *pkg = ctx->pkg, *opkg;
@@ -2426,12 +2393,8 @@ static int apk_db_install_archive_entry(void *_ctx,
int ret = 0, r;
char tmpname_file[TMPNAME_MAX], tmpname_link_target[TMPNAME_MAX];
- r = apk_sign_ctx_process_file(&ctx->sctx, ae, is);
- if (r <= 0)
- return r;
-
/* Package metainfo and script processing */
- if (ctx->sctx.control_started && !ctx->sctx.data_started) {
+ if (ectx->metadata) {
if (ae->name[0] != '.') return 0;
if (strcmp(ae->name, ".PKGINFO") == 0) {
apk_blob_t l, token = APK_BLOB_STR("\n");
@@ -2452,8 +2415,7 @@ static int apk_db_install_archive_entry(void *_ctx,
apk_db_run_pending_script(ctx);
/* Rest of files need to be inside data portion */
- if (!ctx->sctx.data_started || ae->name[0] == '.')
- return 0;
+ if (ae->name[0] == '.') return 0;
/* Sanity check the file name */
if (ae->name[0] == '/' || contains_control_character(ae->name) ||
@@ -2582,7 +2544,7 @@ static int apk_db_install_archive_entry(void *_ctx,
/* Extract the file with temporary name */
file->acl = apk_db_acl_atomize_digest(db, ae->mode, ae->uid, ae->gid, &ae->xattr_digest);
- r = apk_archive_entry_extract(
+ r = apk_extract_file(
db->root_fd, ae,
format_tmpname(pkg, file, tmpname_file),
format_tmpname(pkg, link_target_file, tmpname_link_target),
@@ -2843,10 +2805,9 @@ static int apk_db_unpack_pkg(struct apk_database *db,
.cb = cb,
.cb_ctx = cb_ctx,
};
- apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, apk_ctx_get_trust(db->ctx));
- r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), apk_db_install_archive_entry, &ctx, db->id_cache);
- apk_sign_ctx_free(&ctx.sctx);
-
+ apk_extract_init(&ctx.ectx, db->ctx, apk_db_install_archive_entry);
+ apk_extract_verify_identity(&ctx.ectx, &pkg->csum);
+ r = apk_extract(&ctx.ectx, is);
if (need_copy && r == 0) pkg->repos |= BIT(APK_REPOSITORY_CACHED);
if (r != 0) goto err_msg;
diff --git a/src/extract.c b/src/extract.c
new file mode 100644
index 0000000..c5169be
--- /dev/null
+++ b/src/extract.c
@@ -0,0 +1,147 @@
+/* extract.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include "apk_extract.h"
+
+int apk_extract_file(int atfd, const struct apk_file_info *ae,
+ const char *extract_name, const char *link_target,
+ struct apk_istream *is,
+ apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
+ unsigned int extract_flags, struct apk_out *out)
+{
+ struct apk_xattr *xattr;
+ const char *fn = extract_name ?: ae->name;
+ int fd, r = -1, atflags = 0, ret = 0;
+
+ if (!(extract_flags & APK_EXTRACTF_NO_OVERWRITE)) {
+ if (unlinkat(atfd, fn, 0) != 0 && errno != ENOENT) return -errno;
+ }
+
+ switch (ae->mode & S_IFMT) {
+ case S_IFDIR:
+ r = mkdirat(atfd, fn, ae->mode & 07777);
+ if (r < 0 && errno != EEXIST)
+ ret = -errno;
+ break;
+ case S_IFREG:
+ if (ae->link_target == NULL) {
+ int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
+ int fd = openat(atfd, fn, flags, ae->mode & 07777);
+ if (fd < 0) {
+ ret = -errno;
+ break;
+ }
+ struct apk_ostream *os = apk_ostream_to_fd(fd);
+ if (IS_ERR(os)) {
+ ret = PTR_ERR(os);
+ break;
+ }
+ apk_stream_copy(is, os, ae->size, cb, cb_ctx, dctx);
+ r = apk_ostream_close(os);
+ if (r < 0) {
+ unlinkat(atfd, fn, 0);
+ ret = r;
+ }
+ } else {
+ r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
+ if (r < 0) ret = -errno;
+ }
+ break;
+ case S_IFLNK:
+ r = symlinkat(link_target ?: ae->link_target, atfd, fn);
+ if (r < 0) ret = -errno;
+ atflags |= AT_SYMLINK_NOFOLLOW;
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ r = mknodat(atfd, fn, ae->mode, ae->device);
+ if (r < 0) ret = -errno;
+ break;
+ }
+ if (ret) {
+ apk_err(out, "Failed to create %s: %s", ae->name, strerror(-ret));
+ return ret;
+ }
+
+ if (!(extract_flags & APK_EXTRACTF_NO_CHOWN)) {
+ r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
+ if (r < 0) {
+ apk_err(out, "Failed to set ownership on %s: %s",
+ fn, strerror(errno));
+ if (!ret) ret = -errno;
+ }
+
+ /* chown resets suid bit so we need set it again */
+ if (ae->mode & 07000) {
+ r = fchmodat(atfd, fn, ae->mode & 07777, atflags);
+ if (r < 0) {
+ apk_err(out, "Failed to set file permissions on %s: %s",
+ fn, strerror(errno));
+ if (!ret) ret = -errno;
+ }
+ }
+ }
+
+ /* extract xattrs */
+ if (!S_ISLNK(ae->mode) && ae->xattrs && ae->xattrs->num) {
+ r = 0;
+ fd = openat(atfd, fn, O_RDWR);
+ if (fd >= 0) {
+ foreach_array_item(xattr, ae->xattrs) {
+ if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) {
+ r = -errno;
+ if (r != -ENOTSUP) break;
+ }
+ }
+ close(fd);
+ } else {
+ r = -errno;
+ }
+ if (r) {
+ if (r != -ENOTSUP)
+ apk_err(out, "Failed to set xattrs on %s: %s",
+ fn, strerror(-r));
+ if (!ret) ret = r;
+ }
+ }
+
+ if (!S_ISLNK(ae->mode)) {
+ /* preserve modification time */
+ struct timespec times[2];
+
+ times[0].tv_sec = times[1].tv_sec = ae->mtime;
+ times[0].tv_nsec = times[1].tv_nsec = 0;
+ r = utimensat(atfd, fn, times, atflags);
+ if (r < 0) {
+ apk_err(out, "Failed to preserve modification time on %s: %s",
+ fn, strerror(errno));
+ if (!ret || ret == -ENOTSUP) ret = -errno;
+ }
+ }
+
+ return ret;
+}
+
+int apk_extract(struct apk_extract_ctx *ectx, struct apk_istream *is)
+{
+ void *sig;
+
+ if (IS_ERR(is)) return PTR_ERR(is);
+
+ sig = apk_istream_peek(is, 4);
+ if (IS_ERR(sig)) return apk_istream_close_error(is, PTR_ERR(sig));
+
+ if (memcmp(sig, "ADB", 3) == 0) return apk_extract_v3(ectx, is);
+ return apk_extract_v2(ectx, is);
+}
diff --git a/src/extract_v2.c b/src/extract_v2.c
new file mode 100644
index 0000000..217a07d
--- /dev/null
+++ b/src/extract_v2.c
@@ -0,0 +1,347 @@
+/* extract_v2.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include "apk_context.h"
+#include "apk_extract.h"
+#include "apk_package.h"
+#include "apk_tar.h"
+
+#define APK_SIGN_NONE 0
+#define APK_SIGN_VERIFY 1
+#define APK_SIGN_VERIFY_IDENTITY 2
+#define APK_SIGN_GENERATE 4
+#define APK_SIGN_VERIFY_AND_GENERATE 5
+
+struct apk_sign_ctx {
+ struct apk_trust *trust;
+ int action;
+ const EVP_MD *md;
+ int num_signatures;
+ int control_started : 1;
+ int data_started : 1;
+ int has_data_checksum : 1;
+ int control_verified : 1;
+ int data_verified : 1;
+ int allow_untrusted : 1;
+ char data_checksum[EVP_MAX_MD_SIZE];
+ struct apk_checksum identity;
+ EVP_MD_CTX *mdctx;
+
+ struct {
+ apk_blob_t data;
+ EVP_PKEY *pkey;
+ char *identity;
+ } signature;
+};
+
+static void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, struct apk_checksum *identity, struct apk_trust *trust)
+{
+ memset(ctx, 0, sizeof(struct apk_sign_ctx));
+ ctx->trust = trust;
+ ctx->action = action;
+ ctx->allow_untrusted = trust->allow_untrusted;
+ switch (action) {
+ case APK_SIGN_VERIFY:
+ /* If we're only verifing, we're going to start with a
+ * signature section, which we don't need a hash of */
+ ctx->md = EVP_md_null();
+ break;
+ case APK_SIGN_VERIFY_IDENTITY:
+ /* If we're checking the package against a particular hash,
+ * we need to start with that hash, because there may not
+ * be a signature section to deduce it from */
+ ctx->md = EVP_sha1();
+ memcpy(&ctx->identity, identity, sizeof(ctx->identity));
+ break;
+ case APK_SIGN_GENERATE:
+ case APK_SIGN_VERIFY_AND_GENERATE:
+ ctx->md = EVP_sha1();
+ break;
+ default:
+ ctx->action = APK_SIGN_NONE;
+ ctx->md = EVP_md_null();
+ ctx->control_started = 1;
+ ctx->data_started = 1;
+ break;
+ }
+ ctx->mdctx = EVP_MD_CTX_new();
+ EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL);
+ EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
+}
+
+static void apk_sign_ctx_free(struct apk_sign_ctx *ctx)
+{
+ if (ctx->signature.data.ptr != NULL)
+ free(ctx->signature.data.ptr);
+ EVP_MD_CTX_free(ctx->mdctx);
+}
+
+static int check_signing_key_trust(struct apk_sign_ctx *sctx)
+{
+ switch (sctx->action) {
+ case APK_SIGN_VERIFY:
+ case APK_SIGN_VERIFY_AND_GENERATE:
+ if (sctx->signature.pkey == NULL) {
+ if (sctx->allow_untrusted)
+ break;
+ return -APKE_SIGNATURE_UNTRUSTED;
+ }
+ }
+ return 0;
+}
+
+static int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_file_info *fi,
+ struct apk_istream *is)
+{
+ static struct {
+ char type[8];
+ unsigned int nid;
+ } signature_type[] = {
+ { "RSA512", NID_sha512 },
+ { "RSA256", NID_sha256 },
+ { "RSA", NID_sha1 },
+ { "DSA", NID_dsa },
+ };
+ const EVP_MD *md = NULL;
+ const char *name = NULL;
+ struct apk_pkey *pkey;
+ int r, i;
+
+ if (ctx->data_started)
+ return 1;
+
+ if (fi->name[0] != '.' || strchr(fi->name, '/') != NULL) {
+ /* APKv1.0 compatibility - first non-hidden file is
+ * considered to start the data section of the file.
+ * This does not make any sense if the file has v2.0
+ * style .PKGINFO */
+ if (ctx->has_data_checksum)
+ return -APKE_V2PKG_FORMAT;
+ /* Error out early if identity part is missing */
+ if (ctx->action == APK_SIGN_VERIFY_IDENTITY)
+ return -APKE_V2PKG_FORMAT;
+ ctx->data_started = 1;
+ ctx->control_started = 1;
+ r = check_signing_key_trust(ctx);
+ if (r < 0)
+ return r;
+ return 1;
+ }
+
+ if (ctx->control_started)
+ return 1;
+
+ if (strncmp(fi->name, ".SIGN.", 6) != 0) {
+ ctx->control_started = 1;
+ return 1;
+ }
+
+ /* By this point, we must be handling a signature file */
+ ctx->num_signatures++;
+
+ /* Already found a signature by a trusted key; no need to keep searching */
+ if ((ctx->action != APK_SIGN_VERIFY &&
+ ctx->action != APK_SIGN_VERIFY_AND_GENERATE) ||
+ ctx->signature.pkey != NULL)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(signature_type); i++) {
+ size_t slen = strlen(signature_type[i].type);
+ if (strncmp(&fi->name[6], signature_type[i].type, slen) == 0 &&
+ fi->name[6+slen] == '.') {
+ md = EVP_get_digestbynid(signature_type[i].nid);
+ name = &fi->name[6+slen+1];
+ break;
+ }
+ }
+ if (!md) return 0;
+
+ pkey = apk_trust_key_by_name(ctx->trust, name);
+ if (pkey) {
+ ctx->md = md;
+ ctx->signature.pkey = pkey->key;
+ ctx->signature.data = apk_blob_from_istream(is, fi->size);
+ }
+ return 0;
+}
+
+
+/* apk_sign_ctx_mpart_cb() handles hashing archives and checking signatures, but
+ it can't do it alone. apk_sign_ctx_process_file() must be in the loop to
+ actually select which signature is to be verified and load the corresponding
+ public key into the context object, and apk_sign_ctx_parse_pkginfo_line()
+ needs to be called when handling the .PKGINFO file to find any applicable
+ datahash and load it into the context for this function to check against. */
+static int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
+{
+ struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
+ unsigned char calculated[EVP_MAX_MD_SIZE];
+ int r, end_of_control;
+
+ if ((part == APK_MPART_DATA) ||
+ (part == APK_MPART_BOUNDARY && sctx->data_started))
+ goto update_digest;
+
+ /* Still in signature blocks? */
+ if (!sctx->control_started) {
+ if (part == APK_MPART_END)
+ return -APKE_V2PKG_FORMAT;
+ goto reset_digest;
+ }
+
+ /* Grab state and mark all remaining block as data */
+ end_of_control = (sctx->data_started == 0);
+ sctx->data_started = 1;
+
+ /* End of control-block and control does not have data checksum? */
+ if (sctx->has_data_checksum == 0 && end_of_control &&
+ part != APK_MPART_END)
+ goto update_digest;
+
+ /* Drool in the remainder of the digest block now, we will finish
+ * hashing it in all cases */
+ EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
+
+ if (sctx->has_data_checksum && !end_of_control) {
+ /* End of data-block with a checksum read from the control block */
+ EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
+ if (EVP_MD_CTX_size(sctx->mdctx) == 0 ||
+ memcmp(calculated, sctx->data_checksum, EVP_MD_CTX_size(sctx->mdctx)) != 0)
+ return -APKE_V2PKG_INTEGRITY;
+ sctx->data_verified = 1;
+ if (!sctx->allow_untrusted && !sctx->control_verified)
+ return -APKE_SIGNATURE_UNTRUSTED;
+ return 0;
+ }
+
+ /* Either end of control block with a data checksum or end
+ * of the data block following a control block without a data
+ * checksum. In either case, we're checking a signature. */
+ r = check_signing_key_trust(sctx);
+ if (r < 0)
+ return r;
+
+ switch (sctx->action) {
+ case APK_SIGN_VERIFY:
+ case APK_SIGN_VERIFY_AND_GENERATE:
+ if (sctx->signature.pkey != NULL) {
+ r = EVP_VerifyFinal(sctx->mdctx,
+ (unsigned char *) sctx->signature.data.ptr,
+ sctx->signature.data.len,
+ sctx->signature.pkey);
+ if (r != 1 && !sctx->allow_untrusted)
+ return -APKE_SIGNATURE_INVALID;
+ } else {
+ r = 0;
+ if (!sctx->allow_untrusted)
+ return -APKE_SIGNATURE_UNTRUSTED;
+ }
+ if (r == 1) {
+ sctx->control_verified = 1;
+ if (!sctx->has_data_checksum && part == APK_MPART_END)
+ sctx->data_verified = 1;
+ }
+ if (sctx->action == APK_SIGN_VERIFY_AND_GENERATE) goto generate_identity;
+ break;
+ case APK_SIGN_VERIFY_IDENTITY:
+ /* Reset digest for hashing data */
+ EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
+ if (memcmp(calculated, sctx->identity.data,
+ sctx->identity.type) != 0)
+ return -APKE_V2PKG_INTEGRITY;
+ sctx->control_verified = 1;
+ if (!sctx->has_data_checksum && part == APK_MPART_END)
+ sctx->data_verified = 1;
+ break;
+ case APK_SIGN_GENERATE:
+ generate_identity:
+ /* Package identity is the checksum */
+ sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
+ EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
+ if (!sctx->has_data_checksum) return -APKE_V2PKG_FORMAT;
+ break;
+ }
+reset_digest:
+ EVP_DigestInit_ex(sctx->mdctx, sctx->md, NULL);
+ EVP_MD_CTX_set_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
+ return 0;
+
+update_digest:
+ EVP_MD_CTX_clear_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
+ EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
+ return 0;
+}
+
+static int apk_extract_v2_entry(void *pctx, const struct apk_file_info *fi, struct apk_istream *is)
+{
+ struct apk_extract_ctx *ectx = pctx;
+ struct apk_sign_ctx *sctx = ectx->pctx;
+ int r;
+
+ r = apk_sign_ctx_process_file(sctx, fi, is);
+ if (r <= 0) return r;
+
+ ectx->metadata = sctx->control_started && !sctx->data_started;
+ ectx->metadata_verified = sctx->control_verified;
+
+ r = ectx->cb ? ectx->cb(ectx, fi, is) : 0;
+
+ if (ectx->metadata && strcmp(fi->name, ".PKGINFO") == 0) {
+ // Parse the .PKGINFO for the data, in case the callback did not do it.
+ apk_blob_t l, r, token = APK_BLOB_STR("\n");
+ while (apk_istream_get_delim(is, token, &l) == 0) {
+ if (l.len < 1 || l.ptr[0] == '#') continue;
+ if (apk_blob_split(l, APK_BLOB_STR(" = "), &l, &r))
+ apk_extract_v2_control(ectx, l, r);
+ }
+ }
+
+ return r;
+}
+
+int apk_extract_v2(struct apk_extract_ctx *ectx, struct apk_istream *is)
+{
+ struct apk_ctx *ac = ectx->ac;
+ struct apk_trust *trust = apk_ctx_get_trust(ac);
+ struct apk_sign_ctx sctx;
+ int r, action;
+
+ if (ectx->generate_identity)
+ action = trust->allow_untrusted ? APK_SIGN_GENERATE : APK_SIGN_VERIFY_AND_GENERATE;
+ else if (ectx->identity)
+ action = trust->allow_untrusted ? APK_SIGN_NONE : APK_SIGN_VERIFY_IDENTITY;
+ else
+ action = trust->allow_untrusted ? APK_SIGN_NONE : APK_SIGN_VERIFY;
+
+ ectx->pctx = &sctx;
+ apk_sign_ctx_init(&sctx, action, ectx->identity, trust);
+ r = apk_tar_parse(
+ apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx),
+ apk_extract_v2_entry, ectx, apk_ctx_get_id_cache(ac));
+ if (ectx->generate_identity) *ectx->identity = sctx.identity;
+ apk_sign_ctx_free(&sctx);
+ apk_extract_reset(ectx);
+
+ return r;
+}
+
+void apk_extract_v2_control(struct apk_extract_ctx *ectx, apk_blob_t l, apk_blob_t r)
+{
+ struct apk_sign_ctx *sctx = ectx->pctx;
+
+ if (!sctx || !sctx->control_started || sctx->data_started) return;
+
+ if (apk_blob_compare(APK_BLOB_STR("datahash"), l) == 0) {
+ sctx->has_data_checksum = 1;
+ sctx->md = EVP_sha256();
+ apk_blob_pull_hexdump(
+ &r, APK_BLOB_PTR_LEN(sctx->data_checksum,
+ EVP_MD_size(sctx->md)));
+ }
+}
diff --git a/src/extract_v3.c b/src/extract_v3.c
new file mode 100644
index 0000000..c6e80df
--- /dev/null
+++ b/src/extract_v3.c
@@ -0,0 +1,16 @@
+/* extract_v3.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include "apk_context.h"
+#include "apk_extract.h"
+
+int apk_extract_v3(struct apk_extract_ctx *ectx, struct apk_istream *is)
+{
+ return apk_istream_close_error(is, -APKE_FORMAT_NOT_SUPPORTED);
+}
diff --git a/src/meson.build b/src/meson.build
index 98b2461..3bdb477 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -14,15 +14,18 @@ libapk_src = [
'context.c',
'crypto_openssl.c',
'database.c',
+ 'extract.c',
+ 'extract_v2.c',
+ 'extract_v3.c',
'hash.c',
'io.c',
- 'io_archive.c',
'io_url.c',
'io_gunzip.c',
'package.c',
'pathbuilder.c',
'print.c',
'solver.c',
+ 'tar.c',
'trust.c',
'version.c',
]
@@ -30,11 +33,11 @@ libapk_src = [
libapk_headers = [
'apk_applet.h',
'apk_atom.h',
- 'apk_archive.h',
'apk_blob.h',
'apk_crypto.h',
'apk_database.h',
'apk_defines.h',
+ 'apk_extract.h',
'apk_hash.h',
'apk_io.h',
'apk_openssl.h',
@@ -44,6 +47,7 @@ libapk_headers = [
'apk_provider_data.h',
'apk_solver_data.h',
'apk_solver.h',
+ 'apk_tar.h',
'apk_version.h',
]
diff --git a/src/package.c b/src/package.c
index 9686286..9e272b6 100644
--- a/src/package.c
+++ b/src/package.c
@@ -23,10 +23,10 @@
#include <openssl/pem.h>
#include "apk_defines.h"
-#include "apk_archive.h"
#include "apk_package.h"
#include "apk_database.h"
#include "apk_print.h"
+#include "apk_extract.h"
const apk_spn_match_def apk_spn_dependency_comparer = {
[7] = (1<<4) /*<*/ | (1<<5) /*=*/ | (1<<6) /*<*/,
@@ -470,301 +470,10 @@ int apk_script_type(const char *name)
return APK_SCRIPT_INVALID;
}
-void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
- struct apk_checksum *identity, struct apk_trust *trust)
-{
- memset(ctx, 0, sizeof(struct apk_sign_ctx));
- ctx->trust = trust;
- ctx->action = action;
- ctx->allow_untrusted = trust->allow_untrusted;
- switch (action) {
- case APK_SIGN_VERIFY:
- /* If we're only verifing, we're going to start with a
- * signature section, which we don't need a hash of */
- ctx->md = EVP_md_null();
- break;
- case APK_SIGN_VERIFY_IDENTITY:
- /* If we're checking the package against a particular hash,
- * we need to start with that hash, because there may not
- * be a signature section to deduce it from */
- ctx->md = EVP_sha1();
- memcpy(&ctx->identity, identity, sizeof(ctx->identity));
- break;
- case APK_SIGN_GENERATE:
- case APK_SIGN_VERIFY_AND_GENERATE:
- ctx->md = EVP_sha1();
- break;
- default:
- ctx->action = APK_SIGN_NONE;
- ctx->md = EVP_md_null();
- ctx->control_started = 1;
- ctx->data_started = 1;
- break;
- }
- ctx->mdctx = EVP_MD_CTX_new();
- EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL);
- EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
-}
-
-void apk_sign_ctx_free(struct apk_sign_ctx *ctx)
-{
- if (ctx->signature.data.ptr != NULL)
- free(ctx->signature.data.ptr);
- EVP_MD_CTX_free(ctx->mdctx);
-}
-
-static int check_signing_key_trust(struct apk_sign_ctx *sctx)
-{
- switch (sctx->action) {
- case APK_SIGN_VERIFY:
- case APK_SIGN_VERIFY_AND_GENERATE:
- if (sctx->signature.pkey == NULL) {
- if (sctx->allow_untrusted)
- break;
- return -APKE_SIGNATURE_UNTRUSTED;
- }
- }
- return 0;
-}
-
-int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
- const struct apk_file_info *fi,
- struct apk_istream *is)
-{
- static struct {
- char type[8];
- unsigned int nid;
- } signature_type[] = {
- { "RSA512", NID_sha512 },
- { "RSA256", NID_sha256 },
- { "RSA", NID_sha1 },
- { "DSA", NID_dsa },
- };
- const EVP_MD *md = NULL;
- const char *name = NULL;
- struct apk_pkey *pkey;
- int r, i;
-
- if (ctx->data_started)
- return 1;
-
- if (fi->name[0] != '.' || strchr(fi->name, '/') != NULL) {
- /* APKv1.0 compatibility - first non-hidden file is
- * considered to start the data section of the file.
- * This does not make any sense if the file has v2.0
- * style .PKGINFO */
- if (ctx->has_data_checksum)
- return -APKE_V2PKG_FORMAT;
- /* Error out early if identity part is missing */
- if (ctx->action == APK_SIGN_VERIFY_IDENTITY)
- return -APKE_V2PKG_FORMAT;
- ctx->data_started = 1;
- ctx->control_started = 1;
- r = check_signing_key_trust(ctx);
- if (r < 0)
- return r;
- return 1;
- }
-
- if (ctx->control_started)
- return 1;
-
- if (strncmp(fi->name, ".SIGN.", 6) != 0) {
- ctx->control_started = 1;
- return 1;
- }
-
- /* By this point, we must be handling a signature file */
- ctx->num_signatures++;
-
- /* Already found a signature by a trusted key; no need to keep searching */
- if ((ctx->action != APK_SIGN_VERIFY &&
- ctx->action != APK_SIGN_VERIFY_AND_GENERATE) ||
- ctx->signature.pkey != NULL)
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(signature_type); i++) {
- size_t slen = strlen(signature_type[i].type);
- if (strncmp(&fi->name[6], signature_type[i].type, slen) == 0 &&
- fi->name[6+slen] == '.') {
- md = EVP_get_digestbynid(signature_type[i].nid);
- name = &fi->name[6+slen+1];
- break;
- }
- }
- if (!md) return 0;
-
- pkey = apk_trust_key_by_name(ctx->trust, name);
- if (pkey) {
- ctx->md = md;
- ctx->signature.pkey = pkey->key;
- ctx->signature.data = apk_blob_from_istream(is, fi->size);
- }
- return 0;
-}
-
-int apk_sign_ctx_parse_pkginfo_line(void *ctx, apk_blob_t line)
-{
- struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
- apk_blob_t l, r;
-
- if (!sctx->control_started || sctx->data_started)
- return 0;
-
- if (line.ptr == NULL || line.len < 1 || line.ptr[0] == '#')
- return 0;
-
- if (!apk_blob_split(line, APK_BLOB_STR(" = "), &l, &r))
- return 0;
-
- if (apk_blob_compare(APK_BLOB_STR("datahash"), l) == 0) {
- sctx->has_data_checksum = 1;
- sctx->md = EVP_sha256();
- apk_blob_pull_hexdump(
- &r, APK_BLOB_PTR_LEN(sctx->data_checksum,
- EVP_MD_size(sctx->md)));
- }
-
- return 0;
-}
-
-int apk_sign_ctx_verify_tar(void *sctx, const struct apk_file_info *fi,
- struct apk_istream *is)
-{
- struct apk_sign_ctx *ctx = (struct apk_sign_ctx *) sctx;
- int r;
-
- r = apk_sign_ctx_process_file(ctx, fi, is);
- if (r <= 0)
- return r;
-
- if (!ctx->control_started || ctx->data_started)
- return 0;
-
- if (strcmp(fi->name, ".PKGINFO") == 0) {
- apk_blob_t l, token = APK_BLOB_STR("\n");
- while (apk_istream_get_delim(is, token, &l) == 0)
- apk_sign_ctx_parse_pkginfo_line(ctx, l);
- }
-
- return 0;
-}
-
-/* apk_sign_ctx_mpart_cb() handles hashing archives and checking signatures, but
- it can't do it alone. apk_sign_ctx_process_file() must be in the loop to
- actually select which signature is to be verified and load the corresponding
- public key into the context object, and apk_sign_ctx_parse_pkginfo_line()
- needs to be called when handling the .PKGINFO file to find any applicable
- datahash and load it into the context for this function to check against. */
-int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
-{
- struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
- unsigned char calculated[EVP_MAX_MD_SIZE];
- int r, end_of_control;
-
- if ((part == APK_MPART_DATA) ||
- (part == APK_MPART_BOUNDARY && sctx->data_started))
- goto update_digest;
-
- /* Still in signature blocks? */
- if (!sctx->control_started) {
- if (part == APK_MPART_END)
- return -APKE_V2PKG_FORMAT;
- goto reset_digest;
- }
-
- /* Grab state and mark all remaining block as data */
- end_of_control = (sctx->data_started == 0);
- sctx->data_started = 1;
-
- /* End of control-block and control does not have data checksum? */
- if (sctx->has_data_checksum == 0 && end_of_control &&
- part != APK_MPART_END)
- goto update_digest;
-
- /* Drool in the remainder of the digest block now, we will finish
- * hashing it in all cases */
- EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
-
- if (sctx->has_data_checksum && !end_of_control) {
- /* End of data-block with a checksum read from the control block */
- EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
- if (EVP_MD_CTX_size(sctx->mdctx) == 0 ||
- memcmp(calculated, sctx->data_checksum,
- EVP_MD_CTX_size(sctx->mdctx)) != 0)
- return -APKE_V2PKG_INTEGRITY;
- sctx->data_verified = 1;
- if (!sctx->allow_untrusted && !sctx->control_verified)
- return -APKE_SIGNATURE_UNTRUSTED;
- return 0;
- }
-
- /* Either end of control block with a data checksum or end
- * of the data block following a control block without a data
- * checksum. In either case, we're checking a signature. */
- r = check_signing_key_trust(sctx);
- if (r < 0)
- return r;
-
- switch (sctx->action) {
- case APK_SIGN_VERIFY:
- case APK_SIGN_VERIFY_AND_GENERATE:
- if (sctx->signature.pkey != NULL) {
- r = EVP_VerifyFinal(sctx->mdctx,
- (unsigned char *) sctx->signature.data.ptr,
- sctx->signature.data.len,
- sctx->signature.pkey);
- if (r != 1 && !sctx->allow_untrusted)
- return -APKE_SIGNATURE_INVALID;
- } else {
- r = 0;
- if (!sctx->allow_untrusted)
- return -APKE_SIGNATURE_UNTRUSTED;
- }
- if (r == 1) {
- sctx->control_verified = 1;
- if (!sctx->has_data_checksum && part == APK_MPART_END)
- sctx->data_verified = 1;
- }
- if (sctx->action == APK_SIGN_VERIFY_AND_GENERATE) {
- sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
- EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
- }
- break;
- case APK_SIGN_VERIFY_IDENTITY:
- /* Reset digest for hashing data */
- EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
- if (memcmp(calculated, sctx->identity.data,
- sctx->identity.type) != 0)
- return -APKE_V2PKG_INTEGRITY;
- sctx->control_verified = 1;
- if (!sctx->has_data_checksum && part == APK_MPART_END)
- sctx->data_verified = 1;
- break;
- case APK_SIGN_GENERATE:
- /* Package identity is the checksum */
- sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
- EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
- if (sctx->action == APK_SIGN_GENERATE &&
- sctx->has_data_checksum)
- return -ECANCELED;
- break;
- }
-reset_digest:
- EVP_DigestInit_ex(sctx->mdctx, sctx->md, NULL);
- EVP_MD_CTX_set_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
- return 0;
-
-update_digest:
- EVP_MD_CTX_clear_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
- EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
- return 0;
-}
-
struct read_info_ctx {
struct apk_database *db;
struct apk_package *pkg;
- struct apk_sign_ctx *sctx;
+ struct apk_extract_ctx ectx;
};
int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
@@ -840,7 +549,7 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
return 0;
}
-static int read_info_line(void *ctx, apk_blob_t line)
+static int read_info_line(struct read_info_ctx *ri, apk_blob_t line)
{
static struct {
const char *str;
@@ -862,7 +571,6 @@ static int read_info_line(void *ctx, apk_blob_t line)
{ "commit", 'c' },
{ "provider_priority", 'k' },
};
- struct read_info_ctx *ri = (struct read_info_ctx *) ctx;
apk_blob_t l, r;
int i;
@@ -872,36 +580,32 @@ static int read_info_line(void *ctx, apk_blob_t line)
if (!apk_blob_split(line, APK_BLOB_STR(" = "), &l, &r))
return 0;
+ apk_extract_v2_control(&ri->ectx, l, r);
+
for (i = 0; i < ARRAY_SIZE(fields); i++) {
if (apk_blob_compare(APK_BLOB_STR(fields[i].str), l) == 0) {
apk_pkg_add_info(ri->db, ri->pkg, fields[i].field, r);
return 0;
}
}
- apk_sign_ctx_parse_pkginfo_line(ri->sctx, line);
return 0;
}
-static int read_info_entry(void *ctx, const struct apk_file_info *ae,
- struct apk_istream *is)
+static int apk_pkg_parse_entry(struct apk_extract_ctx *ectx, const struct apk_file_info *ae,
+ struct apk_istream *is)
{
- struct read_info_ctx *ri = (struct read_info_ctx *) ctx;
+ struct read_info_ctx *ri = container_of(ectx, struct read_info_ctx, ectx);
struct apk_package *pkg = ri->pkg;
- int r;
- r = apk_sign_ctx_process_file(ri->sctx, ae, is);
- if (r <= 0)
- return r;
-
- if (!ri->sctx->control_started || ri->sctx->data_started)
- return 0;
+ if (ectx->metadata_verified) return -ECANCELED;
+ if (!ectx->metadata) return 0;
if (strcmp(ae->name, ".PKGINFO") == 0) {
/* APK 2.0 format */
apk_blob_t l, token = APK_BLOB_STR("\n");
while (apk_istream_get_delim(is, token, &l) == 0)
- read_info_line(ctx, l);
+ read_info_line(ri, l);
} else if (strcmp(ae->name, ".INSTALL") == 0) {
apk_warn(&ri->db->ctx->out,
"Package '%s-" BLOB_FMT "' contains deprecated .INSTALL",
@@ -911,8 +615,7 @@ static int read_info_entry(void *ctx, const struct apk_file_info *ae,
return 0;
}
-int apk_pkg_read(struct apk_database *db, const char *file,
- struct apk_sign_ctx *sctx, struct apk_package **pkg)
+int apk_pkg_read(struct apk_database *db, const char *file, struct apk_package **pkg)
{
struct read_info_ctx ctx;
struct apk_file_info fi;
@@ -924,25 +627,22 @@ int apk_pkg_read(struct apk_database *db, const char *file,
memset(&ctx, 0, sizeof(ctx));
ctx.db = db;
- ctx.sctx = sctx;
ctx.pkg = apk_pkg_new();
r = -ENOMEM;
if (ctx.pkg == NULL)
goto err;
ctx.pkg->size = fi.size;
+ apk_extract_init(&ctx.ectx, db->ctx, apk_pkg_parse_entry);
+ apk_extract_generate_identity(&ctx.ectx, &ctx.pkg->csum);
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, file), apk_sign_ctx_mpart_cb, sctx),
- read_info_entry, &ctx, db->id_cache);
+ r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, file));
if (r < 0 && r != -ECANCELED)
goto err;
if (ctx.pkg->name == NULL || ctx.pkg->uninstallable) {
r = -ENOTSUP;
goto err;
}
- if (sctx->action != APK_SIGN_VERIFY)
- ctx.pkg->csum = sctx->identity;
ctx.pkg->filename = strdup(file);
ctx.pkg = apk_db_pkg_add(db, ctx.pkg);
diff --git a/src/print.c b/src/print.c
index 1248995..ea66b90 100644
--- a/src/print.c
+++ b/src/print.c
@@ -39,6 +39,7 @@ const char *apk_error_str(int error)
case APKE_SIGNATURE_FAIL: return "signing failure";
case APKE_SIGNATURE_UNTRUSTED: return "UNTRUSTED signature";
case APKE_SIGNATURE_INVALID: return "BAD signature";
+ case APKE_FORMAT_NOT_SUPPORTED: return "file format not supported (in this applet)";
case APKE_ADB_COMPRESSION: return "ADB compression not supported";
case APKE_ADB_HEADER: return "ADB header error";
case APKE_ADB_VERSION: return "incompatible ADB version";
diff --git a/src/io_archive.c b/src/tar.c
index 85f095b..c84ab29 100644
--- a/src/io_archive.c
+++ b/src/tar.c
@@ -1,4 +1,4 @@
-/* io_archive.c - Alpine Package Keeper (APK)
+/* tar.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
@@ -7,27 +7,11 @@
* SPDX-License-Identifier: GPL-2.0-only
*/
-#include <stdio.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <string.h>
-#include <unistd.h>
-#include <sysexits.h>
-#include <sys/wait.h>
#include <sys/stat.h>
-#include <sys/xattr.h>
#include <sys/sysmacros.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdlib.h>
#include "apk_defines.h"
-#include "apk_print.h"
-#include "apk_archive.h"
-#include "apk_openssl.h"
+#include "apk_tar.h"
struct tar_header {
/* ustar header, Posix 1003.1 */
@@ -331,123 +315,3 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae
return 0;
}
-
-int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
- const char *extract_name, const char *link_target,
- struct apk_istream *is,
- apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
- unsigned int extract_flags, struct apk_out *out)
-{
- struct apk_xattr *xattr;
- const char *fn = extract_name ?: ae->name;
- int fd, r = -1, atflags = 0, ret = 0;
-
- if (!(extract_flags & APK_EXTRACTF_NO_OVERWRITE)) {
- if (unlinkat(atfd, fn, 0) != 0 && errno != ENOENT) return -errno;
- }
-
- switch (ae->mode & S_IFMT) {
- case S_IFDIR:
- r = mkdirat(atfd, fn, ae->mode & 07777);
- if (r < 0 && errno != EEXIST)
- ret = -errno;
- break;
- case S_IFREG:
- if (ae->link_target == NULL) {
- int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
- int fd = openat(atfd, fn, flags, ae->mode & 07777);
- if (fd < 0) {
- ret = -errno;
- break;
- }
- struct apk_ostream *os = apk_ostream_to_fd(fd);
- if (IS_ERR(os)) {
- ret = PTR_ERR(os);
- break;
- }
- apk_stream_copy(is, os, ae->size, cb, cb_ctx, dctx);
- r = apk_ostream_close(os);
- if (r < 0) {
- unlinkat(atfd, fn, 0);
- ret = r;
- }
- } else {
- r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
- if (r < 0) ret = -errno;
- }
- break;
- case S_IFLNK:
- r = symlinkat(link_target ?: ae->link_target, atfd, fn);
- if (r < 0) ret = -errno;
- atflags |= AT_SYMLINK_NOFOLLOW;
- break;
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- r = mknodat(atfd, fn, ae->mode, ae->device);
- if (r < 0) ret = -errno;
- break;
- }
- if (ret) {
- apk_err(out, "Failed to create %s: %s", ae->name, strerror(-ret));
- return ret;
- }
-
- if (!(extract_flags & APK_EXTRACTF_NO_CHOWN)) {
- r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
- if (r < 0) {
- apk_err(out, "Failed to set ownership on %s: %s",
- fn, strerror(errno));
- if (!ret) ret = -errno;
- }
-
- /* chown resets suid bit so we need set it again */
- if (ae->mode & 07000) {
- r = fchmodat(atfd, fn, ae->mode & 07777, atflags);
- if (r < 0) {
- apk_err(out, "Failed to set file permissions on %s: %s",
- fn, strerror(errno));
- if (!ret) ret = -errno;
- }
- }
- }
-
- /* extract xattrs */
- if (!S_ISLNK(ae->mode) && ae->xattrs && ae->xattrs->num) {
- r = 0;
- fd = openat(atfd, fn, O_RDWR);
- if (fd >= 0) {
- foreach_array_item(xattr, ae->xattrs) {
- if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) {
- r = -errno;
- if (r != -ENOTSUP) break;
- }
- }
- close(fd);
- } else {
- r = -errno;
- }
- if (r) {
- if (r != -ENOTSUP)
- apk_err(out, "Failed to set xattrs on %s: %s",
- fn, strerror(-r));
- if (!ret) ret = r;
- }
- }
-
- if (!S_ISLNK(ae->mode)) {
- /* preserve modification time */
- struct timespec times[2];
-
- times[0].tv_sec = times[1].tv_sec = ae->mtime;
- times[0].tv_nsec = times[1].tv_nsec = 0;
- r = utimensat(atfd, fn, times, atflags);
- if (r < 0) {
- apk_err(out, "Failed to preserve modification time on %s: %s",
- fn, strerror(errno));
- if (!ret || ret == -ENOTSUP) ret = -errno;
- }
- }
-
- return ret;
-}