aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsinanmohd <sinan@sinanmohd.com>2023-12-27 16:05:41 +0530
committersinanmohd <sinan@sinanmohd.com>2023-12-29 23:22:06 +0530
commit438ad16d03f38e0e444f6ad575078ee949679a86 (patch)
tree0688901d51b9b1736679ac92af5a4636d2553bed
repo: init
-rw-r--r--.gitignore2
-rw-r--r--Makefile13
-rw-r--r--flake.lock27
-rw-r--r--flake.nix30
-rw-r--r--gpg.c64
-rw-r--r--gpg.h1
-rw-r--r--pass.c52
-rw-r--r--pass_util.c78
-rw-r--r--pass_util.h1
-rw-r--r--util.c33
-rw-r--r--util.h16
11 files changed, 317 insertions, 0 deletions
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 <stdio.h>
+#include <locale.h>
+
+#include <gpgme.h>
+
+#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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <linux/limits.h>
+
+#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 <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/limits.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+
+#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