s3-pdb_ldap: fix memleak.
[metze/samba/wip.git] / source3 / passdb / pdb_ldap.c
index 35793257697785ac7b6be7150abf864ec0616c74..a66ae9791ac6abafe0864a8b52af5a1cdaa0aea1 100644 (file)
@@ -336,7 +336,7 @@ int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
                                          const char **attr)
 {
        char *filter = NULL;
-       char *escape_user = escape_ldap_string_alloc(user);
+       char *escape_user = escape_ldap_string(talloc_tos(), user);
        int ret = -1;
 
        if (!escape_user) {
@@ -350,7 +350,7 @@ int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
        filter = talloc_asprintf(talloc_tos(), "(&%s%s)", "(uid=%u)",
                get_objclass_filter(ldap_state->schema_ver));
        if (!filter) {
-               SAFE_FREE(escape_user);
+               TALLOC_FREE(escape_user);
                return LDAP_NO_MEMORY;
        }
        /*
@@ -360,7 +360,7 @@ int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
 
        filter = talloc_all_string_sub(talloc_tos(),
                                filter, "%u", escape_user);
-       SAFE_FREE(escape_user);
+       TALLOC_FREE(escape_user);
        if (!filter) {
                return LDAP_NO_MEMORY;
        }
@@ -540,7 +540,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
        uint32 hours_len;
        uint8           hours[MAX_HOURS_LEN];
        char *temp = NULL;
-       LOGIN_CACHE     *cache_entry = NULL;
+       struct login_cache cache_entry;
        uint32          pwHistLen;
        bool expand_explicit = lp_passdb_expand_explicit();
        bool ret = false;
@@ -560,7 +560,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
                goto fn_exit;
        }
 
-       if (!(username = smbldap_talloc_smallest_attribute(priv2ld(ldap_state),
+       if (!(username = smbldap_talloc_first_attribute(priv2ld(ldap_state),
                                        entry,
                                        "uid",
                                        ctx))) {
@@ -609,7 +609,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
                }
        }
 
-       if (pdb_get_init_flags(sampass,PDB_USERSID) == PDB_DEFAULT) {
+       if (IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
                DEBUG(1, ("init_sam_from_ldap: no %s or %s attribute found for this user %s\n", 
                        get_userattr_key2string(ldap_state->schema_ver,
                                LDAP_ATTR_USER_SID),
@@ -902,7 +902,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
 
        pwHistLen = 0;
 
-       pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+       pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
        if (pwHistLen > 0){
                uint8 *pwhist = NULL;
                int i;
@@ -915,9 +915,9 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
 
                pwHistLen = MIN(pwHistLen, MAX_PW_HISTORY_LEN);
 
-               if ((pwhist = TALLOC_ARRAY(ctx, uint8,
-                                       pwHistLen * PW_HISTORY_ENTRY_LEN)) ==
-                               NULL){
+               pwhist = TALLOC_ARRAY(ctx, uint8,
+                                     pwHistLen * PW_HISTORY_ENTRY_LEN);
+               if (pwhist == NULL) {
                        DEBUG(0, ("init_sam_from_ldap: talloc failed!\n"));
                        goto fn_exit;
                }
@@ -1029,6 +1029,17 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
        }
 
        if (lp_parm_bool(-1, "ldapsam", "trusted", False)) {
+               struct passwd unix_pw;
+               bool have_uid = false;
+               bool have_gid = false;
+               DOM_SID mapped_gsid;
+               const DOM_SID *primary_gsid;
+
+               ZERO_STRUCT(unix_pw);
+
+               unix_pw.pw_name = username;
+               unix_pw.pw_passwd = discard_const_p(char, "x");
+
                temp = smbldap_talloc_single_attribute(
                                priv2ld(ldap_state),
                                entry,
@@ -1036,8 +1047,68 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
                                ctx);
                if (temp) {
                        /* We've got a uid, feed the cache */
-                       uid_t uid = strtoul(temp, NULL, 10);
-                       store_uid_sid_cache(pdb_get_user_sid(sampass), uid);
+                       unix_pw.pw_uid = strtoul(temp, NULL, 10);
+                       have_uid = true;
+               }
+               temp = smbldap_talloc_single_attribute(
+                               priv2ld(ldap_state),
+                               entry,
+                               "gidNumber",
+                               ctx);
+               if (temp) {
+                       /* We've got a uid, feed the cache */
+                       unix_pw.pw_gid = strtoul(temp, NULL, 10);
+                       have_gid = true;
+               }
+               unix_pw.pw_gecos = smbldap_talloc_single_attribute(
+                               priv2ld(ldap_state),
+                               entry,
+                               "gecos",
+                               ctx);
+               if (unix_pw.pw_gecos) {
+                       unix_pw.pw_gecos = fullname;
+               }
+               unix_pw.pw_dir = smbldap_talloc_single_attribute(
+                               priv2ld(ldap_state),
+                               entry,
+                               "homeDirectory",
+                               ctx);
+               if (unix_pw.pw_dir) {
+                       unix_pw.pw_dir = discard_const_p(char, "");
+               }
+               unix_pw.pw_shell = smbldap_talloc_single_attribute(
+                               priv2ld(ldap_state),
+                               entry,
+                               "loginShell",
+                               ctx);
+               if (unix_pw.pw_shell) {
+                       unix_pw.pw_shell = discard_const_p(char, "");
+               }
+
+               if (have_uid && have_gid) {
+                       sampass->unix_pw = tcopy_passwd(sampass, &unix_pw);
+               } else {
+                       sampass->unix_pw = Get_Pwnam_alloc(sampass, unix_pw.pw_name);
+               }
+
+               if (sampass->unix_pw == NULL) {
+                       DEBUG(0,("init_sam_from_ldap: Failed to find Unix account for %s\n",
+                                pdb_get_username(sampass)));
+                       goto fn_exit;
+               }
+
+               store_uid_sid_cache(pdb_get_user_sid(sampass),
+                                   sampass->unix_pw->pw_uid);
+               idmap_cache_set_sid2uid(pdb_get_user_sid(sampass),
+                                       sampass->unix_pw->pw_uid);
+
+               gid_to_sid(&mapped_gsid, sampass->unix_pw->pw_gid);
+               primary_gsid = pdb_get_group_sid(sampass);
+               if (primary_gsid && sid_equal(primary_gsid, &mapped_gsid)) {
+                       store_gid_sid_cache(primary_gsid,
+                                           sampass->unix_pw->pw_gid);
+                       idmap_cache_set_sid2uid(primary_gsid,
+                                               sampass->unix_pw->pw_gid);
                }
        }
 
