aboutsummaryrefslogtreecommitdiffstats
path: root/src/exec-cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exec-cmd.c')
-rw-r--r--src/exec-cmd.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/src/exec-cmd.c b/src/exec-cmd.c
new file mode 100644
index 0000000..6aced93
--- /dev/null
+++ b/src/exec-cmd.c
@@ -0,0 +1,495 @@
+/***
+ This file is part of LockPassword
+ Copyright (C) 2020-2021 Aleksandr D. Goncharov (Joursoir) <chat@joursoir.net>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include "exec-cmd.h"
+#include "constants.h"
+#include "easydir.h"
+#include "implementation.h"
+#include "exec-cmd.h"
+#include "tree.h"
+
+int cmd_init(int argc, char *argv[])
+{
+ const char description[] = "init gpg-key\n";
+ int retval = 0, result;
+ char *gpg_key = argv[2];
+ if(gpg_key == NULL)
+ usageprint("%s", description);
+
+ // create .gpg-key in storage
+ FILE *filekey = fopen(GPGKEY_FILE, "w");
+ if(!filekey)
+ errprint_r(1, "%s\n", strerror(errno));
+
+ result = fputs(gpg_key, filekey);
+ if(result == EOF)
+ errprint_ptr(&retval, 1, "%s\n", strerror(errno));
+ else
+ printf("LockPassword initialized for %s\n", gpg_key);
+
+ fclose(filekey);
+ return retval;
+}
+
+int cmd_insert(int argc, char *argv[])
+{
+ const char description[] = "insert [-ecf] passname\n";
+ int retval = 0, result;
+ int flag_echo = 0, flag_force = 0, flag_copy = 0;
+ const struct option long_options[] = {
+ {"echo", no_argument, NULL, 'e'},
+ {"force", no_argument, NULL, 'f'},
+ {"copy", no_argument, NULL, 'c'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while((result = getopt_long(argc, argv, "efc", long_options, NULL)) != -1) {
+ switch(result) {
+ case 'e': { flag_echo = 1; break; }
+ case 'f': { flag_force = 1; break; }
+ case 'c': { flag_copy = 1; break; }
+ default: usageprint("%s", description);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "insert"
+ dbgprint("passname: %s\n", argv[optind]);
+
+ char *path = argv[optind];
+ if(path == NULL)
+ usageprint("%s", description);
+
+ result = check_sneaky_paths(path);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+
+ if(file_exist(path) == F_ISFILE) {
+ if(!flag_force) {
+ if(overwrite_answer(path) != 'y')
+ return 1;
+ }
+ }
+
+ char *f_pass, *s_pass;
+ do { // START DO
+
+ if(!flag_echo) {
+ visible_enter(0);
+
+ printf("Type your password: ");
+ f_pass = get_input(minlen_pass, maxlen_pass);
+ printf("\n");
+ if(f_pass == NULL) {
+ errprint_ptr(&retval, 1, "Incorrect password\n");
+ break;
+ }
+
+ printf("Type your password again: ");
+ s_pass = get_input(minlen_pass, maxlen_pass);
+ printf("\n");
+ if(s_pass == NULL) {
+ errprint_ptr(&retval, 1, "Incorrect password\n");
+ break;
+ }
+
+ if(strcmp(f_pass, s_pass) != 0) {
+ errprint_ptr(&retval, 1, "Password do not match\n");
+ break;
+ }
+ }
+ else {
+ printf("Type your password: ");
+ f_pass = get_input(minlen_pass, maxlen_pass);
+ if(f_pass == NULL) {
+ errprint_ptr(&retval, 1, "Incorrect password\n");
+ break;
+ }
+ }
+
+ result = insert_pass(path, f_pass);
+ if(result) {
+ errprint_ptr(&retval, 1, "Can't add password to LockPassword\n");
+ break;
+ }
+ if(flag_copy)
+ copy_outside(f_pass);
+
+ printf("Password added successfully for %s\n", path);
+
+ } while(0); // END DO
+
+ visible_enter(1);
+ if(f_pass)
+ free(f_pass);
+ if(s_pass)
+ free(s_pass);
+ return retval;
+}
+
+int cmd_edit(int argc, char *argv[])
+{
+ const char description[] = "edit passname\n";
+ int result, fd, pid, len_pass, save_errno;
+ /* We expect tmpfs to be mounted at /dev/shm */
+ char path_tmpfile[] = "/dev/shm/lpass.XXXXXX";
+ char *editor, *password;
+ char *path = argv[2];
+ if(!path)
+ usageprint("%s", description);
+
+ result = check_sneaky_paths(path);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+
+ result = file_exist(path);
+ if(result == F_NOEXIST)
+ errprint_r(1, "No such file exists\n");
+ if(result == F_ISDIR)
+ errprint_r(1, "It's a directory\n");
+
+ editor = getenv("EDITOR");
+ if(!editor)
+ editor = STD_TEXT_EDITOR;
+
+ password = get_password(path);
+ if(password == NULL)
+ errprint_r(1, "Decrypt password failed\n");
+
+ fd = mkstemp(path_tmpfile);
+ if(fd == -1) {
+ free(password);
+ errprint_r(1, "Create temporary file failed: %s\n", strerror(errno));
+ }
+ dbgprint("tmp file: %s\n", path_tmpfile);
+
+ len_pass = strlen(password);
+ result = write(fd, password, len_pass);
+ free(password);
+ close(fd);
+ if(result != len_pass) {
+ unlink(path_tmpfile);
+ errprint_r(1, "Write password to temporary file failed\n");
+ }
+
+ // fork for text editor
+ char *editor_arg[] = {editor, path_tmpfile, NULL};
+ pid = fork();
+ if(pid == -1) {
+ unlink(path_tmpfile);
+ errprint_r(1, "Start %s failed: %s\n", editor, strerror(errno));
+ }
+ if(pid == 0) { /* new process */
+ execvp(editor, editor_arg);
+ perror(editor);
+ exit(1);
+ }
+ wait(&pid);
+
+ fd = open(path_tmpfile, O_RDONLY);
+ if(fd == -1) {
+ unlink(path_tmpfile);
+ errprint_r(1, "Open temporary file failed: %s\n", strerror(errno));
+ }
+
+ password = malloc(sizeof(char) * (maxlen_pass + 1));
+ len_pass = read(fd, password, maxlen_pass);
+ save_errno = errno;
+ close(fd);
+ unlink(path_tmpfile);
+ if(len_pass < minlen_pass) {
+ free(password);
+ if(len_pass == -1)
+ errprint_r(1, "Read temporary file failed: %s\n", strerror(save_errno));
+ else
+ errprint_r(1, "Min. password length is %d\n", minlen_pass);
+ }
+ password[len_pass-1] = '\0';
+ dbgprint("new pass: %s\n", password);
+
+ // encrypt
+ result = insert_pass(path, password);
+ free(password);
+ if(result)
+ errprint_r(1, "Can't add password to LockPassword\n");
+
+ return 0;
+}
+
+int cmd_generate(int argc, char *argv[])
+{
+ const char description[] = "generate [-l=pass-length] [-f] passname\n";
+ int pass_length = stdlen_pass;
+ int flag_force = 0, flag_copy = 0, result;
+ const struct option long_options[] = {
+ {"length", required_argument, NULL, 'l'},
+ {"force", no_argument, NULL, 'f'},
+ {"copy", no_argument, NULL, 'c'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while((result = getopt_long(argc, argv, "l:fc", long_options, NULL)) != -1) {
+ switch(result) {
+ // if optarg - incorrect number, atoi return 0
+ case 'l': { pass_length = atoi(optarg); break; }
+ case 'f': { flag_force = 1; break; }
+ case 'c': { flag_copy = 1; break; }
+ default: usageprint("%s", description);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "generate"
+ dbgprint("passname: %s\n", argv[optind]);
+
+ char *path = argv[optind];
+ if(path == NULL)
+ usageprint("%s", description);
+
+ if(pass_length < minlen_pass || pass_length > maxlen_pass)
+ errprint_r(1, "You typed an incorrect length\n");
+
+ result = check_sneaky_paths(path);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+
+ result = file_exist(path);
+ if(result == F_ISFILE) {
+ if(!flag_force) {
+ if(overwrite_answer(path) != 'y')
+ return 1;
+ }
+ }
+ else if(result == F_ISDIR)
+ errprint_r(1, "You can't generate password for directory\n");
+
+ // generate password
+ char *g_pass = gen_password(pass_length);
+
+ result = insert_pass(path, g_pass);
+ if(result) {
+ free(g_pass);
+ errprint_r(1, "Can't add password to LockPassword\n");
+ }
+
+ if(flag_copy)
+ copy_outside(g_pass);
+ else
+ printf("Generated password: %s\n", g_pass);
+ printf("Password added successfully for %s\n", path);
+ free(g_pass);
+ return 0;
+}
+
+int cmd_remove(int argc, char *argv[])
+{
+ const char description[] = "rm passname\n";
+ int result;
+ char *path = argv[2];
+ if(!path)
+ usageprint("%s", description);
+
+ result = check_sneaky_paths(path);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+
+ result = file_exist(path);
+ if(result == F_NOEXIST)
+ errprint_r(1, "No such file exists\n");
+ if(result == F_ISDIR) {
+ if(count_dir_entries(path) != 0)
+ errprint_r(1, "Directory not empty\n");
+ }
+
+ result = remove(path);
+ if(result)
+ errprint_r(1, "%s\n", strerror(errno));
+ return 0;
+}
+
+int cmd_move(int argc, char *argv[])
+{
+ /* we have a two situation:
+ 1) mv file file
+ 2) mv file directory */
+
+ const char description[] = "mv [-f] old-path new-path\n";
+ const struct option long_options[] = {
+ {"force", no_argument, NULL, 'f'},
+ {NULL, 0, NULL, 0}
+ };
+
+ int result, flag_force = 0;
+ while((result = getopt_long(argc, argv, "f", long_options, NULL)) != -1) {
+ switch(result) {
+ case 'f': { flag_force = 1; break; }
+ default: usageprint("%s", description);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "move"
+ if(!argv[optind] || !argv[optind+1])
+ usageprint("%s", description);
+
+ char *old_path = argv[optind];
+ char *new_path = argv[optind+1];
+ dbgprint("old-path = %s\n", old_path);
+ dbgprint("new-path = %s\n", new_path);
+
+ result = check_sneaky_paths(old_path);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+ result = file_exist(old_path);
+ if(result == F_NOEXIST)
+ errprint_r(1, "No such file exists\n");
+
+ result = check_sneaky_paths(new_path);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+ result = file_exist(new_path);
+ if(result != F_NOEXIST) {
+ if(!flag_force) {
+ if(overwrite_answer(new_path) != 'y')
+ return 1;
+ }
+ }
+
+ result = rename(old_path, new_path);
+ if(result)
+ errprint_r(1, "%s\n", strerror(errno));
+ return 0;
+}
+
+int cmd_help(int argc, char *argv[])
+{
+ printf("Synopsis:\n"
+ "\tlpass [command] [arguments] ...\n"
+
+ "Commands:\n"
+ "\tinit gpg-key\n"
+ "\t\tInitialize the password manager using the passed gpg-key.\n"
+ "\tinsert [-e, --echo] [-c, --copy] [-f, --force] passname\n"
+ "\t\tAdd the specified passname to the password manager.\n"
+ "\tedit [-t, --text-editor=text-editor] passname\n"
+ "\t\tOpen the specified passname in a text editor, waiting for changes.\n"
+ "\tgenerate [-l, --length=pass-length] [-c, --copy] [-f, --force] passname\n"
+ "\t\tGenerate a random password and write it in passname.\n"
+ "\tmv [-f, --force] old-path new-path\n"
+ "\t\tMove/rename old-path to new-path.\n"
+ "\trm passname\n"
+ "\t\tRemove the passname you specified from the password manager.\n"
+ "\thelp\n"
+ "\t\tPrint help information about commands and the application itself.\n"
+ "\tversion\n"
+ "\t\tPrint version information.\n"
+
+ "\nMore information may be found in the lpass(1) man page.\n");
+ return 0;
+}
+
+int cmd_version(int argc, char *argv[])
+{
+ printf("LockPassword v%s\n"
+ "Release date: %s\n\n"
+ "Copyright (C) 2020-2021 Aleksandr D. Goncharov (Joursoir)\n"
+ "License: GNU GPL version 3\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "This program comes with ABSOLUTELY NO WARRANTY.\n",
+ VERSION, DATE_RELEASE);
+ return 0;
+}
+
+int cmd_showtree(int argc, char *argv[])
+{
+ const char description[] = "[-c] [passname]\n";
+ int flag_copy = 0;
+ int retval = 0, result;
+ char *path;
+ const struct option long_options[] = {
+ {"copy", no_argument, NULL, 'c'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while((result = getopt_long(argc, argv, "c", long_options, NULL)) != -1) {
+ switch(result) {
+ case 'c': { flag_copy = 1; break; }
+ default: usageprint("%s", description);
+ }
+ }
+
+ if(argv[optind]) {
+ result = check_sneaky_paths(argv[optind]);
+ if(result)
+ errprint_r(1, "You have used forbidden paths\n");
+ path = malloc(sizeof(char) * (strlen(argv[optind]) + 1));
+ strcpy(path, argv[optind]);
+ }
+ else {
+ path = malloc(sizeof(char) * 2);
+ strcpy(path, ".");
+ }
+
+ do { // START_DO
+
+ result = file_exist(path);
+ if(result == F_ISDIR)
+ {
+ if(flag_copy) {
+ errprint_ptr(&retval, 1,
+ "You must type a passname, not a directory\n");
+ break;
+ }
+
+ if(strcmp(path, ".") == 0)
+ printf("Password Manager\n");
+ else
+ printf("Password Manager/%s\n", path);
+ tree(path, "");
+ }
+ else if(result == F_ISFILE)
+ {
+ char *pass = get_password(path);
+ if(!pass) {
+ errprint_ptr(&retval, 1, "Decrypt password failed\n");
+ break;
+ }
+
+ if(flag_copy)
+ copy_outside(pass);
+ else
+ printf("%s\n", pass);
+
+ free(pass);
+ }
+ else
+ errprint_ptr(&retval, 1,
+ "This path is not in the password storage\n");
+
+ } while(0); // END_DO
+
+ free(path);
+ return retval;
+}