From 243c88e20bad08a7b2fe268cec3a7b5129f461a2 Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Sat, 20 Apr 2024 19:08:55 +0530 Subject: npassd: init --- README.md | 29 +++++++++++++++-- flake.nix | 13 +++++--- include/npassd/common.h | 1 + include/npassd/service.h | 14 +++++++++ include/npassd/session.h | 19 ++++++++++++ meson.build | 3 ++ src/libnpass/meson.build | 2 +- src/npassd/meson.build | 15 +++++++++ src/npassd/npassd.c | 63 +++++++++++++++++++++++++++++++++++++ src/npassd/service.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ src/npassd/session.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 308 insertions(+), 9 deletions(-) create mode 100644 include/npassd/common.h create mode 100644 include/npassd/service.h create mode 100644 include/npassd/session.h create mode 100644 src/npassd/meson.build create mode 100644 src/npassd/npassd.c create mode 100644 src/npassd/service.c create mode 100644 src/npassd/session.c diff --git a/README.md b/README.md index 21eef9a..8daca01 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ section. Todo ==== -- [x] cmdline +- [x] npass (cli) - [x] pass init - [x] pass ls - [x] pass rm @@ -18,15 +18,38 @@ Todo - [x] pass gen - [x] pass cat - [x] pass help -- [ ] dbus +- [ ] npassd (dbus) + - [ ] org.freedesktop.Secret.Service + - [x] OpenSession + - [ ] CreateCollection + - [ ] SearchItems + - [ ] Unlock + - [ ] Lock + - [ ] GetSecrets + - [ ] ReadAlias + - [ ] SetAlias + - [ ] CollectionCreated + - [ ] CollectionDeleted + - [ ] CollectionChanged + - [ ] READ + - [x] org.freedesktop.Secret.Session + - [x] Close + - [ ] org.freedesktop.Secret.Item + - [ ] org.freedesktop.Secret.Collection + - [ ] org.freedesktop.Secret.Prompt - [x] nix flake - [x] shell - [x] pkg + - [ ] module Dependencies ============ -- meson (*Compile-time) +- meson (*) +- pkg-config (*+) - gpgme +- basu, elogind or systemd (+) + +_\* build-time dependency, + npassd dependency_ Installation ============ diff --git a/flake.nix b/flake.nix index c3e1b2b..2d53f76 100644 --- a/flake.nix +++ b/flake.nix @@ -20,6 +20,9 @@ buildInputs = with pkgs; [ gpgme + systemdLibs + + pkg-config meson ninja @@ -39,20 +42,20 @@ }; }); - packages = forAllSystems ({ system, pkgs }: let - inherit (pkgs) meson ninja gpgme; - in { + packages = forAllSystems ({ system, pkgs }: { npass = pkgs.stdenv.mkDerivation (finalAttrs: { pname = "npass"; version = self.shortRev or self.dirtyShortRev; src = ./.; - nativeBuildInputs = [ + nativeBuildInputs = with pkgs; [ meson ninja + pkg-config ]; - buildInputs = [ + buildInputs = with pkgs; [ gpgme + systemdLibs ]; meta = { diff --git a/include/npassd/common.h b/include/npassd/common.h new file mode 100644 index 0000000..b3ef866 --- /dev/null +++ b/include/npassd/common.h @@ -0,0 +1 @@ +#define DBUS_OBJECT_PATH "/org/freedesktop/secrets" diff --git a/include/npassd/service.h b/include/npassd/service.h new file mode 100644 index 0000000..e1a42fc --- /dev/null +++ b/include/npassd/service.h @@ -0,0 +1,14 @@ +#include + +#include "npassd/session.h" + +#define MAX_SESSION 128 + +struct service { + sd_bus *bus; + sd_bus_slot *slot; + struct session session[MAX_SESSION]; +}; + +int service_init(sd_bus *bus, struct service *service); +void service_free(struct service *service); diff --git a/include/npassd/session.h b/include/npassd/session.h new file mode 100644 index 0000000..6763c6a --- /dev/null +++ b/include/npassd/session.h @@ -0,0 +1,19 @@ +#include +#include + +#include "npassd/common.h" + +#define SESSION_IFACE "org.freedesktop.Secret.Session" + +/* reusable slots */ +struct session { + bool isactive; + sd_bus_slot *slot; + /* +32 for snprintf("/session/%d") */ + char path[sizeof(DBUS_OBJECT_PATH) + 32]; +}; + +void session_init(struct session *s, size_t n); +int session_slot_available(struct session *s, size_t n); +int session_free(struct session *s); +int session_new(sd_bus *bus, struct session *s, unsigned slot_no); diff --git a/meson.build b/meson.build index 0384579..b77292e 100644 --- a/meson.build +++ b/meson.build @@ -19,7 +19,10 @@ add_project_arguments( ) gpgme_dep = dependency('gpgme', version: '>= 1.0') +sdbus_dep = dependency('libsystemd', 'libelogind', 'basu') + npass_inc = include_directories('include') subdir('src/libnpass') +subdir('src/npassd') subdir('src/npass') diff --git a/src/libnpass/meson.build b/src/libnpass/meson.build index 1ce4621..ac3cd1d 100644 --- a/src/libnpass/meson.build +++ b/src/libnpass/meson.build @@ -3,7 +3,7 @@ lib_npass = static_library( [ 'util.c', 'gpg.c', - 'libnpass.c' + 'libnpass.c', ], dependencies: gpgme_dep, diff --git a/src/npassd/meson.build b/src/npassd/meson.build new file mode 100644 index 0000000..10302cd --- /dev/null +++ b/src/npassd/meson.build @@ -0,0 +1,15 @@ +e = executable( + 'npassd', + [ + 'npassd.c', + 'service.c', + 'session.c', + ], + + include_directories: npass_inc, + dependencies: sdbus_dep, + link_with: lib_npass, + install: true, +) + +test('npassd', e) diff --git a/src/npassd/npassd.c b/src/npassd/npassd.c new file mode 100644 index 0000000..a2f5173 --- /dev/null +++ b/src/npassd/npassd.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +#include "npassd/service.h" +#include "util.h" + +#define DBUS_WELL_KNOWN_NAME "org.freedesktop.secrets" + +int main(void) +{ + int ret; + sd_bus *bus; + struct service service; + + ret = sd_bus_open_user(&bus); + if (ret < 0) { + print_err("Failed to connect to bus: %s", strerror(-ret)); + return EXIT_FAILURE; + } + + ret = sd_bus_request_name(bus, DBUS_WELL_KNOWN_NAME, 0); + if (ret < 0) { + print_err("Failed to acquire service name: %s", strerror(-ret)); + if (ret == -EEXIST) + print_err( + "%s", + "Is a secret-service daemon already running?"); + + goto out_free_bus; + } + + ret = service_init(bus, &service); + if (ret < 0) + goto out_free_bus; + + for (;;) { + ret = sd_bus_process(bus, NULL); + if (ret < 0) { + fprintf(stderr, "Failed to process bus: %s\n", + strerror(-ret)); + goto out_free_service; + } + if (ret > 0) + continue; + + ret = sd_bus_wait(bus, UINT64_MAX); + if (ret < 0) { + fprintf(stderr, "Failed to wait on bus: %s\n", + strerror(-ret)); + goto out_free_service; + } + } + +out_free_service: + service_free(&service); +out_free_bus: + sd_bus_unref(bus); + + return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/npassd/service.c b/src/npassd/service.c new file mode 100644 index 0000000..5628e45 --- /dev/null +++ b/src/npassd/service.c @@ -0,0 +1,77 @@ +#include +#include +#include + +#include "npassd/common.h" +#include "npassd/service.h" +#include "util.h" + +#define SERVICE_IFACE "org.freedesktop.Secret.Service" + +static int handle_open_session(sd_bus_message *msg, void *data, + sd_bus_error *ret_error); + +static const sd_bus_vtable service_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("OpenSession", "sv", "vo", handle_open_session, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END, +}; + +static int handle_open_session(sd_bus_message *msg, void *data, + sd_bus_error *ret_error) +{ + struct service *service = data; + int ret, session_slot_no; + char *algo; + + ret = sd_bus_message_read(msg, "s", &algo); + if (ret < 0) + return ret; + + ret = strcmp(algo, "plain"); + if (ret) { + sd_bus_error_set_const(ret_error, SD_BUS_ERROR_NOT_SUPPORTED, + "Unsupported encryption algorithm"); + return -ENOTSUP; + } + + session_slot_no = session_slot_available(service->session, MAX_SESSION); + if (session_slot_no < 0) { + print_err("No free slot available: %s", + strerror(-session_slot_no)); + return ret; + } + + ret = session_new(service->bus, &service->session[session_slot_no], + session_slot_no); + if (ret < 0) + return ret; + + return sd_bus_reply_method_return( + msg, "vs", "s", "", service->session[session_slot_no].path); +} + +void service_free(struct service *service) +{ + for (int i = 0; i < MAX_SESSION; i++) + session_free(&service->session[i]); + + sd_bus_slot_unref(service->slot); +} + +int service_init(sd_bus *bus, struct service *service) +{ + int ret; + + service->bus = bus; + session_init(service->session, MAX_SESSION); + + ret = sd_bus_add_object_vtable(service->bus, &service->slot, + DBUS_OBJECT_PATH, SERVICE_IFACE, + service_vtable, service); + if (ret < 0) + print_err("Failed to connect to bus: %s", strerror(-ret)); + + return ret; +} diff --git a/src/npassd/session.c b/src/npassd/session.c new file mode 100644 index 0000000..e674bb7 --- /dev/null +++ b/src/npassd/session.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include + +#include "npassd/common.h" +#include "npassd/session.h" +#include "util.h" + +static int handle_close(__attribute__((unused)) sd_bus_message *msg, void *data, + __attribute__((unused)) sd_bus_error *ret_error); + +static const sd_bus_vtable session_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("Close", "", "", handle_close, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END, +}; + +static int handle_close(__attribute__((unused)) sd_bus_message *msg, void *data, + __attribute__((unused)) sd_bus_error *ret_error) +{ + int ret; + + ret = session_free((struct session *)data); + if (ret < 0) + print_err("Failed to free session: %s", strerror(-ret)); + + return ret; +} + +int session_slot_available(struct session *s, size_t n) +{ + static pthread_mutex_t lock; + + pthread_mutex_lock(&lock); + for (size_t i = 0; i < n; i++) { + if (s[i].isactive == false) { + pthread_mutex_unlock(&lock); + return i; + } + } + + pthread_mutex_unlock(&lock); + return -ENOMEM; +} + +int session_new(sd_bus *bus, struct session *session, unsigned session_no) +{ + int ret; + + snprintf(session->path, sizeof(session->path), + DBUS_OBJECT_PATH "/session/%d", session_no); + ret = sd_bus_add_object_vtable(bus, &session->slot, session->path, + SESSION_IFACE, session_vtable, session); + if (ret < 0) + print_err("Failed to create session: %s", strerror(-ret)); + else + session->isactive = true; + + return ret; +} + +int session_free(struct session *s) +{ + if (!s->isactive) + return -EINVAL; + + s->isactive = false; + sd_bus_slot_unref(s->slot); + + return 0; +} + +void session_init(struct session *s, size_t n) +{ + for (size_t i = 0; i < n; i++) + s[i].isactive = false; +} -- cgit v1.2.3