summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2019-04-03 11:59:37 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2019-06-20 15:49:36 +0200
commit90142f2d70018d862cba02067159cad8c7db4239 (patch)
tree9ddc0fb58a01cd852dc024774e3255a7e76bef53
parent4292c1ae6db9edd4b178c10bc5045534ea38e4a5 (diff)
downloadgnutls-90142f2d70018d862cba02067159cad8c7db4239.tar.gz
Use inih to parse configuration file
This introduces the inih copylib, and makes our configuration file parsing more flexible. Relates: #587 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--cfg.mk2
-rw-r--r--configure.ac7
-rw-r--r--devel/cppcheck.suppressions2
-rw-r--r--lib/Makefile.am6
-rw-r--r--lib/inih/LICENSE.txt27
-rw-r--r--lib/inih/ini.c269
-rw-r--r--lib/inih/ini.h131
-rw-r--r--lib/name_val_array.h130
-rw-r--r--lib/priority.c125
9 files changed, 607 insertions, 92 deletions
diff --git a/cfg.mk b/cfg.mk
index 200f421659..8f8d2a1d38 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -45,7 +45,6 @@ VC_LIST_ALWAYS_EXCLUDE_REGEX = ^maint.mk|gtk-doc.make|m4/pkg|doc/fdl-1.3.texi|sr
update-copyright-env = UPDATE_COPYRIGHT_USE_INTERVALS=1
# Explicit syntax-check exceptions.
-exclude_file_name_regexp--sc_error_message_period = ^src/crywrap/crywrap.c$$
exclude_file_name_regexp--sc_error_message_uppercase = ^doc/examples/ex-cxx.cpp|guile/src/core.c|src/certtool.c|src/ocsptool.c|src/crywrap/crywrap.c|tests/pkcs12_encode.c$$
exclude_file_name_regexp--sc_file_system = ^doc/doxygen/Doxyfile
exclude_file_name_regexp--sc_prohibit_cvs_keyword = ^lib/nettle/.*$$
@@ -56,6 +55,7 @@ exclude_file_name_regexp--sc_m4_quote_check='lib/unistring/m4/absolute-header.m4
exclude_file_name_regexp--sc_makefile_at_at_check='lib/unistring/Makefile.am'
exclude_file_name_regexp--sc_prohibit_stddef_without_use='u*-normalize.c'
exclude_file_name_regexp--sc_prohibit_strncpy='unistr.in.h'
+exclude_file_name_regexp--sc_prohibit_strncpy='lib/inih/ini.c'
gl_public_submodule_commit =
autoreconf:
diff --git a/configure.ac b/configure.ac
index e0c5c25d5b..c2fe1794ef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -950,6 +950,13 @@ dnl Some variables needed in makefiles
YEAR=`date +%Y`
AC_SUBST([YEAR], $YEAR)
+dnl configuration options for config file parsing (inih)
+AC_DEFINE([INI_MAX_LINE], 2048, [inih maximum line size])
+AC_DEFINE([INI_ALLOW_INLINE_COMMENTS], 1, [whether to allowin inline comments])
+AC_DEFINE([INI_STOP_ON_FIRST_ERROR], 1, [whether to stop on first error])
+AC_DEFINE_UNQUOTED([INI_INLINE_COMMENT_PREFIXES], [";#"], [The inline comment prefixes])
+AC_DEFINE_UNQUOTED([INI_START_COMMENT_PREFIXES], [";#"], [The comment prefixes])
+
AC_CONFIG_FILES([guile/pre-inst-guile], [chmod +x guile/pre-inst-guile])
AC_CONFIG_FILES([
Makefile
diff --git a/devel/cppcheck.suppressions b/devel/cppcheck.suppressions
index 8fa8ccb766..2273647a4f 100644
--- a/devel/cppcheck.suppressions
+++ b/devel/cppcheck.suppressions
@@ -2,3 +2,5 @@ allocaCalled:lib/nettle/int/pss*.c
variableScope:lib/safe-memfuncs.c:42
variableScope:gl/gettext.h
redundantAssignment:lib/nettle/backport/cmac.c:132
+variableScope:lib/inih/ini.c:97
+variableScope:lib/inih/ini.c:241
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 83b328e89a..5f2d3f849a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -72,11 +72,11 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c gthreads.h handshake-tls
pk.c cert-cred.c global.c constate.c anon_cred.c pkix_asn1_tab.c gnutls_asn1_tab.c \
mem.c fingerprint.c tls-sig.c ecc.c alert.c privkey_raw.c atomic.h \
system/certs.c system/threads.c system/fastopen.c system/sockets.c \
- str-iconv.c system.c profiles.c profiles.h \
+ str-iconv.c system.c profiles.c profiles.h inih/ini.c \
str.c str-unicode.c str-idna.c state.c cert-cred-x509.c file.c supplemental.c \
random.c crypto-api.c crypto-api.h privkey.c pcert.c pubkey.c locks.c dtls.c \
system_override.c crypto-backend.c verify-tofu.c pin.c tpm.c fips.c \
- safe-memfuncs.c atfork.c atfork.h randomart.c \
+ safe-memfuncs.c atfork.c atfork.h randomart.c name_val_array.h \
system-keys.h urls.c urls.h prf.c auto-verify.c dh-session.c \
cert-session.c handshake-checks.c dtls-sw.c dh-primes.c openpgp_compat.c \
crypto-selftests.c crypto-selftests-pk.c secrets.c extv.c extv.h \
@@ -117,7 +117,7 @@ HFILES = abstract_int.h debug.h cipher.h \
dh.h kx.h hash_int.h cipher_int.h \
db.h auth.h hello_ext.h handshake-defs.h \
x509_b64.h sslv2_compat.h datum.h \
- mpi.h pk.h record.h \
+ mpi.h pk.h record.h inih/ini.h \
constate.h global.h tls-sig.h mem.h \
session_pack.h str.h str_array.h \
state.h x509.h crypto-backend.h \
diff --git a/lib/inih/LICENSE.txt b/lib/inih/LICENSE.txt
new file mode 100644
index 0000000000..cb7ee2d017
--- /dev/null
+++ b/lib/inih/LICENSE.txt
@@ -0,0 +1,27 @@
+
+The "inih" library is distributed under the New BSD license:
+
+Copyright (c) 2009, Ben Hoyt
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Ben Hoyt nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/inih/ini.c b/lib/inih/ini.c
new file mode 100644
index 0000000000..81df6a037f
--- /dev/null
+++ b/lib/inih/ini.c
@@ -0,0 +1,269 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+https://github.com/benhoyt/inih
+
+*/
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Used by ini_parse_string() to keep track of string parsing state. */
+typedef struct {
+ const char* ptr;
+ size_t num_left;
+} ini_parse_string_ctx;
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+ char* p = s + strlen(s);
+ while (p > s && isspace((unsigned char)(*--p)))
+ *p = '\0';
+ return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+ while (*s && isspace((unsigned char)(*s)))
+ s++;
+ return (char*)s;
+}
+
+/* Return pointer to first char (of chars) or inline comment in given string,
+ or pointer to null at end of string if neither found. Inline comment must
+ be prefixed by a whitespace character to register as a comment. */
+static char* find_chars_or_comment(const char* s, const char* chars)
+{
+#if INI_ALLOW_INLINE_COMMENTS
+ int was_space = 0;
+ while (*s && (!chars || !strchr(chars, *s)) &&
+ !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
+ was_space = isspace((unsigned char)(*s));
+ s++;
+ }
+#else
+ while (*s && (!chars || !strchr(chars, *s))) {
+ s++;
+ }
+#endif
+ return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+ strncpy(dest, src, size - 1);
+ dest[size - 1] = '\0';
+ return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
+ void* user)
+{
+ /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+ int max_line = INI_MAX_LINE;
+#else
+ char* line;
+ int max_line = INI_INITIAL_ALLOC;
+#endif
+#if INI_ALLOW_REALLOC && !INI_USE_STACK
+ char* new_line;
+ int offset;
+#endif
+ char section[MAX_SECTION] = "";
+ char prev_name[MAX_NAME] = "";
+
+ char* start;
+ char* end;
+ char* name;
+ char* value;
+ int lineno = 0;
+ int error = 0;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_INITIAL_ALLOC);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+#if INI_HANDLER_LINENO
+#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
+#else
+#define HANDLER(u, s, n, v) handler(u, s, n, v)
+#endif
+
+ /* Scan through stream line by line */
+ while (reader(line, max_line, stream) != NULL) {
+#if INI_ALLOW_REALLOC && !INI_USE_STACK
+ offset = strlen(line);
+ while (offset == max_line - 1 && line[offset - 1] != '\n') {
+ max_line *= 2;
+ if (max_line > INI_MAX_LINE)
+ max_line = INI_MAX_LINE;
+ new_line = realloc(line, max_line);
+ if (!new_line) {
+ free(line);
+ return -2;
+ }
+ line = new_line;
+ if (reader(line + offset, max_line - offset, stream) == NULL)
+ break;
+ if (max_line >= INI_MAX_LINE)
+ break;
+ offset += strlen(line + offset);
+ }
+#endif
+
+ lineno++;
+
+ start = line;
+#if INI_ALLOW_BOM
+ if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+ (unsigned char)start[1] == 0xBB &&
+ (unsigned char)start[2] == 0xBF) {
+ start += 3;
+ }
+#endif
+ start = lskip(rstrip(start));
+
+ if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
+ /* Start-of-line comment */
+ }
+#if INI_ALLOW_MULTILINE
+ else if (*prev_name && *start && start > line) {
+ /* Non-blank line with leading whitespace, treat as continuation
+ of previous name's value (as per Python configparser). */
+ if (!HANDLER(user, section, prev_name, start) && !error)
+ error = lineno;
+ }
+#endif
+ else if (*start == '[') {
+ /* A "[section]" line */
+ end = find_chars_or_comment(start + 1, "]");
+ if (*end == ']') {
+ *end = '\0';
+ strncpy0(section, start + 1, sizeof(section));
+ *prev_name = '\0';
+ }
+ else if (!error) {
+ /* No ']' found on section line */
+ error = lineno;
+ }
+ }
+ else if (*start) {
+ /* Not a comment, must be a name[=:]value pair */
+ end = find_chars_or_comment(start, "=:");
+ if (*end == '=' || *end == ':') {
+ *end = '\0';
+ name = rstrip(start);
+ value = end + 1;
+#if INI_ALLOW_INLINE_COMMENTS
+ end = find_chars_or_comment(value, NULL);
+ if (*end)
+ *end = '\0';
+#endif
+ value = lskip(value);
+ rstrip(value);
+
+ /* Valid name[=:]value pair found, call handler */
+ strncpy0(prev_name, name, sizeof(prev_name));
+ if (!HANDLER(user, section, name, value) && !error)
+ error = lineno;
+ }
+ else if (!error) {
+ /* No '=' or ':' found on name[=:]value line */
+ error = lineno;
+ }
+ }
+
+#if INI_STOP_ON_FIRST_ERROR
+ if (error)
+ break;
+#endif
+ }
+
+#if !INI_USE_STACK
+ free(line);
+#endif
+
+ return error;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file, ini_handler handler, void* user)
+{
+ return ini_parse_stream((ini_reader)fgets, file, handler, user);
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename, ini_handler handler, void* user)
+{
+ FILE* file;
+ int error;
+
+ file = fopen(filename, "r");
+ if (!file)
+ return -1;
+ error = ini_parse_file(file, handler, user);
+ fclose(file);
+ return error;
+}
+
+/* An ini_reader function to read the next line from a string buffer. This
+ is the fgets() equivalent used by ini_parse_string(). */
+static char* ini_reader_string(char* str, int num, void* stream) {
+ ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
+ const char* ctx_ptr = ctx->ptr;
+ size_t ctx_num_left = ctx->num_left;
+ char* strp = str;
+ char c;
+
+ if (ctx_num_left == 0 || num < 2)
+ return NULL;
+
+ while (num > 1 && ctx_num_left != 0) {
+ c = *ctx_ptr++;
+ ctx_num_left--;
+ *strp++ = c;
+ if (c == '\n')
+ break;
+ num--;
+ }
+
+ *strp = '\0';
+ ctx->ptr = ctx_ptr;
+ ctx->num_left = ctx_num_left;
+ return str;
+}
+
+/* See documentation in header file. */
+int ini_parse_string(const char* string, ini_handler handler, void* user) {
+ ini_parse_string_ctx ctx;
+
+ ctx.ptr = string;
+ ctx.num_left = strlen(string);
+ return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
+ user);
+}
diff --git a/lib/inih/ini.h b/lib/inih/ini.h
new file mode 100644
index 0000000000..6c3d664d2e
--- /dev/null
+++ b/lib/inih/ini.h
@@ -0,0 +1,131 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+https://github.com/benhoyt/inih
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <config.h>
+
+/* Nonzero if ini_handler callback should accept lineno parameter. */
+#ifndef INI_HANDLER_LINENO
+#define INI_HANDLER_LINENO 0
+#endif
+
+/* Typedef for prototype of handler function. */
+#if INI_HANDLER_LINENO
+typedef int (*ini_handler)(void* user, const char* section,
+ const char* name, const char* value,
+ int lineno);
+#else
+typedef int (*ini_handler)(void* user, const char* section,
+ const char* name, const char* value);
+#endif
+
+/* Typedef for prototype of fgets-style reader function. */
+typedef char* (*ini_reader)(char* str, int num, void* stream);
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+ (whitespace stripped), and comments starting with ';' (semicolon). Section
+ is "" if name=value pair parsed before any section heading. name:value
+ pairs are also supported as a concession to Python's configparser.
+
+ For each name=value pair parsed, call handler function with given user
+ pointer as well as section, name, and value (data only valid for duration
+ of handler call). Handler should return nonzero on success, zero on error.
+
+ Returns 0 on success, line number of first error on parse error (doesn't
+ stop on first error), -1 on file open error, or -2 on memory allocation
+ error (only when INI_USE_STACK is zero).
+*/
+int ini_parse(const char* filename, ini_handler handler, void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+ close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file, ini_handler handler, void* user);
+
+/* Same as ini_parse(), but takes an ini_reader function pointer instead of
+ filename. Used for implementing custom or string-based I/O (see also
+ ini_parse_string). */
+int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
+ void* user);
+
+/* Same as ini_parse(), but takes a zero-terminated string with the INI data
+instead of a file. Useful for parsing INI data from a network socket or
+already in memory. */
+int ini_parse_string(const char* string, ini_handler handler, void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+ configparser. If allowed, ini_parse() will call the handler with the same
+ name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+ the file. See https://github.com/benhoyt/inih/issues/21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Chars that begin a start-of-line comment. Per Python configparser, allow
+ both ; and # comments at the start of a line by default. */
+#ifndef INI_START_COMMENT_PREFIXES
+#define INI_START_COMMENT_PREFIXES ";#"
+#endif
+
+/* Nonzero to allow inline comments (with valid inline comment characters
+ specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
+ Python 3.2+ configparser behaviour. */
+#ifndef INI_ALLOW_INLINE_COMMENTS
+#define INI_ALLOW_INLINE_COMMENTS 1
+#endif
+#ifndef INI_INLINE_COMMENT_PREFIXES
+#define INI_INLINE_COMMENT_PREFIXES ";"
+#endif
+
+/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Maximum line length for any line in INI file (stack or heap). Note that
+ this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 200
+#endif
+
+/* Nonzero to allow heap line buffer to grow via realloc(), zero for a
+ fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is
+ zero. */
+#ifndef INI_ALLOW_REALLOC
+#define INI_ALLOW_REALLOC 0
+#endif
+
+/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK
+ is zero. */
+#ifndef INI_INITIAL_ALLOC
+#define INI_INITIAL_ALLOC 200
+#endif
+
+/* Stop parsing on first error (default is to keep parsing). */
+#ifndef INI_STOP_ON_FIRST_ERROR
+#define INI_STOP_ON_FIRST_ERROR 0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
diff --git a/lib/name_val_array.h b/lib/name_val_array.h
new file mode 100644
index 0000000000..e4b3754df1
--- /dev/null
+++ b/lib/name_val_array.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011-2019 Free Software Foundation, Inc.
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef GNUTLS_NAME_VAL_ARRAY_H
+#define GNUTLS_NAME_VAL_ARRAY_H
+
+#include "gnutls_int.h"
+#include "errors.h"
+
+/* Functionality to allow an array of strings. Strings
+ * are allowed to be added to the list and matched against it.
+ */
+
+typedef struct name_val_array_st {
+ char *name;
+ unsigned name_size;
+ char *val;
+ struct name_val_array_st *next;
+} *name_val_array_t;
+
+inline static void _name_val_array_init(name_val_array_t * head)
+{
+ *head = NULL;
+}
+
+inline static void _name_val_array_clear(name_val_array_t * head)
+{
+ name_val_array_t prev, array = *head;
+
+ while (array != NULL) {
+ prev = array;
+ array = prev->next;
+ gnutls_free(prev);
+ }
+ *head = NULL;
+}
+
+inline static const char *_name_val_array_value(name_val_array_t head,
+ const char *name, unsigned name_size)
+{
+ name_val_array_t array = head;
+
+ while (array != NULL) {
+ if (array->name_size == name_size &&
+ memcmp(array->name, name, name_size) == 0) {
+ return array->val;
+ }
+ array = array->next;
+ }
+
+ return NULL;
+}
+
+inline static void append(name_val_array_t array, const char *name,
+ unsigned name_len, const char *val,
+ unsigned val_len)
+{
+ array->name = ((char *) array) + sizeof(struct name_val_array_st);
+ memcpy(array->name, name, name_len);
+ array->name[name_len] = 0;
+ array->name_size = name_len;
+
+ array->val = ((char *) array) + name_len + 1 + sizeof(struct name_val_array_st);
+ if (val)
+ memcpy(array->val, val, val_len);
+ array->val[val_len] = 0;
+
+ array->next = NULL;
+}
+
+inline static int _name_val_array_append(name_val_array_t * head,
+ const char *name,
+ const char *val)
+{
+ name_val_array_t prev, array;
+ unsigned name_len = strlen(name);
+ unsigned val_len = (val==NULL)?0:strlen(val);
+
+ if (*head == NULL) {
+ *head =
+ gnutls_malloc(val_len + name_len + 2 +
+ sizeof(struct name_val_array_st));
+ if (*head == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ array = *head;
+ append(array, name, name_len, val, val_len);
+ } else {
+ array = *head;
+ prev = array;
+
+ while (array != NULL) {
+ prev = array;
+ array = prev->next;
+ }
+ prev->next =
+ gnutls_malloc(name_len + val_len + 2 +
+ sizeof(struct name_val_array_st));
+ array = prev->next;
+
+ if (array == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ append(array, name, name_len, val, val_len);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/lib/priority.c b/lib/priority.c
index 746eae05a4..7a9a6cbfea 100644
--- a/lib/priority.c
+++ b/lib/priority.c
@@ -38,6 +38,8 @@
#include <gnutls/gnutls.h>
#include "profiles.h"
#include "c-strcase.h"
+#include "inih/ini.h"
+#include "name_val_array.h"
#define MAX_ELEMENTS 64
@@ -944,91 +946,65 @@ static void dummy_func(gnutls_priority_t c)
#include <priority_options.h>
-static char *check_str(char *line, size_t line_size, const char *needle, size_t needle_size)
-{
- char *p;
- unsigned n;
-
- while (c_isspace(*line)) {
- line++;
- line_size--;
- }
-
- if (line[0] == '#' || needle_size >= line_size)
- return NULL;
+static name_val_array_t system_wide_priority_strings = NULL;
+static unsigned system_wide_priority_strings_init = 0;
- if (memcmp(line, needle, needle_size) == 0) {
- p = &line[needle_size];
- while (c_isspace(*p)) {
- p++;
- }
- if (*p != '=') {
- return NULL;
- } else
- p++;
+static const char *system_priority_file = SYSTEM_PRIORITY_FILE;
+static time_t system_priority_last_mod = 0;
- while (c_isspace(*p)) {
- p++;
+static int cfg_ini_handler(void *_ctx, const char *section, const char *name, const char *value)
+{
+ /* Parse sections */
+ if (section == NULL || section[0] == 0) {
+ if (system_wide_priority_strings_init == 0) {
+ _name_val_array_init(&system_wide_priority_strings);
+ system_wide_priority_strings_init = 1;
}
- n = strlen(p);
+ _gnutls_debug_log("cfg: adding priority: %s -> %s\n", name, value);
- if (n > 1 && p[n-1] == '\n') {
- n--;
- p[n] = 0;
- }
-
- if (n > 1 && p[n-1] == '\r') {
- n--;
- p[n] = 0;
- }
- return p;
+ return _name_val_array_append(&system_wide_priority_strings, name, value);
+ } else {
+ _gnutls_debug_log("cfg: skipping unknown section %s\n",
+ section);
}
- return NULL;
+ return 0;
}
-static const char *system_priority_file = SYSTEM_PRIORITY_FILE;
-static char *system_priority_buf = NULL;
-static size_t system_priority_buf_size = 0;
-static time_t system_priority_last_mod = 0;
-
-
static void _gnutls_update_system_priorities(void)
{
-#ifdef HAVE_FMEMOPEN
- gnutls_datum_t data;
int ret;
struct stat sb;
if (stat(system_priority_file, &sb) < 0) {
- _gnutls_debug_log("unable to access: %s: %d\n",
+ _gnutls_debug_log("cfg: unable to access: %s: %d\n",
system_priority_file, errno);
return;
}
- if (system_priority_buf != NULL &&
+ if (system_wide_priority_strings_init != 0 &&
sb.st_mtime == system_priority_last_mod) {
- _gnutls_debug_log("system priority %s has not changed\n",
+ _gnutls_debug_log("cfg: system priority %s has not changed\n",
system_priority_file);
return;
}
- ret = gnutls_load_file(system_priority_file, &data);
+ if (system_wide_priority_strings_init != 0)
+ _name_val_array_clear(&system_wide_priority_strings);
+
+ ret = ini_parse(system_priority_file, cfg_ini_handler, NULL);
if (ret < 0) {
- _gnutls_debug_log("unable to load: %s: %d\n",
+ _gnutls_debug_log("cfg: unable to parse: %s: %d\n",
system_priority_file, ret);
return;
}
- _gnutls_debug_log("cached system priority %s mtime %lld\n",
+ _gnutls_debug_log("cfg: loaded system priority %s mtime %lld\n",
system_priority_file,
(unsigned long long)sb.st_mtime);
- gnutls_free(system_priority_buf);
- system_priority_buf = (char*)data.data;
- system_priority_buf_size = data.size;
+
system_priority_last_mod = sb.st_mtime;
-#endif
}
void _gnutls_load_system_priorities(void)
@@ -1044,11 +1020,7 @@ void _gnutls_load_system_priorities(void)
void _gnutls_unload_system_priorities(void)
{
-#ifdef HAVE_FMEMOPEN
- gnutls_free(system_priority_buf);
-#endif
- system_priority_buf = NULL;
- system_priority_buf_size = 0;
+ _name_val_array_clear(&system_wide_priority_strings);
system_priority_last_mod = 0;
}
@@ -1063,14 +1035,12 @@ void _gnutls_unload_system_priorities(void)
*/
char *_gnutls_resolve_priorities(const char* priorities)
{
-char *p = (char*)priorities;
-char *additional = NULL;
-char *ret = NULL;
-char *ss, *ss_next, *line = NULL;
-unsigned ss_len, ss_next_len;
-int l;
-FILE* fp = NULL;
-size_t n, n2 = 0, line_size;
+ const char *p = priorities;
+ char *additional = NULL;
+ char *ret = NULL;
+ const char *ss, *ss_next;
+ unsigned ss_len, ss_next_len;
+ size_t n, n2 = 0;
while (c_isspace(*p))
p++;
@@ -1102,35 +1072,17 @@ size_t n, n2 = 0, line_size;
ss_next_len = 0;
}
-#ifdef HAVE_FMEMOPEN
/* Always try to refresh the cached data, to
* allow it to be updated without restarting
* all applications
*/
_gnutls_update_system_priorities();
- fp = fmemopen(system_priority_buf, system_priority_buf_size, "r");
-#else
- fp = fopen(system_priority_file, "r");
-#endif
- if (fp == NULL) {/* fail */
- ret = NULL;
- goto finish;
- }
- do {
- l = getline(&line, &line_size, fp);
- if (l > 0) {
- p = check_str(line, line_size, ss, ss_len);
- if (p != NULL)
- break;
- }
- } while (l>0);
+ p = _name_val_array_value(system_wide_priority_strings, ss, ss_len);
_gnutls_debug_log("resolved '%.*s' to '%s', next '%.*s'\n",
ss_len, ss, S(p), ss_next_len, S(ss_next));
ss = ss_next;
- fclose(fp);
- fp = NULL;
} while (ss && p == NULL);
if (p == NULL) {
@@ -1164,9 +1116,6 @@ finish:
if (ret != NULL) {
_gnutls_debug_log("selected priority string: %s\n", ret);
}
- free(line);
- if (fp != NULL)
- fclose(fp);
return ret;
}