diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | TODO.adoc | 1 | ||||
-rw-r--r-- | src/gpg.c | 63 | ||||
-rw-r--r-- | src/gpg.h | 1 | ||||
-rw-r--r-- | src/gpgedit_config.c | 1 | ||||
-rw-r--r-- | src/gpgedit_config.h | 2 | ||||
-rw-r--r-- | src/logger.c | 62 | ||||
-rw-r--r-- | src/logger.h | 32 | ||||
-rw-r--r-- | src/main.c | 32 |
9 files changed, 143 insertions, 52 deletions
@@ -4,6 +4,7 @@ CCOPTS = --std=gnu99 -Wall all: if [ ! -d obj ]; then mkdir obj; fi cc $(CCOPTS) $(DBG) -c src/strll.c -o obj/strll.o + cc $(CCOPTS) $(DBG) -c src/logger.c -o obj/logger.o cc $(CCOPTS) $(DBG) -lgpgme -c src/gpgedit_config.c -o obj/gpgedit_config.o cc $(CCOPTS) $(DBG) -lgpgme -c src/gpg.c -o obj/gpg.o cc $(CCOPTS) $(DBG) -lgpgme obj/*.o src/main.c -o $(out) @@ -14,3 +14,4 @@ Implement * [ ] Recipient removal from existing file * [x] New file creation (at least one recipient required) * [x] Helptext +* [x] Basic logging framework (to support debug, quiet, silent modes) @@ -18,23 +18,26 @@ int gpg_failiferr(gpgme_error_t err) { if(err != GPG_ERR_NO_ERROR) { - printf("ERROR: "); if(err == GPG_ERR_INV_VALUE) { - printf("Invalid data structure\n"); - } else if(err == GPG_ERR_ENOMEM) { - printf("Insufficient memory to allocate GPG context\n"); + logger(LOG_FATAL, "Invalid data structure\n"); + } else if(err == GPG_ERR_NO_DATA) { + logger(LOG_FATAL, "Data struct contains no encrypted data\n"); + } else if(err == GPG_ERR_DECRYPT_FAILED) { + logger(LOG_FATAL, "Could not decrypt file\n"); } else if(err == GPG_ERR_ENOMEM) { - printf("Insufficient memory to allocate GPG context\n"); + logger(LOG_FATAL, "Insufficient memory to allocate GPG context\n"); } else if(err == GPG_ERR_NOT_OPERATIONAL) { - printf("GPGME not initialized\n"); + logger(LOG_FATAL, "GPGME not initialized\n"); } else if(err == GPG_ERR_UNUSABLE_PUBKEY) { - printf("One or more public keys unusable\n"); + logger(LOG_FATAL, "One or more public keys unusable\n"); } else if(err == GPG_ERR_BAD_PASSPHRASE) { - printf("Incorrect passphrase\n"); + logger(LOG_FATAL, "Incorrect passphrase\n"); + } else if(err == GPG_ERR_NOT_IMPLEMENTED) { + logger(LOG_FATAL, "Not implemented\n"); } else { - printf("Unknown error: %d\n", err); + logger(LOG_ERROR, "Unknown error: %d\n", err); } - printf("Message:\n %s\n", gpgme_strerror(err)); + logger(LOG_ERROR, " %s\n", gpgme_strerror(err)); return err; } return 0; @@ -68,7 +71,7 @@ int gpg_data_fwrite(gpgme_data_t dh, FILE* out) { gpgme_data_seek(dh, 0, SEEK_SET); if(gpgme_data_read(dh, buf, 1) < 1) { - printf("Error: GPG data struct is empty. Nothing to write.\n"); + logger(LOG_ERROR, "GPG data struct is empty. Nothing to write.\n"); return -1; } @@ -92,7 +95,7 @@ int gpg_recip_count(gpgme_recipient_t firstrecip) { // Get recipient list recip = firstrecip; while(recip != NULL) { - //printf("-- recipient: %s\n", recip->keyid); + // printf("-- recipient: %s\n", recip->keyid); recip = recip->next; count++; } @@ -162,7 +165,8 @@ size_t gpg_encrypt_file(char* infile, char* outfile, struct strll* recipll) { gpg_failiferr(err); // For debugging purposes - // printf("Reading updated data from memory\n"); // Initialize data structures + logger(LOG_DEBUG, "Reading updated data from memory\n"); + // Initialize data structures err = gpgme_data_new_from_file(&indata, infile, 1); gpg_failiferr(err); @@ -183,11 +187,10 @@ size_t gpg_encrypt_file(char* infile, char* outfile, struct strll* recipll) { err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, indata, outdata); gpg_failiferr(err); - // For debugging purposes - // printf("No errors detecting during encryption.\n"); // For debugging purposes - // printf("Writing to disk\n"); + logger(LOG_DEBUG, "No errors detecting during encryption. Writing to disk\n"); + // Write to disk! FILE* refd = fopen(outfile, "w"); gpg_data_fwrite(outdata, refd); @@ -211,35 +214,11 @@ gpg_decrypt_file(char* infile, char* outfile, gpgme_ctx_t ctx) { // returned. gpgme_data_new(&outdata); err = gpgme_data_new_from_file(&indata, infile, 1); - if(err != GPG_ERR_NO_ERROR) { - printf("ERROR: "); - if(err == GPG_ERR_INV_VALUE) { - printf("Invalid data struct or file path\n"); - } else if(err == GPG_ERR_NOT_IMPLEMENTED) { - printf("Not implemented\n"); - } else if(err == GPG_ERR_ENOMEM) { - printf("Insufficient memory to allocate data struct\n"); - } - return NULL; - } + gpg_failiferr(err); // Attempt to decrypt err = gpgme_op_decrypt(ctx, indata, outdata); - if(err != GPG_ERR_NO_ERROR) { - printf("ERROR: "); - if(err == GPG_ERR_INV_VALUE) { - printf("Invalid pointer to cipher or plain data structs\n"); - } else if(err == GPG_ERR_NO_DATA) { - printf("Cipher struct contains no encrypted data\n"); - } else if(err == GPG_ERR_DECRYPT_FAILED) { - printf("Ciphertext is invalid\n"); - } else if(err == GPG_ERR_BAD_PASSPHRASE) { - printf("Passphrase is incorrect\n"); - } else { - printf("Unhandled error\n %s\n", gpgme_strerror(err)); - } - return NULL; - } + gpg_failiferr(err); // Write decrypted data to outfile FILE* outfd = fopen(outfile, "w"); @@ -25,6 +25,7 @@ #include <locale.h> #include "strll.h" +#include "logger.h" #define READSIZE 256 diff --git a/src/gpgedit_config.c b/src/gpgedit_config.c index dbf2e6b..ae618f3 100644 --- a/src/gpgedit_config.c +++ b/src/gpgedit_config.c @@ -21,6 +21,7 @@ struct gpgedit_config* gpgedit_config_new() { c = malloc(sizeof(struct gpgedit_config)); c->file = NULL; c->recipients = strll_new(); + c->log_level = LOG_INFO; return c; } diff --git a/src/gpgedit_config.h b/src/gpgedit_config.h index 1c74a29..8f2013c 100644 --- a/src/gpgedit_config.h +++ b/src/gpgedit_config.h @@ -18,11 +18,13 @@ #include <string.h> #include "strll.h" +#include "logger.h" struct gpgedit_config { char* file; // File path to be edited struct strll* recipients; // Pointer to first item in the linked list struct gpgme_key_t* keys; + int log_level; // Runtime log level }; struct gpgedit_config* gpgedit_config_new(); diff --git a/src/logger.c b/src/logger.c new file mode 100644 index 0000000..1060eca --- /dev/null +++ b/src/logger.c @@ -0,0 +1,62 @@ +// GPGEdit edits GPG encrypted files +// Copyright (C) 2018 Aaron Ball <nullspoon@oper.io> +// +// 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 "logger.h" + + +int _log_level = LOG_INFO; // Global log level, set by logger_init(). + + +// logger_init: +// Initialize the logger-related variables. +// +// @lvl Integer representing log level. Use LOG_* macros (eg: LOG_ERROR, +// LOG_DEBUG, LOG_INFO, etc) +void logger_init(int lvl) { + _log_level = lvl; +} + + +// logger: +// Logger function. Writes log messages to stdout if specified message level is +// less than or equal to the runtime global log level. Global log level is set +// by logger_init. +// +// @lvl Integer representing log level +// @format Format (like printf) of message +// @... Additional arguments for printf statement. +void logger(int lvl, char* format, ...) { + va_list valist; + va_start(valist, format); + + if(lvl <= _log_level) { + if(lvl == LOG_DEBUG) + printf("DEBUG: "); + + if(lvl == LOG_FATAL) + printf("FATAL: "); + + if(lvl == LOG_ERROR) + printf("ERROR: "); + + if(lvl == LOG_ERROR) + printf("WARN: "); + + vprintf(format, valist); + } + + va_end(valist); +} diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..1dce255 --- /dev/null +++ b/src/logger.h @@ -0,0 +1,32 @@ +// GPGEdit edits GPG encrypted files +// Copyright (C) 2018 Aaron Ball <nullspoon@oper.io> +// +// 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 <stdarg.h> + +#ifndef GPGEDIT_LOGGER_H +#define GPGEDIT_LOGGER_H + +#define LOG_DEBUG 50 +#define LOG_INFO 40 +#define LOG_WARN 30 +#define LOG_ERROR 20 +#define LOG_FATAL 10 + +void logger_init(int); +void logger(int, char*, ...); + +#endif @@ -23,6 +23,7 @@ #include "gpg.h" #include "gpgedit_config.h" #include "strll.h" +#include "logger.h" void system_edit(char* file) { char cmd[256]; // Buffer for editor command @@ -50,8 +51,11 @@ void usage() { "\nUsage:\n\n" " gpgedit [-r user@host] <file.gpg>\n" "\nArguments:\n" + " -h,--help Print this help text\n" + " -q,--quiet Quiet output (only error and fatal)\n" " -r,--recipient Adds a recipient key to the encrypted output\n" - " -h,--help Print this help text\n"; + " -s,--silent No output (only if you have good karma)\n" + " -v,--verbose Verbose output (debug level)\n"; printf("%s\n", helptext); } @@ -63,8 +67,14 @@ void parseargs(int argc, char* argv[], struct gpgedit_config* config) { while(i < argc) { if(strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--recipient") == 0) { i++; - //printf("Adding recipient %s\n", argv[i]); + logger(LOG_DEBUG, "Adding recipient %s\n", argv[i]); strll_add(config->recipients, argv[i]); + } else if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { + config->log_level = LOG_DEBUG; + } else if(strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) { + config->log_level = LOG_ERROR; + } else if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--silent") == 0) { + config->log_level = -1; } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { usage(); exit(0); @@ -84,9 +94,11 @@ int main(int argc, char* argv[]) { config = gpgedit_config_new(); parseargs(argc, argv, config); + // Initialize the logger + logger_init(config->log_level); if(config->file == NULL) { - printf("Please specify a gpg encrypted file to edit\n"); + logger(LOG_INFO, "Please specify a gpg encrypted file to edit\n"); return 1; } @@ -95,7 +107,7 @@ int main(int argc, char* argv[]) { // to create it. FILE* fd = fopen(config->file, "r"); if(!fd) { - printf("File '%s' does not exist. Creating.\n", config->file); + logger(LOG_INFO, "File '%s' does not exist. Creating.\n", config->file); mkstemp(tmpfile); } else { // File exists, close the fd for testing existance @@ -105,7 +117,7 @@ int main(int argc, char* argv[]) { // to, and run decryption operation. err = init_gpg(&decctx, GPGME_PROTOCOL_OPENPGP); if(err != GPG_ERR_NO_ERROR) { - printf("Error: %s\n", gpgme_strerror(err)); + logger(LOG_ERROR, "%s\n", gpgme_strerror(err)); return 1; } @@ -120,16 +132,16 @@ int main(int argc, char* argv[]) { // We can't do anything if the recipient list is empty (eg: new file but no // recipients specified). if(config->recipients->str == NULL) { - printf("Recipient list empty. Cannot proceed.\n"); + logger(LOG_INFO, "Recipient list empty. Cannot proceed.\n"); } else { // Open the system editor system_edit(tmpfile); - printf("Recipients:\n"); - strll_dump(config->recipients); - // Re-encrypt the plaintext tmp file - //printf("Re-encrypting file '%s' -> '%s'\n", tmpfile, config->file); + logger(LOG_DEBUG, + "Re-encrypting file '%s' -> '%s'\n", + tmpfile, + config->file); gpg_encrypt_file(tmpfile, config->file, config->recipients); } |