[sssd] Update SSSD for the F19 test day
Jakub Hrozek
jhrozek at fedoraproject.org
Tue May 7 13:03:15 UTC 2013
commit 14fef6c6d9a152c6d6d45fbb4ca3e5a485eb9e07
Author: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue May 7 10:44:52 2013 +0200
Update SSSD for the F19 test day
- Explicitly Require libini_config >= 1.0.0.1 to work around a SONAME bug in ding-libs
- Fix SSH integration with fully-qualified domains
- Add the ability to dynamically discover the NetBIOS name
...D-read-flat-name-and-SID-of-the-AD-domain.patch | 702 ++++++++++++++++++++
...e-the-index-parameter-in-resolv_get_socka.patch | 65 ++
...TIL-Add-function-sss_names_init_from_args.patch | 205 ++++++
...Fix-parsing-of-names-from-client-requests.patch | 116 ++++
...arate-field-for-domain-name-in-client-req.patch | 315 +++++++++
...skip-domains-with-use_fully_qualified_nam.patch | 30 +
sssd.spec | 16 +-
7 files changed, 1448 insertions(+), 1 deletions(-)
---
diff --git a/0001-AD-read-flat-name-and-SID-of-the-AD-domain.patch b/0001-AD-read-flat-name-and-SID-of-the-AD-domain.patch
new file mode 100644
index 0000000..c866125
--- /dev/null
+++ b/0001-AD-read-flat-name-and-SID-of-the-AD-domain.patch
@@ -0,0 +1,702 @@
+From 4cdaf239d4504966bed8ecd5e3fa07def74c7302 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose at redhat.com>
+Date: Thu, 2 May 2013 20:28:30 +0200
+Subject: [PATCH 1/6] AD: read flat name and SID of the AD domain
+
+For various features either the flat/short/NetBIOS domain name or the
+domain SID is needed. Since the responders already try to do a subdomain
+lookup when and known domain name is encountered I added a subdomain
+lookup to the AD provider which currently only reads the SID from the
+base DN and the NetBIOS name from a reply of a LDAP ping. The results
+are written to the cache to have them available even if SSSD is started
+in offline mode. Looking up trusted domains can be added later.
+
+Since all the needed responder code is already available from the
+corresponding work for the IPA provider this patch fixes
+
+https://fedorahosted.org/sssd/ticket/1468
+---
+ Makefile.am | 2 +
+ src/config/etc/sssd.api.d/sssd-ad.conf | 2 +
+ src/man/sssd-ad.5.xml | 4 +
+ src/man/sssd.conf.5.xml | 4 +
+ src/providers/ad/ad_init.c | 31 ++
+ src/providers/ad/ad_subdomains.c | 522 +++++++++++++++++++++++++++++++++
+ src/providers/ad/ad_subdomains.h | 37 +++
+ 7 files changed, 602 insertions(+)
+ create mode 100644 src/providers/ad/ad_subdomains.c
+ create mode 100644 src/providers/ad/ad_subdomains.h
+
+diff --git a/Makefile.am b/Makefile.am
+index 3abea76c18f49df623ff9c38ebc5d604596d2516..b72384a77fe5bb3d2d40229026c463fefabc1387 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1621,6 +1621,8 @@ libsss_ad_la_SOURCES = \
+ src/providers/ad/ad_access.h \
+ src/providers/ad/ad_opts.h \
+ src/providers/ad/ad_srv.c \
++ src/providers/ad/ad_subdomains.c \
++ src/providers/ad/ad_subdomains.h \
+ src/util/find_uid.c \
+ src/util/user_info_msg.c \
+ src/util/sss_krb5.c \
+diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
+index b4b1d0ba11d600a8b9a300f15cc8058be470f422..3be25e8da05ee6b1bbdb947e919421358591cdde 100644
+--- a/src/config/etc/sssd.api.d/sssd-ad.conf
++++ b/src/config/etc/sssd.api.d/sssd-ad.conf
+@@ -126,3 +126,5 @@ krb5_use_enterprise_principal = bool, None, false
+ [provider/ad/chpass]
+ krb5_kpasswd = str, None, false
+ krb5_backup_kpasswd = str, None, false
++
++[provider/ad/subdomains]
+diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
+index c19607715dafd39f167c3066831ae7ad09ffe459..4dcd552d7f1fe3235af9c582c49c553441a014e9 100644
+--- a/src/man/sssd-ad.5.xml
++++ b/src/man/sssd-ad.5.xml
+@@ -95,6 +95,10 @@ ldap_id_mapping = False
+ specified as the lower-case version of the long
+ version of the Active Directory domain.
+ </para>
++ <para>
++ The short domain name (also known as the NetBIOS
++ or the flat name) is autodetected by the SSSD.
++ </para>
+ </listitem>
+ </varlistentry>
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index 04c699948b093c235762c0d9f8223911a6fd2ada..99337fbba9fb8d39a62eb84313c5b89761ee950d 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -1481,6 +1481,10 @@ override_homedir = /home/%u
+ Regular expression for this domain that describes
+ how to parse the string containing user name and
+ domain into these components.
++ The "domain" can match either the SSSD
++ configuration domain name, or, in the case
++ of IPA trust subdomains and Active Directory
++ domains, the flat (NetBIOS) name of the domain.
+ </para>
+ <para>
+ Default for the AD and IPA provider:
+diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
+index 2f5a5da1510b0241a4bee12fc93da174fdd0d116..f90df2a6913222b023704e9e1d1dce9561772e98 100644
+--- a/src/providers/ad/ad_init.c
++++ b/src/providers/ad/ad_init.c
+@@ -37,6 +37,7 @@
+ #include "providers/ad/ad_id.h"
+ #include "providers/ad/ad_srv.h"
+ #include "providers/dp_dyndns.h"
++#include "providers/ad/ad_subdomains.h"
+
+ struct ad_options *ad_options = NULL;
+
+@@ -361,3 +362,33 @@ ad_shutdown(struct be_req *req)
+ /* TODO: Clean up any internal data */
+ sdap_handler_done(req, DP_ERR_OK, EOK, NULL);
+ }
++
++int sssm_ad_subdomains_init(struct be_ctx *bectx,
++ struct bet_ops **ops,
++ void **pvt_data)
++{
++ int ret;
++ struct ad_id_ctx *id_ctx;
++ const char *ad_domain;
++
++ ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("sssm_ad_id_init failed.\n"));
++ return ret;
++ }
++
++ if (ad_options == NULL) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Global AD options not available.\n"));
++ return EINVAL;
++ }
++
++ ad_domain = dp_opt_get_string(ad_options->basic, AD_DOMAIN);
++
++ ret = ad_subdom_init(bectx, id_ctx, ad_domain, ops, pvt_data);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("ad_subdom_init failed.\n"));
++ return ret;
++ }
++
++ return EOK;
++}
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..1da343f8711b2b99a7afff6a4a398a1aa515a875
+--- /dev/null
++++ b/src/providers/ad/ad_subdomains.c
+@@ -0,0 +1,522 @@
++/*
++ SSSD
++
++ AD Subdomains Module
++
++ Authors:
++ Sumit Bose <sbose at redhat.com>
++
++ Copyright (C) 2013 Red Hat
++
++ 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 <http://www.gnu.org/licenses/>.
++*/
++
++#include "providers/ldap/sdap_async.h"
++#include "providers/ad/ad_subdomains.h"
++#include <ctype.h>
++#include <ndr.h>
++#include <ndr/ndr_nbt.h>
++
++#define AD_AT_OBJECT_SID "objectSID"
++#define AD_AT_DNS_DOMAIN "DnsDomain"
++#define AD_AT_NT_VERSION "NtVer"
++#define AD_AT_NETLOGON "netlogon"
++
++#define MASTER_DOMAIN_SID_FILTER "objectclass=domain"
++
++/* do not refresh more often than every 5 seconds for now */
++#define AD_SUBDOMAIN_REFRESH_LIMIT 5
++
++/* refresh automatically every 4 hours */
++#define AD_SUBDOMAIN_REFRESH_PERIOD (3600 * 4)
++
++struct ad_subdomains_ctx {
++ struct be_ctx *be_ctx;
++ struct sdap_id_ctx *sdap_id_ctx;
++ struct sss_idmap_ctx *idmap_ctx;
++ char *domain_name;
++
++ time_t last_refreshed;
++ struct tevent_timer *timer_event;
++};
++
++struct ad_subdomains_req_ctx {
++ struct be_req *be_req;
++ struct ad_subdomains_ctx *sd_ctx;
++ struct sdap_id_op *sdap_op;
++
++ char *current_filter;
++ size_t base_iter;
++
++ size_t reply_count;
++ struct sysdb_attrs **reply;
++
++ char *master_sid;
++ char *flat_name;
++};
++
++static void ad_subdomains_get_conn_done(struct tevent_req *req);
++static errno_t ad_subdomains_get_master_sid(struct ad_subdomains_req_ctx *ctx);
++static void ad_subdomains_get_master_sid_done(struct tevent_req *req);
++static void ad_subdomains_get_netlogon_done(struct tevent_req *req);
++
++static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
++ struct be_req *be_req)
++{
++ struct ad_subdomains_req_ctx *req_ctx = NULL;
++ struct tevent_req *req;
++ int dp_error = DP_ERR_FATAL;
++ int ret;
++
++ req_ctx = talloc(be_req, struct ad_subdomains_req_ctx);
++ if (req_ctx == NULL) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ req_ctx->be_req = be_req;
++ req_ctx->sd_ctx = ctx;
++ req_ctx->current_filter = NULL;
++ req_ctx->base_iter = 0;
++ req_ctx->reply_count = 0;
++ req_ctx->reply = NULL;
++
++ req_ctx->sdap_op = sdap_id_op_create(req_ctx,
++ ctx->sdap_id_ctx->conn_cache);
++ if (req_ctx->sdap_op == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++
++ req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
++ if (req == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_connect_send failed: %d(%s).\n",
++ ret, strerror(ret)));
++ goto done;
++ }
++
++ tevent_req_set_callback(req, ad_subdomains_get_conn_done, req_ctx);
++
++ return;
++
++done:
++ talloc_free(req_ctx);
++ if (ret == EOK) {
++ dp_error = DP_ERR_OK;
++ }
++ be_req_terminate(be_req, dp_error, ret, NULL);
++}
++
++static void ad_subdomains_get_conn_done(struct tevent_req *req)
++{
++ int ret;
++ int dp_error = DP_ERR_FATAL;
++ struct ad_subdomains_req_ctx *ctx;
++
++ ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
++
++ ret = sdap_id_op_connect_recv(req, &dp_error);
++ talloc_zfree(req);
++ if (ret) {
++ if (dp_error == DP_ERR_OFFLINE) {
++ DEBUG(SSSDBG_MINOR_FAILURE,
++ ("No AD server is available, cannot get the "
++ "subdomain list while offline\n"));
++ } else {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Failed to connect to AD server: [%d](%s)\n",
++ ret, strerror(ret)));
++ }
++
++ goto fail;
++ }
++
++ ret = ad_subdomains_get_master_sid(ctx);
++ if (ret == EAGAIN) {
++ return;
++ } else if (ret != EOK) {
++ goto fail;
++ }
++
++ DEBUG(SSSDBG_OP_FAILURE, ("No search base available.\n"));
++ ret = EINVAL;
++
++fail:
++ be_req_terminate(ctx->be_req, dp_error, ret, NULL);
++}
++
++static errno_t ad_subdomains_get_master_sid(struct ad_subdomains_req_ctx *ctx)
++{
++ struct tevent_req *req;
++ struct sdap_search_base *base;
++ const char *master_sid_attrs[] = {AD_AT_OBJECT_SID, NULL};
++
++
++ base = ctx->sd_ctx->sdap_id_ctx->opts->search_bases[ctx->base_iter];
++ if (base == NULL) {
++ return EOK;
++ }
++
++ req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
++ ctx->sd_ctx->sdap_id_ctx->opts,
++ sdap_id_op_handle(ctx->sdap_op),
++ base->basedn, LDAP_SCOPE_BASE,
++ MASTER_DOMAIN_SID_FILTER, master_sid_attrs,
++ NULL, 0,
++ dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
++ SDAP_SEARCH_TIMEOUT),
++ false);
++
++ if (req == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send failed.\n"));
++ return ENOMEM;
++ }
++
++ tevent_req_set_callback(req, ad_subdomains_get_master_sid_done, ctx);
++
++ return EAGAIN;
++}
++
++static void ad_subdomains_get_master_sid_done(struct tevent_req *req)
++{
++ int ret;
++ size_t reply_count;
++ struct sysdb_attrs **reply = NULL;
++ struct ad_subdomains_req_ctx *ctx;
++ struct ldb_message_element *el;
++ char *sid_str;
++ enum idmap_error_code err;
++ static const char *attrs[] = {AD_AT_NETLOGON, NULL};
++ char *filter;
++ char *ntver;
++
++ ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
++
++ ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
++ talloc_zfree(req);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send request failed.\n"));
++ goto done;
++ }
++
++ if (reply_count == 0) {
++ ctx->base_iter++;
++ ret = ad_subdomains_get_master_sid(ctx);
++ if (ret == EAGAIN) {
++ return;
++ } else if (ret != EOK) {
++ goto done;
++ }
++ } else if (reply_count == 1) {
++ ret = sysdb_attrs_get_el(reply[0], AD_AT_OBJECT_SID, &el);
++ if (ret != EOK || el->num_values != 1) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_attrs_get_el failed.\n"));
++ goto done;
++ }
++
++ err = sss_idmap_bin_sid_to_sid(ctx->sd_ctx->idmap_ctx,
++ el->values[0].data,
++ el->values[0].length,
++ &sid_str);
++ if (err != IDMAP_SUCCESS) {
++ DEBUG(SSSDBG_MINOR_FAILURE,
++ ("Could not convert SID: [%s].\n", idmap_error_string(err)));
++ ret = EFAULT;
++ goto done;
++ }
++
++ ctx->master_sid = talloc_steal(ctx, sid_str);
++ } else {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("More than one result for domain SID found.\n"));
++ ret = EINVAL;
++ goto done;
++ }
++
++ DEBUG(SSSDBG_TRACE_FUNC, ("Found SID [%s].\n", ctx->master_sid));
++
++ ntver = sss_ldap_encode_ndr_uint32(ctx, NETLOGON_NT_VERSION_5EX |
++ NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
++ if (ntver == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sss_ldap_encode_ndr_uint32 failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++
++ filter = talloc_asprintf(ctx, "(&(%s=%s)(%s=%s))",
++ AD_AT_DNS_DOMAIN, ctx->sd_ctx->domain_name,
++ AD_AT_NT_VERSION, ntver);
++ if (filter == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_asprintf failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++
++ req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
++ ctx->sd_ctx->sdap_id_ctx->opts,
++ sdap_id_op_handle(ctx->sdap_op),
++ "", LDAP_SCOPE_BASE, filter, attrs, NULL, 0,
++ dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic,
++ SDAP_SEARCH_TIMEOUT),
++ false);
++ if (req == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++
++ tevent_req_set_callback(req, ad_subdomains_get_netlogon_done, ctx);
++ return;
++
++done:
++ be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
++}
++
++static void ad_subdomains_get_netlogon_done(struct tevent_req *req)
++{
++ int ret;
++ size_t reply_count;
++ struct sysdb_attrs **reply = NULL;
++ struct ad_subdomains_req_ctx *ctx;
++ struct ldb_message_element *el;
++ DATA_BLOB blob;
++ enum ndr_err_code ndr_err;
++ struct ndr_pull *ndr_pull = NULL;
++ struct netlogon_samlogon_response response;
++
++ ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
++
++ ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
++ talloc_zfree(req);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send request failed.\n"));
++ goto done;
++ }
++
++ if (reply_count == 0) {
++ DEBUG(SSSDBG_TRACE_FUNC, ("No netlogon data available.\n"));
++ } else if (reply_count > 1) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("More than one netlogon info returned.\n"));
++ ret = EINVAL;
++ goto done;
++ }
++
++ ret = sysdb_attrs_get_el(reply[0], AD_AT_NETLOGON, &el);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_el() failed\n"));
++ goto done;
++ }
++
++ if (el->num_values == 0) {
++ DEBUG(SSSDBG_OP_FAILURE, ("netlogon has no value\n"));
++ ret = ENOENT;
++ goto done;
++ } else if (el->num_values > 1) {
++ DEBUG(SSSDBG_OP_FAILURE, ("More than one netlogon value?\n"));
++ ret = EIO;
++ goto done;
++ }
++
++ blob.data = el->values[0].data;
++ blob.length = el->values[0].length;
++
++ ndr_pull = ndr_pull_init_blob(&blob, ctx);
++ if (ndr_pull == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("ndr_pull_init_blob() failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++
++ ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
++ &response);
++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
++ DEBUG(SSSDBG_OP_FAILURE, ("ndr_pull_netlogon_samlogon_response() "
++ "failed [%d]\n", ndr_err));
++ ret = EBADMSG;
++ goto done;
++ }
++
++ if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) {
++ DEBUG(SSSDBG_OP_FAILURE, ("Wrong version returned [%x]\n",
++ response.ntver));
++ ret = EBADMSG;
++ goto done;
++ }
++
++ if (response.data.nt5_ex.domain_name != NULL &&
++ *response.data.nt5_ex.domain_name != '\0') {
++ ctx->flat_name = talloc_strdup(ctx, response.data.nt5_ex.domain_name);
++ if (ctx->flat_name == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
++ ret = ENOMEM;
++ goto done;
++ }
++ }
++
++ DEBUG(SSSDBG_TRACE_FUNC, ("Found flat name [%s].\n", ctx->flat_name));
++
++ ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
++ NULL, ctx->flat_name, ctx->master_sid);
++
++ ret = EOK;
++
++done:
++
++ if (ret == EOK) {
++ ctx->sd_ctx->last_refreshed = time(NULL);
++ }
++ be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
++}
++
++static void ad_subdom_online_cb(void *pvt);
++
++static void ad_subdom_timer_refresh(struct tevent_context *ev,
++ struct tevent_timer *te,
++ struct timeval current_time,
++ void *pvt)
++{
++ ad_subdom_online_cb(pvt);
++}
++
++static void ad_subdom_be_req_callback(struct be_req *be_req,
++ int dp_err, int dp_ret,
++ const char *errstr)
++{
++ talloc_free(be_req);
++}
++
++static void ad_subdom_online_cb(void *pvt)
++{
++ struct ad_subdomains_ctx *ctx;
++ struct be_req *be_req;
++ struct timeval tv;
++
++ ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
++ if (!ctx) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Bad private pointer\n"));
++ return;
++ }
++
++ be_req = be_req_create(ctx, NULL, ctx->be_ctx,
++ ad_subdom_be_req_callback, NULL);
++ if (be_req == NULL) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("be_req_create() failed.\n"));
++ return;
++ }
++
++ ad_subdomains_retrieve(ctx, be_req);
++
++ tv = tevent_timeval_current_ofs(AD_SUBDOMAIN_REFRESH_PERIOD, 0);
++ ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
++ ad_subdom_timer_refresh, ctx);
++ if (!ctx->timer_event) {
++ DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom timer event\n"));
++ }
++}
++
++static void ad_subdom_offline_cb(void *pvt)
++{
++ struct ad_subdomains_ctx *ctx;
++
++ ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
++
++ if (ctx) {
++ talloc_zfree(ctx->timer_event);
++ }
++}
++
++void ad_subdomains_handler(struct be_req *be_req)
++{
++ struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
++ struct ad_subdomains_ctx *ctx;
++ time_t now;
++
++ ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
++ struct ad_subdomains_ctx);
++ if (!ctx) {
++ be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
++ return;
++ }
++
++ now = time(NULL);
++
++ if (ctx->last_refreshed > now - AD_SUBDOMAIN_REFRESH_LIMIT) {
++ be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
++ return;
++ }
++
++ ad_subdomains_retrieve(ctx, be_req);
++}
++
++struct bet_ops ad_subdomains_ops = {
++ .handler = ad_subdomains_handler,
++ .finalize = NULL
++};
++
++static void *idmap_talloc(size_t size, void *pvt)
++{
++ return talloc_size(pvt, size);
++}
++
++static void idmap_free(void *ptr, void *pvt)
++{
++ talloc_free(ptr);
++}
++
++int ad_subdom_init(struct be_ctx *be_ctx,
++ struct ad_id_ctx *id_ctx,
++ const char *ad_domain,
++ struct bet_ops **ops,
++ void **pvt_data)
++{
++ struct ad_subdomains_ctx *ctx;
++ int ret;
++ enum idmap_error_code err;
++
++ ctx = talloc_zero(id_ctx, struct ad_subdomains_ctx);
++ if (ctx == NULL) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero failed.\n"));
++ return ENOMEM;
++ }
++
++ ctx->be_ctx = be_ctx;
++ ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
++ ctx->domain_name = talloc_strdup(ctx, ad_domain);
++ if (ctx->domain_name == NULL) {
++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n"));
++ return ENOMEM;
++ }
++ *ops = &ad_subdomains_ops;
++ *pvt_data = ctx;
++
++ ret = be_add_online_cb(ctx, be_ctx, ad_subdom_online_cb, ctx, NULL);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom online callback"));
++ }
++
++ ret = be_add_offline_cb(ctx, be_ctx, ad_subdom_offline_cb, ctx, NULL);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom offline callback"));
++ }
++
++ err = sss_idmap_init(idmap_talloc, ctx, idmap_free, &ctx->idmap_ctx);
++ if (err != IDMAP_SUCCESS) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to initialize idmap context.\n"));
++ return EFAULT;
++ }
++
++ return EOK;
++}
+diff --git a/src/providers/ad/ad_subdomains.h b/src/providers/ad/ad_subdomains.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..b1a418f132595c10abd8448f78a5df62402314a8
+--- /dev/null
++++ b/src/providers/ad/ad_subdomains.h
+@@ -0,0 +1,37 @@
++/*
++ SSSD
++
++ AD Subdomains Module
++
++ Authors:
++ Sumit Bose <sbose at redhat.com>
++
++ Copyright (C) 2013 Red Hat
++
++ 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 <http://www.gnu.org/licenses/>.
++*/
++
++#ifndef _IPA_SUBDOMAINS_H_
++#define _IPA_SUBDOMAINS_H_
++
++#include "providers/dp_backend.h"
++#include "providers/ad/ad_common.h"
++
++int ad_subdom_init(struct be_ctx *be_ctx,
++ struct ad_id_ctx *id_ctx,
++ const char *ad_domain,
++ struct bet_ops **ops,
++ void **pvt_data);
++
++#endif /* _IPA_SUBDOMAINS_H_ */
+--
+1.8.2.1
+
diff --git a/0002-Actually-use-the-index-parameter-in-resolv_get_socka.patch b/0002-Actually-use-the-index-parameter-in-resolv_get_socka.patch
new file mode 100644
index 0000000..c0d4494
--- /dev/null
+++ b/0002-Actually-use-the-index-parameter-in-resolv_get_socka.patch
@@ -0,0 +1,65 @@
+From 7c091610f5b35e8ba89da839322f6591f1e7619b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek at redhat.com>
+Date: Mon, 6 May 2013 15:10:22 +0200
+Subject: [PATCH 2/6] Actually use the index parameter in
+ resolv_get_sockaddr_address_index
+
+---
+ src/resolv/async_resolv.c | 11 +++++++----
+ src/resolv/async_resolv.h | 5 +++--
+ 2 files changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c
+index 1eb0acf83cb5bb48d92a58b8baf872f4ca4d8278..ad9d58297d0701e2a48ef86179c93c71320654fb 100644
+--- a/src/resolv/async_resolv.c
++++ b/src/resolv/async_resolv.c
+@@ -1453,8 +1453,9 @@ resolv_get_string_ptr_address(TALLOC_CTX *mem_ctx,
+ }
+
+ struct sockaddr_storage *
+-resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
+- int port, int index)
++resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx,
++ struct resolv_hostent *hostent,
++ int port, int addrindex)
+ {
+ struct sockaddr_storage *sockaddr;
+
+@@ -1470,14 +1471,16 @@ resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *ho
+ case AF_INET:
+ sockaddr->ss_family = AF_INET;
+ memcpy(&((struct sockaddr_in *) sockaddr)->sin_addr,
+- hostent->addr_list[0]->ipaddr, sizeof(struct in_addr));
++ hostent->addr_list[addrindex]->ipaddr,
++ sizeof(struct in_addr));
+ ((struct sockaddr_in *) sockaddr)->sin_port = (in_port_t) htons(port);
+
+ break;
+ case AF_INET6:
+ sockaddr->ss_family = AF_INET6;
+ memcpy(&((struct sockaddr_in6 *) sockaddr)->sin6_addr,
+- hostent->addr_list[0]->ipaddr, sizeof(struct in6_addr));
++ hostent->addr_list[addrindex]->ipaddr,
++ sizeof(struct in6_addr));
+ ((struct sockaddr_in6 *) sockaddr)->sin6_port = (in_port_t) htons(port);
+ break;
+ default:
+diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h
+index 9bf5e0c40e44c385858fa4d85adebe6e022ca006..a8207884c79d7a12af2bc1fc9da9c1304b2c252d 100644
+--- a/src/resolv/async_resolv.h
++++ b/src/resolv/async_resolv.h
+@@ -129,8 +129,9 @@ resolv_get_string_ptr_address(TALLOC_CTX *mem_ctx,
+ resolv_get_string_address_index(mem_ctx, hostent, 0)
+
+ struct sockaddr_storage *
+-resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx, struct resolv_hostent *hostent,
+- int port, int index);
++resolv_get_sockaddr_address_index(TALLOC_CTX *mem_ctx,
++ struct resolv_hostent *hostent,
++ int port, int addrindex);
+
+ #define resolv_get_sockaddr_address(mem_ctx, rhostent, port) \
+ resolv_get_sockaddr_address_index(mem_ctx, rhostent, port, 0)
+--
+1.8.2.1
+
diff --git a/0003-UTIL-Add-function-sss_names_init_from_args.patch b/0003-UTIL-Add-function-sss_names_init_from_args.patch
new file mode 100644
index 0000000..d250c91
--- /dev/null
+++ b/0003-UTIL-Add-function-sss_names_init_from_args.patch
@@ -0,0 +1,205 @@
+From f54b271376b23cb968eafb9ffd5100c6dadad2a7 Mon Sep 17 00:00:00 2001
+From: Jan Cholasta <jcholast at redhat.com>
+Date: Fri, 26 Apr 2013 09:40:53 +0200
+Subject: [PATCH 3/6] UTIL: Add function sss_names_init_from_args
+
+This function allows initializing sss_names_ctx using a regular expression and
+fully qualified format string specified in its arguments.
+---
+ src/util/usertools.c | 107 +++++++++++++++++++++++++++++++--------------------
+ src/util/util.h | 7 ++++
+ 2 files changed, 73 insertions(+), 41 deletions(-)
+
+diff --git a/src/util/usertools.c b/src/util/usertools.c
+index 7323d9f8260580f32b4ab55c8c2db5bd7eec20ed..91110f263657de9ba53ed305e7c4710eb006bec6 100644
+--- a/src/util/usertools.c
++++ b/src/util/usertools.c
+@@ -135,13 +135,11 @@ done:
+ #endif
+ }
+
+-int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
+- const char *domain, struct sss_names_ctx **out)
++int sss_names_init_from_args(TALLOC_CTX *mem_ctx, const char *re_pattern,
++ const char *fq_fmt, struct sss_names_ctx **out)
+ {
+ struct sss_names_ctx *ctx;
+- TALLOC_CTX *tmpctx = NULL;
+ const char *errstr;
+- char *conf_path;
+ int errval;
+ int errpos;
+ int ret;
+@@ -150,6 +148,49 @@ int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
+ if (!ctx) return ENOMEM;
+ talloc_set_destructor(ctx, sss_names_ctx_destructor);
+
++ ctx->re_pattern = talloc_strdup(ctx, re_pattern);
++ if (ctx->re_pattern == NULL) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ DEBUG(SSSDBG_CONF_SETTINGS, ("Using re [%s].\n", ctx->re_pattern));
++
++ ctx->fq_fmt = talloc_strdup(ctx, fq_fmt);
++ if (ctx->fq_fmt == NULL) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ ctx->re = pcre_compile2(ctx->re_pattern,
++ NAME_DOMAIN_PATTERN_OPTIONS,
++ &errval, &errstr, &errpos, NULL);
++ if (!ctx->re) {
++ DEBUG(1, ("Invalid Regular Expression pattern at position %d."
++ " (Error: %d [%s])\n", errpos, errval, errstr));
++ ret = EFAULT;
++ goto done;
++ }
++
++ *out = ctx;
++ ret = EOK;
++
++done:
++ if (ret != EOK) {
++ talloc_free(ctx);
++ }
++ return ret;
++}
++
++int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
++ const char *domain, struct sss_names_ctx **out)
++{
++ TALLOC_CTX *tmpctx = NULL;
++ char *conf_path;
++ char *re_pattern;
++ char *fq_fmt;
++ int ret;
++
+ tmpctx = talloc_new(NULL);
+ if (tmpctx == NULL) {
+ ret = ENOMEM;
+@@ -162,19 +203,19 @@ int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
+ goto done;
+ }
+
+- ret = confdb_get_string(cdb, ctx, conf_path,
+- CONFDB_NAME_REGEX, NULL, &ctx->re_pattern);
++ ret = confdb_get_string(cdb, tmpctx, conf_path,
++ CONFDB_NAME_REGEX, NULL, &re_pattern);
+ if (ret != EOK) goto done;
+
+ /* If not found in the domain, look in globals */
+- if (ctx->re_pattern == NULL) {
+- ret = confdb_get_string(cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
+- CONFDB_NAME_REGEX, NULL, &ctx->re_pattern);
++ if (re_pattern == NULL) {
++ ret = confdb_get_string(cdb, tmpctx, CONFDB_MONITOR_CONF_ENTRY,
++ CONFDB_NAME_REGEX, NULL, &re_pattern);
+ if (ret != EOK) goto done;
+ }
+
+- if (ctx->re_pattern == NULL) {
+- ret = get_id_provider_default_re(ctx, cdb, conf_path, &ctx->re_pattern);
++ if (re_pattern == NULL) {
++ ret = get_id_provider_default_re(tmpctx, cdb, conf_path, &re_pattern);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Failed to get provider default regular " \
+ "expression for domain [%s].\n", domain));
+@@ -182,10 +223,10 @@ int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
+ }
+ }
+
+- if (!ctx->re_pattern) {
+- ctx->re_pattern = talloc_strdup(ctx,
+- "(?P<name>[^@]+)@?(?P<domain>[^@]*$)");
+- if (!ctx->re_pattern) {
++ if (!re_pattern) {
++ re_pattern = talloc_strdup(tmpctx,
++ "(?P<name>[^@]+)@?(?P<domain>[^@]*$)");
++ if (!re_pattern) {
+ ret = ENOMEM;
+ goto done;
+ }
+@@ -195,49 +236,33 @@ int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb,
+ "not support non-unique named subpatterns.\n"));
+ DEBUG(2, ("Please make sure that your pattern [%s] only contains "
+ "subpatterns with a unique name and uses "
+- "the Python syntax (?P<name>).\n", ctx->re_pattern));
++ "the Python syntax (?P<name>).\n", re_pattern));
+ #endif
+ }
+
+- DEBUG(SSSDBG_CONF_SETTINGS, ("Using re [%s].\n", ctx->re_pattern));
+-
+- ret = confdb_get_string(cdb, ctx, conf_path,
+- CONFDB_FULL_NAME_FORMAT, NULL, &ctx->fq_fmt);
++ ret = confdb_get_string(cdb, tmpctx, conf_path,
++ CONFDB_FULL_NAME_FORMAT, NULL, &fq_fmt);
+ if (ret != EOK) goto done;
+
+ /* If not found in the domain, look in globals */
+- if (ctx->fq_fmt == NULL) {
+- ret = confdb_get_string(cdb, ctx, CONFDB_MONITOR_CONF_ENTRY,
+- CONFDB_FULL_NAME_FORMAT, NULL, &ctx->fq_fmt);
++ if (fq_fmt == NULL) {
++ ret = confdb_get_string(cdb, tmpctx, CONFDB_MONITOR_CONF_ENTRY,
++ CONFDB_FULL_NAME_FORMAT, NULL, &fq_fmt);
+ if (ret != EOK) goto done;
+ }
+
+- if (!ctx->fq_fmt) {
+- ctx->fq_fmt = talloc_strdup(ctx, "%1$s@%2$s");
+- if (!ctx->fq_fmt) {
++ if (!fq_fmt) {
++ fq_fmt = talloc_strdup(tmpctx, "%1$s@%2$s");
++ if (!fq_fmt) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+- ctx->re = pcre_compile2(ctx->re_pattern,
+- NAME_DOMAIN_PATTERN_OPTIONS,
+- &errval, &errstr, &errpos, NULL);
+- if (!ctx->re) {
+- DEBUG(1, ("Invalid Regular Expression pattern at position %d."
+- " (Error: %d [%s])\n", errpos, errval, errstr));
+- ret = EFAULT;
+- goto done;
+- }
+-
+- *out = ctx;
+- ret = EOK;
++ ret = sss_names_init_from_args(mem_ctx, re_pattern, fq_fmt, out);
+
+ done:
+ talloc_free(tmpctx);
+- if (ret != EOK) {
+- talloc_free(ctx);
+- }
+ return ret;
+ }
+
+diff --git a/src/util/util.h b/src/util/util.h
+index 33725f63591a4d165a084c1fd361f9651e80e50b..49dc850c36cedd83755034367357fab41bd32ec6 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -401,6 +401,13 @@ struct sss_names_ctx {
+ pcre *re;
+ };
+
++/* initialize sss_names_ctx directly from arguments */
++int sss_names_init_from_args(TALLOC_CTX *mem_ctx,
++ const char *re_pattern,
++ const char *fq_fmt,
++ struct sss_names_ctx **out);
++
++/* initialize sss_names_ctx from domain configuration */
+ int sss_names_init(TALLOC_CTX *mem_ctx,
+ struct confdb_ctx *cdb,
+ const char *domain,
+--
+1.8.2.1
+
diff --git a/0004-SSH-Fix-parsing-of-names-from-client-requests.patch b/0004-SSH-Fix-parsing-of-names-from-client-requests.patch
new file mode 100644
index 0000000..b063bbd
--- /dev/null
+++ b/0004-SSH-Fix-parsing-of-names-from-client-requests.patch
@@ -0,0 +1,116 @@
+From 728b10c81204929be5669c1e67bd086e09c47c00 Mon Sep 17 00:00:00 2001
+From: Jan Cholasta <jcholast at redhat.com>
+Date: Fri, 26 Apr 2013 09:53:47 +0200
+Subject: [PATCH 4/6] SSH: Fix parsing of names from client requests
+
+Try to parse names in the form user at domain first, as that's what sss_ssh_*
+send in requests when the --domain option is used. Do not parse host names
+using domain-specific regular expression.
+---
+ src/responder/ssh/sshsrv.c | 8 ++++++++
+ src/responder/ssh/sshsrv_cmd.c | 23 ++++++++++++++++++++---
+ src/responder/ssh/sshsrv_private.h | 2 ++
+ 3 files changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
+index 8a66f2239ac370218ec48d4cfc003d40dc1b7aec..410e631af43b8e8ef160334bab9a540ea913804c 100644
+--- a/src/responder/ssh/sshsrv.c
++++ b/src/responder/ssh/sshsrv.c
+@@ -118,6 +118,14 @@ int ssh_process_init(TALLOC_CTX *mem_ctx,
+ ssh_ctx->rctx = rctx;
+ ssh_ctx->rctx->pvt_ctx = ssh_ctx;
+
++ ret = sss_names_init_from_args(ssh_ctx,
++ "(?P<name>[^@]+)@?(?P<domain>[^@]*$)",
++ "%1$s@%2$s", &ssh_ctx->snctx);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_FATAL_FAILURE, ("fatal error initializing regex data\n"));
++ goto fail;
++ }
++
+ /* Enable automatic reconnection to the Data Provider */
+ ret = confdb_get_int(ssh_ctx->rctx->cdb,
+ CONFDB_SSH_CONF_ENTRY,
+diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
+index 671160ea77904bc5d9a74fee1e351fec8b7cb3fb..374abe6c6ef4ffe1abeeafa2fe94602f5bff3414 100644
+--- a/src/responder/ssh/sshsrv_cmd.c
++++ b/src/responder/ssh/sshsrv_cmd.c
+@@ -55,6 +55,7 @@ sss_ssh_cmd_get_user_pubkeys(struct cli_ctx *cctx)
+ return ENOMEM;
+ }
+ cmd_ctx->cctx = cctx;
++ cmd_ctx->is_user = true;
+
+ ret = ssh_cmd_parse_request(cmd_ctx);
+ if (ret != EOK) {
+@@ -101,6 +102,7 @@ sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx)
+ return ENOMEM;
+ }
+ cmd_ctx->cctx = cctx;
++ cmd_ctx->is_user = false;
+
+ ret = ssh_cmd_parse_request(cmd_ctx);
+ if (ret != EOK) {
+@@ -673,6 +675,8 @@ static errno_t
+ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
+ {
+ struct cli_ctx *cctx = cmd_ctx->cctx;
++ struct ssh_ctx *ssh_ctx = talloc_get_type(cctx->rctx->pvt_ctx,
++ struct ssh_ctx);
+ errno_t ret;
+ uint8_t *body;
+ size_t body_len;
+@@ -705,14 +709,27 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
+ }
+ c += name_len;
+
+- ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
+- cctx->rctx->default_domain,name,
+- &cmd_ctx->domname, &cmd_ctx->name);
++ ret = sss_parse_name(cmd_ctx, ssh_ctx->snctx, name,
++ &cmd_ctx->domname, &cmd_ctx->name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Invalid name received [%s]\n", name));
+ return ENOENT;
+ }
+
++ if (cmd_ctx->is_user && cmd_ctx->domname == NULL) {
++ name = cmd_ctx->name;
++
++ ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
++ cctx->rctx->default_domain, name,
++ &cmd_ctx->domname,
++ &cmd_ctx->name);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Invalid name received [%s]\n", name));
++ return ENOENT;
++ }
++ }
++
+ if (flags & 1) {
+ SAFEALIGN_COPY_UINT32_CHECK(&alias_len, body+c, body_len, &c);
+ if (alias_len == 0 || alias_len > body_len - c) {
+diff --git a/src/responder/ssh/sshsrv_private.h b/src/responder/ssh/sshsrv_private.h
+index 296bd94a2947796198a0559c06d904b389283ade..ebb30ce7cbc982bb29b73592d5873e7d3652228a 100644
+--- a/src/responder/ssh/sshsrv_private.h
++++ b/src/responder/ssh/sshsrv_private.h
+@@ -28,6 +28,7 @@
+
+ struct ssh_ctx {
+ struct resp_ctx *rctx;
++ struct sss_names_ctx *snctx;
+
+ bool hash_known_hosts;
+ int known_hosts_timeout;
+@@ -38,6 +39,7 @@ struct ssh_cmd_ctx {
+ char *name;
+ char *alias;
+ char *domname;
++ bool is_user;
+
+ struct sss_domain_info *domain;
+ bool check_next;
+--
+1.8.2.1
+
diff --git a/0005-SSH-Use-separate-field-for-domain-name-in-client-req.patch b/0005-SSH-Use-separate-field-for-domain-name-in-client-req.patch
new file mode 100644
index 0000000..2faed0f
--- /dev/null
+++ b/0005-SSH-Use-separate-field-for-domain-name-in-client-req.patch
@@ -0,0 +1,315 @@
+From 28e55560008f21a532b103b3f612c6fca2a54d76 Mon Sep 17 00:00:00 2001
+From: Jan Cholasta <jcholast at redhat.com>
+Date: Fri, 26 Apr 2013 10:45:42 +0200
+Subject: [PATCH 5/6] SSH: Use separate field for domain name in client
+ requests
+
+Instead of appending @domain to names when the --domain option of sss_ssh_* is
+used, put domain name in a separate field in client requests.
+---
+ src/responder/ssh/sshsrv_cmd.c | 91 +++++++++++++++++++---------
+ src/sss_client/ssh/sss_ssh_authorizedkeys.c | 15 +----
+ src/sss_client/ssh/sss_ssh_client.c | 38 ++++++++----
+ src/sss_client/ssh/sss_ssh_client.h | 1 +
+ src/sss_client/ssh/sss_ssh_knownhostsproxy.c | 12 +---
+ src/util/sss_ssh.h | 4 ++
+ 6 files changed, 97 insertions(+), 64 deletions(-)
+
+diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
+index 374abe6c6ef4ffe1abeeafa2fe94602f5bff3414..d2f889fa6ac1e414dfa9bbd943b8ef6af125ae74 100644
+--- a/src/responder/ssh/sshsrv_cmd.c
++++ b/src/responder/ssh/sshsrv_cmd.c
+@@ -685,12 +685,14 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
+ uint32_t name_len;
+ char *name;
+ uint32_t alias_len;
+- char *alias;
++ char *alias = NULL;
++ uint32_t domain_len;
++ char *domain = cctx->rctx->default_domain;
+
+ sss_packet_get_body(cctx->creq->in, &body, &body_len);
+
+ SAFEALIGN_COPY_UINT32_CHECK(&flags, body+c, body_len, &c);
+- if (flags > 1) {
++ if (flags & ~(uint32_t)SSS_SSH_REQ_MASK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid flags received [0x%x]\n", flags));
+ return EINVAL;
+ }
+@@ -709,28 +711,7 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
+ }
+ c += name_len;
+
+- ret = sss_parse_name(cmd_ctx, ssh_ctx->snctx, name,
+- &cmd_ctx->domname, &cmd_ctx->name);
+- if (ret != EOK) {
+- DEBUG(SSSDBG_OP_FAILURE, ("Invalid name received [%s]\n", name));
+- return ENOENT;
+- }
+-
+- if (cmd_ctx->is_user && cmd_ctx->domname == NULL) {
+- name = cmd_ctx->name;
+-
+- ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
+- cctx->rctx->default_domain, name,
+- &cmd_ctx->domname,
+- &cmd_ctx->name);
+- if (ret != EOK) {
+- DEBUG(SSSDBG_OP_FAILURE,
+- ("Invalid name received [%s]\n", name));
+- return ENOENT;
+- }
+- }
+-
+- if (flags & 1) {
++ if (flags & SSS_SSH_REQ_ALIAS) {
+ SAFEALIGN_COPY_UINT32_CHECK(&alias_len, body+c, body_len, &c);
+ if (alias_len == 0 || alias_len > body_len - c) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid alias length\n"));
+@@ -744,11 +725,67 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
+ return EINVAL;
+ }
+ c += alias_len;
++ }
+
+- if (strcmp(cmd_ctx->name, alias) != 0) {
+- cmd_ctx->alias = talloc_strdup(cmd_ctx, alias);
+- if (!cmd_ctx->alias) return ENOMEM;
++ if (flags & SSS_SSH_REQ_DOMAIN) {
++ SAFEALIGN_COPY_UINT32_CHECK(&domain_len, body+c, body_len, &c);
++ if (domain_len > 0) {
++ if (domain_len > body_len - c) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid domain length\n"));
++ return EINVAL;
++ }
++
++ domain = (char *)(body+c);
++ if (!sss_utf8_check((const uint8_t *)domain, domain_len-1) ||
++ domain[domain_len-1] != 0) {
++ DEBUG(SSSDBG_CRIT_FAILURE,
++ ("Domain is not valid UTF-8 string\n"));
++ return EINVAL;
++ }
++ c += domain_len;
++ }
++
++ DEBUG(SSSDBG_TRACE_FUNC,
++ ("Requested domain [%s]\n", domain ? domain : "<ALL>"));
++ } else {
++ DEBUG(SSSDBG_TRACE_FUNC, ("Splitting domain from name [%s]\n", name));
++
++ ret = sss_parse_name(cmd_ctx, ssh_ctx->snctx, name,
++ &cmd_ctx->domname, &cmd_ctx->name);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("Invalid name received [%s]\n", name));
++ return ENOENT;
+ }
++
++ name = cmd_ctx->name;
++ }
++
++ if (cmd_ctx->is_user && cmd_ctx->domname == NULL) {
++ DEBUG(SSSDBG_TRACE_FUNC,
++ ("Parsing name [%s][%s]\n", name, domain ? domain : "<ALL>"));
++
++ ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
++ domain, name,
++ &cmd_ctx->domname,
++ &cmd_ctx->name);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Invalid name received [%s]\n", name));
++ return ENOENT;
++ }
++ } else if (cmd_ctx->name == NULL && cmd_ctx->domname == NULL) {
++ cmd_ctx->name = talloc_strdup(cmd_ctx, name);
++ if (!cmd_ctx->name) return ENOMEM;
++
++ if (domain != NULL) {
++ cmd_ctx->domname = talloc_strdup(cmd_ctx, domain);
++ if (!cmd_ctx->domname) return ENOMEM;
++ }
++ }
++
++ if (alias != NULL && strcmp(cmd_ctx->name, alias) != 0) {
++ cmd_ctx->alias = talloc_strdup(cmd_ctx, alias);
++ if (!cmd_ctx->alias) return ENOMEM;
+ }
+
+ return EOK;
+diff --git a/src/sss_client/ssh/sss_ssh_authorizedkeys.c b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
+index 11deff9a6bb2592ce102ff314bcb2b92f90fa1da..bc991a837635186449b1fd5f1c6bdc944176c43d 100644
+--- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c
++++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
+@@ -43,7 +43,6 @@ int main(int argc, const char **argv)
+ POPT_TABLEEND
+ };
+ poptContext pc = NULL;
+- const char *user;
+ struct sss_ssh_ent *ent;
+ size_t i;
+ char *repr;
+@@ -84,21 +83,9 @@ int main(int argc, const char **argv)
+ BAD_POPT_PARAMS(pc, _("User not specified\n"), ret, fini);
+ }
+
+- /* append domain to username if domain is specified */
+- if (pc_domain) {
+- user = talloc_asprintf(mem_ctx, "%s@%s", pc_user, pc_domain);
+- if (!user) {
+- ERROR("Not enough memory\n");
+- ret = EXIT_FAILURE;
+- goto fini;
+- }
+- } else {
+- user = pc_user;
+- }
+-
+ /* look up public keys */
+ ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_USER_PUBKEYS,
+- user, NULL, &ent);
++ pc_user, pc_domain, NULL, &ent);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("sss_ssh_get_ent() failed (%d): %s\n", ret, strerror(ret)));
+diff --git a/src/sss_client/ssh/sss_ssh_client.c b/src/sss_client/ssh/sss_ssh_client.c
+index 645f2928985637f26213ab7a0d48a626b088ad58..5312dba2be32aa0cc8813dedfc4189edeff7085c 100644
+--- a/src/sss_client/ssh/sss_ssh_client.c
++++ b/src/sss_client/ssh/sss_ssh_client.c
+@@ -70,29 +70,34 @@ int set_locale(void)
+
+ /* SSH public key request:
+ *
+- * 0..3: flags (unsigned int, must be 0 or 1)
+- * 4..7: name length (unsigned int)
+- * 8..(X-1): name (null-terminated UTF-8 string)
+- * if (flags & 1) {
+- * X..(X+3): alias length (unsigned int)
+- * (X+4)..Y: alias (null-terminated UTF-8 string)
+- * }
++ * header:
++ * 0..3: flags (unsigned int, must be combination of SSS_SSH_REQ_* flags)
++ * 4..7: name length (unsigned int)
++ * 8..X: name (null-terminated UTF-8 string)
++ * alias (only included if flags & SSS_SSH_REQ_ALIAS):
++ * 0..3: alias length (unsigned int)
++ * 4..X: alias (null-terminated UTF-8 string)
++ * domain (ony included if flags & SSS_SSH_REQ_DOMAIN):
++ * 0..3: domain length (unsigned int, 0 means default domain)
++ * 4..X: domain (null-terminated UTF-8 string)
+ *
+ * SSH public key reply:
+ *
+- * 0..3: number of results (unsigned int)
+- * 4..7: reserved (unsigned int, must be 0)
+- * 8..$: array of results:
++ * header:
++ * 0..3: number of results (unsigned int)
++ * 4..7: reserved (unsigned int, must be 0)
++ * results (repeated for each result):
+ * 0..3: flags (unsigned int, must be 0)
+ * 4..7: name length (unsigned int)
+ * 8..(X-1): name (null-terminated UTF-8 string)
+ * X..(X+3): key length (unsigned int)
+- * (X+4)..Y: key (public key blob as defined in RFC4253, section 6.6)
++ * (X+4)..Y: key (public key data)
+ */
+ errno_t
+ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
+ enum sss_cli_command command,
+ const char *name,
++ const char *domain,
+ const char *alias,
+ struct sss_ssh_ent **result)
+ {
+@@ -102,6 +107,7 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
+ uint32_t flags;
+ uint32_t name_len;
+ uint32_t alias_len;
++ uint32_t domain_len;
+ size_t req_len;
+ uint8_t *req = NULL;
+ size_t c = 0;
+@@ -122,11 +128,15 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
+ req_len = 2*sizeof(uint32_t) + name_len;
+
+ if (alias) {
+- flags |= 1;
++ flags |= SSS_SSH_REQ_ALIAS;
+ alias_len = strlen(alias)+1;
+ req_len += sizeof(uint32_t) + alias_len;
+ }
+
++ flags |= SSS_SSH_REQ_DOMAIN;
++ domain_len = domain ? (strlen(domain)+1) : 0;
++ req_len += sizeof(uint32_t) + domain_len;
++
+ req = talloc_array(tmp_ctx, uint8_t, req_len);
+ if (!req) {
+ ret = ENOMEM;
+@@ -140,6 +150,10 @@ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
+ SAFEALIGN_SET_UINT32(req+c, alias_len, &c);
+ safealign_memcpy(req+c, alias, alias_len, &c);
+ }
++ SAFEALIGN_SET_UINT32(req+c, domain_len, &c);
++ if (domain_len > 0) {
++ safealign_memcpy(req+c, domain, domain_len, &c);
++ }
+
+ /* send request */
+ rd.data = req;
+diff --git a/src/sss_client/ssh/sss_ssh_client.h b/src/sss_client/ssh/sss_ssh_client.h
+index 7ffc3983e11c4cfb5fcef9ff417592f63fef3b74..5ad0643f9b821d1ceec85c477ee2037c73e73d7f 100644
+--- a/src/sss_client/ssh/sss_ssh_client.h
++++ b/src/sss_client/ssh/sss_ssh_client.h
+@@ -34,6 +34,7 @@ errno_t
+ sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
+ enum sss_cli_command command,
+ const char *name,
++ const char *domain,
+ const char *alias,
+ struct sss_ssh_ent **result);
+
+diff --git a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
+index 600895d1fec81be59f0a6e0092b8a6c9f17890ec..e2202b1839214a165d5a94e3c70ce6af47cb9187 100644
+--- a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
++++ b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c
+@@ -282,19 +282,9 @@ int main(int argc, const char **argv)
+ }
+
+ if (host) {
+- /* append domain to hostname if domain is specified */
+- if (pc_domain) {
+- host = talloc_asprintf(mem_ctx, "%s@%s", host, pc_domain);
+- if (!host) {
+- DEBUG(SSSDBG_CRIT_FAILURE, ("Not enough memory\n"));
+- ret = EXIT_FAILURE;
+- goto fini;
+- }
+- }
+-
+ /* look up public keys */
+ ret = sss_ssh_get_ent(mem_ctx, SSS_SSH_GET_HOST_PUBKEYS,
+- host, pc_host, &ent);
++ host, pc_domain, pc_host, &ent);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("sss_ssh_get_ent() failed (%d): %s\n", ret, strerror(ret)));
+diff --git a/src/util/sss_ssh.h b/src/util/sss_ssh.h
+index fec7c732bdb319a906e01ec185d7ff0e7f2de0fe..1ba50a6552904096f8950b1f53563d7903eaf786 100644
+--- a/src/util/sss_ssh.h
++++ b/src/util/sss_ssh.h
+@@ -21,6 +21,10 @@
+ #ifndef _SSS_SSH_H_
+ #define _SSS_SSH_H_
+
++#define SSS_SSH_REQ_ALIAS 0x01
++#define SSS_SSH_REQ_DOMAIN 0x02
++#define SSS_SSH_REQ_MASK 0x03
++
+ struct sss_ssh_pubkey {
+ uint8_t *data;
+ size_t data_len;
+--
+1.8.2.1
+
diff --git a/0006-SSH-Do-not-skip-domains-with-use_fully_qualified_nam.patch b/0006-SSH-Do-not-skip-domains-with-use_fully_qualified_nam.patch
new file mode 100644
index 0000000..c9a81e3
--- /dev/null
+++ b/0006-SSH-Do-not-skip-domains-with-use_fully_qualified_nam.patch
@@ -0,0 +1,30 @@
+From d5fcc4c497eb17404812be7600fb1181a75cbfd3 Mon Sep 17 00:00:00 2001
+From: Jan Cholasta <jcholast at redhat.com>
+Date: Fri, 26 Apr 2013 10:07:22 +0200
+Subject: [PATCH 6/6] SSH: Do not skip domains with use_fully_qualified_names
+ in host key requests
+
+---
+ src/responder/ssh/sshsrv_cmd.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c
+index d2f889fa6ac1e414dfa9bbd943b8ef6af125ae74..bb765c62890aa326cfad87f511622167df61f0a1 100644
+--- a/src/responder/ssh/sshsrv_cmd.c
++++ b/src/responder/ssh/sshsrv_cmd.c
+@@ -300,12 +300,6 @@ ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx)
+ struct tevent_req *req;
+ struct dp_callback_ctx *cb_ctx;
+
+- /* if it is a domainless search, skip domains that require fully
+- * qualified names instead */
+- while (cmd_ctx->domain && cmd_ctx->check_next && cmd_ctx->domain->fqnames) {
+- cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
+- }
+-
+ if (!cmd_ctx->domain) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("No matching domain found for [%s], fail!\n", cmd_ctx->name));
+--
+1.8.2.1
+
diff --git a/sssd.spec b/sssd.spec
index 0b6057a..3639f3d 100644
--- a/sssd.spec
+++ b/sssd.spec
@@ -16,7 +16,7 @@
Name: sssd
Version: 1.10.0
-Release: 3%{?dist}.beta1
+Release: 4%{?dist}.beta1
Group: Applications/System
Summary: System Security Services Daemon
License: GPLv3+
@@ -25,6 +25,13 @@ Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}beta1.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
### Patches ###
+Patch0001: 0001-AD-read-flat-name-and-SID-of-the-AD-domain.patch
+Patch0002: 0002-Actually-use-the-index-parameter-in-resolv_get_socka.patch
+Patch0003: 0003-UTIL-Add-function-sss_names_init_from_args.patch
+Patch0004: 0004-SSH-Fix-parsing-of-names-from-client-requests.patch
+Patch0005: 0005-SSH-Use-separate-field-for-domain-name-in-client-req.patch
+Patch0006: 0006-SSH-Do-not-skip-domains-with-use_fully_qualified_nam.patch
+
Patch0501: 0501-FEDORA-Switch-the-default-ccache-location.patch
### Dependencies ###
@@ -38,6 +45,7 @@ Requires: libipa_hbac%{?_isa} = %{version}-%{release}
Requires: libsss_idmap%{?_isa} = %{version}-%{release}
Requires: python-sssdconfig = %{version}-%{release}
Requires: krb5-libs%{?_isa} >= 1.10
+Requires: libini_config >= 1.0.0.1
Requires(post): systemd-units initscripts chkconfig
Requires(preun): systemd-units initscripts chkconfig
Requires(postun): systemd-units initscripts chkconfig
@@ -595,6 +603,12 @@ fi
%postun -n libsss_sudo -p /sbin/ldconfig
%changelog
+* Tue May 7 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.10.0-4.beta1
+- Explicitly Require libini_config >= 1.0.0.1 to work around a SONAME bug
+ in ding-libs
+- Fix SSH integration with fully-qualified domains
+- Add the ability to dynamically discover the NetBIOS name
+
* Fri May 3 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.10.0-3.beta1
- New upstream release 1.10 beta1
- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.10.0beta1
More information about the scm-commits
mailing list