>From 31af93f59adfc4a74df19e1fb56948a8b95e58e2 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 19 Nov 2009 17:53:38 +0100 Subject: [PATCH] Read KDC info from file instead from environment Then name or IP adress of the KDC is written into the pubconf directory into a file named kdcinfo.REALM. The locator plugin will then read this file and pass the data to the kerberos libraries. --- contrib/sssd.spec.in | 3 + server/Makefile.am | 4 +- server/conf_macros.m4 | 17 ++ server/configure.ac | 1 + server/krb5_plugin/sssd_krb5_locator_plugin.c | 122 ++++++++++---- server/providers/ipa/ipa_common.c | 30 +++- server/providers/ipa/ipa_common.h | 5 +- server/providers/ipa/ipa_init.c | 13 +- server/providers/krb5/krb5_auth.c | 61 ++++++- server/providers/krb5/krb5_auth.h | 4 +- server/providers/krb5/krb5_common.c | 224 +++++++++++++++++++++++-- server/providers/krb5/krb5_common.h | 12 ++- server/providers/krb5/krb5_init.c | 52 +++++- 13 files changed, 474 insertions(+), 74 deletions(-) diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 173d049..1251fe5 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -28,6 +28,7 @@ Requires(postun): /sbin/service %define sssdstatedir %{_localstatedir}/lib/sss %define dbpath %{sssdstatedir}/db %define pipepath %{sssdstatedir}/pipes +%define pubconfpath %{sssdstatedir}/pubconf ### Build Dependencies ### @@ -80,6 +81,7 @@ KRB5_LIBS=-lkrb5 \ --without-tests \ --with-db-path=%{dbpath} \ --with-pipe-path=%{pipepath} \ + --with-pubconf-path=%{pubconfpath} \ --with-init-dir=%{_initrddir} \ --enable-nsslibdir=/%{_lib} @@ -138,6 +140,7 @@ rm -rf $RPM_BUILD_ROOT %dir %{sssdstatedir} %attr(700,root,root) %dir %{dbpath} %attr(755,root,root) %dir %{pipepath} +%attr(755,root,root) %dir %{pubconfpath} %attr(700,root,root) %dir %{pipepath}/private %attr(750,root,root) %dir %{_var}/log/%{name} %attr(700,root,root) %dir %{_sysconfdir}/sssd diff --git a/server/Makefile.am b/server/Makefile.am index c40942a..6db4f04 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -22,6 +22,7 @@ pidpath = @pidpath@ pipepath = @pipepath@ initdir = @initdir@ logpath = @logpath@ +pubconfpath = @pubconfpath@ AM_CFLAGS = if WANT_AUX_INFO @@ -749,7 +750,8 @@ installsssddirs:: $(DESTDIR)$(dbpath) \ $(DESTDIR)$(pidpath) \ $(DESTDIR)$(initdir) \ - $(DESTDIR)$(logpath) + $(DESTDIR)$(logpath) \ + $(DESTDIR)$(pubconfpath) install-exec-hook: installsssddirs if [ "$(DESTDIR)" = "" ]; then \ diff --git a/server/conf_macros.m4 b/server/conf_macros.m4 index 0990e50..86ccf5d 100644 --- a/server/conf_macros.m4 +++ b/server/conf_macros.m4 @@ -66,6 +66,23 @@ AC_DEFUN([WITH_LOG_PATH], AC_DEFINE_UNQUOTED(LOG_PATH, "$config_logpath", [Where to store log files for the SSSD]) ]) +AC_DEFUN([WITH_PUBCONF_PATH], + [ AC_ARG_WITH([pubconf-path], + [AC_HELP_STRING([--with-pubconf-path=PATH], + [Where to store pubconf files for the SSSD [/var/lib/sss/pubconf]] + ) + ] + ) + config_pubconfpath="\"VARDIR\"/lib/sss/pubconf" + pubconfpath="${localstatedir}/lib/sss/pubconf" + if test x"$with_pubconf_path" != x; then + config_pubconfpath=$with_pubconf_path + pubconfpath=$with_pubconf_path + fi + AC_SUBST(pubconfpath) + AC_DEFINE_UNQUOTED(PUBCONF_PATH, "$config_pubconfpath", [Where to store pubconf files for the SSSD]) + ]) + AC_DEFUN([WITH_PIPE_PATH], [ AC_ARG_WITH([pipe-path], [AC_HELP_STRING([--with-pipe-path=PATH], diff --git a/server/configure.ac b/server/configure.ac index 1a94158..696a5a4 100644 --- a/server/configure.ac +++ b/server/configure.ac @@ -45,6 +45,7 @@ WITH_DB_PATH WITH_PLUGIN_PATH WITH_PID_PATH WITH_LOG_PATH +WITH_PUBCONF_PATH WITH_PIPE_PATH WITH_INIT_DIR WITH_SHADOW_UTILS_PATH diff --git a/server/krb5_plugin/sssd_krb5_locator_plugin.c b/server/krb5_plugin/sssd_krb5_locator_plugin.c index a30586c..5e79733 100644 --- a/server/krb5_plugin/sssd_krb5_locator_plugin.c +++ b/server/krb5_plugin/sssd_krb5_locator_plugin.c @@ -27,12 +27,14 @@ #include #include #include - +#include +#include #include #include "providers/krb5/krb5_common.h" +#define BUFSIZE 512 #define SSSD_KRB5_LOCATOR_DEBUG "SSSD_KRB5_LOCATOR_DEBUG" #define DEBUG_KEY "[sssd_krb5_locator] " #define PLUGIN_DEBUG(body) do { \ @@ -67,33 +69,60 @@ void debug_fn(const char *format, ...) free(s); } -krb5_error_code sssd_krb5_locator_init(krb5_context context, - void **private_data) +static int get_kdcinfo(const char *realm, struct sssd_ctx *ctx) { - struct sssd_ctx *ctx; - const char *dummy; int ret; + char *kdcinfo_name = NULL; + size_t len; + uint8_t buf[BUFSIZE + 1]; + uint8_t *p; + int fd = -1; + + len = strlen(realm) + strlen(KDCINFO_TMPL); + + kdcinfo_name = calloc(1, len + 1); + if (kdcinfo_name == NULL) { + PLUGIN_DEBUG(("malloc failed.\n")); + return ENOMEM; + } - ctx = calloc(1,sizeof(struct sssd_ctx)); - if (ctx == NULL) return ENOMEM; + ret = snprintf(kdcinfo_name, len, KDCINFO_TMPL, realm); + if (ret < 0) { + PLUGIN_DEBUG(("snprintf failed")); + ret = EINVAL; + } + kdcinfo_name[len] = '\0'; - dummy = getenv(SSSD_KRB5_LOCATOR_DEBUG); - if (dummy == NULL) { - ctx->debug = false; - } else { - ctx->debug = true; - PLUGIN_DEBUG(("sssd_krb5_locator_init called\n")); + fd = open(kdcinfo_name, O_RDONLY); + if (fd == -1) { + PLUGIN_DEBUG(("open failed [%d][%s].\n", errno, strerror(errno))); + ret = errno; + goto done; } - dummy = getenv(SSSD_KRB5_REALM); - if (dummy == NULL) goto failed; - ctx->sssd_realm = strdup(dummy); - if (ctx->sssd_realm == NULL) goto failed; + len = BUFSIZE; + p = buf; + memset(buf, 0, BUFSIZE+1); + while (len != 0 && (ret = read(fd, p, len)) != 0) { + if (ret == -1) { + if (errno == EINTR) continue; + PLUGIN_DEBUG(("read failed [%d][%s].\n", errno, strerror(errno))); + close(fd); + goto done; + } - dummy = getenv(SSSD_KRB5_KDC); - if (dummy == NULL) goto failed; + len -= ret; + p += ret; + } + close(fd); - ret = getaddrinfo(dummy, "kerberos", NULL, &ctx->sssd_kdc_addrinfo); + if (len == 0) { + PLUGIN_DEBUG(("Content of kdcinfo file [%s] is [%d] or larger.\n", + kdcinfo_name, BUFSIZE)); + } + PLUGIN_DEBUG(("Found kdcinfo [%s].\n", buf)); + + ret = getaddrinfo((char *) buf, "kerberos", NULL, &ctx->sssd_kdc_addrinfo); if (ret != 0) { PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", ret, gai_strerror(ret))); @@ -101,20 +130,43 @@ krb5_error_code sssd_krb5_locator_init(krb5_context context, PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", errno, strerror(errno))); } - goto failed; + goto done; } - *private_data = ctx; + ctx->sssd_realm = strdup(realm); + if (ctx->sssd_realm == NULL) { + PLUGIN_DEBUG(("strdup failed.\n")); + ret = ENOMEM; + goto done; + } - return 0; -failed: - freeaddrinfo(ctx->sssd_kdc_addrinfo); - free(ctx->sssd_realm); - free(ctx); - private_data = NULL; - return EINVAL; +done: + free(kdcinfo_name); + return ret; +} + +krb5_error_code sssd_krb5_locator_init(krb5_context context, + void **private_data) +{ + struct sssd_ctx *ctx; + const char *dummy; + + ctx = calloc(1,sizeof(struct sssd_ctx)); + if (ctx == NULL) return ENOMEM; + + dummy = getenv(SSSD_KRB5_LOCATOR_DEBUG); + if (dummy == NULL) { + ctx->debug = false; + } else { + ctx->debug = true; + PLUGIN_DEBUG(("sssd_krb5_locator_init called\n")); + } + + *private_data = ctx; + + return 0; } void sssd_krb5_locator_close(void *private_data) @@ -150,6 +202,18 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data, if (private_data == NULL) return KRB5_PLUGIN_NO_HANDLE; ctx = (struct sssd_ctx *) private_data; + if (ctx->sssd_realm == NULL || strcmp(ctx->sssd_realm, realm) != 0) { + freeaddrinfo(ctx->sssd_kdc_addrinfo); + ctx->sssd_kdc_addrinfo = NULL; + free(ctx->sssd_realm); + ctx->sssd_realm = NULL; + ret = get_kdcinfo(realm, ctx); + if (ret != EOK) { + PLUGIN_DEBUG(("get_kdcinfo failed.\n")); + return KRB5_PLUGIN_NO_HANDLE; + } + } + PLUGIN_DEBUG(("sssd_realm[%s] requested realm[%s] family[%d] socktype[%d] " "locate_service[%d]\n", ctx->sssd_realm, realm, family, socktype, svc)); diff --git a/server/providers/ipa/ipa_common.c b/server/providers/ipa/ipa_common.c index 2bd9c76..98ac077 100644 --- a/server/providers/ipa/ipa_common.c +++ b/server/providers/ipa/ipa_common.c @@ -478,19 +478,19 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server) /* free old one and replace with new one */ talloc_zfree(service->sdap->uri); service->sdap->uri = new_uri; - talloc_zfree(service->krb_server->address); - service->krb_server->address = address; + talloc_zfree(service->krb5_service->address); + service->krb5_service->address = address; - /* set also env variable */ - ret = setenv(SSSD_KRB5_KDC, address, 1); + ret = write_kdcinfo_file(service->krb5_service->realm, address); if (ret != EOK) { - DEBUG(2, ("setenv %s failed, authentication might fail.\n", - SSSD_KRB5_KDC)); + DEBUG(2, ("write_kdcinfo_file failed, authentication might fail.\n")); } + } int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *servers, struct ipa_service **_service) + const char *servers, const char *domain, + struct ipa_service **_service) { TALLOC_CTX *tmp_ctx; struct ipa_service *service; @@ -514,8 +514,8 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, ret = ENOMEM; goto done; } - service->krb_server = talloc_zero(service, struct krb_server); - if (!service->krb_server) { + service->krb5_service = talloc_zero(service, struct krb5_service); + if (!service->krb5_service) { ret = ENOMEM; goto done; } @@ -532,6 +532,18 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, goto done; } + service->krb5_service->name = talloc_strdup(service, "IPA"); + if (!service->krb5_service->name) { + ret = ENOMEM; + goto done; + } + + service->krb5_service->realm = talloc_strdup(service, domain); + if (!service->krb5_service->realm) { + ret = ENOMEM; + goto done; + } + /* split server parm into a list */ ret = sss_split_list(tmp_ctx, servers, ", ", &list, &count); if (ret != EOK) { diff --git a/server/providers/ipa/ipa_common.h b/server/providers/ipa/ipa_common.h index 8d0840c..8eaae71 100644 --- a/server/providers/ipa/ipa_common.h +++ b/server/providers/ipa/ipa_common.h @@ -29,7 +29,7 @@ struct ipa_service { struct sdap_service *sdap; - struct krb_server *krb_server; + struct krb5_service *krb5_service; }; enum ipa_basic_opt { @@ -72,6 +72,7 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts, struct dp_option **_opts); int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *servers, struct ipa_service **_service); + const char *servers, const char *domain, + struct ipa_service **_service); #endif /* _IPA_COMMON_H_ */ diff --git a/server/providers/ipa/ipa_init.c b/server/providers/ipa/ipa_init.c index ea27997..a3f381e 100644 --- a/server/providers/ipa/ipa_init.c +++ b/server/providers/ipa/ipa_init.c @@ -59,6 +59,7 @@ struct bet_ops ipa_access_ops = { int common_ipa_init(struct be_ctx *bectx) { const char *ipa_servers; + const char *ipa_domain; int ret; ret = ipa_get_options(bectx, bectx->cdb, @@ -74,8 +75,14 @@ int common_ipa_init(struct be_ctx *bectx) return EINVAL; } - ret = ipa_service_init(ipa_options, bectx, - ipa_servers, &ipa_options->service); + ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN); + if (!ipa_domain) { + DEBUG(0, ("Missing ipa_domain option!\n")); + return EINVAL; + } + + ret = ipa_service_init(ipa_options, bectx, ipa_servers, ipa_domain, + &ipa_options->service); if (ret != EOK) { DEBUG(0, ("Failed to init IPA failover service!\n")); return ret; @@ -171,7 +178,7 @@ int sssm_ipa_auth_init(struct be_ctx *bectx, if (!ctx) { return ENOMEM; } - ctx->server = ipa_options->service->krb_server; + ctx->service = ipa_options->service->krb5_service; ipa_options->auth_ctx = ctx; ret = ipa_get_auth_options(ipa_options, bectx->cdb, diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c index 8068bce..7ac440f 100644 --- a/server/providers/krb5/krb5_auth.c +++ b/server/providers/krb5/krb5_auth.c @@ -528,6 +528,7 @@ static errno_t krb5_setup(struct be_req *req, struct krb5child_req **krb5_req) kr->read_from_child_fd = -1; kr->write_to_child_fd = -1; kr->is_offline = false; + kr->active_ccache_present = true; talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); kr->pd = pd; @@ -929,6 +930,7 @@ static int handle_child_recv(struct tevent_req *req, } static void get_user_attr_done(void *pvt, int err, struct ldb_result *res); +static void krb5_resolve_done(struct tevent_req *req); static void krb5_save_ccname_done(struct tevent_req *req); static void krb5_child_done(struct tevent_req *req); static void krb5_pam_handler_cache_done(struct tevent_req *treq); @@ -988,7 +990,6 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) int dp_err = DP_ERR_FATAL; const char *ccache_file = NULL; const char *dummy; - bool active_ccache_present = false; ret = krb5_setup(be_req, &kr); if (ret != EOK) { @@ -1047,7 +1048,7 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) } if (ccache_file == NULL) { - active_ccache_present = false; + kr->active_ccache_present = false; DEBUG(4, ("No active ccache file for user [%s] found.\n", pd->user)); ccache_file = expand_ccname_template(kr, kr, @@ -1059,11 +1060,11 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) goto failed; } } else { - active_ccache_present = true; + kr->active_ccache_present = true; } DEBUG(9, ("Ccache_file is [%s] and %s.\n", ccache_file, - active_ccache_present ? "will be kept/renewed" : - "will be generated")); + kr->active_ccache_present ? "will be kept/renewed" : + "will be generated")); kr->ccname = ccache_file; break; @@ -1074,6 +1075,44 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) break; } + req = be_resolve_server_send(kr, be_req->be_ctx->ev, be_req->be_ctx, + krb5_ctx->service->name); + if (req == NULL) { + DEBUG(1, ("handle_child_send failed.\n")); + goto failed; + } + + tevent_req_set_callback(req, krb5_resolve_done, kr); + + return; + +failed: + talloc_free(kr); + + pd->pam_status = pam_status; + krb_reply(be_req, dp_err, pd->pam_status); +} + +static void krb5_resolve_done(struct tevent_req *req) +{ + struct krb5child_req *kr = tevent_req_callback_data(req, + struct krb5child_req); + int ret; + int pam_status = PAM_SYSTEM_ERR; + int dp_err = DP_ERR_FATAL; + struct pam_data *pd = kr->pd; + struct be_req *be_req = kr->req; + + ret = be_resolve_server_recv(req, &kr->srv); + talloc_zfree(req); + if (ret) { + /* all servers have been tried and none + * was found good, setting offline, + * but we still have to call the child to setup + * the ccache file. */ + be_mark_offline(be_req->be_ctx); + kr->is_offline = true; + } if (be_is_offline(be_req->be_ctx)) { DEBUG(9, ("Preparing for offline operation.\n")); @@ -1081,14 +1120,14 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) memset(pd->authtok, 0, pd->authtok_size); pd->authtok_size = 0; - if (active_ccache_present) { + if (kr->active_ccache_present) { req = krb5_save_ccname_send(kr, be_req->be_ctx->ev, be_req->be_ctx->sysdb, be_req->be_ctx->domain, pd->user, kr->ccname); if (req == NULL) { DEBUG(1, ("krb5_save_ccname_send failed.\n")); - goto failed; + goto done; } tevent_req_set_callback(req, krb5_save_ccname_done, kr); @@ -1099,15 +1138,14 @@ static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) req = handle_child_send(kr, be_req->be_ctx->ev, kr); if (req == NULL) { DEBUG(1, ("handle_child_send failed.\n")); - goto failed; + goto done; } tevent_req_set_callback(req, krb5_child_done, kr); return; -failed: +done: talloc_free(kr); - pd->pam_status = pam_status; krb_reply(be_req, dp_err, pd->pam_status); } @@ -1189,6 +1227,9 @@ static void krb5_child_done(struct tevent_req *req) } if (*msg_status == PAM_AUTHINFO_UNAVAIL) { + if (kr->srv != NULL) { + fo_set_server_status(kr->srv, SERVER_NOT_WORKING); + } be_mark_offline(be_req->be_ctx); kr->is_offline = true; } diff --git a/server/providers/krb5/krb5_auth.h b/server/providers/krb5/krb5_auth.h index 7851ebb..7facb00 100644 --- a/server/providers/krb5/krb5_auth.h +++ b/server/providers/krb5/krb5_auth.h @@ -50,6 +50,8 @@ struct krb5child_req { const char *ccname; const char *homedir; bool is_offline; + struct fo_server *srv; + bool active_ccache_present; }; struct fo_service; @@ -80,7 +82,7 @@ struct krb5_ctx { action_type action; struct dp_option *opts; - struct krb_server *server; + struct krb5_service *service; int child_debug_fd; }; diff --git a/server/providers/krb5/krb5_common.c b/server/providers/krb5/krb5_common.c index 6c23536..6817d65 100644 --- a/server/providers/krb5/krb5_common.c +++ b/server/providers/krb5/krb5_common.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "providers/dp_backend.h" #include "providers/krb5/krb5_common.h" @@ -47,17 +48,8 @@ errno_t check_and_export_options(struct dp_option *opts, const char *realm; const char *dummy; struct stat stat_buf; - - dummy = dp_opt_get_cstring(opts, KRB5_KDC); - if (dummy == NULL) { - DEBUG(2, ("No KDC expicitly configured, using defaults")); - } else { - ret = setenv(SSSD_KRB5_KDC, dummy, 1); - if (ret != EOK) { - DEBUG(2, ("setenv %s failed, authentication might fail.\n", - SSSD_KRB5_KDC)); - } - } + char **list; + int count; realm = dp_opt_get_cstring(opts, KRB5_REALM); if (realm == NULL) { @@ -68,12 +60,30 @@ errno_t check_and_export_options(struct dp_option *opts, } realm = dom->name; } + ret = setenv(SSSD_KRB5_REALM, realm, 1); if (ret != EOK) { DEBUG(2, ("setenv %s failed, authentication might fail.\n", SSSD_KRB5_REALM)); } + dummy = dp_opt_get_cstring(opts, KRB5_KDC); + if (dummy == NULL) { + DEBUG(1, ("No KDC expicitly configured, using defaults")); + } else { + ret = sss_split_list(opts, dummy, ", ", &list, &count); + if (ret != EOK) { + DEBUG(1, ("Failed to parse server list!\n")); + return ret; + } + ret = write_kdcinfo_file(realm, list[0]); + if (ret != EOK) { + DEBUG(1, ("write_kdcinfo_file failed, " + "using kerberos defaults from /etc/krb5.conf")); + } + talloc_free(list); + } + dummy = dp_opt_get_cstring(opts, KRB5_CCACHEDIR); ret = lstat(dummy, &stat_buf); if (ret != EOK) { @@ -154,3 +164,195 @@ done: return ret; } + +errno_t write_kdcinfo_file(const char *realm, const char *kdc) +{ + int ret; + int fd = -1; + char *tmp_name = NULL; + char *kdcinfo_name = NULL; + TALLOC_CTX *tmp_ctx = NULL; + int kdc_len; + + if (realm == NULL || *realm == '\0' || kdc == NULL || *kdc == '\0') { + DEBUG(1, ("Missing or empty realm or kdc.\n")); + return EINVAL; + } + + kdc_len = strlen(kdc); + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(1, ("talloc_new failed.\n")); + return ENOMEM; + } + + tmp_name = talloc_asprintf(tmp_ctx, PUBCONF_PATH"/.kdcinfo_dummy_XXXXXX"); + if (tmp_name == NULL) { + DEBUG(1, ("talloc_asprintf failed.\n")); + ret = ENOMEM; + goto done; + } + + kdcinfo_name = talloc_asprintf(tmp_ctx, KDCINFO_TMPL, realm); + if (kdcinfo_name == NULL) { + DEBUG(1, ("talloc_asprintf failed.\n")); + ret = ENOMEM; + goto done; + } + + fd = mkstemp(tmp_name); + if (fd == -1) { + DEBUG(1, ("mkstemp failed [%d][%s].\n", errno, strerror(errno))); + ret = errno; + goto done; + } + + ret = write(fd, kdc, kdc_len); + if (ret == -1) { + DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno))); + goto done; + } + if (ret != kdc_len) { + DEBUG(1, ("Partial write occured, this should never happen.\n")); + ret = EINTR; + goto done; + } + + ret = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (ret == -1) { + DEBUG(1, ("fchmod failed [%d][%s].\n", errno, strerror(errno))); + goto done; + } + + ret = close(fd); + if (ret == -1) { + DEBUG(1, ("close failed [%d][%s].\n", errno, strerror(errno))); + goto done; + } + + ret = rename(tmp_name, kdcinfo_name); + if (ret == -1) { + DEBUG(1, ("rename failed [%d][%s].\n", errno, strerror(errno))); + goto done; + } + +done: + talloc_free(tmp_ctx); + return ret; +} + +static void krb5_resolve_callback(void *private_data, struct fo_server *server) +{ + struct krb5_service *krb5_service; + struct hostent *srvaddr; + char *address; + int ret; + + krb5_service = talloc_get_type(private_data, struct krb5_service); + if (!krb5_service) { + DEBUG(1, ("FATAL: Bad private_data\n")); + return; + } + + srvaddr = fo_get_server_hostent(server); + if (!srvaddr) { + DEBUG(1, ("FATAL: No hostent available for server (%s)\n", + fo_get_server_name(server))); + return; + } + + address = talloc_asprintf(krb5_service, srvaddr->h_name); + if (!address) { + DEBUG(1, ("Failed to copy address ...\n")); + return; + } + + talloc_zfree(krb5_service->address); + krb5_service->address = address; + + ret = write_kdcinfo_file(krb5_service->realm, address); + if (ret != EOK) { + DEBUG(2, ("write_kdcinfo_file failed, authentication might fail.\n")); + } + + return; +} + + +int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, + const char *service_name, const char *servers, + const char *realm, struct krb5_service **_service) +{ + TALLOC_CTX *tmp_ctx; + struct krb5_service *service; + char **list = NULL; + int count = 0; + int ret; + int i; + + tmp_ctx = talloc_new(memctx); + if (!tmp_ctx) { + return ENOMEM; + } + + service = talloc_zero(tmp_ctx, struct krb5_service); + if (!service) { + ret = ENOMEM; + goto done; + } + + ret = be_fo_add_service(ctx, service_name); + if (ret != EOK) { + DEBUG(1, ("Failed to create failover service!\n")); + goto done; + } + + service->name = talloc_strdup(service, service_name); + if (!service->name) { + ret = ENOMEM; + goto done; + } + + service->realm = talloc_strdup(service, realm); + if (!service->realm) { + ret = ENOMEM; + goto done; + } + + ret = sss_split_list(tmp_ctx, servers, ", ", &list, &count); + if (ret != EOK) { + DEBUG(1, ("Failed to parse server list!\n")); + goto done; + } + + for (i = 0; i < count; i++) { + + talloc_steal(service, list[i]); + + ret = be_fo_add_server(ctx, service_name, list[i], 0, NULL); + if (ret && ret != EEXIST) { + DEBUG(0, ("Failed to add server\n")); + goto done; + } + + DEBUG(6, ("Added Server %s\n", list[i])); + } + + ret = be_fo_service_add_callback(memctx, ctx, service_name, + krb5_resolve_callback, service); + if (ret != EOK) { + DEBUG(1, ("Failed to add failover callback!\n")); + goto done; + } + + ret = EOK; + +done: + if (ret == EOK) { + *_service = talloc_steal(memctx, service); + } + talloc_zfree(tmp_ctx); + return ret; +} + diff --git a/server/providers/krb5/krb5_common.h b/server/providers/krb5/krb5_common.h index 42b0037..832ffcd 100644 --- a/server/providers/krb5/krb5_common.h +++ b/server/providers/krb5/krb5_common.h @@ -37,6 +37,8 @@ #define SSSD_KRB5_REALM "SSSD_KRB5_REALM" #define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE" +#define KDCINFO_TMPL PUBCONF_PATH"/kdcinfo.%s" + enum krb5_opts { KRB5_KDC = 0, KRB5_REALM, @@ -50,8 +52,10 @@ enum krb5_opts { KRB5_OPTS }; -struct krb_server { +struct krb5_service { + char *name; char *address; + char *realm; }; errno_t check_and_export_options(struct dp_option *opts, @@ -59,4 +63,10 @@ errno_t check_and_export_options(struct dp_option *opts, errno_t krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb, const char *conf_path, struct dp_option **_opts); + +errno_t write_kdcinfo_file(const char *realm, const char *kdc); + +int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, + const char *service_name, const char *servers, + const char *realm, struct krb5_service **_service); #endif /* __KRB5_COMMON_H__ */ diff --git a/server/providers/krb5/krb5_init.c b/server/providers/krb5/krb5_init.c index 26cf5e3..a070c8c 100644 --- a/server/providers/krb5/krb5_init.c +++ b/server/providers/krb5/krb5_init.c @@ -29,12 +29,14 @@ #include "providers/krb5/krb5_auth.h" #include "providers/krb5/krb5_common.h" -struct bet_ops krb5_auth_ops = { - .handler = krb5_pam_handler, - .finalize = NULL, +struct krb5_options { + struct dp_option *opts; + struct krb5_ctx *auth_ctx; }; -struct bet_ops krb5_chpass_ops = { +struct krb5_options *krb5_options = NULL; + +struct bet_ops krb5_auth_ops = { .handler = krb5_pam_handler, .finalize = NULL, }; @@ -48,6 +50,28 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, struct tevent_signal *sige; unsigned v; FILE *debug_filep; + const char *krb5_servers; + const char *krb5_realm; + + if (krb5_options == NULL) { + krb5_options = talloc_zero(bectx, struct krb5_options); + if (krb5_options == NULL) { + DEBUG(1, ("talloc_zero failed.\n")); + return ENOMEM; + } + ret = krb5_get_options(krb5_options, bectx->cdb, bectx->conf_path, + &krb5_options->opts); + if (ret != EOK) { + DEBUG(1, ("krb5_get_options failed.\n")); + return ret; + } + } + + if (krb5_options->auth_ctx != NULL) { + *ops = &krb5_auth_ops; + *pvt_auth_data = krb5_options->auth_ctx; + return EOK; + } ctx = talloc_zero(bectx, struct krb5_ctx); if (!ctx) { @@ -56,11 +80,25 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, } ctx->action = INIT_PW; + ctx->opts = krb5_options->opts; + + krb5_servers = dp_opt_get_string(ctx->opts, KRB5_KDC); + if (krb5_servers == NULL) { + DEBUG(0, ("Missing krb5_kdcip option!\n")); + return EINVAL; + } + + krb5_realm = dp_opt_get_string(ctx->opts, KRB5_REALM); + if (krb5_realm == NULL) { + DEBUG(0, ("Missing krb5_realm option!\n")); + return EINVAL; + } - ret = krb5_get_options(ctx, bectx->cdb, bectx->conf_path, &ctx->opts); + ret = krb5_service_init(ctx, bectx, "KRB5", krb5_servers, krb5_realm, + &ctx->service); if (ret != EOK) { - DEBUG(1, ("krb5_get_options failed.\n")); - goto fail; + DEBUG(0, ("Failed to init IPA failover service!\n")); + return ret; } ret = check_and_export_options(ctx->opts, bectx->domain); -- 1.6.2.5