[network-manager-openvpn: 3/4] properties/import: fix parsing for openvpn's special handling of comments and quoting



commit 7cc6312779556cc53cb546fcce6f4d2e30ad20e3
Author: Thomas Haller <thaller redhat com>
Date:   Mon Jun 27 16:14:18 2016 +0200

    properties/import: fix parsing for openvpn's special handling of comments and quoting
    
    openvpn doesn't treat quotes and comments like shell does. Instead:
    
      - comments start with ';' or '#'. They can not only start at the first
        characther of the line. Instead comments can start at every beginning
        of a word (but not inside a word). E.g. "a#comment" is not taken as "a"
        followed by a comment, instead it is taken literally.
    
      - quotation is quite peculiar. On the first character of a word,
        openvpn decides whether it has a quoted word at hand or not.
        In case of a quoted word, the word ends with the closing quote.
        That means, "'a'b" becomes "a","b", not "ab".
        In case of an unquoted word, quotes inside the word are ignored
        until the word ends with spaces. That means, "a'b'" is taken
        literally as "a'b'".
    
    *Sigh*
    
    See: 
https://github.com/OpenVPN/openvpn/blob/2011b8324feca30df753a4a0a116d37c04742520/src/openvpn/options.c#L3639

 properties/import-export.c            |   87 +++++++++++++++++++--------------
 properties/tests/conf/password.conf   |    2 +-
 properties/tests/test-import-export.c |    6 +-
 3 files changed, 55 insertions(+), 40 deletions(-)
