diff options
author | Günther Deschner <gd@samba.org> | 2008-05-16 14:16:19 +0200 |
---|---|---|
committer | Günther Deschner <gd@samba.org> | 2008-05-16 14:23:51 +0200 |
commit | d41bc18b77562ca2fe7360944d9782509b1552fe (patch) | |
tree | f54ce1064f66297bad210ad1cc4d2466f3aab9fc | |
parent | 58f22b738e038730dbb0e0d0779099ce364f7b9a (diff) | |
download | samba-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.c | 35 | ||||
-rw-r--r-- | source/rpc_server/srv_samr_nt.c | 128 |
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; +} |