2020-11-27 15:23:33 +00:00
|
|
|
#include "adb.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "apk_adb.h"
|
|
|
|
#include "apk_applet.h"
|
|
|
|
#include "apk_print.h"
|
|
|
|
|
|
|
|
struct adb_walk_ctx {
|
|
|
|
struct adb_walk *d;
|
|
|
|
struct apk_trust *trust;
|
2021-07-16 16:01:41 +00:00
|
|
|
struct adb db;
|
|
|
|
struct adb_verify_ctx vfy;
|
2020-11-27 15:23:33 +00:00
|
|
|
};
|
|
|
|
|
2021-07-16 16:01:41 +00:00
|
|
|
static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istream *is);
|
2020-11-27 15:23:33 +00:00
|
|
|
static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v);
|
|
|
|
|
|
|
|
static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t *kind, adb_val_t v)
|
|
|
|
{
|
|
|
|
struct adb_walk *d = ctx->d;
|
2021-07-16 16:01:41 +00:00
|
|
|
struct adb origdb;
|
2020-11-27 15:23:33 +00:00
|
|
|
struct adb_obj o;
|
|
|
|
struct adb_object_schema *obj_schema;
|
2021-07-16 16:01:41 +00:00
|
|
|
struct apk_istream is;
|
2020-11-27 15:23:33 +00:00
|
|
|
char tmp[256];
|
|
|
|
apk_blob_t b;
|
|
|
|
|
|
|
|
if (v == ADB_VAL_NULL) return 0;
|
|
|
|
|
|
|
|
d->ops->key(d, name ? APK_BLOB_STR(name) : APK_BLOB_NULL);
|
|
|
|
|
|
|
|
switch (*kind) {
|
|
|
|
case ADB_KIND_ARRAY:
|
|
|
|
obj_schema = container_of(kind, struct adb_object_schema, kind);
|
2021-07-16 16:01:41 +00:00
|
|
|
adb_r_obj(&ctx->db, v, &o, obj_schema);
|
2020-11-27 15:23:33 +00:00
|
|
|
//if (!adb_ra_num(&o)) return 0;
|
|
|
|
|
|
|
|
d->ops->start_array(d, adb_ra_num(&o));
|
|
|
|
for (size_t i = ADBI_FIRST; i <= adb_ra_num(&o); i++) {
|
|
|
|
dump_item(ctx, NULL, obj_schema->fields[0].kind, adb_ro_val(&o, i));
|
|
|
|
}
|
|
|
|
d->ops->end(d);
|
|
|
|
break;
|
|
|
|
case ADB_KIND_ADB:
|
2021-07-16 16:01:41 +00:00
|
|
|
apk_istream_from_blob(&is, adb_r_blob(&ctx->db, v));
|
2020-11-27 15:23:33 +00:00
|
|
|
origdb = ctx->db;
|
|
|
|
d->ops->start_object(d);
|
2021-07-16 16:01:41 +00:00
|
|
|
adb_m_process(&ctx->db, &is,
|
|
|
|
container_of(kind, struct adb_adb_schema, kind)->schema_id | ADB_SCHEMA_IMPLIED,
|
|
|
|
0, adb_walk_block);
|
2020-11-27 15:23:33 +00:00
|
|
|
d->ops->end(d);
|
|
|
|
ctx->db = origdb;
|
|
|
|
break;
|
2021-06-02 19:35:58 +00:00
|
|
|
case ADB_KIND_OBJECT:;
|
|
|
|
struct adb_object_schema *object = container_of(kind, struct adb_object_schema, kind);
|
|
|
|
if (!object->tostring) {
|
|
|
|
d->ops->start_object(d);
|
|
|
|
dump_object(ctx, object, v);
|
|
|
|
d->ops->end(d);
|
|
|
|
} else {
|
|
|
|
dump_object(ctx, object, v);
|
|
|
|
}
|
2020-11-27 15:23:33 +00:00
|
|
|
break;
|
|
|
|
case ADB_KIND_BLOB:
|
|
|
|
case ADB_KIND_INT:;
|
|
|
|
struct adb_scalar_schema *scalar = container_of(kind, struct adb_scalar_schema, kind);
|
|
|
|
if (scalar->tostring) {
|
2021-07-16 16:01:41 +00:00
|
|
|
b = scalar->tostring(&ctx->db, v, tmp, sizeof tmp);
|
2020-11-27 15:23:33 +00:00
|
|
|
} else {
|
|
|
|
b = APK_BLOB_STR("(unknown)");
|
|
|
|
}
|
|
|
|
if (!APK_BLOB_IS_NULL(b))
|
|
|
|
d->ops->scalar(d, b, scalar->multiline);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v)
|
|
|
|
{
|
|
|
|
size_t schema_len = 0;
|
|
|
|
struct adb_obj o;
|
|
|
|
char tmp[256];
|
|
|
|
apk_blob_t b;
|
|
|
|
struct adb_walk *d = ctx->d;
|
|
|
|
|
2021-07-16 16:01:41 +00:00
|
|
|
adb_r_obj(&ctx->db, v, &o, schema);
|
2020-11-27 15:23:33 +00:00
|
|
|
if (schema) {
|
|
|
|
if (schema->tostring) {
|
|
|
|
b = schema->tostring(&o, tmp, sizeof tmp);
|
|
|
|
if (!APK_BLOB_IS_NULL(b))
|
|
|
|
d->ops->scalar(d, b, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
schema_len = schema->num_fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = ADBI_FIRST; i < adb_ro_num(&o); i++) {
|
|
|
|
adb_val_t val = adb_ro_val(&o, i);
|
|
|
|
if (val == ADB_NULL) continue;
|
|
|
|
if (i < schema_len && schema->fields[i-1].kind != 0) {
|
|
|
|
dump_item(ctx, schema->fields[i-1].name, schema->fields[i-1].kind, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-07-16 16:01:41 +00:00
|
|
|
static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istream *is)
|
2020-11-27 15:23:33 +00:00
|
|
|
{
|
2021-07-16 16:01:41 +00:00
|
|
|
struct adb_walk_ctx *ctx = container_of(db, struct adb_walk_ctx, db);
|
|
|
|
struct adb_walk *d = ctx->d;
|
2021-06-19 11:42:11 +00:00
|
|
|
char tmp[16+ADB_MAX_SIGNATURE_LEN*2];
|
2020-11-27 15:23:33 +00:00
|
|
|
struct adb_sign_hdr *s;
|
2021-07-16 16:01:41 +00:00
|
|
|
uint32_t schema_magic = ctx->db.hdr.schema;
|
2020-11-27 15:23:33 +00:00
|
|
|
const struct adb_db_schema *ds;
|
|
|
|
int r, len;
|
2021-07-16 16:01:41 +00:00
|
|
|
size_t sz = adb_block_length(b);
|
|
|
|
apk_blob_t data;
|
2020-11-27 15:23:33 +00:00
|
|
|
|
2021-07-16 16:01:41 +00:00
|
|
|
switch (adb_block_type(b)) {
|
|
|
|
case ADB_BLOCK_ADB:
|
|
|
|
d->ops->schema(d, db->hdr.schema);
|
|
|
|
for (ds = d->schemas; ds->magic; ds++)
|
|
|
|
if (ds->magic == schema_magic) break;
|
|
|
|
len = snprintf(tmp, sizeof tmp, "ADB block, size: %zu", sz);
|
|
|
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
|
|
|
if (ds->root) dump_object(ctx, ds->root, adb_r_root(db));
|
|
|
|
break;
|
|
|
|
case ADB_BLOCK_SIG:
|
|
|
|
s = (struct adb_sign_hdr*) apk_istream_get(is, sz);
|
|
|
|
data = APK_BLOB_PTR_LEN((char*)s, sz);
|
|
|
|
r = adb_trust_verify_signature(ctx->trust, db, &ctx->vfy, data);
|
|
|
|
len = snprintf(tmp, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg);
|
|
|
|
for (size_t j = sizeof *s; j < data.len; j++)
|
|
|
|
len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)data.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: %zu", sz);
|
|
|
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %zu",
|
|
|
|
adb_block_type(b), sz);
|
|
|
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
2020-11-27 15:23:33 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-07-16 16:01:41 +00:00
|
|
|
int adb_walk_adb(struct adb_walk *d, struct apk_istream *is, struct apk_trust *trust)
|
2020-11-27 15:23:33 +00:00
|
|
|
{
|
|
|
|
struct adb_walk_ctx ctx = {
|
|
|
|
.d = d,
|
|
|
|
.trust = trust,
|
|
|
|
};
|
2021-07-16 16:01:41 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
if (IS_ERR(is)) return PTR_ERR(is);
|
|
|
|
|
|
|
|
r = adb_m_process(&ctx.db, is, 0, 0, adb_walk_block);
|
|
|
|
adb_free(&ctx.db);
|
|
|
|
return r;
|
2020-11-27 15:23:33 +00:00
|
|
|
}
|