mkpkg: new applet to create v2 packages with basic functionality

cute-signatures
Timo Teräs 2021-06-07 19:49:15 +03:00
parent cd9aef8f7c
commit 7c9f001cda
17 changed files with 651 additions and 214 deletions

View File

@ -13,13 +13,16 @@
#include "apk_blob.h"
#include "apk_trust.h"
static char padding_zeroes[ADB_BLOCK_ALIGNMENT] = {0};
/* Block enumeration */
static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_blob_t b)
{
size_t pos = (char *)blk - b.ptr;
if (pos == b.len) return NULL;
pos += sizeof(struct adb_block);
if (pos > b.len || ADB_BLOCK_SIZE(blk) > b.len - pos) return ERR_PTR(-EBADMSG);
if (sizeof(struct adb_block) > b.len - pos) return ERR_PTR(-EBADMSG);
if (adb_block_rawsize(blk) < sizeof(struct adb_block)) return ERR_PTR(-EBADMSG);
if (adb_block_size(blk) > b.len - pos) return ERR_PTR(-EBADMSG);
return blk;
}
@ -30,7 +33,7 @@ struct adb_block *adb_block_first(apk_blob_t b)
struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b)
{
return adb_block_validate((struct adb_block*)((char*)cur + sizeof(struct adb_block) + ADB_BLOCK_SIZE(cur)), b);
return adb_block_validate((struct adb_block*)((char*)cur + adb_block_size(cur)), b);
}
/* Init stuff */
@ -71,8 +74,8 @@ static int __adb_m_parse(struct adb *db, struct apk_trust *t)
int trusted = t ? 0 : 1;
adb_foreach_block(blk, db->data) {
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
switch (ADB_BLOCK_TYPE(blk)) {
apk_blob_t b = adb_block_blob(blk);
switch (adb_block_type(blk)) {
case ADB_BLOCK_ADB:
if (!APK_BLOB_IS_NULL(db->adb)) break;
db->adb = b;
@ -575,13 +578,12 @@ copy:
adb_val_t adb_w_adb(struct adb *db, struct adb *valdb)
{
uint32_t bsz;
struct adb_block blk = {
.type_size = htole32((ADB_BLOCK_ADB << 30) + valdb->adb.len)
};
struct adb_block blk = adb_block_init(ADB_BLOCK_ADB, valdb->adb.len);
struct iovec vec[] = {
{ .iov_base = &bsz, .iov_len = sizeof bsz },
{ .iov_base = &blk, .iov_len = sizeof blk },
{ .iov_base = valdb->adb.ptr, .iov_len = valdb->adb.len },
{ .iov_base = padding_zeroes, .iov_len = adb_block_padding(&blk) },
};
if (valdb->adb.len <= 4) return ADB_NULL;
bsz = htole32(iovec_len(vec, ARRAY_SIZE(vec)) - sizeof bsz);
@ -817,9 +819,8 @@ int adb_c_header(struct apk_ostream *os, struct adb *db)
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val)
{
struct adb_block blk = {
.type_size = htole32((type << 30) + val.len)
};
struct adb_block blk = adb_block_init(type, val.len);
size_t padding = adb_block_padding(&blk);
int r;
r = apk_ostream_write(os, &blk, sizeof blk);
@ -827,6 +828,39 @@ int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val)
r = apk_ostream_write(os, val.ptr, val.len);
if (r < 0) return r;
if (padding) {
r = apk_ostream_write(os, padding_zeroes, padding);
if (r < 0) return r;
}
return 0;
}
int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is)
{
struct adb_block blk = adb_block_init(ADB_BLOCK_DATA, size + hdr.len);
size_t padding = adb_block_padding(&blk);
int r;
if (IS_ERR(os)) return PTR_ERR(os);
if (IS_ERR(is)) return apk_ostream_cancel(os, PTR_ERR(is));
r = apk_ostream_write(os, &blk, sizeof blk);
if (r < 0) return r;
r = apk_ostream_write(os, hdr.ptr, hdr.len);
if (r < 0) return r;
r = apk_stream_copy(is, os, size, 0, 0, 0);
if (r < 0) return r;
if (padding) {
r = apk_ostream_write(os, padding_zeroes, padding);
if (r < 0) return r;
}
apk_istream_close(is);
return 0;
}
@ -842,7 +876,7 @@ int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_ist
mdctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(mdctx, EVP_sha512(), 0);
}
r = apk_stream_copy(is, os, ADB_BLOCK_SIZE(b), 0, 0, mdctx);
r = apk_stream_copy(is, os, adb_block_size(b), 0, 0, mdctx);
if (vfy) {
EVP_DigestFinal_ex(mdctx, vfy->sha512, 0);
EVP_MD_CTX_free(mdctx);
@ -851,17 +885,23 @@ int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_ist
return r;
}
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t)
int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t)
{
if (IS_ERR(os)) return PTR_ERR(os);
if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) {
apk_ostream_cancel(os, -EAPKFORMAT);
goto ret;
}
if (IS_ERR(os))
return apk_ostream_cancel(os, PTR_ERR(os));
if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC))
return apk_ostream_cancel(os, -EAPKFORMAT);
adb_c_header(os, db);
adb_c_block(os, ADB_BLOCK_ADB, db->adb);
if (t) adb_trust_write_signatures(t, db, NULL, os);
ret:
return apk_ostream_error(os);
}
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t)
{
adb_c_adb(os, db, t);
return apk_ostream_close(os);
}
@ -922,8 +962,7 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
if (EVP_DigestSignInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig.hdr.sign_ver, sizeof sig.hdr.sign_ver) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig.hdr.hash_alg, sizeof sig.hdr.hash_alg) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig.v0, sizeof sig.v0) != 1 ||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) {
ERR_print_errors_fp(stdout);
@ -962,8 +1001,7 @@ int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct a
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
if (EVP_DigestVerifyInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig->sign_ver, sizeof sig->sign_ver) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig->hash_alg, sizeof sig->hash_alg) != 1 ||
EVP_DigestUpdate(trust->mdctx, sig0, sizeof *sig0) != 1 ||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) {
ERR_clear_error();
@ -998,16 +1036,16 @@ int adb_c_xfrm(struct adb_xfrm *x, int (*cb)(struct adb_xfrm *, struct adb_block
goto err;
}
if ((block_no++ == 0) != (ADB_BLOCK_TYPE(&blk) == ADB_BLOCK_ADB)) goto bad_msg;
if ((block_no++ == 0) != (adb_block_type(&blk) == ADB_BLOCK_ADB)) goto bad_msg;
sz = ADB_BLOCK_SIZE(&blk);
sz = adb_block_size(&blk) - sizeof blk;
r = cb(x, &blk, apk_istream_segment(&seg, x->is, sz, 0));
if (r < 0) goto err;
if (r == 0 && seg.bytes_left == sz) {
r = apk_ostream_write(x->os, &blk, sizeof blk);
if (r < 0) goto err;
r = apk_stream_copy(x->is, x->os, seg.bytes_left, 0, 0, 0);
r = apk_stream_copy(x->is, x->os, sz, 0, 0, 0);
if (r < 0) goto err;
} else if (seg.bytes_left > 0) {
r = apk_istream_read(x->is, NULL, sz - seg.bytes_left);

View File

@ -51,17 +51,29 @@ struct adb_header {
};
/* Blocks */
#define ADB_BLOCK_ALIGNMENT 8
#define ADB_BLOCK_END -1
#define ADB_BLOCK_ADB 0
#define ADB_BLOCK_SIG 2
#define ADB_BLOCK_TYPE(b) (le32toh((b)->type_size) >> 30)
#define ADB_BLOCK_SIZE(b) (le32toh((b)->type_size) & 0x3fffffff)
#define ADB_BLOCK_DATA 3
struct adb_block {
uint32_t type_size;
};
static inline struct adb_block adb_block_init(uint32_t type, uint32_t length) {
return (struct adb_block) { .type_size = htole32((type << 30) + sizeof(struct adb_block) + length)};
}
static inline uint32_t adb_block_type(struct adb_block *b) { return le32toh((b)->type_size) >> 30; }
static inline uint32_t adb_block_rawsize(struct adb_block *b) { return le32toh((b)->type_size) & 0x3fffffff; }
static inline uint32_t adb_block_size(struct adb_block *b) { return ROUND_UP(adb_block_rawsize(b), ADB_BLOCK_ALIGNMENT); }
static inline uint32_t adb_block_length(struct adb_block *b) { return adb_block_rawsize(b) - sizeof(struct adb_block); }
static inline uint32_t adb_block_padding(struct adb_block *b) { return adb_block_size(b) - adb_block_rawsize(b); }
static inline void *adb_block_payload(struct adb_block *b) { return b + 1; }
static inline apk_blob_t adb_block_blob(struct adb_block *b) {
return APK_BLOB_PTR_LEN(adb_block_payload(b), adb_block_length(b));
}
struct adb_sign_hdr {
uint8_t sign_ver, hash_alg;
};
@ -81,7 +93,6 @@ struct adb_sign_v0 {
/* Block enumeration */
struct adb_block *adb_block_first(apk_blob_t b);
struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b);
#define adb_foreach_block(__blk, __adb) \
for (__blk = adb_block_first(__adb); !IS_ERR_OR_NULL(__blk); __blk = adb_block_next(__blk, __adb))
@ -218,7 +229,9 @@ int adb_s_field_by_name(const struct adb_object_schema *, const char *);
/* Creation */
int adb_c_header(struct apk_ostream *os, struct adb *db);
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t);
int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is);
int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *);
int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t);
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t);
/* Trust */
@ -279,6 +292,7 @@ struct adb_walk_gentext {
struct adb_walk_genadb {
struct adb_walk d;
struct adb db;
adb_val_t stored_object;
struct adb idb[ADB_WALK_GENADB_MAX_IDB];
int nest, nestdb, num_vals;
struct adb_obj objs[ADB_WALK_GENADB_MAX_NESTING];

View File

@ -107,11 +107,10 @@ static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema
static int dump_adb(struct adb_walk_ctx *ctx)
{
char tmp[256];
char tmp[512];
struct adb_block *blk;
struct adb_sign_hdr *s;
struct adb_verify_ctx vfy = {};
unsigned char *id;
uint32_t schema_magic = ctx->db->hdr.schema;
const struct adb_db_schema *ds;
struct adb_walk *d = ctx->d;
@ -121,10 +120,10 @@ static int dump_adb(struct adb_walk_ctx *ctx)
if (ds->magic == schema_magic) break;
adb_foreach_block(blk, ctx->db->data) {
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
switch (ADB_BLOCK_TYPE(blk)) {
apk_blob_t b = adb_block_blob(blk);
switch (adb_block_type(blk)) {
case ADB_BLOCK_ADB:
len = snprintf(tmp, sizeof tmp, "ADB block, size: %u", ADB_BLOCK_SIZE(blk));
len = snprintf(tmp, sizeof tmp, "ADB block, size: %u", adb_block_length(blk));
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
if (ds->root) {
ctx->db->adb = b;
@ -134,23 +133,19 @@ static int dump_adb(struct adb_walk_ctx *ctx)
case ADB_BLOCK_SIG:
s = (struct adb_sign_hdr*) b.ptr;
r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b);
len = snprintf(tmp, sizeof tmp, "signature: v%d ", s->sign_ver);
switch (s->sign_ver) {
case 0:
id = (unsigned char*)(s + 1);
for (size_t j = 0; j < 16; j++)
len += snprintf(&tmp[len], sizeof tmp - len, "%02x", id[j]);
break;
default:
break;
}
len = snprintf(tmp, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg);
for (size_t j = sizeof *s; j < b.len; j++)
len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)b.ptr[j]);
len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK");
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
break;
case ADB_BLOCK_DATA:
len = snprintf(tmp, sizeof tmp, "data block, size: %d", adb_block_length(blk));
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
break;
default:
len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %d",
ADB_BLOCK_TYPE(blk), ADB_BLOCK_SIZE(blk));
adb_block_type(blk), adb_block_length(blk));
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
}
}

