This is meant to be initialised to the size of the buffer.
[ira/wip.git] / source3 / passdb / pdb_ldap.c
index 75969fbbb2e4b9097a8ea8c168cf5d0fd673f2f7..8a2378f91b281fef28896fe2b931489ef009764e 100644 (file)
@@ -28,7 +28,6 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_PASSDB
 
-#ifdef HAVE_LDAP
 /* TODO:
 *  persistent connections: if using NSS LDAP, many connections are made
 *      however, using only one within Samba would be nice
@@ -75,6 +74,8 @@ struct ldapsam_privates {
 
        char *bind_dn;
        char *bind_secret;
+
+       unsigned int num_failures;
 };
 
 #define LDAPSAM_DONT_PING_TIME 10      /* ping only all 10 seconds */
@@ -167,7 +168,7 @@ static int ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP **
        int version;
        BOOL ldap_v3 = False;
 
-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#ifdef HAVE_LDAP_INITIALIZE
        DEBUG(10, ("ldapsam_open_connection: %s\n", ldap_state->uri));
        
        if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
@@ -407,18 +408,21 @@ static int ldapsam_connect_system(struct ldapsam_privates *ldap_state, LDAP * ld
        rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
 
        if (rc != LDAP_SUCCESS) {
-               char *ld_error;
+               char *ld_error = NULL;
                ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
                                &ld_error);
-               DEBUG(0,
+               DEBUG(ldap_state->num_failures ? 2 : 0,
                      ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
-                              ldap_dn, ldap_err2string(rc),
+                              ldap_dn ? ld_error : "(unknown)", ldap_err2string(rc),
                               ld_error));
-               free(ld_error);
+               SAFE_FREE(ld_error);
+               ldap_state->num_failures++;
                return rc;
        }
-       
-       DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
+
+       ldap_state->num_failures = 0;
+
+       DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
        return rc;
 }
 
@@ -439,7 +443,7 @@ static int ldapsam_open(struct ldapsam_privates *ldap_state)
 
        if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + LDAPSAM_DONT_PING_TIME) < time(NULL))) {
                struct sockaddr_un addr;
-               socklen_t len;
+               socklen_t len = sizeof(addr);
                int sd;
                if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
                    getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
@@ -500,13 +504,23 @@ static int ldapsam_retry_open(struct ldapsam_privates *ldap_state, int *attempts
        SMB_ASSERT(ldap_state && attempts);
                
        if (*attempts != 0) {
-               /* we retry after 0.5, 2, 4.5, 8, 12.5, 18, 24.5 seconds */
-               msleep((((*attempts)*(*attempts))/2)*1000);
+               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 = ldapsam_open(ldap_state))) {
-               DEBUG(0,("Connection to LDAP Server failed for the %d try!\n",*attempts));
+               DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
                return rc;
        } 
        
@@ -530,7 +544,7 @@ static int ldapsam_search(struct ldapsam_privates *ldap_state,
                        continue;
                
                rc = ldap_search_s(ldap_state->ldap_struct, base, scope, 
-                                  filter, attrs, attrsonly, res);
+                                  filter, (char **)attrs, attrsonly, res);
        }
        
        if (rc == LDAP_SERVER_DOWN) {
@@ -613,6 +627,7 @@ static int ldapsam_delete(struct ldapsam_privates *ldap_state, char *dn)
        return rc;
 }
 
