#include #include #include #include #include #include "libnpass/libnpass.h" #include "util.h" #define invalid_usage_err_ret() \ err_ret(1, "invalid usage, try pass help") #define DEF_DEPTTH 16; #define BLUE "\e[0;34m" #define NCOL "\e[0m" typedef enum { DEPTH_ITS_OVER = 0, DEPTH_NOT_OVER = 1, } depth_state_t; void print_usage(void); int cat(const char *path); int add(const char *path); int gen(int argc, char *argv[]); int ls(const char *path, size_t depth); 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 [-d|-a|-g|-l] pass-name\n" " Generate new password\n" " cat pass-name\n" " Show encrypted password\n" " help\n" " Show this help\n"); } int cat(const char *path) { int r; r = pass_cat(stdout, path); if (!r && isatty(STDOUT_FILENO)) putchar('\n'); return r; } int ls(const char *path, size_t depth) { void *p; char *prefix; int i, j, len; struct store *stor; char new_path[PATH_MAX]; static depth_state_t *depth_state; static size_t depth_state_len = DEF_DEPTTH; len = readstore_all(path, &stor); if (len < 0) return 1; if (!depth) { depth_state = malloc(sizeof(depth_state_t) * depth_state_len); puts((path) ? path : "Password Store"); } else if (depth == depth_state_len - 1) { depth_state_len *= 2; p = realloc(stor, sizeof(depth_state[0]) * len); if (!p) err_ret(1, "%s", strerror(errno)); depth_state = p; } qsort(stor, len, sizeof(stor[0]), pass_store_cmp); for (i = 0; i < len; i++) { if (i == len - 1) { prefix = "└──"; depth_state[depth] = DEPTH_ITS_OVER; } else { prefix = "├──"; depth_state[depth] = DEPTH_NOT_OVER; } for (j = 0; (size_t) j < depth; j++) printf("%s ", (depth_state[j]) == DEPTH_ITS_OVER ? " " : "│"); if (stor[i].type == PASS_STORE_DIR) { printf("%s %s%s%s\n", prefix, BLUE, stor[i].name, NCOL); snprintf(new_path, sizeof(new_path), "%s/%s", (path) ? path : "", stor[i].name); ls(new_path, depth + 1); } else { printf("%s %s\n", prefix, stor[i].name); } } if (!depth) free(depth_state); free(stor); return 0; } int add(const char *path) { char *p1 = NULL, *p2 = NULL; FILE *in; size_t n; int r; in = fopen("/dev/tty", "r"); if (!in) in = stdin; fputs("Password: ", stdout); r = pass_getpass(&p1, &n, in); if (r < 0) { if (in != stdin) fclose(in); err_ret(1, "%d:%s:", errno, strerror(errno)); } fputs("\nRetype password: ", stdout); r = pass_getpass(&p2, &n, in); putc('\n', stdout); if (r < 0) { if (in != stdin) fclose(in); if (p1) free(p1); err_ret(1, "%d:%s:", errno, strerror(errno)); } if (in != stdin) fclose(in); if (strcmp(p1, p2)) { free(p1); free(p2); err_ret(1, "Sorry, passwords do not match"); } free(p1); r = pass_add(path, p2, n); free(p2); return r; } int gen(int argc, char *argv[]) { char *pass; int opt, r = 0; size_t len = 30; pass_gen_t gen = PASS_GEN_GRAPH; while ((opt = getopt(argc, argv, "dagl:")) != -1) { switch (opt) { case 'd': gen = PASS_GEN_DIGIT; break; case 'a': gen = PASS_GEN_ALNUM; break; case 'g': gen = PASS_GEN_GRAPH; break; case 'l': len = atoi(optarg); break; } } if (optind != argc - 1) invalid_usage_err_ret(); pass = malloc(sizeof(char) * len); if (!pass) err_ret(1, "%s", strerror(errno)); r = pass_gen(gen, pass, len); if (r) goto out_free_pass; r = pass_add(argv[optind], pass, len); if (!r) printf("%s\n", pass); out_free_pass: free(pass); return r; } int main(int argc, char *argv[]) { int r = 0; pass_store_t store_type; ++argv; if (!--argc) { r = ls(NULL, 0); } else if (!strcmp("help", *argv)) { print_usage(); } else if (!strcmp("init", *argv)) { if (argc != 2) invalid_usage_err_ret(); r = pass_init(argv[1]); } else if (!strcmp("ls", *argv)) { if (argc > 2) invalid_usage_err_ret(); r = ls(argv[1], 0); } else if (!strcmp("cat", *argv)) { if (argc != 2) invalid_usage_err_ret(); r = cat(argv[1]); } else if (!strcmp("add", *argv)) { if (argc != 2) invalid_usage_err_ret(); r = add(argv[1]); } else if (!strcmp("rm", *argv)) { if (argc != 2) invalid_usage_err_ret(); r = pass_rm(argv[1]); } else if (!strcmp("gen", *argv)) { if (argc < 2) invalid_usage_err_ret(); r = gen(argc, argv); } else if (argc == 1){ store_type = pass_store_type(*argv); switch (store_type) { case PASS_STORE_DIR: r = ls(*argv, 0); break; case PASS_STORE_ENC: r = cat(*argv); break; default: return 1; break; } } else { invalid_usage_err_ret(); } return r; }