View File

@ -74,7 +74,7 @@ static int adb_walk_genadb_end(struct adb_walk *d)
dt->num_vals -= dt->objs[dt->nest].schema->num_fields;
if (dt->nest == 0) {
adb_w_root(&dt->db, val);
dt->stored_object = val;
return 0;
}

View File

@ -422,17 +422,16 @@ const struct adb_object_schema schema_index = {
},
};
static uint32_t file_get_default_int(unsigned i)
{
switch (i) {
case ADBI_FI_UID:
case ADBI_FI_GID:
return 0;
case ADBI_FI_MODE:
return 0644;
}
return -1;
}
const struct adb_object_schema schema_acl = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_ACL_MAX,
.fields = {
ADB_FIELD(ADBI_ACL_MODE, "mode", scalar_oct),
ADB_FIELD(ADBI_ACL_USER, "user", scalar_string),
ADB_FIELD(ADBI_ACL_GROUP, "group", scalar_string),
//ADB_FIELD(ADBI_ACL_XATTRS, "xattr", schema_string_array),
},
};
static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
@ -442,15 +441,14 @@ static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
const struct adb_object_schema schema_file = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_FI_MAX,
.get_default_int = file_get_default_int,
.compare = file_cmp,
.fields = {
ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_FI_ACL, "acl", schema_acl),
ADB_FIELD(ADBI_FI_SIZE, "size", scalar_int),
ADB_FIELD(ADBI_FI_MTIME, "mtime", scalar_int),
ADB_FIELD(ADBI_FI_HASHES, "hash", scalar_hexblob),
ADB_FIELD(ADBI_FI_UID, "uid", scalar_int),
ADB_FIELD(ADBI_FI_GID, "gid", scalar_int),
ADB_FIELD(ADBI_FI_MODE, "mode", scalar_oct),
ADB_FIELD(ADBI_FI_XATTRS, "xattr", scalar_hexblob),
ADB_FIELD(ADBI_FI_TARGET, "target", scalar_string),
},
};
@ -461,38 +459,22 @@ const struct adb_object_schema schema_file_array = {
.fields = ADB_ARRAY_ITEM(schema_file),
};
static uint32_t path_get_default_int(unsigned i)
{
switch (i) {
case ADBI_FI_UID:
case ADBI_FI_GID:
return 0;
case ADBI_FI_MODE:
return 0755;
}
return -1;
}
const struct adb_object_schema schema_path = {
const struct adb_object_schema schema_dir = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_FI_MAX,
.get_default_int = path_get_default_int,
.num_fields = ADBI_DI_MAX,
.compare = file_cmp,
.fields = {
ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_FI_FILES, "files", schema_file_array),
ADB_FIELD(ADBI_FI_UID, "uid", scalar_int),
ADB_FIELD(ADBI_FI_GID, "gid", scalar_int),
ADB_FIELD(ADBI_FI_MODE, "mode", scalar_oct),
ADB_FIELD(ADBI_FI_XATTRS, "xattr", scalar_hexblob),
ADB_FIELD(ADBI_DI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_DI_ACL, "acl", schema_acl),
ADB_FIELD(ADBI_DI_FILES, "files", schema_file_array),
},
};
const struct adb_object_schema schema_path_array = {
const struct adb_object_schema schema_dir_array = {
.kind = ADB_KIND_ARRAY,
.pre_commit = adb_wa_sort,
.num_fields = APK_MAX_MANIFEST_PATHS,
.fields = ADB_ARRAY_ITEM(schema_path),
.fields = ADB_ARRAY_ITEM(schema_dir),
};
const struct adb_object_schema schema_scripts = {
@ -520,7 +502,7 @@ const struct adb_object_schema schema_package = {
.compare = package_cmp,
.fields = {
ADB_FIELD(ADBI_PKG_PKGINFO, "info", schema_pkginfo),
ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_path_array),
ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_dir_array),
ADB_FIELD(ADBI_PKG_SCRIPTS, "scripts", schema_scripts),
ADB_FIELD(ADBI_PKG_TRIGGERS, "triggers", schema_string_array),
//ADB_FIELD(ADBI_PKG_PASSWD, "passwd", schema_string_array),

View File

@ -33,16 +33,28 @@
#define ADBI_PI_RECOMMENDS 0x13
#define ADBI_PI_MAX 0x14
/* ACL entries */
#define ADBI_ACL_MODE 0x01
#define ADBI_ACL_USER 0x02
#define ADBI_ACL_GROUP 0x03
#define ADBI_ACL_XATTRS 0x04
#define ADBI_ACL_MAX 0x05
/* File Info */
#define ADBI_FI_NAME 0x01
#define ADBI_FI_HASHES 0x02
#define ADBI_FI_FILES 0x02
#define ADBI_FI_MODE 0x03
#define ADBI_FI_UID 0x04
#define ADBI_FI_GID 0x05
#define ADBI_FI_XATTRS 0x06
#define ADBI_FI_ACL 0x02
#define ADBI_FI_SIZE 0x03
#define ADBI_FI_MTIME 0x04
#define ADBI_FI_HASHES 0x05
#define ADBI_FI_TARGET 0x06
#define ADBI_FI_MAX 0x07
/* Directory Info */
#define ADBI_DI_NAME 0x01
#define ADBI_DI_ACL 0x02
#define ADBI_DI_FILES 0x03
#define ADBI_DI_MAX 0x04
/* Scripts */
#define ADBI_SCRPT_TRIGGER 0x01
#define ADBI_SCRPT_PREINST 0x02
@ -81,7 +93,7 @@
extern const struct adb_object_schema
schema_dependency, schema_dependency_array,
schema_pkginfo, schema_pkginfo_array,
schema_file, schema_file_array, schema_path, schema_path_array,
schema_acl, schema_file, schema_file_array, schema_dir, schema_dir_array,
schema_string_array, schema_scripts, schema_package, schema_package_adb_array,
schema_index, schema_idb;

View File

@ -191,14 +191,14 @@ APK_ARRAY(apk_string_array, char *);
#define LIST_POISON1 (void *) 0xdeadbeef
#define LIST_POISON2 (void *) 0xabbaabba
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next;
};
struct hlist_head {
struct hlist_node *first;
};
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;

View File

@ -15,14 +15,17 @@
#include "apk_defines.h"
#include "apk_blob.h"
#include "apk_hash.h"
#include "apk_atom.h"
struct apk_id_hash {
int empty;
struct hlist_head by_id[16], by_name[16];
};
struct apk_id_cache {
int root_fd;
unsigned int genid;
struct apk_hash uid_cache;
struct apk_hash gid_cache;
struct apk_id_hash uid_cache;
struct apk_id_hash gid_cache;
};
struct apk_xattr {
@ -148,6 +151,7 @@ struct apk_ostream *apk_ostream_to_fd(int fd);
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode);
size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
static inline int apk_ostream_error(struct apk_ostream *os) { return os->rc; }
static inline int apk_ostream_cancel(struct apk_ostream *os, int rc) { if (!os->rc) os->rc = rc; return rc; }
static inline ssize_t apk_ostream_write(struct apk_ostream *os, const void *buf, size_t size)
{
@ -181,7 +185,9 @@ const char *apk_url_local_file(const char *url);
void apk_id_cache_init(struct apk_id_cache *idc, int root_fd);
void apk_id_cache_free(struct apk_id_cache *idc);
void apk_id_cache_reset(struct apk_id_cache *idc);
uid_t apk_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid);
uid_t apk_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, uid_t default_gid);
uid_t apk_id_cache_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid);
gid_t apk_id_cache_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, gid_t default_gid);
apk_blob_t apk_id_cache_resolve_user(struct apk_id_cache *idc, uid_t uid);
apk_blob_t apk_id_cache_resolve_group(struct apk_id_cache *idc, gid_t gid);
#endif