+#ifdef LDAP_EXOP_X_MODIFY_PASSWD
 static int ldapsam_extended_operation(struct ldapsam_privates *ldap_state, LDAP_CONST char *reqoid, struct berval *reqdata, LDAPControl **serverctrls, LDAPControl **clientctrls, char **retoidp, struct berval **retdatap)
 {
        int             rc = LDAP_SERVER_DOWN;
@@ -636,6 +651,7 @@ static int ldapsam_extended_operation(struct ldapsam_privates *ldap_state, LDAP_
                
        return rc;
 }
+#endif
 
 /*******************************************************************
  run the search by name.
@@ -650,10 +666,14 @@ static int ldapsam_search_one_user (struct ldapsam_privates *ldap_state, const c
        rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope, filter, attr, 0, result);
 
        if (rc != LDAP_SUCCESS) {
-               DEBUG(0,("ldapsam_search_one_user: Problem during the LDAP search: %s\n", 
-                       ldap_err2string (rc)));
+               char *ld_error = NULL;
+               ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+                               &ld_error);
+               DEBUG(0,("ldapsam_search_one_user: Problem during the LDAP search: %s (%s)\n", 
+                       ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
                DEBUG(3,("ldapsam_search_one_user: Query was: %s, %s\n", lp_ldap_suffix(), 
                        filter));
+               SAFE_FREE(ld_error);
        }
        
        return rc;
@@ -915,8 +935,13 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
        ldap_mods_free(mods, 1);
 
        if (rc != LDAP_SUCCESS) {
-               DEBUG(0, ("could not delete attributes for %s, error: %s\n",
-                         dn, ldap_err2string(rc)));
+               char *ld_error = NULL;
+               ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+                               &ld_error);
+               
+               DEBUG(0, ("could not delete attributes for %s, error: %s (%s)\n",
+                         dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
+               SAFE_FREE(ld_error);
                ldap_memfree(dn);
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -1279,6 +1304,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
   * If we are updating the record AND the attribute is CHANGED.
   * If we are adding   the record AND it is SET or CHANGED (ie not default)
 *********************************************************************/
+#ifdef LDAP_EXOP_X_MODIFY_PASSWD
 static BOOL need_ldap_mod(BOOL pdb_add, const SAM_ACCOUNT * sampass, enum pdb_elements element) {
        if (pdb_add) {
                return (!IS_SAM_DEFAULT(sampass, element));
@@ -1286,6 +1312,7 @@ static BOOL need_ldap_mod(BOOL pdb_add, const SAM_ACCOUNT * sampass, enum pdb_el
                return IS_SAM_CHANGED(sampass, element);
        }
 }
+#endif
 
 /**********************************************************************
   Set attribute to newval in LDAP, regardless of what value the
@@ -1293,16 +1320,10 @@ static BOOL need_ldap_mod(BOOL pdb_add, const SAM_ACCOUNT * sampass, enum pdb_el
 *********************************************************************/
 static void make_ldap_mod(LDAP *ldap_struct, LDAPMessage *existing,
                          LDAPMod ***mods,
-                         const SAM_ACCOUNT *sampass, BOOL pdb_add,
-                         enum pdb_elements element,
                          const char *attribute, const char *newval)
 {
        char **values = NULL;
 
-       if (!need_ldap_mod(pdb_add, sampass, element)) {
-               return;
-       }
-
        if (existing != NULL) {
                values = ldap_get_values(ldap_struct, existing, attribute);
        }
@@ -1349,7 +1370,8 @@ Initialize SAM_ACCOUNT from an LDAP query
 static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, 
                                LDAPMessage *existing,
                                LDAPMod *** mods, const SAM_ACCOUNT * sampass,
-                               BOOL pdb_add)
+                               BOOL (*need_update)(const SAM_ACCOUNT *,
+                                                   enum pdb_elements))
 {
        pstring temp;
        uint32 rid;
@@ -1365,8 +1387,10 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
         * took out adding "objectclass: sambaAccount"
         * do this on a per-mod basis
         */
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_USERNAME, "uid", pdb_get_username(sampass));
+       if (need_update(sampass, PDB_USERNAME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods, 
+                             "uid", pdb_get_username(sampass));
+
        DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
 
        rid = pdb_get_user_rid(sampass);
@@ -1378,7 +1402,7 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                        rid = ldapsam_get_next_available_nua_rid(ldap_state);
                        if (rid == 0) {
                                DEBUG(0, ("NO user RID specified on account %s, and "
-                                         "findining next available NUA RID failed, "
+                                         "finding next available NUA RID failed, "
                                          "cannot store!\n",
                                          pdb_get_username(sampass)));
                                ldap_mods_free(*mods, 1);
@@ -1393,8 +1417,10 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
        }
 
        slprintf(temp, sizeof(temp) - 1, "%i", rid);
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_USERSID, "rid", temp);
+
+       if (need_update(sampass, PDB_USERSID))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "rid", temp);
 
 
        rid = pdb_get_group_rid(sampass);
