URL: https://github.com/SSSD/sssd/pull/677
Author: thalman
 Title: #677: pcre: port to pcre2
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/677/head:pr677
git checkout pr677
From c3341d33f6568cf404d0a83e95abb1341d89219d Mon Sep 17 00:00:00 2001
From: Tomas Halman <thal...@redhat.com>
Date: Mon, 15 Oct 2018 15:13:38 +0200
Subject: [PATCH] pcre: port to pcre2

Some distributions want to drop pcre support. Sssd should work with
pcre2. With this patch sssd tries to use pcre2 if pcre is not present.

Resolves:
https://pagure.io/SSSD/sssd/issue/3833
---
 Makefile.am                      |   2 +
 src/external/libpcre.m4          |  46 ++++++-
 src/providers/krb5/krb5_auth.h   |   2 +-
 src/providers/krb5/krb5_common.h |   2 +-
 src/providers/krb5/krb5_init.c   |  19 +--
 src/providers/krb5/krb5_utils.c  |  12 +-
 src/providers/krb5/krb5_utils.h  |   2 +-
 src/responder/common/responder.h |   2 +-
 src/tests/krb5_child-test.c      |  18 +--
 src/tests/krb5_utils-tests.c     |  13 +-
 src/util/sss_regexp.c            | 215 +++++++++++++++++++++++++++++++
 src/util/sss_regexp.h            |  96 ++++++++++++++
 src/util/usertools.c             |  50 ++-----
 src/util/util.h                  |   4 +-
 14 files changed, 390 insertions(+), 93 deletions(-)
 create mode 100644 src/util/sss_regexp.c
 create mode 100644 src/util/sss_regexp.h

diff --git a/Makefile.am b/Makefile.am
index 3667856c68..1df2c0833e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -662,6 +662,7 @@ dist_noinst_HEADERS = \
     src/util/sss_nss.h \
     src/util/sss_ldap.h \
     src/util/sss_python.h \
+    src/util/sss_regexp.h \
     src/util/sss_krb5.h \
     src/util/sss_selinux.h \
     src/util/sss_sockets.h \
@@ -1265,6 +1266,7 @@ libsss_util_la_SOURCES = \
     src/util/sss_ptr_hash.c \
     src/util/files.c \
     src/util/selinux.c \
+    src/util/sss_regexp.c \
     $(NULL)
 libsss_util_la_CFLAGS = \
     $(AM_CFLAGS) \
diff --git a/src/external/libpcre.m4 b/src/external/libpcre.m4
index 2326cbf864..bb53a47b68 100644
--- a/src/external/libpcre.m4
+++ b/src/external/libpcre.m4
@@ -1,13 +1,45 @@
 AC_SUBST(PCRE_LIBS)
 AC_SUBST(PCRE_CFLAGS)
 
