This patch cleans up some of our ldap code, for better behaviour:
authorAndrew Bartlett <abartlet@samba.org>
Fri, 4 Jul 2003 13:29:42 +0000 (13:29 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 4 Jul 2003 13:29:42 +0000 (13:29 +0000)
We now always read the Domain SID out of LDAP.  If the local secrets.tdb
is ever different to LDAP, it is overwritten out of LDAP.   We also
store the 'algorithmic rid base' into LDAP, and assert if it changes.
(This ensures cross-host synchronisation, and allows for possible
integration with idmap).  If we fail to read/add the domain entry, we just
fallback to the old behaviour.

We always use an existing DN when adding IDMAP entries to LDAP, unless
no suitable entry is available.  This means that a user's posixAccount
will have a SID added to it, or a user's sambaSamAccount will have a UID
added.  Where we cannot us an existing DN, we use
'sambaSid=S-x-y-z,....' as the DN.

The code now allows modifications to the ID mapping in many cases.

Likewise, we now check more carefully when adding new user entires to LDAP,
to not duplicate SIDs (for users, at this stage), and to add the sambaSamAccount
onto the idmap entry for that user, if it is already established (ensuring
we do not duplicate sambaSid entries in the directory).

The allocated UID code has been expanded to take into account the space
between '1000 - algorithmic rid base'.  This much better fits into what
an NT4 does - allocating in the bottom part of the RID range.

On the code cleanup side of things, we now share as much code as
possible between idmap_ldap and pdb_ldap.

We also no longer use the race-prone 'enumerate all users' method for
finding the next RID to allocate.  Instead, we just start at the bottom
of the range, and increment again if the user already exists.  The first
time this is run, it may well take a long time, but next time will just
be able to use the next Rid.

Thanks to metze and AB for double-checking parts of this.

Andrew Bartlett
(This used to be commit 9c595c8c2327b92a86901d84c3f2c284dabd597e)

examples/LDAP/samba.schema
source3/include/smbldap.h
source3/lib/smbldap.c
source3/passdb/passdb.c
source3/passdb/pdb_ldap.c
source3/sam/idmap_ldap.c
source3/sam/idmap_util.c
source3/smbd/server.c
source3/utils/pdbedit.c

index 067f5a497dca7cf0fbb2f1132050270a101d0139..6e8387f16e734420481882ca68a484f4ad2a3b4b 100644 (file)
@@ -276,6 +276,16 @@ attributetype ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid'
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
+attributetype ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid'
+       DESC 'Next NT rid to give out for anything'
+       EQUALITY integerMatch
+       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase'
+       DESC 'Base at which the samba RID generation algorithm should operate'
+       EQUALITY integerMatch
+       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
 
 #######################################################################
 ##              objectClasses used by Samba 3.0 schema               ##
@@ -312,16 +322,23 @@ objectclass ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY
 ##
 objectclass ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL
        DESC 'Samba Domain Information'
-       MUST ( sambaDomainName $ sambaNextGroupRid $ sambaNextUserRid $
-              sambaSID ) )
+       MUST ( sambaDomainName $ 
+              sambaSID ) 
+       MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $
+             sambaAlgorithmicRidBase ) )
 
 ## used for idmap_ldap module
 objectclass ( 1.3.6.1.4.1.7165.1.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY
         DESC 'Pool for allocating UNIX uids/gids'
         MUST ( uidNumber $ gidNumber ) )
 
-objectclass ( 1.3.6.1.4.1.7165.1.2.2.8 NAME 'sambaIdmapEntry' SUP top STRUCTURAL
+
+objectclass ( 1.3.6.1.4.1.7165.1.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY
         DESC 'Mapping from a SID to an ID'
         MUST ( sambaSID )
-       MAY ( uidNumber $ gidNumber ))
+       MAY ( uidNumber $ gidNumber ) )
+
+objectclass ( 1.3.6.1.4.1.7165.1.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL
+        DESC 'Structural Class for a SID'
+        MUST ( sambaSID ) )
 
index 5f3606aa32c649062defdacd50d2f5edb8a98eb8..589d01aa6dd592f76149cea731912c7a216fe3f6 100644 (file)
@@ -37,6 +37,7 @@
 #define LDAP_OBJ_DOMINFO               "sambaDomain"
 #define LDAP_OBJ_IDPOOL                        "sambaUnixIdPool"
 #define LDAP_OBJ_IDMAP_ENTRY           "sambaIdmapEntry"
+#define LDAP_OBJ_SID_ENTRY             "sambaSidEntry"
 
 #define LDAP_OBJ_ACCOUNT               "account"
 #define LDAP_OBJ_POSIXACCOUNT          "posixAccount"
@@ -85,7 +86,8 @@
 #define LDAP_ATTR_GROUP_SID            30
 #define LDAP_ATTR_GROUP_TYPE           31
 #define LDAP_ATTR_SID                  32
-
+#define LDAP_ATTR_ALGORITHMIC_RID_BASE  33
+#define LDAP_ATTR_NEXT_RID              34
 
 typedef struct _attrib_map_entry {
        int             attrib;
@@ -113,6 +115,8 @@ void smbldap_set_mod (LDAPMod *** modlist, int modop, const char *attribute, con
 void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing,
                      LDAPMod ***mods,
                      const char *attribute, const char *newval);
+BOOL smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+                                  const char *attribute, pstring value);
 
 /**
  * Struct to keep the state for all the ldap stuff 
index 84017873177311606d757257f840f97fc4f24bdd..f65860d1b8f7e783d61e05b0e3f206f49d024c26 100644 (file)
@@ -102,9 +102,11 @@ ATTRIB_MAP_ENTRY attrib_map_v30[] = {
 
 ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
        { LDAP_ATTR_DOMAIN,             "sambaDomainName"       },
+       { LDAP_ATTR_NEXT_RID,           "sambaNextRid"          },
        { LDAP_ATTR_NEXT_USERRID,       "sambaNextUserRid"      },
        { LDAP_ATTR_NEXT_GROUPRID,      "sambaNextGroupRid"     },
        { LDAP_ATTR_DOM_SID,            LDAP_ATTRIBUTE_SID      },
+       { LDAP_ATTR_ALGORITHMIC_RID_BASE,"sambaAlgorithmicRidBase"},
        { LDAP_ATTR_LIST_END,           NULL                    },
 };
 
@@ -271,6 +273,40 @@ BOOL fetch_ldap_pw(char **dn, char** pw)
        return True;
 }
 
+/*******************************************************************
+search an attribute and return the first value found.
+******************************************************************/
+ BOOL smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
+                                  const char *attribute, pstring value)
+{
+       char **values;
+       
+       if ( !attribute )
+               return False;
+               
+       value[0] = '\0';
+
+       if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
+               DEBUG (10, ("smbldap_get_single_attribute: [%s] = [<does not exist>]\n", attribute));
+               
+               return False;
+       }
+       
+       if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, sizeof(pstring)) == (size_t)-1)
+       {
+               DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n", 
+                         attribute, values[0]));
+               ldap_value_free(values);
+               return False;
+       }
+       
+       ldap_value_free(values);
+#ifdef DEBUG_PASSWORDS
+       DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n", attribute, value));
+#endif 
+       return True;
+}
+
 /************************************************************************
  Routine to manage the LDAPMod structure array
  manage memory used by the array, by each struct, and values
@@ -819,7 +855,7 @@ static NTSTATUS smbldap_close(struct smbldap_state *ldap_state)
        return NT_STATUS_OK;
 }
 
-static int smbldap_retry_open(struct smbldap_state *ldap_state, int *attempts)
+int smbldap_retry_open(struct smbldap_state *ldap_state, int *attempts)
 {
        int rc;
 
index ece4a1e057a1cb0bc340d9a9c619aeac072c2592..54a852601a4bd7786c09cc8d9c6042941e5521d2 100644 (file)
@@ -581,7 +581,7 @@ BOOL pdb_gethexpwd(const char *p, unsigned char *pwd)
        return (True);
 }
 
-static int algorithmic_rid_base(void)
+int algorithmic_rid_base(void)
 {
        static int rid_offset = 0;
 
index ec164a7e7be4f8ce411c85e44ef4d0bf248ab9af..6911cea369f01e885c9ff3429b7f0340d2c9e9db 100644 (file)
@@ -216,8 +216,6 @@ static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state,
        pstring filter;
        int rc;
 
-       /* check if the user rid exists, if not, try searching on the uid */
-
        snprintf(filter, sizeof(filter)-1, "(&(rid=%i)%s)", rid, 
                get_objclass_filter(ldap_state->schema_ver));
        
@@ -237,8 +235,6 @@ static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state,
        int rc;
        fstring sid_string;
 
-       /* check if the user rid exsists, if not, try searching on the uid */
-
        snprintf(filter, sizeof(filter)-1, "(&(%s=%s)%s)", 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
                sid_to_string(sid_string, sid), 
@@ -249,40 +245,6 @@ static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state,
        return rc;
 }
 