@@ -1049,7 +1120,7 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
        }
 
        /* see if we have newer updates */
-       if (!(cache_entry = login_cache_read(sampass))) {
+       if (!login_cache_read(sampass, &cache_entry)) {
                DEBUG (9, ("No cache entry, bad count = %u, bad time = %u\n",
                           (unsigned int)pdb_get_bad_password_count(sampass),
                           (unsigned int)pdb_get_bad_password_time(sampass)));
@@ -1059,10 +1130,10 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
 
        DEBUG(7, ("ldap time is %u, cache time is %u, bad time = %u\n",
                  (unsigned int)ldap_entry_time,
-                 (unsigned int)cache_entry->entry_timestamp,
-                 (unsigned int)cache_entry->bad_password_time));
+                 (unsigned int)cache_entry.entry_timestamp,
+                 (unsigned int)cache_entry.bad_password_time));
 
-       if (ldap_entry_time > cache_entry->entry_timestamp) {
+       if (ldap_entry_time > cache_entry.entry_timestamp) {
                /* cache is older than directory , so
                   we need to delete the entry but allow the
                   fields to be written out */
@@ -1071,13 +1142,13 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
                /* read cache in */
                pdb_set_acct_ctrl(sampass,
                                  pdb_get_acct_ctrl(sampass) |
-                                 (cache_entry->acct_ctrl & ACB_AUTOLOCK),
+                                 (cache_entry.acct_ctrl & ACB_AUTOLOCK),
                                  PDB_SET);
                pdb_set_bad_password_count(sampass,
-                                          cache_entry->bad_password_count,
+                                          cache_entry.bad_password_count,
                                           PDB_SET);
                pdb_set_bad_password_time(sampass,
-                                         cache_entry->bad_password_time,
+                                         cache_entry.bad_password_time,
                                          PDB_SET);
        }
 
@@ -1086,7 +1157,6 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
   fn_exit:
 
        TALLOC_FREE(ctx);
-       SAFE_FREE(cache_entry);
        return ret;
 }
 
@@ -1327,7 +1397,7 @@ static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                if (need_update(sampass, PDB_PWHISTORY)) {
                        char *pwstr = NULL;
                        uint32 pwHistLen = 0;
-                       pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen);
+                       pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
 
                        pwstr = SMB_MALLOC_ARRAY(char, 1024);
                        if (!pwstr) {
@@ -1404,7 +1474,7 @@ static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                uint16 badcount = pdb_get_bad_password_count(sampass);
                time_t badtime = pdb_get_bad_password_time(sampass);
                uint32 pol;
-               pdb_get_account_policy(AP_BAD_ATTEMPT_LOCKOUT, &pol);
+               pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &pol);
 
                DEBUG(3, ("updating bad password fields, policy=%u, count=%u, time=%u\n",
                        (unsigned int)pol, (unsigned int)badcount, (unsigned int)badtime));
@@ -1440,7 +1510,7 @@ static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                        DEBUG(7, ("bad password count is reset, deleting login cache entry for %s\n", pdb_get_nt_username(sampass)));
                        login_cache_delentry(sampass);
                } else {
-                       LOGIN_CACHE cache_entry;
+                       struct login_cache cache_entry;
 
                        cache_entry.entry_timestamp = time(NULL);
                        cache_entry.acct_ctrl = pdb_get_acct_ctrl(sampass);
@@ -1448,7 +1518,7 @@ static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
                        cache_entry.bad_password_time = badtime;
 
                        DEBUG(7, ("Updating bad password count and time in login cache\n"));
-                       login_cache_write(sampass, cache_entry);
+                       login_cache_write(sampass, &cache_entry);
                }
        }
 
