From 6fa0f1ba2be41ec829a16bf50454baab808e7615 Mon Sep 17 00:00:00 2001 From: Vratislav Podzimek Date: Tue, 5 Dec 2023 16:02:13 +0100 Subject: [PATCH 1/2] Migrate to PCRE2 PCRE has been deprecated for long enough. Ticket: ENT-10629 Changelog: CFEngine now uses PCRE2 for regular expressions --- .github/workflows/job-static-check.yml | 2 +- .github/workflows/macos_unit_tests.yml | 2 +- CONTRIBUTING.md | 2 +- INSTALL | 14 ++--- LICENSE | 2 +- cf-agent/Makefile.am | 8 +-- cf-agent/files_editxml.c | 17 +----- cf-agent/verify_users_pam.c | 39 ++++++-------- cf-check/Makefile.am | 8 +-- cf-execd/Makefile.am | 4 +- cf-execd/cf-execd-runner.c | 19 ++----- cf-execd/exec-config.c | 48 +++++++++++------ cf-key/Makefile.am | 4 +- cf-monitord/Makefile.am | 4 +- cf-net/Makefile.am | 2 +- cf-promises/Makefile.am | 2 +- cf-runagent/Makefile.am | 2 +- cf-secret/Makefile.am | 2 +- cf-serverd/Makefile.am | 2 +- cf-testd/Makefile.am | 2 +- configure.ac | 36 +++++++------ contrib/vagrant-ci/centos-7-x64/Vagrantfile | 2 +- docs/BSD.md | 2 +- libcfnet/Makefile.am | 2 +- libenv/Makefile.am | 2 +- libenv/sysinfo.c | 31 ++++++----- libenv/unix_iface.c | 17 ++---- libntech | 2 +- libpromises/Makefile.am | 8 +-- libpromises/cf3lex.l | 2 +- libpromises/class.c | 4 +- libpromises/eval_context.c | 6 +-- libpromises/evalfunction.c | 58 ++++++++++----------- libpromises/generic_agent.c | 10 ++-- libpromises/item_lib.c | 6 +-- libpromises/match_scope.c | 33 ++++++------ libpromises/matching.c | 38 +++++++------- libpromises/rlist.c | 14 ++--- libpromises/verify_vars.c | 2 +- tests/acceptance/25_cf-execd/Makefile.am | 4 +- tests/static-check/run.sh | 2 +- tests/unit/Makefile.am | 1 - tests/valgrind-check/Containerfile | 2 +- 43 files changed, 227 insertions(+), 242 deletions(-) diff --git a/.github/workflows/job-static-check.yml b/.github/workflows/job-static-check.yml index 3bce8bf965..a86a5836f8 100644 --- a/.github/workflows/job-static-check.yml +++ b/.github/workflows/job-static-check.yml @@ -41,7 +41,7 @@ jobs: sudo apt-get install -y dpkg-dev debhelper g++ libncurses5 pkg-config \ build-essential libpam0g-dev fakeroot gcc make autoconf buildah \ liblmdb-dev libacl1-dev libcurl4-openssl-dev libyaml-dev libxml2-dev \ - libssl-dev libpcre3-dev + libssl-dev libpcre2-dev - name: Run Autogen run: NO_CONFIGURE=1 PROJECT=community ./buildscripts/build-scripts/autogen diff --git a/.github/workflows/macos_unit_tests.yml b/.github/workflows/macos_unit_tests.yml index d42545e022..a9736c9c06 100644 --- a/.github/workflows/macos_unit_tests.yml +++ b/.github/workflows/macos_unit_tests.yml @@ -11,7 +11,7 @@ jobs: with: submodules: recursive - name: Install dependencies - run: brew install lmdb automake openssl pcre + run: brew install lmdb automake openssl pcre2 - name: Run autotools / configure run: ./autogen.sh --enable-debug - name: Compile and link diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bef03d742e..aea7355ffb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -294,7 +294,7 @@ Keep in mind that these are guidelines, there will always be some situations whe ``` AM_CFLAGS = \ $(OPENSSL_CFLAGS) \ - $(PCRE_CFLAGS) \ + $(PCRE2_CFLAGS) \ $(ENTERPRISE_CFLAGS) ``` * Inside an `if`, you cannot indent with tabs (lines will be silently skipped): diff --git a/INSTALL b/INSTALL index 05f950d6c2..fff3ea87eb 100644 --- a/INSTALL +++ b/INSTALL @@ -16,7 +16,7 @@ In order to build CFEngine you need the following tools and libraries installed: * PAM library * OpenSSL library -* PCRE library +* PCRE2 library * POSIX threads (pthreads) library, if not provided by the operating system * Latest available LMDB (Lightning Memory-mapped DataBase), Tokyo Cabinet or QDBM @@ -119,13 +119,13 @@ $ sudo yum install epel-release && sudo yum update Or on RHEL, replacing the version number with yours: $ sudo subscription-manager repos --enable codeready-builder-for-rhel-9-x86_64-rpms && sudo yum update -$ sudo yum install -y gcc gdb make git libtool autoconf automake byacc flex openssl-devel pcre-devel lmdb-devel pam-devel flex-devel libyaml-devel fakeroot libxml2-devel +$ sudo yum install -y gcc gdb make git libtool autoconf automake byacc flex openssl-devel pcre2-devel lmdb-devel pam-devel flex-devel libyaml-devel fakeroot libxml2-devel For SELinux support you will need selinux-policy-devel package and specify `--with-selinux-policy` to `autogen.sh` or `configure` * Debian (Debian 12 2023-10-09) -$ sudo apt-get install -y build-essential git libtool autoconf automake bison flex libssl-dev libpcre3-dev libbison-dev libacl1 libacl1-dev lmdb-utils liblmdb-dev libpam0g-dev libtool libyaml-dev libxml2-dev +$ sudo apt-get install -y build-essential git libtool autoconf automake bison flex libssl-dev libpcre2-dev libbison-dev libacl1 libacl1-dev lmdb-utils liblmdb-dev libpam0g-dev libtool libyaml-dev libxml2-dev * FreeBSD (12.1 2020-04-07) @@ -133,19 +133,19 @@ See docs/BSD.md * SUSE (Tumbleweed 2020-02-02) -$ sudo zypper install gdb gcc make lmdb autoconf automake libtool git python3 pcre-devel libopenssl-devel pam-devel +$ sudo zypper install gdb gcc make lmdb autoconf automake libtool git python3 pcre2-devel libopenssl-devel pam-devel * AlpineOS (3.11.3 x86_64 2020-04-13) -$ sudo apk add alpine-sdk lmdb-dev openssl-dev bison flex-dev acl-dev pcre-dev autoconf automake libtool git python3 gdb +$ sudo apk add alpine-sdk lmdb-dev openssl-dev bison flex-dev acl-dev pcre2-dev autoconf automake libtool git python3 gdb $ ./autogen.sh --without-pam * Termux (2020-04-24) -$ pkg install build-essential git autoconf automake bison flex liblmdb openssl pcre libacl libyaml +$ pkg install build-essential git autoconf automake bison flex liblmdb openssl pcre2 libacl libyaml $ ./autogen.sh --without-pam * OSX (2021-10-20) -brew install openssl lmdb autoconf automake libtool bison flex pcre m4 gcc make +brew install openssl lmdb autoconf automake libtool bison flex pcre2 m4 gcc make ./autogen.sh --enable-debug diff --git a/LICENSE b/LICENSE index d3a45f3372..de552fa877 100644 --- a/LICENSE +++ b/LICENSE @@ -7,7 +7,7 @@ This file contains a copy of: CFEngine is provided under the terms of the GNU General Public License version 3 (below), with explicit permission to link with the OpenSSL library, BerkeleyDB -library and and PCRE library. +library and PCRE2 library. On some systems, code under the Frontier Artistic License (/libcompat/snprintf) might become compiled. This is compatible with the diff --git a/cf-agent/Makefile.am b/cf-agent/Makefile.am index 076f319659..afc788b761 100644 --- a/cf-agent/Makefile.am +++ b/cf-agent/Makefile.am @@ -30,7 +30,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libntech/libutils \ @CPPFLAGS@ \ $(ENTERPRISE_CPPFLAGS) \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(LIBVIRT_CPPFLAGS) \ $(POSTGRESQL_CPPFLAGS) \ $(MYSQL_CPPFLAGS) \ @@ -41,7 +41,7 @@ AM_CFLAGS = \ @CFLAGS@ \ $(ENTERPRISE_CFLAGS) \ $(OPENSSL_CFLAGS) \ - $(PCRE_CFLAGS) \ + $(PCRE2_CFLAGS) \ $(LIBVIRT_CFLAGS) \ $(POSTGRESQL_CFLAGS) \ $(MYSQL_CFLAGS) \ @@ -51,7 +51,7 @@ AM_CFLAGS = \ AM_LDFLAGS = \ @LDFLAGS@ \ $(OPENSSL_LDFLAGS) \ - $(PCRE_LDFLAGS) \ + $(PCRE2_LDFLAGS) \ $(LIBVIRT_LDFLAGS) \ $(POSTGRESQL_LDFLAGS) \ $(MYSQL_LDFLAGS) \ @@ -64,7 +64,7 @@ endif libcf_agent_la_LIBADD = ../libpromises/libpromises.la \ $(OPENSSL_LIBS) \ - $(PCRE_LIBS) \ + $(PCRE2_LIBS) \ $(LIBVIRT_LIBS) \ $(POSTGRESQL_LIBS) \ $(MYSQL_LIBS) \ diff --git a/cf-agent/files_editxml.c b/cf-agent/files_editxml.c index cd2c2c4fc3..ba0a51925f 100644 --- a/cf-agent/files_editxml.c +++ b/cf-agent/files_editxml.c @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -42,6 +41,7 @@ #include #include #include +#include /* StringMatch() */ enum editxmltypesequence { @@ -2981,20 +2981,7 @@ xmlChar *CharToXmlChar(char c[CF_BUFSIZE]) static bool ContainsRegex(const char* rawstring, const char* regex) { - int ovector[OVECCOUNT], rc; - const char *errorstr; - int erroffset; - - pcre *rx = pcre_compile(regex, 0, &errorstr, &erroffset, NULL); - - if ((rc = pcre_exec(rx, NULL, rawstring, strlen(rawstring), 0, 0, ovector, OVECCOUNT)) >= 0) - { - pcre_free(rx); - return true; - } - - pcre_free(rx); - return false; + return StringMatch(regex, rawstring, NULL, NULL); } /*********************************************************************/ diff --git a/cf-agent/verify_users_pam.c b/cf-agent/verify_users_pam.c index 99d5b7a596..268b8d846f 100644 --- a/cf-agent/verify_users_pam.c +++ b/cf-agent/verify_users_pam.c @@ -35,6 +35,7 @@ #include #include #include // CompileRegex() +#include // BufferData() #include #include @@ -146,8 +147,8 @@ static bool GetAIXShadowHash(const char *puser, const char **result) size_t puser_len = strlen(puser); char name_regex_str[strlen(puser) + 3]; - pcre *name_regex = CompileRegex("^(\\S+):"); - pcre *hash_regex = CompileRegex("^\\s+password\\s*=\\s*(\\S+)"); + pcre2_code *name_regex = CompileRegex("^(\\S+):"); + pcre2_code *hash_regex = CompileRegex("^\\s+password\\s*=\\s*(\\S+)"); bool in_user_section = false; while (true) @@ -162,13 +163,13 @@ static bool GetAIXShadowHash(const char *puser, const char **result) goto end; } - int submatch_vec[6]; - int pcre_result = pcre_exec(name_regex, NULL, buf, strlen(buf), 0, 0, submatch_vec, 6); - if (pcre_result >= 0) + size_t match_start; + size_t match_end; + if (StringMatchWithPrecompiledRegex(name_regex, buf, &match_start, &match_end)) { - if (submatch_vec[3] - submatch_vec[2] == puser_len - && strncmp(buf + submatch_vec[2], puser, puser_len) == 0) + /* Compare the part without the ':' */ + if (StringEqualN(buf, puser, match_end - match_start - 1)) { in_user_section = true; } @@ -178,35 +179,27 @@ static bool GetAIXShadowHash(const char *puser, const char **result) } continue; } - else if (pcre_result != PCRE_ERROR_NOMATCH) - { - errno = EINVAL; - goto end; - } - if (!in_user_section) { continue; } - pcre_result = pcre_exec(hash_regex, NULL, buf, strlen(buf), 0, 0, submatch_vec, 6); - if (pcre_result >= 0) + Seq *captures = StringMatchCapturesWithPrecompiledRegex(hash_regex, buf, false); + if (captures != NULL) { - memcpy(hash_buf, buf + submatch_vec[2], submatch_vec[3] - submatch_vec[2]); + /* captures are buffers, the first one being the full match, the + * second being the first capture group, etc. */ + StringCopy(BufferData(SeqAt(captures, 1)), hash_buf, sizeof(hash_buf)); *result = hash_buf; ret = true; - goto end; - } - else if (pcre_result != PCRE_ERROR_NOMATCH) - { - errno = EINVAL; + SeqDestroy(captures); goto end; } } end: - pcre_free(name_regex); - pcre_free(hash_regex); + pcre2_code_free(name_regex); + pcre2_code_free(hash_regex); free(buf); fclose(fptr); return ret; diff --git a/cf-check/Makefile.am b/cf-check/Makefile.am index 498d6bb3e5..c70b3f51a5 100644 --- a/cf-check/Makefile.am +++ b/cf-check/Makefile.am @@ -27,7 +27,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libntech/libutils \ -I$(srcdir)/../libntech/libcompat \ -I$(srcdir)/../libcfecompat \ @CPPFLAGS@ \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(LIBYAML_CPPFLAGS) \ $(LMDB_CPPFLAGS) \ $(OPENSSL_CPPFLAGS) @@ -35,20 +35,20 @@ AM_CPPFLAGS = -I$(srcdir)/../libntech/libutils \ AM_CFLAGS = \ @CFLAGS@ \ $(LMDB_CFLAGS) \ - $(PCRE_CFLAGS) \ + $(PCRE2_CFLAGS) \ $(LIBYAML_CFLAGS) \ $(PTHREAD_CFLAGS) AM_LDFLAGS = \ @LDFLAGS@ \ - $(PCRE_LDFLAGS) \ + $(PCRE2_LDFLAGS) \ $(LIBYAML_LDFLAGS) \ $(LMDB_LDFLAGS) libcf_check_la_LIBADD = ../libntech/libutils/libutils.la \ ../libcfecompat/libcfecompat.la \ $(LMDB_LIBS) \ - $(PCRE_LIBS) \ + $(PCRE2_LIBS) \ $(LIBYAML_LIBS) \ $(PTHREAD_LIBS) \ $(OPENSSL_LIBS) diff --git a/cf-execd/Makefile.am b/cf-execd/Makefile.am index 556e4c147a..190dde9ffc 100644 --- a/cf-execd/Makefile.am +++ b/cf-execd/Makefile.am @@ -30,12 +30,12 @@ AM_CPPFLAGS = \ -I$(srcdir)/../libcfnet \ -I$(srcdir)/../libenv \ -I$(srcdir)/../cf-check \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(OPENSSL_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = \ - $(PCRE_CFLAGS) \ + $(PCRE2_CFLAGS) \ $(OPENSSL_CFLAGS) \ $(PTHREAD_CFLAGS) \ $(ENTERPRISE_CFLAGS) diff --git a/cf-execd/cf-execd-runner.c b/cf-execd/cf-execd-runner.c index 8217194d8f..c364043580 100644 --- a/cf-execd/cf-execd-runner.c +++ b/cf-execd/cf-execd-runner.c @@ -447,20 +447,13 @@ static bool CompareResultEqualOrFiltered(const ExecConfig *config, FILE *new_fp = safe_fopen(filename, "r"); if (new_fp) { - const char *errptr; - int erroffset; - pcre_extra *regex_extra = NULL; // Match timestamps and remove them. Not Y21K safe! :-) - pcre *regex = pcre_compile(LOGGING_TIMESTAMP_REGEX, PCRE_MULTILINE, &errptr, &erroffset, NULL); + pcre2_code *regex = CompileRegex(LOGGING_TIMESTAMP_REGEX); if (!regex) { UnexpectedError("Compiling regular expression failed"); rtn = false; } - else - { - regex_extra = pcre_study(regex, 0, &errptr); - } size_t old_line_size = CF_BUFSIZE; char *old_line = xmalloc(old_line_size); @@ -508,7 +501,7 @@ static bool CompareResultEqualOrFiltered(const ExecConfig *config, // Remove timestamps from lines before comparison. char *index; - if (pcre_exec(regex, regex_extra, old_msg, strlen(old_msg), 0, 0, NULL, 0) >= 0) + if (StringMatchWithPrecompiledRegex(regex, old_msg, NULL, NULL)) { index = strstr(old_msg, ": "); if (index != NULL) @@ -516,7 +509,7 @@ static bool CompareResultEqualOrFiltered(const ExecConfig *config, old_msg = index + 2; } } - if (pcre_exec(regex, regex_extra, new_msg, strlen(new_msg), 0, 0, NULL, 0) >= 0) + if (StringMatchWithPrecompiledRegex(regex, new_msg, NULL, NULL)) { index = strstr(new_msg, ": "); if (index != NULL) @@ -535,11 +528,7 @@ static bool CompareResultEqualOrFiltered(const ExecConfig *config, free(old_line); free(new_line); - if (regex_extra) - { - free(regex_extra); - } - pcre_free(regex); + pcre2_code_free(regex); } else { diff --git a/cf-execd/exec-config.c b/cf-execd/exec-config.c index 979b0b64ae..3438c73064 100644 --- a/cf-execd/exec-config.c +++ b/cf-execd/exec-config.c @@ -23,7 +23,8 @@ */ #include - +#define PCRE2_CODE_UNIT_WIDTH 8 +#include #include #include #include @@ -32,7 +33,6 @@ #include #include #include // TODO: fix -#include // pcre_free() #include @@ -54,30 +54,44 @@ static char *GetIpAddresses(const EvalContext *ctx) static void RegexFree(void *ptr) { - pcre_free(ptr); + pcre2_code_free(ptr); } -static void MailFilterFill(const char *str, +static void MailFilterFill(const char *pattern, Seq **output, Seq **output_regex, const char *filter_type) { - const char *errorstr; - int erroffset; - pcre *rx = pcre_compile(str, - PCRE_MULTILINE | PCRE_DOTALL | PCRE_ANCHORED, - &errorstr, &erroffset, NULL); - if (!rx) + int err_code; + size_t err_offset; + pcre2_code *regex = pcre2_compile((PCRE2_SPTR) pattern, PCRE2_ZERO_TERMINATED, + PCRE2_MULTILINE | PCRE2_DOTALL | PCRE2_ANCHORED, + &err_code, &err_offset, NULL); + + if (regex != NULL) { - Log(LOG_LEVEL_ERR, - "Invalid regular expression in mailfilter_%s: " - "pcre_compile() '%s' in expression '%s' (offset: %d). " - "Ignoring expression.", filter_type, - errorstr, str, erroffset); + SeqAppend(*output, xstrdup(pattern)); + SeqAppend(*output_regex, regex); } else { - SeqAppend(*output, xstrdup(str)); - SeqAppend(*output_regex, rx); + char err_msg[128]; + if (pcre2_get_error_message(err_code, (PCRE2_UCHAR*) err_msg, sizeof(err_msg)) != + PCRE2_ERROR_BADDATA) + { + Log(LOG_LEVEL_ERR, + "Invalid regular expression in mailfilter_%s: " + "pcre2_compile() '%s' in expression '%s' (offset: %zd). " + "Ignoring expression.", + filter_type, err_msg, pattern, err_offset); + } + else + { + Log(LOG_LEVEL_ERR, + "Invalid regular expression in mailfilter_%s: " + "pcre2_compile() failed for expression '%s' (offset: %zd). " + "Ignoring expression.", + filter_type, pattern, err_offset); + } } } diff --git a/cf-key/Makefile.am b/cf-key/Makefile.am index cce61505d5..568429854d 100644 --- a/cf-key/Makefile.am +++ b/cf-key/Makefile.am @@ -28,13 +28,13 @@ AM_CPPFLAGS = \ -I$(srcdir)/../libcfecompat \ -I$(srcdir)/../libcfnet \ -I$(srcdir)/../libpromises \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(OPENSSL_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = \ $(OPENSSL_CFLAGS) \ - $(PCRE_CFLAGS) \ + $(PCRE2_CFLAGS) \ $(ENTERPRISE_CFLAGS) libcf_key_la_SOURCES = \ diff --git a/cf-monitord/Makefile.am b/cf-monitord/Makefile.am index 627d152424..9e332ab433 100644 --- a/cf-monitord/Makefile.am +++ b/cf-monitord/Makefile.am @@ -29,7 +29,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/../libcfnet \ -I$(srcdir)/../libenv \ -I$(srcdir)/../libpromises \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(OPENSSL_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) @@ -79,7 +79,7 @@ TESTS += get_socket_info noinst_PROGRAMS = get_socket_info get_socket_info_SOURCES = get_socket_info.c get_socket_info_LDADD = ../libntech/libutils/libutils.la \ - $(PCRE_LIBS) \ + $(PCRE2_LIBS) \ $(LIBYAML_LIBS) \ libcf-monitord.la endif diff --git a/cf-net/Makefile.am b/cf-net/Makefile.am index 53a68f45f2..acaad3f8c5 100644 --- a/cf-net/Makefile.am +++ b/cf-net/Makefile.am @@ -27,7 +27,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libntech/libutils \ -I$(srcdir)/../libcfecompat \ -I$(srcdir)/../libcfnet \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = @CFLAGS@ \ diff --git a/cf-promises/Makefile.am b/cf-promises/Makefile.am index d12e76375a..998057ce39 100644 --- a/cf-promises/Makefile.am +++ b/cf-promises/Makefile.am @@ -30,7 +30,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/../libcfnet \ @CPPFLAGS@ \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = @CFLAGS@ \ diff --git a/cf-runagent/Makefile.am b/cf-runagent/Makefile.am index e75bd25c3a..4daf9d489b 100644 --- a/cf-runagent/Makefile.am +++ b/cf-runagent/Makefile.am @@ -27,7 +27,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libntech/libutils \ -I$(srcdir)/../libcfnet \ -I$(srcdir)/../libcfecompat \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = @CFLAGS@ \ diff --git a/cf-secret/Makefile.am b/cf-secret/Makefile.am index d0e13581a3..ca35702f4a 100644 --- a/cf-secret/Makefile.am +++ b/cf-secret/Makefile.am @@ -27,7 +27,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libntech/libutils \ -I$(srcdir)/../libcfecompat \ -I$(srcdir)/../libcfnet \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = @CFLAGS@ \ diff --git a/cf-serverd/Makefile.am b/cf-serverd/Makefile.am index 0b60c53891..327151fdf4 100644 --- a/cf-serverd/Makefile.am +++ b/cf-serverd/Makefile.am @@ -28,7 +28,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libntech/libutils \ -I$(srcdir)/../libcfecompat \ -I$(srcdir)/../libenv \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = \ diff --git a/cf-testd/Makefile.am b/cf-testd/Makefile.am index eefeec8911..ddd24fdf29 100644 --- a/cf-testd/Makefile.am +++ b/cf-testd/Makefile.am @@ -29,7 +29,7 @@ AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libntech/libutils \ -I$(srcdir)/../libenv \ -I$(srcdir)/../cf-serverd \ $(OPENSSL_CPPFLAGS) \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = \ diff --git a/configure.ac b/configure.ac index e3076c9263..c8bbde60ad 100644 --- a/configure.ac +++ b/configure.ac @@ -504,24 +504,26 @@ CF3_WITH_LIBRARY(openssl, [ ) ]) -dnl PCRE +dnl PCRE2 +AC_ARG_WITH([pcre2], [AS_HELP_STRING([--with-pcre2[[=PATH]]], [Specify PCRE2 path])], [], [with_pcre2=yes]) -AC_ARG_WITH([pcre], [AS_HELP_STRING([--with-pcre[[=PATH]]], [Specify PCRE path])], [], [with_pcre=yes]) - -if test "x$with_pcre" = "xno"; then - AC_MSG_ERROR([PCRE is required]) +if test "x$with_pcre2" = "xno"; then + AC_MSG_ERROR([PCRE2 is required]) fi -CF3_WITH_LIBRARY(pcre, [ - AC_CHECK_LIB(pcre, pcre_exec, [], [AC_MSG_ERROR(Cannot find PCRE)]) - AC_CHECK_HEADERS([pcre.h], [], - [AC_CHECK_HEADERS([pcre/pcre.h], [PCRE_CPPFLAGS="-Ipcre"], - AC_MSG_ERROR(Cannot find PCRE))]) -]) +CF3_WITH_LIBRARY(pcre2, [ + AC_CHECK_LIB(pcre2-8, pcre2_compile_8, [], [AC_MSG_ERROR(Cannot find PCRE2)]) + AC_CHECK_HEADERS( + [pcre2.h], + [], + AC_MSG_ERROR(Cannot find PCRE2), + [#define PCRE2_CODE_UNIT_WIDTH 8] + )] +) dnl defined for libntech -AC_DEFINE(WITH_PCRE, 1, [Define if PCRE is being used]) +AC_DEFINE(WITH_PCRE2, 1, [Define if PCRE2 is being used]) dnl systemd-socket activation @@ -1306,10 +1308,10 @@ dnl ###################################################################### dnl Collect all the options dnl ###################################################################### -CORE_CPPFLAGS="$LMDB_CPPFLAGS $TOKYOCABINET_CPPFLAGS $QDBM_CPPFLAGS $PCRE_CPPFLAGS $OPENSSL_CPPFLAGS $SQLITE3_CPPFLAGS $LIBACL_CPPFLAGS $LIBCURL_CPPFLAGS $LIBYAML_CPPFLAGS $POSTGRESQL_CPPFLAGS $MYSQL_CPPFLAGS $LIBXML2_CPPFLAGS $CPPFLAGS $CFECOMPAT_CPPFLAGS" -CORE_CFLAGS="$LMDB_CFLAGS $TOKYOCABINET_CFLAGS $QDBM_CFLAGS $PCRE_CFLAGS $OPENSSL_CFLAGS $SQLITE3_CFLAGS $LIBACL_CFLAGS $LIBCURL_CFLAGS $LIBYAML_CFLAGS $POSTGRESQL_CFLAGS $MYSQL_CFLAGS $LIBXML2_CFLAGS $CFLAGS" -CORE_LDFLAGS="$LMDB_LDFLAGS $TOKYOCABINET_LDFLAGS $QDBM_LDFLAGS $PCRE_LDFLAGS $OPENSSL_LDFLAGS $SQLITE3_LDFLAGS $LIBACL_LDFLAGS $LIBCURL_LDFLAGS $LIBYAML_LDFLAGS $POSTGRESQL_LDFLAGS $MYSQL_LDFLAGS $LIBXML2_LDFLAGS $LDFLAGS" -CORE_LIBS="$LMDB_LIBS $TOKYOCABINET_LIBS $QDBM_LIBS $PCRE_LIBS $OPENSSL_LIBS $SQLITE3_LIBS $LIBACL_LIBS $LIBCURL_LIBS $LIBYAML_LIBS $POSTGRESQL_LIBS $MYSQL_LIBS $LIBXML2_LIBS $LIBS" +CORE_CPPFLAGS="$LMDB_CPPFLAGS $TOKYOCABINET_CPPFLAGS $QDBM_CPPFLAGS $PCRE2_CPPFLAGS $OPENSSL_CPPFLAGS $SQLITE3_CPPFLAGS $LIBACL_CPPFLAGS $LIBCURL_CPPFLAGS $LIBYAML_CPPFLAGS $POSTGRESQL_CPPFLAGS $MYSQL_CPPFLAGS $LIBXML2_CPPFLAGS $CPPFLAGS $CFECOMPAT_CPPFLAGS" +CORE_CFLAGS="$LMDB_CFLAGS $TOKYOCABINET_CFLAGS $QDBM_CFLAGS $PCRE2_CFLAGS $OPENSSL_CFLAGS $SQLITE3_CFLAGS $LIBACL_CFLAGS $LIBCURL_CFLAGS $LIBYAML_CFLAGS $POSTGRESQL_CFLAGS $MYSQL_CFLAGS $LIBXML2_CFLAGS $CFLAGS" +CORE_LDFLAGS="$LMDB_LDFLAGS $TOKYOCABINET_LDFLAGS $QDBM_LDFLAGS $PCRE2_LDFLAGS $OPENSSL_LDFLAGS $SQLITE3_LDFLAGS $LIBACL_LDFLAGS $LIBCURL_LDFLAGS $LIBYAML_LDFLAGS $POSTGRESQL_LDFLAGS $MYSQL_LDFLAGS $LIBXML2_LDFLAGS $LDFLAGS" +CORE_LIBS="$LMDB_LIBS $TOKYOCABINET_LIBS $QDBM_LIBS $PCRE2_LIBS $OPENSSL_LIBS $SQLITE3_LIBS $LIBACL_LIBS $LIBCURL_LIBS $LIBYAML_LIBS $POSTGRESQL_LIBS $MYSQL_LIBS $LIBXML2_LIBS $LIBS" dnl ###################################################################### dnl Make them available to subprojects. @@ -1731,7 +1733,7 @@ AC_MSG_RESULT([> Required libraries]) AC_MSG_RESULT([-> OpenSSL: $OPENSSL_PATH]) -AC_MSG_RESULT([-> PCRE: $PCRE_PATH]) +AC_MSG_RESULT([-> PCRE2: $PCRE2_PATH]) if test $WITH_TOKYO = 1; then AC_MSG_RESULT([-> DB: Tokyo Cabinet: $TOKYOCABINET_PATH]) diff --git a/contrib/vagrant-ci/centos-7-x64/Vagrantfile b/contrib/vagrant-ci/centos-7-x64/Vagrantfile index 3cdc812f6d..394a692e86 100644 --- a/contrib/vagrant-ci/centos-7-x64/Vagrantfile +++ b/contrib/vagrant-ci/centos-7-x64/Vagrantfile @@ -44,7 +44,7 @@ SHELL nd.vm.provision "shell", inline: <<-SHELL set -e -yum -q -y install lmdb-devel pcre-devel openssl-devel libyaml-devel libxml2-devel +yum -q -y install lmdb-devel pcre2-devel openssl-devel libyaml-devel libxml2-devel SHELL nd.vm.provision "shell", inline: <<-SHELL diff --git a/docs/BSD.md b/docs/BSD.md index ccbfd31bc3..17caa4e4a8 100644 --- a/docs/BSD.md +++ b/docs/BSD.md @@ -44,7 +44,7 @@ $ git rebase master Within `core` directory: ``` -$ ./autogen.sh --enable-debug -C --with-lmdb=/usr/local/ --with-pcre=/usr/local/ +$ ./autogen.sh --enable-debug -C --with-lmdb=/usr/local/ --with-pcre2=/usr/local/ $ gmake -j8 ``` diff --git a/libcfnet/Makefile.am b/libcfnet/Makefile.am index e0c1a65b9f..3e5cff8619 100644 --- a/libcfnet/Makefile.am +++ b/libcfnet/Makefile.am @@ -25,7 +25,7 @@ noinst_LTLIBRARIES = libcfnet.la AM_CPPFLAGS = -I$(top_srcdir)/libntech/libutils \ -I$(top_srcdir)/libpromises \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(SYSTEMD_SOCKET_CPPFLAGS) \ $(OPENSSL_CPPFLAGS) diff --git a/libenv/Makefile.am b/libenv/Makefile.am index 5a9d9dbe3a..2c66662361 100644 --- a/libenv/Makefile.am +++ b/libenv/Makefile.am @@ -40,7 +40,7 @@ endif AM_CPPFLAGS = -I$(top_srcdir)/libntech/libutils AM_CPPFLAGS += $(OPENSSL_CPPFLAGS) # because libutils needs it -AM_CPPFLAGS += $(PCRE_CPPFLAGS) +AM_CPPFLAGS += $(PCRE2_CPPFLAGS) # Those dependencies are ought to go away ASAP AM_CPPFLAGS += -I$(top_srcdir)/libcfnet diff --git a/libenv/sysinfo.c b/libenv/sysinfo.c index 0ed26955b5..272b19bf7e 100644 --- a/libenv/sysinfo.c +++ b/libenv/sysinfo.c @@ -24,6 +24,8 @@ #include +#define PCRE2_CODE_UNIT_WIDTH 8 +#include #include #include #include @@ -3240,21 +3242,19 @@ int GetUptimeMinutes(time_t now) // index number (i.e., the count of left-parentheses): #define UPTIME_REGEXP " up (\\d+ day[^,]*,|) *(\\d+( ho?u?r|:(\\d+))|(\\d+) min)" #define UPTIME_BACKREFS 5 -#define UPTIME_OVECTOR ((UPTIME_BACKREFS + 1) * 3) static time_t GetBootTimeFromUptimeCommand(time_t now) { FILE *uptimecmd; - pcre *rx; - int ovector[UPTIME_OVECTOR], i; char *backref = NULL; const char *uptimepath = "/usr/bin/uptime"; time_t uptime = 0; - const char *errptr; - int erroffset; - rx = pcre_compile(UPTIME_REGEXP, 0, &errptr, &erroffset, NULL); - if (rx == NULL) + int err_code; + size_t err_offset; + pcre2_code *regex = pcre2_compile((PCRE2_SPTR) UPTIME_REGEXP, PCRE2_ZERO_TERMINATED, 0, + &err_code, &err_offset, NULL); + if (regex == NULL) { Log(LOG_LEVEL_DEBUG, "failed to compile regexp to parse uptime command"); return(-1); @@ -3266,23 +3266,29 @@ static time_t GetBootTimeFromUptimeCommand(time_t now) if (!uptimecmd) { Log(LOG_LEVEL_ERR, "uptime failed: (cf_popen: %s)", GetErrorStr()); + pcre2_code_free(regex); return -1; } size_t uptime_output_size = CF_SMALLBUF; char *uptime_output = xmalloc(uptime_output_size); - i = CfReadLine(&uptime_output, &uptime_output_size, uptimecmd); + ssize_t n_read = CfReadLine(&uptime_output, &uptime_output_size, uptimecmd); cf_pclose(uptimecmd); - if (i == -1 && !feof(uptimecmd)) + if (n_read == -1 && !feof(uptimecmd)) { Log(LOG_LEVEL_ERR, "Reading uptime output failed. (getline: '%s')", GetErrorStr()); + pcre2_code_free(regex); return -1; } - if ((i > 0) && (pcre_exec(rx, NULL, (const char *)uptime_output, i, 0, 0, ovector, UPTIME_OVECTOR) > 1)) + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL); + if ((n_read > 0) && + (pcre2_match(regex, (PCRE2_SPTR) uptime_output, PCRE2_ZERO_TERMINATED, + 0, 0, match_data, NULL) > 1)) { - for (i = 1; i <= UPTIME_BACKREFS ; i++) + size_t *ovector = pcre2_get_ovector_pointer(match_data); + for (int i = 1; i <= UPTIME_BACKREFS ; i++) { if (ovector[i * 2 + 1] - ovector[i * 2] == 0) // strlen(backref) { @@ -3314,7 +3320,8 @@ static time_t GetBootTimeFromUptimeCommand(time_t now) { Log(LOG_LEVEL_ERR, "uptime PCRE match failed: regexp: '%s', uptime: '%s'", UPTIME_REGEXP, uptime_output); } - pcre_free(rx); + pcre2_match_data_free(match_data); + pcre2_code_free(regex); Log(LOG_LEVEL_VERBOSE, "Reading boot time from uptime command successful."); return(uptime ? (now - uptime) : -1); } diff --git a/libenv/unix_iface.c b/libenv/unix_iface.c index ee44319407..5f90da63ea 100644 --- a/libenv/unix_iface.c +++ b/libenv/unix_iface.c @@ -1287,7 +1287,7 @@ static JsonElement* GetNetworkingStatsInfo(const char *filename) // always returns the parsed data. If the key is not NULL, also // creates a sys.KEY variable. -JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* key, const char* extracted_key, ProcPostProcessFn post, ProcTiebreakerFn tiebreak, const char* regex) +JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* key, const char* extracted_key, ProcPostProcessFn post, ProcTiebreakerFn tiebreak, const char* pattern) { JsonElement *info = NULL; bool extract_key_mode = (extracted_key != NULL); @@ -1297,15 +1297,8 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* { Log(LOG_LEVEL_VERBOSE, "Reading %s info from %s", key, filename); - pcre *pattern = NULL; - { - const char *errorstr; - int erroffset; - pattern = pcre_compile(regex, PCRE_MULTILINE | PCRE_DOTALL, - &errorstr, &erroffset, NULL); - } - - if (pattern != NULL) + pcre2_code *regex = CompileRegex(pattern); + if (regex != NULL) { size_t line_size = CF_BUFSIZE; char *line = xmalloc(line_size); @@ -1314,7 +1307,7 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* while (CfReadLine(&line, &line_size, fin) != -1) { - JsonElement *item = StringCaptureData(pattern, regex, line); + JsonElement *item = StringCaptureData(regex, NULL, line); if (item != NULL) { @@ -1378,7 +1371,7 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* BufferDestroy(varname); } - pcre_free(pattern); + pcre2_code_free(regex); } fclose(fin); diff --git a/libntech b/libntech index 469add75b0..0aefa4a3e8 160000 --- a/libntech +++ b/libntech @@ -1 +1 @@ -Subproject commit 469add75b05c44c6368689dc480707f2f3a7ab6b +Subproject commit 0aefa4a3e861b7307732d4cccffb80f751f84bf8 diff --git a/libpromises/Makefile.am b/libpromises/Makefile.am index c190effcd3..edf8f4609a 100644 --- a/libpromises/Makefile.am +++ b/libpromises/Makefile.am @@ -30,7 +30,7 @@ AM_LDFLAGS = endif AM_LDFLAGS += $(CORE_LDFLAGS) $(LMDB_LDFLAGS) $(TOKYOCABINET_LDFLAGS) $(QDBM_LDFLAGS) \ - $(PCRE_LDFLAGS) $(OPENSSL_LDFLAGS) $(SQLITE3_LDFLAGS) $(LIBACL_LDFLAGS) $(LIBYAML_LDFLAGS) $(LIBCURL_LDFLAGS) + $(PCRE2_LDFLAGS) $(OPENSSL_LDFLAGS) $(SQLITE3_LDFLAGS) $(LIBACL_LDFLAGS) $(LIBYAML_LDFLAGS) $(LIBCURL_LDFLAGS) AM_CPPFLAGS = \ -I$(srcdir)/../libntech/libutils -I$(srcdir)/../libcfecompat \ @@ -39,16 +39,16 @@ AM_CPPFLAGS = \ -I$(srcdir)/../cf-check \ $(CORE_CPPFLAGS) $(ENTERPRISE_CPPFLAGS) \ $(LMDB_CPPFLAGS) $(TOKYOCABINET_CPPFLAGS) $(QDBM_CPPFLAGS) \ - $(PCRE_CPPFLAGS) $(OPENSSL_CPPFLAGS) $(SQLITE3_CPPFLAGS) $(LIBACL_CPPFLAGS) $(LIBYAML_CPPFLAGS) $(LIBCURL_CPPFLAGS) + $(PCRE2_CPPFLAGS) $(OPENSSL_CPPFLAGS) $(SQLITE3_CPPFLAGS) $(LIBACL_CPPFLAGS) $(LIBYAML_CPPFLAGS) $(LIBCURL_CPPFLAGS) AM_CFLAGS = $(CORE_CFLAGS) $(ENTERPRISE_CFLAGS) \ $(LMDB_CFLAGS) $(TOKYOCABINET_CFLAGS) $(QDBM_CFLAGS) \ - $(PCRE_CFLAGS) $(OPENSSL_CFLAGS) $(SQLITE3_CFLAGS) $(LIBACL_CFLAGS) $(LIBYAML_CFLAGS) $(LIBCURL_CFLAGS) + $(PCRE2_CFLAGS) $(OPENSSL_CFLAGS) $(SQLITE3_CFLAGS) $(LIBACL_CFLAGS) $(LIBYAML_CFLAGS) $(LIBCURL_CFLAGS) AM_YFLAGS = -d LIBS = $(LMDB_LIBS) $(TOKYOCABINET_LIBS) $(QDBM_LIBS) \ - $(PCRE_LIBS) $(OPENSSL_LIBS) $(SQLITE3_LIBS) $(LIBACL_LIBS) $(LIBYAML_LIBS) $(LIBCURL_LIBS) + $(PCRE2_LIBS) $(OPENSSL_LIBS) $(SQLITE3_LIBS) $(LIBACL_LIBS) $(LIBYAML_LIBS) $(LIBCURL_LIBS) # The lib providing sd_listen_fds() is not needed in libpromises, it's actually # needed in libcfnet. But adding it here is an easy way to make sure it's diff --git a/libpromises/cf3lex.l b/libpromises/cf3lex.l index 792723f0e8..df30d0c9a4 100644 --- a/libpromises/cf3lex.l +++ b/libpromises/cf3lex.l @@ -58,7 +58,7 @@ #define ParserDebug(...) ((void) 0) #define P PARSER_STATE -static pcre *context_expression_whitespace_rx = NULL; +static pcre2_code *context_expression_whitespace_rx = NULL; static int DeEscapeQuotedString(const char *from, char *to); diff --git a/libpromises/class.c b/libpromises/class.c index de49e7114d..94ce671f02 100644 --- a/libpromises/class.c +++ b/libpromises/class.c @@ -177,7 +177,7 @@ Class *ClassTableMatch(const ClassTable *table, const char *regex) ClassTableIterator *it = ClassTableIteratorNew(table, NULL, true, true); Class *cls = NULL; - pcre *pattern = CompileRegex(regex); + pcre2_code *pattern = CompileRegex(regex); if (pattern == NULL) { // TODO: perhaps pcre has can give more info on this error? @@ -205,7 +205,7 @@ Class *ClassTableMatch(const ClassTable *table, const char *regex) } } - pcre_free(pattern); + pcre2_code_free(pattern); ClassTableIteratorDestroy(it); return cls; diff --git a/libpromises/eval_context.c b/libpromises/eval_context.c index 1d50f4eeab..527985a7ac 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -110,7 +110,7 @@ TYPED_MAP_DEFINE(RemoteVarPromises, char *, Seq *, SeqDestroy_untyped) -static pcre *context_expression_whitespace_rx = NULL; +static pcre2_code *context_expression_whitespace_rx = NULL; #include @@ -3563,7 +3563,7 @@ StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, con { StringSet *matching = StringSetNew(); - pcre *rx = CompileRegex(regex); + pcre2_code *rx = CompileRegex(regex); Class *cls; while ((cls = ClassTableIteratorNext(iter))) @@ -3623,7 +3623,7 @@ StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, con if (rx) { - pcre_free(rx); + pcre2_code_free(rx); } return matching; diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c index 82bf17054f..a61753a694 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -1433,7 +1433,7 @@ static JsonElement *VariablesMatching(const EvalContext *ctx, const FnCall *fp, JsonElement *matching = JsonObjectCreate(10); const char *regex = RlistScalarValue(args); - pcre *rx = CompileRegex(regex); + pcre2_code *rx = CompileRegex(regex); Variable *v = NULL; while ((v = VariableTableIteratorNext(iter))) @@ -1507,7 +1507,7 @@ static JsonElement *VariablesMatching(const EvalContext *ctx, const FnCall *fp, if (rx) { - pcre_free(rx); + pcre2_code_free(rx); } return matching; @@ -1681,7 +1681,7 @@ static FnCallResult FnCallBundlesMatching(EvalContext *ctx, const Policy *policy } const char *regex = RlistScalarValue(finalargs); - pcre *rx = CompileRegex(regex); + pcre2_code *rx = CompileRegex(regex); if (!rx) { return FnFailure(); @@ -1744,14 +1744,14 @@ static FnCallResult FnCallBundlesMatching(EvalContext *ctx, const Policy *policy free(bundle_name); } - pcre_free(rx); + pcre2_code_free(rx); return (FnCallResult) { FNCALL_SUCCESS, { matches, RVAL_TYPE_LIST } }; } /*********************************************************************/ -static bool AddPackagesMatchingJsonLine(pcre *matcher, JsonElement *json, char *line) +static bool AddPackagesMatchingJsonLine(pcre2_code *matcher, JsonElement *json, char *line) { const size_t line_length = strlen(line); if (line_length > CF_BUFSIZE - 80) @@ -1788,7 +1788,7 @@ static bool AddPackagesMatchingJsonLine(pcre *matcher, JsonElement *json, char * return true; } -static bool GetLegacyPackagesMatching(pcre *matcher, JsonElement *json, const bool installed_mode) +static bool GetLegacyPackagesMatching(pcre2_code *matcher, JsonElement *json, const bool installed_mode) { char filename[CF_MAXVARSIZE]; if (installed_mode) @@ -1836,7 +1836,7 @@ static bool GetLegacyPackagesMatching(pcre *matcher, JsonElement *json, const bo return ret; } -static bool GetPackagesMatching(pcre *matcher, JsonElement *json, const bool installed_mode, Rlist *default_inventory) +static bool GetPackagesMatching(pcre2_code *matcher, JsonElement *json, const bool installed_mode, Rlist *default_inventory) { dbid database = (installed_mode == true ? dbid_packages_installed : dbid_packages_updates); @@ -1932,7 +1932,7 @@ static bool GetPackagesMatching(pcre *matcher, JsonElement *json, const bool ins static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs) { const bool installed_mode = (strcmp(fp->name, "packagesmatching") == 0); - pcre *matcher; + pcre2_code *matcher; { const char *regex_package = RlistScalarValue(finalargs); const char *regex_version = RlistScalarValue(finalargs->next); @@ -1998,7 +1998,7 @@ static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUS else { Log(LOG_LEVEL_DEBUG, "No valid package module inventory found"); - pcre_free(matcher); + pcre2_code_free(matcher); JsonDestroy(json); if (inventory_allocated) { @@ -2012,7 +2012,7 @@ static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUS { RlistDestroy(default_inventory); } - pcre_free(matcher); + pcre2_code_free(matcher); if (ret == false) { @@ -3262,7 +3262,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, const FnCall *fp, const Rlist *finalargs) { - pcre *rx = CompileRegex(RlistScalarValue(finalargs)); + pcre2_code *rx = CompileRegex(RlistScalarValue(finalargs)); if (!rx) { return FnFailure(); @@ -3276,7 +3276,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, if (!fin) { Log(LOG_LEVEL_ERR, "File '%s' could not be read in getfields(). (fopen: %s)", filename, GetErrorStr()); - pcre_free(rx); + pcre2_code_free(rx); return FnFailure(); } @@ -3318,7 +3318,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, VarRefDestroy(ref); free(line); RlistDestroy(newlist); - pcre_free(rx); + pcre2_code_free(rx); return FnFailure(); } } @@ -3335,7 +3335,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, line_count++; } - pcre_free(rx); + pcre2_code_free(rx); free(line); if (!feof(fin)) @@ -3354,7 +3354,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, static FnCallResult FnCallCountLinesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, ARG_UNUSED const FnCall *fp, const Rlist *finalargs) { - pcre *rx = CompileRegex(RlistScalarValue(finalargs)); + pcre2_code *rx = CompileRegex(RlistScalarValue(finalargs)); if (!rx) { return FnFailure(); @@ -3366,7 +3366,7 @@ static FnCallResult FnCallCountLinesMatching(ARG_UNUSED EvalContext *ctx, ARG_UN if (!fin) { Log(LOG_LEVEL_ERR, "File '%s' could not be read in countlinesmatching(). (fopen: %s)", filename, GetErrorStr()); - pcre_free(rx); + pcre2_code_free(rx); return FnReturn("0"); } @@ -3388,7 +3388,7 @@ static FnCallResult FnCallCountLinesMatching(ARG_UNUSED EvalContext *ctx, ARG_UN free(line); } - pcre_free(rx); + pcre2_code_free(rx); if (!feof(fin)) { @@ -4844,7 +4844,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, bool invert, long max) { - pcre *rx = NULL; + pcre2_code *rx = NULL; if (do_regex) { rx = CompileRegex(regex); @@ -4860,7 +4860,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, // we failed to produce a valid JsonElement, so give up if (json == NULL) { - pcre_free(rx); + pcre2_code_free(rx); return FnFailure(); } else if (JsonGetElementType(json) != JSON_ELEMENT_TYPE_CONTAINER) @@ -4868,7 +4868,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, Log(LOG_LEVEL_VERBOSE, "Function '%s', argument '%s' was not a data container or list", fp->name, RlistScalarValueSafe(rp)); JsonDestroyMaybe(json, allocated); - pcre_free(rx); + pcre2_code_free(rx); return FnFailure(); } @@ -4923,7 +4923,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, if (rx) { - pcre_free(rx); + pcre2_code_free(rx); } bool contextmode = false; @@ -6408,7 +6408,7 @@ static FnCallResult FnCallRegExtract(EvalContext *ctx, ARG_UNUSED const Policy * static FnCallResult FnCallRegLine(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs) { - pcre *rx = CompileRegex(RlistScalarValue(finalargs)); + pcre2_code *rx = CompileRegex(RlistScalarValue(finalargs)); if (!rx) { return FnFailure(); @@ -6419,7 +6419,7 @@ static FnCallResult FnCallRegLine(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const FILE *fin = safe_fopen(arg_filename, "rt"); if (!fin) { - pcre_free(rx); + pcre2_code_free(rx); return FnReturnContext(false); } @@ -6432,12 +6432,12 @@ static FnCallResult FnCallRegLine(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const { free(line); fclose(fin); - pcre_free(rx); + pcre2_code_free(rx); return FnReturnContext(true); } } - pcre_free(rx); + pcre2_code_free(rx); free(line); if (!feof(fin)) @@ -8237,7 +8237,7 @@ static char *StripPatterns(char *file_buffer, const char *pattern, const char *f return file_buffer; } - pcre *rx = CompileRegex(pattern); + pcre2_code *rx = CompileRegex(pattern); if (!rx) { return file_buffer; @@ -8268,7 +8268,7 @@ static char *StripPatterns(char *file_buffer, const char *pattern, const char *f } } - pcre_free(rx); + pcre2_code_free(rx); return file_buffer; } @@ -8904,7 +8904,7 @@ void ModuleProtocol(EvalContext *ctx, const char *command, const char *line, int content[0] != '\0') { /* Symbol ID without \200 to \377: */ - pcre *context_name_rx = CompileRegex("[a-zA-Z0-9_]+"); + pcre2_code *context_name_rx = CompileRegex("[a-zA-Z0-9_]+"); if (!context_name_rx) { Log(LOG_LEVEL_ERR, @@ -8923,7 +8923,7 @@ void ModuleProtocol(EvalContext *ctx, const char *command, const char *line, int if (context_name_rx) { - pcre_free(context_name_rx); + pcre2_code_free(context_name_rx); } } else if (sscanf(line + 1, "meta=%1024[^\n]", content) == 1 && diff --git a/libpromises/generic_agent.c b/libpromises/generic_agent.c index 187d3df7e4..d93301313d 100644 --- a/libpromises/generic_agent.c +++ b/libpromises/generic_agent.c @@ -49,7 +49,7 @@ #include #include #include -#include // pcre +#include // CompileRegex() #include #include #include @@ -2720,7 +2720,7 @@ void GenericAgentShowContextsFormatted(EvalContext *ctx, const char *regexp) Seq *seq = SeqNew(1000, free); - pcre *rx = CompileRegex(regexp); + pcre2_code *rx = CompileRegex(regexp); if (rx == NULL) { @@ -2750,7 +2750,7 @@ void GenericAgentShowContextsFormatted(EvalContext *ctx, const char *regexp) free(class_name); } - pcre_free(rx); + pcre2_code_free(rx); SeqSort(seq, StrCmpWrapper, NULL); @@ -2776,7 +2776,7 @@ void GenericAgentShowVariablesFormatted(EvalContext *ctx, const char *regexp) Seq *seq = SeqNew(2000, free); - pcre *rx = CompileRegex(regexp); + pcre2_code *rx = CompileRegex(regexp); if (rx == NULL) { @@ -2838,7 +2838,7 @@ void GenericAgentShowVariablesFormatted(EvalContext *ctx, const char *regexp) free(varname); } - pcre_free(rx); + pcre2_code_free(rx); SeqSort(seq, StrCmpWrapper, NULL); diff --git a/libpromises/item_lib.c b/libpromises/item_lib.c index 64c97da00d..ac17c03b09 100644 --- a/libpromises/item_lib.c +++ b/libpromises/item_lib.c @@ -875,7 +875,7 @@ bool DeleteItemGeneral(Item **list, const char *string, ItemMatchType type) return false; } - pcre *rx = NULL; + pcre2_code *rx = NULL; if (type == ITEM_MATCH_TYPE_REGEX_COMPLETE_NOT || type == ITEM_MATCH_TYPE_REGEX_COMPLETE) { @@ -947,7 +947,7 @@ bool DeleteItemGeneral(Item **list, const char *string, ItemMatchType type) free(ip); if (rx) { - pcre_free(rx); + pcre2_code_free(rx); } return true; @@ -960,7 +960,7 @@ bool DeleteItemGeneral(Item **list, const char *string, ItemMatchType type) if (rx) { - pcre_free(rx); + pcre2_code_free(rx); } return false; diff --git a/libpromises/match_scope.c b/libpromises/match_scope.c index 3f8980bdb3..e5739fb97a 100644 --- a/libpromises/match_scope.c +++ b/libpromises/match_scope.c @@ -31,19 +31,23 @@ /* Sets variables */ -static bool RegExMatchSubString(EvalContext *ctx, pcre *rx, const char *teststring, int *start, int *end) +static bool RegExMatchSubString(EvalContext *ctx, pcre2_code *regex, const char *teststring, int *start, int *end) { - int ovector[OVECCOUNT]; - int rc = 0; - - if ((rc = pcre_exec(rx, NULL, teststring, strlen(teststring), 0, 0, ovector, OVECCOUNT)) >= 0) + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL); + int result = pcre2_match(regex, (PCRE2_SPTR) teststring, PCRE2_ZERO_TERMINATED, + 0, 0, match_data, NULL); + /* pcre2_match() returns the highest capture group number + 1, i.e. 1 means + * a match with 0 capture groups. 0 means the vector of offsets is small, + * negative numbers are errors (incl. no match). */ + if (result > 0) { + size_t *ovector = pcre2_get_ovector_pointer(match_data); *start = ovector[0]; *end = ovector[1]; EvalContextVariableClearMatch(ctx); - for (int i = 0; i < rc; i++) /* make backref vars $(1),$(2) etc */ + for (int i = 0; i < result; i++) /* make backref vars $(1),$(2) etc */ { const char *backref_start = teststring + ovector[i * 2]; int backref_len = ovector[i * 2 + 1] - ovector[i * 2]; @@ -64,12 +68,13 @@ static bool RegExMatchSubString(EvalContext *ctx, pcre *rx, const char *teststri *end = 0; } - pcre_free(rx); - return rc >= 0; + pcre2_match_data_free(match_data); + pcre2_code_free(regex); + return result > 0; } /* Sets variables */ -static bool RegExMatchFullString(EvalContext *ctx, pcre *rx, const char *teststring) +static bool RegExMatchFullString(EvalContext *ctx, pcre2_code *rx, const char *teststring) { int match_start; int match_len; @@ -86,14 +91,12 @@ static bool RegExMatchFullString(EvalContext *ctx, pcre *rx, const char *teststr bool FullTextMatch(EvalContext *ctx, const char *regexp, const char *teststring) { - pcre *rx; - if (strcmp(regexp, teststring) == 0) { return true; } - rx = CompileRegex(regexp); + pcre2_code *rx = CompileRegex(regexp); if (rx == NULL) { return false; @@ -111,16 +114,16 @@ bool FullTextMatch(EvalContext *ctx, const char *regexp, const char *teststring) bool ValidateRegEx(const char *regex) { - pcre *rx = CompileRegex(regex); + pcre2_code *rx = CompileRegex(regex); bool regex_valid = rx != NULL; - pcre_free(rx); + pcre2_code_free(rx); return regex_valid; } bool BlockTextMatch(EvalContext *ctx, const char *regexp, const char *teststring, int *start, int *end) { - pcre *rx = CompileRegex(regexp); + pcre2_code *rx = CompileRegex(regexp); if (rx == NULL) { diff --git a/libpromises/matching.c b/libpromises/matching.c index 69692524b1..a168a61444 100644 --- a/libpromises/matching.c +++ b/libpromises/matching.c @@ -37,32 +37,32 @@ /* Pure, non-thread-safe */ -static char *FirstBackReference(pcre *rx, const char *teststring) +static char *FirstBackReference(pcre2_code *regex, const char *teststring) { static char backreference[CF_BUFSIZE]; /* GLOBAL_R, no initialization needed */ - - int ovector[OVECCOUNT], i, rc; - memset(backreference, 0, CF_BUFSIZE); - if ((rc = pcre_exec(rx, NULL, teststring, strlen(teststring), 0, 0, ovector, OVECCOUNT)) >= 0) + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL); + int result = pcre2_match(regex, (PCRE2_SPTR) teststring, PCRE2_ZERO_TERMINATED, + 0, 0, match_data, NULL); + /* pcre2_match() returns the highest capture group number + 1, i.e. 1 means + * a match with 0 capture groups. 0 means the vector of offsets is small, + * negative numbers are errors (incl. no match). */ + if (result > 0) { - for (i = 1; i < rc; i++) /* make backref vars $(1),$(2) etc */ + size_t *ovector = pcre2_get_ovector_pointer(match_data); + /* ovector[0] and ovector[1] are for the start and end of the whole + * match, the capture groups follow in [1] and [2], etc. */ + const char *backref_start = teststring + ovector[2]; + size_t backref_len = ovector[3] - ovector[2]; + if (backref_len < CF_MAXVARSIZE) { - const char *backref_start = teststring + ovector[i * 2]; - int backref_len = ovector[i * 2 + 1] - ovector[i * 2]; - - if (backref_len < CF_MAXVARSIZE) - { - strncpy(backreference, backref_start, backref_len); - } - - break; + strncpy(backreference, backref_start, backref_len); } } - free(rx); - + pcre2_match_data_free(match_data); + pcre2_code_free(regex); return backreference; } @@ -70,14 +70,12 @@ char *ExtractFirstReference(const char *regexp, const char *teststring) { char *backreference; - pcre *rx; - if ((regexp == NULL) || (teststring == NULL)) { return ""; } - rx = CompileRegex(regexp); + pcre2_code *rx = CompileRegex(regexp); if (rx == NULL) { return ""; diff --git a/libpromises/rlist.c b/libpromises/rlist.c index 022b5c2798..f69cee1b6f 100644 --- a/libpromises/rlist.c +++ b/libpromises/rlist.c @@ -241,7 +241,7 @@ bool RlistMatchesRegex(const Rlist *list, const char *regex) return false; } - pcre *rx = CompileRegex(regex); + pcre2_code *rx = CompileRegex(regex); if (!rx) { return false; @@ -252,12 +252,12 @@ bool RlistMatchesRegex(const Rlist *list, const char *regex) if (rp->val.type == RVAL_TYPE_SCALAR && StringMatchFullWithPrecompiledRegex(rx, RlistScalarValue(rp))) { - pcre_free(rx); + pcre2_code_free(rx); return true; } } - pcre_free(rx); + pcre2_code_free(rx); return false; } @@ -1168,7 +1168,7 @@ Rlist *RlistFromSplitRegex(const char *string, const char *regex, size_t max_ent Rlist *result = NULL; Buffer *buffer = BufferNewWithCapacity(CF_MAXVARSIZE); - pcre *rx = CompileRegex(regex); + pcre2_code *rx = CompileRegex(regex); if (rx) { while ((entry_count < max_entries) && @@ -1191,7 +1191,7 @@ Rlist *RlistFromSplitRegex(const char *string, const char *regex, size_t max_ent sp += end; } - pcre_free(rx); + pcre2_code_free(rx); } if (entry_count < max_entries) @@ -1231,7 +1231,7 @@ Rlist *RlistFromRegexSplitNoOverflow(const char *string, const char *regex, int const char *sp = string; // We will avoid compiling regex multiple times. - pcre *pattern = CompileRegex(regex); + pcre2_code *pattern = CompileRegex(regex); if (pattern == NULL) { @@ -1262,7 +1262,7 @@ Rlist *RlistFromRegexSplitNoOverflow(const char *string, const char *regex, int assert(count < max); RlistAppendScalar(&liststart, sp); - pcre_free(pattern); + pcre2_code_free(pattern); return liststart; } diff --git a/libpromises/verify_vars.c b/libpromises/verify_vars.c index f522278652..2d6f9feed1 100644 --- a/libpromises/verify_vars.c +++ b/libpromises/verify_vars.c @@ -61,7 +61,7 @@ static bool IsLegalVariableName(EvalContext *ctx, const Promise *pp) /* TODO: remove at some point (global, leaked), but for now * this offers an attractive speedup. */ - static pcre *rx = NULL; + static pcre2_code *rx = NULL; if (!rx) { /* \200-\377 is there for multibyte unicode characters */ diff --git a/tests/acceptance/25_cf-execd/Makefile.am b/tests/acceptance/25_cf-execd/Makefile.am index a17d8dc894..dd2290e1cf 100644 --- a/tests/acceptance/25_cf-execd/Makefile.am +++ b/tests/acceptance/25_cf-execd/Makefile.am @@ -29,11 +29,11 @@ AM_CPPFLAGS = \ -I$(srcdir)/../../../libcfnet \ -I$(srcdir)/../../../libenv \ -I$(srcdir)/../../../cf-execd \ - $(PCRE_CPPFLAGS) \ + $(PCRE2_CPPFLAGS) \ $(ENTERPRISE_CPPFLAGS) AM_CFLAGS = \ - $(PCRE_CFLAGS) \ + $(PCRE2_CFLAGS) \ $(OPENSSL_CFLAGS) \ $(ENTERPRISE_CFLAGS) diff --git a/tests/static-check/run.sh b/tests/static-check/run.sh index 9b47189ea2..b640ab1e9e 100755 --- a/tests/static-check/run.sh +++ b/tests/static-check/run.sh @@ -15,7 +15,7 @@ fi function create_image() { local c=$(buildah from -q $BASE_IMG) buildah run $c -- dnf -q -y install "@C Development Tools and Libraries" clang cppcheck which >/dev/null 2>&1 - buildah run $c -- dnf -q -y install pcre-devel openssl-devel libxml2-devel pam-devel lmdb-devel libacl-devel libyaml-devel curl-devel libvirt-devel >/dev/null 2>&1 + buildah run $c -- dnf -q -y install pcre-devel pcre2-devel openssl-devel libxml2-devel pam-devel lmdb-devel libacl-devel libyaml-devel curl-devel libvirt-devel >/dev/null 2>&1 buildah run $c -- dnf clean all >/dev/null 2>&1 buildah commit $c cfengine-static-checker-f$STATIC_CHECKS_FEDORA_VERSION >/dev/null 2>&1 echo $c diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 1cde4a8878..26c3b4c28c 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -67,7 +67,6 @@ libtest_la_LIBADD = ../../libntech/libcompat/libcompat.la check_LTLIBRARIES += libstr.la libstr_la_SOURCES = \ ../../libntech/libutils/buffer.c \ - ../../libntech/libutils/pcre_wrap.c \ ../../libntech/libutils/encode.c \ ../../libntech/libutils/logging.c \ ../../libntech/libutils/misc_lib.c \ diff --git a/tests/valgrind-check/Containerfile b/tests/valgrind-check/Containerfile index 9a0cebb92c..a0ef77c9f5 100644 --- a/tests/valgrind-check/Containerfile +++ b/tests/valgrind-check/Containerfile @@ -1,6 +1,6 @@ FROM ubuntu:22.04 AS build RUN DEBIAN_FRONTEND=noninteractive apt-get update -y -RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libssl-dev libxml2-dev libpam0g-dev liblmdb-dev libacl1-dev libpcre3 libpcre3-dev +RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libssl-dev libxml2-dev libpam0g-dev liblmdb-dev libacl1-dev libpcre2-dev RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3 git flex bison byacc automake make autoconf libtool valgrind COPY masterfiles masterfiles COPY core core From 65b08fa2f421a8511d4f65cc12811e74cc23240f Mon Sep 17 00:00:00 2001 From: Vratislav Podzimek Date: Mon, 11 Dec 2023 15:55:17 +0100 Subject: [PATCH 2/2] Use the new Regex type for compiled regular expressions Makes things nicer than using the PCRE2's `pcre2_code` type directly as it provides at least a little bit of abstraction. Introduced in NorthernTechHQ/libntech@8b678ccbc7010. Ticket: ENT-10629 Changelog: None --- cf-agent/verify_users_pam.c | 8 ++--- cf-execd/cf-execd-runner.c | 4 +-- libenv/unix_iface.c | 4 +-- libntech | 2 +- libpromises/cf3lex.l | 2 +- libpromises/class.c | 4 +-- libpromises/eval_context.c | 6 ++-- libpromises/evalfunction.c | 58 ++++++++++++++++++------------------- libpromises/generic_agent.c | 8 ++--- libpromises/item_lib.c | 6 ++-- libpromises/match_scope.c | 14 ++++----- libpromises/matching.c | 6 ++-- libpromises/rlist.c | 14 ++++----- libpromises/verify_vars.c | 2 +- 14 files changed, 69 insertions(+), 69 deletions(-) diff --git a/cf-agent/verify_users_pam.c b/cf-agent/verify_users_pam.c index 268b8d846f..c2769b85b0 100644 --- a/cf-agent/verify_users_pam.c +++ b/cf-agent/verify_users_pam.c @@ -147,8 +147,8 @@ static bool GetAIXShadowHash(const char *puser, const char **result) size_t puser_len = strlen(puser); char name_regex_str[strlen(puser) + 3]; - pcre2_code *name_regex = CompileRegex("^(\\S+):"); - pcre2_code *hash_regex = CompileRegex("^\\s+password\\s*=\\s*(\\S+)"); + Regex *name_regex = CompileRegex("^(\\S+):"); + Regex *hash_regex = CompileRegex("^\\s+password\\s*=\\s*(\\S+)"); bool in_user_section = false; while (true) @@ -198,8 +198,8 @@ static bool GetAIXShadowHash(const char *puser, const char **result) } end: - pcre2_code_free(name_regex); - pcre2_code_free(hash_regex); + RegexDestroy(name_regex); + RegexDestroy(hash_regex); free(buf); fclose(fptr); return ret; diff --git a/cf-execd/cf-execd-runner.c b/cf-execd/cf-execd-runner.c index c364043580..ab8ce0b12c 100644 --- a/cf-execd/cf-execd-runner.c +++ b/cf-execd/cf-execd-runner.c @@ -448,7 +448,7 @@ static bool CompareResultEqualOrFiltered(const ExecConfig *config, if (new_fp) { // Match timestamps and remove them. Not Y21K safe! :-) - pcre2_code *regex = CompileRegex(LOGGING_TIMESTAMP_REGEX); + Regex *regex = CompileRegex(LOGGING_TIMESTAMP_REGEX); if (!regex) { UnexpectedError("Compiling regular expression failed"); @@ -528,7 +528,7 @@ static bool CompareResultEqualOrFiltered(const ExecConfig *config, free(old_line); free(new_line); - pcre2_code_free(regex); + RegexDestroy(regex); } else { diff --git a/libenv/unix_iface.c b/libenv/unix_iface.c index 5f90da63ea..f9fa05d537 100644 --- a/libenv/unix_iface.c +++ b/libenv/unix_iface.c @@ -1297,7 +1297,7 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* { Log(LOG_LEVEL_VERBOSE, "Reading %s info from %s", key, filename); - pcre2_code *regex = CompileRegex(pattern); + Regex *regex = CompileRegex(pattern); if (regex != NULL) { size_t line_size = CF_BUFSIZE; @@ -1371,7 +1371,7 @@ JsonElement* GetProcFileInfo(EvalContext *ctx, const char* filename, const char* BufferDestroy(varname); } - pcre2_code_free(regex); + RegexDestroy(regex); } fclose(fin); diff --git a/libntech b/libntech index 0aefa4a3e8..1899478f19 160000 --- a/libntech +++ b/libntech @@ -1 +1 @@ -Subproject commit 0aefa4a3e861b7307732d4cccffb80f751f84bf8 +Subproject commit 1899478f1998755ff65a19b369b1c7b79f1b6982 diff --git a/libpromises/cf3lex.l b/libpromises/cf3lex.l index df30d0c9a4..bcbc9313b0 100644 --- a/libpromises/cf3lex.l +++ b/libpromises/cf3lex.l @@ -58,7 +58,7 @@ #define ParserDebug(...) ((void) 0) #define P PARSER_STATE -static pcre2_code *context_expression_whitespace_rx = NULL; +static Regex *context_expression_whitespace_rx = NULL; static int DeEscapeQuotedString(const char *from, char *to); diff --git a/libpromises/class.c b/libpromises/class.c index 94ce671f02..6b0e903a70 100644 --- a/libpromises/class.c +++ b/libpromises/class.c @@ -177,7 +177,7 @@ Class *ClassTableMatch(const ClassTable *table, const char *regex) ClassTableIterator *it = ClassTableIteratorNew(table, NULL, true, true); Class *cls = NULL; - pcre2_code *pattern = CompileRegex(regex); + Regex *pattern = CompileRegex(regex); if (pattern == NULL) { // TODO: perhaps pcre has can give more info on this error? @@ -205,7 +205,7 @@ Class *ClassTableMatch(const ClassTable *table, const char *regex) } } - pcre2_code_free(pattern); + RegexDestroy(pattern); ClassTableIteratorDestroy(it); return cls; diff --git a/libpromises/eval_context.c b/libpromises/eval_context.c index 527985a7ac..3918aec26e 100644 --- a/libpromises/eval_context.c +++ b/libpromises/eval_context.c @@ -110,7 +110,7 @@ TYPED_MAP_DEFINE(RemoteVarPromises, char *, Seq *, SeqDestroy_untyped) -static pcre2_code *context_expression_whitespace_rx = NULL; +static Regex *context_expression_whitespace_rx = NULL; #include @@ -3563,7 +3563,7 @@ StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, con { StringSet *matching = StringSetNew(); - pcre2_code *rx = CompileRegex(regex); + Regex *rx = CompileRegex(regex); Class *cls; while ((cls = ClassTableIteratorNext(iter))) @@ -3623,7 +3623,7 @@ StringSet *ClassesMatching(const EvalContext *ctx, ClassTableIterator *iter, con if (rx) { - pcre2_code_free(rx); + RegexDestroy(rx); } return matching; diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c index a61753a694..1d22460b80 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -1433,7 +1433,7 @@ static JsonElement *VariablesMatching(const EvalContext *ctx, const FnCall *fp, JsonElement *matching = JsonObjectCreate(10); const char *regex = RlistScalarValue(args); - pcre2_code *rx = CompileRegex(regex); + Regex *rx = CompileRegex(regex); Variable *v = NULL; while ((v = VariableTableIteratorNext(iter))) @@ -1507,7 +1507,7 @@ static JsonElement *VariablesMatching(const EvalContext *ctx, const FnCall *fp, if (rx) { - pcre2_code_free(rx); + RegexDestroy(rx); } return matching; @@ -1681,7 +1681,7 @@ static FnCallResult FnCallBundlesMatching(EvalContext *ctx, const Policy *policy } const char *regex = RlistScalarValue(finalargs); - pcre2_code *rx = CompileRegex(regex); + Regex *rx = CompileRegex(regex); if (!rx) { return FnFailure(); @@ -1744,14 +1744,14 @@ static FnCallResult FnCallBundlesMatching(EvalContext *ctx, const Policy *policy free(bundle_name); } - pcre2_code_free(rx); + RegexDestroy(rx); return (FnCallResult) { FNCALL_SUCCESS, { matches, RVAL_TYPE_LIST } }; } /*********************************************************************/ -static bool AddPackagesMatchingJsonLine(pcre2_code *matcher, JsonElement *json, char *line) +static bool AddPackagesMatchingJsonLine(Regex *matcher, JsonElement *json, char *line) { const size_t line_length = strlen(line); if (line_length > CF_BUFSIZE - 80) @@ -1788,7 +1788,7 @@ static bool AddPackagesMatchingJsonLine(pcre2_code *matcher, JsonElement *json, return true; } -static bool GetLegacyPackagesMatching(pcre2_code *matcher, JsonElement *json, const bool installed_mode) +static bool GetLegacyPackagesMatching(Regex *matcher, JsonElement *json, const bool installed_mode) { char filename[CF_MAXVARSIZE]; if (installed_mode) @@ -1836,7 +1836,7 @@ static bool GetLegacyPackagesMatching(pcre2_code *matcher, JsonElement *json, co return ret; } -static bool GetPackagesMatching(pcre2_code *matcher, JsonElement *json, const bool installed_mode, Rlist *default_inventory) +static bool GetPackagesMatching(Regex *matcher, JsonElement *json, const bool installed_mode, Rlist *default_inventory) { dbid database = (installed_mode == true ? dbid_packages_installed : dbid_packages_updates); @@ -1932,7 +1932,7 @@ static bool GetPackagesMatching(pcre2_code *matcher, JsonElement *json, const bo static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs) { const bool installed_mode = (strcmp(fp->name, "packagesmatching") == 0); - pcre2_code *matcher; + Regex *matcher; { const char *regex_package = RlistScalarValue(finalargs); const char *regex_version = RlistScalarValue(finalargs->next); @@ -1998,7 +1998,7 @@ static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUS else { Log(LOG_LEVEL_DEBUG, "No valid package module inventory found"); - pcre2_code_free(matcher); + RegexDestroy(matcher); JsonDestroy(json); if (inventory_allocated) { @@ -2012,7 +2012,7 @@ static FnCallResult FnCallPackagesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUS { RlistDestroy(default_inventory); } - pcre2_code_free(matcher); + RegexDestroy(matcher); if (ret == false) { @@ -3262,7 +3262,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, const FnCall *fp, const Rlist *finalargs) { - pcre2_code *rx = CompileRegex(RlistScalarValue(finalargs)); + Regex *rx = CompileRegex(RlistScalarValue(finalargs)); if (!rx) { return FnFailure(); @@ -3276,7 +3276,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, if (!fin) { Log(LOG_LEVEL_ERR, "File '%s' could not be read in getfields(). (fopen: %s)", filename, GetErrorStr()); - pcre2_code_free(rx); + RegexDestroy(rx); return FnFailure(); } @@ -3318,7 +3318,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, VarRefDestroy(ref); free(line); RlistDestroy(newlist); - pcre2_code_free(rx); + RegexDestroy(rx); return FnFailure(); } } @@ -3335,7 +3335,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, line_count++; } - pcre2_code_free(rx); + RegexDestroy(rx); free(line); if (!feof(fin)) @@ -3354,7 +3354,7 @@ static FnCallResult FnCallGetFields(EvalContext *ctx, static FnCallResult FnCallCountLinesMatching(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, ARG_UNUSED const FnCall *fp, const Rlist *finalargs) { - pcre2_code *rx = CompileRegex(RlistScalarValue(finalargs)); + Regex *rx = CompileRegex(RlistScalarValue(finalargs)); if (!rx) { return FnFailure(); @@ -3366,7 +3366,7 @@ static FnCallResult FnCallCountLinesMatching(ARG_UNUSED EvalContext *ctx, ARG_UN if (!fin) { Log(LOG_LEVEL_ERR, "File '%s' could not be read in countlinesmatching(). (fopen: %s)", filename, GetErrorStr()); - pcre2_code_free(rx); + RegexDestroy(rx); return FnReturn("0"); } @@ -3388,7 +3388,7 @@ static FnCallResult FnCallCountLinesMatching(ARG_UNUSED EvalContext *ctx, ARG_UN free(line); } - pcre2_code_free(rx); + RegexDestroy(rx); if (!feof(fin)) { @@ -4844,7 +4844,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, bool invert, long max) { - pcre2_code *rx = NULL; + Regex *rx = NULL; if (do_regex) { rx = CompileRegex(regex); @@ -4860,7 +4860,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, // we failed to produce a valid JsonElement, so give up if (json == NULL) { - pcre2_code_free(rx); + RegexDestroy(rx); return FnFailure(); } else if (JsonGetElementType(json) != JSON_ELEMENT_TYPE_CONTAINER) @@ -4868,7 +4868,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, Log(LOG_LEVEL_VERBOSE, "Function '%s', argument '%s' was not a data container or list", fp->name, RlistScalarValueSafe(rp)); JsonDestroyMaybe(json, allocated); - pcre2_code_free(rx); + RegexDestroy(rx); return FnFailure(); } @@ -4923,7 +4923,7 @@ static FnCallResult FilterInternal(EvalContext *ctx, if (rx) { - pcre2_code_free(rx); + RegexDestroy(rx); } bool contextmode = false; @@ -6408,7 +6408,7 @@ static FnCallResult FnCallRegExtract(EvalContext *ctx, ARG_UNUSED const Policy * static FnCallResult FnCallRegLine(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const Policy *policy, const FnCall *fp, const Rlist *finalargs) { - pcre2_code *rx = CompileRegex(RlistScalarValue(finalargs)); + Regex *rx = CompileRegex(RlistScalarValue(finalargs)); if (!rx) { return FnFailure(); @@ -6419,7 +6419,7 @@ static FnCallResult FnCallRegLine(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const FILE *fin = safe_fopen(arg_filename, "rt"); if (!fin) { - pcre2_code_free(rx); + RegexDestroy(rx); return FnReturnContext(false); } @@ -6432,12 +6432,12 @@ static FnCallResult FnCallRegLine(ARG_UNUSED EvalContext *ctx, ARG_UNUSED const { free(line); fclose(fin); - pcre2_code_free(rx); + RegexDestroy(rx); return FnReturnContext(true); } } - pcre2_code_free(rx); + RegexDestroy(rx); free(line); if (!feof(fin)) @@ -8237,7 +8237,7 @@ static char *StripPatterns(char *file_buffer, const char *pattern, const char *f return file_buffer; } - pcre2_code *rx = CompileRegex(pattern); + Regex *rx = CompileRegex(pattern); if (!rx) { return file_buffer; @@ -8268,7 +8268,7 @@ static char *StripPatterns(char *file_buffer, const char *pattern, const char *f } } - pcre2_code_free(rx); + RegexDestroy(rx); return file_buffer; } @@ -8904,7 +8904,7 @@ void ModuleProtocol(EvalContext *ctx, const char *command, const char *line, int content[0] != '\0') { /* Symbol ID without \200 to \377: */ - pcre2_code *context_name_rx = CompileRegex("[a-zA-Z0-9_]+"); + Regex *context_name_rx = CompileRegex("[a-zA-Z0-9_]+"); if (!context_name_rx) { Log(LOG_LEVEL_ERR, @@ -8923,7 +8923,7 @@ void ModuleProtocol(EvalContext *ctx, const char *command, const char *line, int if (context_name_rx) { - pcre2_code_free(context_name_rx); + RegexDestroy(context_name_rx); } } else if (sscanf(line + 1, "meta=%1024[^\n]", content) == 1 && diff --git a/libpromises/generic_agent.c b/libpromises/generic_agent.c index d93301313d..4647ad7e87 100644 --- a/libpromises/generic_agent.c +++ b/libpromises/generic_agent.c @@ -2720,7 +2720,7 @@ void GenericAgentShowContextsFormatted(EvalContext *ctx, const char *regexp) Seq *seq = SeqNew(1000, free); - pcre2_code *rx = CompileRegex(regexp); + Regex *rx = CompileRegex(regexp); if (rx == NULL) { @@ -2750,7 +2750,7 @@ void GenericAgentShowContextsFormatted(EvalContext *ctx, const char *regexp) free(class_name); } - pcre2_code_free(rx); + RegexDestroy(rx); SeqSort(seq, StrCmpWrapper, NULL); @@ -2776,7 +2776,7 @@ void GenericAgentShowVariablesFormatted(EvalContext *ctx, const char *regexp) Seq *seq = SeqNew(2000, free); - pcre2_code *rx = CompileRegex(regexp); + Regex *rx = CompileRegex(regexp); if (rx == NULL) { @@ -2838,7 +2838,7 @@ void GenericAgentShowVariablesFormatted(EvalContext *ctx, const char *regexp) free(varname); } - pcre2_code_free(rx); + RegexDestroy(rx); SeqSort(seq, StrCmpWrapper, NULL); diff --git a/libpromises/item_lib.c b/libpromises/item_lib.c index ac17c03b09..d9ad53b598 100644 --- a/libpromises/item_lib.c +++ b/libpromises/item_lib.c @@ -875,7 +875,7 @@ bool DeleteItemGeneral(Item **list, const char *string, ItemMatchType type) return false; } - pcre2_code *rx = NULL; + Regex *rx = NULL; if (type == ITEM_MATCH_TYPE_REGEX_COMPLETE_NOT || type == ITEM_MATCH_TYPE_REGEX_COMPLETE) { @@ -947,7 +947,7 @@ bool DeleteItemGeneral(Item **list, const char *string, ItemMatchType type) free(ip); if (rx) { - pcre2_code_free(rx); + RegexDestroy(rx); } return true; @@ -960,7 +960,7 @@ bool DeleteItemGeneral(Item **list, const char *string, ItemMatchType type) if (rx) { - pcre2_code_free(rx); + RegexDestroy(rx); } return false; diff --git a/libpromises/match_scope.c b/libpromises/match_scope.c index e5739fb97a..51142bf74d 100644 --- a/libpromises/match_scope.c +++ b/libpromises/match_scope.c @@ -31,7 +31,7 @@ /* Sets variables */ -static bool RegExMatchSubString(EvalContext *ctx, pcre2_code *regex, const char *teststring, int *start, int *end) +static bool RegExMatchSubString(EvalContext *ctx, Regex *regex, const char *teststring, int *start, int *end) { pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL); int result = pcre2_match(regex, (PCRE2_SPTR) teststring, PCRE2_ZERO_TERMINATED, @@ -69,12 +69,12 @@ static bool RegExMatchSubString(EvalContext *ctx, pcre2_code *regex, const char } pcre2_match_data_free(match_data); - pcre2_code_free(regex); + RegexDestroy(regex); return result > 0; } /* Sets variables */ -static bool RegExMatchFullString(EvalContext *ctx, pcre2_code *rx, const char *teststring) +static bool RegExMatchFullString(EvalContext *ctx, Regex *rx, const char *teststring) { int match_start; int match_len; @@ -96,7 +96,7 @@ bool FullTextMatch(EvalContext *ctx, const char *regexp, const char *teststring) return true; } - pcre2_code *rx = CompileRegex(regexp); + Regex *rx = CompileRegex(regexp); if (rx == NULL) { return false; @@ -114,16 +114,16 @@ bool FullTextMatch(EvalContext *ctx, const char *regexp, const char *teststring) bool ValidateRegEx(const char *regex) { - pcre2_code *rx = CompileRegex(regex); + Regex *rx = CompileRegex(regex); bool regex_valid = rx != NULL; - pcre2_code_free(rx); + RegexDestroy(rx); return regex_valid; } bool BlockTextMatch(EvalContext *ctx, const char *regexp, const char *teststring, int *start, int *end) { - pcre2_code *rx = CompileRegex(regexp); + Regex *rx = CompileRegex(regexp); if (rx == NULL) { diff --git a/libpromises/matching.c b/libpromises/matching.c index a168a61444..5d0135470f 100644 --- a/libpromises/matching.c +++ b/libpromises/matching.c @@ -37,7 +37,7 @@ /* Pure, non-thread-safe */ -static char *FirstBackReference(pcre2_code *regex, const char *teststring) +static char *FirstBackReference(Regex *regex, const char *teststring) { static char backreference[CF_BUFSIZE]; /* GLOBAL_R, no initialization needed */ memset(backreference, 0, CF_BUFSIZE); @@ -62,7 +62,7 @@ static char *FirstBackReference(pcre2_code *regex, const char *teststring) } pcre2_match_data_free(match_data); - pcre2_code_free(regex); + RegexDestroy(regex); return backreference; } @@ -75,7 +75,7 @@ char *ExtractFirstReference(const char *regexp, const char *teststring) return ""; } - pcre2_code *rx = CompileRegex(regexp); + Regex *rx = CompileRegex(regexp); if (rx == NULL) { return ""; diff --git a/libpromises/rlist.c b/libpromises/rlist.c index f69cee1b6f..ac4e750b81 100644 --- a/libpromises/rlist.c +++ b/libpromises/rlist.c @@ -241,7 +241,7 @@ bool RlistMatchesRegex(const Rlist *list, const char *regex) return false; } - pcre2_code *rx = CompileRegex(regex); + Regex *rx = CompileRegex(regex); if (!rx) { return false; @@ -252,12 +252,12 @@ bool RlistMatchesRegex(const Rlist *list, const char *regex) if (rp->val.type == RVAL_TYPE_SCALAR && StringMatchFullWithPrecompiledRegex(rx, RlistScalarValue(rp))) { - pcre2_code_free(rx); + RegexDestroy(rx); return true; } } - pcre2_code_free(rx); + RegexDestroy(rx); return false; } @@ -1168,7 +1168,7 @@ Rlist *RlistFromSplitRegex(const char *string, const char *regex, size_t max_ent Rlist *result = NULL; Buffer *buffer = BufferNewWithCapacity(CF_MAXVARSIZE); - pcre2_code *rx = CompileRegex(regex); + Regex *rx = CompileRegex(regex); if (rx) { while ((entry_count < max_entries) && @@ -1191,7 +1191,7 @@ Rlist *RlistFromSplitRegex(const char *string, const char *regex, size_t max_ent sp += end; } - pcre2_code_free(rx); + RegexDestroy(rx); } if (entry_count < max_entries) @@ -1231,7 +1231,7 @@ Rlist *RlistFromRegexSplitNoOverflow(const char *string, const char *regex, int const char *sp = string; // We will avoid compiling regex multiple times. - pcre2_code *pattern = CompileRegex(regex); + Regex *pattern = CompileRegex(regex); if (pattern == NULL) { @@ -1262,7 +1262,7 @@ Rlist *RlistFromRegexSplitNoOverflow(const char *string, const char *regex, int assert(count < max); RlistAppendScalar(&liststart, sp); - pcre2_code_free(pattern); + RegexDestroy(pattern); return liststart; } diff --git a/libpromises/verify_vars.c b/libpromises/verify_vars.c index 2d6f9feed1..7134e94da8 100644 --- a/libpromises/verify_vars.c +++ b/libpromises/verify_vars.c @@ -61,7 +61,7 @@ static bool IsLegalVariableName(EvalContext *ctx, const Promise *pp) /* TODO: remove at some point (global, leaked), but for now * this offers an attractive speedup. */ - static pcre2_code *rx = NULL; + static Regex *rx = NULL; if (!rx) { /* \200-\377 is there for multibyte unicode characters */