-/*******************************************************************
-search an attribute and return the first value found.
-******************************************************************/
-static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
-                                 const char *attribute, pstring value)
-{
-       char **values;
-       
-       if ( !attribute )
-               return False;
-               
-       value[0] = '\0';
-
-       if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
-               DEBUG (10, ("get_single_attribute: [%s] = [<does not exist>]\n", attribute));
-               
-               return False;
-       }
-       
-       if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, sizeof(pstring)) == (size_t)-1)
-       {
-               DEBUG(1, ("get_single_attribute: string conversion of [%s] = [%s] failed!\n", 
-                         attribute, values[0]));
-               ldap_value_free(values);
-               return False;
-       }
-       
-       ldap_value_free(values);
-#ifdef DEBUG_PASSWORDS
-       DEBUG (100, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
-#endif 
-       return True;
-}
-
 /*******************************************************************
  Delete complete object or objectclass and attrs from
  object found in search_result depending on lp_ldap_delete_dn
@@ -367,167 +329,6 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
        return NT_STATUS_OK;
 }
                                          
-/**********************************************************************
-Search for the domain info entry
-*********************************************************************/
-static int ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
-                                     LDAPMessage ** result)
-{
-       pstring filter;
-       int rc;
-       char **attr_list;
-
-       snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
-               LDAP_OBJ_DOMINFO,
-               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
-               ldap_state->domain_name);
-
-       DEBUG(2, ("Searching for:[%s]\n", filter));
-
-
-       attr_list = get_attr_list( dominfo_attr_list );
-       rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, 
-                                  attr_list , result);
-       free_attr_list( attr_list );
-
-       if (rc != LDAP_SUCCESS) {
-               DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
-               DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
-       }
-       
-       return rc;
-}
-
-/**********************************************************************
- If this entry is is the 'allocated' range, extract the RID and return 
- it, so we can find the 'next' rid to allocate.
-
- Do this, no matter what type of object holds the RID - be it a user,
- group or somthing else.
-*********************************************************************/
-static uint32 entry_to_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry, int rid_type) 
-{
-       pstring sid_string;
-       DOM_SID dom_sid;
-       uint32 rid;
-
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
-               LDAP_ATTRIBUTE_SID, sid_string)) 
-       {
-               return 0;
-       }
-       
-       if (!string_to_sid(&dom_sid, sid_string)) {
-               return 0;
-       }
-
-       if (!sid_peek_check_rid(&dom_sid, get_global_sam_sid(), &rid)) {
-               /* not our domain, so we don't care */
-               return 0;
-       }
-
-       switch (rid_type) {
-       case USER_RID_TYPE:
-               if (rid >= ldap_state->low_allocated_user_rid && 
-                   rid <= ldap_state->high_allocated_user_rid) {
-                       return rid;
-               }
-               break;
-       case GROUP_RID_TYPE:
-               if (rid >= ldap_state->low_allocated_group_rid && 
-                   rid <= ldap_state->high_allocated_group_rid) {
-                       return rid;
-               }
-               break;
-       }
-       return 0;
-}
-
-
-/**********************************************************************
-Connect to LDAP server and find the next available 'allocated' RID.
-
-The search is done 'per type' as we allocate seperate pools for the
-EVEN and ODD (user and group) RIDs.  
-
-This is only done once, so that we can fill out the sambaDomain.
-*********************************************************************/
-static uint32 search_next_allocated_rid(struct ldapsam_privates *ldap_state, int rid_type)
-{
-       int rc;
-       LDAPMessage *result;
-       LDAPMessage *entry;
-       uint32 top_rid = 0;
-       uint32 next_rid;
-       uint32 count;
-       uint32 rid;
-       char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
-       fstring filter;
-       
-       snprintf( filter, sizeof(filter)-1, "(%s=*)", LDAP_ATTRIBUTE_SID );
-
-       DEBUG(2, ("search_top_allocated_rid: searching for:[%s]\n", filter));
-
-       rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, 
-                                  sid_attr, &result);
-
-       if (rc != LDAP_SUCCESS) {
-               DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
-               DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
-
-               result = NULL;
-               return 0;
-       }
-       
-       count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
-       DEBUG(2, ("search_top_allocated_rid: %d entries in the base!\n", count));
-       
-       if (count == 0) {
-               DEBUG(3, ("LDAP search returned no records, assuming no allocated RIDs present!: %s\n", ldap_err2string(rc)));
-               DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
-       } else {
-               entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,result);
-               
-               top_rid = entry_to_rid(ldap_state, entry, rid_type);
-               
-               while ((entry = ldap_next_entry(ldap_state->smbldap_state->ldap_struct, entry))) {
-                       
-                       rid = entry_to_rid(ldap_state, entry, rid_type);
-                       if (((rid & ~RID_TYPE_MASK) == rid_type) && (rid > top_rid)) {
-                               top_rid = rid;
-                       }
-               }
-       }
-
-       switch (rid_type) {
-       case USER_RID_TYPE:
-               if (top_rid < ldap_state->low_allocated_user_rid) {
-                       return ldap_state->low_allocated_user_rid;
-               }
-               break;
-       case GROUP_RID_TYPE:
-               if (top_rid < ldap_state->low_allocated_group_rid) 
-                       return ldap_state->low_allocated_group_rid;
-               break;
-       }
-
-       next_rid = (top_rid & ~RID_TYPE_MASK) + rid_type + RID_MULTIPLIER;
-
-       switch (rid_type) {
-       case USER_RID_TYPE:
-               if (next_rid > ldap_state->high_allocated_user_rid) {
-                       return 0;
-               }
-               break;
-       case GROUP_RID_TYPE:
-               if (next_rid > ldap_state->high_allocated_group_rid) {
-                       return 0;
-               }
-               break;
-       }
-       return next_rid;
-}
-
 /**********************************************************************
  Add the sambaDomain to LDAP, so we don't have to search for this stuff
  again.  This is a once-add operation for now.
@@ -536,7 +337,8 @@ static uint32 search_next_allocated_rid(struct ldapsam_privates *ldap_state, int
 *********************************************************************/
 static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state) 
 {
-       pstring tmp;
+       fstring sid_string;
+       fstring algorithmic_rid_base_string;
        pstring filter, dn;
        LDAPMod **mods = NULL;
        int rc;
@@ -545,22 +347,9 @@ static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state)
        int num_result;
        char **attr_list;
 
-       uint32 next_allocated_user_rid;
-       uint32 next_allocated_group_rid;
-
-       next_allocated_user_rid = search_next_allocated_rid(ldap_state, USER_RID_TYPE);
-       if (!next_allocated_user_rid) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       next_allocated_group_rid = search_next_allocated_rid(ldap_state, GROUP_RID_TYPE);
-       if (!next_allocated_group_rid) {
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
        slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", 
-               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
-               ldap_state->domain_name, LDAP_OBJ_DOMINFO);
+                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
+                 ldap_state->domain_name, LDAP_OBJ_DOMINFO);
 
        attr_list = get_attr_list( dominfo_attr_list );
        rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, 
@@ -582,6 +371,7 @@ static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state)
        /* Check if we need to add an entry */
        DEBUG(3,("Adding new domain\n"));
        ldap_op = LDAP_MOD_ADD;
+
        snprintf(dn, sizeof(dn), "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
                ldap_state->domain_name, lp_ldap_suffix());
 
@@ -592,15 +382,15 @@ static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state)
        smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
                ldap_state->domain_name);
 
-       sid_to_string(tmp, &ldap_state->domain_sid);
-       smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), tmp);
-
-       snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_user_rid);
-       smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), tmp);
+       /* If we don't have an entry, then ask secrets.tdb for what it thinks.  
+          It may choose to make it up */
 
-       snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_group_rid);
-       smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), tmp);
+       sid_to_string(sid_string, get_global_sam_sid());
+       smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string);
 
+       slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base());
+       smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
+                       algorithmic_rid_base_string);
        smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
 
        switch(ldap_op)
@@ -637,7 +427,59 @@ static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state)
 }
 
 /**********************************************************************
- Even if the sambaAccount attribute in LDAP tells us that this RID is 
+Search for the domain info entry
+*********************************************************************/
+static NTSTATUS ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
+                                          LDAPMessage ** result, BOOL try_add)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+       pstring filter;
+       int rc;
+       char **attr_list;
+       int count;
+
+       snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
+               LDAP_OBJ_DOMINFO,
+               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
+               ldap_state->domain_name);
+
+       DEBUG(2, ("Searching for:[%s]\n", filter));
+
+
+       attr_list = get_attr_list( dominfo_attr_list );
+       rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, 
+                                  attr_list , result);
+       free_attr_list( attr_list );
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
+               DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
+       } else if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, *result) < 1) {
+               DEBUG(3, ("Got no domain info entries for domain %s\n",
+                         ldap_state->domain_name));
+               ldap_msgfree(*result);
+               *result = NULL;
+               if (try_add && NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) {
+                       return ldapsam_search_domain_info(ldap_state, result, False);
+               } else {
+                       DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret)));
+                       return ret;
+               }
+       } else if ((count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, *result)) > 1) {
+               DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
+                         count, ldap_state->domain_name));
+               ldap_msgfree(*result);
+               *result = NULL;
+               return ret;
+       } else {
+               return NT_STATUS_OK;
+       }
+       
+       return ret;
+}
+
+/**********************************************************************
+ 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 ldapsam_privates *ldap_state, 
@@ -689,15 +531,17 @@ static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *ri
 {
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
        int rc;
-       LDAPMessage *result = NULL;
+       LDAPMessage *domain_result = NULL;
        LDAPMessage *entry  = NULL;
        char *dn;
        LDAPMod **mods = NULL;
-       int count;
        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;
 
        if ( ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT ) {
                DEBUG(0, ("Allocated RIDs require the %s objectclass used by 'ldapsam'\n", 
@@ -707,100 +551,129 @@ static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *ri
        
        while (attempts < 10) 
        {
-               char *ld_error;
-               if (ldapsam_search_domain_info(ldap_state, &result)) {
-                       return ret;
-               }
-
-               if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) < 1) {
-                       DEBUG(3, ("Got no domain info entries for domain %s\n",
-                                 ldap_state->domain_name));
-                       ldap_msgfree(result);
-                       if (NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) {
-                               continue;
-                       } else {
-                               DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret)));
-                               return ret;
-                       }
-               }
-               
-               if ((count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result)) > 1) {
-                       DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
-                                 count, ldap_state->domain_name));
-                       ldap_msgfree(result);
+               if (!NT_STATUS_IS_OK(ret = ldapsam_search_domain_info(ldap_state, &domain_result, True))) {
                        return ret;
                }
-
-               entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
+       
+               entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, domain_result);
                if (!entry) {
-                       ldap_msgfree(result);
+                       DEBUG(0, ("Could not get domain info entry\n"));
+                       ldap_msgfree(domain_result);
                        return ret;
                }
 
                if ((dn = ldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry)) == NULL) {
                        DEBUG(0, ("Could not get domain info DN\n"));
-                       ldap_msgfree(result);
+                       ldap_msgfree(domain_result);
                        return ret;
                }
 
-               /* yes, we keep 2 seperate counters, to avoid stomping on the two
+               /* 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 */
-
-               switch (rid_type) {
-               case USER_RID_TYPE:
-                       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
-                               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
-                               old_rid_string)) 
-                       {
-                               ldap_memfree(dn);
-                               ldap_msgfree(result);
-                               return ret;
-                       }
-                       break;
-               case GROUP_RID_TYPE:
-                       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
-                               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
-                               old_rid_string)) 
-                       {
-                               ldap_memfree(dn);
-                               ldap_msgfree(result);
-                               return ret;
-                       }
-                       break;
+               
+               if (smbldap_get_single_attribute(ldap_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(ldap_state->smbldap_state->ldap_struct, entry, &mods, 
+                                        get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
+                                        algorithmic_rid_base_string);
                }
 
-               /* This is the core of the whole routine. If we had
-                   scheme-style closures, there would be a *lot* less code
-                   duplication... */
-               *rid = (uint32)atol(old_rid_string);
-               next_rid = *rid+RID_MULTIPLIER;
+               next_rid = 0;
 
-               slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
+               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_attribute(ldap_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;
+                       }
 
-               switch (rid_type) {
-               case USER_RID_TYPE:
-                       if (next_rid > ldap_state->high_allocated_user_rid) {
+                       next_rid = *rid+1;
+                       if (next_rid >= alg_rid_base) {
                                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(ldap_state->smbldap_state->ldap_struct, entry, &mods, 
-                               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), 
-                               next_rid_string);
-                       break;
+                                        get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), 
+                                        next_rid_string);
+               }
 