44
src/apk_pathbuilder.h Normal file
View File

@ -0,0 +1,44 @@
/* apk_pathbuilder.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2021 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#ifndef APK_PATHBUILDER_H
#define APK_PATHBUILDER_H
#include "apk_blob.h"
struct apk_pathbuilder {
uint16_t namelen;
char name[PATH_MAX];
};
int apk_pathbuilder_pushb(struct apk_pathbuilder *pb, apk_blob_t b);
void apk_pathbuilder_pop(struct apk_pathbuilder *pb);
static inline int apk_pathbuilder_setb(struct apk_pathbuilder *pb, apk_blob_t b)
{
pb->namelen = 0;
return apk_pathbuilder_pushb(pb, b);
}
static inline int apk_pathbuilder_push(struct apk_pathbuilder *pb, const char *name)
{
return apk_pathbuilder_pushb(pb, APK_BLOB_STR(name));
}
static inline const char *apk_pathbuilder_cstr(const struct apk_pathbuilder *pb)
{
return pb->name;
}
static inline apk_blob_t apk_pathbuilder_get(const struct apk_pathbuilder *pb)
{
return APK_BLOB_PTR_LEN((void*)pb->name, pb->namelen);
}
#endif

View File

@ -68,8 +68,10 @@ static int adbgen_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *
adb_w_init_alloca(&genadb.idb[0], 0, 100);
foreach_array_item(arg, args) {
adb_reset(&genadb.db);
adb_reset(&genadb.idb[0]);
r = adb_walk_istream(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg));
if (!r) {
adb_w_root(&genadb.db, genadb.stored_object);
r = adb_c_create(apk_ostream_to_fd(STDOUT_FILENO), &genadb.db,
apk_ctx_get_trust(ac));
}

View File

@ -44,7 +44,7 @@ static int update_signatures(struct adb_xfrm *xfrm, struct adb_block *blk, struc
struct apk_trust *trust = apk_ctx_get_trust(ctx->ac);
int r;
switch (blk ? ADB_BLOCK_TYPE(blk) : -1) {
switch (blk ? adb_block_type(blk) : -1) {
case ADB_BLOCK_ADB:
return adb_c_block_copy(xfrm->os, blk, is, &xfrm->vfy);
case ADB_BLOCK_SIG:

View File

@ -18,6 +18,7 @@ struct conv_script {
};
struct conv_ctx {
struct apk_ctx *ac;
struct apk_atom_pool atoms;
struct adb_obj pkgs;
@ -100,8 +101,9 @@ static int read_triggers(struct conv_ctx *ctx, struct apk_istream *is)
static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
{
struct apk_id_cache *idc = apk_ctx_get_id_cache(ctx->ac);
struct apk_checksum csum;
struct adb_obj pkg, pkginfo, files, file, paths, path, scripts, triggers;
struct adb_obj pkg, pkginfo, files, file, paths, path, scripts, triggers, acl;
apk_blob_t l, val, spc = APK_BLOB_STR(" "), nl = APK_BLOB_STR("\n");
struct conv_script *s;
int i;
@ -111,14 +113,15 @@ static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
adb_wo_alloca(&pkginfo, &schema_pkginfo, &ctx->dbp);
adb_wo_alloca(&files, &schema_file_array, &ctx->dbp);
adb_wo_alloca(&file, &schema_file, &ctx->dbp);
adb_wo_alloca(&paths, &schema_path_array, &ctx->dbp);
adb_wo_alloca(&path, &schema_path, &ctx->dbp);
adb_wo_alloca(&paths, &schema_dir_array, &ctx->dbp);
adb_wo_alloca(&path, &schema_dir, &ctx->dbp);
adb_wo_alloca(&pkg, &schema_package, &ctx->dbp);
adb_wo_alloca(&acl, &schema_acl, &ctx->dbp);
while (!APK_BLOB_IS_NULL(l = apk_istream_get_delim(is, nl))) {
if (l.len < 2) {
adb_wa_append_obj(&files, &file);
adb_wo_obj(&path, ADBI_FI_FILES, &files);
adb_wo_obj(&path, ADBI_DI_FILES, &files);
adb_wa_append_obj(&paths, &path);
adb_wo_obj(&pkg, ADBI_PKG_PKGINFO, &pkginfo);
@ -152,28 +155,30 @@ static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
break;
case 'F': // directory name
adb_wa_append_obj(&files, &file);
adb_wo_obj(&path, ADBI_FI_FILES, &files);
adb_wo_obj(&path, ADBI_DI_FILES, &files);
adb_wa_append_obj(&paths, &path);
adb_wo_blob(&path, ADBI_FI_NAME, val);
adb_wo_blob(&path, ADBI_DI_NAME, val);
break;
case 'M': // directory mode: uid:gid:mode:xattrcsum
adb_wo_int(&path, ADBI_FI_UID, apk_blob_pull_uint(&val, 10));
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, apk_blob_pull_uint(&val, 10)));
apk_blob_pull_char(&val, ':');
adb_wo_int(&path, ADBI_FI_GID, apk_blob_pull_uint(&val, 10));
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, apk_blob_pull_uint(&val, 10)));
apk_blob_pull_char(&val, ':');
adb_wo_int(&path, ADBI_FI_MODE, apk_blob_pull_uint(&val, 8));
adb_wo_int(&acl, ADBI_ACL_MODE, apk_blob_pull_uint(&val, 8));
adb_wo_obj(&path, ADBI_DI_ACL, &acl);
break;
case 'R': // file name
adb_wa_append_obj(&files, &file);
adb_wo_blob(&file, ADBI_FI_NAME, val);
break;
case 'a': // file mode: uid:gid:mode:xattrcsum
adb_wo_int(&file, ADBI_FI_UID, apk_blob_pull_uint(&val, 10));
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, apk_blob_pull_uint(&val, 10)));
apk_blob_pull_char(&val, ':');
adb_wo_int(&file, ADBI_FI_GID, apk_blob_pull_uint(&val, 10));
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, apk_blob_pull_uint(&val, 10)));
apk_blob_pull_char(&val, ':');
adb_wo_int(&file, ADBI_FI_MODE, apk_blob_pull_uint(&val, 8));
adb_wo_int(&acl, ADBI_ACL_MODE, apk_blob_pull_uint(&val, 8));
adb_wo_obj(&file, ADBI_FI_ACL, &acl);
break;
case 'Z': // file content hash
apk_blob_pull_csum(&val, &csum);
@ -196,6 +201,7 @@ static int conv_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *ar
int r;
int root_fd = apk_ctx_fd_root(ac);
ctx->ac = ac;
list_init(&ctx->script_head);
apk_atom_init(&ctx->atoms);

284
src/app_mkpkg.c Normal file
View File

@ -0,0 +1,284 @@
/* app_mkpkg.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2008-2021 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "apk_defines.h"
#include "apk_adb.h"
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_pathbuilder.h"
#include "apk_print.h"
#define BLOCK_SIZE 4096
struct mkpkg_ctx {
struct apk_ctx *ac;
const char *files_dir, *output;
struct adb db;
struct adb_obj paths, *files;
struct apk_sign_ctx sctx;
apk_blob_t info[ADBI_PI_MAX];
uint64_t installed_size;
struct apk_pathbuilder pb;
};
#define MKPKG_OPTIONS(OPT) \
OPT(OPT_MKPKG_files, APK_OPT_ARG APK_OPT_SH("f") "files") \
OPT(OPT_MKPKG_info, APK_OPT_ARG APK_OPT_SH("i") "info") \
OPT(OPT_MKPKG_output, APK_OPT_ARG APK_OPT_SH("o") "output") \
APK_OPT_APPLET(option_desc, MKPKG_OPTIONS);
static int option_parse_applet(void *ctx, struct apk_ctx *ac, int optch, const char *optarg)
{
struct apk_out *out = &ac->out;
struct mkpkg_ctx *ictx = ctx;
apk_blob_t l, r;
int i;
switch (optch) {
case OPT_MKPKG_info:
apk_blob_split(APK_BLOB_STR(optarg), APK_BLOB_STRLIT(":"), &l, &r);
i = adb_s_field_by_name_blob(&schema_pkginfo, l);
if (!i || i == ADBI_PI_FILE_SIZE || i == ADBI_PI_INSTALLED_SIZE) {
apk_err(out, "invalid pkginfo field: " BLOB_FMT, BLOB_PRINTF(l));
return -EINVAL;
}
ictx->info[i] = r;
break;
case OPT_MKPKG_files:
ictx->files_dir = optarg;
break;
case OPT_MKPKG_output:
ictx->output = optarg;
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct apk_option_group optgroup_applet = {
.desc = option_desc,
.parse = option_parse_applet,
};
static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry);
static int mkpkg_process_directory(struct mkpkg_ctx *ctx, int dirfd, struct apk_file_info *fi)
{
struct apk_ctx *ac = ctx->ac;
struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
struct apk_out *out = &ac->out;
struct adb_obj acl, fio, files, *prev_files;
apk_blob_t dirname = apk_pathbuilder_get(&ctx->pb);
int r;
adb_wo_alloca(&fio, &schema_dir, &ctx->db);
adb_wo_alloca(&acl, &schema_acl, &ctx->db);
adb_wo_blob(&fio, ADBI_DI_NAME, dirname);
adb_wo_int(&acl, ADBI_ACL_MODE, fi->mode & ~S_IFMT);
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, fi->uid));
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, fi->gid));
adb_wo_obj(&fio, ADBI_DI_ACL, &acl);
adb_wo_alloca(&files, &schema_file_array, &ctx->db);
prev_files = ctx->files;
ctx->files = &files;
r = apk_dir_foreach_file(dirfd, mkpkg_process_dirent, ctx);
ctx->files = prev_files;
if (r) {
apk_err(out, "failed to process directory '%s': %d",
apk_pathbuilder_cstr(&ctx->pb), r);
return r;
}
adb_wo_obj(&fio, ADBI_DI_FILES, &files);
adb_wa_append_obj(&ctx->paths, &fio);
return 0;
}
static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry)
{
struct mkpkg_ctx *ctx = pctx;
struct apk_ctx *ac = ctx->ac;
struct apk_out *out = &ac->out;
struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
struct apk_file_info fi;
struct adb_obj fio, acl;
int r;
r = apk_fileinfo_get(dirfd, entry, APK_FI_NOFOLLOW | APK_FI_CSUM(APK_CHECKSUM_SHA1), &fi, NULL);
if (r) return r;
switch (fi.mode & S_IFMT) {
case S_IFDIR:
apk_pathbuilder_push(&ctx->pb, entry);
r = mkpkg_process_directory(ctx, openat(dirfd, entry, O_RDONLY), &fi);
apk_pathbuilder_pop(&ctx->pb);
break;
case S_IFREG:
adb_wo_alloca(&fio, &schema_file, &ctx->db);
adb_wo_alloca(&acl, &schema_acl, &ctx->db);
adb_wo_blob(&fio, ADBI_FI_NAME, APK_BLOB_STR(entry));
adb_wo_blob(&fio, ADBI_FI_HASHES, APK_BLOB_PTR_LEN((char*) fi.csum.data, fi.csum.type));
adb_wo_int(&fio, ADBI_FI_MTIME, fi.mtime);
adb_wo_int(&fio, ADBI_FI_SIZE, fi.size);
ctx->installed_size += (fi.size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE-1);
adb_wo_int(&acl, ADBI_ACL_MODE, fi.mode & 07777);
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, fi.uid));
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, fi.gid));
adb_wo_obj(&fio, ADBI_FI_ACL, &acl);
adb_wa_append_obj(ctx->files, &fio);
break;
default:
apk_pathbuilder_push(&ctx->pb, entry);
apk_err(out, "special file '%s' not supported",
apk_pathbuilder_cstr(&ctx->pb), entry);
apk_pathbuilder_pop(&ctx->pb);
r = -EINVAL;
break;
}
return r;
}
static char *pkgi_filename(struct adb_obj *pkgi, char *buf, size_t n)
{
apk_blob_t to = APK_BLOB_PTR_LEN(buf, n);
apk_blob_push_blob(&to, adb_ro_blob(pkgi, ADBI_PI_NAME));
apk_blob_push_blob(&to, APK_BLOB_STR("-"));
apk_blob_push_blob(&to, adb_ro_blob(pkgi, ADBI_PI_VERSION));
apk_blob_push_blob(&to, APK_BLOB_STR(".apk"));
apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
if (APK_BLOB_IS_NULL(to)) return 0;
return buf;
}
static int mkpkg_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
struct apk_trust *trust = apk_ctx_get_trust(ac);
struct adb_obj pkg, pkgi;
int i, j, r;
struct mkpkg_ctx *ctx = pctx;
struct apk_ostream *os;
char outbuf[PATH_MAX];
ctx->ac = ac;
adb_w_init_alloca(&ctx->db, ADB_SCHEMA_PACKAGE, 40);
adb_wo_alloca(&pkg, &schema_package, &ctx->db);
adb_wo_alloca(&pkgi, &schema_pkginfo, &ctx->db);
adb_wo_alloca(&ctx->paths, &schema_dir_array, &ctx->db);
// prepare package info
for (i = 0; i < ARRAY_SIZE(ctx->info); i++) {
apk_blob_t val = ctx->info[i];
if (APK_BLOB_IS_NULL(val)) {
switch (i) {
case ADBI_PI_NAME:
case ADBI_PI_VERSION:
r = -EINVAL;
apk_err(out, "required pkginfo field '%s' not provided",
schema_pkginfo.fields[i-1].name);
goto err;
}
continue;
}
adb_wo_val_fromstring(&pkgi, i, val);
}
if (adb_ro_val(&pkgi, ADBI_PI_ARCH) == ADB_VAL_NULL)
adb_wo_blob(&pkgi, ADBI_PI_ARCH, APK_BLOB_STRLIT(APK_DEFAULT_ARCH));
// scan and add all files
if (ctx->files_dir) {
struct apk_file_info fi;
r = apk_fileinfo_get(AT_FDCWD, ctx->files_dir, APK_FI_NOFOLLOW, &fi, 0);
if (r) {
apk_err(out, "file directory '%s': %s",
ctx->files_dir, apk_error_str(r));
goto err;
}
r = mkpkg_process_directory(ctx, openat(AT_FDCWD, ctx->files_dir, O_RDONLY), &fi);
if (r) goto err;
if (!ctx->installed_size) ctx->installed_size = BLOCK_SIZE;
}
adb_wo_int(&pkgi, ADBI_PI_INSTALLED_SIZE, ctx->installed_size);
adb_wo_obj(&pkg, ADBI_PKG_PKGINFO, &pkgi);
adb_wo_obj(&pkg, ADBI_PKG_PATHS, &ctx->paths);
adb_w_rootobj(&pkg);
// re-read since object resets
adb_r_rootobj(&ctx->db, &pkg, &schema_package);
adb_ro_obj(&pkg, ADBI_PKG_PKGINFO, &pkgi);
adb_ro_obj(&pkg, ADBI_PKG_PATHS, &ctx->paths);
if (!ctx->output) {
ctx->output = pkgi_filename(&pkgi, outbuf, sizeof outbuf);
}
// construct package with ADB as header, and the file data in
// concatenated data blocks
os = apk_ostream_gzip(apk_ostream_to_file(AT_FDCWD, ctx->output, 0644));
adb_c_adb(os, &ctx->db, trust);
int files_fd = openat(AT_FDCWD, ctx->files_dir, O_RDONLY);
for (i = ADBI_FIRST; i <= adb_ra_num(&ctx->paths); i++) {
struct adb_obj path, files, file;
adb_ro_obj(&ctx->paths, i, &path);
adb_ro_obj(&path, ADBI_DI_FILES, &files);
apk_blob_t dirname = adb_ro_blob(&path, ADBI_DI_NAME);
apk_pathbuilder_setb(&ctx->pb, dirname);
for (j = ADBI_FIRST; j <= adb_ra_num(&files); j++) {
adb_ro_obj(&files, j, &file);
apk_blob_t filename = adb_ro_blob(&file, ADBI_FI_NAME);
apk_blob_t target = adb_ro_blob(&file, ADBI_FI_TARGET);
size_t sz = adb_ro_int(&file, ADBI_FI_SIZE);
if (!APK_BLOB_IS_NULL(target)) continue;
if (!sz) continue;
struct {
uint32_t path_idx;
uint32_t file_idx;
} hdr = { i, j };
apk_pathbuilder_pushb(&ctx->pb, filename);
adb_c_block_data(
os, APK_BLOB_STRUCT(hdr), sz,
apk_istream_from_fd(openat(files_fd,
apk_pathbuilder_cstr(&ctx->pb),
O_RDONLY)));
apk_pathbuilder_pop(&ctx->pb);
}
}
close(files_fd);
r = apk_ostream_close(os);
err:
adb_free(&ctx->db);
if (r) apk_err(out, "failed to create package: %s", apk_error_str(r));
return r;
}
static struct apk_applet apk_mkpkg = {
.name = "mkpkg",
.context_size = sizeof(struct mkpkg_ctx),
.optgroups = { &optgroup_global, &optgroup_signing, &optgroup_applet },
.main = mkpkg_main,
};
APK_DEFINE_APPLET(apk_mkpkg);

210
src/io.c
View File

@ -1033,72 +1033,86 @@ size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
}
struct cache_item {
apk_hash_node hash_node;
unsigned int genid;
union {
uid_t uid;
gid_t gid;
};
struct hlist_node by_id, by_name;
unsigned long id;
unsigned short len;
char name[];
};
static apk_blob_t cache_item_get_key(apk_hash_item item)
static void idhash_init(struct apk_id_hash *idh)
{
struct cache_item *ci = (struct cache_item *) item;
return APK_BLOB_PTR_LEN(ci->name, ci->len);
memset(idh, 0, sizeof *idh);
idh->empty = 1;
}
static const struct apk_hash_ops id_hash_ops = {
.node_offset = offsetof(struct cache_item, hash_node),
.get_key = cache_item_get_key,
.hash_key = apk_blob_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) free,
};
static void idhash_reset(struct apk_id_hash *idh)
{
struct hlist_node *iter, *next;
struct cache_item *ci;
int i;
static struct cache_item *resolve_cache_item(struct apk_hash *hash, apk_blob_t name)
for (i = 0; i < ARRAY_SIZE(idh->by_id); i++)
hlist_for_each_entry_safe(ci, iter, next, &idh->by_id[i], by_id)
free(ci);
idhash_init(idh);
}
static void idcache_add(struct apk_id_hash *hash, apk_blob_t name, unsigned long id)
{
struct cache_item *ci;
unsigned long h;
h = id_hash_ops.hash_key(name);
ci = (struct cache_item *) apk_hash_get_hashed(hash, name, h);
if (ci != NULL)
return ci;
ci = calloc(1, sizeof(struct cache_item) + name.len);
if (ci == NULL)
return NULL;
if (!ci) return;
ci->id = id;
ci->len = name.len;
memcpy(ci->name, name.ptr, name.len);
apk_hash_insert_hashed(hash, ci, h);
return ci;
h = apk_blob_hash(name);
hlist_add_head(&ci->by_id, &hash->by_id[id % ARRAY_SIZE(hash->by_id)]);
hlist_add_head(&ci->by_name, &hash->by_name[h % ARRAY_SIZE(hash->by_name)]);
}
static struct cache_item *idcache_by_name(struct apk_id_hash *hash, apk_blob_t name)
{
struct cache_item *ci;
struct hlist_node *pos;
unsigned long h = apk_blob_hash(name);
hlist_for_each_entry(ci, pos, &hash->by_name[h % ARRAY_SIZE(hash->by_name)], by_name)
if (apk_blob_compare(name, APK_BLOB_PTR_LEN(ci->name, ci->len)) == 0)
return ci;
return 0;
}
static struct cache_item *idcache_by_id(struct apk_id_hash *hash, unsigned long id)
{
struct cache_item *ci;
struct hlist_node *pos;
hlist_for_each_entry(ci, pos, &hash->by_id[id % ARRAY_SIZE(hash->by_name)], by_id)
if (ci->id == id) return ci;
return 0;
}
void apk_id_cache_init(struct apk_id_cache *idc, int root_fd)
{
idc->root_fd = root_fd;
idc->genid = 1;
apk_hash_init(&idc->uid_cache, &id_hash_ops, 256);
apk_hash_init(&idc->gid_cache, &id_hash_ops, 256);
}
void apk_id_cache_free(struct apk_id_cache *idc)
{
if (!idc->root_fd) return;
apk_hash_free(&idc->uid_cache);
apk_hash_free(&idc->gid_cache);
idc->root_fd = 0;
idhash_init(&idc->uid_cache);
idhash_init(&idc->gid_cache);
}
void apk_id_cache_reset(struct apk_id_cache *idc)
{
idc->genid++;
if (idc->genid == 0)
idc->genid = 1;
idhash_reset(&idc->uid_cache);
idhash_reset(&idc->gid_cache);
}
void apk_id_cache_free(struct apk_id_cache *idc)
{
apk_id_cache_reset(idc);
idc->root_fd = 0;
}
static FILE *fopenat(int dirfd, const char *pathname)
@ -1114,86 +1128,94 @@ static FILE *fopenat(int dirfd, const char *pathname)
return f;
}
uid_t apk_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid)
static void idcache_load_users(int root_fd, struct apk_id_hash *idh)
{
#ifdef HAVE_FGETPWENT_R
char buf[1024];
struct passwd pwent;
#endif
struct cache_item *ci;
struct passwd *pwd;
FILE *in;
ci = resolve_cache_item(&idc->uid_cache, username);
if (ci == NULL) return default_uid;
if (!idh->empty) return;
idh->empty = 0;
if (ci->genid != idc->genid) {
ci->genid = idc->genid;
ci->uid = -1;
in = fopenat(root_fd, "etc/passwd");
if (!in) return;
in = fopenat(idc->root_fd, "etc/passwd");
if (in) {
do {
do {
#ifdef HAVE_FGETPWENT_R
fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd);
fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd);
#else
pwd = fgetpwent(in);
pwd = fgetpwent(in);
#endif
if (!pwd) break;
idcache_add(idh, APK_BLOB_STR(pwd->pw_name), pwd->pw_uid);
} while (1);
fclose(in);
#ifndef HAVE_FGETPWENT_R
endpwent();
#endif
if (pwd == NULL)
break;
if (apk_blob_compare(APK_BLOB_STR(pwd->pw_name), username) == 0) {
ci->uid = pwd->pw_uid;
break;
}
} while (1);
fclose(in);
}
}
if (ci->uid != -1)
return ci->uid;
return default_uid;
}
uid_t apk_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, uid_t default_gid)
static void idcache_load_groups(int root_fd, struct apk_id_hash *idh)
{
#ifdef HAVE_FGETGRENT_R
char buf[1024];
struct group grent;
#endif
struct cache_item *ci;
struct group *grp;
FILE *in;
ci = resolve_cache_item(&idc->gid_cache, groupname);
if (ci == NULL) return default_gid;
if (!idh->empty) return;
idh->empty = 0;
if (ci->genid != idc->genid) {
ci->genid = idc->genid;
ci->gid = -1;
in = fopenat(root_fd, "etc/group");
if (!in) return;
in = fopenat(idc->root_fd, "etc/group");
if (in) {
do {
do {
#ifdef HAVE_FGETGRENT_R
fgetgrent_r(in, &grent, buf, sizeof(buf), &grp);
fgetgrent_r(in, &grent, buf, sizeof(buf), &grp);
#else
grp = fgetgrent(in);
grp = fgetgrent(in);
#endif
if (!grp) break;
idcache_add(idh, APK_BLOB_STR(grp->gr_name), grp->gr_gid);
} while (1);
fclose(in);
#ifndef HAVE_FGETGRENT_R
endgrent();
#endif
if (grp == NULL)
break;
if (apk_blob_compare(APK_BLOB_STR(grp->gr_name), groupname) == 0) {
ci->gid = grp->gr_gid;
break;
}
} while (1);
fclose(in);
}
}
if (ci->gid != -1)
return ci->gid;
return default_gid;
}
uid_t apk_id_cache_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid)
{
struct cache_item *ci;
idcache_load_users(idc->root_fd, &idc->uid_cache);
ci = idcache_by_name(&idc->uid_cache, username);
return ci ? ci->id : default_uid;
}
gid_t apk_id_cache_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, gid_t default_gid)
{
struct cache_item *ci;
idcache_load_groups(idc->root_fd, &idc->gid_cache);
ci = idcache_by_name(&idc->gid_cache, groupname);
return ci ? ci->id : default_gid;
}
apk_blob_t apk_id_cache_resolve_user(struct apk_id_cache *idc, uid_t uid)
{
struct cache_item *ci;
idcache_load_users(idc->root_fd, &idc->uid_cache);
ci = idcache_by_id(&idc->uid_cache, uid);
return ci ? APK_BLOB_PTR_LEN(ci->name, ci->len) : APK_BLOB_STRLIT("nobody");
}
apk_blob_t apk_id_cache_resolve_group(struct apk_id_cache *idc, gid_t gid)
{
struct cache_item *ci;
idcache_load_groups(idc->root_fd, &idc->gid_cache);
ci = idcache_by_id(&idc->gid_cache, gid);
return ci ? APK_BLOB_PTR_LEN(ci->name, ci->len) : APK_BLOB_STRLIT("nobody");
}

View File

@ -150,8 +150,8 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
entry = (struct apk_file_info){
.size = GET_OCTAL(buf.size),
.uid = apk_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid)),
.gid = apk_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid)),
.uid = apk_id_cache_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid)),
.gid = apk_id_cache_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid)),
.mode = GET_OCTAL(buf.mode) & 07777,
.mtime = GET_OCTAL(buf.mtime),
.name = entry.name,

View File

@ -18,6 +18,7 @@ libapk_src = [
'io_url.c',
'io_gunzip.c',
'package.c',
'pathbuilder.c',
'print.c',
'solver.c',
'trust.c',
@ -35,6 +36,7 @@ libapk_headers = [
'apk_io.h',
'apk_openssl.h',
'apk_package.h',
'apk_pathbuilder.h',
'apk_print.h',
'apk_provider_data.h',
'apk_solver_data.h',
@ -60,6 +62,7 @@ apk_src = [
'app_list.c',
'app_manifest.c',
'app_mkndx.c',
'app_mkpkg.c',
'app_policy.c',
'app_update.c',
'app_upgrade.c',

29
src/pathbuilder.c Normal file
View File

@ -0,0 +1,29 @@
/* apk_pathbuilder.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2021 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <errno.h>
#include "apk_pathbuilder.h"
int apk_pathbuilder_pushb(struct apk_pathbuilder *pb, apk_blob_t b)
{
size_t i = pb->namelen;
if (i + b.len + 2 >= ARRAY_SIZE(pb->name)) return -ENAMETOOLONG;
if (i) pb->name[i++] = '/';
memcpy(&pb->name[i], b.ptr, b.len);
pb->namelen = i + b.len;
pb->name[pb->namelen] = 0;
return 0;
}
void apk_pathbuilder_pop(struct apk_pathbuilder *pb)
{
char *slash = memrchr(pb->name, '/', pb->namelen);
if (slash) pb->namelen = slash - pb->name;
else pb->namelen = 0;
pb->name[pb->namelen] = 0;
}