diff options
author | Tim Rühsen <tim.ruehsen@gmx.de> | 2019-05-25 21:19:47 +0200 |
---|---|---|
committer | Tim Rühsen <tim.ruehsen@gmx.de> | 2019-05-29 17:01:45 +0200 |
commit | 6b2e17fcf2ba349875969e8e01fbeaf92afa59cf (patch) | |
tree | b3e6abb7f96bb432966cda8650a3b7f65ab4fe40 | |
parent | 98590fe57ba10372036f97fe0ff3c93220bca13c (diff) | |
download | gnutls-tmp-remove-libopts.tar.gz |
Add src/psk2.c using new src/options.c [skip ci]tmp-remove-libopts
Signed-off-by: Tim Rühsen <tim.ruehsen@gmx.de>
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 11 | ||||
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/options.c | 428 | ||||
-rw-r--r-- | src/options.h | 51 | ||||
-rw-r--r-- | src/psk2.c | 334 | ||||
-rw-r--r-- | src/psk2tool.md.in | 60 |
7 files changed, 890 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 2112606601..2625231563 100644 --- a/configure.ac +++ b/configure.ac @@ -727,6 +727,7 @@ AM_MISSING_PROG([AUTOGEN], [autogen]) included_libopts=no if test "$enable_tools" != "no" || test "$enable_doc" != "no"; then + AC_CHECK_PROGS([PANDOC], [pandoc]) AC_CHECK_PROGS([autogen], [autogen]) if test -z "$autogen"; then @@ -747,6 +748,7 @@ else gl_STDNORETURN_H AM_CONDITIONAL([INSTALL_LIBOPTS],[false]) fi +AM_CONDITIONAL([WITH_PANDOC], [ test -n "$PANDOC" ]) AM_CONDITIONAL(NEED_LIBOPTS, test "$included_libopts" = "yes") diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index 9beee86060..5df18471d5 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -26,7 +26,7 @@ MAINTAINERCLEANFILES = stamp_mans -include $(top_srcdir)/doc/doc.mk TOOLS_MANS = gnutls-cli.1 gnutls-cli-debug.1 gnutls-serv.1 \ - certtool.1 psktool.1 p11tool.1 ocsptool.1 tpmtool.1 + certtool.1 psktool.1 psk2tool.1 p11tool.1 ocsptool.1 tpmtool.1 SRP_MANS = srptool.1 DANE_MANS = danetool.1 @@ -99,6 +99,15 @@ psktool.1: ../../src/psktool-args.def autogen -L ../../src -DMAN_SECTION=1 -Tagman-cmd.tpl "$<".tmp && \ rm -f "$<".tmp +psk2tool.1: $(top_srcdir)/src/psk2.c $(top_srcdir)/src/psk2tool.md.in $(top_srcdir)/src/options.c + $(top_builddir)/src/psk2tool --options-md >$@.tmp + ( \ + echo "% psk2tool(1) GnuTLS PSK2 tool|GnuTLS $(PACKAGE_VERSION)"; \ + echo; \ + sed -e '/@OPTIONS@/{r $@.tmp' -e 'd}' $(top_srcdir)/src/psk2tool.md.in; \ + ) | $(PANDOC) -s -f markdown -t man -o $@ + rm -f $@.tmp + APIMANS = APIMANS += dane_cert_type_name.3 APIMANS += dane_cert_usage_name.3 diff --git a/src/Makefile.am b/src/Makefile.am index 0374924c53..a40626206a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -82,7 +82,7 @@ else LIBOPTS = $(LIBOPTS_LDADD) endif -bin_PROGRAMS = psktool gnutls-cli-debug certtool +bin_PROGRAMS = psktool psk2tool gnutls-cli-debug certtool if ENABLE_SRP bin_PROGRAMS += srptool endif @@ -129,6 +129,10 @@ noinst_LTLIBRARIES += libcmd-psk.la libcmd_psk_la_SOURCES = psktool-args.def nodist_libcmd_psk_la_SOURCES = psktool-args.c psktool-args.h +psk2tool_SOURCES = psk2.c options.c +psk2tool_LDADD = ../lib/libgnutls.la ../gl/libgnu.la +psk2tool_LDADD += $(LTLIBINTL) gl/libgnu_gpl.la + if ENABLE_OCSP diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000000..b50d4e3eb5 --- /dev/null +++ b/src/options.c @@ -0,0 +1,428 @@ +/* + * Copyright(c) 2012 Tim Ruehsen + * Copyright(c) 2015-2019 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <c-ctype.h> // c_tolower, c_isalnum + +#include <gnutls/gnutls.h> +#include "options.h" + +int parse_integer(option_t opt, const char *val, const char invert) +{ + *((int *)opt->var) = val ? atoi(val) : 0; + + return 0; +} + +static int parse_filename(option_t opt, const char *val, const char invert) +{ + free(*((char **)opt->var)); +// *((const char **)opt->var) = val ? shell_expand(val) : NULL; + *((char **)opt->var) = val ? strdup(val) : NULL; + + return 0; +} + +int parse_string(option_t opt, const char *val, const char invert) +{ + free(*((char **)opt->var)); + *((char **)opt->var) = val ? strdup(val) : NULL; + + return 0; +} + +/* +static int parse_stringset(option_t opt, const char *val, const char invert) +{ + wget_stringmap_t *map = *((wget_stringmap_t **)opt->var); + + if (val) { + const char *s, *p; + + wget_stringmap_clear(map); + + for (s = p = val; *p; s = p + 1) { + if ((p = strchrnul(s, ',')) != s) + wget_stringmap_put_noalloc(map, wget_strmemdup(s, p - s), NULL); + } + } else { + wget_stringmap_clear(map); + } + + return 0; +} + +static const char *_strchrnul_esc(const char *s, char c) +{ + const char *p; + + for (p = s; *p; p++) { + if (*p == '\\' && (p[1] == '\\' || p[1] == c)) + p++; + else if (*p == c) + return p; + } + + return p; // pointer to trailing \0 +} + +static char *_strmemdup_esc(const char *s, size_t size) +{ + const char *p, *e; + size_t newsize = 0; + + for (p = s, e = s + size; p < e; p++) { + if (*p == '\\') { + if (p < e - 1) { + newsize++; + p++; + } + } else + newsize++; + } + + char *ret = malloc(newsize + 1); + char *dst = ret; + + for (p = s, e = s + size; p < e; p++) { + if (*p == '\\') { + if (p < e - 1) + *dst++ = *++p; + } else + *dst++ = *p; + } + *dst = 0; + + return ret; +} + +static int parse_stringlist_expand(option_t opt, const char *val, int expand, int max_entries) +{ + if (val && *val) { + wget_vector_t *v = *((wget_vector_t **)opt->var); + const char *s, *p; + + if (!v) + v = *((wget_vector_t **)opt->var) = wget_vector_create(8, (wget_vector_compare_t)strcmp); + + for (s = p = val; *p; s = p + 1) { + if ((p = _strchrnul_esc(s, ',')) != s) { + if (wget_vector_size(v) >= max_entries) { + wget_debug_printf("%s: More than %d entries, ignoring overflow\n", __func__, max_entries); + return -1; + } + + const char *fname = _strmemdup_esc(s, p - s); + + if (expand && *s == '~') { + wget_vector_add_noalloc(v, shell_expand(fname)); + xfree(fname); + } else + wget_vector_add_noalloc(v, fname); + } + } + } else { + wget_vector_free(opt->var); + } + + return 0; +} + +static int parse_stringlist(option_t opt, const char *val, const char invert) +{ + // max number of 1024 entries to avoid out-of-memory + return parse_stringlist_expand(opt, val, 0, 1024); +} +*/ + +int parse_bool(option_t opt, const char *val, const char invert) +{ + if (opt->var) { + if (!val || !strcmp(val, "1") || !strcmp(val, "y") || !strcmp(val, "yes") || !strcmp(val, "on")) + *((char *) opt->var) = !invert; + else if (!*val || !strcmp(val, "0") || !strcmp(val, "n") || !strcmp(val, "no") || !strcmp(val, "off")) + *((char *) opt->var) = invert; + else { + fprintf(stderr, "Invalid boolean value '%s'\n", val); + return -1; + } + } + + return 0; +} + +static inline void print_first(const char s, const char *l, const char *msg) +{ + if (s) + printf(" -%c, --%-20s %s", s, l, msg); + else + printf(" --%-20s %s", l, msg); +} + +static inline void print_next(const char *msg) +{ + printf("%32s%s", "", msg); +} + +void print_options(const struct optionw *options, int noptions) +{ + for (int it = 0; it < noptions; it++) { + print_first(options[it].short_name, + options[it].long_name, + options[it].help_str[0]); + for (unsigned i = 1; i < countof(options[it].help_str) && options[it].help_str[i]; i++) + print_next(options[it].help_str[i]); + } +} + +static inline void print_first_md(const char s, const char *l, const char *msg) +{ + if (s) + printf("## `-%c`, `--%s`\n\n%s", s, l, msg); + else + printf("## `--%s`\n\n%s", l, msg); +} + +static void print_options_md(const struct optionw *options, int noptions) +{ + for (int it = 0; it < noptions; it++) { + print_first_md(options[it].short_name, + options[it].long_name, + options[it].help_str[0]); + for (unsigned i = 1; i < countof(options[it].help_str) && options[it].help_str[i]; i++) + printf("%s", options[it].help_str[i]); + printf("\n"); + } +} + +static int opt_compare(const void *key, const void *option) +{ + return strcmp(key, ((option_t) option)->long_name); +} + +static int opt_compare_config_linear(const char *key, const char *command) +{ + const char *s1 = key, *s2 = command; + + for (; *s1 && *s2; s1++, s2++) { + if (*s2 == '-' || *s2 == '_') { + if (*s1 == '-' || *s1 == '_') + s1++; + s2++; + } + + if (!*s1 || !*s2 || c_tolower(*s1) != *s2) break; + // *s2 is guaranteed to be lower case so convert *s1 to lower case + } + + return *s1 != *s2; // no need for tolower() here +} + +// return values: +// < 0 : parse error +// >= 0 : number of arguments processed +static int set_long_option(const char *name, const char *value, const struct optionw *options, int noptions) +{ + option_t opt; + char invert = 0, value_present = 0, case_insensitive = 1; + char namebuf[strlen(name) + 1], *p; + int ret = 0, rc; + + if ((p = strchr(name, '='))) { + // option with appended value + memcpy(namebuf, name, p - name); + namebuf[p - name] = 0; + name = namebuf; + value = p + 1; + value_present = 1; + } + + // If the option is passed from .wget2rc (--*), delete the "--" prefix + if (!strncmp(name, "--", 2)) { + case_insensitive = 0; + name += 2; + } + // If the option is negated (--no-) delete the "no-" prefix + if (!strncmp(name, "no-", 3)) { + invert = 1; + name += 3; + } + + if (case_insensitive) { + opt = bsearch(name, options, noptions, sizeof(options[0]), opt_compare); + if (!opt) { + // Fallback to linear search for 'unsharp' searching. + // Maybe the user asked for e.g. https_only or httpsonly instead of https-only + // opt_compare_config_linear() will find these. Wget -e/--execute compatibility. + for (int it = 0; it < noptions && !opt; it++) + if (opt_compare_config_linear(name, options[it].long_name) == 0) + opt = &options[it]; + } + } else + opt = bsearch(name, options, noptions, sizeof(options[0]), opt_compare); + + if (!opt) { + fprintf(stderr, "Unknown option '%s'\n", name); + return -1; + } + + if (value_present) { + // "option=*" + if (invert) { + if (!opt->nargs || opt->parser == parse_string || +// opt->parser == parse_stringset || +// opt->parser == parse_stringlist || + opt->parser == parse_filename) +// || opt->parser == parse_filenames) + { + fprintf(stderr, "Option 'no-%s' doesn't allow an argument\n", name); + return -1; + } + } else if (!opt->nargs) { + printf("Option '%s' doesn't allow an argument\n", name); + return -1; + } + } else { + // "option" + switch (opt->nargs) { + case 0: + value = NULL; + break; + case 1: + if (!value) { + fprintf(stderr, "Missing argument for option '%s'\n", name); + // empty string is allowed in value i.e. *value = '\0' + return -1; + } + + if (invert && (opt->parser == parse_string || +// opt->parser == parse_stringset || +// opt->parser == parse_stringlist || + opt->parser == parse_filename)) +// || opt->parser == parse_filenames)) + value = NULL; + else + ret = opt->nargs; + break; + case -1: + if(value) + ret = 1; + break; + default: + break; + } + } + + if ((rc = opt->parser(opt, value, invert)) < 0) + return rc; + + return ret; +} + +int parse_command_line(int argc, const char **argv, const struct optionw *options, int noptions) +{ + static short shortcut_to_option[128]; + const char *first_arg = NULL; + int n, rc; + + if (argc == 2 && !strcmp(argv[1], "--options-md")) { + print_options_md(options, noptions); + exit(EXIT_SUCCESS); + } + + // init the short option lookup table + if (!shortcut_to_option[0]) { + for (int it = 0; it < noptions; it++) { + if (options[it].short_name) + shortcut_to_option[(unsigned char)options[it].short_name] = it + 1; + } + } + + // I like the idea of getopt() but not it's implementation (e.g. global variables). + // Therefore I implement my own getopt() behavior. + for (n = 1; n < argc && first_arg != argv[n]; n++) { + const char *argp = argv[n]; + + if (argp[0] != '-') { + // Move args behind options to allow mixed args/options like getopt(). + // In the end, the order of the args is as before. + const char *cur = argv[n]; + for (int it = n; it < argc - 1; it++) + argv[it] = argv[it + 1]; + argv[argc - 1] = cur; + + // Once we see the first arg again, we are done + if (!first_arg) + first_arg = cur; + + n--; + continue; + } + + if (argp[1] == '-') { + // long option + if (argp[2] == 0) + return n + 1; + + if ((rc = set_long_option(argp + 2, n < argc - 1 ? argv[n+1] : NULL, options, noptions)) < 0) + return rc; + + n += rc; + + } else if (argp[1]) { + // short option(s) + for (int pos = 1; argp[pos]; pos++) { + option_t opt; + int idx; + + if (c_isalnum(argp[pos]) && (idx = shortcut_to_option[(unsigned char)argp[pos]])) { + opt = &options[idx - 1]; + // printf("opt=%p [%c]\n",(void *)opt,argp[pos]); + // printf("name=%s\n",opt->long_name); + if (opt->nargs > 0) { + const char *val; + + if (!argp[pos + 1] && argc <= n + opt->nargs) { + fprintf(stderr,"Missing argument(s) for option '-%c'\n", argp[pos]); + return -1; + } + val = argp[pos + 1] ? argp + pos + 1 : argv[++n]; + if ((rc = opt->parser(opt, val, 0)) < 0) + return rc; + n += rc; + break; + } else {//if (opt->args == 0) + if ((rc = opt->parser(opt, NULL, 0)) < 0) + return rc; + } + } else { + fprintf(stderr,"Unknown option '-%c'\n", argp[pos]); + return -1; + } + } + } + } + + return n; +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000000..033bd4d31d --- /dev/null +++ b/src/options.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011-2012 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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/>. + */ + +#ifndef GNUTLS_SRC_OPTIONS_H +#define GNUTLS_SRC_OPTIONS_H + +// number of elements within an array +#define countof(a) (sizeof(a)/sizeof(*(a))) + +typedef const struct optionw *option_t; // forward declaration + +struct optionw { + const char + *long_name; + void + *var; + int + (*parser)(option_t opt, const char *val, const char invert); + int + nargs; // -1: optional argument, else: number of arguments + char + short_name; + const char + *help_str[4]; +}; + +int parse_command_line(int argc, const char **argv, const struct optionw *options, int noptions); +int parse_integer(option_t opt, const char *val, const char invert); +int parse_bool(option_t opt, const char *val, const char invert); +int parse_string(option_t opt, const char *val, const char invert); +void print_options(const struct optionw *options, int noptions); +int print_version(option_t opt, const char *val, const char invert); +int print_help(option_t opt, const char *val, const char invert); + +#endif /* GNUTLS_SRC_OPTIONS_H */ diff --git a/src/psk2.c b/src/psk2.c new file mode 100644 index 0000000000..82184db4a0 --- /dev/null +++ b/src/psk2.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2005-2012 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 <config.h> + +/* Gnulib portability files. */ + +#ifndef ENABLE_PSK + +#include <stdio.h> + +int main(int argc, char **argv) +{ + printf("\nPSK not supported. This program is a dummy.\n\n"); + return 1; +}; + +#else + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifndef _WIN32 +#include <pwd.h> +#include <unistd.h> +#else +#include <windows.h> +#endif + +/* Gnulib portability files. */ +#include <minmax.h> +#include "getpass.h" + +/* GnuTLS files */ +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> /* for random */ +#include "options.h" + +static struct config { + bool debug; + int keysize; + char *username; + char *pskfile; +} config = { + // default values for config options (if not 0 or NULL) + .keysize = -1, +}; + +static const struct optionw options[] = { + { "debug", &config.debug, parse_bool, -1, 'd', + { "Print debugging messages. (default: off)\n" + } + }, + { "help", NULL, print_help, 0, 'h', + { "Display extended usage information and exit\n" + } + }, + { "pskfile", &config.pskfile, parse_string, 1, 'p', + { "Specify a pre-shared key file\n" + } + }, + { "keysize", &config.keysize, parse_integer, 1, 's', + { "Specify the key size in bytes (default is 32-bytes or 256-bits)\n", + "- it must be in the range:\n", + "0 to 512\n" + } + }, + { "username", &config.pskfile, parse_string, 1, 'u', + { "Specify the username to use\n" + } + }, + { "version", NULL, print_version, -1, 'v', + { "Display the version information and exit\n" + } + }, +}; + +int print_version(option_t opt, const char *val, const char invert) +{ + puts( + "psktool " PACKAGE_VERSION "\n" + "Copyright (C) 2000-2018 Free Software Foundation, and others, all rights reserved.\n" + "This is free software. It is licensed for use, modification and\n" + "redistribution under the terms of the GNU General Public License,\n" + "version 3 or later <https://gnu.org/licenses/gpl.html>\n" + "\n" + "Please send bug reports to: <bugs@gnutls.org>"); + + return -1; // stop processing & exit +} + +int print_help(option_t opt, const char *val, const char invert) +{ + puts( + "psktool - GnuTLS PSK tool\n" + "Usage: psktool [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n"); + + print_options(options, countof(options)); + + puts( + "\n" + "Program that generates random keys for use with TLS-PSK. The keys are\n" + "stored in hexadecimal format in a key file.\n" + "\n" + "Please send bug reports to: <bugs@gnutls.org>"); + + return -1; // stop processing and exit +} + + +static int write_key(const char *username, const char *key, int key_size, + const char *passwd_file); + +#define MAX_KEY_SIZE 512 +int main(int argc, const char **argv) +{ + int ret; +#ifndef _WIN32 + struct passwd *pwd; +#endif + unsigned char key[MAX_KEY_SIZE]; + char hex_key[MAX_KEY_SIZE * 2 + 1]; + int key_size; + gnutls_datum_t dkey; + const char *passwd, *username; + size_t hex_key_size = sizeof(hex_key); + + if ((ret = gnutls_global_init()) < 0) { + fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + umask(066); + + if (parse_command_line(argc, argv, options, countof(options)) < 0) + exit(1); + + if (!config.pskfile) { + fprintf(stderr, "You need to specify a PSK key file\n"); + exit(1); + } else + passwd = config.pskfile; + + if (!config.username) { +#ifndef _WIN32 + pwd = getpwuid(getuid()); + + if (pwd == NULL) { + fprintf(stderr, "No such user\n"); + return -1; + } + + username = pwd->pw_name; +#else + fprintf(stderr, "Please specify a user\n"); + return -1; +#endif + } else + username = config.username; + + if (config.keysize > MAX_KEY_SIZE) { + fprintf(stderr, "Key size is too long\n"); + exit(1); + } + + if (config.keysize < 1) + key_size = 32; + else + key_size = config.keysize; + + printf("Generating a random key for user '%s'\n", username); + + ret = gnutls_rnd(GNUTLS_RND_RANDOM, (char *) key, key_size); + if (ret < 0) { + fprintf(stderr, "Not enough randomness\n"); + exit(1); + } + + dkey.data = key; + dkey.size = key_size; + + ret = gnutls_hex_encode(&dkey, hex_key, &hex_key_size); + if (ret < 0) { + fprintf(stderr, "HEX encoding error\n"); + exit(1); + } + + ret = write_key(username, hex_key, hex_key_size, passwd); + if (ret == 0) + printf("Key stored to %s\n", passwd); + + return ret; +} + +static int filecopy(const char *src, const char *dst) +{ + FILE *fd, *fd2; + char line[5 * 1024]; + char *p; + + fd = fopen(dst, "w"); + if (fd == NULL) { + fprintf(stderr, "Cannot open '%s' for write\n", dst); + return -1; + } + + fd2 = fopen(src, "r"); + if (fd2 == NULL) { + /* empty file */ + fclose(fd); + return 0; + } + + line[sizeof(line) - 1] = 0; + do { + p = fgets(line, sizeof(line) - 1, fd2); + if (p == NULL) + break; + + fputs(line, fd); + } + while (1); + + fclose(fd); + fclose(fd2); + + return 0; +} + +static int +write_key(const char *username, const char *key, int key_size, + const char *passwd_file) +{ + FILE *fd; + char line[5 * 1024]; + char *p, *pp; + char tmpname[1024]; + + + /* delete previous entry */ + struct stat st; + FILE *fd2; + int put; + + if (strlen(passwd_file) + 5 > sizeof(tmpname)) { + fprintf(stderr, "file '%s' is tooooo long\n", passwd_file); + return -1; + } + + snprintf(tmpname, sizeof(tmpname), "%s.tmp", passwd_file); + + if (stat(tmpname, &st) != -1) { + fprintf(stderr, "file '%s' is locked\n", tmpname); + return -1; + } + + if (filecopy(passwd_file, tmpname) != 0) { + fprintf(stderr, "Cannot copy '%s' to '%s'\n", passwd_file, + tmpname); + return -1; + } + + fd = fopen(passwd_file, "w"); + if (fd == NULL) { + fprintf(stderr, "Cannot open '%s' for write\n", + passwd_file); + (void)remove(tmpname); + return -1; + } + + fd2 = fopen(tmpname, "r"); + if (fd2 == NULL) { + fprintf(stderr, "Cannot open '%s' for read\n", tmpname); + (void)remove(tmpname); + fclose(fd); + return -1; + } + + put = 0; + do { + p = fgets(line, sizeof(line) - 1, fd2); + if (p == NULL) + break; + + pp = strchr(line, ':'); + if (pp == NULL) + continue; + + if (strncmp(p, username, + MAX(strlen(username), + (unsigned int) (pp - p))) == 0) { + put = 1; + fprintf(fd, "%s:%s\n", username, key); + } else { + fputs(line, fd); + } + } + while (1); + + if (put == 0) { + fprintf(fd, "%s:%s\n", username, key); + } + + fclose(fd); + fclose(fd2); + + (void)remove(tmpname); + + + return 0; +} + +#endif /* ENABLE_PSK */ diff --git a/src/psk2tool.md.in b/src/psk2tool.md.in new file mode 100644 index 0000000000..3c2b4317ca --- /dev/null +++ b/src/psk2tool.md.in @@ -0,0 +1,60 @@ +# NAME + + psktool - GnuTLS PSK tool + +# SYNOPSIS + + psktool [-flags] [-flag [value]] [--option-name[[=| ]value]] + + All arguments must be options. + +# DESCRIPTION + + Program that generates random keys for use with TLS-PSK. The keys are stored in hexadecimal format in a key + file. + +# OPTIONS + +@OPTIONS@ + +# EXAMPLES + +To add a user 'psk_identity' in keys.psk for use with GnuTLS run: +``` +$ ./psktool -u psk_identity -p keys.psk +Generating a random key for user 'psk_identity' +Key stored to keys.psk +$ cat keys.psk +psk_identity:88f3824b3e5659f52d00e959bacab954b6540344 +``` + +This command will create keys.psk if it does not exist and will add user 'psk_identity'. + +# EXIT STATUS + +One of the following exit values will be returned: + +## 0 (EXIT_SUCCESS) + + Successful program execution. + +## 1 (EXIT_FAILURE) + + The operation failed or the command syntax was not valid. + +# SEE ALSO + +gnutls-cli-debug (1), gnutls-serv (1), srptool (1), certtool (1) + +# AUTHORS + +Nikos Mavrogiannopoulos, Simon Josefsson and others; see /usr/share/doc/gnutls/AUTHORS for a complete list. + +# COPYRIGHT + +Copyright (C) 2000-2019 Free Software Foundation, and others all rights reserved. This program is released +under the terms of the GNU General Public License, version 3 or later. + +# BUGS + +Please send bug reports to: bugs@gnutls.org |