---
diff --git a/properties/import-export.c b/properties/import-export.c
index a558867..62d5f74 100644
--- a/properties/import-export.c
+++ b/properties/import-export.c
@@ -459,7 +459,7 @@ args_parse_line (const char *line,
 
        index = g_array_new (FALSE, FALSE, sizeof (gsize));
 
-       do {
+       for (;;) {
                char quote, ch0;
                gssize word_start = line - line_start;
                gsize index_i;
@@ -467,51 +467,66 @@ args_parse_line (const char *line,
                index_i = str_buf - str_buf_orig;
                g_array_append_val (index, index_i);
 
-               do {
-                       switch ((ch0 = _ch_step_1 (&line, &line_len))) {
-                       case '"':
-                       case '\'':
-                               quote = ch0;
-
-                               while (line_len > 0 && line[0] != quote) {
-                                       if (quote == '"' && line[0] == '\\') {
-                                               _ch_step_1 (&line, &line_len);
-                                               if (line_len <= 0)
-                                                       break;
-                                       }
-                                       _strbuf_append_c (&str_buf, &str_buf_len, _ch_step_1 (&line, 
&line_len));
-                               }
+               switch ((ch0 = _ch_step_1 (&line, &line_len))) {
+               case '"':
+               case '\'':
+                       quote = ch0;
 
-                               if (line_len <= 0) {
-                                       *out_error = g_strdup_printf (_("unterminated %s at position %lld"),
-                                                                     quote == '"' ? _("double quote") : 
_("single quote"),
-                                                                     (long long) word_start);
-                                       return FALSE;
+                       while (line_len > 0 && line[0] != quote) {
+                               if (quote == '"' && line[0] == '\\') {
+                                       _ch_step_1 (&line, &line_len);
+                                       if (line_len <= 0)
+                                               break;
                                }
+                               _strbuf_append_c (&str_buf, &str_buf_len, _ch_step_1 (&line, &line_len));
+                       }
+
+                       if (line_len <= 0) {
+                               *out_error = g_strdup_printf (_("unterminated %s at position %lld"),
+                                                             quote == '"' ? _("double quote") : _("single 
quote"),
+                                                             (long long) word_start);
+                               return FALSE;
+                       }
 
-                               _ch_step_1 (&line, &line_len);
-                               break;
-                       case '\\':
-                               if (line_len <= 0) {
-                                       *out_error = g_strdup_printf (_("trailing escaping backslash at 
position %lld"),
-                                                                     (long long) word_start);
-                                       return FALSE;
+                       /* openvpn terminates parsing of quoted paramaters after the closing quote.
+                        * E.g. "'a'b" gives "a", "b". */
+                       _ch_step_1 (&line, &line_len);
+                       break;
+               default:
+                       /* once openvpn encounters a non-quoted word, it doesn't consider quoting
+                        * inside the word.
+                        * E.g. "a'b'" gives "a'b'". */
+                       for (;;) {
+                               if (ch0 == '\\') {
+                                       if (line_len <= 0) {
+                                               *out_error = g_strdup_printf (_("trailing escaping backslash 
at position %lld"),
+                                                                             (long long) word_start);
+                                               return FALSE;
+                                       }
+                                       ch0 = _ch_step_1 (&line, &line_len);
                                }
-                               _strbuf_append_c (&str_buf, &str_buf_len, _ch_step_1 (&line, &line_len));
-                               break;
-                       default:
-                               if (g_ascii_isspace (ch0))
-                                       goto word_completed;
                                _strbuf_append_c (&str_buf, &str_buf_len, ch0);
-                               break;
+                               if (line_len <= 0)
+                                       break;
+                               ch0 = _ch_step_1 (&line, &line_len);
+                               if (g_ascii_isspace (ch0))
+                                       break;
                        }
-               } while (line_len > 0);
-word_completed:
+                       break;
+               }
 
                /* the current word is complete.*/
                _strbuf_append_c (&str_buf, &str_buf_len, '\0');
                _ch_skip_over_leading_whitespace (&line, &line_len);
-       } while (line_len > 0);
+
+               if (line_len <= 0)
+                       break;
+
+               if (NM_IN_SET (line[0], ';', '#')) {
+                       /* comments are allowed to start at the beginning of the next word. */
+                       break;
+               }
+       }
 
        str_buf_len = str_buf - str_buf_orig;
 
diff --git a/properties/tests/conf/password.conf b/properties/tests/conf/password.conf
index c924a4f..cfe5835 100644
--- a/properties/tests/conf/password.conf
+++ b/properties/tests/conf/password.conf
@@ -14,7 +14,7 @@ group openvpn
 
 
 ca cacert.pem
-cipher AES-256-CBC
+cipher AES-256-CBC #xcomment
 reneg-sec 0
 
 auth-user-pass
diff --git a/properties/tests/test-import-export.c b/properties/tests/test-import-export.c
index 936662c..a78d2d2 100644
--- a/properties/tests/test-import-export.c
+++ b/properties/tests/test-import-export.c
@@ -1287,9 +1287,9 @@ test_args_parse_line (void)
        do_test_args_parse_line (" b \\ \\a ", TRUE, "b", " a");
        do_test_args_parse_line ("\\ b \\ \\a ", TRUE, " b", " a");
        do_test_args_parse_line ("'\\ b \\ \\a '", TRUE, "\\ b \\ \\a ");
-       do_test_args_parse_line ("\"\\ b \\ \\a \"a'b'", TRUE, " b  a ab");
-       do_test_args_parse_line ("\"\\ b \\ \\a \"a\\ 'b'", TRUE, " b  a a b");
-       do_test_args_parse_line ("\"\\ b \\ \\a \"a\\ 'b'   sd\\ \t", TRUE, " b  a a b", "sd ");
+       do_test_args_parse_line ("\"\\ b \\ \\a \"a'b'", TRUE, " b  a ", "a'b'");
+       do_test_args_parse_line ("\"\\ b \\ \\a \"a\\ 'b'", TRUE, " b  a ", "a 'b'");
+       do_test_args_parse_line ("\"\\ b \\ \\a \"a\\ 'b'   sd\\ \t", TRUE, " b  a ", "a 'b'", "sd ");
 
        do_test_args_parse_line ("\"adfdaf  adf  ", FALSE);
        do_test_args_parse_line ("\"adfdaf  adf  \\\"", FALSE);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]