@@ -1413,8 +1439,10 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
        }
 
        slprintf(temp, sizeof(temp) - 1, "%i", rid);
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_GROUPSID, "primaryGroupID", temp);
+
+       if (need_update(sampass, PDB_GROUPSID))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "primaryGroupID", temp);
 
        /* displayName, cn, and gecos should all be the same
         *  most easily accomplished by giving them the same OID
@@ -1424,81 +1452,100 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
         *  it does not exist.
         */
 
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_FULLNAME, "displayName",
-                     pdb_get_fullname(sampass));
+       if (need_update(sampass, PDB_FULLNAME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "displayName", pdb_get_fullname(sampass));
 
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_ACCTDESC, "description",
-                     pdb_get_acct_desc(sampass));
+       if (need_update(sampass, PDB_ACCTDESC))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "description", pdb_get_acct_desc(sampass));
 
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_WORKSTATIONS, "userWorkstations",
-                     pdb_get_workstations(sampass));
+       if (need_update(sampass, PDB_WORKSTATIONS))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "userWorkstations", pdb_get_workstations(sampass));
 
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_SMBHOME, "smbHome",
-                     pdb_get_homedir(sampass));
+       if (need_update(sampass, PDB_SMBHOME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "smbHome", pdb_get_homedir(sampass));
                        
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_DRIVE, "homeDrive",
-                     pdb_get_dir_drive(sampass));
+       if (need_update(sampass, PDB_DRIVE))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "homeDrive", pdb_get_dir_drive(sampass));
 
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_LOGONSCRIPT, "scriptPath",
-                     pdb_get_logon_script(sampass));
+       if (need_update(sampass, PDB_LOGONSCRIPT))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "scriptPath", pdb_get_logon_script(sampass));
 
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_PROFILE, "profilePath",
-                     pdb_get_profile_path(sampass));
+       if (need_update(sampass, PDB_PROFILE))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "profilePath", pdb_get_profile_path(sampass));
 
        slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_LOGONTIME, "logonTime", temp);
+
+       if (need_update(sampass, PDB_LOGONTIME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "logonTime", temp);
 
        slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_LOGOFFTIME, "logoffTime", temp);
+
+       if (need_update(sampass, PDB_LOGOFFTIME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "logoffTime", temp);
 
        slprintf (temp, sizeof (temp) - 1, "%li",
                  pdb_get_kickoff_time(sampass));
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_KICKOFFTIME, "kickoffTime", temp);
+
+       if (need_update(sampass, PDB_KICKOFFTIME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "kickoffTime", temp);
 
        slprintf (temp, sizeof (temp) - 1, "%li",
                  pdb_get_pass_can_change_time(sampass));
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_CANCHANGETIME, "pwdCanChange", temp);
+
+       if (need_update(sampass, PDB_CANCHANGETIME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "pwdCanChange", temp);
 
        slprintf (temp, sizeof (temp) - 1, "%li",
                  pdb_get_pass_must_change_time(sampass));
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_MUSTCHANGETIME, "pwdMustChange", temp);
+
+       if (need_update(sampass, PDB_MUSTCHANGETIME))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "pwdMustChange", temp);
 
        if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))||
            (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
 
                pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass),
                               pdb_get_acct_ctrl(sampass));
-               make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                             PDB_LMPASSWD, "lmPassword", temp);
+
+               if (need_update(sampass, PDB_LMPASSWD))
+                       make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                                     "lmPassword", temp);
 
                pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass),
                               pdb_get_acct_ctrl(sampass));
-               make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                             PDB_NTPASSWD, "ntPassword", temp);
+
+               if (need_update(sampass, PDB_NTPASSWD))
+                       make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                                     "ntPassword", temp);
 
                slprintf (temp, sizeof (temp) - 1, "%li",
                          pdb_get_pass_last_set_time(sampass));
-               make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                             PDB_PASSLASTSET, "pwdLastSet", temp);
+
+               if (need_update(sampass, PDB_PASSLASTSET))
+                       make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                                     "pwdLastSet", temp);
        }
 
        /* FIXME: Hours stuff goes in LDAP  */
-       make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
-                     PDB_ACCTCTRL, "acctFlags",
-                     pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
-                                           NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
+       if (need_update(sampass, PDB_ACCTCTRL))
+               make_ldap_mod(ldap_state->ldap_struct, existing, mods,
+                             "acctFlags",
+                             pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
+                                                   NEW_PW_FORMAT_SPACE_PADDED_LEN));
+
        return True;
 }
 
@@ -1848,15 +1895,15 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
                }
                
                if (rc!=LDAP_SUCCESS) {
-                       char *ld_error;
+                       char *ld_error = NULL;
                        ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
                                        &ld_error);
                        DEBUG(1,
                              ("failed to %s user dn= %s with: %s\n\t%s\n",
                               ldap_op == LDAP_MOD_ADD ? "add" : "modify",
                               dn, ldap_err2string(rc),
-                              ld_error));
-                       free(ld_error);
+                              ld_error?ld_error:"unknown"));
+                       SAFE_FREE(ld_error);
                        return NT_STATUS_UNSUCCESSFUL;
                }  
        }
@@ -1941,6 +1988,16 @@ static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_A
        return ret;
 }
 