-               case GROUP_RID_TYPE:
-                       if (next_rid > ldap_state->high_allocated_group_rid) {
-                               return NT_STATUS_UNSUCCESSFUL;
+               if (!next_rid) { /* not got one already */
+                       switch (rid_type) {
+                       case USER_RID_TYPE:
+                               if (smbldap_get_single_attribute(ldap_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);
+                                       
+                               } else {
+                                       *rid = ldap_state->low_allocated_user_rid;
+                               }
+                               break;
+                       case GROUP_RID_TYPE:
+                               if (smbldap_get_single_attribute(ldap_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);
+                               } else {
+                                       *rid = ldap_state->low_allocated_group_rid;
+                               }
+                               break;
                        }
+                       
+                       /* This is the core of the whole routine. If we had
+                          scheme-style closures, there would be a *lot* less code
+                          duplication... */
 
-                       /* Try to make the modification atomically by enforcing the
-                          old value in the delete mod. */
-                       smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods,
-                               get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
-                               next_rid_string);
-                       break;
+                       next_rid = *rid+RID_MULTIPLIER;
+                       slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
+                       
+                       switch (rid_type) {
+                       case USER_RID_TYPE:
+                               if (next_rid > ldap_state->high_allocated_user_rid) {
+                                       return NT_STATUS_UNSUCCESSFUL;
+                               }
+                               
+                               /* Try to make the modification atomically by enforcing the
+                                  old value in the delete mod. */
+                               smbldap_make_mod(ldap_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:
+                               if (next_rid > ldap_state->high_allocated_group_rid) {
+                                       return NT_STATUS_UNSUCCESSFUL;
+                               }
+                               
+                               /* Try to make the modification atomically by enforcing the
+                                  old value in the delete mod. */
+                               smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods,
+                                                get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
+                                                next_rid_string);
+                               break;
+                       }
                }
 
                if ((rc = ldap_modify_s(ldap_state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
@@ -809,27 +682,27 @@ static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *ri
                        pstring domain_sid_string;
                        int error = 0;
 
-                       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, result,
+                       if (!smbldap_get_single_attribute(ldap_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);
                                ldap_memfree(dn);
-                               ldap_msgfree(result);
+                               ldap_msgfree(domain_result);
                                return ret;
                        }
 
                        if (!string_to_sid(&dom_sid, domain_sid_string)) { 
                                ldap_mods_free(mods, True);
                                ldap_memfree(dn);
-                               ldap_msgfree(result);
+                               ldap_msgfree(domain_result);
                                return ret;
                        }
 
                        ldap_mods_free(mods, True);
                        mods = NULL;
                        ldap_memfree(dn);
-                       ldap_msgfree(result);
+                       ldap_msgfree(domain_result);
 
                        sid_copy(&sid, &dom_sid);
                        sid_append_rid(&sid, *rid);
@@ -845,8 +718,9 @@ static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *ri
                        return NT_STATUS_OK;
                }
 
+               ld_error = NULL;
                ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
-               DEBUG(2, ("Failed to modify rid: %s\n", ld_error));
+               DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
                SAFE_FREE(ld_error);
 
                ldap_mods_free(mods, True);
@@ -855,8 +729,8 @@ static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *ri
                ldap_memfree(dn);
                dn = NULL;
 
-               ldap_msgfree(result);
-               result = NULL;
+               ldap_msgfree(domain_result);
+               domain_result = NULL;
 
                {
                        /* Sleep for a random timeout */
@@ -905,13 +779,13 @@ static BOOL get_unix_attributes (struct ldapsam_privates *ldap_state,
        }
        ldap_value_free(ldap_values);
 
-       if ( !get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if ( !smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_UNIX_HOME), homedir) ) 
        {
                return False;
        }
        
-       if ( !get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if ( !smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_GIDNUMBER), temp) )
        {
                return False;
@@ -989,7 +863,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                return False;
        }
        
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, "uid", username)) {
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, "uid", username)) {
                DEBUG(1, ("No uid attribute found for this user!\n"));
                return False;
        }
@@ -1009,13 +883,13 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
        
        if ( ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ) 
        {
-               if (get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+               if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                        get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), temp)) 
                {
                        pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
                }
                
-               if (get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+               if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                        get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_SID), temp)) 
                {
                        pdb_set_group_sid_from_string(sampass, temp, PDB_SET);                  
@@ -1029,14 +903,14 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
        } 
        else 
        {
-               if (get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+               if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
                        get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID), temp)) 
                {
                        user_rid = (uint32)atol(temp);
                        pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
                }
                
-               if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+               if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                        get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_RID), temp)) 
                {
                        pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
@@ -1083,7 +957,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                }
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET), temp)) 
        {
                /* leave as default */
@@ -1092,7 +966,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp)) 
        {
                /* leave as default */
@@ -1101,7 +975,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_logon_time(sampass, logon_time, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp)) 
        {
                /* leave as default */
@@ -1110,7 +984,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp)) 
        {
                /* leave as default */
@@ -1119,7 +993,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp)) 
        {
                /* leave as default */
@@ -1128,7 +1002,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp)) 
        {       
                /* leave as default */
@@ -1143,10 +1017,10 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
         * that fits your needs; using cn then displayName rather than 'userFullName'
         */
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME), fullname)) 
        {
-               if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+               if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
                        get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_CN), fullname)) 
                {
                        /* leave as default */
@@ -1157,7 +1031,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_fullname(sampass, fullname, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE), dir_drive)) 
        {
                pdb_set_dir_drive(sampass, talloc_sub_specified(sampass->mem_ctx, 
@@ -1169,7 +1043,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH), homedir)) 
        {
                pdb_set_homedir(sampass, talloc_sub_specified(sampass->mem_ctx, 
@@ -1181,7 +1055,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_homedir(sampass, homedir, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT), logon_script)) 
        {
                pdb_set_logon_script(sampass, talloc_sub_specified(sampass->mem_ctx, 
@@ -1193,7 +1067,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_logon_script(sampass, logon_script, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH), profile_path)) 
        {
                pdb_set_profile_path(sampass, talloc_sub_specified(sampass->mem_ctx, 
@@ -1205,7 +1079,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_profile_path(sampass, profile_path, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC), acct_desc)) 
        {
                /* leave as default */
@@ -1213,7 +1087,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS), workstations)) 
        {
                /* leave as default */;
@@ -1227,7 +1101,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
        hours_len = 21;
        memset(hours, 0xff, hours_len);
 
-       if (!get_single_attribute (ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute (ldap_state->smbldap_state->ldap_struct, entry, 
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW), temp)) 
        {
                /* leave as default */
@@ -1239,7 +1113,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                ZERO_STRUCT(smblmpwd);
        }
 
-       if (!get_single_attribute (ldap_state->smbldap_state->ldap_struct, entry,
+       if (!smbldap_get_single_attribute (ldap_state->smbldap_state->ldap_struct, entry,
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW), temp)) 
        {
                /* leave as default */
@@ -1251,7 +1125,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
                ZERO_STRUCT(smbntpwd);
        }
 
-       if (!get_single_attribute (ldap_state->smbldap_state->ldap_struct, entry,
+       if (!smbldap_get_single_attribute (ldap_state->smbldap_state->ldap_struct, entry,
                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), temp)) 
        {
                acct_ctrl |= ACB_NORMAL;
@@ -1346,10 +1220,10 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                switch ( ldap_state->schema_ver )
                {
                        case SCHEMAVER_SAMBAACCOUNT:
-                               if (!sid_peek_check_rid(get_global_sam_sid(), user_sid, &rid)) {
+                               if (!sid_peek_check_rid(&ldap_state->domain_sid, user_sid, &rid)) {
                                        DEBUG(1, ("User's SID (%s) is not for this domain (%s), cannot add to LDAP!\n", 
                                                sid_to_string(sid_string, user_sid), 
-                                               sid_to_string(dom_sid_string, get_global_sam_sid())));
+                                               sid_to_string(dom_sid_string, &ldap_state->domain_sid)));
                                        return False;
                                }
                                slprintf(temp, sizeof(temp) - 1, "%i", rid);
@@ -1382,10 +1256,10 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                switch ( ldap_state->schema_ver )
                {
                        case SCHEMAVER_SAMBAACCOUNT:
-                               if (!sid_peek_check_rid(get_global_sam_sid(), group_sid, &rid)) {
+                               if (!sid_peek_check_rid(&ldap_state->domain_sid, group_sid, &rid)) {
                                        DEBUG(1, ("User's Primary Group SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
                                                sid_to_string(sid_string, group_sid),
-                                               sid_to_string(dom_sid_string, get_global_sam_sid())));
+                                               sid_to_string(dom_sid_string, &ldap_state->domain_sid)));
                                        return False;
                                }
 
@@ -1637,48 +1511,59 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT
        return ret;
 }
 
-/**********************************************************************
-Get SAM_ACCOUNT entry from LDAP by SID
-*********************************************************************/
-static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
+static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, 
+                                  const DOM_SID *sid, LDAPMessage **result) 
 {
-       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
-       struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
-       LDAPMessage *result;
-       LDAPMessage *entry;
-       fstring sid_string;
-       int count;
-       int rc;
+       int rc = -1;
        char ** attr_list;
-       
        switch ( ldap_state->schema_ver )
        {
                case SCHEMAVER_SAMBASAMACCOUNT:
                        attr_list = get_userattr_list(ldap_state->schema_ver);
-                       rc = ldapsam_search_suffix_by_sid(ldap_state, sid, &result, attr_list);
+                       rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list);
                        free_attr_list( attr_list );
 
                        if ( rc != LDAP_SUCCESS ) 
-                               return NT_STATUS_NO_SUCH_USER;
+                               return rc;
                        break;
                        
                case SCHEMAVER_SAMBAACCOUNT:
                {
                        uint32 rid;
-                       if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
-                               return NT_STATUS_NO_SUCH_USER;
+                       if (!sid_peek_check_rid(&ldap_state->domain_sid, sid, &rid)) {
+                               return rc;
                        }
                
                        attr_list = get_userattr_list(ldap_state->schema_ver);
-                       rc = ldapsam_search_suffix_by_rid(ldap_state, rid, &result, attr_list );
+                       rc = ldapsam_search_suffix_by_rid(ldap_state, rid, result, attr_list );
                        free_attr_list( attr_list );
 
                        if ( rc != LDAP_SUCCESS ) 
-                               return NT_STATUS_NO_SUCH_USER;
+                               return rc;
                }
                break;
        }
-       
+       return rc;
+}
+
+/**********************************************************************
+Get SAM_ACCOUNT entry from LDAP by SID
+*********************************************************************/
+static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+       LDAPMessage *result;
+       LDAPMessage *entry;
+       int count;
+       int rc;
+       fstring sid_string;
+
+       rc = ldapsam_get_ldap_user_by_sid(ldap_state, 
+                                         sid, &result); 
+       if (rc != LDAP_SUCCESS)
+               return NT_STATUS_NO_SUCH_USER;
+
        count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
        
        if (count < 1) 
@@ -1737,7 +1622,9 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
                switch(ldap_op)
                {
                        case LDAP_MOD_ADD: 
-                               smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_ACCOUNT);
+                               smbldap_set_mod(&mods, LDAP_MOD_ADD, 
+                                               "objectclass", 
+                                               LDAP_OBJ_ACCOUNT);
                                rc = smbldap_add(ldap_state->smbldap_state, 
                                                 dn, mods);
                                break;
@@ -1746,7 +1633,8 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
                                                    dn ,mods);
                                break;
                        default:        
-                               DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
+                               DEBUG(0,("Wrong LDAP operation type: %d!\n", 
+                                        ldap_op));
                                return NT_STATUS_INVALID_PARAMETER;
                }
                