@@ -1488,6 +1558,16 @@ static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list,
        (*attr_list)[i+1] = NULL;
 }
 
+static void ldapsam_add_unix_attributes(TALLOC_CTX *mem_ctx,
+                                       const char ***attr_list)
+{
+       append_attr(mem_ctx, attr_list, "uidNumber");
+       append_attr(mem_ctx, attr_list, "gidNumber");
+       append_attr(mem_ctx, attr_list, "homeDirectory");
+       append_attr(mem_ctx, attr_list, "loginShell");
+       append_attr(mem_ctx, attr_list, "gecos");
+}
+
 /**********************************************************************
 Get struct samu entry from LDAP by username.
 *********************************************************************/
@@ -1506,7 +1586,7 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, struct samu
        append_attr(user, &attr_list,
                    get_userattr_key2string(ldap_state->schema_ver,
                                            LDAP_ATTR_MOD_TIMESTAMP));
-       append_attr(user, &attr_list, "uidNumber");
+       ldapsam_add_unix_attributes(user, &attr_list);
        rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result,
                                           attr_list);
        TALLOC_FREE( attr_list );
@@ -1563,7 +1643,7 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state,
                                    get_userattr_key2string(
                                            ldap_state->schema_ver,
                                            LDAP_ATTR_MOD_TIMESTAMP));
-                       append_attr(tmp_ctx, &attr_list, "uidNumber");
+                       ldapsam_add_unix_attributes(tmp_ctx, &attr_list);
                        rc = ldapsam_search_suffix_by_sid(ldap_state, sid,
                                                          result, attr_list);
                        TALLOC_FREE(tmp_ctx);
@@ -1701,6 +1781,7 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
                char *utf8_password;
                char *utf8_dn;
                size_t converted_size;
+               int ret;
 
                if (!ldap_state->is_nds_ldap) {
 
@@ -1732,14 +1813,31 @@ static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods,
                }
 
                if ((ber_printf (ber, "{") < 0) ||
-                   (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, utf8_dn) < 0) ||
-                   (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, utf8_password) < 0) ||
-                   (ber_printf (ber, "n}") < 0)) {
-                       DEBUG(0,("ldapsam_modify_entry: ber_printf returns a value <0\n"));
-                       ber_free(ber,1);
-                       TALLOC_FREE(utf8_dn);
-                       TALLOC_FREE(utf8_password);
-                       return NT_STATUS_UNSUCCESSFUL;
+                   (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
+                                utf8_dn) < 0)) {
+                       DEBUG(0,("ldapsam_modify_entry: ber_printf returns a "
+                                "value <0\n"));
+                       ber_free(ber,1);
+                       TALLOC_FREE(utf8_dn);
+                       TALLOC_FREE(utf8_password);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+
+               if ((utf8_password != NULL) && (*utf8_password != '\0')) {
+                       ret = ber_printf(ber, "ts}",
+                                        LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
+                                        utf8_password);
+               } else {
+                       ret = ber_printf(ber, "}");
+               }
+
+               if (ret < 0) {
+                       DEBUG(0,("ldapsam_modify_entry: ber_printf returns a "
+                                "value <0\n"));
+                       ber_free(ber,1);
+                       TALLOC_FREE(utf8_dn);
+                       TALLOC_FREE(utf8_password);
+                       return NT_STATUS_UNSUCCESSFUL;
                }
 
                if ((rc = ber_flatten (ber, &bv))<0) {
@@ -1968,6 +2066,18 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struc
  - The "rename user script" has full responsibility for changing everything
 ***************************************************************************/
 
+static NTSTATUS ldapsam_del_groupmem(struct pdb_methods *my_methods,
+                                    TALLOC_CTX *tmp_ctx,
+                                    uint32 group_rid,
+                                    uint32 member_rid);
+
+static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
+                                              TALLOC_CTX *mem_ctx,
+                                              struct samu *user,
+                                              DOM_SID **pp_sids,
+                                              gid_t **pp_gids,
+                                              size_t *p_num_groups);
+
 static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods,
                                           struct samu *old_acct,
                                           const char *newname)
@@ -2120,18 +2230,18 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct s
        /* does the entry already exist but without a samba attributes?
           we need to return the samba attributes here */
 
-       escape_user = escape_ldap_string_alloc( username );
+       escape_user = escape_ldap_string(talloc_tos(), username);
        filter = talloc_strdup(attr_list, "(uid=%u)");
        if (!filter) {
                status = NT_STATUS_NO_MEMORY;
                goto fn_exit;
        }
        filter = talloc_all_string_sub(attr_list, filter, "%u", escape_user);
+       TALLOC_FREE(escape_user);
        if (!filter) {
                status = NT_STATUS_NO_MEMORY;
                goto fn_exit;
        }
-       SAFE_FREE(escape_user);
 
        rc = smbldap_search_suffix(ldap_state->smbldap_state,
                                   filter, attr_list, &result);
@@ -2278,7 +2388,6 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct s
   fn_exit:
 
        TALLOC_FREE(ctx);
-       SAFE_FREE(escape_user);
        if (result) {
                ldap_msgfree(result);
        }