+/**********************************************************************
+  Helper function to determine for update_sam_account whether
+  we need LDAP modification.
+*********************************************************************/
+static BOOL element_is_changed(const SAM_ACCOUNT *sampass,
+                              enum pdb_elements element)
+{
+       return IS_SAM_CHANGED(sampass, element);
+}
+
 /**********************************************************************
 Update SAM_ACCOUNT 
 *********************************************************************/
@@ -1968,7 +2025,8 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A
        entry = ldap_first_entry(ldap_state->ldap_struct, result);
        dn = ldap_get_dn(ldap_state->ldap_struct, entry);
 
-       if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd, False)) {
+       if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
+                               element_is_changed)) {
                DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
                ldap_msgfree(result);
                return NT_STATUS_UNSUCCESSFUL;
@@ -1986,9 +2044,13 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A
        ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, False);
        ldap_mods_free(mods,1);
 
-       if (NT_STATUS_IS_ERR(ret)) {
-               DEBUG(0,("failed to modify user with uid = %s\n",
-                                       pdb_get_username(newpwd)));
+       if (!NT_STATUS_IS_OK(ret)) {
+               char *ld_error = NULL;
+               ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+                               &ld_error);
+               DEBUG(0,("failed to modify user with uid = %s, error: %s (%s)\n",
+                        pdb_get_username(newpwd), ld_error?ld_error:"(unknwon)", ldap_err2string(rc)));
+               SAFE_FREE(ld_error);
                return ret;
        }
 
@@ -1997,6 +2059,17 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_A
        return NT_STATUS_OK;
 }
 
+/**********************************************************************
+  Helper function to determine for update_sam_account whether
+  we need LDAP modification.
+*********************************************************************/
+static BOOL element_is_set_or_changed(const SAM_ACCOUNT *sampass,
+                                     enum pdb_elements element)
+{
+       return (IS_SAM_SET(sampass, element) ||
+               IS_SAM_CHANGED(sampass, element));
+}
+
 /**********************************************************************
 Add SAM_ACCOUNT to LDAP 
 *********************************************************************/
@@ -2067,10 +2140,10 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
                 }
        }
 
-       if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd, True)) {
+       if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
+                               element_is_set_or_changed)) {
                DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
                ldap_msgfree(result);
-               ldap_mods_free(mods, 1);
                return NT_STATUS_UNSUCCESSFUL;          
        }
        
@@ -2134,11 +2207,15 @@ static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
                            filter, group_attr, 0, result);
 
        if (rc != LDAP_SUCCESS) {
+               char *ld_error = NULL;
+               ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+                               &ld_error);
                DEBUG(0, ("ldapsam_search_one_group: "
-                         "Problem during the LDAP search: %s\n",
-                         ldap_err2string(rc)));
+                         "Problem during the LDAP search: LDAP error: %s (%s)",
+                         ld_error?ld_error:"(unknown)", ldap_err2string(rc)));
                DEBUG(3, ("ldapsam_search_one_group: Query was: %s, %s\n",
                          lp_ldap_suffix(), filter));
+               SAFE_FREE(ld_error);
        }
 
        return rc;
@@ -2190,7 +2267,8 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
                temp[0] = '\0';
                if (!get_single_attribute(ldap_state->ldap_struct, entry, "cn",
                                          temp)) {
-                       DEBUG(0, ("Attributes displayName and cn not found for gidNumber(%i)\n",map->gid));
+                       DEBUG(0, ("Attributes cn not found either "
+                                 "for gidNumber(%i)\n",map->gid));
                        return False;
                }
        }
@@ -2209,8 +2287,9 @@ static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
        return True;
 }
 
-static BOOL init_ldap_from_group(struct ldapsam_privates *ldap_state,
-                                LDAPMod ***mods, int ldap_op,
+static BOOL init_ldap_from_group(LDAP *ldap_struct,
+                                LDAPMessage *existing,
+                                LDAPMod ***mods,
                                 const GROUP_MAP *map)
 {
        pstring tmp;
@@ -2223,13 +2302,12 @@ static BOOL init_ldap_from_group(struct ldapsam_privates *ldap_state,
        *mods = NULL;
 
        sid_to_string(tmp, &map->sid);
-       make_a_mod(mods, ldap_op, "ntSid", tmp);
-
+       make_ldap_mod(ldap_struct, existing, mods, "ntSid", tmp);
        snprintf(tmp, sizeof(tmp)-1, "%i", map->sid_name_use);
-       make_a_mod(mods, ldap_op, "ntGroupType", tmp);
+       make_ldap_mod(ldap_struct, existing, mods, "ntGroupType", tmp);
 
-       make_a_mod(mods, ldap_op, "displayName", map->nt_name);
-       make_a_mod(mods, ldap_op, "description", map->comment);
+       make_ldap_mod(ldap_struct, existing, mods, "displayName", map->nt_name);
+       make_ldap_mod(ldap_struct, existing, mods, "description", map->comment);
 
        return True;
 }
@@ -2312,8 +2390,8 @@ static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
        /* TODO: Escaping of name? */
 
        snprintf(filter, sizeof(filter)-1,
-                "(&(objectClass=sambaGroupMapping)(|(displayName=%s)(cn=%s))",
-                name,name);
+                "(&(objectClass=sambaGroupMapping)(|(displayName=%s)(cn=%s)))",
+                name, name);
 
        return ldapsam_getgroup(methods, filter, map);
 }