@@ -1979,7 +1867,9 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
        char            **attr_list;
        char            *escape_user;
        const char      *username = pdb_get_username(newpwd);
+       const DOM_SID   *sid = pdb_get_user_sid(newpwd);
        pstring         filter;
+       fstring         sid_string;
 
        if (!username || !*username) {
                DEBUG(0, ("Cannot add user without a username!\n"));
@@ -1987,8 +1877,8 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
        }
 
        /* free this list after the second search or in case we exit on failure */
-       
        attr_list = get_userattr_list(ldap_state->schema_ver);
+
        rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list);
 
        if (rc != LDAP_SUCCESS) {
@@ -2004,9 +1894,24 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
                return NT_STATUS_UNSUCCESSFUL;
        }
        ldap_msgfree(result);
+       result = NULL;
+
+       if (element_is_set_or_changed(newpwd, PDB_USERSID)) {
+               rc = ldapsam_get_ldap_user_by_sid(ldap_state, 
+                                                 sid, &result); 
+               if (rc == LDAP_SUCCESS) {
+                       if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) {
+                               DEBUG(0,("SID '%s' already in the base, with samba attributes\n", 
+                                        sid_to_string(sid_string, sid)));
+                               free_attr_list( attr_list );
+                               return NT_STATUS_UNSUCCESSFUL;
+                       }
+                       ldap_msgfree(result);
+               }
+       }
 
        /* does the entry already exist but without a samba rttibutes?
-          we don't really care what attributes are returned here */
+          we need to return the samba attributes here */
           
        escape_user = escape_ldap_string_alloc( username );
        pstrcpy( filter, lp_ldap_filter() );
@@ -2015,15 +1920,16 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
 
        rc = smbldap_search_suffix(ldap_state->smbldap_state, 
                                   filter, attr_list, &result);
-       free_attr_list( attr_list );
-
-       if ( rc != LDAP_SUCCESS )
+       if ( rc != LDAP_SUCCESS ) {
+               free_attr_list( attr_list );
                return NT_STATUS_UNSUCCESSFUL;
+       }
 
        num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
        
        if (num_result > 1) {
                DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
+               free_attr_list( attr_list );
                ldap_msgfree(result);
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -2038,15 +1944,57 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
                tmp = ldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry);
                slprintf (dn, sizeof (dn) - 1, "%s", tmp);
                ldap_memfree (tmp);
-       } else {
+
+       } else if (ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT) {
+
+               /* There might be a SID for this account already - say an idmap entry */
+
+               snprintf(filter, sizeof(filter)-1, "(&(%s=%s)(|(objectClass=%s)(objectClass=%s)))", 
+                        get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
+                        sid_to_string(sid_string, sid),
+                        LDAP_OBJ_IDMAP_ENTRY,
+                        LDAP_OBJ_SID_ENTRY);
+               
+               rc = smbldap_search_suffix(ldap_state->smbldap_state, 
+                                          filter, attr_list, &result);
+               free_attr_list( attr_list );
+                       
+               if ( rc != LDAP_SUCCESS ) {
+                       free_attr_list( attr_list );
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+               
+               num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
+               
+               if (num_result > 1) {
+                       DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
+                       free_attr_list( attr_list );
+                       ldap_msgfree(result);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+               
+               /* Check if we need to update an existing entry */
+               if (num_result == 1) {
+                       char *tmp;
+                       
+                       DEBUG(3,("User exists without samba attributes: adding them\n"));
+                       ldap_op = LDAP_MOD_REPLACE;
+                       entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result);
+                       tmp = ldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry);
+                       slprintf (dn, sizeof (dn) - 1, "%s", tmp);
+                       ldap_memfree (tmp);
+               }
+       }
+       
+       if (num_result == 0) {
                /* Check if we need to add an entry */
                DEBUG(3,("Adding new user\n"));
                ldap_op = LDAP_MOD_ADD;
                if (username[strlen(username)-1] == '$') {
-                        slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
-                } else {
-                        slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
-                }
+                       slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
+               } else {
+                       slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
+               }
        }
 
        if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
@@ -2089,21 +2037,6 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
        return NT_STATUS_OK;
 }
 
-/**********************************************************************
- Housekeeping
- *********************************************************************/
-
-static void free_private_data(void **vp) 
-{
-       struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
-
-       smbldap_free_struct(&(*ldap_state)->smbldap_state);
-
-       *ldap_state = NULL;
-
-       /* No need to free any further, as it is talloc()ed */
-}
-
 /**********************************************************************
  *********************************************************************/
 
@@ -2154,7 +2087,7 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
                return False;
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), temp)) 
        {
                DEBUG(0, ("Mandatory attribute %s not found\n", 
@@ -2165,7 +2098,7 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
 
        map->gid = (gid_t)atol(temp);
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID), temp)) 
        {
                DEBUG(0, ("Mandatory attribute %s not found\n",
@@ -2174,7 +2107,7 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
        }
        string_to_sid(&map->sid, temp);
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), temp)) 
        {
                DEBUG(0, ("Mandatory attribute %s not found\n",
@@ -2189,11 +2122,11 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
                return False;
        }
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), temp)) 
        {
                temp[0] = '\0';
-               if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+               if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                        get_attr_key2string( groupmap_attr_list, LDAP_ATTR_CN), temp)) 
                {
                        DEBUG(0, ("Attributes cn not found either "
@@ -2203,7 +2136,7 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
        }
        fstrcpy(map->nt_name, temp);
 
-       if (!get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+       if (!smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
                get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), temp)) 
        {
                temp[0] = '\0';
@@ -2333,13 +2266,18 @@ static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
                                 const char *name)
 {
        pstring filter;
+       char *escape_name = escape_ldap_string_alloc(name);
 
-       /* TODO: Escaping of name? */
+       if (!escape_name) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
                LDAP_OBJ_GROUPMAP,
-               get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), name,
-               get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN), name);
+               get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), escape_name,
+               get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN), escape_name);
+
+       SAFE_FREE(escape_name);
 
        return ldapsam_getgroup(methods, filter, map);
 }
@@ -2650,6 +2588,21 @@ static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
        return NT_STATUS_OK;
 }
 
+/**********************************************************************
+ Housekeeping
+ *********************************************************************/
+
+static void free_private_data(void **vp) 
+{
+       struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
+
+       smbldap_free_struct(&(*ldap_state)->smbldap_state);
+
+       *ldap_state = NULL;
+
+       /* No need to free any further, as it is talloc()ed */
+}
+
 /**********************************************************************
  Intitalise the parts of the pdb_context that are common to all pdb_ldap modes
  *********************************************************************/
@@ -2700,8 +2653,6 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **
                return NT_STATUS_NO_MEMORY;
        }
 
-       sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
-
        (*pdb_method)->private_data = ldap_state;
 
        (*pdb_method)->free_private_data = free_private_data;
@@ -2743,6 +2694,8 @@ static NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **
        ldap_state = (*pdb_method)->private_data;
        ldap_state->schema_ver = SCHEMAVER_SAMBAACCOUNT;
 
+       sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
+
        return NT_STATUS_OK;
 }
 
