diff options
Diffstat (limited to 'src/libnpass/libnpass.c')
-rw-r--r-- | src/libnpass/libnpass.c | 170 |
1 files changed, 168 insertions, 2 deletions
diff --git a/src/libnpass/libnpass.c b/src/libnpass/libnpass.c index aa1a285..37fc40c 100644 --- a/src/libnpass/libnpass.c +++ b/src/libnpass/libnpass.c @@ -7,6 +7,7 @@ #include <libgen.h> #include <termios.h> #include <stdio.h> +#include <dirent.h> #include "libnpass/libnpass.h" #include "libnpass/gpg.h" @@ -14,8 +15,8 @@ #include "util.h" -#define DEF_PASS_DIR "pass" -#define FPR_MAX 256 +#define DEF_PASS_DIR "pass" +#define FPR_MAX NAME_MAX static char pass_dir[PATH_MAX] = {0}; const char *pass_gen_set[] = { @@ -32,6 +33,7 @@ const char *pass_gen_set[] = { }; int set_pass_dir(void); +int is_storeobj(struct dirent *dir); int set_pass_dir(void) { const char *env; @@ -59,6 +61,170 @@ int set_pass_dir(void) { return 1; } +int pass_store_cmp(const void *vp1, const void *vp2) { + struct store *sp1, *sp2; + + sp1 = (struct store *) vp1; + sp2 = (struct store *) vp2; + return strcmp(sp1->name, sp2->name); +} + +int is_storeobj(struct dirent *dir) { + int r; + char *s; + + switch (dir->d_type) { + case DT_DIR: + r = strcmp(dir->d_name, "."); + if (r) + r = strcmp(dir->d_name, ".."); + + return r; + break; + case DT_REG: + s = strrchr(dir->d_name, '.'); + if (!s) + return 0; + + r = strcmp(s, ".gpg"); + return (r == 0); + break; + default: + return 0; + break; + } +} + +pass_store_t pass_store_type(const char *spath) { + int r; + struct stat sbuf; + char abs_path[PATH_MAX]; + + r = set_pass_dir(); + if (r) + err_ret(PASS_STORE_INV, "PASSWORD_STORE_DIR not set"); + + r = snprintf(abs_path, sizeof(abs_path) - 1, "%s/%s", + pass_dir, spath); + if (r >= (int) sizeof(abs_path)) + err_ret(PASS_STORE_INV, "path exceeded PATH_MAX"); + r = stat(abs_path, &sbuf); + if (!r && (sbuf.st_mode & S_IFMT) == S_IFDIR) + return PASS_STORE_DIR; + + r = snprintf(abs_path, sizeof(abs_path) - 1, "%s/%s.gpg", + pass_dir, spath); + if (r >= (int) sizeof(abs_path)) + err_ret(PASS_STORE_INV, "path exceeded PATH_MAX"); + r = stat(abs_path, &sbuf); + if (r) + err_ret(PASS_STORE_INV, "%s", strerror(errno)); + + if ((sbuf.st_mode & S_IFMT) == S_IFREG) { + return PASS_STORE_ENC; + } else { + err_ret(PASS_STORE_INV, "%s is not a regular file", abs_path); + } +} + +DIR *openstore(const char *spath) { + int r; + DIR *d; + const char *path; + char abs_path[PATH_MAX]; + + r = set_pass_dir(); + if (r) + err_ret(NULL, "PASSWORD_STORE_DIR not set"); + + if (spath) { + r = snprintf(abs_path, sizeof(abs_path) - 1, "%s/%s", + pass_dir, spath); + if (r >= (int) sizeof(abs_path)) + err_ret(NULL, "path exceeded PATH_MAX"); + + path = abs_path; + } else { + path = pass_dir; + } + + d = opendir(path); + if (!d) + err_ret(NULL, "%s", strerror(errno)); + + return d; +} + +int readstore(DIR *dirp, struct store *s) { + struct dirent *dir; + + errno = 0; + + while ((dir = readdir(dirp))) { + if (is_storeobj(dir)) + break; + } + + if (!dir) { + if (errno != 0) + err_ret(1, "%s", strerror(errno)); + + return EOF; + } + + strncpy(s->name , dir->d_name, sizeof(s->name)); + switch (dir->d_type) { + case DT_DIR: + s->type = PASS_STORE_DIR; + break; + case DT_REG: + /* this is safe since is_storeobj() + * rejects files without .gpg suffix */ + *(strrchr(s->name, '.')) = '\0'; + s->type = PASS_STORE_ENC; + break; + default: + s->type = PASS_STORE_INV; + break; + } + + return 0; +} + +int readstore_all(const char *path, struct store **stor) { + int r; + void *p; + size_t i; + DIR *dirp; + size_t len = PATH_MAX; + + *stor = malloc(sizeof(struct store) * len); + if (!*stor) + err_ret(-1, "%s", strerror(errno)); + + dirp = openstore(path); + if (!dirp) { + free(*stor); + return -1; + }; + + for (i = 0; !(r = readstore(dirp, *stor + i)); i++) { + if (i < len - 1) + continue; + + len *= 2; + p = realloc(*stor, sizeof(**stor) * len); + if (!p) { + free(*stor); + err_ret(-1, "%s", strerror(errno)); + } else { + *stor = p; + } + } + + return i; +} + int pass_init(const char *fpr) { int r; |