diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2019-04-03 11:59:37 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2019-06-20 15:49:36 +0200 |
commit | 90142f2d70018d862cba02067159cad8c7db4239 (patch) | |
tree | 9ddc0fb58a01cd852dc024774e3255a7e76bef53 | |
parent | 4292c1ae6db9edd4b178c10bc5045534ea38e4a5 (diff) | |
download | gnutls-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.mk | 2 | ||||
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | devel/cppcheck.suppressions | 2 | ||||
-rw-r--r-- | lib/Makefile.am | 6 | ||||
-rw-r--r-- | lib/inih/LICENSE.txt | 27 | ||||
-rw-r--r-- | lib/inih/ini.c | 269 | ||||
-rw-r--r-- | lib/inih/ini.h | 131 | ||||
-rw-r--r-- | lib/name_val_array.h | 130 | ||||
-rw-r--r-- | lib/priority.c | 125 |
9 files changed, 607 insertions, 92 deletions
@@ -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; } |