@@ -2420,6 +2529,7 @@ for gidNumber(%lu)\n",(unsigned long)map->gid));
 
        if (lp_parm_bool(-1, "ldapsam", "trusted", false)) {
                store_gid_sid_cache(&map->sid, map->gid);
+               idmap_cache_set_sid2gid(&map->sid, map->gid);
        }
 
        TALLOC_FREE(ctx);
@@ -2528,7 +2638,7 @@ static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
                                 const char *name)
 {
        char *filter = NULL;
-       char *escape_name = escape_ldap_string_alloc(name);
+       char *escape_name = escape_ldap_string(talloc_tos(), name);
        NTSTATUS status;
 
        if (!escape_name) {
@@ -2540,11 +2650,11 @@ static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
                get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), escape_name,
                get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN),
                escape_name) < 0) {
-               SAFE_FREE(escape_name);
+               TALLOC_FREE(escape_name);
                return NT_STATUS_NO_MEMORY;
        }
 
-       SAFE_FREE(escape_name);
+       TALLOC_FREE(escape_name);
        status = ldapsam_getgroup(methods, filter, map);
        SAFE_FREE(filter);
        return status;
@@ -2654,7 +2764,7 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods,
 
        values = ldap_get_values(conn->ldap_struct, entry, "memberUid");
 
