Blame SOURCES/0005-logrotate-3.18.0-stricter-config-parser.patch

eabc67
From 6db706b51af0a6f6ce28bceaefb4157347d2fa18 Mon Sep 17 00:00:00 2001
eabc67
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
eabc67
Date: Tue, 20 Apr 2021 17:41:10 +0200
eabc67
Subject: [PATCH 1/6] Log if keyword is not properly separated
eabc67
eabc67
The man page states
eabc67
  Values are separated from directives by whitespace and/or an
eabc67
  optional =.
eabc67
eabc67
But logrotate does accept no separator, like
eabc67
  rotate7
eabc67
eabc67
Log those occurrences with a normal severity, as this usage is not
eabc67
intended.
eabc67
eabc67
Upstream-commit: 2b588b5ec2e5c27bee857c4abeddafa6a9602ebc
eabc67
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
eabc67
---
eabc67
 config.c | 5 +++++
eabc67
 1 file changed, 5 insertions(+)
eabc67
eabc67
diff --git a/config.c b/config.c
eabc67
index 1bca9e4..8049211 100644
eabc67
--- a/config.c
eabc67
+++ b/config.c
eabc67
@@ -1088,6 +1088,11 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                     key = isolateWord(&start, &buf, length);
eabc67
                     if (key == NULL)
eabc67
                         continue;
