Add .includedir pragma
authorRich Salz <rsalz@akamai.com>
Fri, 30 Apr 2021 16:18:00 +0000 (12:18 -0400)
committerTomas Mraz <tomas@openssl.org>
Wed, 5 May 2021 11:11:35 +0000 (13:11 +0200)
Also add a negative test, and fix typo's.

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15090)

CHANGES.md
crypto/conf/conf_api.c
crypto/conf/conf_def.c
doc/man5/config.pod
include/openssl/conf.h.in
test/recipes/90-test_includes.t
test/recipes/90-test_includes_data/incdir.cnf [new file with mode: 0644]

index 1d2bfd5d634ae74ae68fb6feaa95b9a7fa3ffe27..7b6c7c5ffb065d66b6f3e6b02be88fd13f50e5da 100644 (file)
@@ -23,8 +23,8 @@ OpenSSL 3.0
 
 ### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
 
- * Add ".pragma abspath:true" to prevent relative file inclusion in
-   config files.
+ * Add "abspath" and "includedir" pragma's to config files, to prevent,
+   or modify relative pathname inclusion.
 
    * Rich Salz *
 
index c2c461d83264acc44db679ccfaeaed7a898af052..41a09c42bc994469dc81011f2b8a0d9401984b6b 100644 (file)
@@ -146,6 +146,7 @@ void _CONF_free_data(CONF *conf)
      * with
      */
 
+    OPENSSL_free(conf->includedir);
     lh_CONF_VALUE_doall(conf->data, value_free_stack_doall);
     lh_CONF_VALUE_free(conf->data);
 }