-PKG_CHECK_MODULES([PCRE], [libpcre], [found_libpcre=yes], [found_libpcre=no])
-PKG_CHECK_EXISTS(libpcre >= 7,
-                 [AC_MSG_NOTICE([PCRE version is 7 or higher])],
-                 [AC_MSG_NOTICE([PCRE version is below 7])
-                  AC_DEFINE([HAVE_LIBPCRE_LESSER_THAN_7],
-                            1,
-                            [Define if libpcre version is less than 7])])
+PKG_CHECK_MODULES(
+    [PCRE],
+    [libpcre],
+    [
+        found_libpcre=yes
+        PKG_CHECK_EXISTS(
+            libpcre >= 7,
+            [AC_MSG_NOTICE([PCRE version is 7 or higher])],
+            [
+                AC_MSG_NOTICE([PCRE version is below 7])
+                AC_DEFINE(
+                    [HAVE_LIBPCRE_LESSER_THAN_7],
+                    1,
+                    [Define if libpcre version is less than 7]
+                )
+            ]
+        )
+    ],
+    [
+        PKG_CHECK_MODULES(
+            [PCRE2],
+            [libpcre2-8],
+            [
+                found_libpcre=yes
+                AC_DEFINE(
+                    [HAVE_LIBPCRE2],
+                    1,
+                    [Define if libpcre2 is present]
+                )
+                AC_DEFINE(
+                    [PCRE2_CODE_UNIT_WIDTH],
+                    8,
+                    [Define libpcre2 unit size]
+                )
+            ],
+            [found_libpcre=no]
+        )
+    ]
+)
 
 SSS_AC_EXPAND_LIB_DIR()
 AS_IF([test x"$found_libpcre" != xyes],
diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h
index 847fbf52b8..c706625f6f 100644
--- a/src/providers/krb5/krb5_auth.h
+++ b/src/providers/krb5/krb5_auth.h
@@ -26,8 +26,8 @@
 #ifndef __KRB5_AUTH_H__
 #define __KRB5_AUTH_H__
 
-#include <pcre.h>
 
+#include "util/sss_regexp.h"
 #include "util/sss_krb5.h"
 #include "providers/backend.h"
 #include "util/child_common.h"
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
index bf36a551a9..4b27f166ac 100644
--- a/src/providers/krb5/krb5_common.h
+++ b/src/providers/krb5/krb5_common.h
@@ -121,7 +121,7 @@ struct krb5_ctx {
     struct krb5_service *kpasswd_service;
     int child_debug_fd;
 
-    pcre *illegal_path_re;
+    sss_regexp_t *illegal_path_re;
 
     struct deferred_auth_ctx *deferred_auth_ctx;
     struct renew_tgt_ctx *renew_tgt_ctx;
diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c
index 66ae68fb47..5f956b88e7 100644
--- a/src/providers/krb5/krb5_init.c
+++ b/src/providers/krb5/krb5_init.c
@@ -108,16 +108,6 @@ static errno_t krb5_init_kdc(struct krb5_ctx *ctx, struct be_ctx *be_ctx)
     return EOK;
 }
 
-int krb5_ctx_re_destructor(struct krb5_ctx *ctx)
-{
-    if (ctx->illegal_path_re != NULL) {
-        pcre_free(ctx->illegal_path_re);
-        ctx->illegal_path_re = NULL;
-    }
-
-    return 0;
-}
-
 errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx,
                        struct be_ctx *be_ctx,
                        struct data_provider *provider,
@@ -127,7 +117,7 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx,
     struct krb5_ctx *ctx;
     const char *errstr;
     int errval;
-    int errpos;
+    size_t errpos;
     errno_t ret;
 
     ctx = talloc_zero(mem_ctx, struct krb5_ctx);
@@ -166,15 +156,14 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    ctx->illegal_path_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
-                                         &errval, &errstr, &errpos, NULL);
+    ctx->illegal_path_re = sss_regexp_new(ctx, ILLEGAL_PATH_PATTERN, 0,
+                                          &errval, &errstr, &errpos);
     if (ctx->illegal_path_re == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid Regular Expression pattern "
-              "at position %d. (Error: %d [%s])\n", errpos, errval, errstr);
+              "at position %zu. (Error: %d [%s])\n", errpos, errval, errstr);
         ret = EFAULT;
         goto done;
     }
-    talloc_set_destructor(ctx, krb5_ctx_re_destructor);
 
     ret = be_fo_set_dns_srv_lookup_plugin(be_ctx, NULL);
     if (ret != EOK) {
diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
index 1389596b37..e3f8f2140e 100644
--- a/src/providers/krb5/krb5_utils.c
+++ b/src/providers/krb5/krb5_utils.c
@@ -203,29 +203,29 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
 #define L_EXP_USERNAME (sizeof(S_EXP_USERNAME) - 1)
 
 static errno_t
-check_ccache_re(const char *filename, pcre *illegal_re)
+check_ccache_re(const char *filename, sss_regexp_t *illegal_re)
 {
     errno_t ret;
 
-    ret = pcre_exec(illegal_re, NULL, filename, strlen(filename),
-                    0, 0, NULL, 0);
+    ret = sss_regexp_match(illegal_re, filename, 0, 0);
+
     if (ret == 0) {
         DEBUG(SSSDBG_OP_FAILURE,
               "Illegal pattern in ccache directory name [%s].\n", filename);
         return EINVAL;
-    } else if (ret == PCRE_ERROR_NOMATCH) {
+    } else if (ret == SSS_REGEXP_ERROR_NOMATCH) {
         DEBUG(SSSDBG_TRACE_LIBS,
               "Ccache directory name [%s] does not contain "
                "illegal patterns.\n", filename);
         return EOK;
     }
 
-    DEBUG(SSSDBG_CRIT_FAILURE, "pcre_exec failed [%d].\n", ret);
+    DEBUG(SSSDBG_CRIT_FAILURE, "regexp match failed [%d].\n", ret);
     return EFAULT;
 }
 
 char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
-                             const char *template, pcre *illegal_re,
+                             const char *template, sss_regexp_t *illegal_re,
                              bool file_mode, bool case_sensitive)
 {
     char *copy;
diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
index 3051a99445..473006b9cf 100644
--- a/src/providers/krb5/krb5_utils.h
+++ b/src/providers/krb5/krb5_utils.h
@@ -43,7 +43,7 @@ errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb,
                                          const char *upn);
 
 char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
