[PATCHES] idmap_rfc2307 with test
Christof Schmitt
christof.schmitt at us.ibm.com
Thu Feb 21 14:41:26 MST 2013
Here is an updated version of the idmap_rfc2307 module. The patches
apply to current master. The first five patches eliminate some code
duplication and allow the reuse of some ad and ldap code. The last
patch implements a testcase for the new idmap module.
--
Christof Schmitt || IBM || SONAS System Development || Tucson, AZ
christof.schmitt at us.ibm.com || +1-520-799-2469 (T/L: 321-2469)
-------------- next part --------------
>From 5e9e5f393450c366914ea6b6ace64bef7c76833c Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:30:48 -0700
Subject: [PATCH 01/11] s3-winbindd: Move common code for LDAP id mapping to idmap_utils
idmap_ad and idmap_ldap use the same helper functions and the same
maximum query size. Move the code to idmap_utils so that it can be
shared by every module issuing LDAP queries.
---
source3/winbindd/idmap_ad.c | 43 +++---------------------------------
source3/winbindd/idmap_ldap.c | 46 +--------------------------------------
source3/winbindd/idmap_proto.h | 6 +++++
source3/winbindd/idmap_util.c | 41 +++++++++++++++++++++++++++++++++++
4 files changed, 53 insertions(+), 83 deletions(-)
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index bfe7d4b..d6f31ba 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -41,7 +41,6 @@
#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
-#define IDMAP_AD_MAX_IDS 30
#define CHECK_ALLOC_DONE(mem) do { \
if (!mem) { \
DEBUG(0, ("Out of memory!\n")); \
@@ -250,40 +249,6 @@ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
}
/************************************************************************
- Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
- ***********************************************************************/
-
-static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
-{
- int i;
-
- for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
- if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
- return maps[i];
- }
- }
-
- return NULL;
-}
-
-/************************************************************************
- Search up to IDMAP_AD_MAX_IDS entries in maps for a match
- ***********************************************************************/
-
-static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
-{
- int i;
-
- for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
- if (dom_sid_equal(maps[i]->sid, sid)) {
- return maps[i];
- }
- }
-
- return NULL;
-}
-
-/************************************************************************
***********************************************************************/
static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
@@ -337,7 +302,7 @@ static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map
again:
bidx = idx;
- for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+ for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
switch (ids[idx]->xid.type) {
case ID_TYPE_UID:
if ( ! u_filter) {
@@ -462,7 +427,7 @@ again:
continue;
}
- map = find_map_by_id(&ids[bidx], type, id);
+ map = idmap_find_map_by_id(&ids[bidx], type, id);
if (!map) {
DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
continue;
@@ -567,7 +532,7 @@ again:
CHECK_ALLOC_DONE(filter);
bidx = idx;
- for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+ for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
ids[idx]->status = ID_UNKNOWN;
@@ -617,7 +582,7 @@ again:
continue;
}
- map = find_map_by_sid(&ids[bidx], &sid);
+ map = idmap_find_map_by_sid(&ids[bidx], &sid);
if (!map) {
DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
continue;
diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c
index 0c58bf4..03872e7 100644
--- a/source3/winbindd/idmap_ldap.c
+++ b/source3/winbindd/idmap_ldap.c
@@ -663,34 +663,10 @@ static NTSTATUS idmap_ldap_new_mapping(struct idmap_domain *dom, struct id_map *
return ret;
}
-
-/* max number of ids requested per batch query */
-#define IDMAP_LDAP_MAX_IDS 30
-
/**********************************
lookup a set of unix ids.
**********************************/
-/* this function searches up to IDMAP_LDAP_MAX_IDS entries
- * in maps for a match */
-static struct id_map *find_map_by_id(struct id_map **maps,
- enum id_type type,
- uint32_t id)
-{
- int i;
-
- for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
- if (maps[i] == NULL) { /* end of the run */
- return NULL;
- }
- if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
- return maps[i];
- }
- }
-
- return NULL;
-}
-
static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
struct id_map **ids)
{
@@ -846,7 +822,7 @@ again:
}
TALLOC_FREE(tmp);
- map = find_map_by_id(&ids[bidx], type, id);
+ map = idmap_find_map_by_id(&ids[bidx], type, id);
if (!map) {
DEBUG(2, ("WARNING: couldn't match sid (%s) "
"with requested ids\n", sidstr));
@@ -903,24 +879,6 @@ done:
lookup a set of sids.
**********************************/
-/* this function searches up to IDMAP_LDAP_MAX_IDS entries
- * in maps for a match */
-static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
-{
- int i;
-
- for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
- if (maps[i] == NULL) { /* end of the run */
- return NULL;
- }
- if (dom_sid_equal(maps[i]->sid, sid)) {
- return maps[i];
- }
- }
-
- return NULL;
-}
-
static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
struct id_map **ids)
{
@@ -1053,7 +1011,7 @@ again:
continue;
}
- map = find_map_by_sid(&ids[bidx], &sid);
+ map = idmap_find_map_by_sid(&ids[bidx], &sid);
if (!map) {
DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
"in ids", sidstr));
diff --git a/source3/winbindd/idmap_proto.h b/source3/winbindd/idmap_proto.h
index 892b258..a709807 100644
--- a/source3/winbindd/idmap_proto.h
+++ b/source3/winbindd/idmap_proto.h
@@ -54,5 +54,11 @@ NTSTATUS idmap_tdb_init(void);
NTSTATUS idmap_uid_to_sid(const char *domname, struct dom_sid *sid, uid_t uid);
NTSTATUS idmap_gid_to_sid(const char *domname, struct dom_sid *sid, gid_t gid);
bool idmap_unix_id_is_in_range(uint32_t id, struct idmap_domain *dom);
+struct id_map *idmap_find_map_by_id(struct id_map **maps, enum id_type type,
+ uint32_t id);
+struct id_map *idmap_find_map_by_sid(struct id_map **maps, struct dom_sid *sid);
+
+/* max number of ids requested per LDAP batch query */
+#define IDMAP_LDAP_MAX_IDS 30
#endif /* _WINBINDD_IDMAP_PROTO_H_ */
diff --git a/source3/winbindd/idmap_util.c b/source3/winbindd/idmap_util.c
index 9d9ada7..cbad91d 100644
--- a/source3/winbindd/idmap_util.c
+++ b/source3/winbindd/idmap_util.c
@@ -172,3 +172,44 @@ bool idmap_unix_id_is_in_range(uint32_t id, struct idmap_domain *dom)
return true;
}
+
+/**
+ * Helper for unixids_to_sids: find entry by id in mapping array,
+ * search up to IDMAP_AD_MAX_IDS entries
+ */
+struct id_map *idmap_find_map_by_id(struct id_map **maps, enum id_type type,
+ uint32_t id)
+{
+ int i;
+
+ for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
+ if (maps[i] == NULL) { /* end of the run */
+ return NULL;
+ }
+ if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
+ return maps[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Helper for sids_to_unix_ids: find entry by SID in mapping array,
+ * search up to IDMAP_AD_MAX_IDS entries
+ */
+struct id_map *idmap_find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
+{
+ int i;
+
+ for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
+ if (maps[i] == NULL) { /* end of the run */
+ return NULL;
+ }
+ if (dom_sid_equal(maps[i]->sid, sid)) {
+ return maps[i];
+ }
+ }
+
+ return NULL;
+}
--
1.7.1
>From b4b140f916af4f076a0fda4a828db45d81ac34f6 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:31:19 -0700
Subject: [PATCH 02/11] s3-winbindd: Move idmap_fetch_secret to idmap_utils.c for reuse
---
source3/winbindd/idmap_ldap.c | 24 ------------------------
source3/winbindd/idmap_proto.h | 2 ++
source3/winbindd/idmap_util.c | 25 +++++++++++++++++++++++++
3 files changed, 27 insertions(+), 24 deletions(-)
diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c
index 03872e7..0520f21 100644
--- a/source3/winbindd/idmap_ldap.c
+++ b/source3/winbindd/idmap_ldap.c
@@ -39,30 +39,6 @@
#include "smbldap.h"
#include "passdb/pdb_ldap_schema.h"
-static char *idmap_fetch_secret(const char *backend,
- const char *domain, const char *identity)
-{
- char *tmp, *ret;
- int r;
-
- r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
-
- if (r < 0)
- return NULL;
-
- /* make sure the key is case insensitive */
- if (!strupper_m(tmp)) {
- SAFE_FREE(tmp);
- return NULL;
- }
-
- ret = secrets_fetch_generic(tmp, identity);
-
- SAFE_FREE(tmp);
-
- return ret;
-}
-
struct idmap_ldap_context {
struct smbldap_state *smbldap_state;
char *url;
diff --git a/source3/winbindd/idmap_proto.h b/source3/winbindd/idmap_proto.h
index a709807..f7af8ed 100644
--- a/source3/winbindd/idmap_proto.h
+++ b/source3/winbindd/idmap_proto.h
@@ -57,6 +57,8 @@ bool idmap_unix_id_is_in_range(uint32_t id, struct idmap_domain *dom);
struct id_map *idmap_find_map_by_id(struct id_map **maps, enum id_type type,
uint32_t id);
struct id_map *idmap_find_map_by_sid(struct id_map **maps, struct dom_sid *sid);
+char *idmap_fetch_secret(const char *backend, const char *domain,
+ const char *identity);
/* max number of ids requested per LDAP batch query */
#define IDMAP_LDAP_MAX_IDS 30
diff --git a/source3/winbindd/idmap_util.c b/source3/winbindd/idmap_util.c
index cbad91d..a068298 100644
--- a/source3/winbindd/idmap_util.c
+++ b/source3/winbindd/idmap_util.c
@@ -24,6 +24,7 @@
#include "idmap.h"
#include "idmap_cache.h"
#include "../libcli/security/security.h"
+#include "secrets.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
@@ -213,3 +214,27 @@ struct id_map *idmap_find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
return NULL;
}
+
+char *idmap_fetch_secret(const char *backend, const char *domain,
+ const char *identity)
+{
+ char *tmp, *ret;
+ int r;
+
+ r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
+
+ if (r < 0)
+ return NULL;
+
+ /* make sure the key is case insensitive */
+ if (!strupper_m(tmp)) {
+ SAFE_FREE(tmp);
+ return NULL;
+ }
+
+ ret = secrets_fetch_generic(tmp, identity);
+
+ SAFE_FREE(tmp);
+
+ return ret;
+}
--
1.7.1
>From 4ad90a5bbd71d3fcc4714013e657a39fbdbc3100 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:31:28 -0700
Subject: [PATCH 03/11] s3-winbindd: Move code for verifying ADS connection to common helper function
---
source3/winbindd/idmap_ad.c | 26 +----------------
source3/winbindd/winbindd_ads.c | 54 ++++++++++++++++++++++--------------
source3/winbindd/winbindd_proto.h | 6 ++++
3 files changed, 41 insertions(+), 45 deletions(-)
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index d6f31ba..0e00a34 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -39,8 +39,6 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
-#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
-
#define CHECK_ALLOC_DONE(mem) do { \
if (!mem) { \
DEBUG(0, ("Out of memory!\n")); \
@@ -74,29 +72,9 @@ static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
+ ads_cached_connection_reuse(&ctx->ads);
if (ctx->ads != NULL) {
-
- time_t expire;
- time_t now = time(NULL);
-
- ads = ctx->ads;
-
- expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
-
- /* check for a valid structure */
- DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
- (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
-
- if ( ads->config.realm && (expire > time(NULL))) {
- return ADS_SUCCESS;
- } else {
- /* we own this ADS_STRUCT so make sure it goes away */
- DEBUG(7,("Deleting expired krb5 credential cache\n"));
- ads->is_mine = True;
- ads_destroy( &ads );
- ads_kdestroy(WINBIND_CCACHE_NAME);
- ctx->ads = NULL;
- }
+ return ADS_SUCCESS;
}
/* we don't want this to affect the users ccache */
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index 921d408..ea6170d 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -40,43 +40,55 @@
extern struct winbindd_methods reconnect_methods;
-/*
- return our ads connections structure for a domain. We keep the connection
- open to make things faster
-*/
-static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
+/**
+ * Check if cached connection can be reused. If the connection cannot
+ * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
+ */
+void ads_cached_connection_reuse(ADS_STRUCT **adsp)
{
- ADS_STRUCT *ads;
- ADS_STATUS status;
- fstring dc_name;
- struct sockaddr_storage dc_ss;
-
- DEBUG(10,("ads_cached_connection\n"));
- if (domain->private_data) {
+ ADS_STRUCT *ads = *adsp;
+ if (ads != NULL) {
time_t expire;
time_t now = time(NULL);
- /* check for a valid structure */
- ads = (ADS_STRUCT *)domain->private_data;
-
expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
- DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
- (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
+ DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
+ "is now %d)\n", (uint32)expire - (uint32)now,
+ (uint32) expire, (uint32) now));
if ( ads->config.realm && (expire > now)) {
- return ads;
+ return;
} else {
/* we own this ADS_STRUCT so make sure it goes away */
DEBUG(7,("Deleting expired krb5 credential cache\n"));
ads->is_mine = True;
ads_destroy( &ads );
- ads_kdestroy("MEMORY:winbind_ccache");
- domain->private_data = NULL;
+ ads_kdestroy(WINBIND_CCACHE_NAME);
+ *adsp = NULL;
}
}
+}
+
+/*
+ return our ads connections structure for a domain. We keep the connection
+ open to make things faster
+*/
+static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ fstring dc_name;
+ struct sockaddr_storage dc_ss;
+
+ DEBUG(10,("ads_cached_connection\n"));
+ ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
+
+ if (domain->private_data) {
+ return (ADS_STRUCT *)domain->private_data;
+ }
ads = ads_init(domain->alt_name, domain->name, NULL);
if (!ads) {
@@ -1282,7 +1294,7 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
ads = (ADS_STRUCT *)domain->private_data;
ads->is_mine = True;
ads_destroy(&ads);
- ads_kdestroy("MEMORY:winbind_ccache");
+ ads_kdestroy(WINBIND_CCACHE_NAME);
domain->private_data = NULL;
}
}
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 00b7c32..0d75791 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -23,6 +23,8 @@
#ifndef _WINBINDD_PROTO_H_
#define _WINBINDD_PROTO_H_
+#include "ads.h"
+
/* The following definitions come from winbindd/winbindd.c */
struct messaging_context *winbind_messaging_context(void);
void request_error(struct winbindd_cli_state *state);
@@ -890,4 +892,8 @@ NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client **samr_pipe,
struct policy_handle *samr_domain_hnd);
+/* The following definitions come from winbindd/winbindd_ads.c */
+#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
+void ads_cached_connection_reuse(ADS_STRUCT **ads);
+
#endif /* _WINBINDD_PROTO_H_ */
--
1.7.1
>From 6d7460df31d88762a2f110ba053d0c992c005d80 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:31:37 -0700
Subject: [PATCH 04/11] s3-winbindd: Use common helper function for connecting to ADS
---
source3/winbindd/idmap_ad.c | 41 ++-----------
source3/winbindd/winbindd_ads.c | 125 ++++++++++++++++++++++---------------
source3/winbindd/winbindd_proto.h | 7 ++
3 files changed, 87 insertions(+), 86 deletions(-)
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index 0e00a34..5b9c377 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -58,13 +58,8 @@ struct idmap_ad_context {
static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
{
- ADS_STRUCT *ads;
- ADS_STATUS status;
- fstring dc_name;
- struct sockaddr_storage dc_ip;
struct idmap_ad_context *ctx;
- char *ldap_server = NULL;
- char *realm = NULL;
+ char *ldap_server, *realm, *password;
struct winbindd_domain *wb_dom;
DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
@@ -77,9 +72,6 @@ static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
return ADS_SUCCESS;
}
- /* we don't want this to affect the users ccache */
- setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
-
/*
* At this point we only have the NetBIOS domain name.
* Check if we can get server nam and realm from SAF cache
@@ -99,35 +91,12 @@ static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
realm = wb_dom->alt_name;
}
- if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) {
- DEBUG(1,("ads_init failed\n"));
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
/* the machine acct password might have change - fetch it every time */
- SAFE_FREE(ads->auth.password);
- ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
-
- SAFE_FREE(ads->auth.realm);
- ads->auth.realm = SMB_STRDUP(lp_realm());
-
- /* setup server affinity */
-
- get_dc_name(dom->name, realm, dc_name, &dc_ip );
-
- status = ads_connect(ads);
- if (!ADS_ERR_OK(status)) {
- DEBUG(1, ("ad_idmap_cached_connection_internal: failed to "
- "connect to AD\n"));
- ads_destroy(&ads);
- return status;
- }
-
- ads->is_mine = False;
-
- ctx->ads = ads;
+ password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ realm = SMB_STRDUP(lp_realm());
- return ADS_SUCCESS;
+ return ads_cached_connection_connect(&ctx->ads, realm, dom->name,
+ ldap_server, password, realm, 0);
}
/************************************************************************
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index ea6170d..ffc62ba 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -72,16 +72,73 @@ void ads_cached_connection_reuse(ADS_STRUCT **adsp)
}
}
+ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
+ const char *dom_name_alt,
+ const char *dom_name,
+ const char *ldap_server,
+ char *password,
+ char *realm,
+ time_t renewable)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ struct sockaddr_storage dc_ss;
+ fstring dc_name;
+
+ /* we don't want this to affect the users ccache */
+ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
+
+ ads = ads_init(dom_name_alt, dom_name, ldap_server);
+ if (!ads) {
+ DEBUG(1,("ads_init for domain %s failed\n", dom_name));
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ SAFE_FREE(ads->auth.password);
+ SAFE_FREE(ads->auth.realm);
+
+ ads->auth.renewable = renewable;
+ ads->auth.password = password;
+ ads->auth.realm = realm;
+
+ ads->auth.realm = SMB_STRDUP(realm);
+ if (!strupper_m(ads->auth.realm)) {
+ ads_destroy(&ads);
+ return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /* Setup the server affinity cache. We don't reaally care
+ about the name. Just setup affinity and the KRB5_CONFIG
+ file. */
+ get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
+
+ status = ads_connect(ads);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("ads_connect for domain %s failed: %s\n",
+ dom_name, ads_errstr(status)));
+ ads_destroy(&ads);
+ return status;
+ }
+
+ /* set the flag that says we don't own the memory even
+ though we do so that ads_destroy() won't destroy the
+ structure we pass back by reference */
+
+ ads->is_mine = False;
+
+ *adsp = ads;
+
+ return status;
+}
+
/*
return our ads connections structure for a domain. We keep the connection
open to make things faster
*/
static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
{
- ADS_STRUCT *ads;
ADS_STATUS status;
- fstring dc_name;
- struct sockaddr_storage dc_ss;
+ char *password, *realm;
DEBUG(10,("ads_cached_connection\n"));
ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
@@ -90,37 +147,22 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
return (ADS_STRUCT *)domain->private_data;
}
- ads = ads_init(domain->alt_name, domain->name, NULL);
- if (!ads) {
- DEBUG(1,("ads_init for domain %s failed\n", domain->name));
- return NULL;
- }
-
- /* we don't want ads operations to affect the default ccache */
- ads->auth.ccache_name = SMB_STRDUP("MEMORY:winbind_ccache");
-
/* the machine acct password might have change - fetch it every time */
- SAFE_FREE(ads->auth.password);
- SAFE_FREE(ads->auth.realm);
-
if ( IS_DC ) {
- if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
- ads_destroy( &ads );
- return NULL;
- }
- ads->auth.realm = SMB_STRDUP( ads->server.realm );
- if (!strupper_m( ads->auth.realm )) {
- ads_destroy( &ads );
+ if ( !pdb_get_trusteddom_pw( domain->name, &password, NULL,
+ NULL ) ) {
return NULL;
}
+ realm = NULL;
}
else {
struct winbindd_domain *our_domain = domain;
- ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ password = secrets_fetch_machine_password(lp_workgroup(), NULL,
+ NULL);
/* always give preference to the alt_name in our
primary domain if possible */
@@ -128,30 +170,21 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
our_domain = find_our_domain();
if ( our_domain->alt_name[0] != '\0' ) {
- ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
- if (!strupper_m( ads->auth.realm )) {
- ads_destroy( &ads );
- return NULL;
- }
+ realm = SMB_STRDUP( our_domain->alt_name );
}
else
- ads->auth.realm = SMB_STRDUP( lp_realm() );
+ realm = SMB_STRDUP( lp_realm() );
}
- ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
+ status = ads_cached_connection_connect(
+ (ADS_STRUCT **)&domain->private_data,
+ domain->alt_name,
+ domain->name, NULL,
+ password, realm,
+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
- /* Setup the server affinity cache. We don't reaally care
- about the name. Just setup affinity and the KRB5_CONFIG
- file. */
-
- get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
-
- status = ads_connect(ads);
- if (!ADS_ERR_OK(status) || !ads->config.realm) {
- DEBUG(1,("ads_connect for domain %s failed: %s\n",
- domain->name, ads_errstr(status)));
- ads_destroy(&ads);
+ if (!ADS_ERR_OK(status)) {
/* if we get ECONNREFUSED then it might be a NT4
server, fall back to MSRPC */
if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
@@ -163,17 +196,9 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
return NULL;
}
- /* set the flag that says we don't own the memory even
- though we do so that ads_destroy() won't destroy the
- structure we pass back by reference */
-
- ads->is_mine = False;
-
- domain->private_data = (void *)ads;
- return ads;
+ return (ADS_STRUCT *)domain->private_data;
}
-
/* Query display info for a realm. This is the basic user list fn */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 0d75791..8bd7a39 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -895,5 +895,12 @@ NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
/* The following definitions come from winbindd/winbindd_ads.c */
#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
void ads_cached_connection_reuse(ADS_STRUCT **ads);
+ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
+ const char *dom_name_alt,
+ const char *dom_name,
+ const char *ldap_server,
+ char *password,
+ char *realm,
+ time_t renewable);
#endif /* _WINBINDD_PROTO_H_ */
--
1.7.1
>From dad6b8ab1e518246e31bfc547089690f85c97971 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:31:41 -0700
Subject: [PATCH 05/11] s3-winbindd: Move connection to AD server from idmap_ad
Having this in a common place allows reuse by other idmap modules.
---
source3/winbindd/idmap_ad.c | 49 +++------------------------------
source3/winbindd/winbindd_ads.c | 55 +++++++++++++++++++++++++++++++-----
source3/winbindd/winbindd_proto.h | 10 +------
3 files changed, 52 insertions(+), 62 deletions(-)
diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index 5b9c377..5bafa90 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -56,58 +56,17 @@ struct idmap_ad_context {
/************************************************************************
***********************************************************************/
-static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
+static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
{
- struct idmap_ad_context *ctx;
- char *ldap_server, *realm, *password;
- struct winbindd_domain *wb_dom;
+ ADS_STATUS status;
+ struct idmap_ad_context * ctx;
DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
dom->name));
ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
- ads_cached_connection_reuse(&ctx->ads);
- if (ctx->ads != NULL) {
- return ADS_SUCCESS;
- }
-
- /*
- * At this point we only have the NetBIOS domain name.
- * Check if we can get server nam and realm from SAF cache
- * and the domain list.
- */
- ldap_server = saf_fetch(dom->name);
- DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:""));
-
- wb_dom = find_domain_from_name_noinit(dom->name);
- if (wb_dom == NULL) {
- DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n",
- dom->name));
- realm = NULL;
- } else {
- DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
- " domain '%s'\n", wb_dom->alt_name, dom->name));
- realm = wb_dom->alt_name;
- }
-
- /* the machine acct password might have change - fetch it every time */
- password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
- realm = SMB_STRDUP(lp_realm());
-
- return ads_cached_connection_connect(&ctx->ads, realm, dom->name,
- ldap_server, password, realm, 0);
-}
-
-/************************************************************************
- ***********************************************************************/
-
-static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
-{
- ADS_STATUS status;
- struct idmap_ad_context * ctx;
-
- status = ad_idmap_cached_connection_internal(dom);
+ status = ads_idmap_cached_connection(&ctx->ads, dom->name);
if (!ADS_ERR_OK(status)) {
return status;
}
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index ffc62ba..2dcd07d 100644
--- a/source3/winbindd/winbindd_ads.c
+++ b/source3/winbindd/winbindd_ads.c
@@ -40,11 +40,13 @@
extern struct winbindd_methods reconnect_methods;
+#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
+
/**
* Check if cached connection can be reused. If the connection cannot
* be reused the ADS_STRUCT is freed and the pointer is set to NULL.
*/
-void ads_cached_connection_reuse(ADS_STRUCT **adsp)
+static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
{
ADS_STRUCT *ads = *adsp;
@@ -72,13 +74,13 @@ void ads_cached_connection_reuse(ADS_STRUCT **adsp)
}
}
-ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
- const char *dom_name_alt,
- const char *dom_name,
- const char *ldap_server,
- char *password,
- char *realm,
- time_t renewable)
+static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
+ const char *dom_name_alt,
+ const char *dom_name,
+ const char *ldap_server,
+ char *password,
+ char *realm,
+ time_t renewable)
{
ADS_STRUCT *ads;
ADS_STATUS status;
@@ -131,6 +133,43 @@ ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
return status;
}
+ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
+{
+ char *ldap_server, *realm, *password;
+ struct winbindd_domain *wb_dom;
+
+ ads_cached_connection_reuse(adsp);
+ if (*adsp != NULL) {
+ return ADS_SUCCESS;
+ }
+
+ /*
+ * At this point we only have the NetBIOS domain name.
+ * Check if we can get server nam and realm from SAF cache
+ * and the domain list.
+ */
+ ldap_server = saf_fetch(dom_name);
+ DEBUG(10, ("ldap_server from saf cache: '%s'\n",
+ ldap_server ? ldap_server : ""));
+
+ wb_dom = find_domain_from_name_noinit(dom_name);
+ if (wb_dom == NULL) {
+ DEBUG(10, ("could not find domain '%s'\n", dom_name));
+ realm = NULL;
+ } else {
+ DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
+ " domain '%s'\n", wb_dom->alt_name, dom_name));
+ realm = wb_dom->alt_name;
+ }
+
+ /* the machine acct password might have change - fetch it every time */
+ password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ realm = SMB_STRDUP(lp_realm());
+
+ return ads_cached_connection_connect(adsp, realm, dom_name, ldap_server,
+ password, realm, 0);
+}
+
/*
return our ads connections structure for a domain. We keep the connection
open to make things faster
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 8bd7a39..b07f303 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -893,14 +893,6 @@ NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
struct policy_handle *samr_domain_hnd);
/* The following definitions come from winbindd/winbindd_ads.c */
-#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
-void ads_cached_connection_reuse(ADS_STRUCT **ads);
-ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
- const char *dom_name_alt,
- const char *dom_name,
- const char *ldap_server,
- char *password,
- char *realm,
- time_t renewable);
+ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name);
#endif /* _WINBINDD_PROTO_H_ */
--
1.7.1
>From 87fbb20f504235d691280d88aac053baee9623c3 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:32:37 -0700
Subject: [PATCH 06/11] s3-winbindd: Add new module idmap_rfc2307
This module allows querying id mappings from LDAP servers as described
in RFC 2307. The LDAP records can be queried from an Active Directory
Server or from a stand-alone LDAP server.
---
source3/Makefile.in | 4 +
source3/configure.in | 1 +
source3/winbindd/idmap_rfc2307.c | 870 ++++++++++++++++++++++++++++++++++++++
source3/winbindd/wscript_build | 10 +
source3/wscript | 2 +-
5 files changed, 886 insertions(+), 1 deletions(-)
create mode 100644 source3/winbindd/idmap_rfc2307.c
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 90f12b7..194cba7 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -2694,6 +2694,10 @@ bin/ad. at SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ad.o
@echo "Building plugin $@"
@$(SHLD_MODULE) winbindd/idmap_ad.o
+bin/rfc2307. at SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_rfc2307.o
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) winbindd/idmap_rfc2307.o
+
bin/hash. at SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_HASH_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(IDMAP_HASH_OBJ)
diff --git a/source3/configure.in b/source3/configure.in
index 56c9190..59eb087 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -6382,6 +6382,7 @@ SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_autorid, winbindd/idmap_autorid.o, "bin/autorid.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_ad, winbindd/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
+SMB_MODULE(idmap_rfc2307, winbindd/idmap_rfc2307.o, "bin/rfc2307.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_hash, \$(IDMAP_HASH_OBJ), "bin/hash.$SHLIBEXT", IDMAP)
SMB_SUBSYSTEM(IDMAP, winbindd/idmap.o)
diff --git a/source3/winbindd/idmap_rfc2307.c b/source3/winbindd/idmap_rfc2307.c
new file mode 100644
index 0000000..2b7a593
--- /dev/null
+++ b/source3/winbindd/idmap_rfc2307.c
@@ -0,0 +1,870 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Id mapping using LDAP records as defined in RFC 2307
+ *
+ * The SID<->uid/gid mapping is performed in two steps: 1) Query the
+ * AD server for the name<->sid mapping. 2) Query an LDAP server
+ * according to RFC 2307 for the name<->uid/gid mapping.
+ *
+ * Copyright (C) Christof Schmitt 2012,2013
+ *
+ * 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 "includes.h"
+#include "winbindd.h"
+#include "ads.h"
+#include "idmap.h"
+#include "smbldap.h"
+#include "nsswitch/winbind_client.h"
+#include "lib/winbind_util.h"
+
+/*
+ * Config and connection info per domain.
+ */
+struct idmap_rfc2307_context {
+ const char *bind_path_user;
+ const char *bind_path_group;
+ const char *ldap_domain;
+ bool cn_realm;
+ bool user_cn;
+ const char *realm;
+
+ /*
+ * Pointer to ldap struct in ads or smbldap_state, has to be
+ * updated after connecting to server
+ */
+ LDAP *ldap;
+
+ /* Optional function to check connection to server */
+ NTSTATUS (*check_connection)(struct idmap_domain *dom);
+
+ /* Issue ldap query */
+ NTSTATUS (*search)(struct idmap_rfc2307_context *ctx,
+ const char *bind_path, const char *expr,
+ const char **attrs, LDAPMessage **res);
+
+ /* Access to LDAP in AD server */
+ ADS_STRUCT *ads;
+
+ /* Access to stand-alone LDAP server */
+ struct smbldap_state *smbldap_state;
+};
+
+/*
+ * backend functions for LDAP queries through ADS
+ */
+
+static NTSTATUS idmap_rfc2307_ads_check_connection(struct idmap_domain *dom)
+{
+ struct idmap_rfc2307_context *ctx;
+ const char *dom_name = dom->name;
+ ADS_STATUS status;
+
+ DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
+ dom->name));
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
+ dom_name = ctx->ldap_domain ? ctx->ldap_domain : dom->name;
+
+ status = ads_idmap_cached_connection(&ctx->ads, dom_name);
+ if (ADS_ERR_OK(status)) {
+ ctx->ldap = ctx->ads->ldap.ld;
+ if (ctx->cn_realm) {
+ ctx->realm = ctx->ads->server.realm;
+ }
+ } else {
+ DEBUG(1, ("Could not connect to domain %s: %s\n", dom->name,
+ ads_errstr(status)));
+ }
+
+ return ads_ntstatus(status);
+}
+
+static NTSTATUS idmap_rfc2307_ads_search(struct idmap_rfc2307_context *ctx,
+ const char *bind_path,
+ const char *expr,
+ const char **attrs,
+ LDAPMessage **result)
+{
+ ADS_STATUS status;
+
+ status = ads_do_search_retry(ctx->ads, bind_path,
+ LDAP_SCOPE_SUBTREE, expr, attrs, result);
+ return ads_ntstatus(status);
+}
+
+static NTSTATUS idmap_rfc2307_init_ads(struct idmap_rfc2307_context *ctx,
+ const char *cfg_opt)
+{
+ const char *ldap_domain;
+
+ ctx->search = idmap_rfc2307_ads_search;
+ ctx->check_connection = idmap_rfc2307_ads_check_connection;
+
+ ldap_domain = lp_parm_const_string(-1, cfg_opt, "ldap_domain",
+ NULL);
+ if (ldap_domain) {
+ ctx->ldap_domain = talloc_strdup(ctx, ldap_domain);
+ if (ctx->ldap_domain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * backend function for LDAP queries through stand-alone LDAP server
+ */
+
+static NTSTATUS idmap_rfc2307_ldap_search(struct idmap_rfc2307_context *ctx,
+ const char *bind_path,
+ const char *expr,
+ const char **attrs,
+ LDAPMessage **result)
+{
+ int ret;
+
+ ret = smbldap_search(ctx->smbldap_state, bind_path, LDAP_SCOPE_SUBTREE,
+ expr, attrs, 0, result);
+ ctx->ldap = ctx->smbldap_state->ldap_struct;
+
+ if (ret == LDAP_SUCCESS) {
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_LDAP(ret);
+}
+
+static bool idmap_rfc2307_get_uint32(LDAP *ldap, LDAPMessage *entry,
+ const char *field, uint32 *value)
+{
+ bool b;
+ char str[20];
+
+ b = smbldap_get_single_attribute(ldap, entry, field, str, sizeof(str));
+
+ if (b) {
+ *value = atoi(str);
+ }
+
+ return b;
+}
+
+static NTSTATUS idmap_rfc2307_init_ldap(struct idmap_rfc2307_context *ctx,
+ struct idmap_domain *dom,
+ const char *config_option)
+{
+ NTSTATUS ret;
+ char *url;
+ char *secret = NULL;
+ const char *ldap_url, *user_dn, *ldap_realm;
+ TALLOC_CTX *mem_ctx = ctx;
+
+ ldap_url = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
+ if (!ldap_url) {
+ DEBUG(1, ("ERROR: missing idmap ldap url\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ url = talloc_strdup(talloc_tos(), ldap_url);
+
+ user_dn = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
+ if (user_dn) {
+ secret = idmap_fetch_secret("ldap", dom->name, user_dn);
+ if (!secret) {
+ ret = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ /* assume anonymous if we don't have a specified user */
+ ret = smbldap_init(mem_ctx, winbind_event_context(), url,
+ (user_dn == NULL), user_dn, secret,
+ &ctx->smbldap_state);
+ SAFE_FREE(secret);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", url));
+ goto done;
+ }
+
+ ctx->search = idmap_rfc2307_ldap_search;
+
+ if (ctx->cn_realm) {
+ ldap_realm = lp_parm_const_string(-1, config_option,
+ "ldap_realm", NULL);
+ if (!ldap_realm) {
+ DEBUG(1, ("ERROR: cn_realm set, "
+ "but ldap_realm is missing\n"));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ ctx->realm = talloc_strdup(mem_ctx, ldap_realm);
+ if (!ctx->realm) {
+ ret = NT_STATUS_NO_MEMORY;
+ }
+ }
+
+done:
+ talloc_free(url);
+ return ret;
+}
+
+/*
+ * common code for stand-alone LDAP and ADS
+ */
+
+static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct id_map **ids,
+ LDAPMessage *result,
+ const char *dom_name,
+ const char **attrs, int type)
+{
+ int count, i;
+ LDAPMessage *entry;
+
+ count = ldap_count_entries(ctx->ldap, result);
+
+ for (i = 0; i < count; i++) {
+ char *name;
+ enum lsa_SidType lsa_type;
+ struct id_map *map;
+ uint32_t id;
+ bool b;
+
+ if (i == 0) {
+ entry = ldap_first_entry(ctx->ldap, result);
+ } else {
+ entry = ldap_next_entry(ctx->ldap, result);
+ }
+ if (!entry) {
+ DEBUG(2, ("Unable to fetch entry.\n"));
+ break;
+ }
+
+ name = smbldap_talloc_single_attribute(ctx->ldap, entry,
+ attrs[0], mem_ctx);
+ if (!name) {
+ DEBUG(1, ("Could not get user name\n"));
+ continue;
+ }
+
+ b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id);
+ if (!b) {
+ DEBUG(1, ("Could not pull id for record %s\n", name));
+ continue;
+ }
+
+ map = idmap_find_map_by_id(ids, type, id);
+ if (!map) {
+ DEBUG(1, ("Could not find id %d, name %s\n", id, name));
+ continue;
+ }
+
+ if (ctx->cn_realm) {
+ /* Strip @realm from user or group name */
+ char *delim;
+
+ delim = strchr(name, '@');
+ if (delim) {
+ *delim = '\0';
+ }
+ }
+
+ /* by default calls to winbindd are disabled
+ the following call will not recurse so this is safe */
+ (void)winbind_on();
+ /* Lookup name from PDC using lsa_lookup_names() */
+ b = winbind_lookup_name(dom_name, name, map->sid, &lsa_type);
+ (void)winbind_off();
+
+ if (!b) {
+ DEBUG(1, ("SID lookup failed for id %d, %s\n",
+ id, name));
+ continue;
+ }
+
+ if (type == ID_TYPE_UID && lsa_type != SID_NAME_USER) {
+ DEBUG(1, ("Wrong type %d for user name %s\n",
+ type, name));
+ continue;
+ }
+
+ if (type == ID_TYPE_GID && lsa_type != SID_NAME_DOM_GRP &&
+ lsa_type != SID_NAME_ALIAS &&
+ lsa_type != SID_NAME_WKN_GRP) {
+ DEBUG(1, ("Wrong type %d for group name %s\n",
+ type, name));
+ continue;
+ }
+
+ map->status = ID_MAPPED;
+ }
+}
+
+/*
+ * Map unixids to names and then to sids.
+ */
+static NTSTATUS idmap_rfc2307_unixids_to_sids(struct idmap_domain *dom,
+ struct id_map **ids)
+{
+ struct idmap_rfc2307_context *ctx;
+ char *fltr_usr = NULL, *fltr_grp = NULL;
+ TALLOC_CTX *mem_ctx;
+ int cnt_usr = 0, cnt_grp = 0, idx = 0, bidx = 0;
+ LDAPMessage *result = NULL;
+ NTSTATUS ret;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
+ mem_ctx = talloc_new(ctx);
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ctx->check_connection) {
+ ret = ctx->check_connection(dom);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+ }
+
+again:
+ bidx = idx;
+
+ if (!fltr_usr) {
+ /* prepare new user query, see getpwuid() in RFC2307 */
+ fltr_usr = talloc_asprintf(mem_ctx,
+ "(&(objectClass=posixAccount)(|");
+ }
+
+ if (!fltr_grp) {
+ /* prepare new group query, see getgrgid() in RFC2307 */
+ fltr_grp = talloc_asprintf(mem_ctx,
+ "(&(objectClass=posixGroup)(|");
+ }
+
+ if (!fltr_usr || !fltr_grp) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ while (cnt_usr < IDMAP_LDAP_MAX_IDS &&
+ cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) {
+
+ switch (ids[idx]->xid.type) {
+ case ID_TYPE_UID:
+ fltr_usr = talloc_asprintf_append_buffer(fltr_usr,
+ "(uidNumber=%d)", ids[idx]->xid.id);
+ cnt_usr++;
+ break;
+ case ID_TYPE_GID:
+ fltr_grp = talloc_asprintf_append_buffer(fltr_grp,
+ "(gidNumber=%d))", ids[idx]->xid.id);
+ cnt_grp++;
+ break;
+ default:
+ DEBUG(3, ("Error: unknown ID type %d\n",
+ ids[idx]->xid.type));
+ ret = NT_STATUS_UNSUCCESSFUL;
+ goto out;
+ }
+
+ if (!fltr_usr || !fltr_grp) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ idx++;
+ }
+
+ if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) {
+ const char *attrs[] = { NULL, /* uid or cn */
+ "uidNumber",
+ NULL };
+
+ fltr_usr = talloc_strdup_append(fltr_usr, "))");
+ if (!fltr_usr) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ attrs[0] = ctx->user_cn ? "cn" : "uid";
+ ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs,
+ &result);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+
+ idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result,
+ dom->name, attrs, ID_TYPE_UID);
+ cnt_usr = 0;
+ TALLOC_FREE(fltr_usr);
+ }
+
+ if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) {
+ const char *attrs[] = { "cn", "gidNumber", NULL };
+
+ fltr_grp = talloc_strdup_append(fltr_grp, "))");
+ if (!fltr_grp) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+ ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs,
+ &result);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+
+ idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result,
+ dom->name, attrs, ID_TYPE_GID);
+ cnt_grp = 0;
+ TALLOC_FREE(fltr_grp);
+ }
+
+ if (ids[idx]) {
+ goto again;
+ }
+
+ ret = NT_STATUS_OK;
+
+out:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+struct idmap_rfc2307_map {
+ struct id_map *map;
+ const char *name;
+ enum id_type type;
+};
+
+/*
+ * Lookup names for SIDS and store the data in the local mapping
+ * array.
+ */
+static NTSTATUS idmap_rfc_2307_sids_to_names(TALLOC_CTX *mem_ctx,
+ struct id_map **ids,
+ struct idmap_rfc2307_map *maps,
+ struct idmap_rfc2307_context *ctx)
+{
+ int i;
+
+ for (i = 0; ids[i]; i++) {
+ const char *domain, *name;
+ enum lsa_SidType lsa_type;
+ struct id_map *id = ids[i];
+ struct idmap_rfc2307_map *map = &maps[i];
+ bool b;
+
+ /* by default calls to winbindd are disabled
+ the following call will not recurse so this is safe */
+ (void)winbind_on();
+ b = winbind_lookup_sid(mem_ctx, ids[i]->sid, &domain, &name,
+ &lsa_type);
+ (void)winbind_off();
+
+ if (!b) {
+ DEBUG(1, ("Lookup sid %s failed.\n",
+ sid_string_dbg(ids[i]->sid)));
+ continue;
+ }
+
+ switch(lsa_type) {
+ case SID_NAME_USER:
+ id->xid.type = map->type = ID_TYPE_UID;
+ if (ctx->user_cn && ctx->cn_realm) {
+ name = talloc_asprintf(mem_ctx, "%s@%s",
+ name, ctx->realm);
+ }
+ id->xid.type = map->type = ID_TYPE_UID;
+ break;
+
+ case SID_NAME_DOM_GRP:
+ case SID_NAME_ALIAS:
+ case SID_NAME_WKN_GRP:
+ if (ctx->cn_realm) {
+ name = talloc_asprintf(mem_ctx, "%s@%s",
+ name, ctx->realm);
+ }
+ id->xid.type = map->type = ID_TYPE_GID;
+ break;
+
+ default:
+ DEBUG(1, ("Unknown lsa type %d for sid %s\n",
+ lsa_type, sid_string_dbg(id->sid)));
+ id->status = ID_UNMAPPED;
+ continue;
+ }
+
+ map->map = id;
+ id->status = ID_UNKNOWN;
+ map->name = strupper_talloc(mem_ctx, name);
+
+ if (!map->name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Find id_map entry by looking up the name in the internal
+ * mapping array.
+ */
+static struct id_map* idmap_rfc2307_find_map(struct idmap_rfc2307_map *maps,
+ enum id_type type,
+ const char *name)
+{
+ int i;
+
+ DEBUG(10, ("Looking for name %s, type %d\n", name, type));
+
+ for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
+ if (maps[i].map == NULL) { /* end of the run */
+ return NULL;
+ }
+ DEBUG(10, ("Entry %d: name %s, type %d\n",
+ i, maps[i].name, maps[i].type));
+ if (type == maps[i].type && strcmp(name, maps[i].name) == 0) {
+ return maps[i].map;
+ }
+ }
+
+ return NULL;
+}
+
+static void idmap_rfc2307_map_xid_results(struct idmap_rfc2307_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct id_map **ids,
+ struct idmap_rfc2307_map *maps,
+ LDAPMessage *result,
+ struct idmap_domain *dom,
+ const char **attrs, enum id_type type)
+{
+ int count, i;
+ LDAPMessage *entry;
+
+ count = ldap_count_entries(ctx->ldap, result);
+
+ for (i = 0; i < count; i++) {
+ uint32_t id;
+ char *name;
+ bool b;
+ struct id_map *id_map;
+
+ if (i == 0) {
+ entry = ldap_first_entry(ctx->ldap, result);
+ } else {
+ entry = ldap_next_entry(ctx->ldap, result);
+ }
+ if (!entry) {
+ DEBUG(2, ("Unable to fetch entry.\n"));
+ break;
+ }
+
+ name = smbldap_talloc_single_attribute(ctx->ldap, entry,
+ attrs[0], mem_ctx);
+ if (!name) {
+ DEBUG(1, ("Could not get user name\n"));
+ continue;
+ }
+
+ b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id);
+ if (!b) {
+ DEBUG(5, ("Could not pull id for record %s\n", name));
+ continue;
+ }
+
+ if (!idmap_unix_id_is_in_range(id, dom)) {
+ DEBUG(5, ("Requested id (%u) out of range (%u - %u).\n",
+ id, dom->low_id, dom->high_id));
+ continue;
+ }
+
+ if (!strupper_m(name)) {
+ DEBUG(5, ("Could not convert %s to uppercase\n", name));
+ continue;
+ }
+ id_map = idmap_rfc2307_find_map(maps, type, name);
+ if (!id_map) {
+ DEBUG(0, ("Could not find mapping entry for name %s\n",
+ name));
+ continue;
+ }
+
+ id_map->xid.id = id;
+ id_map->status = ID_MAPPED;
+ }
+}
+
+/*
+ * Map sids to names and then to unixids.
+ */
+static NTSTATUS idmap_rfc2307_sids_to_unixids(struct idmap_domain *dom,
+ struct id_map **ids)
+{
+ struct idmap_rfc2307_context *ctx;
+ TALLOC_CTX *mem_ctx;
+ struct idmap_rfc2307_map *int_maps;
+ int cnt_usr = 0, cnt_grp = 0, idx = 0, bidx = 0;
+ char *fltr_usr = NULL, *fltr_grp = NULL;
+ NTSTATUS ret;
+ int i;
+
+ ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
+ mem_ctx = talloc_new(talloc_tos());
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ctx->check_connection) {
+ ret = ctx->check_connection(dom);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+ }
+
+ for (i = 0; ids[i]; i++);
+ int_maps = talloc_zero_array(mem_ctx, struct idmap_rfc2307_map, i);
+ if (!int_maps) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = idmap_rfc_2307_sids_to_names(mem_ctx, ids, int_maps, ctx);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+
+again:
+ if (!fltr_usr) {
+ /* prepare new user query, see getpwuid() in RFC2307 */
+ fltr_usr = talloc_asprintf(mem_ctx,
+ "(&(objectClass=posixAccount)(|");
+ }
+
+ if (!fltr_grp) {
+ /* prepare new group query, see getgrgid() in RFC2307 */
+ fltr_grp = talloc_asprintf(mem_ctx,
+ "(&(objectClass=posixGroup)(|");
+ }
+
+ if (!fltr_usr || !fltr_grp) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ while (cnt_usr < IDMAP_LDAP_MAX_IDS &&
+ cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) {
+ struct id_map *id = ids[idx];
+ struct idmap_rfc2307_map *map = &int_maps[idx];
+
+ switch(id->xid.type) {
+ case ID_TYPE_UID:
+ fltr_usr = talloc_asprintf_append_buffer(fltr_usr,
+ "(%s=%s)", (ctx->user_cn ? "cn" : "uid"),
+ map->name);
+ cnt_usr++;
+ break;
+
+ case ID_TYPE_GID:
+ fltr_grp = talloc_asprintf_append_buffer(fltr_grp,
+ "(cn=%s)", map->name);
+ cnt_grp++;
+ break;
+
+ default:
+ DEBUG(10, ("Nothing to do for SID %s, "
+ "previous name lookup failed\n",
+ sid_string_dbg(map->map->sid)));
+ }
+
+ if (!fltr_usr || !fltr_grp) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ idx++;
+ }
+
+ if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) {
+ const char *attrs[] = { NULL, /* uid or cn */
+ "uidNumber",
+ NULL };
+ LDAPMessage *result;
+
+ fltr_usr = talloc_strdup_append(fltr_usr, "))");
+ if (!fltr_usr) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ attrs[0] = ctx->user_cn ? "cn" : "uid";
+ ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs,
+ &result);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+
+ idmap_rfc2307_map_xid_results(ctx, mem_ctx, &ids[bidx],
+ int_maps, result, dom,
+ attrs, ID_TYPE_UID);
+
+ cnt_usr = 0;
+ TALLOC_FREE(fltr_usr);
+ }
+
+ if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) {
+ const char *attrs[] = {"cn", "gidNumber", NULL };
+ LDAPMessage *result;
+
+ fltr_grp = talloc_strdup_append(fltr_grp, "))");
+ if (!fltr_grp) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs,
+ &result);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto out;
+ }
+
+ idmap_rfc2307_map_xid_results(ctx, mem_ctx, &ids[bidx],
+ int_maps, result, dom,
+ attrs, ID_TYPE_GID);
+ cnt_grp = 0;
+ TALLOC_FREE(fltr_grp);
+ }
+
+ if (ids[idx]) {
+ goto again;
+ }
+
+ ret = NT_STATUS_OK;
+
+out:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+static int idmap_rfc2307_context_destructor(struct idmap_rfc2307_context *ctx)
+{
+ if (ctx->ads != NULL) {
+ /* we own this ADS_STRUCT so make sure it goes away */
+ ctx->ads->is_mine = True;
+ ads_destroy( &ctx->ads );
+ ctx->ads = NULL;
+ }
+
+ if (ctx->smbldap_state != NULL) {
+ smbldap_free_struct(&ctx->smbldap_state);
+ }
+
+ return 0;
+}
+
+static NTSTATUS idmap_rfc2307_initialize(struct idmap_domain *domain)
+{
+ struct idmap_rfc2307_context *ctx;
+ char *cfg_opt;
+ const char *bind_path_user, *bind_path_group, *ldap_server;
+ NTSTATUS status;
+
+ ctx = talloc_zero(domain, struct idmap_rfc2307_context);
+ if (ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(ctx, idmap_rfc2307_context_destructor);
+
+ cfg_opt = talloc_asprintf(ctx, "idmap config %s", domain->name);
+ if (cfg_opt == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto err;
+ }
+
+ bind_path_user = lp_parm_const_string(-1, cfg_opt, "bind_path_user",
+ NULL);
+ if (bind_path_user) {
+ ctx->bind_path_user = talloc_strdup(ctx, bind_path_user);
+ if (ctx->bind_path_user == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto err;
+ }
+ } else {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ bind_path_group = lp_parm_const_string(-1, cfg_opt, "bind_path_group",
+ NULL);
+ if (bind_path_group) {
+ ctx->bind_path_group = talloc_strdup(ctx, bind_path_group);
+ if (ctx->bind_path_group == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto err;
+ }
+ } else {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ ldap_server = lp_parm_const_string(-1, cfg_opt, "ldap_server", NULL);
+ if (!ldap_server) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto err;
+ }
+
+ if (strcmp(ldap_server, "stand-alone") == 0) {
+ status = idmap_rfc2307_init_ldap(ctx, domain, cfg_opt);
+
+ } else if (strcmp(ldap_server, "ad") == 0) {
+ status = idmap_rfc2307_init_ads(ctx, cfg_opt);
+
+ } else {
+ status = NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err;
+ }
+
+ ctx->cn_realm = lp_parm_bool(-1, cfg_opt, "cn_realm", false);
+ ctx->user_cn = lp_parm_bool(-1, cfg_opt, "user_cn", false);
+
+ domain->private_data = ctx;
+ talloc_free(cfg_opt);
+ return NT_STATUS_OK;
+
+err:
+ talloc_free(cfg_opt);
+ talloc_free(ctx);
+ return status;
+}
+
+static struct idmap_methods rfc2307_methods = {
+ .init = idmap_rfc2307_initialize,
+ .unixids_to_sids = idmap_rfc2307_unixids_to_sids,
+ .sids_to_unixids = idmap_rfc2307_sids_to_unixids,
+};
+
+NTSTATUS idmap_rfc2307_init(void)
+{
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rfc2307",
+ &rfc2307_methods);
+}
diff --git a/source3/winbindd/wscript_build b/source3/winbindd/wscript_build
index 7e80727..aacd859 100644
--- a/source3/winbindd/wscript_build
+++ b/source3/winbindd/wscript_build
@@ -1,6 +1,7 @@
#!/usr/bin/env python
IDMAP_AD_SRC = '''idmap_ad.c'''
+IDMAP_RFC2307_SRC = '''idmap_rfc2307.c'''
IDMAP_RID_SRC = '''idmap_rid.c'''
IDMAP_PASSDB_SRC = '''idmap_passdb.c'''
IDMAP_LDAP_SRC = '''idmap_ldap.c'''
@@ -43,6 +44,15 @@ bld.SAMBA3_MODULE('idmap_ad',
internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_ad'),
enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad') and bld.CONFIG_SET("HAVE_LDAP"))
+bld.SAMBA3_MODULE('idmap_rfc2307',
+ subsystem='idmap',
+ allow_undefined_symbols=True,
+ source=IDMAP_RFC2307_SRC,
+ init_function='',
+ deps='ads',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_rfc2307'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_rfc2307') and bld.CONFIG_SET("HAVE_LDAP"))
+
bld.SAMBA3_MODULE('idmap_rid',
subsystem='idmap',
allow_undefined_symbols=True,
diff --git a/source3/wscript b/source3/wscript
index 7a99dc1..9424b1c 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -1693,7 +1693,7 @@ main() {
vfs_commit
vfs_crossrename vfs_linux_xfs_sgid
vfs_time_audit idmap_autorid idmap_tdb2
- idmap_rid idmap_hash'''))
+ idmap_rid idmap_hash idmap_rfc2307'''))
if Options.options.developer:
default_static_modules.extend(TO_LIST('charset_weird'))
--
1.7.1
>From 893fee568105fc442b5973c3e748409ddc1c329d Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:32:54 -0700
Subject: [PATCH 07/11] s3-docs: Add manpage for idmap_rfc2307 module
---
docs-xml/manpages/idmap_rfc2307.8.xml | 165 +++++++++++++++++++++++++++++++++
docs-xml/wscript_build | 1 +
2 files changed, 166 insertions(+), 0 deletions(-)
create mode 100644 docs-xml/manpages/idmap_rfc2307.8.xml
diff --git a/docs-xml/manpages/idmap_rfc2307.8.xml b/docs-xml/manpages/idmap_rfc2307.8.xml
new file mode 100644
index 0000000..f680945
--- /dev/null
+++ b/docs-xml/manpages/idmap_rfc2307.8.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="idmap_rfc2307.8">
+
+<refmeta>
+ <refentrytitle>idmap_rfc2307</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+<refnamediv>
+ <refname>idmap_rfc2307</refname>
+ <refpurpose>Samba's idmap_rfc2307 Backend for Winbind</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <title>DESCRIPTION</title>
+
+ <para>The idmap_rfc2307 plugin provides a way for winbind to
+ read id mappings from records in an LDAP server as defined in
+ RFC 2307. The LDAP server can be stand-alone or the LDAP
+ server provided by the AD server. An AD server is always
+ required to provide the mapping between name and SID, and the
+ LDAP server is queried for the mapping between name and
+ uid/gid. This module implements only the "idmap"
+ API, and is READONLY.</para>
+
+ <para>Mappings must be provided in advance by the
+ administrator by creating the user accounts in the Active
+ Directory server and the posixAccount and posixGroup objects
+ in the LDAP server. The names in the Active Directory server
+ and in the LDAP server have to be the same.</para>
+
+ <para>This id mapping approach allows the reuse of existing
+ LDAP authentication servers that store records in the RFC 2307
+ format.</para>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>IDMAP OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>range = low - high</term>
+ <listitem><para> Defines the available
+ matching UID and GID range for which the
+ backend is authoritative. Note that the range
+ acts as a filter. If specified any UID or GID
+ stored in AD that fall outside the range is
+ ignored and the corresponding map is
+ discarded. It is intended as a way to avoid
+ accidental UID/GID overlaps between local and
+ remotely defined IDs.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ldap_server = <ad | stand-alone ></term>
+ <listitem><para>Defines the type of LDAP
+ server to use. This can either be the LDAP
+ server provided by the Active Directory server
+ (ad) or a stand-alone LDAP
+ server.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>bind_path_user</term>
+ <listitem><para>Specifies the bind path where
+ user objects can be found in the LDAP
+ server.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>bind_path_group</term>
+ <listitem><para>Specifies the bind path where
+ group objects can be found in the LDAP
+ server.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>user_cn = <yes | no></term>
+ <listitem><para>Query cn attribute instead of
+ uid attribute for the user name in LDAP. This
+ option is not required, the default is
+ no.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cn_realm = <yes | no></term>
+ <listitem><para>Append @realm to cn for groups
+ (and users if user_cn is set) in
+ LDAP. This option is not required, the default
+ is no.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ldap_domain</term>
+ <listitem><para>When using the LDAP server in
+ the Active Directory server, this allows to
+ specify the domain where to access the Active
+ Directory server. This allows using trust
+ relationships while keeping all RFC 2307
+ records in one place. This parameter is
+ optional, the default is to access the AD
+ server in the current domain to query LDAP
+ records.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ldap_url</term>
+ <listitem><para>When using a stand-alone LDAP
+ server, this parameter specifies the ldap URL
+ for accessing the LDAP
+ server.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ldap_user_dn</term>
+ <listitem><para>Defines the user DN to be used
+ for authentication. The secret for
+ authenticating this user should be stored with
+ net idmap secret (see
+ <citerefentry><refentrytitle>net</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry>). If
+ absent, an anonymous bind will be
+ performed.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ldap_realm</term>
+ <listitem><para>Defines the realm to use in
+ the user and group names. This is only
+ required when using cn_realm together with a
+ stand-alone ldap server.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>EXAMPLES</title>
+
+ <para>The following example shows how to retrieve id mappings
+ from a stand-alone LDAP server. This example also shows how
+ to leave a small non conflicting range for local id allocation
+ that may be used in internal backends like BUILTIN.</para>
+
+ <programlisting>
+ [global]
+ idmap config * : backend = tdb
+ idmap config * : range = 1000000-1999999
+
+ idmap config DOMAIN : backend = rfc2307
+ idmap config DOMAIN : range = 2000000-2999999
+ idmap config DOMAIN : ldap_server = stand-alone
+ idmap config DOMAIN : ldap_url = ldap://ldap1.example.com
+ idmap config DOMAIN : ldap_user_dn = cn=ldapmanager,dc=example,dc=com
+ idmap config DOMAIN : bind_path_user = ou=People,dc=example,dc=com
+ idmap config DOMAIN : bind_path_group = ou=Group,dc=example,dc=com
+ </programlisting>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>
+ The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.
+ </para>
+</refsect1>
+
+</refentry>
diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build
index 25e381e..0c6d4a4 100644
--- a/docs-xml/wscript_build
+++ b/docs-xml/wscript_build
@@ -12,6 +12,7 @@ manpages='''
manpages/idmap_hash.8
manpages/idmap_ldap.8
manpages/idmap_nss.8
+ manpages/idmap_rfc2307.8
manpages/idmap_rid.8
manpages/idmap_tdb.8
manpages/idmap_tdb2.8
--
1.7.1
>From aca7966413ed488bc5976ecec0d2e30e17e04697 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:33:13 -0700
Subject: [PATCH 08/11] s3-net: Allow setting the ldap password for idmap_rfc2307
---
source3/utils/net_idmap.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/source3/utils/net_idmap.c b/source3/utils/net_idmap.c
index bdc4879..fbeca3e 100644
--- a/source3/utils/net_idmap.c
+++ b/source3/utils/net_idmap.c
@@ -634,9 +634,11 @@ static int net_idmap_secret(struct net_context *c, int argc, const char **argv)
backend = talloc_strdup(ctx, lp_parm_const_string(-1, opt, "backend", "tdb"));
ALLOC_CHECK(backend);
- if ( ( ! backend) || ( ! strequal(backend, "ldap"))) {
+ if ((!backend) || (!strequal(backend, "ldap") &&
+ !strequal(backend, "rfc2307"))) {
d_fprintf(stderr,
- _("The only currently supported backend is LDAP\n"));
+ _("The only currently supported backend are LDAP "
+ "and rfc2307\n"));
talloc_free(ctx);
return -1;
}
--
1.7.1
>From 8b5505f458e426501fc7c86ce3c4bfaa082852ff Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:33:19 -0700
Subject: [PATCH 09/11] packaging(RHEL-CTDB): Add idmap_rfc2307 module
---
packaging/RHEL-CTDB/configure.rpm | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/packaging/RHEL-CTDB/configure.rpm b/packaging/RHEL-CTDB/configure.rpm
index f16b352..398a3f9 100755
--- a/packaging/RHEL-CTDB/configure.rpm
+++ b/packaging/RHEL-CTDB/configure.rpm
@@ -24,7 +24,7 @@ else
CC="gcc"
fi
-shared_modules="idmap_rid,idmap_ad,idmap_tdb2"
+shared_modules="idmap_rid,idmap_ad,idmap_tdb2,idmap_rfc2307"
if test "x$BUILD_GPFS" != "xno"; then
shared_modules="${shared_modules},vfs_gpfs,vfs_tsmsm"
--
1.7.1
>From b2b1f3825c6cbbad586a39b2f6497c9077c7dbc8 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:33:28 -0700
Subject: [PATCH 10/11] Add LD_LIBRARY_PATH to load idmap modules in testenv
---
selftest/wscript | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/selftest/wscript b/selftest/wscript
index c7637a1..d0b54d5 100644
--- a/selftest/wscript
+++ b/selftest/wscript
@@ -173,6 +173,9 @@ def cmd_testonly(opt):
ADD_LD_LIBRARY_PATH('bin/shared')
ADD_LD_LIBRARY_PATH('bin/shared/private')
+ # Allow loading of shared idmap modules
+ ADD_LD_LIBRARY_PATH('bin/modules/idmap')
+
# if we are using a system version of ldb then we need to tell it to
# load modules from our modules path
if env.USING_SYSTEM_LDB:
--
1.7.1
>From ba848c70139ab6a0a2bf406aa89cf79b3aaa689c Mon Sep 17 00:00:00 2001
From: Christof Schmitt <christof.schmitt at us.ibm.com>
Date: Thu, 21 Feb 2013 12:33:23 -0700
Subject: [PATCH 11/11] Add testcase for idmap_rfc2307 module
Create a new test environment with 'idmap config DOMAIN : backend =
rfc2307'. A new test script adds LDAP records and queries them again for
the mapped uid and gid.
---
nsswitch/tests/test_idmap_rfc2307.sh | 80 ++++++++++++++++++++++++++++++++++
selftest/target/Samba.pm | 1 +
selftest/target/Samba3.pm | 79 +++++++++++++++++++++++++++++++++
selftest/target/Samba4.pm | 6 +++
source3/selftest/tests.py | 6 ++-
5 files changed, 171 insertions(+), 1 deletions(-)
create mode 100755 nsswitch/tests/test_idmap_rfc2307.sh
diff --git a/nsswitch/tests/test_idmap_rfc2307.sh b/nsswitch/tests/test_idmap_rfc2307.sh
new file mode 100755
index 0000000..1bed10a
--- /dev/null
+++ b/nsswitch/tests/test_idmap_rfc2307.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Test id mapping through idmap_rfc2307 module
+if [ $# -lt 6 ]; then
+ echo Usage: $0 DOMAIN USERNAME UID GROUPNAME GID LDAPPREFIX
+ exit 1
+fi
+
+DOMAIN="$1"
+USERNAME="$2"
+USERUID="$3"
+GROUPNAME="$4"
+GROUPGID="$5"
+LDAPPREFIX="$6"
+
+echo called with: $1 $2 $3 $4 $5 $6
+
+wbinfo="$VALGRIND $BINDIR/wbinfo"
+ldbadd="$BINDIR/ldbadd"
+failed=0
+
+. `dirname $0`/../../testprogs/blackbox/subunit.sh
+
+# Add id mapping information
+
+cat > $PREFIX/tmpldb <<EOF
+dn: $LDAPPREFIX
+objectclass: organizationalUnit
+EOF
+
+testit "add ldap prefix" $VALGRIND $ldbadd -H ./st/dc/private/sam.ldb $PREFIX/tmpldb
+
+cat > $PREFIX/tmpldb <<EOF
+dn: cn=$USERNAME,$LDAPPREFIX
+objectClass: organizationalPerson
+objectClass: posixAccount
+ou: People
+cn: $USERNAME
+uid: $USERNAME
+uidNumber: $USERUID
+gidNumber: 1
+homeDirectory: /home/admin
+EOF
+
+testit "add ldap user mapping record" $VALGRIND $ldbadd -H ./st/dc/private/sam.ldb $PREFIX/tmpldb
+
+cat > $PREFIX/tmpldb <<EOF
+dn: cn=$GROUPNAME,$LDAPPREFIX
+objectClass: posixGroup
+objectClass: groupOfNames
+cn: $GROUPNAME
+gidNumber: $GROUPGID
+member: cn=$USERNAME,$LDAPPREFIX
+EOF
+
+testit "add ldap group mapping record" $VALGRIND $ldbadd -H ./st/dc/private/sam.ldb $PREFIX/tmpldb
+
+rm -f $PREFIX/tmpldbmodify
+
+testit "wbinfo --name-to-sid" $wbinfo --name-to-sid "$DOMAIN\\$USERNAME" || failed=$(expr $failed + 1)
+user_sid=$($wbinfo -n "$DOMAIN\\$USERNAME" | cut -d " " -f1)
+echo "$DOMAIN\\$USERNAME resolved to $user_sid"
+
+testit "wbinfo --sid-to-uid=$user_sid" $wbinfo --sid-to-uid=$user_sid || failed=$(expr $failed + 1)
+user_uid=$($wbinfo --sid-to-uid=$user_sid | cut -d " " -f1)
+echo "$DOMAIN\\$USERNAME resolved to $user_uid"
+
+testit "test $user_uid -eq $USERUID" test $user_uid -eq $USERUID || failed=$(expr $failed + 1)
+
+# Not sure how to get group names with spaces to resolve through testit
+#testit "wbinfo --name-to-sid" $wbinfo --name-to-sid="$DOMAIN\\$GROUPNAME" || failed=$(expr $failed + 1)
+group_sid=$($wbinfo --name-to-sid="$DOMAIN\\$GROUPNAME" | cut -d " " -f1)
+echo "$DOMAIN\\$GROUPNAME resolved to $group_sid"
+
+testit "wbinfo --sid-to-gid=$group_sid" $wbinfo --sid-to-gid=$group_sid || failed=$(expr $failed + 1)
+group_gid=$($wbinfo --sid-to-gid=$group_sid | cut -d " " -f1)
+echo "$DOMAIN\\$GROUPNAME resolved to $group_gid"
+
+testit "test $group_gid -eq $GROUPGID" test $group_gid -eq $GROUPGID || failed=$(expr $failed + 1)
+
+exit $failed
diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm
index d811053..fc81629 100644
--- a/selftest/target/Samba.pm
+++ b/selftest/target/Samba.pm
@@ -171,6 +171,7 @@ sub get_interface($)
$interfaces{"localsubdc"} = 31;
$interfaces{"chgdcpass"} = 32;
$interfaces{"promotedvdc"} = 33;
+ $interfaces{"s3member_rfc2307"} = 34;
# update lib/socket_wrapper/socket_wrapper.c
# #define MAX_WRAPPED_INTERFACES 32
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index c71419d..31a6f0c 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -331,6 +331,85 @@ sub setup_admember($$$$)
return $ret;
}
+sub setup_admember_rfc2307($$$$)
+{
+ my ($self, $prefix, $dcvars) = @_;
+
+ # If we didn't build with ADS, pretend this env was never available
+ if (not $self->have_ads()) {
+ return "UNKNOWN";
+ }
+
+ print "PROVISIONING S3 AD MEMBER...";
+
+ my $member_options = "
+ security = ads
+ server signing = on
+ workgroup = $dcvars->{DOMAIN}
+ realm = $dcvars->{REALM}
+ idmap config $dcvars->{DOMAIN} : backend = rfc2307
+ idmap config $dcvars->{DOMAIN} : range = 2000000-2999999
+ idmap config $dcvars->{DOMAIN} : ldap_server = ad
+ idmap config $dcvars->{DOMAIN} : bind_path_user = ou=idmap,dc=samba,dc=example,dc=com
+ idmap config $dcvars->{DOMAIN} : bind_path_group = ou=idmap,dc=samba,dc=example,dc=com
+";
+
+ my $ret = $self->provision($prefix,
+ "LOCALADMEMBER",
+ "loCalMemberPass",
+ $member_options);
+
+ $ret or return undef;
+
+ close(USERMAP);
+ $ret->{DOMAIN} = $dcvars->{DOMAIN};
+ $ret->{REALM} = $dcvars->{REALM};
+
+ my $ctx;
+ my $prefix_abs = abs_path($prefix);
+ $ctx = {};
+ $ctx->{krb5_conf} = "$prefix_abs/lib/krb5.conf";
+ $ctx->{domain} = $dcvars->{DOMAIN};
+ $ctx->{realm} = $dcvars->{REALM};
+ $ctx->{dnsname} = lc($dcvars->{REALM});
+ $ctx->{kdc_ipv4} = $dcvars->{SERVER_IP};
+ Samba::mk_krb5_conf($ctx, "");
+
+ $ret->{KRB5_CONFIG} = $ctx->{krb5_conf};
+
+ my $net = Samba::bindir_path($self, "net");
+ my $cmd = "";
+ $cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$ret->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
+ $cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
+ $cmd .= "$net join $ret->{CONFIGURATION}";
+ $cmd .= " -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}";
+
+ if (system($cmd) != 0) {
+ warn("Join failed\n$cmd");
+ return undef;
+ }
+
+ # We need world access to this share, as otherwise the domain
+ # administrator from the AD domain provided by Samba4 can't
+ # access the share for tests.
+ chmod 0777, "$prefix/share";
+
+ if (not $self->check_or_start($ret, "yes", "yes", "yes")) {
+ return undef;
+ }
+
+ $ret->{DC_SERVER} = $dcvars->{SERVER};
+ $ret->{DC_SERVER_IP} = $dcvars->{SERVER_IP};
+ $ret->{DC_NETBIOSNAME} = $dcvars->{NETBIOSNAME};
+ $ret->{DC_USERNAME} = $dcvars->{USERNAME};
+ $ret->{DC_PASSWORD} = $dcvars->{PASSWORD};
+
+ # Special case, this is called from Samba4.pm but needs to use the Samba3 check_env and get_log_env
+ $ret->{target} = $self;
+
+ return $ret;
+}
+
sub setup_simpleserver($$)
{
my ($self, $path) = @_;
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index e9e0037..090be04 100644
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -1661,6 +1661,12 @@ sub setup_env($$$)
return $target3->setup_admember("$path/s3member", $self->{vars}->{dc}, 29);
} elsif ($envname eq "plugin_s4_dc") {
return $self->setup_plugin_s4_dc("$path/plugin_s4_dc");
+ } elsif ($envname eq "s3member_rfc2307") {
+ if (not defined($self->{vars}->{dc})) {
+ $self->setup_dc("$path/dc");
+ }
+ return $target3->setup_admember_rfc2307("$path/s3member",
+ $self->{vars}->{dc}, 34);
} else {
return "UNKNOWN";
}
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 44efe18..a3fa352 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -278,6 +278,8 @@ local = ["local.nss-wrapper", "local.ndr"]
winbind = ["winbind.struct", "winbind.wbclient", "winbind.pac"]
+idmap = [ "idmap.rfc2307" ]
+
rap = ["rap.basic", "rap.rpc", "rap.printing", "rap.sam"]
unix = ["unix.info2", "unix.whoami"]
@@ -286,7 +288,7 @@ nbt = ["nbt.dgram" ]
libsmbclient = ["libsmbclient"]
-tests= base + raw + smb2 + rpc + unix + local + winbind + rap + nbt + libsmbclient
+tests= base + raw + smb2 + rpc + unix + local + winbind + rap + nbt + libsmbclient + idmap
for t in tests:
if t == "base.delaywrite":
@@ -338,6 +340,8 @@ for t in tests:
plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/valid-users-tmp -U$USERNAME%$PASSWORD')
plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/write-list-tmp -U$USERNAME%$PASSWORD')
plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
+ elif t == "idmap.rfc2307":
+ plantestsuite(t, "s3member_rfc2307", [os.path.join(samba3srcdir, "../nsswitch/tests/test_idmap_rfc2307.sh"), '$DOMAIN', 'Administrator', '2000000', '"Domain Users"', '2000001', 'ou=idmap,dc=samba,dc=example,dc=com'])
else:
plansmbtorture4testsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
plansmbtorture4testsuite(t, "plugin_s4_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD')
--
1.7.1
More information about the samba-technical
mailing list