diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 11:11:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 11:11:40 +0000 |
commit | 7731832751ab9f3c6ddeb66f186d3d7fa1934a6d (patch) | |
tree | e91015872543a59be2aad26c2fea02e41b57005d /contrib/slapd-modules/kinit | |
parent | Initial commit. (diff) | |
download | openldap-7731832751ab9f3c6ddeb66f186d3d7fa1934a6d.tar.xz openldap-7731832751ab9f3c6ddeb66f186d3d7fa1934a6d.zip |
Adding upstream version 2.4.57+dfsg.upstream/2.4.57+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | contrib/slapd-modules/kinit/Makefile | 46 | ||||
-rw-r--r-- | contrib/slapd-modules/kinit/README | 36 | ||||
-rw-r--r-- | contrib/slapd-modules/kinit/kinit.c | 295 |
3 files changed, 377 insertions, 0 deletions
diff --git a/contrib/slapd-modules/kinit/Makefile b/contrib/slapd-modules/kinit/Makefile new file mode 100644 index 0000000..2a925ed --- /dev/null +++ b/contrib/slapd-modules/kinit/Makefile @@ -0,0 +1,46 @@ +# $OpenLDAP$ + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +CC = gcc +OPT = -g -O2 -Wall +DEFS = +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) -lkrb5 + +PROGRAMS = kinit.la +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $< + +all: $(PROGRAMS) + +kinit.la: kinit.lo + $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf *.o *.lo *.la .libs + +install: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + diff --git a/contrib/slapd-modules/kinit/README b/contrib/slapd-modules/kinit/README new file mode 100644 index 0000000..d6f73bb --- /dev/null +++ b/contrib/slapd-modules/kinit/README @@ -0,0 +1,36 @@ +This directory contains the "kinit" slapd module. It is a simple plugin to +have slapd request a Kerberos TGT and keep it renewed as long as slapd is +running. + +The current implementation has only been tested against the MIT variant of +the Kerberos libraries. (Heimdal support might come later) + +To use the overlay just load it into the slapd process: + + moduleload </path/to>/kinit.so <principal> </path/to/key.tab> + +The module accepts two arguments. The first one being the principal for which +to request the TGT (it defaults to "ldap/<your hostname>@<DEFAULTREALM>") +and the second one is the path to the keytab file to use for +authentication, defaulting to whatever your system wide kerberos settings +default to). + +Use Makefile or the following commands should work to +build it from inside the unpacked slapd sources, provided the required KRB5 +header files and libaries are installed on your system: + + gcc -fPIC -c -I ../../../include/ -I ../../../servers/slapd kinit.c + gcc -shared -o kinit.so kinit.o -lkrb5 + +--- +This work is part of OpenLDAP Software <http://www.openldap.org/>. + +Copyright 2010-2021 The OpenLDAP Foundation. + +Redistribution and use in source and binary forms, with or without +modification, are permitted only as authorized by the OpenLDAP +Public License. + +A copy of this license is available in the file LICENSE in the +top-level directory of the distribution or, alternatively, at +<http://www.OpenLDAP.org/license.html>. diff --git a/contrib/slapd-modules/kinit/kinit.c b/contrib/slapd-modules/kinit/kinit.c new file mode 100644 index 0000000..7a83d38 --- /dev/null +++ b/contrib/slapd-modules/kinit/kinit.c @@ -0,0 +1,295 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2010-2021 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ + +#include <portable.h> + +#ifndef SLAPD_MOD_KINIT +#define SLAPD_MOD_KINIT SLAPD_MOD_DYNAMIC +#endif + +#ifdef SLAPD_MOD_KINIT + +#include <slap.h> +#include "ldap_rq.h" +#include <ac/errno.h> +#include <ac/string.h> +#include <krb5/krb5.h> + +typedef struct kinit_data { + krb5_context ctx; + krb5_ccache ccache; + krb5_keytab keytab; + krb5_principal princ; + krb5_get_init_creds_opt *opts; +} kinit_data; + +static char* principal; +static char* kt_name; +static kinit_data *kid; + +static void +log_krb5_errmsg( krb5_context ctx, const char* func, krb5_error_code rc ) +{ + const char* errmsg = krb5_get_error_message(ctx, rc); + Log2(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "slapd-kinit: %s: %s\n", func, errmsg); + krb5_free_error_message(ctx, errmsg); + return; +} + +static int +kinit_check_tgt(kinit_data *kid, int *remaining) +{ + int ret=3; + krb5_principal princ; + krb5_error_code rc; + krb5_cc_cursor cursor; + krb5_creds creds; + char *name; + time_t now=time(NULL); + + rc = krb5_cc_get_principal(kid->ctx, kid->ccache, &princ); + if (rc) { + log_krb5_errmsg(kid->ctx, "krb5_cc_get_principal", rc); + return 2; + } else { + if (!krb5_principal_compare(kid->ctx, kid->princ, princ)) { + Log0(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, + "Principal in ccache does not match requested principal\n"); + krb5_free_principal(kid->ctx, princ); + return 2; + } + } + + rc = krb5_cc_start_seq_get(kid->ctx, kid->ccache, &cursor); + if (rc) { + log_krb5_errmsg(kid->ctx, "krb5_cc_start_seq_get", rc); + krb5_free_principal(kid->ctx, princ); + return -1; + } + + while (!(rc = krb5_cc_next_cred(kid->ctx, kid->ccache, &cursor, &creds))) { + if (krb5_is_config_principal(kid->ctx, creds.server)) { + krb5_free_cred_contents(kid->ctx, &creds); + continue; + } + + if (creds.server->length==2 && + (!strcmp(creds.server->data[0].data, "krbtgt")) && + (!strcmp(creds.server->data[1].data, princ->realm.data))) { + + krb5_unparse_name(kid->ctx, creds.server, &name); + + *remaining = (time_t)creds.times.endtime-now; + if ( *remaining <= 0) { + Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: TGT (%s) expired\n", name); + } else { + Log4(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: TGT (%s) expires in %dh:%02dm:%02ds\n", + name, *remaining/3600, (*remaining%3600)/60, *remaining%60); + } + free(name); + + if (*remaining <= 30) { + if (creds.times.renew_till-60 > now) { + int renewal=creds.times.renew_till-now; + Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Time remaining for renewal: %dh:%02dm:%02ds\n", + renewal/3600, (renewal%3600)/60, renewal%60); + ret = 1; + } else { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Only short time left for renewal. " + "Trying to re-init.\n"); + ret = 2; + } + } else { + ret=0; + } + krb5_free_cred_contents(kid->ctx, &creds); + break; + } + krb5_free_cred_contents(kid->ctx, &creds); + + } + krb5_cc_end_seq_get(kid->ctx, kid->ccache, &cursor); + krb5_free_principal(kid->ctx, princ); + return ret; +} + +void* +kinit_qtask( void *ctx, void *arg ) +{ + struct re_s *rtask = arg; + kinit_data *kid = (kinit_data*)rtask->arg; + krb5_error_code rc; + krb5_creds creds; + int nextcheck, remaining, renew=0; + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: running TGT check\n"); + + memset(&creds, 0, sizeof(creds)); + + renew = kinit_check_tgt(kid, &remaining); + + if (renew > 0) { + if (renew==1) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Trying to renew TGT: "); + rc = krb5_get_renewed_creds(kid->ctx, &creds, kid->princ, kid->ccache, NULL); + if (rc!=0) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n"); + log_krb5_errmsg( kid->ctx, + "kinit_qtask, Renewal failed: krb5_get_renewed_creds", rc ); + renew++; + } else { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n"); + krb5_cc_initialize(kid->ctx, kid->ccache, creds.client); + krb5_cc_store_cred(kid->ctx, kid->ccache, &creds); + krb5_free_cred_contents(kid->ctx, &creds); + renew=kinit_check_tgt(kid, &remaining); + } + } + if (renew > 1) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Trying to get new TGT: "); + rc = krb5_get_init_creds_keytab( kid->ctx, &creds, kid->princ, + kid->keytab, 0, NULL, kid->opts); + if (rc) { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n"); + log_krb5_errmsg(kid->ctx, "krb5_get_init_creds_keytab", rc); + } else { + Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n"); + renew=kinit_check_tgt(kid, &remaining); + } + krb5_free_cred_contents(kid->ctx, &creds); + } + } + if (renew == 0) { + nextcheck = remaining-30; + } else { + nextcheck = 60; + } + + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) { + ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); + } + Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, + "kinit_qtask: Next TGT check in %dh:%02dm:%02ds\n", + nextcheck/3600, (nextcheck%3600)/60, nextcheck%60); + rtask->interval.tv_sec = nextcheck; + ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); + slap_wake_listener(); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + return NULL; +} + +int +kinit_initialize(void) +{ + Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_initialize\n" ); + krb5_error_code rc; + struct re_s *task = NULL; + + kid = ch_calloc(1, sizeof(kinit_data) ); + + rc = krb5_init_context( &kid->ctx ); + if ( !rc ) + rc = krb5_cc_default(kid->ctx, &kid->ccache ); + + if ( !rc ) { + if (!principal) { + int len=STRLENOF("ldap/")+global_host_bv.bv_len+1; + principal=ch_calloc(len, 1); + snprintf(principal, len, "ldap/%s", global_host_bv.bv_val); + Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Principal <%s>\n", principal); + + } + rc = krb5_parse_name(kid->ctx, principal, &kid->princ); + } + + if ( !rc && kt_name) { + rc = krb5_kt_resolve(kid->ctx, kt_name, &kid->keytab); + } + + if ( !rc ) + rc = krb5_get_init_creds_opt_alloc(kid->ctx, &kid->opts); + + if ( !rc ) + rc = krb5_get_init_creds_opt_set_out_ccache( kid->ctx, kid->opts, kid->ccache); + + if ( !rc ) { + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + task = ldap_pvt_runqueue_insert( &slapd_rq, 10, kinit_qtask, (void*)kid, + "kinit_qtask", "ldap/bronsted.g17.lan@G17.LAN" ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + } + + if (rc) { + log_krb5_errmsg(kid->ctx, "kinit_initialize", rc); + rc = -1; + } + return rc; +} + +#if SLAPD_MOD_KINIT == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + if (argc > 0) { + principal = ch_strdup(argv[0]); + } + if (argc > 1) { + kt_name = ch_strdup(argv[1]); + } + if (argc > 2) { + return -1; + } + return kinit_initialize(); +} + +int +term_module() { + if (principal) + ch_free(principal); + if (kt_name) + ch_free(kt_name); + if (kid) { + struct re_s *task; + + task=ldap_pvt_runqueue_find( &slapd_rq, kinit_qtask, (void*)kid); + if (task) { + if ( ldap_pvt_runqueue_isrunning(&slapd_rq, task) ) { + ldap_pvt_runqueue_stoptask(&slapd_rq, task); + } + ldap_pvt_runqueue_remove(&slapd_rq, task); + } + if ( kid->ctx ) { + if ( kid->princ ) + krb5_free_principal(kid->ctx, kid->princ); + if ( kid->ccache ) + krb5_cc_close(kid->ctx, kid->ccache); + if ( kid->keytab ) + krb5_kt_close(kid->ctx, kid->keytab); + if ( kid->opts ) + krb5_get_init_creds_opt_free(kid->ctx, kid->opts); + krb5_free_context(kid->ctx); + } + ch_free(kid); + } + return 0; +} +#endif + +#endif /* SLAPD_MOD_KINIT */ + |