-                             const char *template, pcre *illegal_re,
+                             const char *template, sss_regexp_t *illegal_re,
                              bool file_mode, bool case_sensitive);
 
 errno_t get_domain_or_subdomain(struct be_ctx *be_ctx,
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 06945345fb..a843fdc810 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -26,13 +26,13 @@
 
 #include <stdint.h>
 #include <sys/un.h>
-#include <pcre.h>
 #include <sys/resource.h>
 #include <talloc.h>
 #include <tevent.h>
 #include <ldb.h>
 #include <dhash.h>
 
+#include "util/sss_regexp.h"
 #include "sss_iface/sss_iface_async.h"
 #include "responder/common/negcache.h"
 #include "sss_client/sss_cli.h"
diff --git a/src/tests/krb5_child-test.c b/src/tests/krb5_child-test.c
index ec8182647a..c27846248e 100644
--- a/src/tests/krb5_child-test.c
+++ b/src/tests/krb5_child-test.c
@@ -82,39 +82,27 @@ setup_krb5_child_test(TALLOC_CTX *mem_ctx, struct krb5_child_test_ctx **_ctx)
     return EOK;
 }
 
-int re_destructor(void *memctx)
-{
-    struct krb5_ctx *ctx = (struct krb5_ctx *) memctx;
-
-    if (ctx->illegal_path_re) {
-        pcre_free(ctx->illegal_path_re);
-        ctx->illegal_path_re = NULL;
-    }
-    return 0;
-}
-
 static struct krb5_ctx *
 create_dummy_krb5_ctx(TALLOC_CTX *mem_ctx, const char *realm)
 {
     struct krb5_ctx *krb5_ctx;
     const char *errstr;
     int errval;
-    int errpos;
+    size_t errpos;
     int i;
     errno_t ret;
 
     krb5_ctx = talloc_zero(mem_ctx, struct krb5_ctx);
     if (!krb5_ctx) return NULL;
 
-    krb5_ctx->illegal_path_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
-                                        &errval, &errstr, &errpos, NULL);
+    krb5_ctx->illegal_path_re = sss_regexp_new(krb5_ctx, ILLEGAL_PATH_PATTERN, 0,
+                                               &errval, &errstr, &errpos);
     if (krb5_ctx->illegal_path_re == NULL) {
         DEBUG(SSSDBG_OP_FAILURE,
               "Invalid Regular Expression pattern at position %d. "
                "(Error: %d [%s])\n", errpos, errval, errstr);
         goto fail;
     }
-    talloc_set_destructor((TALLOC_CTX *) krb5_ctx, re_destructor);
 
     /* Kerberos options */
     krb5_ctx->opts = talloc_zero_array(krb5_ctx, struct dp_option, KRB5_OPTS);
diff --git a/src/tests/krb5_utils-tests.c b/src/tests/krb5_utils-tests.c
index 2210d65561..2f5db18e6a 100644
--- a/src/tests/krb5_utils-tests.c
+++ b/src/tests/krb5_utils-tests.c
@@ -191,16 +191,16 @@ START_TEST(test_illegal_patterns)
     char *cwd;
     char *dirname;
     char *filename;
-    pcre *illegal_re;
+    sss_regexp_t *illegal_re;
     const char *errstr;
     int errval;
-    int errpos;
+    size_t errpos;
     char *result = NULL;
 
-    illegal_re = pcre_compile2(ILLEGAL_PATH_PATTERN, 0,
-                               &errval, &errstr, &errpos, NULL);
+    illegal_re = sss_regexp_new(NULL, ILLEGAL_PATH_PATTERN, 0,
+                                &errval, &errstr, &errpos);
     fail_unless(illegal_re != NULL, "Invalid Regular Expression pattern at "
-                                    " position %d. (Error: %d [%s])\n",
+                                    " position %zu. (Error: %d [%s])\n",
                                     errpos, errval, errstr);
 
     cwd = getcwd(NULL, 0);