@@ -2754,8 +2707,15 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met
 {
        NTSTATUS nt_status;
        struct ldapsam_privates *ldap_state;
+       uint32 alg_rid_base;
+       pstring alg_rid_base_string;
        uint32 low_idmap_uid, high_idmap_uid;
        uint32 low_idmap_gid, high_idmap_gid;
+       LDAPMessage *result;
+       LDAPMessage *entry;
+       DOM_SID ldap_domain_sid;
+       DOM_SID secrets_domain_sid;
+       pstring domain_sid_string;
 
        if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
                return nt_status;
@@ -2767,6 +2727,52 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met
        ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;     
        ldap_state->permit_non_unix_accounts = False;
 
+       /* Try to setup the Domain Name, Domain SID, algorithmic rid base */
+
+       if (!NT_STATUS_IS_OK(nt_status = ldapsam_search_domain_info(ldap_state, &result, True))) {
+               DEBUG(2, ("WARNING: Could not get domain info, nor add one to the domain\n"));
+               DEBUGADD(2, ("Continuing on regardless, will be unable to allocate new users/groups, and will risk BDCs having inconsistant SIDs\n"));
+               sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
+               return NT_STATUS_OK;
+       }
+
+       /* Given that the above might fail, everything below this must be optional */
+       
+       entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
+       if (!entry) {
+               DEBUG(0, ("Could not get domain info entry\n"));
+               ldap_msgfree(result);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+                                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), 
+                                domain_sid_string)) 
+       {
+               BOOL found_sid;
+               string_to_sid(&ldap_domain_sid, domain_sid_string);
+               found_sid = secrets_fetch_domain_sid(ldap_state->domain_name, &secrets_domain_sid);
+               if (!found_sid || !sid_equal(&secrets_domain_sid, &ldap_domain_sid)) {
+                       /* reset secrets.tdb sid */
+                       secrets_store_domain_sid(ldap_state->domain_name, &ldap_domain_sid);
+               }
+               sid_copy(&ldap_state->domain_sid, &ldap_domain_sid);
+       }
+
+       if (smbldap_get_single_attribute(ldap_state->smbldap_state->ldap_struct, entry, 
+                                get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
+                                alg_rid_base_string)) 
+       {
+               alg_rid_base = (uint32)atol(alg_rid_base_string);
+               if (alg_rid_base != algorithmic_rid_base()) {
+                       DEBUG(0, ("The value of 'algorithmic RID base' has changed since the LDAP\n"
+                                 "database was initialised.  Aborting. \n"));
+                       ldap_msgfree(result);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+       }
+       ldap_msgfree(result);
+       
        /* check for non-unix account ranges */
 
        if (lp_idmap_uid(&low_idmap_uid, &high_idmap_uid) 
index b31ce18925cb75dcd87acaa5985a9804e1b1ea3f..2dccaf04f73f350cd2ba90f42de31a6a72b21b2a 100644 (file)
 
 
 struct ldap_idmap_state {
-       LDAP *ldap_struct;
-       time_t last_ping;
-       char *uri;
-       char *bind_dn;
-       char *bind_secret;
-       unsigned int num_failures;
-       struct ldap_idmap_state *prev, *next;
+       struct smbldap_state *smbldap_state;
+       TALLOC_CTX *mem_ctx;
+
+       /* struct ldap_idmap_state *prev, *next; */
 };
 
-#define LDAP_IDMAP_DONT_PING_TIME 10       /* ping only all 10 seconds */
 #define LDAP_MAX_ALLOC_ID 128              /* number tries while allocating
                                              new id */
 
 static struct ldap_idmap_state ldap_state;
 
-static int ldap_idmap_connect_system(struct ldap_idmap_state *state);
 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type);
+static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, int id_type, 
+                                          const char *ldap_dn, LDAPMessage *entry);
 static NTSTATUS ldap_idmap_close(void);
 
 
-/*******************************************************************
- open a connection to the ldap server.
-******************************************************************/
-static int ldap_idmap_open_connection(struct ldap_idmap_state *state)
-{
-       int rc = LDAP_SUCCESS;
-       int version;
-       BOOL ldap_v3 = False;
-
-#ifdef HAVE_LDAP_INITIALIZE
-       DEBUG(10, ("ldap_idmap_open_connection: %s\n", state->uri));
-       
-       if ((rc = ldap_initialize(&state->ldap_struct, state->uri)) 
-           != LDAP_SUCCESS) {
-               DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
-               return rc;
-       }
-#else 
-       /* Parse the string manually */
-       {
-               int port = 0;
-               fstring protocol;
-               fstring host;
-               const char *p = state->uri; 
-               SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
-               
-               /* skip leading "URL:" (if any) */
-               if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
-                       p += 4;
-               }
-               
-               sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
-               
-               if (port == 0) {
-                       if (strequal(protocol, "ldap")) {
-                               port = LDAP_PORT;
-                       } else if (strequal(protocol, "ldaps")) {
-                               port = LDAPS_PORT;
-                       } else {
-                               DEBUG(0, ("unrecognised protocol (%s)!\n",
-                                         protocol));
-                       }
-               }
-               
-               if ((state->ldap_struct = ldap_init(host, port)) == NULL) {
-                       DEBUG(0, ("ldap_init failed !\n"));
-                       return LDAP_OPERATIONS_ERROR;
-               }
-               
-               if (strequal(protocol, "ldaps")) {
-#ifdef LDAP_OPT_X_TLS
-                       int tls = LDAP_OPT_X_TLS_HARD;
-                       if (ldap_set_option (state->ldap_struct, 
-                                            LDAP_OPT_X_TLS, &tls) != 
-                           LDAP_SUCCESS)
-                       {
-                               DEBUG(0, ("Failed to setup a TLS session\n"));
-                       }
-                       
-                       DEBUG(3,("LDAPS option set...!\n"));
-#else
-                       DEBUG(0,("ldap_idmap_open_connection: Secure "
-                                "connection not supported by LDAP client "
-                                "libraries!\n"));
-                       return LDAP_OPERATIONS_ERROR;
-#endif
-               }
-       }
-#endif
-
-       if (ldap_get_option(state->ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
-                           &version) == LDAP_OPT_SUCCESS) {
-               if (version != LDAP_VERSION3) {
-                       version = LDAP_VERSION3;
-                       if (ldap_set_option(state->ldap_struct,
-                                           LDAP_OPT_PROTOCOL_VERSION,
-                                           &version) == LDAP_OPT_SUCCESS) {
-                               ldap_v3 = True;
-                       }
-               } else {
-                       ldap_v3 = True;
-               }
-       }
-
-       if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
-#ifdef LDAP_OPT_X_TLS
-               if (ldap_v3) {
-                       if ((rc = ldap_start_tls_s(state->ldap_struct, NULL,
-                                                  NULL)) != LDAP_SUCCESS) {
-                               DEBUG(0,("Failed to issue the StartTLS "
-                                        "instruction: %s\n",
-                                        ldap_err2string(rc)));
-                               return rc;
-                       }
-                       DEBUG (3, ("StartTLS issued: using a TLS "
-                                  "connection\n"));
-               } else {
-                       
-                       DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
-                       return LDAP_OPERATIONS_ERROR;
-               }
-#else
-               DEBUG(0,("ldap_idmap_open_connection: StartTLS not supported by "
-                        "LDAP client libraries!\n"));
-               return LDAP_OPERATIONS_ERROR;
-#endif
-       }
-
-       DEBUG(2, ("ldap_idmap_open_connection: connection opened\n"));
-       return rc;
-}
-
-/**********************************************************************
-Connect to LDAP server 
-*********************************************************************/
-static int ldap_idmap_open(struct ldap_idmap_state *state)
-{
-       int rc;
-       SMB_ASSERT(state);
-               
-#ifndef NO_LDAP_SECURITY
-       if (geteuid() != 0) {
-               DEBUG(0, 
-                     ("ldap_idmap_open: cannot access LDAP when not root\n"));
-               return  LDAP_INSUFFICIENT_ACCESS;
-       }
-#endif
-
-       if ((state->ldap_struct != NULL) && 
-           ((state->last_ping + LDAP_IDMAP_DONT_PING_TIME)<time(NULL))) {
-               struct sockaddr_un addr;
-               socklen_t len = sizeof(addr);
-               int sd;
-
-               if (!ldap_get_option(state->ldap_struct,  LDAP_OPT_DESC, &sd)&&
-                   getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
-                       /* the other end has died. reopen. */
-                       ldap_unbind_ext(state->ldap_struct, NULL, NULL);
-                       state->ldap_struct = NULL;
-                       state->last_ping = (time_t)0;
-               } else {
-                       state->last_ping = time(NULL);
-               } 
-       }
-
-       if (state->ldap_struct != NULL) {
-               DEBUG(5,("ldap_idmap_open: already connected to the LDAP "
-                        "server\n"));
-               return LDAP_SUCCESS;
-       }
-
-       if ((rc = ldap_idmap_open_connection(state))) {
-               return rc;
-       }
-
-       if ((rc = ldap_idmap_connect_system(state))) {
-               ldap_unbind_ext(state->ldap_struct, NULL, NULL);
-               state->ldap_struct = NULL;
-               return rc;
-       }
-
-
-       state->last_ping = time(NULL);
-       DEBUG(4,("The LDAP server is succesful connected\n"));
-
-       return LDAP_SUCCESS;
-}
-
-/*******************************************************************
-******************************************************************/
-
-static int ldap_idmap_retry_open(struct ldap_idmap_state *state, int *attempts)
-{
-       int rc;
-
-       SMB_ASSERT(state && attempts);
-
-       if (*attempts != 0) {
-               unsigned int sleep_time;
-               uint8 rand_byte = 128; /* a reasonable place to start */
-
-               generate_random_buffer(&rand_byte, 1, False);
-
-               sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2; 
-               /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
-                  on average.  
-                */
-               DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n",
-                         sleep_time));
-               msleep(sleep_time);
-       }
-       (*attempts)++;
-
-       if ((rc = ldap_idmap_open(state))) {
-               DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",
-                        *attempts));
-               return rc;
-       } 
-       
-       return LDAP_SUCCESS;            
-}
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
-******************************************************************/
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-static int rebindproc_with_state  (LDAP * ld, char **whop, char **credp, 
-                                  int *methodp, int freeit, void *arg)
-{
-       struct ldap_idmap_state *state = arg;
-       
-       /** @TODO Should we be doing something to check what servers we rebind
-           to?  Could we get a referral to a machine that we don't want to
-           give our username and password to? */
-       
-       if (freeit) {
-               SAFE_FREE(*whop);
-               memset(*credp, '\0', strlen(*credp));
-               SAFE_FREE(*credp);
-       } else {
-               DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", 
-                         state->bind_dn));
-
-               *whop = strdup(state->bind_dn);
-               if (!*whop) {
-                       return LDAP_NO_MEMORY;
-               }
-               *credp = strdup(state->bind_secret);
-               if (!*credp) {
-                       SAFE_FREE(*whop);
-                       return LDAP_NO_MEMORY;
-               }
-               *methodp = LDAP_AUTH_SIMPLE;
-       }
-       return 0;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- This version takes a void* that we can shove useful stuff in :-)
- and actually does the connection.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-static int rebindproc_connect_with_state (LDAP *ldap_struct, 
-                                         LDAP_CONST char *url, 
-                                         ber_tag_t request,
-                                         ber_int_t msgid, void *arg)
-{
-       struct ldap_idmap_state *state = arg;
-       int rc;
-       DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n", 
-                state->bind_dn));
-       
-       /** @TODO Should we be doing something to check what servers we rebind
-           to?  Could we get a referral to a machine that we don't want to
-           give our username and password to? */
-
-       rc = ldap_simple_bind_s(ldap_struct, state->bind_dn, 
-                               state->bind_secret);
-       
-       return rc;
-}
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- Add a rebind function for authenticated referrals
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-#else
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
-                      int *method, int freeit )
-{
-       return rebindproc_with_state(ldap_struct, whop, credp,
-                                  method, freeit, &ldap_state);
-       
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- a rebind function for authenticated referrals
- this also does the connection, but no void*.
-******************************************************************/
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2
-static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
-                              ber_int_t msgid)
-{
-       return rebindproc_connect_with_state(ld, url, (ber_tag_t)request,
-                                            msgid, &ldap_state);
-}
-# endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-/*******************************************************************
- connect to the ldap server under system privilege.
-******************************************************************/
-static int ldap_idmap_connect_system(struct ldap_idmap_state *state)
-{
-       int rc;
-       char *ldap_dn;
-       char *ldap_secret;
-
-       /* get the password */
-       if (!fetch_ldap_pw(&ldap_dn, &ldap_secret))
-       {
-               DEBUG(0, ("ldap_idmap_connect_system: Failed to retrieve "
-                         "password from secrets.tdb\n"));
-               return LDAP_INVALID_CREDENTIALS;
-       }
-
-       state->bind_dn = ldap_dn;
-       state->bind_secret = ldap_secret;
-
-       /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite 
-          (OpenLDAP) doesnt' seem to support it */
-          
-       DEBUG(10,("ldap_idmap_connect_system: Binding to ldap server %s as "
-                 "\"%s\"\n", state->uri, ldap_dn));
-
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
-# if LDAP_SET_REBIND_PROC_ARGS == 2    
-       ldap_set_rebind_proc(state->ldap_struct, &rebindproc_connect);  
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3    
-       ldap_set_rebind_proc(state->ldap_struct, 
-                            &rebindproc_connect_with_state, (void *)state);
-# endif
-#else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-# if LDAP_SET_REBIND_PROC_ARGS == 2    
-       ldap_set_rebind_proc(state->ldap_struct, &rebindproc);  
-# endif
-# if LDAP_SET_REBIND_PROC_ARGS == 3    
-       ldap_set_rebind_proc(state->ldap_struct, &rebindproc_with_state,
-                            (void *)state);    
-# endif
-#endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
-
-       rc = ldap_simple_bind_s(state->ldap_struct, ldap_dn, ldap_secret);
-
-       if (rc != LDAP_SUCCESS) {
-               char *ld_error = NULL;
-               ldap_get_option(state->ldap_struct, LDAP_OPT_ERROR_STRING,
-                               &ld_error);
-               DEBUG(state->num_failures ? 2 : 0,
-                     ("failed to bind to server with dn= %s Error: "
-                      "%s\n\t%s\n",
-                      ldap_dn ? ld_error : "(unknown)",
-                      ldap_err2string(rc), ld_error));
-               SAFE_FREE(ld_error);
-               state->num_failures++;
-               return rc;
-       }
-
-       state->num_failures = 0;
-
-       DEBUG(3, ("ldap_idmap_connect_system: succesful connection to the "
-                 "LDAP server\n"));
-       return rc;
-}
-
-/*****************************************************************************
- wrapper around ldap_search()
-*****************************************************************************/
-
-static int ldap_idmap_search(struct ldap_idmap_state *state, 
-                            const char *base, int scope, const char *filter, 
-                            char *attrs[], int attrsonly, 
-                            LDAPMessage **res)
-{
-       int rc = LDAP_SERVER_DOWN;
-       int attempts = 0;
-       char *utf8_filter;
-
-       SMB_ASSERT(state);
-
-       if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
-               return LDAP_NO_MEMORY;
-       }
-
-       while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
-               if ((rc = ldap_idmap_retry_open(state, &attempts)) !=
-                   LDAP_SUCCESS) continue;
-               
-               rc = ldap_search_s(state->ldap_struct, base, scope, 
-                                  utf8_filter, (char**)attrs, attrsonly, res);
-       }
-       
-       if (rc == LDAP_SERVER_DOWN) {
-               DEBUG(0,("ldap_idmap_search: LDAP server is down!\n"));
-               ldap_idmap_close();
-       }
-
-       SAFE_FREE(utf8_filter);
-       return rc;
-}
-
-/***********************************************************************
- search an attribute and return the first value found.
-***********************************************************************/
-
-static BOOL ldap_idmap_attribute (struct ldap_idmap_state *state,
-                                 LDAPMessage * entry,
-                                 const char *attribute, pstring value)
-{
-       char **values;
-       value[0] = '\0';
-
-       if ( !entry )
-               return False;
-                
-       if ((values = ldap_get_values (state->ldap_struct, entry, attribute)) == NULL) 
-       {
-               DEBUG(10,("get_single_attribute: [%s] = [<does not exist>]\n",
-                         attribute));
-               return False;
-       }
-       
-       if (convert_string(CH_UTF8, CH_UNIX,
-               values[0], -1,
-               value, sizeof(pstring)) == (size_t)-1)
-       {
-               DEBUG(1, ("ldap_idmap_attribute: string conversion of [%s] = "
-                         "[%s] failed!\n",  attribute, values[0]));
-               ldap_value_free(values);
-               return False;
-       }
-       ldap_value_free(values);
-
-       return True;
-}
-
 /*****************************************************************************
  Allocate a new uid or gid
 *****************************************************************************/
