From b9c563c29243291f40489bb0dcbf3946fca72d58 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mar 27 2017 07:56:19 +0000 Subject: KCM: Initial responder build and packaging Adds the initial build of the Kerberos Cache Manager responder (KCM). This is a deamon that is capable of holding and storing Kerberos ccaches. When KCM is used, the kerberos libraries (invoked through e.g. kinit) are referred to as a 'client' and the KCM deamon is referred to as 'server'. At the moment, only the Heimdal implementation of Kerberos implements the KCM server: https://www.h5l.org/manual/HEAD/info/heimdal/Credential-cache-server-_002d-KCM.html This patch adds a KCM server to SSSD. In MIT, only the 'client-side' support was added: http://k5wiki.kerberos.org/wiki/Projects/KCM_client This page also describes the protocol between the client and the server. The client is capable of talking to the server over either UNIX sockets (Linux, most Unixes) or Mach RPC (macOS). Our server only implements the UNIX sockets way and should be socket-activated by systemd, although can in theory be also ran explicitly. The KCM server only builds if the configuration option "--with-kcm" is enabled. It is packaged in a new subpackage sssd-kcm in order to allow distributions to enable the KCM credential caches by installing this subpackage only, without the rest of the SSSD. The sssd-kcm subpackage also includes a krb5.conf.d snippet that allows the admin to just uncomment the KCM defaults and instructs them to start the socket. The server can be configured in sssd.conf in the "[kcm]" section. By default, the server only listens on the same socket path the Heimdal server uses, which is "/var/run/.heim_org.h5l.kcm-socket". This is, however, configurable. The file src/responder/kcm/kcm.h is more or less directly imported from the MIT Kerberos tree, with an additional sentinel code and some comments. Not all KCM operations are implemented, only those that also the MIT client implements. That said, this KCM server should also be usable with a Heimdal client, although no special testing was with this hybrid. The patch also adds several error codes that will be used in later patches. Related to: https://pagure.io/SSSD/sssd/issue/2887 Reviewed-by: Michal Židek Reviewed-by: Simo Sorce --- diff --git a/Makefile.am b/Makefile.am index 7516338..4248536 100644 --- a/Makefile.am +++ b/Makefile.am @@ -87,6 +87,7 @@ sudolibdir = @sudolibpath@ polkitdir = @polkitdir@ pamconfdir = $(sysconfdir)/pam.d systemtap_tapdir = @tapset_dir@ +krb5sysincludedir = $(sysconfdir)/krb5.conf.d if HAVE_SYSTEMD_UNIT ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated @@ -186,6 +187,11 @@ endif if BUILD_SECRETS sssdlibexec_PROGRAMS += sssd_secrets endif +if BUILD_KCM +sssdlibexec_PROGRAMS += sssd_kcm +dist_krb5sysinclude_DATA = contrib/kcm_default_ccache +endif + if BUILD_PAC_RESPONDER sssdlibexec_PROGRAMS += sssd_pac @@ -703,6 +709,8 @@ dist_noinst_HEADERS = \ src/responder/secrets/secsrv_private.h \ src/responder/secrets/secsrv_local.h \ src/responder/secrets/secsrv_proxy.h \ + src/responder/kcm/kcm.h \ + src/responder/kcm/kcmsrv_pvt.h \ src/sbus/sbus_client.h \ src/sbus/sssd_dbus.h \ src/sbus/sssd_dbus_meta.h \ @@ -1476,6 +1484,24 @@ sssd_secrets_LDADD = \ $(NULL) endif +if BUILD_KCM +sssd_kcm_SOURCES = \ + src/responder/kcm/kcm.c \ + src/responder/kcm/kcmsrv_cmd.c \ + src/util/sss_sockets.c \ + $(SSSD_RESPONDER_OBJ) \ + $(NULL) +sssd_kcm_CFLAGS = \ + $(AM_CFLAGS) \ + $(KRB5_CFLAGS) \ + $(NULL) +sssd_kcm_LDADD = \ + $(KRB5_LIBS) \ + $(SSSD_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + $(NULL) +endif + sssd_be_SOURCES = \ src/providers/data_provider_be.c \ src/providers/data_provider_req.c \ @@ -4259,6 +4285,12 @@ if BUILD_SUDO src/sysv/systemd/sssd-sudo.service \ $(NULL) endif +if BUILD_KCM + systemdunit_DATA += \ + src/sysv/systemd/sssd-kcm.socket \ + src/sysv/systemd/sssd-kcm.service \ + $(NULL) +endif if WITH_JOURNALD systemdconf_DATA += \ src/sysv/systemd/journal.conf @@ -4350,6 +4382,12 @@ EXTRA_DIST += \ src/sysv/systemd/sssd-sudo.service.in \ $(NULL) endif +if BUILD_KCM +EXTRA_DIST += \ + src/sysv/systemd/sssd-kcm.socket.in \ + src/sysv/systemd/sssd-kcm.service.in \ + $(NULL) +endif src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile @$(MKDIR_P) src/sysv/systemd/ @@ -4433,6 +4471,16 @@ src/sysv/systemd/sssd-sudo.service: src/sysv/systemd/sssd-sudo.service.in Makefi $(replace_script) endif +if BUILD_KCM +src/sysv/systemd/sssd-kcm.socket: src/sysv/systemd/sssd-kcm.socket.in Makefile + @$(MKDIR_P) src/sysv/systemd/ + $(replace_script) + +src/sysv/systemd/sssd-kcm.service: src/sysv/systemd/sssd-kcm.service.in Makefile + @$(MKDIR_P) src/sysv/systemd/ + $(replace_script) +endif + SSSD_USER_DIRS = \ $(DESTDIR)$(dbpath) \ $(DESTDIR)$(keytabdir) \ @@ -4596,6 +4644,9 @@ install-data-hook: if BUILD_SAMBA mv $(DESTDIR)/$(winbindplugindir)/winbind_idmap_sss.so $(DESTDIR)/$(winbindplugindir)/sss.so endif +if BUILD_KCM + $(MKDIR_P) $(DESTDIR)/$(krb5sysincludedir) +endif uninstall-hook: if [ -f $(abs_builddir)/src/config/.files2 ]; then \ @@ -4670,6 +4721,8 @@ endif rm -f $(builddir)/src/sysv/systemd/sssd-sudo.service rm -f $(builddir)/src/sysv/systemd/sssd-secrets.socket rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service + rm -f $(builddir)/src/sysv/systemd/sssd-kcm.socket + rm -f $(builddir)/src/sysv/systemd/sssd-kcm.service rm -f $(builddir)/src/sysv/systemd/journal.conf CLEANFILES += *.X */*.X */*/*.X diff --git a/configure.ac b/configure.ac index dd10120..c363d48 100644 --- a/configure.ac +++ b/configure.ac @@ -155,6 +155,7 @@ WITH_SSSD_USER SSSD_RUNSTATEDIR WITH_SECRETS WITH_SECRETS_DB_PATH +WITH_KCM m4_include([src/external/pkg.m4]) m4_include([src/external/libpopt.m4]) @@ -193,13 +194,20 @@ m4_include([src/external/libresolv.m4]) m4_include([src/external/intgcheck.m4]) m4_include([src/external/systemtap.m4]) m4_include([src/external/service.m4]) -m4_include([src/external/libcurl.m4]) if test x$with_secrets = xyes; then m4_include([src/external/libhttp_parser.m4]) m4_include([src/external/libjansson.m4]) fi +if test x$with_kcm = xyes; then + m4_include([src/external/libcurl.m4]) +fi +# This variable is defined by external/libcurl.m4, but conditionals +# must be always evaluated +AM_CONDITIONAL([BUILD_WITH_LIBCURL], + [test x"$have_curlopt_unix_sockpath" = xyes]) + WITH_UNICODE_LIB if test x$unicode_lib = xlibunistring; then m4_include([src/external/libunistring.m4]) diff --git a/contrib/kcm_default_ccache b/contrib/kcm_default_ccache new file mode 100644 index 0000000..ac88fca --- /dev/null +++ b/contrib/kcm_default_ccache @@ -0,0 +1,12 @@ +# This file should normally be installed by your distribution into a +# directory that is included from the Kerberos configuration file (/etc/krb5.conf) +# On Fedora/RHEL/CentOS, this is /etc/krb5.conf.d/ +# +# To enable the KCM credential cache, uncomment the following lines and +# enable the KCM socket and the service: +# systemctl enable sssd-kcm.socket +# systemctl start sssd-kcm.socket +# systemctl enable sssd-kcm.service + +#[libdefaults] +# default_ccache_name = KCM: diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 28ebe07..5c7c2af 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -112,6 +112,13 @@ %global enable_systemtap_opt --enable-systemtap %endif +%if (0%{?fedora} >= 23 || 0%{?rhel} >= 7) + %global with_kcm 1 + %global with_kcm_option --with-kcm +%else + %global with_kcm_option --without-kcm +%endif + Name: @PACKAGE_NAME@ Version: @PACKAGE_VERSION@ Release: 0@PRERELEASE_VERSION@%{?dist} @@ -677,6 +684,18 @@ Requires: libsss_certmap = %{version}-%{release} %description -n libsss_certmap-devel Library to map certificates to users based on rules +%if (0%{?with_kcm} == 1) +%package kcm +Summary: An implementation of a Kerberos KCM server +Group: Applications/System +License: GPLv3+ +Requires: sssd-common = %{version}-%{release} + +%description kcm +An implementation of a Kerberos KCM server. Use this package if you want to +use the KCM: Kerberos credentials cache. +%endif + %prep %setup -q -n %{name}-%{version} @@ -706,6 +725,7 @@ autoreconf -ivf %{?with_python3_option} \ %{?enable_polkit_rules_option} \ %{?enable_systemtap_opt} \ + %{?with_kcm_option} \ %{?experimental} make %{?_smp_mflags} all @@ -1178,6 +1198,15 @@ done %{_libdir}/libsss_certmap.so %{_libdir}/pkgconfig/sss_certmap.pc +%if (0%{?with_kcm} == 1) +%files kcm +%{_libexecdir}/%{servicename}/sssd_kcm +%dir %{_sysconfdir}/krb5.conf.d +%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache +%{_unitdir}/sssd-kcm.socket +%{_unitdir}/sssd-kcm.service +%endif + %pre common getent group sssd >/dev/null || groupadd -r sssd getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd @@ -1274,6 +1303,18 @@ fi %postun -n libsss_simpleifp -p /sbin/ldconfig +%if (0%{?with_kcm} == 1) +%post kcm +%systemd_post sssd-kcm.socket + +%preun kcm +%systemd_preun sssd-kcm.socket + +%postun kcm +%systemd_postun_with_restart sssd-kcm.socket +%systemd_postun_with_restart sssd-kcm.service +%endif + %changelog * Mon Mar 15 2010 Stephen Gallagher - @PACKAGE_VERSION@-0@PRERELEASE_VERSION@ - Automated build of the SSSD diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 index 749e769..4209972 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 @@ -887,6 +887,22 @@ AC_DEFUN([WITH_SECRETS], AM_CONDITIONAL([BUILD_SECRETS], [test x"$with_secrets" = xyes]) ]) +AC_DEFUN([WITH_KCM], + [ AC_ARG_WITH([kcm], + [AC_HELP_STRING([--with-kcm], + [Whether to build with KCM server support [yes]] + ) + ], + [with_kcm=$withval], + with_kcm=yes + ) + + if test x"$with_kcm" = xyes; then + AC_DEFINE(BUILD_KCM, 1, [whether to build with KCM server support]) + fi + AM_CONDITIONAL([BUILD_KCM], [test x"$with_kcm" = xyes]) + ]) + AC_DEFUN([WITH_SECRETS_DB_PATH], [ AC_ARG_WITH([secrets-db-path], [AC_HELP_STRING([--with-secrets-db-path=PATH], diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index c05b1ce..c443e86 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -231,6 +231,9 @@ #define CONFDB_SEC_MAX_SECRETS "max_secrets" #define CONFDB_SEC_MAX_PAYLOAD_SIZE "max_payload_size" +/* KCM Service */ +#define CONFDB_KCM_CONF_ENTRY "config/kcm" +#define CONFDB_KCM_SOCKET "socket_path" struct confdb_ctx; struct config_file_ctx; diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index c287328..5e789c5 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -9,6 +9,7 @@ section = ssh section = pac section = ifp section = secrets +section = kcm section_re = ^secrets/users/[0-9]\+$ section_re = ^domain/.*$ @@ -262,6 +263,24 @@ option = forward_headers option = username option = password +# KCM responder +[rule/allowed_kcm_options] +validator = ini_allowed_options +section_re = ^kcm$ + +option = timeout +option = debug +option = debug_level +option = debug_timestamps +option = debug_microseconds +option = debug_to_files +option = command +option = reconnection_retries +option = fd_limit +option = client_idle_timeout +option = description +option = socket_path + [rule/allowed_domain_options] validator = ini_allowed_options section_re = ^domain/.*$ diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 index 3bc303c..b420b04 100644 --- a/src/external/libcurl.m4 +++ b/src/external/libcurl.m4 @@ -9,8 +9,8 @@ AS_IF([test x$enable_libcurl = xyes], [PKG_CHECK_MODULES([CURL], [libcurl], [found_libcurl=yes], - [AC_MSG_WARN([ -The libcurl development library was not found. Some features will be disabled.]) + [AC_MSG_ERROR([ +The libcurl development library was not found.]) ])]) AS_IF([test x"$found_libcurl" = xyes], @@ -32,7 +32,5 @@ AS_IF([test x"$found_libcurl" = xyes], AC_SUBST(CURL_LIBS) AC_SUBST(CURL_CFLAGS) -AM_CONDITIONAL([BUILD_WITH_LIBCURL], - [test x"$have_curlopt_unix_sockpath" = xyes]) AM_COND_IF([BUILD_WITH_LIBCURL], [AC_DEFINE_UNQUOTED(HAVE_LIBCURL, 1, [Build with libcurl support])]) diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c new file mode 100644 index 0000000..90a6999 --- /dev/null +++ b/src/responder/kcm/kcm.c @@ -0,0 +1,254 @@ +/* + SSSD + + KCM Server - the mainloop and server setup + + Copyright (C) Red Hat, 2016 + + 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 . +*/ + +#include "config.h" + +#include +#include + +#include "responder/kcm/kcm.h" +#include "responder/kcm/kcmsrv_pvt.h" +#include "responder/common/responder.h" +#include "util/util.h" + +#define DEFAULT_KCM_FD_LIMIT 2048 + +#ifndef SSS_KCM_SOCKET_NAME +#define SSS_KCM_SOCKET_NAME DEFAULT_KCM_SOCKET_PATH +#endif + +static int kcm_responder_ctx_destructor(void *ptr) +{ + struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx); + + /* mark that we are shutting down the responder, so it is propagated + * into underlying contexts that are freed right before rctx */ + DEBUG(SSSDBG_TRACE_FUNC, "Responder is being shut down\n"); + rctx->shutting_down = true; + + return 0; +} + +static int kcm_get_config(struct kcm_ctx *kctx) +{ + int ret; + char *sock_name; + + ret = confdb_get_int(kctx->rctx->cdb, + CONFDB_KCM_CONF_ENTRY, + CONFDB_SERVICE_FD_LIMIT, + DEFAULT_KCM_FD_LIMIT, + &kctx->fd_limit); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get file descriptors limit\n"); + goto done; + } + + ret = confdb_get_int(kctx->rctx->cdb, + kctx->rctx->confdb_service_path, + CONFDB_RESPONDER_CLI_IDLE_TIMEOUT, + CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT, + &kctx->rctx->client_idle_timeout); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot get the client idle timeout [%d]: %s\n", + ret, strerror(ret)); + goto done; + } + + /* Ensure that the client timeout is at least ten seconds */ + if (kctx->rctx->client_idle_timeout < 10) { + kctx->rctx->client_idle_timeout = 10; + } + + ret = confdb_get_string(kctx->rctx->cdb, + kctx->rctx, + kctx->rctx->confdb_service_path, + CONFDB_KCM_SOCKET, + SSS_KCM_SOCKET_NAME, + &sock_name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot get the client idle timeout [%d]: %s\n", + ret, strerror(ret)); + goto done; + } + kctx->rctx->sock_name = sock_name; + + ret = EOK; + +done: + return ret; +} + +static int kcm_data_destructor(void *ptr) +{ + struct kcm_resp_ctx *kcm_data = talloc_get_type(ptr, struct kcm_resp_ctx); + + if (kcm_data != NULL) { + krb5_free_context(kcm_data->k5c); + } + return 0; +} + +static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) +{ + struct kcm_resp_ctx *kcm_data; + krb5_error_code kret; + + kcm_data = talloc_zero(mem_ctx, struct kcm_resp_ctx); + if (kcm_data == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing kcm data\n"); + return NULL; + } + + kret = krb5_init_context(&kcm_data->k5c); + if (kret != EOK) { + talloc_free(kcm_data); + return NULL; + } + talloc_set_destructor((TALLOC_CTX*)kcm_data, kcm_data_destructor); + + return kcm_data; +} + +static int kcm_process_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct confdb_ctx *cdb) +{ + struct resp_ctx *rctx; + struct kcm_ctx *kctx; + int ret; + + rctx = talloc_zero(mem_ctx, struct resp_ctx); + if (rctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n"); + return ENOMEM; + } + rctx->ev = ev; + rctx->cdb = cdb; + rctx->confdb_service_path = CONFDB_KCM_CONF_ENTRY; + rctx->shutting_down = false; + rctx->lfd = -1; + rctx->priv_lfd = -1; + + talloc_set_destructor((TALLOC_CTX*)rctx, kcm_responder_ctx_destructor); + + kctx = talloc_zero(rctx, struct kcm_ctx); + if (kctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing kcm_ctx\n"); + ret = ENOMEM; + goto fail; + } + + kctx->rctx = rctx; + kctx->rctx->pvt_ctx = kctx; + + ret = kcm_get_config(kctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "fatal error getting KCM config\n"); + goto fail; + } + + kctx->kcm_data = kcm_data_setup(kctx); + if (kctx->kcm_data == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error initializing responder data\n"); + ret = EIO; + goto fail; + } + + /* Set up file descriptor limits */ + responder_set_fd_limit(kctx->fd_limit); + + ret = activate_unix_sockets(rctx, kcm_connection_setup); + if (ret != EOK) goto fail; + + DEBUG(SSSDBG_TRACE_FUNC, "KCM Initialization complete\n"); + + return EOK; + +fail: + talloc_free(rctx); + return ret; +} + +int main(int argc, const char *argv[]) +{ + int opt; + poptContext pc; + struct main_context *main_ctx; + int ret; + uid_t uid; + gid_t gid; + + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS + SSSD_SERVER_OPTS(uid, gid) + POPT_TABLEEND + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + umask(DFL_RSP_UMASK); + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + return 1; + } + } + + poptFreeContext(pc); + + DEBUG_INIT(debug_level); + + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_kcm"; + + ret = server_setup("sssd[kcm]", 0, uid, gid, CONFDB_KCM_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; + + ret = die_if_parent_died(); + if (ret != EOK) { + /* This is not fatal, don't return */ + DEBUG(SSSDBG_OP_FAILURE, + "Could not set up to exit when parent process does\n"); + } + + ret = kcm_process_init(main_ctx, + main_ctx->event_ctx, + main_ctx->confdb_ctx); + if (ret != EOK) return 3; + + /* loop on main */ + server_loop(main_ctx); + + return 0; +} diff --git a/src/responder/kcm/kcm.h b/src/responder/kcm/kcm.h new file mode 100644 index 0000000..1ea7e9b --- /dev/null +++ b/src/responder/kcm/kcm.h @@ -0,0 +1,97 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* include/kcm.h - Kerberos cache manager protocol declarations */ +/* + * Copyright (C) 2014 by the Massachusetts Institute of Technology. + * 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. + */ + +#ifndef KCM_H +#define KCM_H + +#define KCM_PROTOCOL_VERSION_MAJOR 2 +#define KCM_PROTOCOL_VERSION_MINOR 0 + +#define KCM_UUID_LEN 16 + +/* This should ideally be in RUNSTATEDIR, but Heimdal uses a hardcoded + * /var/run, and we need to use the same default path. */ +#define DEFAULT_KCM_SOCKET_PATH "/var/run/.heim_org.h5l.kcm-socket" +#define DEFAULT_KCM_MACH_SERVICE "org.h5l.kcm" + +/* + * All requests begin with: + * major version (1 bytes) + * minor version (1 bytes) + * opcode (16-bit big-endian) + * + * All replies begin with a 32-bit big-endian reply code. + * + * Parameters are appended to the request or reply with no delimiters. Flags + * and time offsets are stored as 32-bit big-endian integers. Names are + * marshalled as zero-terminated strings. Principals and credentials are + * marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists + * are not delimited, so nothing can come after them. + */ + +/* Opcodes without comments are currently unused in the MIT client + * implementation. */ +typedef enum kcm_opcode { + KCM_OP_NOOP, + KCM_OP_GET_NAME, + KCM_OP_RESOLVE, + KCM_OP_GEN_NEW, /* 0x3 () -> (name) */ + KCM_OP_INITIALIZE, /* 0x4 (name, princ) -> () */ + KCM_OP_DESTROY, /* 0x4 (name) -> () */ + KCM_OP_STORE, /* 0x6 (name, cred) -> () */ + KCM_OP_RETRIEVE, + KCM_OP_GET_PRINCIPAL, /* 0x8 (name) -> (princ) */ + KCM_OP_GET_CRED_UUID_LIST, /* 0x9 (name) -> (uuid, ...) */ + KCM_OP_GET_CRED_BY_UUID, /* 0xa (name, uuid) -> (cred) */ + KCM_OP_REMOVE_CRED, /* (name, flags, credtag) -> () */ + KCM_OP_SET_FLAGS, + KCM_OP_CHOWN, + KCM_OP_CHMOD, + KCM_OP_GET_INITIAL_TICKET, + KCM_OP_GET_TICKET, + KCM_OP_MOVE_CACHE, + KCM_OP_GET_CACHE_UUID_LIST, /* 0x12 () -> (uuid, ...) */ + KCM_OP_GET_CACHE_BY_UUID, /* 0x13 (uuid) -> (name) */ + KCM_OP_GET_DEFAULT_CACHE, /* 0x14 () -> (name) */ + KCM_OP_SET_DEFAULT_CACHE, /* 0x15 (name) -> () */ + KCM_OP_GET_KDC_OFFSET, /* 0x16 (name) -> (offset) */ + KCM_OP_SET_KDC_OFFSET, /* 0x17 (name, offset) -> () */ + KCM_OP_ADD_NTLM_CRED, + KCM_OP_HAVE_NTLM_CRED, + KCM_OP_DEL_NTLM_CRED, + KCM_OP_DO_NTLM_AUTH, + KCM_OP_GET_NTLM_USER_LIST, + + KCM_OP_SENTINEL, /* SSSD addition, not in the MIT header */ +} kcm_opcode; + +#endif /* KCM_H */ diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c new file mode 100644 index 0000000..e9a03cb --- /dev/null +++ b/src/responder/kcm/kcmsrv_cmd.c @@ -0,0 +1,65 @@ +/* + SSSD + + KCM Server - the KCM server request and reply parsing and dispatching + + Copyright (C) Red Hat, 2016 + + 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 . +*/ + +#include "config.h" +#include "util/util.h" +#include "responder/common/responder.h" + +struct kcm_proto_ctx { + void *unused; +}; + +static void kcm_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *ptr) +{ + errno_t ret; + struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx); + + /* Always reset the idle timer on any activity */ + ret = reset_client_idle_timer(cctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not create idle timer for client. " + "This connection may not auto-terminate\n"); + /* Non-fatal, continue */ + } +} + +int kcm_connection_setup(struct cli_ctx *cctx) +{ + struct kcm_proto_ctx *protocol_ctx; + + protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx); + if (protocol_ctx == NULL) { + return ENOMEM; + } + + cctx->protocol_ctx = protocol_ctx; + cctx->cfd_handler = kcm_fd_handler; + return EOK; +} + +/* Dummy, not used here but required to link to other responder files */ +struct cli_protocol_version *register_cli_protocol_version(void) +{ + return NULL; +} diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h new file mode 100644 index 0000000..a7c9d06 --- /dev/null +++ b/src/responder/kcm/kcmsrv_pvt.h @@ -0,0 +1,58 @@ +/* + SSSD + + KCM Server - private header file + + Copyright (C) Red Hat, 2016 + + 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 . +*/ + +#ifndef __KCMSRV_PVT_H__ +#define __KCMSRV_PVT_H__ + +#include "config.h" + +#include +#include "responder/common/responder.h" + +/* KCM IO structure */ +struct kcm_data { + uint8_t *data; + size_t length; +}; + +/* To avoid leaking the sssd-specific responder data to other + * modules, the ccache databases and other KCM specific data + * are kept separately + */ +struct kcm_resp_ctx { + krb5_context k5c; +}; + +/* responder context that contains both the responder data, + * like the ccaches and the sssd-specific stuff like the + * generic responder ctx + */ +struct kcm_ctx { + struct resp_ctx *rctx; + int fd_limit; + char *socket_path; + + struct kcm_resp_ctx *kcm_data; +}; + +int kcm_connection_setup(struct cli_ctx *cctx); + +#endif /* __KCMSRV_PVT_H__ */ diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in new file mode 100644 index 0000000..1e2bee1 --- /dev/null +++ b/src/sysv/systemd/sssd-kcm.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=SSSD Kerberos Cache Manager +Documentation=man:sssd-kcm(5) + +[Install] +Also=sssd-kcm.socket + +[Service] +ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 --debug-to-files diff --git a/src/sysv/systemd/sssd-kcm.socket.in b/src/sysv/systemd/sssd-kcm.socket.in new file mode 100644 index 0000000..80ec1c0 --- /dev/null +++ b/src/sysv/systemd/sssd-kcm.socket.in @@ -0,0 +1,10 @@ +[Unit] +Description=SSSD Secrets Service responder socket +Documentation=man:sssd-kcm(8) +Requires=sssd-secrets.socket + +[Socket] +ListenStream=@localstatedir@/run/.heim_org.h5l.kcm-socket + +[Install] +WantedBy=sockets.target diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 17388c9..23cfdf9 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -40,6 +40,7 @@ struct err_string error_to_str[] = { { "Credentials are expired, old ccache was removed" }, /* ERR_CREDS_EXPIRED_CCACHE */ { "Failure setting user credentials"}, /* ERR_CREDS_INVALID */ { "No cached credentials available" }, /* ERR_NO_CACHED_CREDS */ + { "No matching credentials found" }, /* ERR_NO_MATCHING_CREDS */ { "Cached credentials are expired" }, /* ERR_CACHED_CREDS_EXPIRED */ { "Authentication Denied" }, /* ERR_AUTH_DENIED */ { "Authentication Failed" }, /* ERR_AUTH_FAILED */ @@ -104,6 +105,10 @@ struct err_string error_to_str[] = { { "The secret payload size is too large" }, /* ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE */ { "No authentication methode available" }, /* ERR_NO_AUTH_METHOD_AVAILABLE */ { "Smartcard authentication not supported" }, /* ERR_SC_AUTH_NOT_SUPPORTED */ + { "Malformed input KCM packet" }, /* ERR_KCM_MALFORMED_IN_PKT */ + { "KCM operation not implemented" }, /* ERR_KCM_OP_NOT_IMPLEMENTED */ + { "End of credential cache reached" }, /* ERR_KCM_CC_END */ + { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ { "ERR_LAST" } /* ERR_LAST */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index 7aacad2..387d481 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -62,6 +62,7 @@ enum sssd_errors { ERR_CREDS_EXPIRED_CCACHE, ERR_CREDS_INVALID, ERR_NO_CACHED_CREDS, + ERR_NO_MATCHING_CREDS, ERR_CACHED_CREDS_EXPIRED, ERR_AUTH_DENIED, ERR_AUTH_FAILED, @@ -126,6 +127,10 @@ enum sssd_errors { ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE, ERR_NO_AUTH_METHOD_AVAILABLE, ERR_SC_AUTH_NOT_SUPPORTED, + ERR_KCM_MALFORMED_IN_PKT, + ERR_KCM_OP_NOT_IMPLEMENTED, + ERR_KCM_CC_END, + ERR_KCM_WRONG_CCNAME_FORMAT, ERR_LAST /* ALWAYS LAST */ };