@@ -233,7 +233,7 @@ START_TEST(test_illegal_patterns)
                                 "illegal pattern '//' in filename [%s].",
                                 filename);
 
-    pcre_free(illegal_re);
+    talloc_free(illegal_re);
 }
 END_TEST
 
@@ -816,4 +816,3 @@ int main(int argc, const char *argv[])
 
     return EXIT_FAILURE;
 }
-
diff --git a/src/util/sss_regexp.c b/src/util/sss_regexp.c
new file mode 100644
index 0000000000..a2ce496a3c
--- /dev/null
+++ b/src/util/sss_regexp.c
@@ -0,0 +1,215 @@
+/*
+    SSSD
+
+    Authors:
+        Tomas Halman <thal...@redhat.com>
+
+    Copyright (C) 2018 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/sss_regexp.h"
+#include <string.h>
+
+#define SSS_REGEXP_OVEC_SIZE 30
+#define SSS_REGEXP_ERR_MSG_SIZE 120 /* 120 is recomended by pcre2 doc */
+
+#ifdef HAVE_LIBPCRE2
+/*
+ * sss_regexp with pcre2
+ */
+struct _sss_regexp_t {
+    pcre2_code *re;
+    unsigned char *error_msg;
+    pcre2_match_data *match_data;
+    char *matched_string;
+};
+
+int sss_regexp_pcre2_destroy(sss_regexp_t *self)
+{
+    if (self->re) pcre2_code_free(self->re);
+    if (self->error_msg) free (self->error_msg);
+    if (self->match_data) pcre2_match_data_free(self->match_data);
+    if (self->matched_string) pcre2_substring_free((PCRE2_UCHAR *)self->matched_string);
+    return 0;
+}
+
+void sss_regexp_pcre2_compile(sss_regexp_t *self,
+                              const char *pattern,
+                              int options,
+                              int *errorcodeptr,
+                              const char **errormsgptr,
+                              size_t *erroffset)
+{
+    self->re = pcre2_compile((PCRE2_SPTR)pattern, strlen(pattern), options, errorcodeptr, erroffset, NULL);
+    self->error_msg = malloc(SSS_REGEXP_ERR_MSG_SIZE);
+    if (self->re && self->error_msg) {
+        pcre2_get_error_message(*errorcodeptr, self->error_msg, SSS_REGEXP_ERR_MSG_SIZE);
+    }
+}
+
+int sss_regexp_pcre2_match(sss_regexp_t *self,
+                           const char *subject,
+                           int startoffset,
+                           int options)
+{
+    if (self->match_data) pcre2_match_data_free(self->match_data);
+    self->match_data = pcre2_match_data_create_from_pattern(self->re, NULL);
+    return pcre2_match(self->re, (PCRE2_SPTR)subject, strlen(subject), startoffset, options, self->match_data, NULL);
+}
+
+int sss_regexp_pcre2_get_named_substring(sss_regexp_t *self,
+                                         const char *name,
+                                         const char **value)
+{
+    PCRE2_SIZE length;
+
+    if (self->matched_string) {
+        pcre2_substring_free((PCRE2_UCHAR *)(self->matched_string));
+        self->matched_string = NULL;
+    }
+    int rc = pcre2_substring_get_byname(self->match_data, (PCRE2_SPTR)name, (PCRE2_UCHAR **) &self->matched_string, &length);
+    *value = self->matched_string;
+    return rc;
+}
+
+#else /* HAVE_LIBPCRE2 */
+/*
+ * sss_regexp with pcre
+ */
+struct _sss_regexp_t {
+    pcre *re;
+    int ovector[SSS_REGEXP_OVEC_SIZE];
+    const char *matched_string;
+    const char *subject;
+};
+
+int sss_regexp_pcre1_destroy(sss_regexp_t *self)
+{
+    if (self->re) pcre_free(self->re);
+    if (self->matched_string) pcre_free_substring(self->matched_string);
+    return 0;
+}
+
+void sss_regexp_pcre1_compile(sss_regexp_t *self,
+                              const char *pattern,
+                              int options,
+                              int *errorcodeptr,
+                              const char **errormsgptr,
+                              size_t *erroffset)
+{
+    self->re = pcre_compile2(pattern, options, errorcodeptr, errormsgptr, (int *)erroffset, NULL);
+}
+
+int sss_regexp_pcre1_match(sss_regexp_t *self,
+                           const char *subject,
+                           int startoffset,
+                           int options)
+{
+    self->subject = subject;
+    return pcre_exec(self->re, NULL, subject, strlen(subject), startoffset, options, self->ovector, SSS_REGEXP_OVEC_SIZE);
+}
+
+int sss_regexp_pcre1_get_named_substring(sss_regexp_t *self,
+                                         const char *name,
+                                         const char **value)
+{
+    if (self->matched_string) {
+        pcre_free_substring(self->matched_string);
+        self->matched_string = NULL;
+    }
+    int rc = pcre_get_named_substring(self->re, self->subject, self->ovector, SSS_REGEXP_OVEC_SIZE, name, &self->matched_string);
+    *value = self->matched_string;
+    return rc;
+}
+
+#endif /* HAVE_LIBPCRE2 */
+
+/*
+ * sss_regexp talloc destructor
+ */
+int sss_regexp_destroy(sss_regexp_t *self)
+{
+    if (! self) return -1;
+#ifdef HAVE_LIBPCRE2
+    return sss_regexp_pcre2_destroy(self);
+#else
+    return sss_regexp_pcre1_destroy(self);
+#endif
+}
+
+/*
+ * sss_regexp constructor
+ */
+sss_regexp_t *sss_regexp_new(TALLOC_CTX *mem_ctx,
+                             const char *pattern,
+                             int options,
+                             int *errorcodeptr,
+                             const char **errormsgptr,
+                             size_t *erroffset)
+{
+    sss_regexp_t *self = talloc_zero (mem_ctx, sss_regexp_t);
+    if (!self) {
+        *errorcodeptr = SSS_REGEXP_ERROR_NOMEMORY;
+        *errormsgptr = "Not enough memory for sss_regexp_t";
+        *erroffset = 0;
+        return NULL;
+    }
+    talloc_set_destructor(self, sss_regexp_destroy);
+
+#ifdef HAVE_LIBPCRE2
+    sss_regexp_pcre2_compile (self, pattern, options, errorcodeptr, errormsgptr, erroffset);
+#else
+    sss_regexp_pcre1_compile (self, pattern, options, errorcodeptr, errormsgptr, erroffset);
+#endif
+
+    return self;
+}
+
+/*
+ * sss_regexp match function
+ */
+int sss_regexp_match(sss_regexp_t *self,
+                     const char *subject,
+                     int startoffset,
+                     int options)
+{
+    if (!self || !self->re || !subject) return SSS_REGEXP_ERROR_NOMATCH;
+
+#ifdef HAVE_LIBPCRE2
+    return sss_regexp_pcre2_match(self, subject, startoffset, options);
+#else
+    return sss_regexp_pcre1_match(self, subject, startoffset, options);
+#endif
+}
+
+
+/*
+ * sss_regexp get named substring
+ */
+int sss_regexp_get_named_substring(sss_regexp_t *self,
+                                   const char *name,
+                                   const char **value)
+{
+    if (!self || !self->re || !name) {
+        *value = NULL;
+        return SSS_REGEXP_ERROR_NOMATCH;
+    }
+#ifdef HAVE_LIBPCRE2
+    return sss_regexp_pcre2_get_named_substring(self, name, value);
+#else
+    return sss_regexp_pcre1_get_named_substring(self, name, value);
+#endif
+}
diff --git a/src/util/sss_regexp.h b/src/util/sss_regexp.h
new file mode 100644
index 0000000000..f21b6b0381
--- /dev/null
+++ b/src/util/sss_regexp.h
@@ -0,0 +1,96 @@
+/*
+    SSSD
+
+    Authors:
+        Tomas Halman <thal...@redhat.com>
+
+    Copyright (C) 2018 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SSS_REGEXP_H_
+#define SSS_REGEXP_H_
+
+#include <stddef.h>
+#include <talloc.h>
+#include "config.h"
+
+/* regexp class */
+typedef struct _sss_regexp_t sss_regexp_t;
+
+#ifdef HAVE_LIBPCRE2
+#  include <pcre2.h>
+#  define SSS_REGEXP_ERROR_NOMATCH  PCRE2_ERROR_NOMATCH
+#  define SSS_REGEXP_ERROR_NOMEMORY PCRE2_ERROR_NOMEMORY
+#  define SSS_REGEXP_NOTEMPTY       PCRE2_NOTEMPTY
+#  define SSS_REGEXP_EXTENDED       PCRE2_EXTENDED
+#  define SSS_REGEXP_DUPNAMES       PCRE2_DUPNAMES
+#else /* HAVE_LIBPCRE2 */
+#  include <pcre.h>
+#  define SSS_REGEXP_ERROR_NOMATCH  PCRE_ERROR_NOMATCH
+#  define SSS_REGEXP_ERROR_NOMEMORY PCRE_ERROR_NOMEMORY
+#  define SSS_REGEXP_NOTEMPTY       PCRE_NOTEMPTY
+#  define SSS_REGEXP_EXTENDED       PCRE_EXTENDED
+#  ifdef HAVE_LIBPCRE_LESSER_THAN_7
+#    define SSS_REGEXP_DUPNAMES     0
+#  else
+#    define SSS_REGEXP_DUPNAMES     PCRE_DUPNAMES
+#  endif
+#endif  /* HAVE_LIBPCRE2 */
+
+/* how to use sss_regexp:
+ *
+ *  int err;
+ *  size_t pos;
+ *  const char *msg;
+ *  const char *found;
+ *
+ *  sss_regexp_t *re = sss_regexp_new (NULL, "#(?P<myname>.+)#", 0, &err, &msg, &pos);
+ *  int rc = sss_regexp_match (re,
+ *                             "a#findthis#b",
+ *                             0,
+ *                             0);
+ *  if (rc != 0) { ... }
+ *  rc = sss_regexp_get_named_substring (re, "myname", &found);
+ *  ...
+ *  talloc_free (re);
+ */
+
+/*
+ * Create new compiled regexp object.
+ */
+sss_regexp_t *sss_regexp_new(TALLOC_CTX *mem_ctx,
+                             const char *pattern,
+                             int options,
+                             int *errorcode,
+                             const char **errormsg,
+                             size_t *erroroffset);
+
+/*
+ * Search subject with previously created regexp.
+ */
+int sss_regexp_match(sss_regexp_t *self,
+                     const char *subject,
+                     int startoffset,
+                     int options);
+
+/*
+ * Get named substring from last sss_regexp_match.
+ */
+int sss_regexp_get_named_substring(sss_regexp_t *self,
+                                   const char *name,
+                                   const char **value);
+
+#endif /* SSS_REGEXP_H_ */
diff --git a/src/util/usertools.c b/src/util/usertools.c
index cf4e4a8280..d612e307a5 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -20,7 +20,6 @@
 */
 
 #include <pwd.h>
