From: Ken Hornstein Date: Sat, 30 Nov 2024 01:34:53 +0000 (-0500) Subject: Add regexp support on Windows using std::regex X-Git-Tag: krb5-1.22-beta1~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=04b22c1c2dfbf7954b6cb114527a50a95ebccad3;p=thirdparty%2Fkrb5.git Add regexp support on Windows using std::regex Provide glue code in libkrb5support to emulate the POSIX regex(3) interface by calling into the C++ std::regex classes. Eliminate compatibility code for pre-POSIX regex functions. [ghudson@mit.edu: additional cleanup of regexp callers; minor style adjustments; removed regerrlen field; edited commit message] --- diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 4b57d3bd02..7397bdcc2b 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -714,53 +714,6 @@ KRB5_NEED_PROTO([#ifdef HAVE_UNISTD_H #include #endif],daemon,1)])dnl -dnl -dnl KRB5_AC_NEED_LIBGEN --- check if libgen needs to be linked in for -dnl compile/step -dnl -dnl -AC_DEFUN(KRB5_AC_NEED_LIBGEN,[ -AC_REQUIRE([AC_PROG_CC])dnl -dnl -dnl regcomp is present but non-functional on Solaris 2.4 -dnl -AC_MSG_CHECKING(for working regcomp) -AC_CACHE_VAL(ac_cv_func_regcomp, -[AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#include - #include - regex_t x; regmatch_t m;]], - [[return regcomp(&x,"pat.*",0) || regexec(&x,"pattern",1,&m,0);]])], - [ac_cv_func_regcomp=yes], [ac_cv_func_regcomp=no], - [AC_MSG_ERROR([Cannot test regcomp when cross compiling])])]) -AC_MSG_RESULT($ac_cv_func_regcomp) -test $ac_cv_func_regcomp = yes && AC_DEFINE(HAVE_REGCOMP,1,[Define if regcomp exists and functions]) -dnl -dnl Check for the compile and step functions - only if regcomp is not available -dnl -if test $ac_cv_func_regcomp = no; then - save_LIBS="$LIBS" - LIBS=-lgen -dnl this will fail if there's no compile/step in -lgen, or if there's -dnl no -lgen. This is fine. - AC_CHECK_FUNCS(compile step) - LIBS="$save_LIBS" -dnl -dnl Set GEN_LIB if necessary -dnl - AC_CHECK_LIB(gen, compile, GEN_LIB=-lgen, GEN_LIB=) - AC_SUBST(GEN_LIB) -fi -]) -dnl -dnl KRB5_AC_REGEX_FUNCS --- check for different regular expression -dnl support functions -dnl -AC_DEFUN(KRB5_AC_REGEX_FUNCS,[ -AC_CHECK_FUNCS(re_comp re_exec regexec) -AC_REQUIRE([KRB5_AC_NEED_LIBGEN])dnl -])dnl dnl dnl WITH_HESIOD dnl @@ -850,7 +803,6 @@ dnl Set variables to build a program. AC_DEFUN(KRB5_BUILD_PROGRAM, [AC_REQUIRE([KRB5_LIB_AUX])dnl -AC_REQUIRE([KRB5_AC_NEED_LIBGEN])dnl AC_SUBST(CC_LINK) AC_SUBST(CXX_LINK) AC_SUBST(RPATH_FLAG) diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in index 8e6eb86601..2cb439887d 100755 --- a/src/build-tools/krb5-config.in +++ b/src/build-tools/krb5-config.in @@ -42,7 +42,6 @@ DEFKTNAME='@DEFKTNAME@' DEFCKTNAME='@DEFCKTNAME@' LIBS='@LIBS@' -GEN_LIB=@GEN_LIB@ # Defaults for program library=krb5 @@ -253,8 +252,7 @@ if test -n "$do_libs"; then fi # If we ever support a flag to generate output suitable for static - # linking, we would output "-lkrb5support $GEN_LIB $LIBS $DL_LIB" - # here. + # linking, we would output "-lkrb5support $LIBS $DL_LIB" here. echo $lib_flags fi diff --git a/src/config/pre.in b/src/config/pre.in index 39c417e430..1197c1ffd6 100644 --- a/src/config/pre.in +++ b/src/config/pre.in @@ -348,9 +348,6 @@ VERTO_DEPS-k5 = $(BUILDTOP)/include/verto.h # LIBS gets substituted in... e.g. -lnsl -lsocket -# GEN_LIB is -lgen if needed for regexp -GEN_LIB = @GEN_LIB@ - # Editline or readline flags and libraries. RL_CFLAGS = @RL_CFLAGS@ RL_LIBS = @RL_LIBS@ @@ -380,7 +377,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME) # HESIOD_LIBS is -lhesiod... HESIOD_LIBS = @HESIOD_LIBS@ -KRB5_BASE_LIBS = $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS) $(DL_LIB) +KRB5_BASE_LIBS = $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(LIBS) $(DL_LIB) KDB5_LIBS = $(KDB5_LIB) $(GSSRPC_LIBS) GSS_LIBS = $(GSS_KRB5_LIB) # needs fixing if ever used on macOS! diff --git a/src/configure.ac b/src/configure.ac index 9d4e08a708..4325fae992 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -490,18 +490,9 @@ AC_SUBST(GETTIMEOFDAY_ST_OBJ) AC_SUBST(EXTRA_SUPPORT_SYMS) DECLARE_SYS_ERRLIST -AC_CHECK_HEADERS(unistd.h paths.h regex.h regexpr.h fcntl.h memory.h ifaddrs.h sys/filio.h byteswap.h machine/endian.h machine/byte_order.h sys/bswap.h endian.h pwd.h arpa/inet.h alloca.h dlfcn.h limits.h sys/random.h) -AC_CHECK_HEADER(regexp.h, [], [], -[#define INIT char *sp = instring; -#define GETC() (*sp++) -#define PEEKC() (*sp) -#define UNGETC(c) (--sp) -#define RETURN(c) return(c) -#define ERROR(c) -]) +AC_CHECK_HEADERS(unistd.h paths.h fcntl.h memory.h ifaddrs.h sys/filio.h byteswap.h machine/endian.h machine/byte_order.h sys/bswap.h endian.h pwd.h arpa/inet.h alloca.h dlfcn.h limits.h sys/random.h) AC_CHECK_MEMBERS([struct stat.st_mtimensec,struct stat.st_mtimespec.tv_nsec,struct stat.st_mtim.tv_nsec],,,[#include #include ]) -KRB5_AC_REGEX_FUNCS AC_TYPE_OFF_T # Fancy caching of perror result... diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h index 77bd6e18a8..0a19b36687 100644 --- a/src/include/k5-platform.h +++ b/src/include/k5-platform.h @@ -70,6 +70,10 @@ #include #endif +#ifdef __cplusplus +extern "C" { +#endif + #ifdef _WIN32 #define CAN_COPY_VA_LIST #endif @@ -1151,4 +1155,8 @@ extern char *k5_secure_getenv(const char *name); int k5_dir_filenames(const char *dirname, char ***fnames_out); void k5_free_filenames(char **fnames); +#ifdef __cplusplus +} +#endif + #endif /* K5_PLATFORM_H */ diff --git a/src/include/k5-regex.h b/src/include/k5-regex.h new file mode 100644 index 0000000000..e43f65c71d --- /dev/null +++ b/src/include/k5-regex.h @@ -0,0 +1,118 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* include/k5-regex.h - Compatibility glue for std::regex on Windows */ + +/* + * Copyright (C) 2024 United States Government as represented by the + * Secretary of the Navy. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * On POSIX platforms we can use the standardized regcomp()/regexec() function + * calls. Windows does not provide POSIX regex functions, but does provide a + * C++ interface (std::regex) that has the same functionality. + */ + +#ifndef _K5_REGEX_H_ +#define _K5_REGEX_H_ + +#ifndef _WIN32 + +/* On POSIX platforms, just include regex.h. */ +#include + +#else /* _WIN32 */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* On Windows, emulate the POSIX interface using functions from + * libkrb5support. */ + +typedef struct { + size_t re_nsub; /* Number of subexpressions */ + void *regex; /* Pointer to std::basic_regex */ + char errmsg[128]; /* Regular expression error message */ +} regex_t; + +typedef ssize_t regoff_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +/* + * Flags to k5_regcomp() + */ + +#define REG_BASIC 0x00 /* Basic regular expressions */ +#define REG_EXTENDED 0x01 /* Extended regular expressions */ +#define REG_ICASE 0x02 /* Case-insensitive match */ +#define REG_NOSUB 0x04 /* Do not do submatching */ + +/* + * Flags to k5_regexec() + */ + +#define REG_NOTBOL 0x01 /* First character not at beginning of line */ +#define REG_NOTEOL 0x02 /* Last character not at end of line */ + +/* + * Error return codes for k5_regcomp()/k5_regexec() + * + * We only define REG_NOMATCH and REG_BADPAT, since no Kerberos code looks + * for anything other than success and REG_NOMATCH. + */ + +#define REG_NOMATCH 1 +#define REG_BADPAT 2 + +/* + * Note that we don't follow the POSIX API exactly because k5_regexec() + * doesn't declare regex_t as const; that's so we can store an error + * string. + */ +int k5_regcomp(regex_t *preg, const char *pattern, int flags); +int k5_regexec(regex_t *preg, const char *string, size_t, + regmatch_t pmatch[], int flags); +size_t k5_regerror(int code, const regex_t *preg, char *errmsg, + size_t errmsg_size); +void k5_regfree(regex_t *preg); + +#define regcomp k5_regcomp +#define regexec k5_regexec +#define regerror k5_regerror +#define regfree k5_regfree + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _WIN32 */ +#endif /* _K5_REGEX_H_ */ diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c index f964e5ca9e..e45551a200 100644 --- a/src/kadmin/dbutil/dump.c +++ b/src/kadmin/dbutil/dump.c @@ -34,9 +34,7 @@ #include #include #include "kdb5_util.h" -#if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) -#include -#endif /* HAVE_REGEX_H */ +#include "k5-regex.h" /* Needed for master key conversion. */ static krb5_boolean mkey_convert; @@ -47,18 +45,6 @@ krb5_kvno new_mkvno; #define K5Q(x) K5Q1(x) #define K5CONST_WIDTH_SCANF_STR(x) "%" K5Q(x) "s" -/* Use compile(3) if no regcomp present. */ -#if !defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H) -#define INIT char *sp = instring; -#define GETC() (*sp++) -#define PEEKC() (*sp) -#define UNGETC(c) (--sp) -#define RETURN(c) return(c) -#define ERROR(c) -#define RE_BUF_SIZE 1024 -#include -#endif /* !HAVE_REGCOMP && HAVE_REGEXP_H */ - typedef krb5_error_code (*dump_func)(krb5_context context, krb5_db_entry *entry, const char *name, FILE *fp, krb5_boolean verbose, @@ -236,23 +222,15 @@ update_ok_file(krb5_context context, int fd) static int name_matches(char *name, struct dump_args *args) { -#if HAVE_REGCOMP regex_t reg; regmatch_t rmatch; int st; char errmsg[BUFSIZ]; -#elif HAVE_REGEXP_H - char regexp_buffer[RE_BUF_SIZE]; -#elif HAVE_RE_COMP - extern char *re_comp(); - char *re_result; -#endif /* HAVE_RE_COMP */ int i, match; /* Check each regular expression in args. */ match = args->nnames ? 0 : 1; for (i = 0; i < args->nnames && !match; i++) { -#if HAVE_REGCOMP /* Compile the regular expression. */ st = regcomp(®, args->names[i], REG_EXTENDED); if (st) { @@ -274,29 +252,6 @@ name_matches(char *name, struct dump_args *args) break; } regfree(®); -#elif HAVE_REGEXP_H - /* Compile the regular expression. */ - compile(args->names[i], regexp_buffer, ®exp_buffer[RE_BUF_SIZE], - '\0'); - if (step(name, regexp_buffer)) { - if (loc1 == name && loc2 == &name[strlen(name)]) - match = 1; - } -#elif HAVE_RE_COMP - /* Compile the regular expression. */ - re_result = re_comp(args->names[i]); - if (re_result) { - fprintf(stderr, _("%s: regular expression error: %s\n"), progname, - re_result); - break; - } - if (re_exec(name)) - match = 1; -#else /* HAVE_RE_COMP */ - /* If no regular expression support, then just compare the strings. */ - if (!strcmp(args->names[i], name)) - match = 1; -#endif /* HAVE_REGCOMP */ } return match; } diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c index aceb0a9b80..0088c8eafb 100644 --- a/src/kadmin/dbutil/kdb5_mkey.c +++ b/src/kadmin/dbutil/kdb5_mkey.c @@ -11,22 +11,7 @@ #include #include "kdb5_util.h" #include - -#if defined(HAVE_COMPILE) && defined(HAVE_STEP) -#define SOLARIS_REGEXPS -#elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXEC) -#define POSIX_REGEXPS -#elif defined(HAVE_RE_COMP) && defined(HAVE_RE_EXEC) -#define BSD_REGEXPS -#else -#error I cannot find any regexp functions -#endif -#ifdef SOLARIS_REGEXPS -#include -#endif -#ifdef POSIX_REGEXPS -#include -#endif +#include "k5-regex.h" extern krb5_keyblock master_keyblock; /* current mkey */ extern krb5_kvno master_kvno; @@ -644,15 +629,7 @@ struct update_enc_mkvno { unsigned int updated; unsigned int dry_run : 1; unsigned int verbose : 1; -#ifdef SOLARIS_REGEXPS - char *expbuf; -#endif -#ifdef POSIX_REGEXPS regex_t preg; -#endif -#if !defined(SOLARIS_REGEXPS) && !defined(POSIX_REGEXPS) - unsigned char placeholder; -#endif }; /* XXX Duplicated in libkadm5srv! */ @@ -667,10 +644,10 @@ struct update_enc_mkvno { * * Effects: * - * regexp is filled in with allocated memory contained a regular - * expression to be used with re_comp/compile that matches what the - * shell-style glob would match. If glob does not contain an "@" - * character and realm is not NULL, "@*" is appended to the regexp. + * regexp is filled in with allocated memory containing a regular + * expression that matches what the shell-style glob would match. + * If glob does not contain an "@" character and realm is not + * NULL, "@*" is appended to the regexp. * * Conversion algorithm: * @@ -745,7 +722,6 @@ update_princ_encryption_1(void *cb, krb5_db_entry *ent) struct update_enc_mkvno *p = cb; char *pname = 0; krb5_error_code retval; - int match; krb5_timestamp now; int result; krb5_kvno old_mkvno; @@ -761,18 +737,8 @@ update_princ_encryption_1(void *cb, krb5_db_entry *ent) goto skip; } -#ifdef SOLARIS_REGEXPS - match = (step(pname, p->expbuf) != 0); -#endif -#ifdef POSIX_REGEXPS - match = (regexec(&p->preg, pname, 0, NULL, 0) == 0); -#endif -#ifdef BSD_REGEXPS - match = (re_exec(pname) != 0); -#endif - if (!match) { + if (regexec(&p->preg, pname, 0, NULL, 0) != 0) goto skip; - } p->re_match_count++; retval = krb5_dbe_get_mkvno(util_context, ent, &old_mkvno); if (retval) { @@ -868,9 +834,6 @@ kdb5_update_princ_encryption(int argc, char *argv[]) krb5_error_code retval; krb5_actkvno_node *actkvno_list = 0; krb5_db_entry *master_entry = NULL; -#ifdef BSD_REGEXPS - char *msg; -#endif char *regexp = NULL; krb5_keyblock *act_mkey; krb5_keylist_node *master_keylist = krb5_db_mkey_list_alias(util_context); @@ -917,17 +880,7 @@ kdb5_update_princ_encryption(int argc, char *argv[]) goto cleanup; } - if ( -#ifdef SOLARIS_REGEXPS - ((data.expbuf = compile(regexp, NULL, NULL)) == NULL) -#endif -#ifdef POSIX_REGEXPS - ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0) -#endif -#ifdef BSD_REGEXPS - ((msg = (char *) re_comp(regexp)) != NULL) -#endif - ) { + if (regcomp(&data.preg, regexp, REG_NOSUB) != 0) { /* XXX syslog msg or regerr(regerrno) */ com_err(progname, 0, _("error compiling converted regexp '%s'"), regexp); @@ -1004,9 +957,7 @@ kdb5_update_princ_encryption(int argc, char *argv[]) cleanup: krb5_db_free_principal(util_context, master_entry); free(regexp); -#ifdef POSIX_REGEXPS regfree(&data.preg); -#endif memset(&new_master_keyblock, 0, sizeof(new_master_keyblock)); krb5_dbe_free_actkvno_list(util_context, actkvno_list); } diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in index d218ea487c..9e173b0486 100644 --- a/src/lib/kadm5/srv/Makefile.in +++ b/src/lib/kadm5/srv/Makefile.in @@ -21,7 +21,7 @@ SHLIB_EXPDEPS=\ $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ $(COM_ERR_DEPLIB) $(SUPPORT_LIBDEP) SHLIB_EXPLIBS = -lgssrpc -lgssapi_krb5 -lkdb5 $(KDB5_DB_LIB) -lkrb5 \ - -lk5crypto $(SUPPORT_LIB) $(COM_ERR_LIB) @GEN_LIB@ $(LIBS) + -lk5crypto $(SUPPORT_LIB) $(COM_ERR_LIB) $(LIBS) RELDIR=kadm5/srv SRCS = $(srcdir)/pwqual.c \ diff --git a/src/lib/kadm5/srv/svr_iters.c b/src/lib/kadm5/srv/svr_iters.c index d5a99dea00..4b26bc939f 100644 --- a/src/lib/kadm5/srv/svr_iters.c +++ b/src/lib/kadm5/srv/svr_iters.c @@ -6,25 +6,11 @@ */ #include "autoconf.h" -#if defined(HAVE_COMPILE) && defined(HAVE_STEP) -#define SOLARIS_REGEXPS -#elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXEC) -#define POSIX_REGEXPS -#elif defined(HAVE_RE_COMP) && defined(HAVE_RE_EXEC) -#define BSD_REGEXPS -#else -#error I cannot find any regexp functions -#endif #include #include #include -#ifdef SOLARIS_REGEXPS -#include -#endif -#ifdef POSIX_REGEXPS -#include -#endif +#include "k5-regex.h" #include #include "server_internal.h" @@ -35,12 +21,7 @@ struct iter_data { int n_names, sz_names; unsigned int malloc_failed; char *exp; -#ifdef SOLARIS_REGEXPS - char *expbuf; -#endif -#ifdef POSIX_REGEXPS regex_t preg; -#endif }; /* XXX Duplicated in kdb5_util! */ @@ -56,9 +37,9 @@ struct iter_data { * Effects: * * regexp is filled in with allocated memory contained a regular - * expression to be used with re_comp/compile that matches what the - * shell-style glob would match. If glob does not contain an "@" - * character and realm is not NULL, "@*" is appended to the regexp. + * expression that matches what the shell-style glob would match. + * If glob does not contain an "@" character and realm is not + * NULL, "@*" is appended to the regexp. * * Conversion algorithm: * @@ -130,15 +111,7 @@ static kadm5_ret_t glob_to_regexp(char *glob, char *realm, char **regexp) static void get_either_iter(struct iter_data *data, char *name) { int match; -#ifdef SOLARIS_REGEXPS - match = (step(name, data->expbuf) != 0); -#endif -#ifdef POSIX_REGEXPS match = (regexec(&data->preg, name, 0, NULL, 0) == 0); -#endif -#ifdef BSD_REGEXPS - match = (re_exec(name) != 0); -#endif if (match) { if (data->n_names == data->sz_names) { int new_sz = data->sz_names * 2; @@ -184,9 +157,6 @@ static kadm5_ret_t kadm5_get_either(int princ, int *count) { struct iter_data data; -#ifdef BSD_REGEXPS - char *msg; -#endif char *regexp = NULL; int i, ret; kadm5_server_handle_t handle = server_handle; @@ -202,18 +172,7 @@ static kadm5_ret_t kadm5_get_either(int princ, ®exp)) != KADM5_OK) return ret; - if ( -#ifdef SOLARIS_REGEXPS - ((data.expbuf = compile(regexp, NULL, NULL)) == NULL) -#endif -#ifdef POSIX_REGEXPS - ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0) -#endif -#ifdef BSD_REGEXPS - ((msg = (char *) re_comp(regexp)) != NULL) -#endif - ) - { + if (regcomp(&data.preg, regexp, REG_NOSUB) != 0) { /* XXX syslog msg or regerr(regerrno) */ free(regexp); return EINVAL; @@ -236,9 +195,7 @@ static kadm5_ret_t kadm5_get_either(int princ, } free(regexp); -#ifdef POSIX_REGEXPS regfree(&data.preg); -#endif if ( !ret && data.malloc_failed) ret = ENOMEM; if ( ret ) { diff --git a/src/lib/krb5/Makefile.in b/src/lib/krb5/Makefile.in index 67fd7c0098..ece308460d 100644 --- a/src/lib/krb5/Makefile.in +++ b/src/lib/krb5/Makefile.in @@ -45,7 +45,7 @@ RELDIR=krb5 SHLIB_EXPDEPS = \ $(TOPLIBD)/libk5crypto$(SHLIBEXT) \ $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB) -SHLIB_EXPLIBS=-lk5crypto $(COM_ERR_LIB) $(SUPPORT_LIB) @GEN_LIB@ \ +SHLIB_EXPLIBS=-lk5crypto $(COM_ERR_LIB) $(SUPPORT_LIB) \ @MACOS_FRAMEWORK@ $(LIBS) all-unix: all-liblinks diff --git a/src/lib/krb5/os/localauth_rule.c b/src/lib/krb5/os/localauth_rule.c index 056857633e..860a1e40eb 100644 --- a/src/lib/krb5/os/localauth_rule.c +++ b/src/lib/krb5/os/localauth_rule.c @@ -68,9 +68,7 @@ #include "os-proto.h" #include #include - -#ifdef HAVE_REGEX_H -#include +#include "k5-regex.h" /* Process the match portion of a rule and update *contextp. Return * KRB5_LNAME_NOTRANS if selstring doesn't match the regexp. */ @@ -303,17 +301,6 @@ cleanup: return ret; } -#else /* HAVE_REGEX_H */ - -static krb5_error_code -an2ln_rule(krb5_context context, krb5_localauth_moddata data, const char *type, - const char *rule, krb5_const_principal aname, char **lname_out) -{ - return KRB5_LNAME_NOTRANS; -} - -#endif - static void freestr(krb5_context context, krb5_localauth_moddata data, char *str) { diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in index 86d5a950a6..f63e44a4d7 100644 --- a/src/util/support/Makefile.in +++ b/src/util/support/Makefile.in @@ -58,6 +58,11 @@ SECURE_GETENV_OBJ= @SECURE_GETENV_OBJ@ ##DOS##SECURE_GETENV_ST_OBJ= ##DOS##SECURE_GETENV_OBJ= +K5_REGEX_ST_OBJ= +K5_REGEX_OBJ= +##DOS##K5_REGEX_ST_OBJ= regex.o +##DOS##K5_REGEX_OBJ= $(OUTPRE)regex.$(OBJEXT) + IPC_ST_OBJ= IPC_OBJ= ##DOS##IPC_ST_OBJ= ipc_stream.o @@ -99,7 +104,8 @@ STLIBOBJS= \ $(MKSTEMP_ST_OBJ) \ $(GETOPT_ST_OBJ) \ $(GETOPT_LONG_ST_OBJ) \ - $(SECURE_GETENV_OBJ) + $(SECURE_GETENV_OBJ) \ + $(K5_REGEX_ST_OBJ) LIBOBJS= \ $(OUTPRE)threads.$(OBJEXT) \ @@ -128,7 +134,8 @@ LIBOBJS= \ $(MKSTEMP_OBJ) \ $(GETOPT_OBJ) \ $(GETOPT_LONG_OBJ) \ - $(SECURE_GETENV_OBJ) + $(SECURE_GETENV_OBJ) \ + $(K5_REGEX_OBJ) SRCS=\ $(srcdir)/threads.c \ @@ -164,7 +171,8 @@ SRCS=\ $(srcdir)/t_utf16.c \ $(srcdir)/getopt.c \ $(srcdir)/getopt_long.c \ - $(srcdir)/secure_getenv.c + $(srcdir)/secure_getenv.c \ + $(srcdir)/regex.c SHLIB_EXPDEPS = # Add -lm if dumping thread stats, for sqrt. @@ -193,7 +201,8 @@ SHLIB_EXPORT_FILE=libkrb5support.exports EXTRA_SUPPORT_SYMS= @EXTRA_SUPPORT_SYMS@ ##DOS##EXTRA_SUPPORT_SYMS= krb5int_mkstemp krb5int_strlcpy krb5int_strlcat \ ##DOS## k5_getopt k5_getopt_long \ -##DOS## krb5int_vasprintf krb5int_asprintf krb5int_gettimeofday $(IPC_SYMS) +##DOS## krb5int_vasprintf krb5int_asprintf krb5int_gettimeofday $(IPC_SYMS) \ +##DOS## k5_regcomp k5_regexec k5_regerror k5_regfree ##DOS##DATA_SUPPORT_SYMS= k5_opterr k5_optind k5_optopt k5_optarg ##DOS##!if 0 diff --git a/src/util/support/regex.cpp b/src/util/support/regex.cpp new file mode 100644 index 0000000000..5b6ef0344a --- /dev/null +++ b/src/util/support/regex.cpp @@ -0,0 +1,153 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* regex.cpp - Glue routines to std::regex functions */ + +/* + * Copyright (C) 2024 United States Government as represented by the + * Secretary of the Navy. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * These functions provide a mostly-complete POSIX regex(3) + * implementation using C++ std::regex. Deficiencies are noted below. + */ + +#include "k5-platform.h" +#include "k5-regex.h" + +#include + +/* + * Our implementation of regcomp() which calls into std::regex. We implement + * the standard flags, but not the non-portable extensions present on some + * platforms. + */ +extern "C" int +k5_regcomp(regex_t *preg, const char *pattern, int cflags) +{ + std::regex *r; + std::regex_constants::syntax_option_type flags; + + memset(preg, 0, sizeof(*preg)); + + flags = (cflags & REG_EXTENDED) ? std::regex::extended : std::regex::basic; + if (cflags & REG_ICASE) + flags |= std::regex::icase; + if (cflags & REG_NOSUB) + flags |= std::regex::nosubs; + + try { + r = new std::regex(pattern, flags); + preg->regex = r; + preg->re_nsub = r->mark_count(); + } catch (std::regex_error& e) { + /* Save the error message in errmsg. We don't actually use the + * error code for anything; return REG_BADPAT for everything. */ + strlcpy(preg->errmsg, e.what(), sizeof(preg->errmsg)); + return REG_BADPAT; + } + + return 0; +} + +extern "C" int +k5_regexec(regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + size_t i; + std::cmatch cm; + std::regex_constants::match_flag_type flags; + std::regex *r = static_cast(preg->regex); + + flags = std::regex_constants::match_default; + if (eflags & REG_NOTBOL) + flags |= std::regex_constants::match_not_bol; + if (eflags & REG_NOTEOL) + flags |= std::regex_constants::match_not_eol; + + try { + if (!std::regex_search(string, cm, *r, flags)) + return REG_NOMATCH; + + /* + * If given, fill in pmatch with the full match string and any + * sub-matches. If we set nosub previously we shouldn't have any + * submatches, but should still have the first element which refers to + * the whole match string. + */ + + for (i = 0; i < nmatch; i++) { + /* + * If we're past the end of the match list (cm.size()) or + * this sub-match didn't match (!cm[i].matched()) then + * return -1 for those array members. + */ + if (i >= cm.size() || !cm[i].matched) { + pmatch[i].rm_so = pmatch[i].rm_eo = -1; + } else { + pmatch[i].rm_so = cm.position(i); + pmatch[i].rm_eo = cm.position(i) + cm.length(i); + } + } + } catch (std::regex_error& e) { + /* See above. */ + strlcpy(preg->errmsg, e.what(), sizeof(preg->errmsg)); + return REG_BADPAT; + } + + return 0; +} + +/* + * Report back an error string. We don't use the errcode for anything, just + * the error string stored in regex_t. If we don't have an error string, + * return an "unknown error" message. + */ +extern "C" size_t +k5_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +{ + const char *err; + size_t errlen; + + err = preg->errmsg; + if (*err == '\0') + err = "Unknown regular expression error"; + + if (errbuf != NULL && errbuf_size > 0) + strlcpy(errbuf, err, errbuf_size); + return strlen(err); +} + +extern "C" void +k5_regfree(regex_t *preg) +{ + if (preg->regex == NULL) + return; + delete static_cast(preg->regex); + memset(preg, 0, sizeof(*preg)); +}