[PATCH] Implement reading keys from stdin.
Hristo Venev
hristo at venev.name
Fri Feb 7 21:00:35 CET 2020
If "-" is specified as a path, the key is read as a single line from stdin. If
multiple "-" keys are specified, the order of the lines containing the keys is
the same as the order of the "-" arguments. An empty line means that there is
no key.
---
src/config.c | 68 +++++++++++++++++++++++++++++++++-----------------
src/fuzz/set.c | 20 +++++++++++----
2 files changed, 60 insertions(+), 28 deletions(-)
diff --git a/src/config.c b/src/config.c
index b8394a5..c5e5267 100644
--- a/src/config.c
+++ b/src/config.c
@@ -21,6 +21,7 @@
#include "encoding.h"
#define COMMENT_CHAR '#'
+#define KEY_LINE_MAX_LEN (WG_KEY_LEN_BASE64 + 1)
static const char *get_value(const char *line, const char *key)
{
@@ -118,42 +119,63 @@ static bool parse_keyfile(uint8_t key[static WG_KEY_LEN], const char *path)
{
FILE *f;
int c;
- char dst[WG_KEY_LEN_BASE64];
+ char dst[KEY_LINE_MAX_LEN];
+ bool is_file = false;
bool ret = false;
- f = fopen(path, "r");
- if (!f) {
- perror("fopen");
- return false;
+ if (!strcmp(path, "-"))
+ f = stdin;
+ else {
+ f = fopen(path, "r");
+ if (!f) {
+ perror("fopen");
+ return false;
+ }
+ is_file = true;
}
- if (fread(dst, WG_KEY_LEN_BASE64 - 1, 1, f) != 1) {
- /* If we're at the end and we didn't read anything, we're /dev/null or an empty file. */
- if (!ferror(f) && feof(f) && !ftell(f)) {
- memset(key, 0, WG_KEY_LEN);
- ret = true;
- goto out;
- }
+ if (!fgets(dst, KEY_LINE_MAX_LEN, f)) {
+ dst[0] = '\0';
+ }
- fprintf(stderr, "Invalid length key in key file\n");
+ if (ferror(f)) {
+ perror("fgets");
goto out;
}
- dst[WG_KEY_LEN_BASE64 - 1] = '\0';
- while ((c = getc(f)) != EOF) {
- if (!isspace(c)) {
- fprintf(stderr, "Found trailing character in key file: `%c'\n", c);
+ /* fgets stores the trailing newline into the buffer. If it is not there and
+ * we have not hit EOF, there must be more of the line left. */
+ size_t n = strlen(dst);
+ if (n != 0 && dst[n - 1] == '\n') {
+ n--;
+ dst[n] = '\0';
+ } else if(!feof(f)) {
+ fprintf(stderr, "Key too long: `%s...'\n", dst);
+ goto out;
+ }
+
+ if (is_file) {
+ while ((c = getc(f)) != EOF) {
+ if (!isspace(c)) {
+ fprintf(stderr, "Found trailing character in key file: `%c'\n", c);
+ goto out;
+ }
+ }
+ if (ferror(f) && errno) {
+ perror("getc");
goto out;
}
}
- if (ferror(f) && errno) {
- perror("getc");
- goto out;
- }
- ret = parse_key(key, dst);
+
+ if(n == 0) {
+ memset(key, 0, WG_KEY_LEN);
+ ret = true;
+ } else
+ ret = parse_key(key, dst);
out:
- fclose(f);
+ if (is_file)
+ fclose(f);
return ret;
}
diff --git a/src/fuzz/set.c b/src/fuzz/set.c
index 2f40615..ded26e6 100644
--- a/src/fuzz/set.c
+++ b/src/fuzz/set.c
@@ -37,20 +37,30 @@ static FILE *hacked_fopen(const char *pathname, const char *mode)
int LLVMFuzzerTestOneInput(const char *data, size_t data_len)
{
char *argv[8192] = { "set", "wg0" }, *args;
- size_t argc = 2;
+ size_t args_len, stdin_len, argc = 2;
+ FILE *input;
- if (!data_len)
+ args_len = strnlen(data, data_len);
+ stdin_len = data_len - args_len;
+ /* POSIX (and therefore glibc) doesn't like fmemopen(_, 0, _) */
+ if (args_len == 0 || stdin_len == 0)
return 0;
- assert((args = malloc(data_len)));
- memcpy(args, data, data_len);
- args[data_len - 1] = '\0';
+ assert((args = malloc(args_len + 1)));
+ memcpy(args, data, args_len);
+ args[args_len] = '\0';
+
+ assert((input = fmemopen((void*)(data + args_len), stdin_len, "r")));
+ /* discard null character, also permit tests where stdin is empty */
+ fgetc(input);
for (char *arg = strtok(args, " \t\n\r"); arg && argc < 8192; arg = strtok(NULL, " \t\n\r")) {
if (arg[0])
argv[argc++] = arg;
}
+ stdin = input;
set_main(argc, argv);
free(args);
+ fclose(stdin);
return 0;
}
--
2.24.1
More information about the WireGuard
mailing list