@@ -2368,14 +2446,17 @@ static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
        tmp = ldap_get_dn(ldap_state->ldap_struct, entry);
        pstrcpy(dn, tmp);
        ldap_memfree(tmp);
-       ldap_msgfree(result);
 
-       if (!init_ldap_from_group(ldap_state, &mods, LDAP_MOD_ADD, map)) {
+       if (!init_ldap_from_group(ldap_state->ldap_struct,
+                                 result, &mods, map)) {
                DEBUG(0, ("init_ldap_from_group failed!\n"));
                ldap_mods_free(mods, 1);
+               ldap_msgfree(result);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       ldap_msgfree(result);
+
        if (mods == NULL) {
                DEBUG(0, ("mods is empty\n"));
                return NT_STATUS_UNSUCCESSFUL;
@@ -2388,7 +2469,12 @@ static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
        ldap_mods_free(mods, 1);
 
        if (rc != LDAP_SUCCESS) {
-               DEBUG(0, ("failed to modify group %i\n", map->gid));
+               char *ld_error = NULL;
+               ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+                               &ld_error);
+               DEBUG(0, ("failed to add group %i error: %s (%s)\n", map->gid, 
+                         ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
+               SAFE_FREE(ld_error);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
@@ -2407,40 +2493,46 @@ static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
        LDAPMessage *entry;
        LDAPMod **mods;
 
-       if (!init_ldap_from_group(ldap_state, &mods, LDAP_MOD_REPLACE, map)) {
-               DEBUG(0, ("init_ldap_from_group failed\n"));
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       if (mods == NULL) {
-               DEBUG(4, ("mods is empty: nothing to do\n"));
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
        rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
 
        if (rc != LDAP_SUCCESS) {
-               ldap_mods_free(mods, 1);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
        if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
                DEBUG(0, ("No group to modify!\n"));
                ldap_msgfree(result);
-               ldap_mods_free(mods, 1);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
        entry = ldap_first_entry(ldap_state->ldap_struct, result);
        dn = ldap_get_dn(ldap_state->ldap_struct, entry);
-        ldap_msgfree(result);
+
+       if (!init_ldap_from_group(ldap_state->ldap_struct,
+                                 result, &mods, map)) {
+               DEBUG(0, ("init_ldap_from_group failed\n"));
+               ldap_msgfree(result);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       ldap_msgfree(result);
+
+       if (mods == NULL) {
+               DEBUG(4, ("mods is empty: nothing to do\n"));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        rc = ldapsam_modify(ldap_state, dn, mods);
 
        ldap_mods_free(mods, 1);
 
        if (rc != LDAP_SUCCESS) {
-               DEBUG(0, ("failed to modify group %i\n", map->gid));
+               char *ld_error = NULL;
+               ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
+                               &ld_error);
+               DEBUG(0, ("failed to modify group %i error: %s (%s)\n", map->gid, 
+                         ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
+               SAFE_FREE(ld_error);
        }
 
        DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
@@ -2680,20 +2772,9 @@ NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method
        return NT_STATUS_OK;
 }
 
-
-#else
-
-NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
+int pdb_ldap_init(void)
 {
-       DEBUG(0, ("ldap not detected at configure time, ldapsam not availalble!\n"));
-       return NT_STATUS_UNSUCCESSFUL;
-}
-
-NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
-{
-       DEBUG(0, ("ldap not dectected at configure time, ldapsam_nua not available!\n"));
-       return NT_STATUS_UNSUCCESSFUL;
+       smb_register_passdb("ldapsam", pdb_init_ldapsam, PASSDB_INTERFACE_VERSION);
+       smb_register_passdb("ldapsam_nua", pdb_init_ldapsam_nua, PASSDB_INTERFACE_VERSION);
+       return True;
 }
-
-
-#endif