From 438ad16d03f38e0e444f6ad575078ee949679a86 Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Wed, 27 Dec 2023 16:05:41 +0530 Subject: repo: init --- .gitignore | 2 ++ Makefile | 13 +++++++++++ flake.lock | 27 +++++++++++++++++++++ flake.nix | 30 ++++++++++++++++++++++++ gpg.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ gpg.h | 1 + pass.c | 52 +++++++++++++++++++++++++++++++++++++++++ pass_util.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pass_util.h | 1 + util.c | 33 ++++++++++++++++++++++++++ util.h | 16 +++++++++++++ 11 files changed, 317 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 gpg.c create mode 100644 gpg.h create mode 100644 pass.c create mode 100644 pass_util.c create mode 100644 pass_util.h create mode 100644 util.c create mode 100644 util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5fe4433 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +pass diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c636e6d --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +OBJECTS = pass.o pass_util.o util.o gpg.o +CC = gcc +CFLAGS = -g -Wvla -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wpedantic -fsanitize=address + +pass: $(OBJECTS) + $(CC) $(CFLAGS) -o pass $(OBJECTS) -l gpgme + +pass.o: pass_util.h util.h +pass_util.o: util.h gpg.h + +.PHONY: clean +clean: + rm -f pass $(OBJECTS) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c64f96f --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1703438236, + "narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=", + "owner": "NixOs", + "repo": "nixpkgs", + "rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b", + "type": "github" + }, + "original": { + "owner": "NixOs", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d6a6346 --- /dev/null +++ b/flake.nix @@ -0,0 +1,30 @@ +{ + description = "A passwordstore and Secret Service API implementation"; + + inputs.nixpkgs.url = "github:NixOs/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: let + lib = nixpkgs.lib; + + supportedSystems = lib.platforms.unix; + forSystem = f: system: f { + inherit system; + pkgs = import nixpkgs { inherit system; }; + }; + forAllSystems = f: lib.genAttrs supportedSystems (forSystem f); + in { + devShells = forAllSystems ({ system, pkgs, ... }: { + default = pkgs.mkShell { + name = "dev"; + + buildInputs = with pkgs; [ gpgme ]; + shellHook = '' + [ -z "$XDG_DATA_HOME" ] && + export XDG_DATA_HOME="$HOME/.local/share" + export PASSWORD_STORE_DIR="$XDG_DATA_HOME/debug_pass" + export PS1="\033[0;32m[󰟵 ]\033[0m $PS1" + ''; + }; + }); + }; +} diff --git a/gpg.c b/gpg.c new file mode 100644 index 0000000..ab7d8dd --- /dev/null +++ b/gpg.c @@ -0,0 +1,64 @@ +#include +#include + +#include + +#include "gpg.h" + +#define fail_if_err(err) \ + if (err) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, \ + gpgme_strsource(err), gpgme_strerror(err)); \ + gpg_cleanup(); \ + return 1; \ + } + +static gpgme_ctx_t ctx = NULL; +static gpgme_key_t key = NULL; + +int gpg_init(void); +void gpg_cleanup(void); + +int gpg_init(void) +{ + gpgme_error_t err; + const char *local = setlocale(LC_ALL, ""); + + gpgme_check_version(NULL); + gpgme_set_locale(NULL, LC_CTYPE, local); +#ifdef LC_MESSAGES + gpgme_set_locale(NULL, LC_MESSAGES, local); +#endif + + err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP); + fail_if_err(err); + err = gpgme_new(&ctx); + fail_if_err(err); + + return 0; +} + +void gpg_cleanup(void) +{ + if (ctx) + gpgme_key_release(key); + if (key) + gpgme_release(ctx); +} + +int gpg_key_validate(const char *fpr) +{ + int r; + gpgme_error_t err; + + r = gpg_init(); + if (r) + return r; + + err = gpgme_get_key(ctx, fpr, &key, 1); + fail_if_err(err); + + gpg_cleanup(); + + return 0; +} diff --git a/gpg.h b/gpg.h new file mode 100644 index 0000000..36904df --- /dev/null +++ b/gpg.h @@ -0,0 +1 @@ +int gpg_key_validate(const char *fpr); diff --git a/pass.c b/pass.c new file mode 100644 index 0000000..41e8a76 --- /dev/null +++ b/pass.c @@ -0,0 +1,52 @@ +#include +#include +#include + +#include "pass_util.h" +#include "util.h" + +void print_usage(void); + +void print_usage(void) +{ + printf("Usage: pass COMMAND\n\n" + + "Commands:\n" + " init key-id/fingerprint\n" + " Initialize new password storage\n" + " ls [ pass-path ]\n" + " List passwords\n" + " rm pass-name\n" + " Remove password\n" + " add pass-name\n" + " Add new password\n" + " gen pass-name\n" + " Generate new password\n" + " cat pass-name\n" + " Show encrypted password\n" + " help\n" + " Show this help\n"); +} + +int main(int argc, char *argv[]) +{ + int r = 0; + + if (!--argc) { + print_usage(); + exit(EXIT_FAILURE); + } + ++argv; + + + if (!strcmp("help", *argv)) { + print_usage(); + } else if (!strcmp("init", *argv)) { + if (!argv[1]) + err_die("invalid usage, try pass help"); + + r = pass_init(argv[1]); + } + + return r; +} diff --git a/pass_util.c b/pass_util.c new file mode 100644 index 0000000..bcc4aaa --- /dev/null +++ b/pass_util.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include + +#include "pass_util.h" +#include "util.h" +#include "gpg.h" + +#define DEF_PASS_DIR "pass" + +char pass_dir[PATH_MAX]; + +int set_pass_dir(void); + +int set_pass_dir(void) { + const char *env; + + env = getenv("PASSWORD_STORE_DIR"); + if (env) { + strncpy(pass_dir, env, sizeof(pass_dir) - 1); + return 0; + } + + env = getenv("XDG_DATA_HOME"); + if (env) { + snprintf(pass_dir, sizeof(pass_dir) - 1, "%s/%s", env, + DEF_PASS_DIR); + return 0; + } + + env = getenv("HOME"); + if (env) { + snprintf(pass_dir, sizeof(pass_dir) - 1, "%s/%s/%s", env, + ".local/share", DEF_PASS_DIR); + return 0; + } + + return 1; +} + +int pass_init(const char *fpr) +{ + int r; + char gpg_id_path[PATH_MAX]; + FILE *gpg_id; + + r = set_pass_dir(); + if (r) + err_die("PASSWORD_STORE_DIR not set"); + + r = gpg_key_validate(fpr); + if (r) + err_die("key not usable, try gpg --full-generate-key"); + + + r = r_mkdir(pass_dir, S_IRWXU); + if (r) + err_die("%s %s", pass_dir, strerror(errno)); + + r = snprintf(gpg_id_path, sizeof(gpg_id_path), "%s/%s", pass_dir, ".gpg-id"); + if (r > (int) sizeof(gpg_id_path)) + err_die("path exceeded PATH_MAX"); + + gpg_id = fopen(gpg_id_path, "w"); + if (!gpg_id) + err_die("%s %s", gpg_id_path, strerror(errno)); + + r = fwrite(fpr, strlen(fpr), 1,gpg_id); + if (!r) + err_die("write failed"); + + fclose(gpg_id); + + return 0; +} diff --git a/pass_util.h b/pass_util.h new file mode 100644 index 0000000..a2cacdc --- /dev/null +++ b/pass_util.h @@ -0,0 +1 @@ +int pass_init(const char *fpr); diff --git a/util.c b/util.c new file mode 100644 index 0000000..6e6079e --- /dev/null +++ b/util.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#include "util.h" + +int r_mkdir(const char *path, mode_t mode) +{ + int r; + size_t len; + char *p; + char tmp[NAME_MAX + 1]; + + strncpy(tmp, path, sizeof(tmp) - 1); + len = strlen(tmp); + if(tmp[len - 1] == '/') + tmp[len - 1] = '\0'; + + for (p = tmp + 1; *p; ++p) { + if (*p == '/') { + *p = '\0'; + + r = mkdir(tmp, mode); + if (r && !(errno & EEXIST)) + return r; + + *p = '/'; + } + } + + return mkdir(path, mode); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..be1c5ec --- /dev/null +++ b/util.h @@ -0,0 +1,16 @@ +#ifndef UTIL_H + +#include +#include + +#define err_die(...) {\ + fprintf(stderr, "err: %s:%d: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fputc('\n', stderr); \ + return 1; \ +} + +int r_mkdir(const char *path, mode_t mode); + +#define UTIL_H +#endif -- cgit v1.2.3