@@ -505,8 +65,8 @@ 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 = 0;
-       LDAPMessage *entry = 0;
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
        pstring id_str, new_id_str;
        LDAPMod **mods = NULL;
        const char *type;
@@ -525,7 +85,7 @@ static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
 
        attr_list = get_attr_list( idpool_attr_list );
        
-       rc = ldap_idmap_search(&ldap_state, lp_ldap_idmap_suffix(),
+       rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
                               LDAP_SCOPE_SUBTREE, filter,
                               attr_list, 0, &result);
        free_attr_list( attr_list );
@@ -535,16 +95,16 @@ static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
                goto out;
        }
        
-       count = ldap_count_entries(ldap_state.ldap_struct, result);
+       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 = ldap_get_dn(ldap_state.ldap_struct, result);
-       entry = ldap_first_entry(ldap_state.ldap_struct, result);
+       dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+       entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
 
-       if (!ldap_idmap_attribute(&ldap_state, entry, type, id_str)) {
+       if (!smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
                DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
                         type));
                goto out;
@@ -578,7 +138,7 @@ static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
        smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );                 
        smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
        
-       rc = ldap_modify_s(ldap_state.ldap_struct, dn, mods);
+       rc = ldap_modify_s(ldap_state.smbldap_state->ldap_struct, dn, mods);
 
        ldap_memfree(dn);
        ldap_mods_free( mods, True );
@@ -600,12 +160,14 @@ out:
 
 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
 {
-       LDAPMessage *result = 0;
-       LDAPMessage *entry = 0;
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
+       fstring id_str;
        pstring sid_str;
        pstring filter;
        pstring suffix;
        const char *type;
+       const char *obj_class;
        int rc;
        int count;
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
@@ -615,49 +177,48 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
        
        if ( id_type & ID_USERID ) {
                type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
-               snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%u))",
-                       LDAP_OBJ_SAMBASAMACCOUNT, type, id.uid );
+               obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
+               snprintf(id_str, sizeof(id_str), "%u", id.uid );        
                pstrcpy( suffix, lp_ldap_suffix());
        }
        else {
                type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
-               snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%u))",
-                       LDAP_OBJ_GROUPMAP, type, id.gid );      
+               obj_class = LDAP_OBJ_GROUPMAP;
+               snprintf(id_str, sizeof(id_str), "%u", id.gid );        
                pstrcpy( suffix, lp_ldap_group_suffix() );
        }
                 
        attr_list = get_attr_list( sidmap_attr_list );
-       rc = ldap_idmap_search(&ldap_state, suffix, LDAP_SCOPE_SUBTREE, 
-               filter, attr_list, 0, &result);
+       snprintf(filter, sizeof(filter), "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))", 
+                LDAP_OBJ_IDMAP_ENTRY, obj_class, type, id_str);
+
+       rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
+                           filter, attr_list, 0, &result);
        
        if (rc != LDAP_SUCCESS) 
                goto out;
           
-       count = ldap_count_entries(ldap_state.ldap_struct, result);
+       count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
 
        /* fall back to looking up an idmap entry if we didn't find and 
           actual user or group */
        
        if (count == 0) {
+               ldap_msgfree(result);
+               result = NULL;
+               
                snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%u))",
                        LDAP_OBJ_IDMAP_ENTRY, type,  ((id_type & ID_USERID) ? id.uid : id.gid));
 
-#if 0  /* commented out for now -- jerry */
-               if ( id_type & ID_USERID )
-                       snprintf( suffix, sizeof(suffix), "%s,%s", IDMAP_USER_SUFFIX, lp_ldap_idmap_suffix() );
-               else
-                       snprintf( suffix, sizeof(suffix), "%s,%s", IDMAP_GROUP_SUFFIX, lp_ldap_idmap_suffix() );
-#else
                pstrcpy( suffix, lp_ldap_idmap_suffix() );
