re-done all of samr_query_disp_info()
authorJean-François Micouleau <jfm@samba.org>
Fri, 21 Dec 2001 13:36:14 +0000 (13:36 +0000)
committerJean-François Micouleau <jfm@samba.org>
Fri, 21 Dec 2001 13:36:14 +0000 (13:36 +0000)
instead of enumerating the whole user db or group db every time, we store
a in memory copy linked to the handle.

that's much faster for large enumeration where the db can't fit in a
single rpc packet. And as it's a copy, it's constant between enumeration.

still some stuff to clean. But now I can fix the W95 userlist bug, as I've
finally found it.

J.F.
(This used to be commit 3ab45215369e8e93d750f4687e9c1f7d47782590)

source3/include/rpc_samr.h
source3/rpc_parse/parse_samr.c
source3/rpc_server/srv_samr_nt.c

index 43ee342ed33c6570b93b4758ce46ccab06e1eff1..777dfa1e465bc0dc5ae2df0d47584d30c9d1edb8 100644 (file)
@@ -146,6 +146,16 @@ SamrTestPrivateFunctionsUser
 #define SAMR_SET_USERINFO      0x3A
 
 
+typedef struct _DISP_USER_INFO {
+       SAM_ACCOUNT *sam;
+       uint32 size;
+} DISP_USER_INFO;
+
+typedef struct _DISP_GROUP_INFO {
+       DOMAIN_GRP *grp;
+       uint32 size;
+} DISP_GROUP_INFO;
+
 
 typedef struct logon_hours_info
 {
@@ -788,7 +798,6 @@ typedef struct samr_entry_info1
 
        uint32 rid_user;
        uint16 acb_info;
-       uint16 pad;
 
        UNIHDR hdr_acct_name;
        UNIHDR hdr_user_name;
@@ -820,7 +829,6 @@ typedef struct samr_entry_info2
 
        uint32 rid_user;
        uint16 acb_info;
-       uint16 pad;
 
        UNIHDR hdr_srv_name;
        UNIHDR hdr_srv_desc;
index bfca4958933d51d20ebfb9dc520cddf2021e9770..fdc2d560e1547da8ec120142a7a68b51aa11f877 100644 (file)
@@ -934,7 +934,6 @@ static void init_sam_entry1(SAM_ENTRY1 * sam, uint32 user_idx,
        sam->user_idx = user_idx;
        sam->rid_user = rid_user;
        sam->acb_info = acb_info;
-       sam->pad = 0;
 
        init_uni_hdr(&sam->hdr_acct_name, len_sam_name);
        init_uni_hdr(&sam->hdr_user_name, len_sam_full);
@@ -964,7 +963,8 @@ static BOOL sam_io_sam_entry1(char *desc, SAM_ENTRY1 * sam,
                return False;
        if(!prs_uint16("acb_info ", ps, depth, &sam->acb_info))
                return False;
-       if(!prs_uint16("pad      ", ps, depth, &sam->pad))
+
+       if(!prs_align(ps))
                return False;
 
        if (!smb_io_unihdr("hdr_acct_name", &sam->hdr_acct_name, ps, depth))
@@ -1013,7 +1013,6 @@ static void init_sam_entry2(SAM_ENTRY2 * sam, uint32 user_idx,
        sam->user_idx = user_idx;
        sam->rid_user = rid_user;
        sam->acb_info = acb_info;
-       sam->pad = 0;
 
        init_uni_hdr(&sam->hdr_srv_name, len_sam_name);
        init_uni_hdr(&sam->hdr_srv_desc, len_sam_desc);
@@ -1042,7 +1041,8 @@ static BOOL sam_io_sam_entry2(char *desc, SAM_ENTRY2 * sam,
                return False;
        if(!prs_uint16("acb_info ", ps, depth, &sam->acb_info))
                return False;
-       if(!prs_uint16("pad      ", ps, depth, &sam->pad))
+
+       if(!prs_align(ps))
                return False;
 
        if(!smb_io_unihdr("unihdr", &sam->hdr_srv_name, ps, depth))     /* account name unicode string header */
@@ -1436,62 +1436,53 @@ BOOL samr_io_q_query_dispinfo(char *desc, SAMR_Q_QUERY_DISPINFO * q_e,
 inits a SAM_DISPINFO_1 structure.
 ********************************************************************/
 
-NTSTATUS init_sam_dispinfo_1(TALLOC_CTX *ctx, SAM_DISPINFO_1 *sam, uint32 *num_entries,
-                        uint32 *data_size, uint32 start_idx,
-                        SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+NTSTATUS init_sam_dispinfo_1(TALLOC_CTX *ctx, SAM_DISPINFO_1 *sam, uint32 num_entries,
+                        uint32 start_idx, DISP_USER_INFO *disp_user_info)
 {
        uint32 len_sam_name, len_sam_full, len_sam_desc;
-       uint32 max_entries, max_data_size;
-       uint32 dsize = 0;
        uint32 i;
 
+       SAM_ACCOUNT *pwd = NULL;
        ZERO_STRUCTP(sam);
 
-       max_entries = *num_entries;
-       max_data_size = *data_size;
-
-       DEBUG(5, ("init_sam_dispinfo_1: max_entries: %d max_dsize: 0x%x\n",
-                 max_entries, max_data_size));
+       DEBUG(10, ("init_sam_dispinfo_1: num_entries: %d\n", num_entries));
 
-       if (max_entries==0)
+       if (num_entries==0)
                return NT_STATUS_OK;
 
-       sam->sam=(SAM_ENTRY1 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY1));
+       sam->sam=(SAM_ENTRY1 *)talloc(ctx, num_entries*sizeof(SAM_ENTRY1));
        if (!sam->sam)
                return NT_STATUS_NO_MEMORY;
 
-       sam->str=(SAM_STR1 *)talloc(ctx, max_entries*sizeof(SAM_STR1));
+       sam->str=(SAM_STR1 *)talloc(ctx, num_entries*sizeof(SAM_STR1));
        if (!sam->str)
                return NT_STATUS_NO_MEMORY;
 
        ZERO_STRUCTP(sam->sam);
        ZERO_STRUCTP(sam->str);
 
-       for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
-               DEBUG(5, ("init_sam_dispinfo_1: entry: %d\n",i));
-               len_sam_name = pass[i].uni_user_name.uni_str_len;
-               len_sam_full = pass[i].uni_full_name.uni_str_len;
-               len_sam_desc = pass[i].uni_acct_desc.uni_str_len;
+       for (i = 0; i < num_entries ; i++) {
+               DEBUG(11, ("init_sam_dispinfo_1: entry: %d\n",i));
+               
+               pwd=disp_user_info[i+start_idx].sam;
+               
+               len_sam_name = strlen(pdb_get_username(pwd));
+               len_sam_full = strlen(pdb_get_fullname(pwd));
+               len_sam_desc = strlen(pdb_get_acct_desc(pwd));
 
                init_sam_entry1(&sam->sam[i], start_idx + i + 1,
                                len_sam_name, len_sam_full, len_sam_desc,
-                               pass[i].user_rid, pass[i].acb_info);
+                               pdb_get_user_rid(pwd), pdb_get_acct_ctrl(pwd));
 
                ZERO_STRUCTP(&sam->str[i].uni_acct_name);
                ZERO_STRUCTP(&sam->str[i].uni_full_name);
                ZERO_STRUCTP(&sam->str[i].uni_acct_desc);
 
-               copy_unistr2(&sam->str[i].uni_acct_name, &pass[i].uni_user_name);
-               copy_unistr2(&sam->str[i].uni_full_name, &pass[i].uni_full_name);
-               copy_unistr2(&sam->str[i].uni_acct_desc, &pass[i].uni_acct_desc);
-
-               dsize += sizeof(SAM_ENTRY1);
-               dsize += len_sam_name + len_sam_full + len_sam_desc;
+               init_unistr2(&sam->str[i].uni_acct_name, pdb_get_username(pwd),  len_sam_name);
+               init_unistr2(&sam->str[i].uni_full_name, pdb_get_fullname(pwd),  len_sam_full);
+               init_unistr2(&sam->str[i].uni_acct_desc, pdb_get_acct_desc(pwd), len_sam_desc);
        }
 
-       *num_entries = i;
-       *data_size = dsize;
-
        return NT_STATUS_OK;
 }
 
@@ -1548,55 +1539,47 @@ static BOOL sam_io_sam_dispinfo_1(char *desc, SAM_DISPINFO_1 * sam,
 inits a SAM_DISPINFO_2 structure.
 ********************************************************************/
 
-NTSTATUS init_sam_dispinfo_2(TALLOC_CTX *ctx, SAM_DISPINFO_2 *sam, uint32 *num_entries,
-                        uint32 *data_size, uint32 start_idx,
-                        SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+NTSTATUS init_sam_dispinfo_2(TALLOC_CTX *ctx, SAM_DISPINFO_2 *sam, uint32 num_entries,
+                        uint32 start_idx, DISP_USER_INFO *disp_user_info)
 {
        uint32 len_sam_name, len_sam_desc;
-       uint32 max_entries, max_data_size;
-       uint32 dsize = 0;
        uint32 i;
 
-       DEBUG(5, ("init_sam_dispinfo_2\n"));
-
+       SAM_ACCOUNT *pwd = NULL;
        ZERO_STRUCTP(sam);
 
-       max_entries = *num_entries;
-       max_data_size = *data_size;
+       DEBUG(10, ("init_sam_dispinfo_2: num_entries: %d\n", num_entries));
 
-       if (max_entries==0)
+       if (num_entries==0)
                return NT_STATUS_OK;
 
-       if (!(sam->sam=(SAM_ENTRY2 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY2))))
+       if (!(sam->sam=(SAM_ENTRY2 *)talloc(ctx, num_entries*sizeof(SAM_ENTRY2))))
                return NT_STATUS_NO_MEMORY;
 
-       if (!(sam->str=(SAM_STR2 *)talloc(ctx, max_entries*sizeof(SAM_STR2))))
+       if (!(sam->str=(SAM_STR2 *)talloc(ctx, num_entries*sizeof(SAM_STR2))))
                return NT_STATUS_NO_MEMORY;
 
        ZERO_STRUCTP(sam->sam);
        ZERO_STRUCTP(sam->str);
 
-       for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
-               len_sam_name = pass[i].uni_user_name.uni_str_len;
-               len_sam_desc = pass[i].uni_acct_desc.uni_str_len;
+       for (i = 0; i < num_entries; i++) {
+               DEBUG(11, ("init_sam_dispinfo_2: entry: %d\n",i));
+               pwd=disp_user_info[i+start_idx].sam;
+
+               len_sam_name = strlen(pdb_get_username(pwd));
+               len_sam_desc = strlen(pdb_get_acct_desc(pwd));
          
                init_sam_entry2(&sam->sam[i], start_idx + i + 1,
                          len_sam_name, len_sam_desc,
-                         pass[i].user_rid, pass[i].acb_info);
+                         pdb_get_user_rid(pwd), pdb_get_acct_ctrl(pwd));
          
                ZERO_STRUCTP(&sam->str[i].uni_srv_name);
                ZERO_STRUCTP(&sam->str[i].uni_srv_desc);
 
-               copy_unistr2(&sam->str[i].uni_srv_name, &pass[i].uni_user_name);
-               copy_unistr2(&sam->str[i].uni_srv_desc, &pass[i].uni_acct_desc);
-         
-               dsize += sizeof(SAM_ENTRY2);
-               dsize += len_sam_name + len_sam_desc;
+               init_unistr2(&sam->str[i].uni_srv_name, pdb_get_username(pwd),  len_sam_name);
+               init_unistr2(&sam->str[i].uni_srv_desc, pdb_get_acct_desc(pwd), len_sam_desc);
        }
 
-       *num_entries = i;
-       *data_size = dsize;
-
        return NT_STATUS_OK;
 }
 
@@ -1655,35 +1638,33 @@ static BOOL sam_io_sam_dispinfo_2(char *desc, SAM_DISPINFO_2 * sam,
 inits a SAM_DISPINFO_3 structure.
 ********************************************************************/
 
-NTSTATUS init_sam_dispinfo_3(TALLOC_CTX *ctx, SAM_DISPINFO_3 *sam, uint32 *num_entries,
-                        uint32 *data_size, uint32 start_idx,
-                        DOMAIN_GRP * grp)
+NTSTATUS init_sam_dispinfo_3(TALLOC_CTX *ctx, SAM_DISPINFO_3 *sam, uint32 num_entries,
+                        uint32 start_idx, DISP_GROUP_INFO *disp_group_info)
 {
        uint32 len_sam_name, len_sam_desc;
-       uint32 max_entries, max_data_size;
-       uint32 dsize = 0;
        uint32 i;
 
-       DEBUG(5, ("init_sam_dispinfo_3\n"));
-
+       DOMAIN_GRP *grp;
        ZERO_STRUCTP(sam);
 
-       max_entries = *num_entries;
-       max_data_size = *data_size;
+       DEBUG(5, ("init_sam_dispinfo_3: num_entries: %d\n", num_entries));
 
-       if (max_entries==0)
+       if (num_entries==0)
                return NT_STATUS_OK;
 
-       if (!(sam->sam=(SAM_ENTRY3 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY3))))
+       if (!(sam->sam=(SAM_ENTRY3 *)talloc(ctx, num_entries*sizeof(SAM_ENTRY3))))
                return NT_STATUS_NO_MEMORY;
 
-       if (!(sam->str=(SAM_STR3 *)talloc(ctx, max_entries*sizeof(SAM_STR3))))
+       if (!(sam->str=(SAM_STR3 *)talloc(ctx, num_entries*sizeof(SAM_STR3))))
                return NT_STATUS_NO_MEMORY;
 
        ZERO_STRUCTP(sam->sam);
        ZERO_STRUCTP(sam->str);
 
-       for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+       for (i = 0; i < num_entries; i++) {
+               DEBUG(11, ("init_sam_dispinfo_3: entry: %d\n",i));
+               grp=disp_group_info[i+start_idx].grp;
+
                len_sam_name = strlen(grp[i].name);
                len_sam_desc = strlen(grp[i].comment);
 
@@ -1691,15 +1672,8 @@ NTSTATUS init_sam_dispinfo_3(TALLOC_CTX *ctx, SAM_DISPINFO_3 *sam, uint32 *num_e
          
                init_unistr2(&sam->str[i].uni_grp_name, grp[i].name, len_sam_name);
                init_unistr2(&sam->str[i].uni_grp_desc, grp[i].comment, len_sam_desc);
-         
-               dsize += sizeof(SAM_ENTRY3);
-               dsize += (len_sam_name + len_sam_desc) * 2;
-               dsize += 14;
        }
 
-       *num_entries = i;
-       *data_size = dsize;
-
        return NT_STATUS_OK;
 }
 
@@ -1758,50 +1732,40 @@ static BOOL sam_io_sam_dispinfo_3(char *desc, SAM_DISPINFO_3 * sam,
 inits a SAM_DISPINFO_4 structure.
 ********************************************************************/
 
-NTSTATUS init_sam_dispinfo_4(TALLOC_CTX *ctx, SAM_DISPINFO_4 *sam, uint32 *num_entries,
-                        uint32 *data_size, uint32 start_idx,
-                        SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES])
+NTSTATUS init_sam_dispinfo_4(TALLOC_CTX *ctx, SAM_DISPINFO_4 *sam, uint32 num_entries,
+                        uint32 start_idx, DISP_USER_INFO *disp_user_info)
 {
-       fstring sam_name;
        uint32 len_sam_name;
-       uint32 max_entries, max_data_size;
-       uint32 dsize = 0;
        uint32 i;
 
-       DEBUG(5, ("init_sam_dispinfo_4\n"));
-
+       SAM_ACCOUNT *pwd = NULL;
        ZERO_STRUCTP(sam);
 
-       max_entries = *num_entries;
-       max_data_size = *data_size;
+       DEBUG(5, ("init_sam_dispinfo_4: num_entries: %d\n", num_entries));
 
-       if (max_entries==0)
+       if (num_entries==0)
                return NT_STATUS_OK;
 
-       if (!(sam->sam=(SAM_ENTRY4 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY4))))
+       if (!(sam->sam=(SAM_ENTRY4 *)talloc(ctx, num_entries*sizeof(SAM_ENTRY4))))
                return NT_STATUS_NO_MEMORY;
 
-       if (!(sam->str=(SAM_STR4 *)talloc(ctx, max_entries*sizeof(SAM_STR4))))
+       if (!(sam->str=(SAM_STR4 *)talloc(ctx, num_entries*sizeof(SAM_STR4))))
                return NT_STATUS_NO_MEMORY;
 
        ZERO_STRUCTP(sam->sam);
        ZERO_STRUCTP(sam->str);
 
-       for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
-               len_sam_name = pass[i].uni_user_name.uni_str_len;
+       for (i = 0; i < num_entries; i++) {
+               DEBUG(11, ("init_sam_dispinfo_2: entry: %d\n",i));
+               pwd=disp_user_info[i+start_idx].sam;
+
+               len_sam_name = strlen(pdb_get_username(pwd));
          
                init_sam_entry4(&sam->sam[i], start_idx + i + 1, len_sam_name);
 
-               unistr2_to_ascii(sam_name, &pass[i].uni_user_name, sizeof(sam_name));
-               init_string2(&sam->str[i].acct_name, sam_name, len_sam_name+1, len_sam_name);
-         
-               dsize += sizeof(SAM_ENTRY4);
-               dsize += len_sam_name;
+               init_string2(&sam->str[i].acct_name, pdb_get_username(pwd), len_sam_name+1, len_sam_name);
        }
        
-       *num_entries = i;
-       *data_size = dsize;
-
        return NT_STATUS_OK;
 }
 
@@ -1859,46 +1823,38 @@ static BOOL sam_io_sam_dispinfo_4(char *desc, SAM_DISPINFO_4 * sam,
 inits a SAM_DISPINFO_5 structure.
 ********************************************************************/
 
-NTSTATUS init_sam_dispinfo_5(TALLOC_CTX *ctx, SAM_DISPINFO_5 *sam, uint32 *num_entries,
-                        uint32 *data_size, uint32 start_idx,
-                        DOMAIN_GRP * grp)
+NTSTATUS init_sam_dispinfo_5(TALLOC_CTX *ctx, SAM_DISPINFO_5 *sam, uint32 num_entries,
+                        uint32 start_idx, DISP_GROUP_INFO *disp_group_info)
 {
        uint32 len_sam_name;
-       uint32 max_entries, max_data_size;
-       uint32 dsize = 0;
        uint32 i;
 
-       DEBUG(5, ("init_sam_dispinfo_5\n"));
-
+       DOMAIN_GRP *grp;
        ZERO_STRUCTP(sam);
 
-       max_entries = *num_entries;
-       max_data_size = *data_size;
+       DEBUG(5, ("init_sam_dispinfo_5: num_entries: %d\n", num_entries));
 
-       if (max_entries==0)
+       if (num_entries==0)
                return NT_STATUS_OK;
 
-       if (!(sam->sam=(SAM_ENTRY5 *)talloc(ctx, max_entries*sizeof(SAM_ENTRY5))))
+       if (!(sam->sam=(SAM_ENTRY5 *)talloc(ctx, num_entries*sizeof(SAM_ENTRY5))))
                return NT_STATUS_NO_MEMORY;
 
-       if (!(sam->str=(SAM_STR5 *)talloc(ctx, max_entries*sizeof(SAM_STR5))))
+       if (!(sam->str=(SAM_STR5 *)talloc(ctx, num_entries*sizeof(SAM_STR5))))
                return NT_STATUS_NO_MEMORY;
 
        ZERO_STRUCTP(sam->sam);
        ZERO_STRUCTP(sam->str);
 
-       for (i = 0; (i < max_entries) && (dsize < max_data_size); i++) {
+       for (i = 0; i < num_entries; i++) {
+               DEBUG(11, ("init_sam_dispinfo_5: entry: %d\n",i));
+               grp=disp_group_info[i+start_idx].grp;
+
                len_sam_name = strlen(grp[i].name);
          
                init_sam_entry5(&sam->sam[i], start_idx + i + 1, len_sam_name);
                init_string2(&sam->str[i].grp_name, grp[i].name, len_sam_name+1, len_sam_name);
-         
-               dsize += sizeof(SAM_ENTRY5);
-               dsize += len_sam_name;
        }
-       
-       *num_entries = i;
-       *data_size = dsize;
 
        return NT_STATUS_OK;
 }
@@ -1948,8 +1904,6 @@ static BOOL sam_io_sam_dispinfo_5(char *desc, SAM_DISPINFO_5 * sam,
                if(!smb_io_string2("grp_name", &sam->str[i].grp_name,
                             sam->sam[i].hdr_grp_name.buffer, ps, depth))
                        return False;
-               if(!prs_align(ps))
-                       return False;
        }
 
        return True;
@@ -1960,16 +1914,13 @@ inits a SAMR_R_QUERY_DISPINFO structure.
 ********************************************************************/
 
 void init_samr_r_query_dispinfo(SAMR_R_QUERY_DISPINFO * r_u,
-                               uint32 num_entries, uint32 data_size,
+                               uint32 num_entries, uint32 total_size, uint32 data_size,
                                uint16 switch_level, SAM_DISPINFO_CTR * ctr,
                                NTSTATUS status)
 {
        DEBUG(5, ("init_samr_r_query_dispinfo: level %d\n", switch_level));
 
-       if (switch_level==4)
-               r_u->total_size = 0;    /* not calculated */
-       else
-               r_u->total_size = data_size;    /* not calculated */
+       r_u->total_size = total_size;
 
        r_u->data_size = data_size;
 
index b918b4dca188afdd5db465fceb60515de10166d9..1cd061369f7505a83bd4be6f8a818f03f47436eb 100644 (file)
@@ -38,10 +38,22 @@ extern rid_name domain_group_rids[];
 extern rid_name domain_alias_rids[];
 extern rid_name builtin_alias_rids[];
 
+
+typedef struct _disp_info {
+       BOOL user_dbloaded;
+       BOOL group_dbloaded;
+       uint32 num_account;
+       uint32 total_size;
+       uint32 last_enum;
+       DISP_USER_INFO *disp_user_info;
+       DISP_GROUP_INFO *disp_group_info;
+} DISP_INFO;
+
 struct samr_info {
-    /* for use by the \PIPE\samr policy */
-    DOM_SID sid;
-    uint32 status; /* some sort of flag.  best to record it.  comes from opnum 0x39 */
+       /* for use by the \PIPE\samr policy */
+       DOM_SID sid;
+       uint32 status; /* some sort of flag.  best to record it.  comes from opnum 0x39 */
+       DISP_INFO disp_info;
 };
 
 /*******************************************************************
@@ -50,6 +62,24 @@ struct samr_info {
 
 static void free_samr_info(void *ptr)
 {
+       int i;
+
+       struct samr_info *info=(struct samr_info *) ptr;
+
+       if (info->disp_info.group_dbloaded) {
+               for (i=0; i<info->disp_info.num_account; i++)
+                       SAFE_FREE(info->disp_info.disp_group_info[i].grp);
+
+               SAFE_FREE(info->disp_info.disp_group_info);
+       }
+
+       if (info->disp_info.user_dbloaded){
+               for (i=0; i<info->disp_info.num_account; i++)
+                       SAFE_FREE(info->disp_info.disp_user_info[i].sam);
+
+               SAFE_FREE(info->disp_info.disp_user_info);
+       }
+       
        SAFE_FREE(ptr);
 }
 
@@ -79,6 +109,137 @@ static void samr_clear_sam_passwd(SAM_ACCOUNT *sam_pass)
        if (sam_pass->nt_pw) memset(sam_pass->nt_pw, '\0', 16);
 }
 
+
+static NTSTATUS load_sampwd_entries(struct samr_info *info, uint16 acb_mask)
+{
+       SAM_ACCOUNT *pwd = NULL;
+       DISP_USER_INFO *pwd_array = NULL;
+
+       DEBUG(10,("load_sampwd_entries\n"));
+
+       /* if the snapshoot is already loaded, return */
+       if (info->disp_info.user_dbloaded==True) {
+               DEBUG(10,("load_sampwd_entries: already in memory\n"));
+               return NT_STATUS_OK;
+       }
+
+       if (!pdb_setsampwent(False)) {
+               DEBUG(0, ("get_sampwd_entries: Unable to open passdb.\n"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       for (pdb_init_sam(&pwd); pdb_getsampwent(pwd) == True; pwd=NULL, pdb_init_sam(&pwd) ) {
+               
+               uint32 len_sam_name, len_sam_full, len_sam_desc;
+
+               if (acb_mask != 0 && !(pwd->acct_ctrl & acb_mask)) {
+                       pdb_free_sam(&pwd);
+                       DEBUG(5,(" acb_mask %x reject\n", acb_mask));
+                       continue;
+               }
+               DEBUG(0,("load_sampwd_entries: entry: %d\n", info->disp_info.num_account));
+
+               /* Realloc some memory for the array of ptr to the SAM_ACCOUNT structs */
+               if (info->disp_info.num_account % MAX_SAM_ENTRIES == 0) {
+               
+                       DEBUG(0,("load_sampwd_entries: allocating more memory\n"));
+               
+               
+                       pwd_array=(DISP_USER_INFO *)Realloc(info->disp_info.disp_user_info, 
+                                         (info->disp_info.num_account+MAX_SAM_ENTRIES)*sizeof(DISP_USER_INFO));
+
+                       if (pwd_array==NULL)
+                               return NT_STATUS_NO_MEMORY;
+
+                       info->disp_info.disp_user_info=pwd_array;
+               }
+       
+               /* link the SAM_ACCOUNT to the array */
+               info->disp_info.disp_user_info[info->disp_info.num_account].sam=pwd;
+
+               /* calculate the size needed to store the data */
+               len_sam_name = strlen(pdb_get_username(pwd));
+               len_sam_full = strlen(pdb_get_fullname(pwd));
+               len_sam_desc = strlen(pdb_get_acct_desc(pwd));
+
+               info->disp_info.disp_user_info[info->disp_info.num_account].size=len_sam_name+
+                                                                                          len_sam_full+
+                                                                                          len_sam_desc;
+               /* keep the total size up to date too */
+               info->disp_info.total_size+=info->disp_info.disp_user_info[info->disp_info.num_account].size;
+       
+               /* 
+                * note: the size calculated are smaller than the size sent on the wire
+                * we add the SAM_ENTRY_x size later
+                */
+               DEBUG(0,("load_sampwd_entries: entry: %d size: %d total: %d\n", info->disp_info.num_account, info->disp_info.disp_user_info[info->disp_info.num_account].size,info->disp_info.total_size));
+
+               info->disp_info.num_account++;  
+       }
+
+       pdb_endsampwent();
+
+       /* the snapshoot is in memory, we're ready to enumerate fast */
+
+       info->disp_info.user_dbloaded=True;
+       info->disp_info.last_enum=0;
+
+       DEBUG(10,("load_sampwd_entries: done\n"));
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS load_group_domain_entries(struct samr_info *info, DOM_SID *sid)
+{
+       GROUP_MAP *map=NULL;
+       DISP_GROUP_INFO *grp_array = NULL;
+       uint32 group_entries = 0;
+       uint32 i;
+
+       DEBUG(10,("load_group_domain_entries\n"));
+
+       /* if the snapshoot is already loaded, return */
+       if (info->disp_info.group_dbloaded==True) {
+               DEBUG(10,("load_group_domain_entries: already in memory\n"));
+               return NT_STATUS_OK;
+       }
+
+       enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV);
+
+       info->disp_info.num_account=group_entries;
+
+       grp_array=(DISP_GROUP_INFO *)malloc(info->disp_info.num_account*sizeof(DISP_GROUP_INFO));
+
+       if (group_entries!=0 && grp_array==NULL) {
+               SAFE_FREE(map);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       info->disp_info.disp_group_info=grp_array;
+
+       for (i=0; i<group_entries; i++) {
+       
+               grp_array[i].grp=(DOMAIN_GRP *)malloc(sizeof(DOMAIN_GRP));
+       
+               fstrcpy(grp_array[i].grp->name, map[i].nt_name);
+               fstrcpy(grp_array[i].grp->comment, map[i].comment);
+               sid_split_rid(&map[i].sid, &grp_array[i].grp->rid);
+               grp_array[i].grp->attr=SID_NAME_DOM_GRP;
+       }
+
+       SAFE_FREE(map);
+
+       /* the snapshoot is in memory, we're ready to enumerate fast */
+
+       info->disp_info.group_dbloaded=True;
+       info->disp_info.last_enum=0;
+
+       DEBUG(10,("load_group_domain_entries: done\n"));
+
+       return NT_STATUS_OK;
+}
+
+
 /*******************************************************************
   This next function should be replaced with something that
   dynamically returns the correct user info..... JRA.
@@ -1022,91 +1183,147 @@ NTSTATUS _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, S
 /*******************************************************************
  samr_reply_query_dispinfo
  ********************************************************************/
-
 NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, SAMR_R_QUERY_DISPINFO *r_u)
 {
-       SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
-       DOMAIN_GRP *grps=NULL;
-       uint16 acb_mask = ACB_NORMAL;
-       uint32 num_entries = 0;
-       int orig_num_entries = 0;
-       int total_entries = 0;
-       uint32 data_size = 0;
-       DOM_SID sid;
-       NTSTATUS disp_ret;
+       struct samr_info *info = NULL;
+       uint32 struct_size=0;
+       uint16 acb_mask;
+       
+       uint32 max_entries=q_u->max_entries;
+       uint32 enum_context=q_u->start_idx;
+       uint32 max_size=q_u->max_size;
+
        SAM_DISPINFO_CTR *ctr;
+       uint32 temp_size=0, total_data_size=0;
+       uint32 i;
+       NTSTATUS disp_ret;
 
        DEBUG(5, ("samr_reply_query_dispinfo: %d\n", __LINE__));
-
        r_u->status = NT_STATUS_OK;
 
-       if (!get_lsa_policy_samr_sid(p, &q_u->domain_pol, &sid))
+       /* find the policy handle.  open a policy on it. */
+       if (!find_policy_by_hnd(p, &q_u->domain_pol, (void **)&info))
                return NT_STATUS_INVALID_HANDLE;
 
-       /* decide how many entries to get depending on the max_entries
-          and max_size passed by client */
-
-       DEBUG(5, ("samr_reply_query_dispinfo: max_entries before %d\n", q_u->max_entries));
+       /*
+        * calculate how many entries we will return.
+        * based on 
+        * - the number of entries the client asked
+        * - our limit on that
+        * - the starting point (enumeration context)
+        * - the buffer size the client will accept
+        */
 
-       if(q_u->max_entries > MAX_SAM_ENTRIES)
-               q_u->max_entries = MAX_SAM_ENTRIES;
+       /*
+        * We are a lot more like W2K. Instead of reading the SAM
+        * each time to find the records we need to send back,
+        * we read it once and link that copy to the sam handle.
+        * For large user list (over the MAX_SAM_ENTRIES)
+        * it's a definitive win.
+        * second point to notice: between enumerations
+        * our sam is now the same as it's a snapshoot.
+        * third point: got rid of the static SAM_USER_21 struct
+        * no more intermediate.
+        * con: it uses much more memory, as a full copy is stored
+        * in memory.
+        *
+        * If you want to change it, think twice and think
+        * of the second point , that's really important.
+        *
+        * JFM, 12/20/2001
+        */
 
-       DEBUG(5, ("samr_reply_query_dispinfo: max_entries after %d\n", q_u->max_entries));
+       /* Get what we need from the password database */
+       switch (q_u->switch_level) {
+               case 0x1:
+                       acb_mask = ACB_NORMAL;
+                       struct_size=0x20;
+                       break;
+               case 0x2:
+                       acb_mask = ACB_WSTRUST;
+                       struct_size=0x20;
+                       break;
+               case 0x3:
+                       struct_size=0x20;
+                       break;
+               case 0x4:
+                       acb_mask = ACB_NORMAL;
+                       struct_size=0x20;
+                       break;
+               case 0x5:
+                       struct_size=0x20;
+                       break;
+               default:
+                       DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", (unsigned int)q_u->switch_level ));
+                       return NT_STATUS_INVALID_INFO_CLASS;
+       }
 
        /* Get what we need from the password database */
        switch (q_u->switch_level) {
-       case 0x2:
-               acb_mask = ACB_WSTRUST;
-               /* Fall through */
-       case 0x1:
-       case 0x4:
-               become_root();
-#if 0
-               r_u->status = get_passwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
-                                               MAX_SAM_ENTRIES, acb_mask);
-#endif
-#if 0
-       /*
-        * Which should we use here ? JRA.
-        */
-               r_u->status = get_sampwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
-                                               MAX_SAM_ENTRIES, acb_mask);
-#endif
-#if 1
-               r_u->status = jf_get_sampwd_entries(pass, q_u->start_idx, &total_entries, &num_entries,
-                                               MAX_SAM_ENTRIES, acb_mask);
-#endif
-               unbecome_root();
-               if (NT_STATUS_IS_ERR(r_u->status)) {
-                       DEBUG(5, ("get_sampwd_entries: failed\n"));
-                       return r_u->status;
-               }
-               break;
-       case 0x3:
-       case 0x5:
-               r_u->status = get_group_domain_entries(p->mem_ctx, &grps, &sid, q_u->start_idx, &num_entries, MAX_SAM_ENTRIES);
-               if (NT_STATUS_IS_ERR(r_u->status))
-                       return r_u->status;
-               break;
-       default:
-               DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", (unsigned int)q_u->switch_level ));
-               return NT_STATUS_INVALID_INFO_CLASS;
+               case 0x1:
+               case 0x2:
+               case 0x4:
+                       if (enum_context!=0 && info->disp_info.user_dbloaded==False)
+                               return NT_STATUS_UNSUCCESSFUL;
+       
+                       become_root();          
+                       r_u->status=load_sampwd_entries(info, acb_mask);
+                       unbecome_root();
+                       if (NT_STATUS_IS_ERR(r_u->status)) {
+                               DEBUG(5, ("_samr_query_dispinfo: load_sampwd_entries failed\n"));
+                               return r_u->status;
+                       }
+                       break;
+               case 0x3:
+               case 0x5:
+                       if (enum_context!=0 && info->disp_info.group_dbloaded==False)
+                               return NT_STATUS_UNSUCCESSFUL;
+
+                       r_u->status = load_group_domain_entries(info, &info->sid);
+                       if (NT_STATUS_IS_ERR(r_u->status))
+                               return r_u->status;
+                       break;
+               default:
+                       DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", (unsigned int)q_u->switch_level ));
+                       return NT_STATUS_INVALID_INFO_CLASS;
+       }
+
+       /* first limit the number of entries we will return */
+       if(max_entries > MAX_SAM_ENTRIES) {
+               DEBUG(5, ("samr_reply_query_dispinfo: client requested %d entries, limiting to %d\n", max_entries, MAX_SAM_ENTRIES));
+               max_entries = MAX_SAM_ENTRIES;
        }
 
-       orig_num_entries = num_entries;
+       if (enum_context > info->disp_info.num_account) {
+               DEBUG(5, ("samr_reply_query_dispinfo: enumeration handle over total entries\n"));
+               return NT_STATUS_OK;
+       }
 
-       if (num_entries > q_u->max_entries)
-               num_entries = q_u->max_entries;
 
-       if (num_entries > MAX_SAM_ENTRIES) {
-               num_entries = MAX_SAM_ENTRIES;
-               DEBUG(5, ("limiting number of entries to %d\n", num_entries));
+       /* verify we won't overflow */
+       if (max_entries > info->disp_info.num_account-enum_context) {
+               max_entries = info->disp_info.num_account-enum_context;
+               DEBUG(5, ("samr_reply_query_dispinfo: only %d entries to return\n", max_entries));
        }
 
-       /* Ensure password info is never given out here. PARANOIA... JRA */
-       samr_clear_passwd_fields(pass, num_entries);
 
-       data_size = q_u->max_size;
+       /* calculate the size */
+       if (q_u->switch_level==3 || q_u->switch_level==5) 
+       for (i=enum_context; (i<enum_context+max_entries) && (temp_size<max_size); i++) {
+               /*temp_size+=info->disp_info.disp_group_info[i].size * 2;*/
+               temp_size+=struct_size;
+       }
+       
+       else
+       for (i=enum_context; (i<enum_context+max_entries) && (temp_size<max_size); i++) {
+               /*temp_size+=info->disp_info.disp_user_info[i].size * 2;*/
+               temp_size+=struct_size;
+       }
+
+       if (i<enum_context+max_entries) {
+               max_entries=i-enum_context;
+               DEBUG(5, ("samr_reply_query_dispinfo: buffer size limits to only %d entries\n", max_entries));
+       }
 
        if (!(ctr = (SAM_DISPINFO_CTR *)talloc_zero(p->mem_ctx,sizeof(SAM_DISPINFO_CTR))))
                return NT_STATUS_NO_MEMORY;
@@ -1116,65 +1333,72 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u, SAMR_
        /* Now create reply structure */
        switch (q_u->switch_level) {
        case 0x1:
-               if (num_entries) {
-                       if (!(ctr->sam.info1 = (SAM_DISPINFO_1 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_1))))
+               if (max_entries) {
+                       if (!(ctr->sam.info1 = (SAM_DISPINFO_1 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_1))))
                                return NT_STATUS_NO_MEMORY;
                }
-               disp_ret = init_sam_dispinfo_1(p->mem_ctx, ctr->sam.info1, &num_entries, &data_size, q_u->start_idx, pass);
+               disp_ret = init_sam_dispinfo_1(p->mem_ctx, ctr->sam.info1, max_entries, enum_context, info->disp_info.disp_user_info);
                if (NT_STATUS_IS_ERR(disp_ret))
                        return disp_ret;
                break;
        case 0x2:
-               if (num_entries) {
-                       if (!(ctr->sam.info2 = (SAM_DISPINFO_2 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_2))))
+               if (max_entries) {
+                       if (!(ctr->sam.info2 = (SAM_DISPINFO_2 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_2))))
                                return NT_STATUS_NO_MEMORY;
                }
-               disp_ret = init_sam_dispinfo_2(p->mem_ctx, ctr->sam.info2, &num_entries, &data_size, q_u->start_idx, pass);
+               disp_ret = init_sam_dispinfo_2(p->mem_ctx, ctr->sam.info2, max_entries, enum_context, info->disp_info.disp_user_info);
                if (NT_STATUS_IS_ERR(disp_ret))
                        return disp_ret;
                break;
        case 0x3:
-               if (num_entries) {
-                       if (!(ctr->sam.info3 = (SAM_DISPINFO_3 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_3))))
+               if (max_entries) {
+                       if (!(ctr->sam.info3 = (SAM_DISPINFO_3 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_3))))
                                return NT_STATUS_NO_MEMORY;
                }
-               disp_ret = init_sam_dispinfo_3(p->mem_ctx, ctr->sam.info3, &num_entries, &data_size, q_u->start_idx, grps);
+               disp_ret = init_sam_dispinfo_3(p->mem_ctx, ctr->sam.info3, max_entries, enum_context, info->disp_info.disp_group_info);
                if (NT_STATUS_IS_ERR(disp_ret))
                        return disp_ret;
                break;
        case 0x4:
-               if (num_entries) {
-                       if (!(ctr->sam.info4 = (SAM_DISPINFO_4 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_4))))
+               if (max_entries) {
+                       if (!(ctr->sam.info4 = (SAM_DISPINFO_4 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_4))))
                                return NT_STATUS_NO_MEMORY;
                }
-               disp_ret = init_sam_dispinfo_4(p->mem_ctx, ctr->sam.info4, &num_entries, &data_size, q_u->start_idx, pass);
+               disp_ret = init_sam_dispinfo_4(p->mem_ctx, ctr->sam.info4, max_entries, enum_context, info->disp_info.disp_user_info);
                if (NT_STATUS_IS_ERR(disp_ret))
                        return disp_ret;
                break;
        case 0x5:
-               if (num_entries) {
-                       if (!(ctr->sam.info5 = (SAM_DISPINFO_5 *)talloc_zero(p->mem_ctx,num_entries*sizeof(SAM_DISPINFO_5))))
+               if (max_entries) {
+                       if (!(ctr->sam.info5 = (SAM_DISPINFO_5 *)talloc_zero(p->mem_ctx,max_entries*sizeof(SAM_DISPINFO_5))))
                                return NT_STATUS_NO_MEMORY;
                }
-               disp_ret = init_sam_dispinfo_5(p->mem_ctx, ctr->sam.info5, &num_entries, &data_size, q_u->start_idx, grps);
+               disp_ret = init_sam_dispinfo_5(p->mem_ctx, ctr->sam.info5, max_entries, enum_context, info->disp_info.disp_group_info);
                if (NT_STATUS_IS_ERR(disp_ret))
                        return disp_ret;
                break;
+
        default:
                ctr->sam.info = NULL;
                return NT_STATUS_INVALID_INFO_CLASS;
        }
 
-       DEBUG(5, ("_samr_query_dispinfo: %d\n", __LINE__));
+       /* calculate the total size */
+       /*total_data_size=info->disp_info.total_size+(info->disp_info.num_account*struct_size);*/
+       total_data_size=info->disp_info.num_account*struct_size;
 
-       if (num_entries < orig_num_entries)
-               return STATUS_MORE_ENTRIES;
+       if (enum_context+max_entries < info->disp_info.num_account)
+               r_u->status = STATUS_MORE_ENTRIES;
 
-       init_samr_r_query_dispinfo(r_u, num_entries, data_size, q_u->switch_level, ctr, r_u->status);
+       DEBUG(5, ("_samr_query_dispinfo: %d\n", __LINE__));
+
+       init_samr_r_query_dispinfo(r_u, max_entries, total_data_size, temp_size, q_u->switch_level, ctr, r_u->status);
 
        return r_u->status;
+
 }
 
+
 /*******************************************************************
  samr_reply_query_aliasinfo
  ********************************************************************/