diff options
author | sinanmohd <sinan@sinanmohd.com> | 2024-04-27 12:31:12 +0530 |
---|---|---|
committer | sinanmohd <sinan@sinanmohd.com> | 2024-04-28 15:43:50 +0530 |
commit | da21dd57634aebffe0f5833b598e1128fafc0def (patch) | |
tree | 71d8e510eb788e0df695052325a1fe4fec6bf5a7 /src/npassd/collection.c | |
parent | 06e3f1885fc112093f867cd5d7a8b163ef28650c (diff) |
npassd/collection: init
Diffstat (limited to 'src/npassd/collection.c')
-rw-r--r-- | src/npassd/collection.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/src/npassd/collection.c b/src/npassd/collection.c new file mode 100644 index 0000000..48167bf --- /dev/null +++ b/src/npassd/collection.c @@ -0,0 +1,289 @@ +#include <errno.h> +#include <linux/limits.h> +#include <sqlite3.h> +#include <stdbool.h> +#include <stdlib.h> +#include <systemd/sd-bus.h> +#include <time.h> + +#include "npassd/collection.h" +#include "npassd/common.h" +#include "npassd/util.h" +#include "util.h" + +#define COLLECTION_IFACE "org.freedesktop.Secret.Collection" +#define DBUS_ROOT_PREFIX "dbus" + +static int collection_alloc(sd_bus *bus, struct collection **p, + const char *root, const char *alias, + const char *label, uint64_t created, + uint64_t modified); +static int collection_db_read(sd_bus *bus, struct sqlite3 *db, + struct collection **p, const char *alias); +static int collection_db_write(struct sqlite3 *db, struct collection *c); + +static int handle_create_item(__attribute__((unused)) sd_bus_message *msg, + __attribute__((unused)) void *data, + __attribute__((unused)) sd_bus_error *ret_error); + +static const sd_bus_vtable collection_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("CreateItem", "", "", handle_create_item, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END, +}; + +static int handle_create_item(__attribute__((unused)) sd_bus_message *msg, + __attribute__((unused)) void *data, + __attribute__((unused)) sd_bus_error *ret_error) +{ + return 0; +} + +static void collection_free(struct collection *c) +{ + if (c == NULL) + return; + + if (c->slot != NULL) + sd_bus_slot_unref(c->slot); + if (c->path != NULL) + free(c->path); + if (c->alias != NULL) + free(c->alias); + if (c->label != NULL) + free(c->label); + if (c->root != NULL) + free(c->root); + + free(c); +} + +static int collection_db_read(sd_bus *bus, struct sqlite3 *db, + struct collection **p, const char *root) +{ + const char *query, *alias, *label; + uint64_t created, modified; + sqlite3_stmt *stmt; + int ret; + + query = "SELECT alias, label, created, modified " + "FROM collections " + "WHERE collections.root = ? "; + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to prepare sql"); + return -EPERM; + } + + ret = sqlite3_bind_text(stmt, 1, root, -1, NULL); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to bind sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_DONE) { + ret = -ENOENT; + goto out_stmt_finalize; + } + if (ret != SQLITE_ROW) { + print_err("%s", "Failed to step sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + alias = (char *)sqlite3_column_text(stmt, 0); + label = (char *)sqlite3_column_text(stmt, 1); + created = sqlite3_column_int64(stmt, 2); + modified = sqlite3_column_int64(stmt, 3); + + if (root == NULL || label == NULL || created == 0 || modified == 0) { + print_err("%s", "Found null value in column"); + ret = -EINVAL; + goto out_stmt_finalize; + } + + ret = collection_alloc(bus, p, root, alias, label, created, modified); + +out_stmt_finalize: + sqlite3_finalize(stmt); + return ret; +} + +static int collection_db_write(struct sqlite3 *db, struct collection *c) +{ + sqlite3_stmt *stmt; + const char *query; + int ret; + + query = "INSERT INTO " + "collections(root, label, alias, created, modified) " + "VALUES (?, ?, ?, ?, ?) "; + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to prepare sql"); + return -EPERM; + } + + ret = sqlite3_bind_text(stmt, 1, c->root, -1, NULL); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to bind sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + ret = sqlite3_bind_text(stmt, 2, c->label, -1, NULL); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to bind sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + ret = sqlite3_bind_text(stmt, 3, c->alias, -1, NULL); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to bind sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + ret = sqlite3_bind_int64(stmt, 4, c->created); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to bind sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + ret = sqlite3_bind_int64(stmt, 5, c->modified); + if (ret != SQLITE_OK) { + print_err("%s", "Failed to bind sql"); + ret = -EPERM; + goto out_stmt_finalize; + } + + ret = sqlite3_step(stmt); + if (ret != SQLITE_DONE) { + print_err("%s", "No such alias"); + ret = -EPERM; + goto out_stmt_finalize; + } + +out_stmt_finalize: + sqlite3_finalize(stmt); + return ret; +} + +static int collection_alloc(sd_bus *bus, struct collection **p, + const char *root, const char *alias, + const char *label, uint64_t created, + uint64_t modified) +{ + struct collection *collection; + int ret; + + *p = malloc(sizeof(**p)); + if (*p == NULL) { + print_err("Failed to make collection: %s", strerror(errno)); + return -errno; + } + collection = *p; + collection->slot = NULL; + collection->root = NULL; + collection->alias = NULL; + collection->label = NULL; + collection->locked = 0; + collection->created = created; + collection->modified = modified; + + collection->root = strdup(root); + if (collection->root == NULL) { + collection_free(collection); + print_err("%s", strerror(errno)); + return -errno; + } + + collection->label = strdup(label); + if (collection->label == NULL) { + collection_free(collection); + print_err("%s", strerror(errno)); + return -errno; + } + + collection->alias = strdup(alias); + if (collection->alias == NULL) { + collection_free(collection); + print_err("%s", strerror(errno)); + return -errno; + } + + ret = asprintf(&collection->path, DBUS_OBJECT_PATH "/collection/%s", + collection->root); + if (ret < 0) { + collection_free(collection); + print_err("%s", "Failed to create collection object path"); + return -ENOMEM; + } + ret = dbus_objpath_alnumify(collection->path); + if (ret < 0) { + collection_free(collection); + print_err("%s", strerror(-ret)); + return ret; + } + + ret = sd_bus_add_object_vtable(bus, &collection->slot, collection->path, + COLLECTION_IFACE, collection_vtable, + collection); + if (ret < 0) { + collection_free(collection); + print_err("Failed to connect to bus: %s", strerror(-ret)); + return ret; + } + + return 0; +} + +int collection_root_make(const char *label, const char *alias, char **root) +{ + int ret; + + if (label == NULL && alias == NULL) { + print_err("%s", strerror(EINVAL)); + return -EINVAL; + } + + ret = asprintf(root, DBUS_ROOT_PREFIX " %s keyring", + alias ? alias : label); + if (ret < 0) { + print_err("%s", "Failed to build collection root path"); + return -EPERM; + } + + return 0; +} + +int collection_new(sd_bus *bus, struct sqlite3 *db, struct collection **p, + const char *alias, const char *label, const char *root) +{ + uint64_t epoch; + int ret; + + ret = collection_db_read(bus, db, p, root); + if (ret != -ENOENT) + return ret; + + errno = 0; + epoch = time(NULL); + if (errno != 0) { + print_err("Failed to get time: %s", strerror(errno)); + return -errno; + } + + ret = collection_alloc(bus, p, root, alias, label, epoch, epoch); + if (ret < 0) + return ret; + + return collection_db_write(db, *p); +} |