eabc67
+                    if (!isspace((unsigned char)*start)) {
eabc67
+                        message(MESS_NORMAL, "%s:%d keyword '%s' not properly"
eabc67
+                                " separated, found %#x\n",
eabc67
+                                configFile, lineNum, key, *start);
eabc67
+                    }
eabc67
                     if (!strcmp(key, "compress")) {
eabc67
                         newlog->flags |= LOG_FLAG_COMPRESS;
eabc67
                     } else if (!strcmp(key, "nocompress")) {
eabc67
-- 
eabc67
2.38.1
eabc67
eabc67
eabc67
From 2a22bf99b41e737fcd8c986be5c4fb761ab101c7 Mon Sep 17 00:00:00 2001
eabc67
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
eabc67
Date: Tue, 20 Apr 2021 17:41:12 +0200
eabc67
Subject: [PATCH 2/6] Log error on keyword parse failure
eabc67
eabc67
isolateWord() only fails on OOM and EOF.
eabc67
eabc67
Upstream-commit: 326179a901b0a8d10e902cae0abab0c68d7abc98
eabc67
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
eabc67
---
eabc67
 config.c | 5 ++++-
eabc67
 1 file changed, 4 insertions(+), 1 deletion(-)
eabc67
eabc67
diff --git a/config.c b/config.c
eabc67
index 8049211..fd6e026 100644
eabc67
--- a/config.c
eabc67
+++ b/config.c
eabc67
@@ -1086,8 +1086,11 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                 if (isalpha((unsigned char)*start)) {
eabc67
                     free(key);
eabc67
                     key = isolateWord(&start, &buf, length);
eabc67
-                    if (key == NULL)
eabc67
+                    if (key == NULL) {
eabc67
+                        message(MESS_ERROR, "%s:%d failed to parse keyword\n",
eabc67
+                                configFile, lineNum);
eabc67
                         continue;
eabc67
+                    }
eabc67
                     if (!isspace((unsigned char)*start)) {
eabc67
                         message(MESS_NORMAL, "%s:%d keyword '%s' not properly"
eabc67
                                 " separated, found %#x\n",
eabc67
-- 
eabc67
2.38.1
eabc67
eabc67
eabc67
From d3b2d0d058d41dd7efccadff8506285af791711c Mon Sep 17 00:00:00 2001
eabc67
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
eabc67
Date: Tue, 20 Apr 2021 17:41:20 +0200
eabc67
Subject: [PATCH 3/6] Fail on parse error of required option value
eabc67
eabc67
Fail on a parse error of a required option value of the directives
eabc67
include, extension, addextension, rotate, start, minage, maxage,
eabc67
shredcycles and su.
eabc67
Failing is better than silently skipping a directive and running with an
eabc67
undesired configuration.
eabc67
eabc67
Upstream-commit: 906ea11981cb1842538c4aaed395885fda693e47
eabc67
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
eabc67
---
eabc67
 config.c | 49 ++++++++++++++++++++++++++++++-------------------
eabc67
 1 file changed, 30 insertions(+), 19 deletions(-)
eabc67
eabc67
diff --git a/config.c b/config.c
eabc67
index fd6e026..227feec 100644
eabc67
--- a/config.c
eabc67
+++ b/config.c
eabc67
@@ -1154,8 +1154,11 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         mode_t tmp_mode = NO_MODE;
eabc67
                         free(key);
eabc67
                         key = isolateLine(&start, &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            message(MESS_ERROR, "%s:%d failed to parse su option value\n",
eabc67
+                                    configFile, lineNum);
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
 
eabc67
                         rv = readModeUidGid(configFile, lineNum, key, "su",
eabc67
                                             &tmp_mode, &newlog->suUid,
eabc67
@@ -1268,13 +1271,14 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "shred cycles",
eabc67
                                            &start, &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         newlog->shred_cycles = (int)strtoul(key, &chptr, 0);
eabc67
                         if (*chptr || newlog->shred_cycles < 0) {
eabc67
                             message(MESS_ERROR, "%s:%d bad shred cycles '%s'\n",
eabc67
                                     configFile, lineNum, key);
eabc67
-                            goto error;
eabc67
+                            RAISE_ERROR();
eabc67
                         }
eabc67
                     } else if (!strcmp(key, "hourly")) {
eabc67
                         set_criterium(&newlog->criterium, ROT_HOURLY, &criterium_set);
eabc67
@@ -1309,8 +1313,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "rotate count", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         newlog->rotateCount = (int)strtol(key, &chptr, 0);
eabc67
                         if (*chptr || newlog->rotateCount < -1) {
eabc67
                             message(MESS_ERROR,
eabc67
@@ -1322,8 +1327,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "start count", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         newlog->logStart = (int)strtoul(key, &chptr, 0);
eabc67
                         if (*chptr || newlog->logStart < 0) {
eabc67
                             message(MESS_ERROR, "%s:%d bad start count '%s'\n",
eabc67
@@ -1334,8 +1340,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "minage count", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         newlog->rotateMinAge = (int)strtoul(key, &chptr, 0);
eabc67
                         if (*chptr || newlog->rotateMinAge < 0) {
eabc67
                             message(MESS_ERROR, "%s:%d bad minimum age '%s'\n",
eabc67
@@ -1346,8 +1353,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "maxage count", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         newlog->rotateAge = (int)strtoul(key, &chptr, 0);
eabc67
                         if (*chptr || newlog->rotateAge < 0) {
eabc67
                             message(MESS_ERROR, "%s:%d bad maximum age '%s'\n",
eabc67
@@ -1519,8 +1527,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "include", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
 
eabc67
                         if (key[0] == '~' && key[1] == '/') {
eabc67
                             /* replace '~' with content of $HOME cause low-level functions
eabc67
@@ -1582,8 +1591,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "extension name", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         freeLogItem (extension);
eabc67
                         newlog->extension = key;
eabc67
                         key = NULL;
eabc67
@@ -1593,8 +1603,9 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                         free(key);
eabc67
                         key = isolateValue(configFile, lineNum, "addextension name", &start,
eabc67
                                            &buf, length);
eabc67
-                        if (key == NULL)
eabc67
-                            continue;
eabc67
+                        if (key == NULL) {
eabc67
+                            RAISE_ERROR();
eabc67
+                        }
eabc67
                         freeLogItem (addextension);
eabc67
                         newlog->addextension = key;
eabc67
                         key = NULL;
eabc67
-- 
eabc67
2.38.1
eabc67
eabc67
eabc67
From 69d2febc6e6e81e34d944b1652144df2e154965d Mon Sep 17 00:00:00 2001
eabc67
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
eabc67
Date: Mon, 26 Jul 2021 19:35:00 +0200
eabc67
Subject: [PATCH 4/6] Do not warn on key value pair separated by only an equal
eabc67
 sign
eabc67
eabc67
Do not warn if a configuration directive is specified with the key and
eabc67
value separated by just an equal sign, like:
eabc67
eabc67
    size=+2048k
eabc67
eabc67
The warning is intended for the usage of:
eabc67
eabc67
    size2048k
eabc67
eabc67
Fixes: 2b588b5e ("Log if keyword is not properly separated")
eabc67
Fixes: #410
eabc67
eabc67
Upstream-commit: a98c38bc867ec59e00625b48262bb3334c8f5728
eabc67
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
eabc67
---
eabc67
 config.c | 2 +-
eabc67
 1 file changed, 1 insertion(+), 1 deletion(-)
eabc67
eabc67
diff --git a/config.c b/config.c
eabc67
index 227feec..6eb94d4 100644
eabc67
--- a/config.c
eabc67
+++ b/config.c
eabc67
@@ -1091,7 +1091,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                                 configFile, lineNum);
eabc67
                         continue;
eabc67
                     }
eabc67
-                    if (!isspace((unsigned char)*start)) {
eabc67
+                    if (!isspace((unsigned char)*start) && *start != '=') {
eabc67
                         message(MESS_NORMAL, "%s:%d keyword '%s' not properly"
eabc67
                                 " separated, found %#x\n",
eabc67
                                 configFile, lineNum, key, *start);
eabc67
-- 
eabc67
2.38.1
eabc67
eabc67
eabc67
From 3a1f8e746b2753efe7472580b1db4395553b1d34 Mon Sep 17 00:00:00 2001
eabc67
From: Felix Wilhelm <fwilhelm@google.com>
eabc67
Date: Thu, 21 Oct 2021 09:47:57 +0000
eabc67
Subject: [PATCH 5/6] config.c: enforce stricter parsing of config files
eabc67
eabc67
Abort parsing of config files that contain invalid lines.
eabc67
This makes it harder to abuse logrotate for privilege escalation
eabc67
attacks where an attacker can partially control a privileged file write.
eabc67
eabc67
Upstream-commit: 124e4ca6532b0fe823fa2ec145294547b3aaeb4b
eabc67
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
eabc67
---
eabc67
 config.c                |  7 ++++---
eabc67
 test/Makefile.am        |  4 +++-
eabc67
 test/test-0102.sh       | 16 ++++++++++++++++
eabc67
 test/test-0103.sh       | 16 ++++++++++++++++
eabc67
 test/test-config.102.in | 10 ++++++++++
eabc67
 test/test-config.103.in | 12 ++++++++++++
eabc67
 6 files changed, 61 insertions(+), 4 deletions(-)
eabc67
 create mode 100755 test/test-0102.sh
eabc67
 create mode 100755 test/test-0103.sh
eabc67
 create mode 100644 test/test-config.102.in
eabc67
 create mode 100644 test/test-config.103.in
eabc67
eabc67
diff --git a/config.c b/config.c
eabc67
index 6eb94d4..c0fd4ff 100644
eabc67
--- a/config.c
eabc67
+++ b/config.c
eabc67
@@ -1089,12 +1089,13 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
eabc67
                     if (key == NULL) {
eabc67
                         message(MESS_ERROR, "%s:%d failed to parse keyword\n",
eabc67
                                 configFile, lineNum);
eabc67
-                        continue;
eabc67
+                        RAISE_ERROR();
eabc67
                     }
eabc67
                     if (!isspace((unsigned char)*start) && *start != '=') {
eabc67
-                        message(MESS_NORMAL, "%s:%d keyword '%s' not properly"
eabc67
+                        message(MESS_ERROR, "%s:%d keyword '%s' not properly"
eabc67
                                 " separated, found %#x\n",
eabc67
                                 configFile, lineNum, key, *start);
eabc67
+                        RAISE_ERROR();
eabc67
                     }
eabc67
                     if (!strcmp(key, "compress")) {
eabc67
                         newlog->flags |= LOG_FLAG_COMPRESS;
eabc67
@@ -1973,7 +1974,7 @@ duperror:
eabc67
                     message(MESS_ERROR, "%s:%d lines must begin with a keyword "
eabc67
                             "or a filename (possibly in double quotes)\n",
eabc67
                             configFile, lineNum);
eabc67
-                    state = STATE_SKIP_LINE;
eabc67
+                    RAISE_ERROR();
eabc67
                 }
eabc67
                 break;
eabc67
             case STATE_SKIP_LINE:
eabc67
diff --git a/test/Makefile.am b/test/Makefile.am
eabc67
index d6fb7c8..cd357e5 100644
eabc67
--- a/test/Makefile.am
eabc67
+++ b/test/Makefile.am
eabc67
@@ -89,7 +89,9 @@ TEST_CASES = \
eabc67
 	test-0088.sh \
eabc67
 	test-0092.sh \
eabc67
 	test-0100.sh \
eabc67
-	test-0101.sh
eabc67
+	test-0101.sh \
eabc67
+	test-0102.sh \
eabc67
+	test-0103.sh
eabc67
 
eabc67
 EXTRA_DIST = \
eabc67
 	compress \
eabc67
diff --git a/test/test-0102.sh b/test/test-0102.sh
eabc67
new file mode 100755
eabc67
index 0000000..d2550a5
eabc67
--- /dev/null
eabc67
+++ b/test/test-0102.sh
eabc67
@@ -0,0 +1,16 @@
eabc67
+#!/bin/sh
eabc67
+
eabc67
+. ./test-common.sh
eabc67
+
eabc67
+cleanup 102
eabc67
+
eabc67
+# ------------------------------- Test 102 ------------------------------------
eabc67
+# test invalid config file with binary content
eabc67
+preptest test.log 102 1
eabc67
+
eabc67
+$RLR test-config.102 --force
eabc67
+
eabc67
+if [ $? -eq 0 ]; then
eabc67
+   echo "No error, but there should be one."
eabc67
+   exit 3
eabc67
+fi
eabc67
diff --git a/test/test-0103.sh b/test/test-0103.sh
eabc67
new file mode 100755
eabc67
index 0000000..bccd8ed
eabc67
--- /dev/null
eabc67
+++ b/test/test-0103.sh
eabc67
@@ -0,0 +1,16 @@
eabc67
+#!/bin/sh
eabc67
+
eabc67
+. ./test-common.sh
eabc67
+
eabc67
+cleanup 103
eabc67
+
eabc67
+# ------------------------------- Test 103 ------------------------------------
eabc67
+# test invalid config file with unknown keywords
eabc67
+preptest test.log 103 1
eabc67
+
eabc67
+$RLR test-config.103 --force
eabc67
+
eabc67
+if [ $? -eq 0 ]; then
eabc67
+   echo "No error, but there should be one."
eabc67
+   exit 3
eabc67
+fi
eabc67
diff --git a/test/test-config.102.in b/test/test-config.102.in
eabc67
new file mode 100644
eabc67
index 0000000..cbca4c4
eabc67
--- /dev/null
eabc67
+++ b/test/test-config.102.in
eabc67
@@ -0,0 +1,10 @@
eabc67
+ELF
eabc67
+
eabc67
+&DIR&/test.log {
eabc67
+ daily
eabc67
+ size=0
eabc67
+
eabc67
+firstaction
eabc67
+ /bin/sh -c "echo test123"
eabc67
+ endscript
eabc67
+}
eabc67
diff --git a/test/test-config.103.in b/test/test-config.103.in
eabc67
new file mode 100644
eabc67
index 0000000..ef4d19c
eabc67
--- /dev/null
eabc67
+++ b/test/test-config.103.in
eabc67
@@ -0,0 +1,12 @@
eabc67
+random noise
eabc67
+a b c d
eabc67
+a::x
eabc67
+
eabc67
+&DIR&/test.log {
eabc67
+ daily
eabc67
+ size=0
eabc67
+
eabc67
+firstaction
eabc67
+ /bin/sh -c "echo test123"
eabc67
+ endscript
eabc67
+}
eabc67
-- 
eabc67
2.38.1
eabc67
eabc67
eabc67
From 2ad71221cd9e485e4d45df4f28b47072491df120 Mon Sep 17 00:00:00 2001
eabc67
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
eabc67
Date: Mon, 13 Dec 2021 21:47:16 +0100
eabc67
Subject: [PATCH 6/6] Add more testcases for stricter configuration parsing
eabc67
eabc67
Upstream-commit: 9cbc22b91caff6cfbd1378737c62276bd9ffe3e7
eabc67
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
eabc67
---
eabc67
 test/Makefile.am        |  4 +++-
eabc67
 test/test-0102.sh       |  5 +++++
eabc67
 test/test-0103.sh       |  5 +++++
eabc67
 test/test-0104.sh       | 19 +++++++++++++++++++
eabc67
 test/test-0105.sh       | 25 +++++++++++++++++++++++++
eabc67
 test/test-config.104.in |  8 ++++++++
eabc67
 test/test-config.105.in |  8 ++++++++
eabc67
 7 files changed, 73 insertions(+), 1 deletion(-)
eabc67
 create mode 100755 test/test-0104.sh
eabc67
 create mode 100755 test/test-0105.sh
eabc67
 create mode 100644 test/test-config.104.in
eabc67
 create mode 100644 test/test-config.105.in
eabc67
eabc67
diff --git a/test/Makefile.am b/test/Makefile.am
eabc67
index cd357e5..f1a0062 100644
eabc67
--- a/test/Makefile.am
eabc67
+++ b/test/Makefile.am
eabc67
@@ -91,7 +91,9 @@ TEST_CASES = \
eabc67
 	test-0100.sh \
eabc67
 	test-0101.sh \
eabc67
 	test-0102.sh \
eabc67
-	test-0103.sh
eabc67
+	test-0103.sh \
eabc67
+	test-0104.sh \
eabc67
+	test-0105.sh
eabc67
 
eabc67
 EXTRA_DIST = \
eabc67
 	compress \
eabc67
diff --git a/test/test-0102.sh b/test/test-0102.sh
eabc67
index d2550a5..367bde9 100755
eabc67
--- a/test/test-0102.sh
eabc67
+++ b/test/test-0102.sh
eabc67
@@ -14,3 +14,8 @@ if [ $? -eq 0 ]; then
eabc67
    echo "No error, but there should be one."
eabc67
    exit 3
eabc67
 fi
eabc67
+
eabc67
+checkoutput <
eabc67
+test.log 0 zero
eabc67
+test.log.1 0 first
eabc67
+EOF
eabc67
diff --git a/test/test-0103.sh b/test/test-0103.sh
eabc67
index bccd8ed..32a3c19 100755
eabc67
--- a/test/test-0103.sh
eabc67
+++ b/test/test-0103.sh
eabc67
@@ -14,3 +14,8 @@ if [ $? -eq 0 ]; then
eabc67
    echo "No error, but there should be one."
eabc67
    exit 3
eabc67
 fi
eabc67
+
eabc67
+checkoutput <
eabc67
+test.log 0 zero
eabc67
+test.log.1 0 first
eabc67
+EOF
eabc67
diff --git a/test/test-0104.sh b/test/test-0104.sh
eabc67
new file mode 100755
eabc67
index 0000000..e3c0009
eabc67
--- /dev/null
eabc67
+++ b/test/test-0104.sh
eabc67
@@ -0,0 +1,19 @@
eabc67
+#!/bin/sh
eabc67
+
eabc67
+. ./test-common.sh
eabc67
+
eabc67
+cleanup 104
eabc67
+
eabc67
+# ------------------------------- Test 104 ------------------------------------
eabc67
+# test config with unknown (new?) keyword
eabc67
+preptest test1.log 104 1
eabc67
+preptest test2.log 104 1
eabc67
+
eabc67
+$RLR test-config.104 --force || exit 23
eabc67
+
eabc67
+checkoutput <
eabc67
+test1.log 0
eabc67
+test1.log.1 0 zero
eabc67
+test2.log 0
eabc67
+test2.log.1 0 zero
eabc67
+EOF
eabc67
diff --git a/test/test-0105.sh b/test/test-0105.sh
eabc67
new file mode 100755
eabc67
index 0000000..b51e9be
eabc67
--- /dev/null
eabc67
+++ b/test/test-0105.sh
eabc67
@@ -0,0 +1,25 @@
eabc67
+#!/bin/sh
eabc67
+
eabc67
+. ./test-common.sh
eabc67
+
eabc67
+cleanup 105
eabc67
+
eabc67
+# ------------------------------- Test 105 ------------------------------------
eabc67
+# test config with garbage keyword bails out
eabc67
+preptest test1.log 105 1
eabc67
+preptest test2.log 105 1
eabc67
+
eabc67
+$RLR test-config.105 --force
eabc67
+
eabc67
+if [ $? -eq 0 ]; then
eabc67
+   echo "No error, but there should be one."
eabc67
+   exit 3
eabc67
+fi
eabc67
+
eabc67
+
eabc67
+checkoutput <
eabc67
+test1.log 0 zero
eabc67
+test1.log.1 0 first
eabc67
+test2.log 0
eabc67
+test2.log.1 0 zero
eabc67
+EOF
eabc67
diff --git a/test/test-config.104.in b/test/test-config.104.in
eabc67
new file mode 100644
eabc67
index 0000000..988d902
eabc67
--- /dev/null
eabc67
+++ b/test/test-config.104.in
eabc67
@@ -0,0 +1,8 @@
eabc67
+&DIR&/test1.log {
eabc67
+    newkeyword
eabc67
+    rotate 1
eabc67
+}
eabc67
+
eabc67
+&DIR&/test2.log {
eabc67
+    rotate 1
eabc67
+}
eabc67
diff --git a/test/test-config.105.in b/test/test-config.105.in
eabc67
new file mode 100644
eabc67
index 0000000..bfab9b9
eabc67
--- /dev/null
eabc67
+++ b/test/test-config.105.in
eabc67
@@ -0,0 +1,8 @@
eabc67
+&DIR&/test1.log {
eabc67
+    g@rbag€[]+#*
eabc67
+    rotate 1
eabc67
+}
eabc67
+
eabc67
+&DIR&/test2.log {
eabc67
+    rotate 1
eabc67
+}
eabc67
-- 
eabc67
2.38.1
eabc67