diff options
| author | Joursoir <chat@joursoir.net> | 2020-10-31 17:45:29 +0000 | 
|---|---|---|
| committer | Joursoir <chat@joursoir.net> | 2020-10-31 17:45:29 +0000 | 
| commit | 64ef51a8ce6bc148ba493e350e2cac4cba470201 (patch) | |
| tree | 4418c4133b16341975cfe4d29df8da6ce27abcff /src | |
| parent | 38a3be4a3eeacec75a534fef6951b9484b4d7098 (diff) | |
| download | lock-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.c | 79 | ||||
| -rw-r--r-- | src/easydir.h | 9 | ||||
| -rw-r--r-- | src/handerror.c | 30 | ||||
| -rw-r--r-- | src/handerror.h | 8 | ||||
| -rw-r--r-- | src/implementation.c | 256 | ||||
| -rw-r--r-- | src/implementation.h | 17 | ||||
| -rw-r--r-- | src/main.c | 517 | 
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 | 
