From 55f933b88c9d9992b1ec0ed7c13a621032f7637d Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Tue, 15 Mar 2022 22:01:39 +0100 Subject: [PATCH] Add an API for keeping a permanent library context, for performance reasons (unbound in buster and newer needs a lot of CU time for creating a new DNS context). --- itkacl-2.1/itkacl-test.c | 19 -- itkacl-2.1/itkacl.h | 14 -- {itkacl-2.1 => itkacl-2.2}/Makefile | 2 +- {itkacl-2.1 => itkacl-2.2}/config.pm | 0 {itkacl-2.1 => itkacl-2.2}/debian/changelog | 8 + {itkacl-2.1 => itkacl-2.2}/debian/compat | 0 {itkacl-2.1 => itkacl-2.2}/debian/control | 0 {itkacl-2.1 => itkacl-2.2}/debian/copyright | 0 .../debian/itkacl-sync.dirs | 0 .../debian/itkacl-sync.install | 0 .../debian/libitkacl-dev.install | 0 .../debian/libitkacl2.install | 0 {itkacl-2.1 => itkacl-2.2}/debian/rules | 0 itkacl-2.2/itkacl-test.c | 28 +++ {itkacl-2.1 => itkacl-2.2}/itkacl.c | 162 +++++++++++------- {itkacl-2.1 => itkacl-2.2}/itkacl.conf | 0 itkacl-2.2/itkacl.h | 32 ++++ {itkacl-2.1 => itkacl-2.2}/itkacl.sql | 0 {itkacl-2.1 => itkacl-2.2}/sync-itkacl.pl | 0 19 files changed, 173 insertions(+), 92 deletions(-) delete mode 100644 itkacl-2.1/itkacl-test.c delete mode 100644 itkacl-2.1/itkacl.h rename {itkacl-2.1 => itkacl-2.2}/Makefile (97%) rename {itkacl-2.1 => itkacl-2.2}/config.pm (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/changelog (63%) rename {itkacl-2.1 => itkacl-2.2}/debian/compat (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/control (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/copyright (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/itkacl-sync.dirs (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/itkacl-sync.install (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/libitkacl-dev.install (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/libitkacl2.install (100%) rename {itkacl-2.1 => itkacl-2.2}/debian/rules (100%) create mode 100644 itkacl-2.2/itkacl-test.c rename {itkacl-2.1 => itkacl-2.2}/itkacl.c (76%) rename {itkacl-2.1 => itkacl-2.2}/itkacl.conf (100%) create mode 100644 itkacl-2.2/itkacl.h rename {itkacl-2.1 => itkacl-2.2}/itkacl.sql (100%) rename {itkacl-2.1 => itkacl-2.2}/sync-itkacl.pl (100%) diff --git a/itkacl-2.1/itkacl-test.c b/itkacl-2.1/itkacl-test.c deleted file mode 100644 index 49388d4..0000000 --- a/itkacl-2.1/itkacl-test.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -int itkacl_check(const char * const realm, const char * const user, - char *errmsg, size_t errmsg_size); - -int main() -{ - char errmsg[1024]; - int ret = itkacl_check("/login/unix-servers/cirkus", "sesse", errmsg, sizeof(errmsg)); - - if (ret == 0) { - printf("OK\n"); - } else if (ret == -1) { - printf("Error: %s\n", errmsg); - } else { - printf("Not OK\n"); - } - return 0; -} diff --git a/itkacl-2.1/itkacl.h b/itkacl-2.1/itkacl.h deleted file mode 100644 index 32d94a7..0000000 --- a/itkacl-2.1/itkacl.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _ITKACL_H -#define _ITKACL_H - -/* - * itkacl control library, version 0.1 - * - * (C) 2004-2009 Steinar H. Gunderson - * GPL, v2. - */ - -int itkacl_check(const char * const realm, const char * const user, - char *errmsg, size_t errmsg_size); - -#endif /* !defined(_ITKACL_H) */ diff --git a/itkacl-2.1/Makefile b/itkacl-2.2/Makefile similarity index 97% rename from itkacl-2.1/Makefile rename to itkacl-2.2/Makefile index 99ef295..029de70 100644 --- a/itkacl-2.1/Makefile +++ b/itkacl-2.2/Makefile @@ -6,7 +6,7 @@ RANLIB=ranlib PREFIX=/usr/local SONAME=libitkacl.so.2 -LIBNAME=libitkacl.so.2.0.0 +LIBNAME=libitkacl.so.2.0.1 all: libitkacl.a $(LIBNAME) itkacl-test clean: diff --git a/itkacl-2.1/config.pm b/itkacl-2.2/config.pm similarity index 100% rename from itkacl-2.1/config.pm rename to itkacl-2.2/config.pm diff --git a/itkacl-2.1/debian/changelog b/itkacl-2.2/debian/changelog similarity index 63% rename from itkacl-2.1/debian/changelog rename to itkacl-2.2/debian/changelog index cf405bf..601f816 100644 --- a/itkacl-2.1/debian/changelog +++ b/itkacl-2.2/debian/changelog @@ -1,3 +1,11 @@ +itkacl (2.2) unstable; urgency=medium + + * Add an API for keeping a permanent library context, for performance reasons + (unbound in buster and newer needs a lot of CU time for creating a new DNS + context). + + -- Steinar H. Gunderson Tue, 15 Mar 2022 21:59:20 +0100 + itkacl (2.1) unstable; urgency=low * Make the core library support a configuration file (/etc/itkacl.conf), diff --git a/itkacl-2.1/debian/compat b/itkacl-2.2/debian/compat similarity index 100% rename from itkacl-2.1/debian/compat rename to itkacl-2.2/debian/compat diff --git a/itkacl-2.1/debian/control b/itkacl-2.2/debian/control similarity index 100% rename from itkacl-2.1/debian/control rename to itkacl-2.2/debian/control diff --git a/itkacl-2.1/debian/copyright b/itkacl-2.2/debian/copyright similarity index 100% rename from itkacl-2.1/debian/copyright rename to itkacl-2.2/debian/copyright diff --git a/itkacl-2.1/debian/itkacl-sync.dirs b/itkacl-2.2/debian/itkacl-sync.dirs similarity index 100% rename from itkacl-2.1/debian/itkacl-sync.dirs rename to itkacl-2.2/debian/itkacl-sync.dirs diff --git a/itkacl-2.1/debian/itkacl-sync.install b/itkacl-2.2/debian/itkacl-sync.install similarity index 100% rename from itkacl-2.1/debian/itkacl-sync.install rename to itkacl-2.2/debian/itkacl-sync.install diff --git a/itkacl-2.1/debian/libitkacl-dev.install b/itkacl-2.2/debian/libitkacl-dev.install similarity index 100% rename from itkacl-2.1/debian/libitkacl-dev.install rename to itkacl-2.2/debian/libitkacl-dev.install diff --git a/itkacl-2.1/debian/libitkacl2.install b/itkacl-2.2/debian/libitkacl2.install similarity index 100% rename from itkacl-2.1/debian/libitkacl2.install rename to itkacl-2.2/debian/libitkacl2.install diff --git a/itkacl-2.1/debian/rules b/itkacl-2.2/debian/rules similarity index 100% rename from itkacl-2.1/debian/rules rename to itkacl-2.2/debian/rules diff --git a/itkacl-2.2/itkacl-test.c b/itkacl-2.2/itkacl-test.c new file mode 100644 index 0000000..88d2777 --- /dev/null +++ b/itkacl-2.2/itkacl-test.c @@ -0,0 +1,28 @@ +#include +#include "itkacl.h" + +int main() +{ + char errmsg[1024]; + int ret; + struct itkacl_ctx *ctx; + + ctx = itkacl_create_ctx(errmsg, sizeof(errmsg)); + if (ctx == NULL) { + printf("Error while creating context: %s\n", errmsg); + return 1; + } + + ret = itkacl_check_with_ctx(ctx, "/login/unix-servers/cirkus", "sesse", errmsg, sizeof(errmsg)); + + itkacl_free_ctx(ctx); + + if (ret == 0) { + printf("OK\n"); + } else if (ret == -1) { + printf("Error: %s\n", errmsg); + } else { + printf("Not OK\n"); + } + return 0; +} diff --git a/itkacl-2.1/itkacl.c b/itkacl-2.2/itkacl.c similarity index 76% rename from itkacl-2.1/itkacl.c rename to itkacl-2.2/itkacl.c index eda3ebb..d7bdfa0 100644 --- a/itkacl-2.1/itkacl.c +++ b/itkacl-2.2/itkacl.c @@ -1,7 +1,7 @@ /* * ITKACL control library. * - * (C) 2004-2013 Steinar H. Gunderson + * (C) 2004-2022 Steinar H. Gunderson * GPL, v2. */ #include @@ -13,12 +13,19 @@ #include #include +#include "itkacl.h" + struct itkacl_config { char nszone[256]; int require_dnssec; char dnssec_public_key[256]; }; +struct itkacl_ctx { + struct itkacl_config config; + struct ub_ctx *ubctx; +}; + #define CONFIG_FILENAME "/etc/itkacl.conf" static int itkacl_read_config(const char * const filename, @@ -106,18 +113,105 @@ static int itkacl_read_config(const char * const filename, int itkacl_check(const char * const realm, const char * const user, char *errmsg, size_t errmsg_size) { - struct itkacl_config config; + struct itkacl_ctx *ctx; + int err; + + ctx = itkacl_create_ctx(errmsg, errmsg_size); + if (ctx == NULL) { + return -1; + } + + err = itkacl_check_with_ctx(ctx, realm, user, errmsg, errmsg_size); + + itkacl_free_ctx(ctx); + + return err; +} + +struct itkacl_ctx *itkacl_create_ctx(char *errmsg, size_t errmsg_size) +{ + struct itkacl_ctx *ctx; + int ret; + + ctx = (struct itkacl_ctx *)malloc(sizeof(struct itkacl_ctx)); + if (ctx == NULL) { + if (errmsg) + snprintf(errmsg, errmsg_size, "Memory allocation failed"); + return NULL; + } + + if (itkacl_read_config(CONFIG_FILENAME, &ctx->config, errmsg, errmsg_size) != 0) { + free(ctx); + return NULL; + } + + /* Create the DNS resolver context. */ + ctx->ubctx = ub_ctx_create(); + if (ctx->ubctx == NULL) { + if (errmsg) + snprintf(errmsg, errmsg_size, "Host name lookup failure: Could not create DNS context"); + free(ctx); + return NULL; + } + + ret = ub_ctx_resolvconf(ctx->ubctx, NULL); + if (ret != 0) { + if (errmsg) + snprintf(errmsg, errmsg_size, + "Host name lookup failure: Could not read resolv.conf " + "(resolver error: %s) (system error: %s)", + ub_strerror(ret), strerror(errno)); + ub_ctx_delete(ctx->ubctx); + free(ctx); + return NULL; + } + + ret = ub_ctx_hosts(ctx->ubctx, NULL); + if (ret != 0) { + if (errmsg) + snprintf(errmsg, errmsg_size, + "Host name lookup failure: Could not read hosts file " + "(resolver error: %s) (system error: %s)", + ub_strerror(ret), strerror(errno)); + ub_ctx_delete(ctx->ubctx); + free(ctx); + return NULL; + } + + if (strlen(ctx->config.dnssec_public_key) != 0) { + ret = ub_ctx_add_ta_file(ctx->ubctx, ctx->config.dnssec_public_key); + if (ret != 0) { + if (errmsg) + snprintf(errmsg, errmsg_size, + "Host name lookup failure: Error adding keys from %s " + "(resolver error: %s) (system error: %s)", + ctx->config.dnssec_public_key, + ub_strerror(ret), strerror(errno)); + ub_ctx_delete(ctx->ubctx); + free(ctx); + return NULL; + } + } + + return ctx; +} + +void itkacl_free_ctx(struct itkacl_ctx *ctx) +{ + ub_ctx_delete(ctx->ubctx); + free(ctx); +} + +int itkacl_check_with_ctx(struct itkacl_ctx *ctx, + const char * const realm, const char * const user, + char *errmsg, size_t errmsg_size) +{ int ret, nxdomain; const char *ptr; char nszone[256]; char temp[256]; - struct ub_ctx* ctx; struct ub_result* result; - if (itkacl_read_config(CONFIG_FILENAME, &config, errmsg, errmsg_size) != 0) { - return -1; - } - if (realm[0] != '/') { if (errmsg) snprintf(errmsg, errmsg_size, "Invalid realm '%s' (missing leading /)", @@ -155,7 +249,7 @@ int itkacl_check(const char * const realm, const char * const user, /* traverse the realm entry by entry from the root, * creating a DNS zone name as we go */ - strcpy(nszone, config.nszone); + strcpy(nszone, ctx->config.nszone); ptr = realm; while (*ptr) { /* copy all characters to next / or end of string */ @@ -187,57 +281,12 @@ int itkacl_check(const char * const realm, const char * const user, strcpy(temp, nszone); sprintf(nszone, "%s.%s", user, temp); - /* Create the DNS resolver context. */ - ctx = ub_ctx_create(); - if (ctx == NULL) { - if (errmsg) - snprintf(errmsg, errmsg_size, "Host name lookup failure: Could not create DNS context"); - return -1; - } - - ret = ub_ctx_resolvconf(ctx, NULL); - if (ret != 0) { - if (errmsg) - snprintf(errmsg, errmsg_size, - "Host name lookup failure: Could not read resolv.conf " - "(resolver error: %s) (system error: %s)", - ub_strerror(ret), strerror(errno)); - ub_ctx_delete(ctx); - return -1; - } - - ret = ub_ctx_hosts(ctx, NULL); - if (ret != 0) { - if (errmsg) - snprintf(errmsg, errmsg_size, - "Host name lookup failure: Could not read hosts file " - "(resolver error: %s) (system error: %s)", - ub_strerror(ret), strerror(errno)); - ub_ctx_delete(ctx); - return -1; - } - - if (strlen(config.dnssec_public_key) != 0) { - ret = ub_ctx_add_ta_file(ctx, config.dnssec_public_key); - if (ret != 0) { - if (errmsg) - snprintf(errmsg, errmsg_size, - "Host name lookup failure: Error adding keys from %s " - "(resolver error: %s) (system error: %s)", - config.dnssec_public_key, - ub_strerror(ret), strerror(errno)); - ub_ctx_delete(ctx); - return -1; - } - } - /* Do the actual DNS lookup (TYPE A, CLASS IN). */ - ret = ub_resolve(ctx, nszone, 1, 1, &result); + ret = ub_resolve(ctx->ubctx, nszone, 1, 1, &result); if (ret != 0) { if (errmsg) snprintf(errmsg, errmsg_size, "Host name lookup failure: %s", ub_strerror(ret)); - ub_ctx_delete(ctx); return -1; } @@ -247,22 +296,19 @@ int itkacl_check(const char * const realm, const char * const user, snprintf(errmsg, errmsg_size, "Host name lookup failure: Bogus DNSSEC result (security failure)"); ub_resolve_free(result); - ub_ctx_delete(ctx); return -1; } - if (config.require_dnssec && !result->secure) { + if (ctx->config.require_dnssec && !result->secure) { if (errmsg) snprintf(errmsg, errmsg_size, "Host name lookup failure: Result was not secured with DNSSEC"); ub_resolve_free(result); - ub_ctx_delete(ctx); return -1; } nxdomain = result->nxdomain; ub_resolve_free(result); - ub_ctx_delete(ctx); if (nxdomain) return 1; diff --git a/itkacl-2.1/itkacl.conf b/itkacl-2.2/itkacl.conf similarity index 100% rename from itkacl-2.1/itkacl.conf rename to itkacl-2.2/itkacl.conf diff --git a/itkacl-2.2/itkacl.h b/itkacl-2.2/itkacl.h new file mode 100644 index 0000000..77be702 --- /dev/null +++ b/itkacl-2.2/itkacl.h @@ -0,0 +1,32 @@ +#ifndef _ITKACL_H +#define _ITKACL_H + +/* + * itkacl control library, version 2.2 + * + * (C) 2004-2022 Steinar H. Gunderson + * GPL, v2. + */ + +int itkacl_check(const char * const realm, const char * const user, + char *errmsg, size_t errmsg_size); + +/* + * Opaque context. A context is created with itkacl_create_ctx() + * and freed with itkacl_free_ctx(), and is thread-safe. + * If you are making multiple calls to itkacl_check(), it is faster + * to reuse the same context over and over (since libunbound can + * have rather high setup times depending on configuration). + * + * Configuration is only reread when the context is created. + */ +struct itkacl_ctx; + +struct itkacl_ctx *itkacl_create_ctx(char *errmsg, size_t errmsg_size); // Returns NULL on failure. +void itkacl_free_ctx(struct itkacl_ctx *ctx); + +int itkacl_check_with_ctx(struct itkacl_ctx *ctx, + const char * const realm, const char * const user, + char *errmsg, size_t errmsg_size); + +#endif /* !defined(_ITKACL_H) */ diff --git a/itkacl-2.1/itkacl.sql b/itkacl-2.2/itkacl.sql similarity index 100% rename from itkacl-2.1/itkacl.sql rename to itkacl-2.2/itkacl.sql diff --git a/itkacl-2.1/sync-itkacl.pl b/itkacl-2.2/sync-itkacl.pl similarity index 100% rename from itkacl-2.1/sync-itkacl.pl rename to itkacl-2.2/sync-itkacl.pl -- 2.39.2