aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJoursoir <chat@joursoir.net>2020-10-31 17:45:29 +0000
committerJoursoir <chat@joursoir.net>2020-10-31 17:45:29 +0000
commit64ef51a8ce6bc148ba493e350e2cac4cba470201 (patch)
tree4418c4133b16341975cfe4d29df8da6ce27abcff /src
parent38a3be4a3eeacec75a534fef6951b9484b4d7098 (diff)
downloadlock-password-64ef51a8ce6bc148ba493e350e2cac4cba470201.tar.gz
lock-password-64ef51a8ce6bc148ba493e350e2cac4cba470201.tar.bz2
lock-password-64ef51a8ce6bc148ba493e350e2cac4cba470201.zip
some features:
remake README.md for new code architecture; add help command; add man page;
Diffstat (limited to 'src')
-rw-r--r--src/easydir.c79
-rw-r--r--src/easydir.h9
-rw-r--r--src/handerror.c30
-rw-r--r--src/handerror.h8
-rw-r--r--src/implementation.c256
-rw-r--r--src/implementation.h17
-rw-r--r--src/main.c517
7 files changed, 916 insertions, 0 deletions
diff --git a/src/easydir.c b/src/easydir.c
new file mode 100644
index 0000000..162bae7
--- /dev/null
+++ b/src/easydir.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "handerror.h"
+
+int deleteFile(char *file_path)
+{
+ char *arguments[] = {"rm", file_path, NULL};
+ easyFork("rm", arguments);
+
+ return 1;
+}
+
+int deleteEmptyDir(char *dir_path)
+{
+ #if defined(DEBUG)
+ char *arguments[] = {"rmdir", "-p", dir_path, NULL};
+ #else
+ char *arguments[] = {"rmdir", "-p", "--ignore-fail-on-non-empty", dir_path, NULL};
+ #endif
+ easyFork("rmdir", arguments);
+
+ return 1;
+}
+
+int checkFileExist(char *path_to_file)
+{
+ FILE *pFile;
+
+ pFile = fopen(path_to_file, "r+"); // r+ so that errno can equal EISDIR
+ if(pFile == NULL) {
+ if(errno == ENOENT) // file doesn't exist
+ return 0;
+ if(errno == EISDIR) // it's directory
+ return 2;
+ else callError(120);
+ }
+ fclose(pFile);
+
+ return 1;
+}
+
+char *fileCropLineFeed(char *path, char *text, int maxlen)
+{
+ FILE *file = fopen(path, "r+");
+ if(file == NULL) callError(130);
+
+ int symbol;
+ int pos = 0;
+ char *str = (char *) malloc(sizeof(char) * maxlen);
+ while((symbol = fgetc(file)))
+ {
+ switch(symbol)
+ {
+ case '\n':
+ case EOF: {
+ str[pos] = '\0';
+ pos = -1; // for break while
+ break;
+ }
+ default: {
+ str[pos] = symbol;
+ pos++;
+ break;
+ }
+ }
+ if(pos == -1) break;
+ if(pos > maxlen-1) { str[pos-1] = '\0'; break; }
+ }
+ fclose(file);
+
+ strcpy(text, str);
+ free(str);
+ return text;
+}
diff --git a/src/easydir.h b/src/easydir.h
new file mode 100644
index 0000000..4680709
--- /dev/null
+++ b/src/easydir.h
@@ -0,0 +1,9 @@
+#ifndef EASYDIR_H
+#define EASYDIR_H
+
+int deleteFile(char *file_path);
+int deleteEmptyDir(char *dir_path);
+int checkFileExist(char *path_to_file);
+char *fileCropLineFeed(char *path, char *text, int maxlen);
+
+#endif \ No newline at end of file
diff --git a/src/handerror.c b/src/handerror.c
new file mode 100644
index 0000000..35e8f28
--- /dev/null
+++ b/src/handerror.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+void callError(int num)
+{
+ fprintf(stderr, "lpass: Sorry, there was an error in the program [#%d]\n", num);
+ exit(3);
+}
+
+void printError(char *text)
+{
+ fprintf(stderr, "%s", text);
+ exit(4);
+}
+
+void easyFork(char *name, char *arguments[])
+{
+ int pid;
+ pid = fork();
+ if(pid == -1) callError(100);
+ if(pid == 0) { /* new process */
+ execvp(name, arguments);
+ perror(name);
+ exit(4);
+ }
+ wait(&pid);
+}
+
diff --git a/src/handerror.h b/src/handerror.h
new file mode 100644
index 0000000..6f75c7b
--- /dev/null
+++ b/src/handerror.h
@@ -0,0 +1,8 @@
+#ifndef HANDERROR_H
+#define HANDERROR_H
+
+void easyFork(char *name, char *arguments[]);
+void callError(int num);
+void printError(char *text);
+
+#endif \ No newline at end of file
diff --git a/src/implementation.c b/src/implementation.c
new file mode 100644
index 0000000..3ba2be7
--- /dev/null
+++ b/src/implementation.c
@@ -0,0 +1,256 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "handerror.h"
+#include "easydir.h"
+#include "implementation.h"
+
+/* define in implementation.h */
+// GPG_PUBLICKEY_MAXLENGTH 1025
+
+#define BASH_EXEC_COPY "lpass_copy.sh"
+
+// == global var ==
+extern char *gPath_rootdir; // /home/[username]/.lockpassword/
+extern char *gPath_subdir; // example: programming/github.com
+extern char *gPath_pass; // example: programming/github.com/joursoir.gpg
+
+static void copyText(char *password)
+{
+ size_t size = (strlen(password) + strlen(BASH_EXEC_COPY) + 1) * sizeof(char);
+ char *command = malloc(size);
+
+ snprintf(command, size, "%s %s", BASH_EXEC_COPY, password);
+ system(command);
+
+ free(command);
+}
+
+void checkForbiddenPaths(char *path) // check two dot in path
+{
+ int firstdot = 0;
+ for(int i=0; i < strlen(path); i++)
+ {
+ if(path[i] == '.')
+ firstdot ? printError("Error: please, don't use forbidden paths\n") : firstdot++;
+ else firstdot = 0;
+ }
+}
+
+char *getGPGKey(char *dest, size_t size)
+{
+ FILE *fileGPG = fopen(".gpg-key", "r");
+ if(fileGPG == NULL) {
+ if(errno == ENOENT) printError("error: No GPG key exists\n");
+ callError(121);
+ }
+
+ if(!fgets(dest, size, fileGPG)) {
+ callError(122);
+ }
+ fclose(fileGPG);
+
+ return dest;
+}
+
+char* getPassword(char *path_pass, char *password, size_t size, int flag_copy)
+{
+ int size_gpgkey = sizeof(char) * GPG_PUBLICKEY_MAXLENGTH;
+ char *secret_gpgkey = (char *) malloc(size_gpgkey);
+ getGPGKey(secret_gpgkey, size_gpgkey);
+
+ char *arguments[] = {"gpg", "-d", "--quiet", "-r", secret_gpgkey, "-o", path_pass, gPath_pass, NULL};
+ easyFork("gpg", arguments);
+
+ FILE *filePass = fopen(path_pass, "r");
+ if(filePass == NULL) callError(127);
+
+ if(!fgets(password, size, filePass)) {
+ callError(111);
+ }
+ fclose(filePass);
+
+ if(flag_copy) copyText(password);
+
+ remove(path_pass);
+ free(secret_gpgkey);
+ return password;
+}
+
+void nonvisibleEnter(int status)
+{
+ struct termios term_settings;
+ tcgetattr(0, &term_settings); // get current settings
+ if(status == 1) {
+ term_settings.c_lflag &= ~ECHO; // flag reset
+ }
+ else {
+ term_settings.c_lflag |= ECHO;
+ }
+ tcsetattr(0, TCSANOW, &term_settings);
+}
+
+void insertPass(char *add_path, char *password, int flag_copy)
+{
+ /* gPath_rootdir = /home/[username]/.lock-password/
+ add_path = banks/france/[number]
+ gPath_pass = banks/france/[number].gpg
+ gPath_subdir = banks/france */
+
+ int size_gpgkey = sizeof(char) * GPG_PUBLICKEY_MAXLENGTH;
+ char *secret_gpgkey = (char *) malloc(size_gpgkey);
+ getGPGKey(secret_gpgkey, size_gpgkey);
+
+ char *arguments1[] = {"mkdir", "-p", gPath_subdir, NULL};
+ easyFork("mkdir", arguments1);
+
+ // create file, copy password there
+ FILE *filePass;
+ filePass = fopen(add_path, "w");
+ if(filePass == NULL) {
+ callError(108);
+ }
+ fputs(password, filePass);
+ fclose(filePass);
+
+ if(flag_copy) copyText(password);
+
+ // encryption
+ char *arguments2[] = {"gpg", "--quiet", "--yes", "-r", secret_gpgkey, "-e", add_path, NULL};
+ easyFork("gpg", arguments2);
+
+ remove(add_path);
+ free(secret_gpgkey);
+}
+
+char *typePass(char *text, char *dest, int minlen, int maxlen)
+{
+ printf("%s", text);
+ if(fgets(dest, sizeof(char)*maxlen, stdin) == NULL) {
+ nonvisibleEnter(0);
+ printError("lpass: Unexpected end of file\n");
+ }
+
+ int len = strlen(dest);
+ if(len < minlen || len > maxlen) {
+ nonvisibleEnter(0);
+ printError("lpass: incorrect password\n");
+ }
+
+ if(dest[len-1] == '\n') {
+ dest[len-1] = '\0';
+ }
+
+ #if defined(DEBUG)
+ printf("%s", dest);
+ #endif
+
+ printf("\n"); // for new line
+ return dest;
+}
+
+int userEnterPassword(int minlen, int maxlen, char *path_insert, int flag_echo, int flag_copy)
+{
+ char *pass_one = (char *) malloc(sizeof(char) * maxlen);
+ int rvalue = 0;
+ if(!flag_echo) {
+ char *pass_two = (char *) malloc(sizeof(char) * maxlen);
+
+ nonvisibleEnter(1); // change terminal work
+ typePass("Type your password: ", pass_one, minlen, maxlen);
+ typePass("Type your password again: ", pass_two, minlen, maxlen);
+ nonvisibleEnter(0);
+
+ if(strcmp(pass_one, pass_two) == 0) {
+ insertPass(path_insert, pass_one, flag_copy);
+ rvalue = 1;
+ }
+ free(pass_two);
+ }
+ else {
+ typePass("Type your password: ", pass_one, minlen, maxlen);
+ insertPass(path_insert, pass_one, flag_copy);
+ rvalue = 1;
+ }
+
+ free(pass_one);
+ return rvalue;
+}
+
+char *generatePassword(char *dest, int amount, int max_len)
+{
+ char allowed_symbols[] = {
+ 'A','E','I','J','O','U','B','C','D','F','G','H',
+ 'K','L','M','N','P','Q','R','S','T','V','W','X',
+ 'Y','Z','a','e','i','j','o','u','b','c','d','f',
+ 'g','h','k','l','m','n','p','q','r','s','t','v',
+ 'w','x','y','z','1','2','3','4','5','6','7','8',
+ '9','0','!','#','$',';','%','^',':','&','?','*',
+ '(',')','-','_','+','=','<', '>'
+ };
+ int max = sizeof(allowed_symbols);
+ srand(time(NULL));
+
+ char password[max_len];
+ for(int i=0; i < amount; i++)
+ {
+ char c = allowed_symbols[rand() % max];
+
+ password[i] = c;
+ password[i+1] = '\0';
+ }
+
+ strcpy(dest, password);
+ return dest;
+}
+
+unsigned long hash(char *str)
+{
+ unsigned long hash = 5381;
+ char c;
+
+ while( (c = *str++) )
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
+}
+
+static void clearStdinBuff()
+{
+ char garbage;
+
+ while( (garbage = fgetc(stdin)) != '\n' && garbage != EOF )
+ ;
+}
+
+
+int getOverwriteAnswer(char *path)
+{
+ int buffSize = (strlen("Password for '' exists. Overwrite? (Y/N)") + strlen(path) + 1)* sizeof(char);
+ char *text = malloc(buffSize);
+ snprintf(text, buffSize, "Password for '%s' exists. Overwrite? (Y/N)", path);
+ printf("%s ", text);
+
+ int answer;
+ while((answer = fgetc(stdin)))
+ {
+ clearStdinBuff();
+ switch(answer)
+ {
+ case 'Y':
+ case 'y': { free(text); return 1; }
+ case 'N':
+ case 'n': { free(text); return 0; }
+ case EOF: printError("Error: Unexpected end of file\n");
+ default: { printf("%s ", text); break; }
+ }
+ }
+
+ free(text);
+ return -1;
+}
diff --git a/src/implementation.h b/src/implementation.h
new file mode 100644
index 0000000..f41cc4a
--- /dev/null
+++ b/src/implementation.h
@@ -0,0 +1,17 @@
+#ifndef IMPLEMENTATION_H
+#define IMPLEMENTATION_H
+
+#define GPG_PUBLICKEY_MAXLENGTH 1025 // +1 for '\0'
+
+void checkForbiddenPaths(char *path);
+char *getGPGKey(char *dest, size_t size);
+char* getPassword(char *path_pass, char *password, size_t size, int flag_copy);
+void nonvisibleEnter(int status);
+void insertPass(char *add_path, char *password, int flag_copy);
+char *typePass(char *text, char *dest, int minlen, int maxlen);
+int userEnterPassword(int minlen, int maxlen, char *path_insert, int flag_echo, int flag_copy);
+char *generatePassword(char *dest, int amount, int max_len);
+unsigned long hash(char *str);
+int getOverwriteAnswer(char *path);
+
+#endif \ No newline at end of file
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..5a9971c
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,517 @@
+/*
+** Code written by Joursoir
+**
+** This is free and unencumbered software released into the public domain.
+** (C) The Unlicense
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <libgen.h>
+
+#include "easydir.h"
+#include "handerror.h"
+#include "implementation.h"
+
+#define VERSION "1.0"
+#define DATE_RELEASE "31 October, 2020"
+//#define DEBUG
+#define STANDARD_TEXTEDITOR "vim"
+#define MAXLEN_TEXTEDITOR 16
+#define MINLEN_PASSWORD 1
+#define MAXLEN_PASSWORD 128
+#define STANDARD_AMOUNT_GENERATE_SYMBOLS 14
+#define LOCKPASS_DIR "/.lock-password/"
+#define GPGKEY_FILE "/.gpg-key"
+
+#define TREE_OUTPUT_FILE ".tree"
+#define TEXTEDITOR_FILE ".text-editor"
+
+#define HASH_INIT 6385337657
+#define HASH_HELP 6385292014
+#define HASH_VERSION 229486327000139
+#define HASH_EDIT 6385183019
+#define HASH_MV 5863624
+#define HASH_MOVE 249844339311324255
+#define HASH_GENERATE 7572409341523952
+#define HASH_INSERT 6953633055386
+#define HASH_RM 5863780
+#define HASH_REMOVE 6953974396019
+#define HASH_DELETE 6953426453624
+#define WITHOUT_ARGUMENTS 1
+
+#define STR_SHOWTREEUSE "Use: lpass [-c=passname] [passname]\n"
+#define STR_INITUSE "Use: lpass init gpg-key\n"
+#define STR_INSERTUSE "Use: lpass insert [-ef] passname\n"
+#define STR_EDITUSE "Use: lpass edit [-t=text-editor] passname\n"
+#define STR_GENERATEUSE "Use: lpass generate [-l=pass-length] [-f] passname\n"
+#define STR_REMOVEUSE "Use: lpass remove/rm/delete passname\n"
+#define STR_MOVEUSE "Use: lpass move/mv [-f] old-path new-path\n"
+
+// == global var ==
+char *gPath_rootdir; // /home/[username]/.lockpassword/
+char *gPath_subdir; // example: programming/github.com
+char *gPath_pass; // example: programming/github.com/joursoir.gpg
+
+static void globalSplitPath(char *source)
+{
+ int len_path = strlen(source) + strlen(".gpg") + 1;
+
+ gPath_pass = malloc(sizeof(char) * len_path); // path without working dir
+ strcpy(gPath_pass, source);
+ strcat(gPath_pass, ".gpg");
+
+ gPath_subdir = malloc(sizeof(char) * len_path); // path without working dir and pass file
+ strcpy(gPath_subdir, source);
+ gPath_subdir = dirname(gPath_subdir);
+
+ #if defined(DEBUG)
+ printf("dir: %s\n", gPath_subdir);
+ printf("pass: %s\n", gPath_pass);
+ #endif
+}
+
+static void cmd_init(int argc, char *argv[])
+{
+ char *gpg_key = argv[2];
+ if(gpg_key == NULL) printError(STR_INITUSE);
+
+ // create main directory:
+ int len_init_storage = strlen(gPath_rootdir) + strlen(GPGKEY_FILE) + 1; // +1 for '\0'
+ char *path_init_storage = (char *) malloc(sizeof(char) * len_init_storage);
+ strcpy(path_init_storage, gPath_rootdir);
+
+ char *arguments[] = {"mkdir", "-vp", path_init_storage, NULL};
+ easyFork("mkdir", arguments);
+
+ strcat(path_init_storage, GPGKEY_FILE);
+
+ // create .gpg-key in storage
+ FILE *filekey;
+ filekey = fopen(path_init_storage, "w");
+ if(filekey == NULL) {
+ callError(122);
+ }
+ fputs(gpg_key, filekey);
+ fclose(filekey);
+
+ free(path_init_storage);
+ printf("LockPassword initialized for %s\n", gpg_key);
+}
+
+static void cmd_edit(int argc, char *argv[])
+{
+ const struct option long_options[] = {
+ {"text-editor", required_argument, NULL, 't'},
+ {NULL, 0, NULL, 0}
+ };
+
+ int result;
+ while((result = getopt_long(argc, argv, "t:", long_options, NULL)) != -1) {
+ switch(result) {
+ case 't':
+ {
+ // create file, copy name text editor there
+ FILE *f_texteditor = fopen(TEXTEDITOR_FILE, "w");
+ if(f_texteditor == NULL) callError(108);
+ fputs(optarg, f_texteditor);
+ fclose(f_texteditor);
+ printf("You changed text editor to %s\n", optarg);
+ break;
+ }
+ default: printError(STR_EDITUSE);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "edit"
+ #if defined(DEBUG)
+ for(int i=0; i < argc; i++) printf("arg: %s\n", argv[i]);
+ printf("passname: %s\n", argv[optind]);
+ #endif
+
+ char *path_to_password;
+ if(argv[optind] == NULL) printError(STR_EDITUSE);
+ else path_to_password = argv[optind];
+
+ checkForbiddenPaths(path_to_password);
+ globalSplitPath(path_to_password);
+
+ if(checkFileExist(gPath_pass) != 1)
+ printError("Error: No such file exists\n");
+
+ // configure text editor file
+ char text_editor[MAXLEN_TEXTEDITOR];
+ FILE *f_texteditor = fopen(TEXTEDITOR_FILE, "r");
+ if(f_texteditor == NULL) {
+ f_texteditor = fopen(TEXTEDITOR_FILE, "w");
+ if(f_texteditor == NULL) callError(108);
+ fputs(STANDARD_TEXTEDITOR, f_texteditor); // in file
+ strcpy(text_editor, STANDARD_TEXTEDITOR); // in variable
+ }
+ else {
+ if(!fgets(text_editor, sizeof(char)*MAXLEN_TEXTEDITOR, f_texteditor))
+ callError(122);
+ }
+ fclose(f_texteditor);
+
+ #if defined(DEBUG)
+ printf("using text editor: %s\n", text_editor);
+ #endif
+ // end configure
+
+ // decryption
+ int size_gpgkey = sizeof(char) * GPG_PUBLICKEY_MAXLENGTH;
+ char *secret_gpgkey = (char *) malloc(size_gpgkey);
+ getGPGKey(secret_gpgkey, size_gpgkey);
+
+ char *decryp_arg[] = {"gpg", "-d", "--quiet", "-r", secret_gpgkey, "-o", path_to_password, gPath_pass, NULL};
+ easyFork("gpg", decryp_arg);
+
+ // start vim/etc for edit passowrd
+ char *texte_arg[] = {text_editor, path_to_password, NULL};
+ easyFork(text_editor, texte_arg);
+
+ // delete '\n' and paste good pass
+ char password[MAXLEN_PASSWORD];
+ fileCropLineFeed(path_to_password, password, MAXLEN_PASSWORD);
+
+ FILE *file = fopen(path_to_password, "w");
+ if(file == NULL) callError(108);
+ fputs(password, file);
+ fclose(file);
+
+ // encryption
+ char *encryp_arg[] = {"gpg", "--quiet", "--yes", "-r", secret_gpgkey, "-e", path_to_password, NULL};
+ easyFork("gpg", encryp_arg);
+
+ remove(path_to_password);
+ free(secret_gpgkey);
+}
+
+static void cmd_move(int argc, char *argv[])
+{
+ /* we have a two situation:
+ 1) mv file file
+ 2) mv file directory */
+
+ 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: printError(STR_MOVEUSE);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "move"
+ #if defined(DEBUG)
+ for(int i=0; i < argc; i++) printf("arg: %s\n", argv[i]);
+ printf("old-path: %s\n", argv[optind]);
+ if(argv[optind] != NULL) printf("new-path: %s\n", argv[optind+1]);
+ #endif
+
+ if(argv[optind] == NULL) printError(STR_MOVEUSE);
+ if(argv[optind+1] == NULL) printError(STR_MOVEUSE);
+
+ char *old_path = argv[optind];
+ checkForbiddenPaths(old_path); globalSplitPath(old_path);
+ if(checkFileExist(gPath_pass) != 1) printError("Error: No such old-path exists\n");
+
+ char *old_path_gpg = gPath_pass;
+ char *old_path_subdir = gPath_subdir;
+
+ char *new_path = argv[optind+1];
+ checkForbiddenPaths(new_path); globalSplitPath(new_path);
+
+ if(checkFileExist(new_path) == 2) // if new-path = dir
+ ;
+ else if(checkFileExist(gPath_pass) == 1) { // if new-path = file
+ if(!flag_force) {
+ if(getOverwriteAnswer(new_path) != 1)
+ return;
+ }
+ new_path = gPath_pass;
+ }
+ else printError("Error: No such new-path exists\n");
+
+ char *arguments[] = {"mv", "-f", old_path_gpg, new_path, NULL};
+ easyFork("mv", arguments);
+
+ deleteEmptyDir(old_path_subdir);
+ free(old_path_subdir); free(old_path_gpg);
+}
+
+static void cmd_generate(int argc, char *argv[])
+{
+ int pass_length = STANDARD_AMOUNT_GENERATE_SYMBOLS, 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: printError(STR_GENERATEUSE);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "generate"
+ #if defined(DEBUG)
+ for(int i=0; i < argc; i++) printf("arg: %s\n", argv[i]);
+ printf("passname: %s\n", argv[optind]);
+ #endif
+
+ char *path_to_password;
+ if(argv[optind] == NULL) printError(STR_GENERATEUSE);
+ else path_to_password = argv[optind];
+
+ if(pass_length < MINLEN_PASSWORD || pass_length > MAXLEN_PASSWORD)
+ printError("Error: you typed an incorrect number\n");
+
+ checkForbiddenPaths(path_to_password);
+ globalSplitPath(path_to_password);
+
+ if(checkFileExist(gPath_pass) == 1) {
+ if(!flag_force) {
+ if(getOverwriteAnswer(path_to_password) != 1)
+ return;
+ }
+ }
+
+ // generate password
+ char gpass[MAXLEN_PASSWORD];
+ generatePassword(gpass, pass_length, MAXLEN_PASSWORD);
+
+ insertPass(path_to_password, gpass, flag_copy);
+ if(!flag_copy) printf("Generated password: %s\n", gpass);
+ printf("Password added successfully for %s\n", path_to_password);
+}
+
+static void cmd_insert(int argc, char *argv[])
+{
+ int flag_echo = 0, flag_force = 0, flag_copy = 0, result;
+ 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: printError(STR_INSERTUSE);
+ }
+ }
+
+ if(optind < argc) optind++; // for skip "insert"
+ #if defined(DEBUG)
+ for(int i=0; i < argc; i++) printf("arg: %s\n", argv[i]);
+ printf("passname: %s\n", argv[optind]);
+ #endif
+
+ char *path_to_password;
+ if(argv[optind] == NULL) printError(STR_INSERTUSE);
+ else path_to_password = argv[optind];
+
+ checkForbiddenPaths(path_to_password);
+ globalSplitPath(path_to_password);
+
+ if(checkFileExist(gPath_pass) == 1) {
+ if(!flag_force) {
+ if(getOverwriteAnswer(path_to_password) != 1)
+ return;
+ }
+ }
+
+ if(userEnterPassword(MINLEN_PASSWORD, MAXLEN_PASSWORD, path_to_password, flag_echo, flag_copy) == 1) {
+ printf("Password added successfully for %s\n", path_to_password);
+ }
+ else
+ printf("Passwords do not match\n");
+}
+
+static void cmd_remove(int argc, char *argv[])
+{
+ char *path_to_password = argv[2];
+ if(path_to_password == NULL)
+ printError(STR_REMOVEUSE);
+
+ checkForbiddenPaths(path_to_password);
+ globalSplitPath(path_to_password);
+
+ if(checkFileExist(gPath_pass) != 1)
+ printError("Error: No such file exists\n");
+
+ if(deleteFile(gPath_pass))
+ deleteEmptyDir(gPath_subdir);
+}
+
+static void cmd_showtree(int argc, char *argv[])
+{
+ int flag_copy = 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: printError(STR_SHOWTREEUSE);
+ }
+ }
+
+ #if defined(DEBUG)
+ for(int i=0; i < argc; i++) printf("arg: %s\n", argv[i]);
+ printf("passname: %s\n", argv[optind]);
+ #endif
+
+ if(argv[optind] == NULL) {
+ if(flag_copy) printError(STR_SHOWTREEUSE);
+ else {
+ path = (char *) malloc(sizeof(char) * 2);
+ strcpy(path, ".");
+ }
+ }
+ else path = argv[optind];
+ checkForbiddenPaths(path);
+
+ if(opendir(path) != NULL) // if it's directory
+ {
+ if(flag_copy) printError("Error: you must type a passname, not a directory\n");
+
+ char *arg1[] = {"tree", "-C", "--noreport", path, "-o", TREE_OUTPUT_FILE, NULL};
+ easyFork("tree", arg1);
+
+ char *arg2[] = {"sed", "-i", "-E", "s/\\.gpg(\\x1B\\[[0-9]+m)?( ->|$)/\\1\\2/g", TREE_OUTPUT_FILE, NULL};
+ easyFork("sed", arg2); // remove .gpg at the pass name
+
+ if(strcmp(path, ".") == 0) printf("Password Manager\n");
+ else printf("Password Manager/%s\n", path);
+
+ char *arg3[] = {"tail", "-n", "+2", TREE_OUTPUT_FILE, NULL};
+ easyFork("tail", arg3); // remove working directory
+
+ remove(TREE_OUTPUT_FILE);
+ }
+ else
+ {
+ globalSplitPath(path);
+
+ if(checkFileExist(gPath_pass) == 1) // exist
+ {
+ char password[MAXLEN_PASSWORD];
+ getPassword(path, password, sizeof(char)*MAXLEN_PASSWORD, flag_copy);
+ if(!flag_copy) printf("%s\n", password);
+ }
+ else printf("Error: %s is not in the password storage\n", path);
+ }
+
+ if(argv[1] == NULL) free(path);
+}
+
+static void cmd_help()
+{
+ printf("Synopsis:\n\tlpass [command] [arguments] ...\n");
+
+ printf("Commands:\n\tinit gpg-key\n");
+ printf("\t\tInitialize the password manager using the passed gpg-key.\n");
+
+ printf("\tinsert [-e, --echo] [-c, --copy] [-f, --force] passname\n");
+ printf("\t\tAdd the specified passname to the password manager.\n");
+
+ printf("\tedit [-t, --text-editor=text-editor] passname\n");
+ printf("\t\tOpen the specified passname in a text editor, waiting for changes.\n");
+
+ printf("\tgenerate [-l, --length=pass-length] [-c, --copy] [-f, --force] passname\n");
+ printf("\t\tGenerate a random password and write it in passname.\n");
+
+ printf("\tmv/move [-f, --force] old-path new-path\n");
+ printf("\t\tMove/rename old-path to new-path.\n");
+
+ printf("\trm/remove/delete passname\n");
+ printf("\t\tRemove the passname you specified from the password manager.\n");
+
+ printf("\thelp\n");
+ printf("\t\tPrint help information about commands and the application itself.\n");
+
+ printf("\tversion\n");
+ printf("\t\tPrint version information.\n");
+
+ printf("\nMore information may be found in the lpass(1) man page.\n");
+}
+
+static void cmd_version()
+{
+ printf("LockPassword v%s\n", VERSION);
+ printf("Release date: %s\n\n", DATE_RELEASE);
+ printf("Code was written by Joursoir\n");
+ printf("This is free and unencumbered software released into the public domain.\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+ if(!isatty(0)) { // stdin
+ printError("lpass: Please, use a terminal to run this program\n");
+ }
+
+ /* init global path to root directory */
+ int len_rootdir = strlen(getenv("HOME")) + strlen(LOCKPASS_DIR) + 1; // +1 for '\0'
+
+ gPath_rootdir = (char *) malloc(sizeof(char) * len_rootdir);
+ strcpy(gPath_rootdir, getenv("HOME"));
+ strcat(gPath_rootdir, LOCKPASS_DIR);
+ /* end init */
+
+ unsigned long ihash = WITHOUT_ARGUMENTS;
+ if(argv[1] != NULL) {
+ ihash = hash(argv[1]);
+ }
+
+ if(chdir(gPath_rootdir) != 0 && ihash != HASH_INIT) {
+ printf("Before starting work, you must initialize LockPassword\n");
+ printError(STR_INITUSE);
+ }
+
+ switch(ihash)
+ {
+ case HASH_INIT: { cmd_init(argc, argv); break; }
+ case HASH_EDIT: { cmd_edit(argc, argv); break; }
+ case HASH_MV:
+ case HASH_MOVE: { cmd_move(argc, argv); break; }
+ case HASH_GENERATE: { cmd_generate(argc, argv); break; }
+ case HASH_INSERT: { cmd_insert(argc, argv); break; }
+ case HASH_RM:
+ case HASH_REMOVE:
+ case HASH_DELETE: { cmd_remove(argc, argv); break; }
+ case HASH_HELP: { cmd_help(); break; }
+ case HASH_VERSION: { cmd_version(); break; }
+ default: { cmd_showtree(argc, argv); break; }
+ }
+
+ if(gPath_subdir != NULL) {
+ free(gPath_subdir);
+ free(gPath_pass);
+ }
+ free(gPath_rootdir);
+ return EXIT_SUCCESS;
+} \ No newline at end of file