summaryrefslogtreecommitdiffstats
path: root/source/sam/idmap_ldap.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/sam/idmap_ldap.c')
-rw-r--r--source/sam/idmap_ldap.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/source/sam/idmap_ldap.c b/source/sam/idmap_ldap.c
new file mode 100644
index 00000000000..2124fb68793
--- /dev/null
+++ b/source/sam/idmap_ldap.c
@@ -0,0 +1,790 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ idmap LDAP backend
+
+ Copyright (C) Tim Potter 2000
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Gerald Carter 2003
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
+
+
+#include <lber.h>
+#include <ldap.h>
+
+#include "smbldap.h"
+
+struct ldap_idmap_state {
+ struct smbldap_state *smbldap_state;
+ TALLOC_CTX *mem_ctx;
+};
+
+static struct ldap_idmap_state ldap_state;
+
+/* number tries while allocating new id */
+#define LDAP_MAX_ALLOC_ID 128
+
+
+/***********************************************************************
+ This function cannot be called to modify a mapping, only set a new one
+***********************************************************************/
+
+static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
+{
+ pstring dn;
+ pstring id_str;
+ fstring type;
+ LDAPMod **mods = NULL;
+ int rc = -1;
+ int ldap_op;
+ fstring sid_string;
+ LDAPMessage *entry = NULL;
+
+ sid_to_string( sid_string, sid );
+
+ ldap_op = LDAP_MOD_ADD;
+ pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
+ sid_string, lp_ldap_idmap_suffix());
+
+ if ( id_type & ID_USERID )
+ fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
+ else
+ fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
+
+ pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
+ (unsigned long)id.gid));
+
+ smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
+
+ smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
+ entry, &mods, type, id_str );
+
+ smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
+ entry, &mods,
+ get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
+ sid_string );
+
+ /* There may well be nothing at all to do */
+
+ if (mods) {
+ smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
+ rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
+ ldap_mods_free( mods, True );
+ } else {
+ rc = LDAP_SUCCESS;
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+ &ld_error);
+ DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
+ (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
+ sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
+ DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
+ ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
+ sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
+ (unsigned long)id.gid), type));
+
+ return NT_STATUS_OK;
+}
+
+/**********************************************************************
+ Even if the sambaDomain attribute in LDAP tells us that this RID is
+ safe to use, always check before use.
+*********************************************************************/
+
+static BOOL sid_in_use(struct ldap_idmap_state *state,
+ const DOM_SID *sid, int *error)
+{
+ fstring filter;
+ fstring sid_string;
+ LDAPMessage *result = NULL;
+ int count;
+ int rc;
+ char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
+
+ slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
+
+ rc = smbldap_search_suffix(state->smbldap_state,
+ filter, sid_attr, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
+ sid_string, ld_error));
+ SAFE_FREE(ld_error);
+
+ *error = rc;
+ return True;
+ }
+
+ if ((count = ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
+ DEBUG(3, ("Sid %s already in use - trying next RID\n",
+ sid_string));
+ ldap_msgfree(result);
+ return True;
+ }
+
+ ldap_msgfree(result);
+
+ /* good, sid is not in use */
+ return False;
+}
+
+/**********************************************************************
+ Set the new nextRid attribute, and return one we can use.
+
+ This also checks that this RID is actually free - in case the admin
+ manually stole it :-).
+*********************************************************************/
+
+static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid,
+ int rid_type)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ int rc;
+ LDAPMessage *domain_result = NULL;
+ LDAPMessage *entry = NULL;
+ char *dn;
+ LDAPMod **mods = NULL;
+ fstring old_rid_string;
+ fstring next_rid_string;
+ fstring algorithmic_rid_base_string;
+ uint32 next_rid;
+ uint32 alg_rid_base;
+ int attempts = 0;
+ char *ld_error = NULL;
+
+ while (attempts < 10) {
+ if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state,
+ &domain_result, get_global_sam_name(), True))) {
+ return ret;
+ }
+
+ entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
+ if (!entry) {
+ DEBUG(0, ("Could not get domain info entry\n"));
+ ldap_msgfree(domain_result);
+ return ret;
+ }
+
+ if ((dn = smbldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
+ DEBUG(0, ("Could not get domain info DN\n"));
+ ldap_msgfree(domain_result);
+ return ret;
+ }
+
+ /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and
+ algorithmic_rid_base. The other two are to avoid stomping on the
+ different sets of algorithmic RIDs */
+
+ if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
+ algorithmic_rid_base_string)) {
+
+ alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
+ } else {
+ alg_rid_base = algorithmic_rid_base();
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
+ algorithmic_rid_base_string);
+ }
+
+ next_rid = 0;
+
+ if (alg_rid_base > BASE_RID) {
+ /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we
+ can allocate to new users */
+ if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
+ old_rid_string)) {
+ *rid = (uint32)atol(old_rid_string);
+ } else {
+ *rid = BASE_RID;
+ }
+
+ next_rid = *rid+1;
+ if (next_rid >= alg_rid_base) {
+ ldap_msgfree(domain_result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
+
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
+ next_rid_string);
+ }
+
+ if (!next_rid) { /* not got one already */
+ switch (rid_type) {
+ case USER_RID_TYPE:
+ if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
+ old_rid_string)) {
+ *rid = (uint32)atol(old_rid_string);
+ }
+ break;
+ case GROUP_RID_TYPE:
+ if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
+ old_rid_string)) {
+ *rid = (uint32)atol(old_rid_string);
+ }
+ break;
+ }
+
+ /* This is the core of the whole routine. If we had
+ scheme-style closures, there would be a *lot* less code
+ duplication... */
+
+ next_rid = *rid+RID_MULTIPLIER;
+ slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
+
+ switch (rid_type) {
+ case USER_RID_TYPE:
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
+ next_rid_string);
+ break;
+
+ case GROUP_RID_TYPE:
+ /* Try to make the modification atomically by enforcing the
+ old value in the delete mod. */
+ smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
+ next_rid_string);
+ break;
+ }
+ }
+
+ if ((rc = smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) {
+ DOM_SID dom_sid;
+ DOM_SID sid;
+ pstring domain_sid_string;
+ int error = 0;
+
+ if (!smbldap_get_single_pstring(state->smbldap_state->ldap_struct, domain_result,
+ get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
+ domain_sid_string)) {
+ ldap_mods_free(mods, True);
+ SAFE_FREE(dn);
+ ldap_msgfree(domain_result);
+ return ret;
+ }
+
+ if (!string_to_sid(&dom_sid, domain_sid_string)) {
+ ldap_mods_free(mods, True);
+ SAFE_FREE(dn);
+ ldap_msgfree(domain_result);
+ return ret;
+ }
+
+ ldap_mods_free(mods, True);
+ mods = NULL;
+ SAFE_FREE(dn);
+ ldap_msgfree(domain_result);
+
+ sid_copy(&sid, &dom_sid);
+ sid_append_rid(&sid, *rid);
+
+ /* check RID is not in use */
+ if (sid_in_use(state, &sid, &error)) {
+ if (error) {
+ return ret;
+ }
+ continue;
+ }
+
+ return NT_STATUS_OK;
+ }
+
+ ld_error = NULL;
+ ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
+ DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
+ SAFE_FREE(ld_error);
+
+ ldap_mods_free(mods, True);
+ mods = NULL;
+
+ SAFE_FREE(dn);
+
+ ldap_msgfree(domain_result);
+ domain_result = NULL;
+
+ {
+ /* Sleep for a random timeout */
+ unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
+ attempts += 1;
+
+ sleeptime %= 100;
+ smb_msleep(sleeptime);
+ }
+ }
+
+ DEBUG(0, ("Failed to set new RID\n"));
+ return ret;
+}
+
+
+/*****************************************************************************
+ Allocate a new RID
+*****************************************************************************/
+
+static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
+{
+ return ldap_next_rid( &ldap_state, rid, rid_type );
+}
+
+/*****************************************************************************
+ Allocate a new uid or gid
+*****************************************************************************/
+
+static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ int rc = LDAP_SERVER_DOWN;
+ int count = 0;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ pstring id_str, new_id_str;
+ LDAPMod **mods = NULL;
+ const char *type;
+ char *dn = NULL;
+ char **attr_list;
+ pstring filter;
+ uid_t luid, huid;
+ gid_t lgid, hgid;
+
+
+ type = (id_type & ID_USERID) ?
+ get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
+ get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+
+ pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
+
+ attr_list = get_attr_list( idpool_attr_list );
+
+ rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter,
+ attr_list, 0, &result);
+ free_attr_list( attr_list );
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
+ goto out;
+ }
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+ if (count != 1) {
+ DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
+ goto out;
+ }
+
+ dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+ if (!dn) {
+ goto out;
+ }
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
+
+ if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
+ DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
+ type));
+ goto out;
+ }
+
+ /* this must succeed or else we wouldn't have initialized */
+
+ lp_idmap_uid( &luid, &huid);
+ lp_idmap_gid( &lgid, &hgid);
+
+ /* make sure we still have room to grow */
+
+ if (id_type & ID_USERID) {
+ id->uid = strtoul(id_str, NULL, 10);
+ if (id->uid > huid ) {
+ DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
+ (unsigned long)huid));
+ goto out;
+ }
+ }
+ else {
+ id->gid = strtoul(id_str, NULL, 10);
+ if (id->gid > hgid ) {
+ DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
+ (unsigned long)hgid));
+ goto out;
+ }
+ }
+
+ pstr_sprintf(new_id_str, "%lu",
+ ((id_type & ID_USERID) ? (unsigned long)id->uid :
+ (unsigned long)id->gid) + 1);
+
+ smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
+ smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
+
+ if (mods == NULL) {
+ DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
+ goto out;
+ }
+
+ rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
+
+ ldap_mods_free( mods, True );
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(0,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
+ type));
+ goto out;
+ }
+
+ ret = NT_STATUS_OK;
+out:
+ SAFE_FREE(dn);
+ if (result != NULL)
+ ldap_msgfree(result);
+
+ return ret;
+}
+
+/*****************************************************************************
+ get a sid from an id
+*****************************************************************************/
+
+static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
+{
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ pstring sid_str;
+ pstring filter;
+ pstring suffix;
+ const char *type;
+ int rc;
+ int count;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+ char **attr_list;
+
+ if ( id_type & ID_USERID )
+ type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
+ else
+ type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+
+ pstrcpy( suffix, lp_ldap_idmap_suffix() );
+ pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
+ LDAP_OBJ_IDMAP_ENTRY, type,
+ ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
+
+ attr_list = get_attr_list( sidmap_attr_list );
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
+ ldap_err2string(rc) ));
+ goto out;
+ }
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ if (count != 1) {
+ DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
+ type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
+ (unsigned long)id.gid)));
+ goto out;
+ }
+
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
+
+ if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
+ goto out;
+
+ if (!string_to_sid(sid, sid_str))
+ goto out;
+
+ ret = NT_STATUS_OK;
+out:
+ free_attr_list( attr_list );
+
+ if (result)
+ ldap_msgfree(result);
+
+ return ret;
+}
+
+/***********************************************************************
+ Get an id from a sid
+***********************************************************************/
+
+static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
+{
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ pstring sid_str;
+ pstring filter;
+ pstring id_str;
+ const char *suffix;
+ const char *type;
+ int rc;
+ int count;
+ char **attr_list;
+ char *dn = NULL;
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ sid_to_string(sid_str, sid);
+
+ DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
+ (*id_type & ID_GROUPID ? "group" : "user") ));
+
+ suffix = lp_ldap_idmap_suffix();
+ pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
+ LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
+
+ if ( *id_type & ID_GROUPID )
+ type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
+ else
+ type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
+
+ /* do the search and check for errors */
+
+ attr_list = get_attr_list( sidmap_attr_list );
+ rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
+ filter, attr_list, 0, &result);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
+ ldap_err2string(rc) ));
+ goto out;
+ }
+
+ /* check for the number of entries returned */
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ if ( count > 1 ) {
+ DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
+ filter, count));
+ goto out;
+ }
+
+ /* try to allocate a new id if we still haven't found one */
+
+ if ( !count ) {
+ int i;
+
+ if (*id_type & ID_QUERY_ONLY) {
+ DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
+ goto out;
+ }
+
+ DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
+
+ for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
+ ret = ldap_allocate_id(id, *id_type);
+ if ( NT_STATUS_IS_OK(ret) )
+ break;
+ }
+
+ if ( !NT_STATUS_IS_OK(ret) ) {
+ DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
+ goto out;
+ }
+
+ DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
+ (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
+
+ ret = ldap_set_mapping(sid, *id, *id_type);
+
+ /* all done */
+
+ goto out;
+ }
+
+ DEBUG(10,("ldap_get_id_from_sid: success\n"));
+
+ entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
+
+ dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+ if (!dn)
+ goto out;
+
+ DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
+
+ if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
+ if ( (*id_type & ID_USERID) )
+ id->uid = strtoul(id_str, NULL, 10);
+ else
+ id->gid = strtoul(id_str, NULL, 10);
+
+ ret = NT_STATUS_OK;
+ goto out;
+ }
+
+out:
+ free_attr_list( attr_list );
+ if (result)
+ ldap_msgfree(result);
+ SAFE_FREE(dn);
+
+ return ret;
+}
+
+/**********************************************************************
+ Verify the sambaUnixIdPool entry in the directiry.
+**********************************************************************/
+
+static NTSTATUS verify_idpool( void )
+{
+ fstring filter;
+ int rc;
+ char **attr_list;
+ LDAPMessage *result = NULL;
+ LDAPMod **mods = NULL;
+ int count;
+
+ fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
+
+ attr_list = get_attr_list( idpool_attr_list );
+ rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
+ free_attr_list ( attr_list );
+
+ if (rc != LDAP_SUCCESS)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+
+ ldap_msgfree(result);
+
+ if ( count > 1 ) {
+ DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
+ filter, lp_ldap_idmap_suffix() ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ else if (count == 0) {
+ uid_t luid, huid;
+ gid_t lgid, hgid;
+ fstring uid_str, gid_str;
+
+ if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
+ DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
+ fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
+
+ smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
+ smbldap_set_mod( &mods, LDAP_MOD_ADD,
+ get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
+
+ rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
+ }
+
+ return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
+}
+
+/*****************************************************************************
+ Initialise idmap database.
+*****************************************************************************/
+
+static NTSTATUS ldap_idmap_init( char *params )
+{
+ NTSTATUS nt_status;
+
+ ldap_state.mem_ctx = talloc_init("idmap_ldap");
+ if (!ldap_state.mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* assume location is the only parameter */
+ if (!NT_STATUS_IS_OK(nt_status =
+ smbldap_init(ldap_state.mem_ctx, params,
+ &ldap_state.smbldap_state))) {
+ talloc_destroy(ldap_state.mem_ctx);
+ return nt_status;
+ }
+
+ /* see if the idmap suffix and sub entries exists */
+
+ nt_status = verify_idpool();
+ if ( !NT_STATUS_IS_OK(nt_status) )
+ return nt_status;
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************************
+ End the LDAP session
+*****************************************************************************/
+
+static NTSTATUS ldap_idmap_close(void)
+{
+
+ smbldap_free_struct(&(ldap_state).smbldap_state);
+ talloc_destroy(ldap_state.mem_ctx);
+
+ DEBUG(5,("The connection to the LDAP server was closed\n"));
+ /* maybe free the results here --metze */
+
+ return NT_STATUS_OK;
+}
+
+
+/* This function doesn't make as much sense in an LDAP world since the calling
+ node doesn't really control the ID ranges */
+static void ldap_idmap_status(void)
+{
+ DEBUG(0, ("LDAP IDMAP Status not available\n"));
+}
+
+static struct idmap_methods ldap_methods = {
+ ldap_idmap_init,
+ ldap_allocate_rid,
+ ldap_allocate_id,
+ ldap_get_sid_from_id,
+ ldap_get_id_from_sid,
+ ldap_set_mapping,
+ ldap_idmap_close,
+ ldap_idmap_status
+
+};
+
+NTSTATUS idmap_ldap_init(void)
+{
+ return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
+}