-#endif
 
-               rc = ldap_idmap_search(&ldap_state, suffix, LDAP_SCOPE_SUBTREE, 
+               rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
                        filter, attr_list, 0, &result);
 
                if (rc != LDAP_SUCCESS)
                           goto out;
                           
-               count = ldap_count_entries(ldap_state.ldap_struct, result);
+               count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
        }
        
        if (count != 1) {
@@ -666,9 +227,9 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
                goto out;
        }
        
-       entry = ldap_first_entry(ldap_state.ldap_struct, result);
+       entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
        
-       if ( !ldap_idmap_attribute(&ldap_state, entry, LDAP_ATTRIBUTE_SID, sid_str) )
+       if ( !smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
                goto out;
           
        if (!string_to_sid(sid, sid_str)) 
@@ -678,6 +239,9 @@ static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
 out:
        free_attr_list( attr_list );     
 
+       if (result)
+               ldap_msgfree(result);
+
        return ret;
 }
 
@@ -687,68 +251,74 @@ out:
 
 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
 {
-       LDAPMessage *result = 0;
-       LDAPMessage *entry = 0;
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
        pstring sid_str;
        pstring filter;
        pstring id_str;
-       pstring suffix; 
+       const char *suffix;     
        const char *type;
        const char *obj_class;
+       const char *posix_obj_class;
        int rc;
        int count;
        char **attr_list;
+       char *dn = NULL;
        NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
 
        /* first try getting the mapping from a samba user or group */
        
+       sid_to_string(sid_str, sid);
        if ( *id_type & ID_USERID ) {
-               type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
+               type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
                obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
-               pstrcpy( suffix, lp_ldap_suffix() );
+               posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
+               suffix = lp_ldap_suffix();
+               snprintf(filter, sizeof(filter), 
+                        "(&(|(&(objectClass=%s)(objectClass=%s))(objectClass=%s))(%s=%s))", 
+                        obj_class, posix_obj_class, LDAP_OBJ_IDMAP_ENTRY, 
+                        get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ), 
+                        sid_str);
        }
        else {
-               type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+               type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
                obj_class = LDAP_OBJ_GROUPMAP;
-               pstrcpy( suffix, lp_ldap_group_suffix() );
-       }       
+               posix_obj_class = LDAP_OBJ_POSIXGROUP;
+               suffix = lp_ldap_group_suffix();
+               snprintf(filter, sizeof(filter), 
+                        "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))", 
+                        obj_class, LDAP_OBJ_IDMAP_ENTRY, 
+                        get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ), 
+                        sid_str);
+       }
           
-       sid_to_string(sid_str, sid);
-       snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%s))", obj_class, 
-               LDAP_ATTRIBUTE_SID, sid_str);
-
        attr_list = get_attr_list( sidmap_attr_list );
-       rc = ldap_idmap_search(&ldap_state, suffix, LDAP_SCOPE_SUBTREE, 
+       rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
                filter, attr_list, 0, &result);
                
        if (rc != LDAP_SUCCESS)
                goto out;
 
-       count = ldap_count_entries(ldap_state.ldap_struct, result);
+       count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
        
-       /* fall back to looking up an idmap entry if we didn't find an
-          actual user or group */
+       /* fall back to looking up an idmap entry if we didn't find anything under the idmap
+          user or group suffix */
 
        if (count == 0) {
+               ldap_msgfree(result);
+               
                snprintf(filter, sizeof(filter), "(&(objectClass=%s)(%s=%s))", 
                        LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
 
-#if 0  /* commented out for now -- jerry */
-               if ( *id_type & ID_USERID )
-                       snprintf( suffix, sizeof(suffix), "%s,%s", IDMAP_USER_SUFFIX, lp_ldap_idmap_suffix() );
-               else
-                       snprintf( suffix, sizeof(suffix), "%s,%s", IDMAP_GROUP_SUFFIX, lp_ldap_idmap_suffix() );
-#else
-               pstrcpy( suffix, lp_ldap_idmap_suffix() );
-#endif 
+               suffix = lp_ldap_idmap_suffix();
 
-               rc = ldap_idmap_search(&ldap_state, suffix, LDAP_SCOPE_SUBTREE, 
+               rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
                        filter, attr_list, 0, &result);
                        
                if (rc != LDAP_SUCCESS)
                        goto out;
                        
-               count = ldap_count_entries(ldap_state.ldap_struct, result);
+               count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
        }
           
        if ( count > 1 ) {
@@ -759,15 +329,28 @@ static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *si
 
        /* we might have an existing entry to work with so pull out the requested information */
        
-       if ( count )
-               entry = ldap_first_entry(ldap_state.ldap_struct, result);
+       if ( count ) {
+               entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
        
-       /* if entry == NULL, then we will default to allocating a new id */
+               dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+               DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
+               
+               if ( smbldap_get_single_attribute(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;
+               }
+       }
        
-       if ( !ldap_idmap_attribute(&ldap_state, entry, type, id_str) ) 
-       {
+       if (!(*id_type & ID_QUERY_ONLY)) {
+               /* if entry == NULL, and we are asked to - allocate a new id */
                int i;
-
+               
                for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) 
                {
                        ret = ldap_allocate_id(id, *id_type);
@@ -781,115 +364,236 @@ static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *si
                }
                
                ret = ldap_set_mapping(sid, *id, *id_type);
-               
-       } 
-       else 
-       {
-               if ( (*id_type & ID_USERID) )
-                       id->uid = strtoul(id_str, NULL, 10);
-               else
-                       id->gid = strtoul(id_str, NULL, 10);
-                       
-               ret = NT_STATUS_OK;
+       } else {
+               /* no match, and not adding one */
+               ret = NT_STATUS_UNSUCCESSFUL;
        }
+
 out:
        free_attr_list( attr_list );
+       if (result)
+               ldap_msgfree(result);
+       if (dn)
+               ldap_memfree(dn);
        
        return ret;
 }
 
 /***********************************************************************
  This function cannot be called to modify a mapping, only set a new one 
+
+ This takes a possible pointer to the existing entry for the UID or SID
+ involved.
 ***********************************************************************/
 
-static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
+static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, 
+                                          int id_type, const char *ldap_dn, 
+                                          LDAPMessage *entry)
 {
-       pstring dn, sid_str, id_str;
+       char *dn = NULL;
+       pstring id_str;
        fstring type;
        LDAPMod **mods = NULL;
-       int rc;
-       int attempts = 0;
+       int rc = -1;
+       int ldap_op;
+       fstring sid_string;
+
+       sid_to_string( sid_string, sid );
+
+       if (ldap_dn) {
+               DEBUG(10, ("Adding new IDMAP mapping on DN: %s", ldap_dn));
+               ldap_op = LDAP_MOD_REPLACE;
+               dn = strdup(ldap_dn);
+       } else {
+               ldap_op = LDAP_MOD_ADD;
+               asprintf(&dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID), 
+                        sid_string, lp_ldap_idmap_suffix());
+       }
+       
+       if (!dn) {
+               DEBUG(0, ("ldap_set_mapping_internals: out of memory allocating DN!\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
 
        if ( id_type & ID_USERID ) 
-               fstrcpy( type, get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) );
+               fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
        else
-               fstrcpy( type, get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER ) );
-
-#if 0
-       snprintf(dn, sizeof(dn), "%s=%u,%s,%s", type, 
-               ((id_type & ID_USERID) ? id.uid : id.gid), 
-               ((id_type & ID_USERID) ? IDMAP_USER_SUFFIX : IDMAP_GROUP_SUFFIX ), 
-               lp_ldap_idmap_suffix());
-#else
-       snprintf(dn, sizeof(dn), "%s=%u,%s", type, 
-               ((id_type & ID_USERID) ? id.uid : id.gid), 
-               lp_ldap_idmap_suffix());
-#endif
+               fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
 
        snprintf(id_str, sizeof(id_str), "%u", ((id_type & ID_USERID) ? id.uid : id.gid));      
-       sid_to_string( sid_str, sid );
        
-       smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
-       smbldap_set_mod( &mods, LDAP_MOD_ADD, type, id_str );
        smbldap_set_mod( &mods, LDAP_MOD_ADD, 
-               get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), sid_str );
+                        "objectClass", LDAP_OBJ_IDMAP_ENTRY );
+       
+       smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
+                         entry, &mods, type, id_str );
 
-       do {
-               if ((rc = ldap_idmap_retry_open(&ldap_state, &attempts)) != LDAP_SUCCESS) 
-                       continue;
-               
-               rc = ldap_add_s(ldap_state.ldap_struct, dn, mods);
-       } while ((rc == LDAP_SERVER_DOWN) && (attempts <= 8));
+       smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
+                         entry, &mods,  
+                         get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), 
+                         sid_string );
+
+       switch(ldap_op)
+       {
+       case LDAP_MOD_ADD: 
+               smbldap_set_mod( &mods, LDAP_MOD_ADD, 
+                                "objectClass", LDAP_OBJ_SID_ENTRY );
+               rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
+               break;
+       case LDAP_MOD_REPLACE: 
+               rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
+               break;
+       }
 
        ldap_mods_free( mods, True );   
 
        if (rc != LDAP_SUCCESS) {
-               DEBUG(0,("ldap_set_mapping: Failed to create mapping from %s to %d [%s]\n",
-                       sid_str, ((id_type & ID_USERID) ? id.uid : id.gid), type));
+               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 create mapping from %s to %u [%s]\n",
+                       sid_string, (unsigned int)((id_type & ID_USERID) ? id.uid : id.gid), type));
+               DEBUG(0, ("ldap_set_mapping_internals: Error was: %s\n", ld_error ? ld_error : "(NULL)"));
                return NT_STATUS_UNSUCCESSFUL;
        }
                
        DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %d [%s]\n",
-               sid_str, ((id_type & ID_USERID) ? id.uid : id.gid), type));
+               sid_string, ((id_type & ID_USERID) ? id.uid : id.gid), type));
 
        return NT_STATUS_OK;
 }
 