-       if (values) {
+       if ((values != NULL) && (values[0] != NULL)) {
 
                filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|", LDAP_OBJ_SAMBASAMACCOUNT);
                if (filter == NULL) {
@@ -2665,20 +2775,19 @@ static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods,
                for (memberuid = values; *memberuid != NULL; memberuid += 1) {
                        char *escape_memberuid;
 
-                       escape_memberuid = escape_ldap_string_alloc(*memberuid);
+                       escape_memberuid = escape_ldap_string(talloc_tos(),
+                                                             *memberuid);
                        if (escape_memberuid == NULL) {
                                ret = NT_STATUS_NO_MEMORY;
                                goto done;
                        }
 
                        filter = talloc_asprintf_append_buffer(filter, "(uid=%s)", escape_memberuid);
+                       TALLOC_FREE(escape_memberuid);
                        if (filter == NULL) {
-                               SAFE_FREE(escape_memberuid);
                                ret = NT_STATUS_NO_MEMORY;
                                goto done;
                        }
-
-                       SAFE_FREE(escape_memberuid);
                }
 
                filter = talloc_asprintf_append_buffer(filter, "))");
@@ -2812,50 +2921,54 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       escape_name = escape_ldap_string_alloc(pdb_get_username(user));
+       escape_name = escape_ldap_string(talloc_tos(), pdb_get_username(user));
        if (escape_name == NULL)
                return NT_STATUS_NO_MEMORY;
 
-       /* retrieve the users primary gid */
-       filter = talloc_asprintf(mem_ctx,
-                                "(&(objectClass=%s)(uid=%s))",
-                                LDAP_OBJ_SAMBASAMACCOUNT,
-                                escape_name);
-       if (filter == NULL) {
-               ret = NT_STATUS_NO_MEMORY;
-               goto done;
-       }
+       if (user->unix_pw) {
+               primary_gid = user->unix_pw->pw_gid;
+       } else {
+               /* retrieve the users primary gid */
+               filter = talloc_asprintf(mem_ctx,
+                                        "(&(objectClass=%s)(uid=%s))",
+                                        LDAP_OBJ_SAMBASAMACCOUNT,
+                                        escape_name);
+               if (filter == NULL) {
+                       ret = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
 
-       rc = smbldap_search(conn, lp_ldap_suffix(),
-                           LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+               rc = smbldap_search(conn, lp_ldap_suffix(),
+                                   LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
 
-       if (rc != LDAP_SUCCESS)
-               goto done;
+               if (rc != LDAP_SUCCESS)
+                       goto done;
 
-       talloc_autofree_ldapmsg(mem_ctx, result);
+               talloc_autofree_ldapmsg(mem_ctx, result);
 
-       count = ldap_count_entries(priv2ld(ldap_state), result);
+               count = ldap_count_entries(priv2ld(ldap_state), result);
 
-       switch (count) {
-       case 0: 
-               DEBUG(1, ("User account [%s] not found!\n", pdb_get_username(user)));
-               ret = NT_STATUS_NO_SUCH_USER;
-               goto done;
-       case 1:
-               entry = ldap_first_entry(priv2ld(ldap_state), result);
+               switch (count) {
+               case 0:
+                       DEBUG(1, ("User account [%s] not found!\n", pdb_get_username(user)));
+                       ret = NT_STATUS_NO_SUCH_USER;
+                       goto done;
+               case 1:
+                       entry = ldap_first_entry(priv2ld(ldap_state), result);
 
-               gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
-               if (!gidstr) {
-                       DEBUG (1, ("Unable to find the member's gid!\n"));
+                       gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
+                       if (!gidstr) {
+                               DEBUG (1, ("Unable to find the member's gid!\n"));
+                               ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
+                               goto done;
+                       }
+                       primary_gid = strtoul(gidstr, NULL, 10);
+                       break;
+               default:
+                       DEBUG(1, ("found more than one account with the same user name ?!\n"));
                        ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
                        goto done;
                }
-               primary_gid = strtoul(gidstr, NULL, 10);
-               break;
-       default:
-               DEBUG(1, ("found more than one account with the same user name ?!\n"));
-               ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
-               goto done;
        }
 
        filter = talloc_asprintf(mem_ctx,
@@ -2950,7 +3063,7 @@ static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
 
  done:
 
-       SAFE_FREE(escape_name);
+       TALLOC_FREE(escape_name);
        return ret;
 }
 
@@ -3693,8 +3806,14 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
        int rc;
        char *filter;
        enum lsa_SidType type = SID_NAME_USE_NONE;
+       bool is_builtin = false;
+       bool sid_added = false;
+
+       *pp_alias_rids = NULL;
+       *p_num_alias_rids = 0;
 
        if (sid_check_is_builtin(domain_sid)) {
+               is_builtin = true;
                type = SID_NAME_ALIAS;
        }
 
@@ -3708,8 +3827,12 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       if (num_members == 0) {
+               return NT_STATUS_OK;
+       }
+
        filter = talloc_asprintf(mem_ctx,
-                                "(&(|(objectclass=%s)(sambaGroupType=%d))(|",
+                                "(&(objectclass=%s)(sambaGroupType=%d)(|",
                                 LDAP_OBJ_GROUPMAP, type);
 
        for (i=0; i<num_members; i++)
@@ -3724,11 +3847,20 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
                return NT_STATUS_NO_MEMORY;
        }
 
-       rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(),
-                           LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
-
-       if (rc != LDAP_SUCCESS)
-               return NT_STATUS_UNSUCCESSFUL;
+       if (is_builtin &&
+           ldap_state->search_cache.filter &&
+           strcmp(ldap_state->search_cache.filter, filter) == 0) {
+               filter = talloc_move(filter, &ldap_state->search_cache.filter);
+               result = ldap_state->search_cache.result;
+               ldap_state->search_cache.result = NULL;
+       } else {
+               rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_suffix(),
+                                   LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+               if (rc != LDAP_SUCCESS) {
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+               talloc_autofree_ldapmsg(filter, result);
+       }
 
        ldap_struct = ldap_state->smbldap_state->ldap_struct;
 
@@ -3752,19 +3884,29 @@ static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
                if (!sid_peek_check_rid(domain_sid, &sid, &rid))
                        continue;
 
+               sid_added = true;
+
                if (!add_rid_to_array_unique(mem_ctx, rid, pp_alias_rids,
                                        p_num_alias_rids)) {
-                       ldap_msgfree(result);
                        return NT_STATUS_NO_MEMORY;
                }
        }
 
-       ldap_msgfree(result);
+       if (!is_builtin && !sid_added) {
+               TALLOC_FREE(ldap_state->search_cache.filter);
+               /*
+                * Note: result is a talloc child of filter because of the
+                * talloc_autofree_ldapmsg() usage
+                */
+               ldap_state->search_cache.filter = talloc_move(ldap_state, &filter);
+               ldap_state->search_cache.result = result;
+       }
+
        return NT_STATUS_OK;
 }
 
 static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods,
-                                                  int policy_index,
+                                                  enum pdb_policy_type type,
                                                   uint32 value)
 {
        NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
@@ -3782,7 +3924,7 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       policy_attr = get_account_policy_attr(policy_index);
+       policy_attr = get_account_policy_attr(type);
        if (policy_attr == NULL) {
                DEBUG(0,("ldapsam_set_account_policy_in_ldap: invalid "
                         "policy\n"));
@@ -3802,7 +3944,7 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods,
                return ntstatus;
        }
 
-       if (!cache_account_policy_set(policy_index, value)) {
+       if (!cache_account_policy_set(type, value)) {
                DEBUG(0,("ldapsam_set_account_policy_in_ldap: failed to "
                         "update local tdb cache\n"));
                return ntstatus;
@@ -3812,14 +3954,15 @@ static NTSTATUS ldapsam_set_account_policy_in_ldap(struct pdb_methods *methods,
 }
 
 static NTSTATUS ldapsam_set_account_policy(struct pdb_methods *methods,
-                                          int policy_index, uint32 value)
+                                          enum pdb_policy_type type,
+                                          uint32_t value)
 {
-       return ldapsam_set_account_policy_in_ldap(methods, policy_index,
+       return ldapsam_set_account_policy_in_ldap(methods, type,
                                                  value);
 }
 
 static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods,
-                                                    int policy_index,
+                                                    enum pdb_policy_type type,
                                                     uint32 *value)
 {
        NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
@@ -3828,6 +3971,7 @@ static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods
        int count;
        int rc;
        char **vals = NULL;
+       char *filter;
        const char *policy_attr = NULL;
 
        struct ldapsam_privates *ldap_state =
@@ -3841,20 +3985,24 @@ static NTSTATUS ldapsam_get_account_policy_from_ldap(struct pdb_methods *methods
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       policy_attr = get_account_policy_attr(policy_index);
+       policy_attr = get_account_policy_attr(type);
        if (!policy_attr) {
                DEBUG(0,("ldapsam_get_account_policy_from_ldap: invalid "
-                        "policy index: %d\n", policy_index));
+                        "policy index: %d\n", type));
                return ntstatus;
        }
 
        attrs[0] = policy_attr;
        attrs[1] = NULL;
 
+       filter = talloc_asprintf(talloc_tos(), "(objectClass=%s)", LDAP_OBJ_DOMINFO);
+       if (filter == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
        rc = smbldap_search(ldap_state->smbldap_state, ldap_state->domain_dn,
-                           LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
+                           LDAP_SCOPE_BASE, filter, attrs, 0,
                            &result);
-
+       TALLOC_FREE(filter);
        if (rc != LDAP_SUCCESS) {
                return ntstatus;
        }
@@ -3898,17 +4046,18 @@ out:
    Guenther
 */
 static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods,
-                                          int policy_index, uint32 *value)
+                                          enum pdb_policy_type type,
+                                          uint32_t *value)
 {
        NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
 
-       if (cache_account_policy_get(policy_index, value)) {
+       if (cache_account_policy_get(type, value)) {
                DEBUG(11,("ldapsam_get_account_policy: got valid value from "
                          "cache\n"));
                return NT_STATUS_OK;
        }
 
-       ntstatus = ldapsam_get_account_policy_from_ldap(methods, policy_index,
+       ntstatus = ldapsam_get_account_policy_from_ldap(methods, type,
                                                        value);
        if (NT_STATUS_IS_OK(ntstatus)) {
                goto update_cache;
@@ -3919,27 +4068,27 @@ static NTSTATUS ldapsam_get_account_policy(struct pdb_methods *methods,
 
 #if 0
        /* should we automagically migrate old tdb value here ? */
-       if (account_policy_get(policy_index, value))
+       if (account_policy_get(type, value))
                goto update_ldap;
 
        DEBUG(10,("ldapsam_get_account_policy: no tdb for %d, trying "
-                 "default\n", policy_index));
+                 "default\n", type));
 #endif
 
-       if (!account_policy_get_default(policy_index, value)) {
+       if (!account_policy_get_default(type, value)) {
                return ntstatus;
        }
 
 /* update_ldap: */
 
-       ntstatus = ldapsam_set_account_policy(methods, policy_index, *value);
+       ntstatus = ldapsam_set_account_policy(methods, type, *value);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ntstatus;
        }
 
  update_cache:
 
-       if (!cache_account_policy_set(policy_index, *value)) {
+       if (!cache_account_policy_set(type, *value)) {
                DEBUG(0,("ldapsam_get_account_policy: failed to update local "
                         "tdb as a cache\n"));
                return NT_STATUS_UNSUCCESSFUL;
@@ -4185,14 +4334,14 @@ static char *get_ldap_filter(TALLOC_CTX *mem_ctx, const char *username)
                goto done;
        }
 
-       escaped = escape_ldap_string_alloc(username);
+       escaped = escape_ldap_string(talloc_tos(), username);
        if (escaped == NULL) goto done;
 
        result = talloc_string_sub(mem_ctx, filter, "%u", username);
 
  done:
        SAFE_FREE(filter);
-       SAFE_FREE(escaped);
+       TALLOC_FREE(escaped);
 
        return result;
 }
@@ -4295,6 +4444,7 @@ static bool ldapsam_search_firstpage(struct pdb_search *search)
        if (state->current_entry == NULL) {
                ldap_msgfree(state->entries);
                state->entries = NULL;
+               return false;
        }
 
        return True;
@@ -4325,6 +4475,7 @@ static bool ldapsam_search_nextpage(struct pdb_search *search)
        if (state->current_entry == NULL) {
                ldap_msgfree(state->entries);
                state->entries = NULL;
+               return false;
        }
 
        return True;
@@ -4924,6 +5075,8 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
 
                id->gid = strtoul(gid_str, NULL, 10);
                *type = (enum lsa_SidType)strtoul(value, NULL, 10);
+               store_gid_sid_cache(sid, id->gid);
+               idmap_cache_set_sid2gid(sid, id->gid);
                ret = True;
                goto done;
        }
@@ -4940,6 +5093,8 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
 
        id->uid = strtoul(value, NULL, 10);
        *type = SID_NAME_USER;
+       store_uid_sid_cache(sid, id->uid);
+       idmap_cache_set_sid2uid(sid, id->uid);
 
        ret = True;
  done:
@@ -4947,8 +5102,151 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
        return ret;
 }
 
+/**
+ * Find the SID for a uid.
+ * This is shortcut is only used if ldapsam:trusted is set to true.
+ */
+static bool ldapsam_uid_to_sid(struct pdb_methods *methods, uid_t uid,
+                              DOM_SID *sid)
+{
+       struct ldapsam_privates *priv =
+               (struct ldapsam_privates *)methods->private_data;
+       char *filter;
+       const char *attrs[] = { "sambaSID", NULL };
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
+       bool ret = false;
+       char *user_sid_string;
+       struct dom_sid user_sid;
+       int rc;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+       filter = talloc_asprintf(tmp_ctx,
+                                "(&(uidNumber=%u)"
+                                "(objectClass=%s)"
+                                "(objectClass=%s))",
+                                (unsigned int)uid,
+                                LDAP_OBJ_POSIXACCOUNT,
+                                LDAP_OBJ_SAMBASAMACCOUNT);
+       if (filter == NULL) {
+               DEBUG(3, ("talloc_asprintf failed\n"));
+               goto done;
+       }
+
+       rc = smbldap_search_suffix(priv->smbldap_state, filter, attrs, &result);
+       if (rc != LDAP_SUCCESS) {
+               goto done;
+       }
+       talloc_autofree_ldapmsg(tmp_ctx, result);
+
+       if (ldap_count_entries(priv2ld(priv), result) != 1) {
+               DEBUG(3, ("ERROR: Got %d entries for uid %u, expected one\n",
+                          ldap_count_entries(priv2ld(priv), result),
+                          (unsigned int)uid));
+               goto done;
+       }
+
+       entry = ldap_first_entry(priv2ld(priv), result);
+
+       user_sid_string = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+                                                         "sambaSID", tmp_ctx);
+       if (user_sid_string == NULL) {
+               DEBUG(1, ("Could not find sambaSID in object '%s'\n",
+                         smbldap_talloc_dn(tmp_ctx, priv2ld(priv), entry)));
+               goto done;
+       }
+
+       if (!string_to_sid(&user_sid, user_sid_string)) {
+               DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n",
+                         user_sid_string));
+               goto done;
+       }
+
+       sid_copy(sid, &user_sid);
+
+       store_uid_sid_cache(sid, uid);
+       idmap_cache_set_sid2uid(sid, uid);
+
+       ret = true;
+
+ done:
+       TALLOC_FREE(tmp_ctx);
+       return ret;
+}
+
+/**
+ * Find the SID for a gid.
+ * This is shortcut is only used if ldapsam:trusted is set to true.
+ */
+static bool ldapsam_gid_to_sid(struct pdb_methods *methods, gid_t gid,
+                              DOM_SID *sid)
+{
+       struct ldapsam_privates *priv =
+               (struct ldapsam_privates *)methods->private_data;
+       char *filter;
+       const char *attrs[] = { "sambaSID", NULL };
+       LDAPMessage *result = NULL;
+       LDAPMessage *entry = NULL;
+       bool ret = false;
+       char *group_sid_string;
+       DOM_SID group_sid;
+       int rc;
+       TALLOC_CTX *tmp_ctx = talloc_stackframe();
+
+       filter = talloc_asprintf(tmp_ctx,
+                                "(&(gidNumber=%u)"
+                                "(objectClass=%s))",
+                                (unsigned int)gid,
+                                LDAP_OBJ_GROUPMAP);
+       if (filter == NULL) {
+               DEBUG(3, ("talloc_asprintf failed\n"));
+               goto done;
+       }
+
+       rc = smbldap_search_suffix(priv->smbldap_state, filter, attrs, &result);
+       if (rc != LDAP_SUCCESS) {
+               goto done;
+       }
+       talloc_autofree_ldapmsg(tmp_ctx, result);
+
+       if (ldap_count_entries(priv2ld(priv), result) != 1) {
+               DEBUG(3, ("ERROR: Got %d entries for gid %u, expected one\n",
+                          ldap_count_entries(priv2ld(priv), result),
+                          (unsigned int)gid));
+               goto done;
+       }
+
+       entry = ldap_first_entry(priv2ld(priv), result);
+
+       group_sid_string = smbldap_talloc_single_attribute(priv2ld(priv), entry,
+                                                         "sambaSID", tmp_ctx);
+       if (group_sid_string == NULL) {
+               DEBUG(1, ("Could not find sambaSID in object '%s'\n",
+                         smbldap_talloc_dn(tmp_ctx, priv2ld(priv), entry)));
+               goto done;
+       }
+
+       if (!string_to_sid(&group_sid, group_sid_string)) {
+               DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n",
+                         group_sid_string));
+               goto done;
+       }
+
+       sid_copy(sid, &group_sid);
+
+       store_gid_sid_cache(sid, gid);
+       idmap_cache_set_sid2gid(sid, gid);
+
+       ret = true;
+
+ done:
+       TALLOC_FREE(tmp_ctx);
+       return ret;
+}
+
+
 /*
- * The following functions is called only if
+ * The following functions are called only if
  * ldapsam:trusted and ldapsam:editposix are
  * set to true
  */
@@ -4994,10 +5292,10 @@ static NTSTATUS ldapsam_create_user(struct pdb_methods *my_methods,
                is_machine = True;
        }
 
-       username = escape_ldap_string_alloc(name);
+       username = escape_ldap_string(talloc_tos(), name);
        filter = talloc_asprintf(tmp_ctx, "(&(uid=%s)(objectClass=%s))",
                                 username, LDAP_OBJ_POSIXACCOUNT);
-       SAFE_FREE(username);
+       TALLOC_FREE(username);
 
        rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
        if (rc != LDAP_SUCCESS) {
@@ -5230,6 +5528,40 @@ static NTSTATUS ldapsam_delete_user(struct pdb_methods *my_methods, TALLOC_CTX *
                return NT_STATUS_NO_MEMORY;
        }
 
+       /* try to remove memberships first */
+       {
+               NTSTATUS status;
+               struct dom_sid *sids = NULL;
+               gid_t *gids = NULL;
+               size_t num_groups = 0;
+               int i;
+               uint32_t user_rid = pdb_get_user_rid(sam_acct);
+
+               status = ldapsam_enum_group_memberships(my_methods,
+                                                       tmp_ctx,
+                                                       sam_acct,
+                                                       &sids,
+                                                       &gids,
+                                                       &num_groups);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto delete_dn;
+               }
+
+               for (i=0; i < num_groups; i++) {
+
+                       uint32_t group_rid;
+
+                       sid_peek_rid(&sids[i], &group_rid);
+
+                       ldapsam_del_groupmem(my_methods,
+                                            tmp_ctx,
+                                            group_rid,
+                                            user_rid);
+               }
+       }
+
+ delete_dn:
+
        rc = smbldap_delete(ldap_state->smbldap_state, dn);
        if (rc != LDAP_SUCCESS) {
                return NT_STATUS_UNSUCCESSFUL;
@@ -5270,10 +5602,10 @@ static NTSTATUS ldapsam_create_dom_group(struct pdb_methods *my_methods,
        gid_t gid = -1;
        int rc;
 
-       groupname = escape_ldap_string_alloc(name);
+       groupname = escape_ldap_string(talloc_tos(), name);
        filter = talloc_asprintf(tmp_ctx, "(&(cn=%s)(objectClass=%s))",
                                 groupname, LDAP_OBJ_POSIXGROUP);
-       SAFE_FREE(groupname);
+       TALLOC_FREE(groupname);
 
        rc = smbldap_search_suffix(ldap_state->smbldap_state, filter, NULL, &result);
        if (rc != LDAP_SUCCESS) {
@@ -5702,7 +6034,8 @@ static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods,
                return NT_STATUS_NO_MEMORY;
        }
 
-       escape_username = escape_ldap_string_alloc(pdb_get_username(sampass));
+       escape_username = escape_ldap_string(talloc_tos(),
+                                            pdb_get_username(sampass));
        if (escape_username== NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -5715,7 +6048,7 @@ static NTSTATUS ldapsam_set_primary_group(struct pdb_methods *my_methods,
                                 LDAP_OBJ_POSIXACCOUNT,
                                 LDAP_OBJ_SAMBASAMACCOUNT);
 
-       SAFE_FREE(escape_username);
+       TALLOC_FREE(escape_username);
 
        if (filter == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -5889,18 +6222,17 @@ static bool ldapsam_get_trusteddom_pw(struct pdb_methods *methods,
        /* domain sid */
        if (sid != NULL) {
                char *sid_str;
-               DOM_SID *dom_sid;
+               struct dom_sid dom_sid;
                sid_str = smbldap_talloc_single_attribute(priv2ld(ldap_state),
                                                          entry, "sambaSID",
                                                          talloc_tos());
                if (sid_str == NULL) {
                        return False;
                }
-               dom_sid = string_sid_talloc(talloc_tos(), sid_str);
-               if (dom_sid == NULL) {
+               if (!string_to_sid(&dom_sid, sid_str)) {
                        return False;
                }
-               sid_copy(sid, dom_sid);
+               sid_copy(sid, &dom_sid);
        }
 
        return True;
@@ -5941,8 +6273,6 @@ static bool ldapsam_set_trusteddom_pw(struct pdb_methods *methods,
        smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
                         "sambaClearTextPassword", pwd);
 
-       talloc_autofree_ldapmod(talloc_tos(), mods);
-
        if (entry != NULL) {
                prev_pwd = smbldap_talloc_single_attribute(priv2ld(ldap_state),
                                entry, "sambaClearTextPassword", talloc_tos());
@@ -5953,6 +6283,8 @@ static bool ldapsam_set_trusteddom_pw(struct pdb_methods *methods,
                }
        }
 
+       talloc_autofree_ldapmod(talloc_tos(), mods);
+
        trusted_dn = trusteddom_dn(ldap_state, domain);
        if (trusted_dn == NULL) {
                return False;
@@ -6236,9 +6568,8 @@ NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location)
 
        trim_char( uri, '\"', '\"' );
        nt_status = pdb_init_ldapsam_common(pdb_method, uri);
-       if (uri) {
-               TALLOC_FREE(uri);
-       }
+
+       TALLOC_FREE(uri);
 
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
@@ -6260,6 +6591,8 @@ NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location)
                        ldapsam_enum_group_memberships;
                (*pdb_method)->lookup_rids = ldapsam_lookup_rids;
                (*pdb_method)->sid_to_id = ldapsam_sid_to_id;
+               (*pdb_method)->uid_to_sid = ldapsam_uid_to_sid;
+               (*pdb_method)->gid_to_sid = ldapsam_gid_to_sid;
 
                if (lp_parm_bool(-1, "ldapsam", "editposix", False)) {
                        (*pdb_method)->create_user = ldapsam_create_user;