summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2008-05-16 14:16:19 +0200
committerGünther Deschner <gd@samba.org>2008-05-16 14:23:51 +0200
commitd41bc18b77562ca2fe7360944d9782509b1552fe (patch)
treef54ce1064f66297bad210ad1cc4d2466f3aab9fc
parent58f22b738e038730dbb0e0d0779099ce364f7b9a (diff)
downloadsamba-d41bc18b77562ca2fe7360944d9782509b1552fe.tar.gz
Fix Bug #5461 and implement a very basic _samr_GetDisplayEnumerationIndex().
Citrix PM cannot use a Samba DC when having more then 900 groups as citrix insists on calling _samr_GetDisplayEnumerationIndex() after receiving the first 900 groups via _samr_QueryDisplayInfo() to get the continuation index. Guenther
-rw-r--r--source/rpc_server/srv_samr.c35
-rw-r--r--source/rpc_server/srv_samr_nt.c128
2 files changed, 160 insertions, 3 deletions
diff --git a/source/rpc_server/srv_samr.c b/source/rpc_server/srv_samr.c
index 6ce4f882619..12705cf2b65 100644
--- a/source/rpc_server/srv_samr.c
+++ b/source/rpc_server/srv_samr.c
@@ -1496,6 +1496,37 @@ static BOOL api_samr_set_dom_info(pipes_struct *p)
}
/*******************************************************************
+ api_samr_get_dispenum_index
+ ********************************************************************/
+
+static BOOL api_samr_get_dispenum_index(pipes_struct *p)
+{
+ SAMR_Q_GET_DISPENUM_INDEX q_u;
+ SAMR_R_GET_DISPENUM_INDEX r_u;
+ prs_struct *data = &p->in_data.data;
+ prs_struct *rdata = &p->out_data.rdata;
+
+ ZERO_STRUCT(q_u);
+ ZERO_STRUCT(r_u);
+
+ if(!samr_io_q_get_dispenum_index("", &q_u, data, 0)) {
+ DEBUG(0,("api_samr_get_dispenum_index: unable to unmarshall SAMR_Q_GET_DISPENUM_INDEX.\n"));
+ return False;
+ }
+
+ r_u.status = _samr_get_dispenum_index(p, &q_u, &r_u);
+
+ /* store the response in the SMB stream */
+ if(!samr_io_r_get_dispenum_index("", &r_u, rdata, 0)) {
+ DEBUG(0,("api_samr_get_dispenum_index: unable to marshall SAMR_R_GET_DISPENUM_INDEX.\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
array of \PIPE\samr operations
********************************************************************/
@@ -1555,7 +1586,9 @@ static struct api_struct api_samr_cmds [] =
{"SAMR_SET_DOMAIN_INFO" , SAMR_SET_DOMAIN_INFO , api_samr_set_dom_info },
{"SAMR_CONNECT4" , SAMR_CONNECT4 , api_samr_connect4 },
{"SAMR_CHGPASSWD_USER3" , SAMR_CHGPASSWD_USER3 , api_samr_chgpasswd_user3 },
- {"SAMR_CONNECT5" , SAMR_CONNECT5 , api_samr_connect5 }
+ {"SAMR_CONNECT5" , SAMR_CONNECT5 , api_samr_connect5 },
+ {"SAMR_GET_DISPENUM_INDEX", SAMR_GET_DISPENUM_INDEX, api_samr_get_dispenum_index },
+ {"SAMR_GET_DISPENUM_INDEX2",SAMR_GET_DISPENUM_INDEX2, api_samr_get_dispenum_index }
};
void samr_get_pipe_fns( struct api_struct **fns, int *n_fns )
diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c
index c766d560f4a..5f1ef25637e 100644
--- a/source/rpc_server/srv_samr_nt.c
+++ b/source/rpc_server/srv_samr_nt.c
@@ -1338,8 +1338,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
if (!NT_STATUS_IS_OK(disp_ret))
return disp_ret;
- /* calculate the total size */
- total_data_size=num_account*struct_size;
+ temp_size = num_account * struct_size;
if (num_account) {
r_u->status = STATUS_MORE_ENTRIES;
@@ -1347,6 +1346,10 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
r_u->status = NT_STATUS_OK;
}
+ if (num_account < max_entries) {
+ r_u->status = NT_STATUS_OK;
+ }
+
/* Ensure we cache this enumeration. */
set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
@@ -5078,3 +5081,124 @@ NTSTATUS _samr_set_dom_info(pipes_struct *p, SAMR_Q_SET_DOMAIN_INFO *q_u, SAMR_R
return r_u->status;
}
+
+/*******************************************************************
+ _samr_get_dispenum_index
+ ********************************************************************/
+
+NTSTATUS _samr_get_dispenum_index(pipes_struct *p, SAMR_Q_GET_DISPENUM_INDEX *q_u, SAMR_R_GET_DISPENUM_INDEX *r_u)
+{
+ struct samr_info *info = NULL;
+ uint32 max_entries = (uint32) -1;
+ uint32 enum_context = 0;
+ int i;
+ uint32 num_account = 0;
+ struct samr_displayentry *entries = NULL;
+ fstring account_name;
+
+ DEBUG(5, ("_samr_get_dispenum_index: %d\n", __LINE__));
+
+ r_u->status = NT_STATUS_UNSUCCESSFUL;
+
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->domain_pol, (void **)(void *)&info))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if ((q_u->switch_level < 1) || (q_u->switch_level > 3)) {
+ DEBUG(0,("_samr_get_dispenum_index: Unknown info level (%u)\n",
+ (unsigned int)q_u->switch_level ));
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (!rpcstr_pull_unistr2_fstring(account_name, &q_u->name.unistring)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+
+ /* The following done as ROOT. Don't return without unbecome_root(). */
+
+ switch (q_u->switch_level) {
+ case 0x1:
+ if (info->disp_info->users == NULL) {
+ info->disp_info->users = pdb_search_users(ACB_NORMAL);
+ if (info->disp_info->users == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_get_dispenum_index: starting user enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ } else {
+ DEBUG(10,("_samr_get_dispenum_index: using cached user enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ }
+
+ num_account = pdb_search_entries(info->disp_info->users,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 0x2:
+ if (info->disp_info->machines == NULL) {
+ info->disp_info->machines =
+ pdb_search_users(ACB_WSTRUST|ACB_SVRTRUST);
+ if (info->disp_info->machines == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_get_dispenum_index: starting machine enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ } else {
+ DEBUG(10,("_samr_get_dispenum_index: using cached machine enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ }
+
+ num_account = pdb_search_entries(info->disp_info->machines,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 0x3:
+ if (info->disp_info->groups == NULL) {
+ info->disp_info->groups = pdb_search_groups();
+ if (info->disp_info->groups == NULL) {
+ unbecome_root();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(10,("_samr_get_dispenum_index: starting group enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ } else {
+ DEBUG(10,("_samr_get_dispenum_index: using cached group enumeration at index %u\n",
+ (unsigned int)enum_context ));
+ }
+
+ num_account = pdb_search_entries(info->disp_info->groups,
+ enum_context, max_entries,
+ &entries);
+ break;
+ default:
+ unbecome_root();
+ smb_panic("info class changed");
+ break;
+ }
+ unbecome_root();
+
+ /* Ensure we cache this enumeration. */
+ set_disp_info_cache_timeout(info->disp_info, DISP_INFO_CACHE_TIMEOUT);
+
+ DEBUG(10,("_samr_get_dispenum_index: looking for :%s\n", account_name));
+
+ for (i=0; i<num_account; i++) {
+ if (strequal(entries[i].account_name, account_name)) {
+ DEBUG(10,("_samr_get_dispenum_index: found %s at idx %d\n",
+ account_name, i));
+
+ init_samr_r_get_dispenum_index(r_u, i);
+
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* assuming account_name lives at the very end */
+ init_samr_r_get_dispenum_index(r_u, num_account);
+
+ return NT_STATUS_OK;
+}