index 9561e2338a5a451f1c0939f424c8383cc36b2bd3..ea6b5bf2445fa2384681c7567ab6f6240569fbf6 100644 (file)
@@ -192,11 +192,11 @@ static int def_load(CONF *conf, const char *name, long *line)
 /* Parse a boolean value and fill in *flag. Return 0 on error. */
 static int parsebool(const char *pval, int *flag)
 {
-    if (strcmp(pval, "on") == 0
-            || strcmp(pval, "true") == 0) {
+    if (strcasecmp(pval, "on") == 0
+            || strcasecmp(pval, "true") == 0) {
         *flag = 1;
-    } else if (strcmp(pval, "off") == 0
-            || strcmp(pval, "false") == 0) {
+    } else if (strcasecmp(pval, "off") == 0
+            || strcasecmp(pval, "false") == 0) {
         *flag = 0;
     } else {
         ERR_raise(ERR_LIB_CONF, CONF_R_INVALID_PRAGMA);
@@ -414,6 +414,8 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                  * Known pragmas:
                  *
                  * dollarid     takes "on", "true or "off", "false"
+                 * abspath      takes "on", "true or "off", "false"
+                 * includedir   directory prefix
                  */
                 if (strcmp(p, "dollarid") == 0) {
                     if (!parsebool(pval, &conf->flag_dollarid))
@@ -421,7 +423,13 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                 } else if (strcmp(p, "abspath") == 0) {
                     if (!parsebool(pval, &conf->flag_abspath))
                         goto err;
+                } else if (strcmp(p, "includedir") == 0) {
+                    if ((conf->includedir = OPENSSL_strdup(pval)) == NULL) {
+                        ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE);
+                        goto err;
+                    }
                 }
+
                 /*
                  * We *ignore* any unknown pragma.
                  */
@@ -433,6 +441,9 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                 const char *include_dir = ossl_safe_getenv("OPENSSL_CONF_INCLUDE");
                 char *include_path = NULL;
 
+                if (include_dir == NULL)
+                    include_dir = conf->includedir;
+
                 if (*p == '=') {
                     p++;
                     p = eat_ws(conf, p);
@@ -441,11 +452,6 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                 if (!str_copy(conf, psection, &include, p))
                     goto err;
 
-                if (conf->flag_abspath && !ossl_is_absolute_path(include)) {
-                    ERR_raise(ERR_LIB_CONF, CONF_R_RELATIVE_PATH);
-                    goto err;
-                }
-
                 if (include_dir != NULL && !ossl_is_absolute_path(include)) {
                     size_t newlen = strlen(include_dir) + strlen(include) + 2;
 
@@ -465,6 +471,12 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                     include_path = include;
                 }
 
+                if (conf->flag_abspath
+                        && !ossl_is_absolute_path(include_path)) {
+                    ERR_raise(ERR_LIB_CONF, CONF_R_RELATIVE_PATH);
+                    goto err;
+                }
+
                 /* get the BIO of the included file */
 #ifndef OPENSSL_NO_POSIX_IO
                 next = process_include(include_path, &dirctx, &dirpath);
@@ -544,6 +556,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
      */
     sk_BIO_free(biosk);
     return 1;
+
  err:
     BUF_MEM_free(buff);
     OPENSSL_free(section);
index 6b800b96e121c46e15aa1305e8ae8bf721d53ae7..ad7d7e1e01e10e178b474adb7b6ccd6b029f1755 100644 (file)
@@ -48,7 +48,7 @@ while scanning a directory, and that file has an B<.include> directive
 that specifies a directory, that is also ignored.
 
 As a general rule, the B<pathname> should be an absolute path; this can
-be enforced with the B<relpath> pragma, described below.
+be enforced with the B<abspath> and B<includedir> pragmas, described below.
 The environment variable B<OPENSSL_CONF_INCLUDE>, if it exists,
 is prepended to all relative pathnames.
 If the pathname is still relative, it is interpreted based on the
@@ -57,7 +57,7 @@ current working directory.
 To require all file inclusions to name absolute paths, use the following
 directive:
 
- .progma [=] abspath:value
+ .pragma [=] abspath:value
 
 The default behavior, where the B<value> is B<false> or B<off>, is to allow
 relative paths. To require all B<.include> pathnames to be absolute paths,
@@ -76,6 +76,13 @@ C<foo> followed by the expansion of the variable C<bar>. If B<value> is
 B<true> or B<on>, then C<foo$bar> is a single seven-character name nad
 variable expansions must be specified using braces or parentheses.
 
+ .pragma [=] includedir:value
+
+If a relative pathname is specified in the B<.include> directive, and
+the B<OPENSSL_CONF_INCLUDE> environment variable doesn't exist, then
+the value of the B<includedir> pragma, if it exists, is prepended to the
+pathname.
+
 =head2 Settings
 
 A configuration file is divided into a number of I<sections>.  A section
index b82a9156261c74aba4f5aba5785d284527061843..ee7cbb00e434c6c1cee772426df8e3dc5b4c4289 100644 (file)
@@ -119,7 +119,9 @@ struct conf_st {
     CONF_METHOD *meth;
     void *meth_data;
     LHASH_OF(CONF_VALUE) *data;
-    unsigned int flag_dollarid:1;
+    int flag_dollarid;
+    int flag_abspath;
+    char *includedir;
     OSSL_LIB_CTX *libctx;
 };
 
index add3813a64634cf4bd8aa7b1f1d9efecbf155bf5..13c5c842024c008fd7ea7f1387b7138331912712 100644 (file)
@@ -13,7 +13,7 @@ plan skip_all => "test_includes doesn't work without posix-io"
 delete $ENV{OPENSSL_CONF_INCLUDE};
 
 plan tests =>                   # The number of tests being performed
-    5
+    6
     + ($^O eq "VMS" ? 2 : 0);
 
 ok(run(test(["conf_include_test", data_file("includes.cnf")])), "test directory includes");
@@ -27,3 +27,4 @@ if ($^O eq "VMS") {
        "test file includes, VMS syntax");
 }
 ok(run(test(["conf_include_test", "-f", data_file("includes-broken.cnf")])), "test broken includes");
+ok(run(test(["conf_include_test",  "-f", data_file("incdir.cnf")])), "test includedir");
diff --git a/test/recipes/90-test_includes_data/incdir.cnf b/test/recipes/90-test_includes_data/incdir.cnf
new file mode 100644 (file)
index 0000000..0d882ed
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Set includedir and expect to fail
+#
+.pragma includedir:/
+
+.include includes.cnf