-#include <pcre.h>
 #include <errno.h>
 #include <talloc.h>
 #include <pwd.h>
@@ -33,11 +32,7 @@
 #include "util/safe-format-string.h"
 #include "responder/common/responder.h"
 
-#ifdef HAVE_LIBPCRE_LESSER_THAN_7
-#define NAME_DOMAIN_PATTERN_OPTIONS (PCRE_EXTENDED)
-#else
-#define NAME_DOMAIN_PATTERN_OPTIONS (PCRE_DUPNAMES | PCRE_EXTENDED)
-#endif
+#define NAME_DOMAIN_PATTERN_OPTIONS (SSS_REGEXP_DUPNAMES | SSS_REGEXP_EXTENDED)
 
 /* Function returns given realm name as new uppercase string */
 char *get_uppercase_realm(TALLOC_CTX *memctx, const char *name)
@@ -60,15 +55,6 @@ char *get_uppercase_realm(TALLOC_CTX *memctx, const char *name)
 }
 
 
-static int sss_names_ctx_destructor(struct sss_names_ctx *snctx)
-{
-    if (snctx->re) {
-        pcre_free(snctx->re);
-        snctx->re = NULL;
-    }
-    return 0;
-}
-
 #define IPA_AD_DEFAULT_RE "(((?P<domain>[^\\\\]+)\\\\(?P<name>.+$))|" \
                          "((?P<name>[^@]+)@(?P<domain>.+$))|" \
                          "(^(?P<name>[^@\\\\]+)$))"