+/***********************************************************************
+ 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) 
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+       char *dn = NULL;
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
+       const char *type;
+       const char *obj_class;
+       const char *posix_obj_class;
+       const char *suffix;
+       fstring sid_str;
+       fstring id_str;
+       pstring filter;
+       char **attr_list;
+       int rc;
+       int count;
+
+       /* try for a samba user or group mapping (looking for an entry with a SID) */
+       if ( id_type & ID_USERID ) {
+               obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
+               suffix = lp_ldap_suffix();
+               type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
+               posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
+               snprintf(id_str, sizeof(id_str), "%u", id.uid );        
+       }
+       else {
+               obj_class = LDAP_OBJ_GROUPMAP;
+               suffix = lp_ldap_group_suffix();
+               type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
+               posix_obj_class = LDAP_OBJ_POSIXGROUP;
+               snprintf(id_str, sizeof(id_str), "%u", id.gid );        
+       }
+       
+       sid_to_string(sid_str, sid);
+       snprintf(filter, sizeof(filter), 
+                "(|"
+                "(&(|(objectClass=%s)(|(objectClass=%s)(objectClass=%s)))(%s=%s))"
+                "(&(objectClass=%s)(%s=%s))"
+                ")", 
+                /* objectClasses that might contain a SID */
+                LDAP_OBJ_SID_ENTRY, LDAP_OBJ_IDMAP_ENTRY, obj_class, 
+                get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ), 
+                sid_str, 
+
+                /* objectClasses that might contain a Unix UID/GID */
+                posix_obj_class, 
+                /* Unix UID/GID specifier*/
+                type, 
+                /* actual ID */
+                id_str);
+
+       attr_list = get_attr_list( sidmap_attr_list );
+       rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
+                           filter, attr_list, 0, &result);
+       free_attr_list( attr_list );
+       
+       if (rc != LDAP_SUCCESS)
+               goto out;
+
+       count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
+       
+       /* fall back to looking up an idmap entry if we didn't find anything under the idmap
+          user or group suffix */
+
+       if (count == 1) {
+               entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
+       
+               dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
+               DEBUG(10, ("Found partial mapping entry at dn=%s, looking for %s\n", dn, type));
+
+               ret = ldap_set_mapping_internals(sid, id, id_type, dn, entry);
+
+               goto out;
+       } else if (count > 1) {
+               DEBUG(0, ("Too many entries trying to find DN to attach ldap \n"));
+               goto out;
+       }
+
+       ret = ldap_set_mapping_internals(sid, id, id_type, NULL, NULL);
+
+out:
+       if (result)
+               ldap_msgfree(result);
+       if (dn)
+               ldap_memfree(dn);
+       
+       return ret;
+}
 /*****************************************************************************
  Initialise idmap database. 
 *****************************************************************************/
 static NTSTATUS ldap_idmap_init( char *params )
 {
        fstring filter;
-#if 0
-       pstring dn;
-#endif
        int rc;
        char **attr_list;
        LDAPMessage *result = NULL;
        LDAPMod **mods = NULL;
        int count;
+       NTSTATUS nt_status;
 
-       /* parse out the server (assuming only parameter is a URI) */
+       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;
+       }
 
-       if ( params )
-               ldap_state.uri = smb_xstrdup( params );
-       else
-               ldap_state.uri = smb_xstrdup( "ldap://localhost/" );
-       
        /* see if the idmap suffix and sub entries exists */
        
        snprintf( filter, sizeof(filter), "(objectclass=%s)", LDAP_OBJ_IDPOOL );
        
        attr_list = get_attr_list( idpool_attr_list );
-       rc = ldap_idmap_search(&ldap_state, lp_ldap_idmap_suffix(), 
+       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.ldap_struct, result);
+       count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
 
        if ( count > 1 ) {
                DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
@@ -900,7 +604,6 @@ static NTSTATUS ldap_idmap_init( char *params )
                uid_t   luid, huid;
                gid_t   lgid, hgid;
                fstring uid_str, gid_str;
-               int attempts = 0;
                
                if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
                        DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
@@ -916,34 +619,9 @@ static NTSTATUS ldap_idmap_init( char *params )
                smbldap_set_mod( &mods, LDAP_MOD_ADD,
                        get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
                
-               do {
-                       if ((rc = ldap_idmap_retry_open(&ldap_state, &attempts)) != LDAP_SUCCESS) 
-                               continue;
-               
-                       rc = ldap_modify_s(ldap_state.ldap_struct, lp_ldap_idmap_suffix(), mods);
-               } while ((rc == LDAP_SERVER_DOWN) && (attempts <= 8));
+               rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
        }
        
-       /* we have the initial entry now; let's create the sub entries */ 
-       /* if they already exist then this will fail, but we don't care */
-       
-#if 0  /* commenting out for now, but I will come back to this --jerry */
-
-       mods = NULL;
-       snprintf( dn, sizeof(dn), "%s,%s", IDMAP_USER_SUFFIX, lp_ldap_idmap_suffix() );
-       smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_OU );
-       smbldap_set_mod( &mods, LDAP_MOD_ADD, "ou", "idmap people" );
-       ldap_add_s(ldap_state.ldap_struct, dn, mods);
-       ldap_mods_free( mods, True );
-       
-       mods = NULL;
-       snprintf( dn, sizeof(dn), "%s,%s", IDMAP_GROUP_SUFFIX, lp_ldap_idmap_suffix() );
-       smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_OU );
-       smbldap_set_mod( &mods, LDAP_MOD_ADD, "ou", "idmap group" );
-       ldap_add_s(ldap_state.ldap_struct, dn, mods);
-       ldap_mods_free( mods, True );
-#endif         
-
        return NT_STATUS_OK;
 }
 
@@ -953,14 +631,9 @@ static NTSTATUS ldap_idmap_init( char *params )
 
 static NTSTATUS ldap_idmap_close(void)
 {
-       if (ldap_state.ldap_struct != NULL) {
-               ldap_unbind_ext(ldap_state.ldap_struct, NULL, NULL);
-               ldap_state.ldap_struct = NULL;
-       }
 
-       SAFE_FREE( ldap_state.uri     );
-       SAFE_FREE( ldap_state.bind_dn );
-       SAFE_FREE( ldap_state.bind_secret );
+       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 */
index 095f5f0874c4a077ca583b12bdb633788e9b8169..ffc3db2a0ae0522c05358ef3bdd98486efe20d3e 100644 (file)
@@ -132,7 +132,6 @@ BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high)
  *THE CANONICAL* convert uid_t to SID function.
  check idmap if uid is in idmap range, otherwise falls back to
  the legacy algorithmic mapping.
- A special cache is used for uids that maps to Wellknown SIDs
  Returns SID pointer.
 *****************************************************************/  
 
@@ -204,7 +203,6 @@ NTSTATUS gid_to_sid(DOM_SID *sid, gid_t gid)
  *THE CANONICAL* convert SID to uid function.
  if it is a foreign sid or it is in idmap rid range check idmap,
  otherwise falls back to the legacy algorithmic mapping.
- A special cache is used for uids that maps to Wellknown SIDs
  Returns True if this name is a user sid and the conversion
  was done correctly, False if not.
 *****************************************************************/  
@@ -351,6 +349,7 @@ BOOL idmap_init_wellknown_sids(void)
        int num_entries=0;
        DOM_SID sid;
        unid_t id;
+       fstring sid_string;
 
        if (!(guest_account && *guest_account)) {
                DEBUG(1, ("NULL guest account!?!?\n"));
@@ -368,6 +367,8 @@ BOOL idmap_init_wellknown_sids(void)
        sid_append_rid(&sid, DOMAIN_USER_RID_GUEST);
 
        if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_USERID))) {
+               DEBUG(0, ("Failed to setup UID mapping for GUEST (%s) to (%u)\n", 
+                         sid_to_string(sid_string, &sid), (unsigned int)id.uid));
                passwd_free(&pass);
                return False;
        }
@@ -378,6 +379,8 @@ BOOL idmap_init_wellknown_sids(void)
        sid_copy(&sid, get_global_sam_sid());
        sid_append_rid(&sid, DOMAIN_GROUP_RID_GUESTS);
        if (!NT_STATUS_IS_OK(wellknown_id_init(&sid, id, ID_GROUPID))) {
+               DEBUG(0, ("Failed to setup GID mapping for Group DOMAIN GUESTS (%s) to (%u)\n", 
+                         sid_to_string(sid_string, &sid), (unsigned int)id.gid));
                passwd_free(&pass);
                return False;
        }
index e2fe2ac819c0ca42736a701c76fd934e9f37a675..6f549aab1c44aca48fdfb61533b0d10b7bdd0d6c 100644 (file)
@@ -842,9 +842,19 @@ void build_options(BOOL screen);
        if (!init_registry())
                exit(1);
 
+       /* Initialise the password backed before idmap and the global_sam_sid
+          to ensure that we fetch from ldap before we make a domain sid up */
+
        if(!initialize_password_db(False))
                exit(1);
 
+       if(!get_global_sam_sid()) {
+               DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
+               exit(1);
+       }
+
+       static_init_auth;
+
        {
                const char *idmap_back = lp_idmap_backend();
 
@@ -852,8 +862,10 @@ void build_options(BOOL screen);
                        exit(1);
        }
 
-       if (!idmap_init_wellknown_sids())
+       if (!idmap_init_wellknown_sids()) {
+               DEBUG(0,("ERROR: Samba failed to initialize it's 'well known' SID -> ID mapping tables.\n"));
                exit(1);
+       }
 
        static_init_rpc;
 
@@ -862,12 +874,6 @@ void build_options(BOOL screen);
        /* possibly reload the services file. */
        reload_services(True);
 
-       if(!get_global_sam_sid()) {
-               DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
-               exit(1);
-       }
-
-
        if (!init_account_policy()) {
                DEBUG(0,("Could not open account policy tdb.\n"));
                exit(1);
index 3fa27513472a0cd7d95fc1dbe356c815810f2edf..5b702f75912d79be436736bfe33342c8f7fcea86 100644 (file)
@@ -606,6 +606,12 @@ int main (int argc, char **argv)
                exit(1);
        }
 
+       /* Initialise the password backed before idmap and the global_sam_sid
+          to ensure that we fetch from ldap before we make a domain sid up */
+       
+       if(!initialize_password_db(False))
+               exit(1);
+
        if (!init_names())
                exit(1);