summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-03-11 16:36:50 +0100
committerStef Walter <stefw@gnome.org>2013-03-15 18:03:09 +0100
commit06bf3da80eb780621e0f1eb0ab8d4716ed7b3478 (patch)
tree5bbdb615c41bab82dc4aac233c078172156d3e0a
parent29af2c1eeca2fb0257e1172753b129d638472f0f (diff)
downloadp11-kit-06bf3da80eb780621e0f1eb0ab8d4716ed7b3478.tar.gz
lexer: Make a lexer for our config file format
This lexer will be used in our PKCS#11 persistence format as well. https://bugs.freedesktop.org/show_bug.cgi?id=62156
-rw-r--r--common/Makefile.am1
-rw-r--r--common/lexer.c238
-rw-r--r--common/lexer.h84
-rw-r--r--common/tests/Makefile.am1
-rw-r--r--common/tests/test-lexer.c281
-rw-r--r--p11-kit/conf.c131
6 files changed, 644 insertions, 92 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index d914fa8..3522acb 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -25,6 +25,7 @@ libp11_library_la_SOURCES = \
constants.c constants.h \
debug.c debug.h \
dict.c dict.h \
+ lexer.c lexer.h \
library.c library.h \
pkcs11.h pkcs11x.h \
$(NULL)
diff --git a/common/lexer.c b/common/lexer.c
new file mode 100644
index 0000000..9898e2c
--- /dev/null
+++ b/common/lexer.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2005 Stefan Walter
+ * Copyright (c) 2011 Collabora Ltd.
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * 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.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ *
+ *
+ * CONTRIBUTORS
+ * Stef Walter <stefw@redhat.com>
+ */
+
+#include "config.h"
+
+#define P11_DEBUG_FLAG P11_DEBUG_CONF
+#include "debug.h"
+#include "lexer.h"
+#include "library.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+p11_lexer_init (p11_lexer *lexer,
+ const char *filename,
+ const char *data,
+ size_t length)
+{
+ return_if_fail (lexer != NULL);
+
+ memset (lexer, 0, sizeof (p11_lexer));
+ lexer->at = data;
+ lexer->remaining = length;
+
+ return_if_fail (filename != NULL);
+ lexer->filename = strdup (filename);
+ return_if_fail (lexer->filename != NULL);
+}
+
+static void
+clear_state (p11_lexer *lexer)
+{
+ switch (lexer->tok_type) {
+ case TOK_FIELD:
+ free (lexer->tok.field.name);
+ free (lexer->tok.field.value);
+ break;
+ case TOK_SECTION:
+ free (lexer->tok.section.name);
+ break;
+ case TOK_PEM:
+ case TOK_EOF:
+ break;
+ }
+
+ memset (&lexer->tok, 0, sizeof (lexer->tok));
+ lexer->tok_type = TOK_EOF;
+ lexer->complained = false;
+}
+
+bool
+p11_lexer_next (p11_lexer *lexer,
+ bool *failed)
+{
+ const char *colon;
+ const char *value;
+ const char *line;
+ const char *end;
+ const char *pos;
+ char *part;
+
+ return_val_if_fail (lexer != NULL, false);
+
+ clear_state (lexer);
+ *failed = false;
+
+ /* Go through lines and process them */
+ while (lexer->remaining != 0) {
+ assert (lexer->remaining > 0);
+
+ /* Is this line the start of a PEM block? */
+ if (strncmp (lexer->at, "-----BEGIN ", 11) == 0) {
+ pos = strnstr (lexer->at, "\n-----END ", lexer->remaining);
+ if (pos != NULL) {
+ end = memchr (pos + 1, '\n', lexer->remaining - (pos - lexer->at) - 1);
+ if (end)
+ end += 1;
+ else
+ end = lexer->at + lexer->remaining;
+ lexer->tok_type = TOK_PEM;
+ lexer->tok.pem.begin = lexer->at;
+ lexer->tok.pem.length = end - lexer->at;
+ assert (end - lexer->at <= lexer->remaining);
+ lexer->remaining -= (end - lexer->at);
+ lexer->at = end;
+ return true;
+ }
+
+ p11_lexer_msg (lexer, "invalid pem block: no ending line");
+ if (failed)
+ *failed = true;
+ return false;
+ }
+
+ line = lexer->at;
+ end = memchr (lexer->at, '\n', lexer->remaining);
+ if (end == NULL) {
+ end = lexer->at + lexer->remaining;
+ lexer->remaining = 0;
+ lexer->at = end;
+ } else {
+ assert ((end - lexer->at) + 1 <= lexer->remaining);
+ lexer->remaining -= (end - lexer->at) + 1;
+ lexer->at = end + 1;
+ }
+
+ /* Strip whitespace from line */
+ while (line != end && isspace (line[0]))
+ ++line;
+ while (line != end && isspace (*(end - 1)))
+ --end;
+
+ /* Empty lines / comments at start */
+ if (line == end || line[0] == '#')
+ continue;
+
+ /* Is the the a section ? */
+ if (line[0] == '[') {
+ if (*(end - 1) != ']') {
+ part = strndup (line, end - line);
+ p11_lexer_msg (lexer, "invalid section header: missing braces");
+ free (part);
+ if (failed)
+ *failed = true;
+ return false;
+ }
+
+ lexer->tok_type = TOK_SECTION;
+ lexer->tok.section.name = strndup (line + 1, (end - line) - 2);
+ return_val_if_fail (lexer->tok.section.name != NULL, false);
+ return true;
+ }
+
+ /* Look for the break between name: value on the same line */
+ colon = memchr (line, ':', end - line);
+ if (!colon) {
+ part = strndup (line, end - line);
+ p11_lexer_msg (lexer, "invalid field line: no colon");
+ free (part);
+ if (failed)
+ *failed = true;
+ return false;
+ }
+
+ /* Strip whitespace from name and value */
+ value = colon + 1;
+ while (value != end && isspace (value[0]))
+ ++value;
+ while (line != colon && isspace (*(colon - 1)))
+ --colon;
+
+ lexer->tok_type = TOK_FIELD;
+ lexer->tok.field.name = strndup (line, colon - line);
+ lexer->tok.field.value = strndup (value, end - value);
+ return_val_if_fail (lexer->tok.field.name && lexer->tok.field.value, false);
+ return true;
+ }
+
+ return false;
+}
+
+void
+p11_lexer_done (p11_lexer *lexer)
+{
+ return_if_fail (lexer != NULL);
+ clear_state (lexer);
+ free (lexer->filename);
+ memset (lexer, 0, sizeof (p11_lexer));
+}
+
+void
+p11_lexer_msg (p11_lexer *lexer,
+ const char *msg)
+{
+ return_if_fail (lexer != NULL);
+
+ if (lexer->complained)
+ return;
+
+ switch (lexer->tok_type) {
+ case TOK_FIELD:
+ p11_message ("%s: %s: %s", lexer->filename,
+ lexer->tok.field.name, msg);
+ break;
+ case TOK_SECTION:
+ p11_message ("%s: [%s]: %s", lexer->filename,
+ lexer->tok.section.name, msg);
+ break;
+ case TOK_PEM:
+ p11_message ("%s: BEGIN ...: %s", lexer->filename, msg);
+ break;
+ default:
+ p11_message ("%s: %s", lexer->filename, msg);
+ break;
+ }
+
+ lexer->complained = true;
+}
diff --git a/common/lexer.h b/common/lexer.h
new file mode 100644
index 0000000..9daf296
--- /dev/null
+++ b/common/lexer.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2005 Stefan Walter
+ * Copyright (c) 2011 Collabora Ltd.
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * 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.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#ifndef P11_LEXER_H__
+#define P11_LEXER_H__
+
+#include "compat.h"
+
+enum {
+ TOK_EOF = 0,
+ TOK_SECTION = 1,
+ TOK_FIELD,
+ TOK_PEM,
+};
+
+typedef struct {
+ char *filename;
+ const char *at;
+ int remaining;
+ int complained;
+
+ int tok_type;
+ union {
+ struct {
+ char *name;
+ } section;
+ struct {
+ char *name;
+ char *value;
+ } field;
+ struct {
+ const char *begin;
+ size_t length;
+ } pem;
+ } tok;
+} p11_lexer;
+
+void p11_lexer_init (p11_lexer *lexer,
+ const char *filename,
+ const char *data,
+ size_t length);
+
+bool p11_lexer_next (p11_lexer *lexer,
+ bool *failed);
+
+void p11_lexer_done (p11_lexer *lexer);
+
+void p11_lexer_msg (p11_lexer *lexer,
+ const char *msg);
+
+#endif /* P11_LEXER_H__ */
diff --git a/common/tests/Makefile.am b/common/tests/Makefile.am
index 582c1fb..f31cebb 100644
--- a/common/tests/Makefile.am
+++ b/common/tests/Makefile.am
@@ -20,6 +20,7 @@ CHECK_PROGS = \
test-constants \
test-attrs \
test-buffer \
+ test-lexer \
$(NULL)
noinst_PROGRAMS = \
diff --git a/common/tests/test-lexer.c b/common/tests/test-lexer.c
new file mode 100644
index 0000000..02ea5c5
--- /dev/null
+++ b/common/tests/test-lexer.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * 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.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "compat.h"
+#include "debug.h"
+#include "lexer.h"
+#include "library.h"
+#include "pem.h"
+
+typedef struct {
+ int tok_type;
+ const char *name;
+ const char *value;
+} expected_tok;
+
+static void
+on_pem_get_type (const char *type,
+ const unsigned char *contents,
+ size_t length,
+ void *user_data)
+{
+ char **result = (char **)user_data;
+ *result = strdup (type);
+}
+
+static void
+check_lex_msg (CuTest *tc,
+ const char *file,
+ int line,
+ const expected_tok *expected,
+ const char *input,
+ bool failure)
+{
+ unsigned int count;
+ p11_lexer lexer;
+ char *type;
+ bool failed;
+ int i;
+
+ p11_lexer_init (&lexer, "test", input, strlen (input));
+ for (i = 0; p11_lexer_next (&lexer, &failed); i++) {
+ CuAssertIntEquals_LineMsg (tc, file, line,
+ "lexer token type does not match",
+ expected[i].tok_type, lexer.tok_type);
+ switch (lexer.tok_type) {
+ case TOK_FIELD:
+ CuAssertStrEquals_LineMsg (tc, file, line,
+ "field name doesn't match",
+ expected[i].name, lexer.tok.field.name);
+ CuAssertStrEquals_LineMsg (tc, file, line,
+ "field value doesn't match",
+ expected[i].value, lexer.tok.field.value);
+ break;
+ case TOK_SECTION:
+ CuAssertStrEquals_LineMsg (tc, file, line,
+ "section name doesn't match",
+ expected[i].name, lexer.tok.field.name);
+ break;
+ case TOK_PEM:
+ type = NULL;
+ count = p11_pem_parse (lexer.tok.pem.begin, lexer.tok.pem.length,
+ on_pem_get_type, &type);
+ CuAssertIntEquals_LineMsg (tc, file, line,
+ "wrong number of PEM blocks",
+ 1, count);
+ CuAssertStrEquals_LineMsg (tc, file, line,
+ "wrong type of PEM block",
+ expected[i].name, type);
+ free (type);
+ break;
+ case TOK_EOF:
+ CuFail_Line (tc, file, line, NULL, "eof should not be recieved");
+ break;
+ }
+ }
+
+ if (failure)
+ CuAssert_Line (tc, file, line, "lexing didn't fail", failed);
+ else
+ CuAssert_Line (tc, file, line, "lexing failed", !failed);
+ CuAssertIntEquals_LineMsg (tc, file, line,
+ "premature end of lexing",
+ TOK_EOF, expected[i].tok_type);
+
+ p11_lexer_done (&lexer);
+}
+
+#define check_lex_success(tc, expected, input) \
+ check_lex_msg (tc, __FILE__, __LINE__, expected, input, false)
+
+#define check_lex_failure(tc, expected, input) \
+ check_lex_msg (tc, __FILE__, __LINE__, expected, input, true)
+
+static void
+test_basic (CuTest *tc)
+{
+ const char *input = "[the header]\n"
+ "field: value\n"
+ "-----BEGIN BLOCK1-----\n"
+ "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n"
+ "-----END BLOCK1-----\n";
+
+ const expected_tok expected[] = {
+ { TOK_SECTION, "the header" },
+ { TOK_FIELD, "field", "value" },
+ { TOK_PEM, "BLOCK1", },
+ { TOK_EOF }
+ };
+
+ check_lex_success (tc, expected, input);
+}
+
+static void
+test_corners (CuTest *tc)
+{
+ const char *input = "\r\n" /* blankline */
+ " [the header]\r\n" /* bad line endings */
+ " field: value \r\n" /* whitespace */
+ "number: 2\n" /* extra space*/
+ "number :3\n" /* extra space*/
+ "number : 4\n" /* extra space*/
+ "\n"
+ " # A comment \n"
+ "not-a-comment: # value\n"
+ "-----BEGIN BLOCK1-----\r\n"
+ "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\r\n"
+ "-----END BLOCK1-----"; /* no new line */
+
+ const expected_tok expected[] = {
+ { TOK_SECTION, "the header" },
+ { TOK_FIELD, "field", "value" },
+ { TOK_FIELD, "number", "2" },
+ { TOK_FIELD, "number", "3" },
+ { TOK_FIELD, "number", "4" },
+ { TOK_FIELD, "not-a-comment", "# value" },
+ { TOK_PEM, "BLOCK1", },
+ { TOK_EOF }
+ };
+
+ check_lex_success (tc, expected, input);
+}
+
+static void
+test_following (CuTest *tc)
+{
+ const char *input = "-----BEGIN BLOCK1-----\n"
+ "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n"
+ "-----END BLOCK1-----\n"
+ "field: value";
+
+ const expected_tok expected[] = {
+ { TOK_PEM, "BLOCK1", },
+ { TOK_FIELD, "field", "value" },
+ { TOK_EOF }
+ };
+
+ check_lex_success (tc, expected, input);
+}
+
+static void
+test_bad_pem (CuTest *tc)
+{
+ const char *input = "field: value\n"
+ "-----BEGIN BLOCK1-----\n"
+ "aYNNXqshlVxCdo8QfKeXh3GUzd/yn4LYIVgQrx4a\n";
+
+ const expected_tok expected[] = {
+ { TOK_FIELD, "field", "value" },
+ { TOK_EOF }
+ };
+
+ p11_message_quiet ();
+
+ check_lex_failure (tc, expected, input);
+
+ p11_message_loud ();
+}
+
+static void
+test_bad_section (CuTest *tc)
+{
+ const char *input = "field: value\n"
+ "[section\n"
+ "bad]\n";
+
+ const expected_tok expected[] = {
+ { TOK_FIELD, "field", "value" },
+ { TOK_EOF }
+ };
+
+ p11_message_quiet ();
+
+ check_lex_failure (tc, expected, input);
+
+ p11_message_loud ();
+}
+
+static void
+test_bad_value (CuTest *tc)
+{
+ const char *input = "field_value\n"
+ "[section\n"
+ "bad]\n";
+
+ const expected_tok expected[] = {
+ { TOK_EOF }
+ };
+
+ p11_message_quiet ();
+
+ check_lex_failure (tc, expected, input);
+
+ p11_message_loud ();
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ putenv ("P11_KIT_STRICT=1");
+ p11_debug_init ();
+ p11_library_init ();
+
+ SUITE_ADD_TEST (suite, test_basic);
+ SUITE_ADD_TEST (suite, test_corners);
+ SUITE_ADD_TEST (suite, test_following);
+ SUITE_ADD_TEST (suite, test_bad_pem);
+ SUITE_ADD_TEST (suite, test_bad_section);
+ SUITE_ADD_TEST (suite, test_bad_value);
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+
+ return ret;
+}
diff --git a/p11-kit/conf.c b/p11-kit/conf.c
index 894566a..2cd5481 100644
--- a/p11-kit/conf.c
+++ b/p11-kit/conf.c
@@ -40,6 +40,7 @@
#include "conf.h"
#define P11_DEBUG_FLAG P11_DEBUG_CONF
#include "debug.h"
+#include "lexer.h"
#include "library.h"
#include "private.h"
@@ -65,46 +66,6 @@
#include <shlobj.h>
#endif
-static void
-strcln (char* data, char ch)
-{
- char* p;
- for (p = data; *data; data++, p++) {
- while (*data == ch)
- data++;
- *p = *data;
- }
-
- /* Renull terminate */
- *p = 0;
-}
-
-static char*
-strbtrim (const char* data)
-{
- while (*data && isspace (*data))
- ++data;
- return (char*)data;
-}
-
-static void
-stretrim (char* data)
-{
- char* t = data + strlen (data);
- while (t > data && isspace (*(t - 1))) {
- t--;
- *t = 0;
- }
-}
-
-static char*
-strtrim (char* data)
-{
- data = (char*)strbtrim (data);
- stretrim (data);
- return data;
-}
-
static int
strequal (const char *one, const char *two)
{
@@ -115,8 +76,10 @@ strequal (const char *one, const char *two)
* CONFIG PARSER
*/
-static char*
-read_config_file (const char* filename, int flags)
+static char *
+read_config_file (const char* filename,
+ int flags,
+ size_t *length)
{
char* config = NULL;
FILE* f = NULL;
@@ -132,13 +95,15 @@ read_config_file (const char* filename, int flags)
(error == ENOENT || error == ENOTDIR)) {
p11_debug ("config file does not exist");
config = strdup ("\n");
+ *length = 0;
return_val_if_fail (config != NULL, NULL);
return config;
} else if ((flags & CONF_IGNORE_ACCESS_DENIED) &&
(error == EPERM || error == EACCES)) {
p11_debug ("config file is inaccessible");
- config = strdup ("\n");
+ config = strdup ("");
+ *length = 0;
return_val_if_fail (config != NULL, NULL);
return config;
}
@@ -177,12 +142,7 @@ read_config_file (const char* filename, int flags)
fclose (f);
/* Null terminate the data */
- config[len] = '\n';
- config[len + 1] = 0;
-
- /* Remove nasty dos line endings */
- strcln (config, '\r');
-
+ *length = len;
return config;
}
@@ -213,71 +173,58 @@ _p11_conf_merge_defaults (p11_dict *map,
p11_dict *
_p11_conf_parse_file (const char* filename, int flags)
{
- char *name;
- char *value;
p11_dict *map = NULL;
char *data;
- char *next;
- char *end;
- int error = 0;
+ p11_lexer lexer;
+ bool failed = false;
+ size_t length;
assert (filename);
p11_debug ("reading config file: %s", filename);
- /* Adds an extra newline to end of file */
- data = read_config_file (filename, flags);
+ data = read_config_file (filename, flags, &length);
if (!data)
return NULL;
map = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, free);
return_val_if_fail (map != NULL, NULL);
- next = data;
-
- /* Go through lines and process them */
- while ((end = strchr (next, '\n')) != NULL) {
- *end = 0;
- name = strbtrim (next);
- next = end + 1;
-
- /* Empty lines / comments at start */
- if (!*name || *name == '#')
- continue;
-
- /* Look for the break between name: value on the same line */
- value = name + strcspn (name, ":");
- if (!*value) {
- p11_message ("%s: invalid config line: %s", filename, name);
- error = EINVAL;
+ p11_lexer_init (&lexer, filename, data, length);
+ while (p11_lexer_next (&lexer, &failed)) {
+ switch (lexer.tok_type) {
+ case TOK_FIELD:
+ p11_debug ("config value: %s: %s", lexer.tok.field.name,
+ lexer.tok.field.value);
+ if (!p11_dict_set (map, lexer.tok.field.name, lexer.tok.field.value))
+ return_val_if_reached (NULL);
+ lexer.tok.field.name = NULL;
+ lexer.tok.field.value = NULL;
+ break;
+ case TOK_PEM:
+ p11_message ("%s: unexpected pem block", filename);
+ failed = true;
+ break;
+ case TOK_SECTION:
+ p11_message ("%s: unexpected section header", filename);
+ failed = true;
+ break;
+ case TOK_EOF:
+ assert_not_reached ();
break;
}
- /* Null terminate and split value part */
- *value = 0;
- value++;
-
- name = strtrim (name);
- value = strtrim (value);
-
- name = strdup (name);
- return_val_if_fail (name != NULL, NULL);
-
- value = strdup (value);
- return_val_if_fail (value != NULL, NULL);
-
- p11_debug ("config value: %s: %s", name, value);
-
- if (!p11_dict_set (map, name, value))
- return_val_if_reached (NULL);
+ if (failed)
+ break;
}
+ p11_lexer_done (&lexer);
free (data);
- if (error != 0) {
+ if (failed) {
p11_dict_free (map);
map = NULL;
- errno = error;
+ errno = EINVAL;
}
return map;