@@ -163,12 +149,11 @@ int sss_names_init_from_args(TALLOC_CTX *mem_ctx, const char *re_pattern,
     struct sss_names_ctx *ctx;
     const char *errstr;
     int errval;
-    int errpos;
+    size_t errpos;
     int ret;
 
     ctx = talloc_zero(mem_ctx, struct sss_names_ctx);
     if (!ctx) return ENOMEM;
-    talloc_set_destructor(ctx, sss_names_ctx_destructor);
 
     ctx->re_pattern = talloc_strdup(ctx, re_pattern);
     if (ctx->re_pattern == NULL) {
@@ -185,12 +170,13 @@ int sss_names_init_from_args(TALLOC_CTX *mem_ctx, const char *re_pattern,
         goto done;
     }
 
-    ctx->re = pcre_compile2(ctx->re_pattern,
-                            NAME_DOMAIN_PATTERN_OPTIONS,
-                            &errval, &errstr, &errpos, NULL);
+    ctx->re = sss_regexp_new(ctx,
+                             ctx->re_pattern,
+                             NAME_DOMAIN_PATTERN_OPTIONS,
+                             &errval, &errstr, &errpos);
     if (!ctx->re) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "Invalid Regular Expression pattern at position %d."
+              "Invalid Regular Expression pattern at position %zu."
                   " (Error: %d [%s])\n", errpos, errval, errstr);
         ret = EFAULT;
         goto done;
@@ -308,16 +294,12 @@ int sss_parse_name(TALLOC_CTX *memctx,
                    struct sss_names_ctx *snctx,
                    const char *orig, char **_domain, char **_name)
 {
-    pcre *re = snctx->re;
+    sss_regexp_t *re = snctx->re;
     const char *result;
-    int ovec[30];
-    int origlen;
-    int ret, strnum;
-
-    origlen = strlen(orig);
+    int ret;
 
-    ret = pcre_exec(re, NULL, orig, origlen, 0, PCRE_NOTEMPTY, ovec, 30);
-    if (ret == PCRE_ERROR_NOMATCH) {
+    ret = sss_regexp_match(re, orig, 0, SSS_REGEXP_NOTEMPTY);
+    if (ret == SSS_REGEXP_ERROR_NOMATCH) {
         return ERR_REGEX_NOMATCH;
     } else if (ret < 0) {
         DEBUG(SSSDBG_MINOR_FAILURE, "PCRE Matching error, %d\n", ret);
@@ -329,24 +311,20 @@ int sss_parse_name(TALLOC_CTX *memctx,
               "Too many matches, the pattern is invalid.\n");
     }
 
-    strnum = ret;
-
     if (_name != NULL) {
         result = NULL;
-        ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result);
+        ret = sss_regexp_get_named_substring(re, "name", &result);
         if (ret < 0  || !result) {
             DEBUG(SSSDBG_OP_FAILURE, "Name not found!\n");
             return EINVAL;
         }
         *_name = talloc_strdup(memctx, result);
-        pcre_free_substring(result);
         if (!*_name) return ENOMEM;
     }
 
     if (_domain != NULL) {
         result = NULL;
-        ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain",
-                                       &result);
+        ret = sss_regexp_get_named_substring(re, "domain", &result);
         if (ret < 0  || !result) {
             DEBUG(SSSDBG_CONF_SETTINGS, "Domain not provided!\n");
             *_domain = NULL;
@@ -354,10 +332,8 @@ int sss_parse_name(TALLOC_CTX *memctx,
             /* ignore "" string */
             if (*result) {
                 *_domain = talloc_strdup(memctx, result);
-                pcre_free_substring(result);
                 if (!*_domain) return ENOMEM;
             } else {
-                pcre_free_substring(result);
                 *_domain = NULL;
             }
         }
diff --git a/src/util/util.h b/src/util/util.h
index 59e7a96ba5..b6628643e3 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -28,7 +28,6 @@
 #include <libintl.h>
 #include <locale.h>
 #include <time.h>
-#include <pcre.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <netinet/in.h>
@@ -44,6 +43,7 @@
 #include "util/atomic_io.h"
 #include "util/util_errors.h"
 #include "util/sss_format.h"
+#include "util/sss_regexp.h"
 #include "util/debug.h"
 
 /* name of the monitor server instance */
@@ -209,7 +209,7 @@ struct sss_names_ctx {
     char *re_pattern;
     char *fq_fmt;
 
-    pcre *re;
+    sss_regexp_t *re;
 };
 
 /* initialize sss_names_ctx directly from arguments */
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: https://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org

Reply via email to