summaryrefslogtreecommitdiff
path: root/source3/rpc_server/srv_samr_nt.c
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2005-04-15 13:41:49 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:56:38 -0500
commitd3d6126d94d55a69c45b2f7a63a7fa9b561baf48 (patch)
treece4e45d5571fb0e1a090b59ffa74a56b8a883334 /source3/rpc_server/srv_samr_nt.c
parent496c6f088492e3f74bba11da21ffc8855b2eb7f9 (diff)
downloadsamba-d3d6126d94d55a69c45b2f7a63a7fa9b561baf48.tar.gz
samba-d3d6126d94d55a69c45b2f7a63a7fa9b561baf48.tar.bz2
samba-d3d6126d94d55a69c45b2f7a63a7fa9b561baf48.zip
r6351: This is quite a large and intrusive patch, but there are not many pieces that
can be taken out of it, so I decided to commit this in one lump. It changes the passdb enumerating functions to use ldap paged results where possible. In particular the samr calls querydispinfo, enumdomusers and friends have undergone significant internal changes. I have tested this extensively with rpcclient and a bit with usrmgr.exe. More tests and the merge to trunk will follow later. The code is based on a first implementation by Günther Deschner, but has evolved quite a bit since then. Volker (This used to be commit f0bb44ac58e190e19eb4e92928979b0446e611c9)
Diffstat (limited to 'source3/rpc_server/srv_samr_nt.c')
-rw-r--r--source3/rpc_server/srv_samr_nt.c818
1 files changed, 238 insertions, 580 deletions
diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c
index 84c78eab64..fe54476cc9 100644
--- a/source3/rpc_server/srv_samr_nt.c
+++ b/source3/rpc_server/srv_samr_nt.c
@@ -43,14 +43,12 @@ 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;
- uint32 num_user_account;
- SAM_ACCOUNT *disp_user_info;
- BOOL group_dbloaded;
- uint32 num_group_account;
- DOMAIN_GRP *disp_group_info;
+typedef struct disp_info {
+ struct pdb_search *users;
+ struct pdb_search *machines;
+ struct pdb_search *groups;
+ struct pdb_search *aliases;
+ struct pdb_search *builtins;
} DISP_INFO;
struct samr_info {
@@ -238,10 +236,9 @@ static struct samr_info *get_samr_info_by_sid(DOM_SID *psid)
mem_ctx = talloc_init("samr_info for domain sid %s", sid_str);
- if ((info = TALLOC_P(mem_ctx, struct samr_info)) == NULL)
+ if ((info = TALLOC_ZERO_P(mem_ctx, struct samr_info)) == NULL)
return NULL;
- ZERO_STRUCTP(info);
DEBUG(10,("get_samr_info_by_sid: created new info for sid %s\n", sid_str));
if (psid) {
sid_copy( &info->sid, psid);
@@ -256,33 +253,22 @@ static struct samr_info *get_samr_info_by_sid(DOM_SID *psid)
Function to free the per handle data.
********************************************************************/
-static void free_samr_users(struct samr_info *info)
-{
- int i;
-
- if (info->disp_info.user_dbloaded){
- for (i=0; i<info->disp_info.num_user_account; i++) {
- SAM_ACCOUNT *sam = &info->disp_info.disp_user_info[i];
- /* Not really a free, actually a 'clear' */
- pdb_free_sam(&sam);
- }
- }
- info->disp_info.user_dbloaded=False;
- info->disp_info.num_user_account=0;
-}
-
/*******************************************************************
Function to free the per handle data.
********************************************************************/
static void free_samr_db(struct samr_info *info)
{
- /* Groups are talloced */
-
- free_samr_users(info);
-
- info->disp_info.group_dbloaded=False;
- info->disp_info.num_group_account=0;
+ pdb_search_destroy(info->disp_info.users);
+ info->disp_info.users = NULL;
+ pdb_search_destroy(info->disp_info.machines);
+ info->disp_info.machines = NULL;
+ pdb_search_destroy(info->disp_info.groups);
+ info->disp_info.groups = NULL;
+ pdb_search_destroy(info->disp_info.aliases);
+ info->disp_info.aliases = NULL;
+ pdb_search_destroy(info->disp_info.builtins);
+ info->disp_info.builtins = NULL;
}
static void free_samr_info(void *ptr)
@@ -309,154 +295,30 @@ static void samr_clear_sam_passwd(SAM_ACCOUNT *sam_pass)
pdb_set_nt_passwd(sam_pass, NULL, PDB_DEFAULT);
}
-
-static NTSTATUS load_sampwd_entries(struct samr_info *info, uint16 acb_mask, BOOL only_machines)
+static uint32 count_sam_users(struct disp_info *info, uint16 acct_flags)
{
- SAM_ACCOUNT *pwd = NULL;
- SAM_ACCOUNT *pwd_array = NULL;
- NTSTATUS nt_status = NT_STATUS_OK;
- TALLOC_CTX *mem_ctx = info->mem_ctx;
- uint16 query_acb_mask = acb_mask;
-
- DEBUG(10,("load_sampwd_entries\n"));
-
- /* if the snapshoot is already loaded, return */
- if ((info->disp_info.user_dbloaded==True)
- && (info->acb_mask == acb_mask)
- && (info->only_machines == only_machines)) {
- DEBUG(10,("load_sampwd_entries: already in memory\n"));
- return NT_STATUS_OK;
- }
-
- free_samr_users(info);
-
- if (only_machines) {
- query_acb_mask |= ACB_WSTRUST;
- query_acb_mask |= ACB_SVRTRUST;
- }
-
- if (!pdb_setsampwent(False, query_acb_mask)) {
- DEBUG(0, ("load_sampwd_entries: Unable to open passdb.\n"));
- return NT_STATUS_ACCESS_DENIED;
- }
-
- for (; (NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(mem_ctx, &pwd)))
- && pdb_getsampwent(pwd) == True; pwd=NULL) {
-
- if (only_machines) {
- if (!((pdb_get_acct_ctrl(pwd) & ACB_WSTRUST)
- || (pdb_get_acct_ctrl(pwd) & ACB_SVRTRUST))) {
- DEBUG(5,("load_sampwd_entries: '%s' is not a machine account - ACB: %x - skipping\n", pdb_get_username(pwd), acb_mask));
- pdb_free_sam(&pwd);
- continue;
- }
- } else {
- if (acb_mask != 0 && !(pdb_get_acct_ctrl(pwd) & acb_mask)) {
- pdb_free_sam(&pwd);
- DEBUG(5,(" acb_mask %x reject\n", acb_mask));
- continue;
- }
- }
-
- /* Realloc some memory for the array of ptr to the SAM_ACCOUNT structs */
- if (info->disp_info.num_user_account % MAX_SAM_ENTRIES == 0) {
-
- DEBUG(10,("load_sampwd_entries: allocating more memory\n"));
- pwd_array=TALLOC_REALLOC_ARRAY(mem_ctx, info->disp_info.disp_user_info, SAM_ACCOUNT,
- info->disp_info.num_user_account+MAX_SAM_ENTRIES);
-
- if (pwd_array==NULL)
- return NT_STATUS_NO_MEMORY;
-
- info->disp_info.disp_user_info=pwd_array;
- }
-
- /* Copy the SAM_ACCOUNT into the array */
- info->disp_info.disp_user_info[info->disp_info.num_user_account]=*pwd;
-
- DEBUG(10,("load_sampwd_entries: entry: %d\n", info->disp_info.num_user_account));
-
- info->disp_info.num_user_account++;
- }
-
- pdb_endsampwent();
-
- /* the snapshoot is in memory, we're ready to enumerate fast */
-
- info->acb_mask = acb_mask;
- info->only_machines = only_machines;
- info->disp_info.user_dbloaded=True;
-
- DEBUG(10,("load_sampwd_entries: done\n"));
-
- return nt_status;
+ struct samr_displayentry *entry;
+ if (info->users == NULL)
+ info->users = pdb_search_users(acct_flags);
+ if (info->users == NULL)
+ return 0;
+ /* Fetch the last possible entry, thus trigger an enumeration */
+ pdb_search_entries(info->users, 0xffffffff, 1, &entry);
+ return info->users->num_entries;
}
-static NTSTATUS load_group_domain_entries(struct samr_info *info, DOM_SID *sid)
+static uint32 count_sam_groups(struct disp_info *info)
{
- GROUP_MAP *map=NULL;
- DOMAIN_GRP *grp_array = NULL;
- uint32 group_entries = 0;
- uint32 i;
- TALLOC_CTX *mem_ctx = info->mem_ctx;
- BOOL ret;
-
- 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;
- }
-
- if (sid_equal(sid, &global_sid_Builtin)) {
- /* No domain groups for now in the BUILTIN domain */
- info->disp_info.num_group_account=0;
- info->disp_info.disp_group_info=NULL;
- info->disp_info.group_dbloaded=True;
- return NT_STATUS_OK;
- }
-
- become_root();
- ret = pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries, ENUM_ONLY_MAPPED);
- unbecome_root();
-
- if ( !ret ) {
- DEBUG(1, ("load_group_domain_entries: pdb_enum_group_mapping() failed!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
-
- info->disp_info.num_group_account=group_entries;
-
- grp_array=TALLOC_ARRAY(mem_ctx, DOMAIN_GRP, info->disp_info.num_group_account);
- if (group_entries!=0 && grp_array==NULL) {
- DEBUG(1, ("load_group_domain_entries: talloc() failed for grp_array!\n"));
- SAFE_FREE(map);
- return NT_STATUS_NO_MEMORY;
- }
-
- info->disp_info.disp_group_info=grp_array;
-
- for (i=0; i<group_entries; i++) {
- fstrcpy(grp_array[i].name, map[i].nt_name);
- fstrcpy(grp_array[i].comment, map[i].comment);
- sid_split_rid(&map[i].sid, &grp_array[i].rid);
- grp_array[i].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;
-
- DEBUG(10,("load_group_domain_entries: done\n"));
-
- return NT_STATUS_OK;
+ struct samr_displayentry *entry;
+ if (info->groups == NULL)
+ info->groups = pdb_search_groups();
+ if (info->groups == NULL)
+ return 0;
+ /* Fetch the last possible entry, thus trigger an enumeration */
+ pdb_search_entries(info->groups, 0xffffffff, 1, &entry);
+ return info->groups->num_entries;
}
-
/*******************************************************************
_samr_close_hnd
********************************************************************/
@@ -656,20 +518,14 @@ NTSTATUS _samr_query_sec_obj(pipes_struct *p, SAMR_Q_QUERY_SEC_OBJ *q_u, SAMR_R_
makes a SAM_ENTRY / UNISTR2* structure from a user list.
********************************************************************/
-static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNISTR2 **uni_name_pp,
- uint32 num_entries, uint32 start_idx, SAM_ACCOUNT *disp_user_info,
- DOM_SID *domain_sid)
+static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp,
+ UNISTR2 **uni_name_pp,
+ uint32 num_entries, uint32 start_idx,
+ struct samr_displayentry *entries)
{
uint32 i;
SAM_ENTRY *sam;
UNISTR2 *uni_name;
- SAM_ACCOUNT *pwd = NULL;
- UNISTR2 uni_temp_name;
- const char *temp_name;
- const DOM_SID *user_sid;
- uint32 user_rid;
- fstring user_sid_string;
- fstring domain_sid_string;
*sam_pp = NULL;
*uni_name_pp = NULL;
@@ -687,31 +543,20 @@ static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UN
}
for (i = 0; i < num_entries; i++) {
- pwd = &disp_user_info[i+start_idx];
- temp_name = pdb_get_username(pwd);
-
+ UNISTR2 uni_temp_name;
/*
* usrmgr expects a non-NULL terminated string with
* trust relationships
*/
- if (pdb_get_acct_ctrl(pwd) & ACB_DOMTRUST) {
- init_unistr2(&uni_temp_name, temp_name, UNI_FLAGS_NONE);
+ if (entries[i].acct_flags & ACB_DOMTRUST) {
+ init_unistr2(&uni_temp_name, entries[i].account_name,
+ UNI_FLAGS_NONE);
} else {
- init_unistr2(&uni_temp_name, temp_name, UNI_STR_TERMINATE);
+ init_unistr2(&uni_temp_name, entries[i].account_name,
+ UNI_STR_TERMINATE);
}
- user_sid = pdb_get_user_sid(pwd);
-
- if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) {
- DEBUG(0, ("make_user_sam_entry_list: User %s has SID %s, which conflicts with "
- "the domain sid %s. Failing operation.\n",
- temp_name,
- sid_to_string(user_sid_string, user_sid),
- sid_to_string(domain_sid_string, domain_sid)));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- init_sam_entry(&sam[i], &uni_temp_name, user_rid);
+ init_sam_entry(&sam[i], &uni_temp_name, entries[i].rid);
copy_unistr2(&uni_name[i], &uni_temp_name);
}
@@ -728,15 +573,12 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u,
SAMR_R_ENUM_DOM_USERS *r_u)
{
struct samr_info *info = NULL;
- uint32 struct_size=0x20; /* W2K always reply that, client doesn't care */
int num_account;
uint32 enum_context=q_u->start_idx;
- uint32 max_size=q_u->max_size;
- uint32 temp_size;
enum remote_arch_types ra_type = get_remote_arch();
int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K;
uint32 max_entries = max_sam_entries;
- DOM_SID domain_sid;
+ struct samr_displayentry *entries = NULL;
r_u->status = NT_STATUS_OK;
@@ -744,8 +586,6 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u,
if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
return NT_STATUS_INVALID_HANDLE;
- domain_sid = info->sid;
-
if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(info->acc_granted,
SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
"_samr_enum_dom_users"))) {
@@ -755,60 +595,36 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u,
DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__));
become_root();
- r_u->status=load_sampwd_entries(info, q_u->acb_mask, False);
+ if (info->disp_info.users == NULL)
+ info->disp_info.users = pdb_search_users(q_u->acb_mask);
+ if (info->disp_info.users == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ num_account = pdb_search_entries(info->disp_info.users,
+ enum_context, max_entries,
+ &entries);
unbecome_root();
-
- if (!NT_STATUS_IS_OK(r_u->status))
- return r_u->status;
-
- num_account = info->disp_info.num_user_account;
- if (enum_context > num_account) {
- DEBUG(5, ("_samr_enum_dom_users: enumeration handle over total entries\n"));
+ if (num_account == 0) {
+ DEBUG(5, ("_samr_enum_dom_users: enumeration handle over "
+ "total entries\n"));
return NT_STATUS_OK;
}
- /* verify we won't overflow */
- if (max_entries > num_account-enum_context) {
- max_entries = num_account-enum_context;
- DEBUG(5, ("_samr_enum_dom_users: only %d entries to return\n", max_entries));
- }
-
- /* calculate the size and limit on the number of entries we will return */
- temp_size=max_entries*struct_size;
-
- if (temp_size>max_size) {
- max_entries=MIN((max_size/struct_size),max_entries);;
- DEBUG(5, ("_samr_enum_dom_users: buffer size limits to only %d entries\n", max_entries));
- }
-
- /*
- * Note from JRA. total_entries is not being used here. Currently if there is a
- * large user base then it looks like NT will enumerate until get_sampwd_entries
- * returns False due to num_entries being zero. This will cause an access denied
- * return. I don't think this is right and needs further investigation. Note that
- * this is also the same in the TNG code (I don't think that has been tested with
- * a very large user list as MAX_SAM_ENTRIES is set to 600).
- *
- * I also think that one of the 'num_entries' return parameters is probably
- * the "max entries" parameter - but in the TNG code they're all currently set to the same
- * value (again I think this is wrong).
- */
-
- r_u->status = make_user_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_acct_name,
- max_entries, enum_context,
- info->disp_info.disp_user_info,
- &domain_sid);
+ r_u->status = make_user_sam_entry_list(p->mem_ctx, &r_u->sam,
+ &r_u->uni_acct_name,
+ num_account, enum_context,
+ entries);
if (!NT_STATUS_IS_OK(r_u->status))
return r_u->status;
- if (enum_context+max_entries < num_account)
+ if (max_entries <= num_account)
r_u->status = STATUS_MORE_ENTRIES;
DEBUG(5, ("_samr_enum_dom_users: %d\n", __LINE__));
- init_samr_r_enum_dom_users(r_u, q_u->start_idx + max_entries, max_entries);
+ init_samr_r_enum_dom_users(r_u, q_u->start_idx + num_account,
+ num_account);
DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__));
@@ -819,8 +635,10 @@ NTSTATUS _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u,
makes a SAM_ENTRY / UNISTR2* structure from a group list.
********************************************************************/
-static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNISTR2 **uni_name_pp,
- uint32 num_sam_entries, DOMAIN_GRP *grp)
+static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp,
+ UNISTR2 **uni_name_pp,
+ uint32 num_sam_entries,
+ struct samr_displayentry *entries)
{
uint32 i;
SAM_ENTRY *sam;
@@ -844,8 +662,9 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST
/*
* JRA. I think this should include the null. TNG does not.
*/
- init_unistr2(&uni_name[i], grp[i].name, UNI_STR_TERMINATE);
- init_sam_entry(&sam[i], &uni_name[i], grp[i].rid);
+ init_unistr2(&uni_name[i], entries[i].account_name,
+ UNI_STR_TERMINATE);
+ init_sam_entry(&sam[i], &uni_name[i], entries[i].rid);
}
*sam_pp = sam;
@@ -853,179 +672,107 @@ static void make_group_sam_entry_list(TALLOC_CTX *ctx, SAM_ENTRY **sam_pp, UNIST
}
/*******************************************************************
- Get the group entries - similar to get_sampwd_entries().
- ******************************************************************/
-
-static NTSTATUS get_group_domain_entries( TALLOC_CTX *ctx,
- DOMAIN_GRP **d_grp, DOM_SID *sid, uint32 start_idx,
- uint32 *p_num_entries, uint32 max_entries )
-{
- GROUP_MAP *map=NULL;
- int i;
- uint32 group_entries = 0;
- uint32 num_entries = 0;
- NTSTATUS result = NT_STATUS_OK;
-
- *p_num_entries = 0;
-
- /* access checks for the users were performed higher up. become/unbecome_root()
- needed for some passdb backends to enumerate groups */
-
- become_root();
- pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries,
- ENUM_ONLY_MAPPED);
- unbecome_root();
-
- num_entries=group_entries-start_idx;
-
- /* limit the number of entries */
- if (num_entries>max_entries) {
- DEBUG(5,("Limiting to %d entries\n", max_entries));
- num_entries=max_entries;
- result = STATUS_MORE_ENTRIES;
- }
-
- *d_grp=TALLOC_ZERO_ARRAY(ctx, DOMAIN_GRP, num_entries);
- if (num_entries!=0 && *d_grp==NULL){
- SAFE_FREE(map);
- return NT_STATUS_NO_MEMORY;
- }
-
- for (i=0; i<num_entries; i++) {
- fstrcpy((*d_grp)[i].name, map[i+start_idx].nt_name);
- fstrcpy((*d_grp)[i].comment, map[i+start_idx].comment);
- sid_split_rid(&map[i+start_idx].sid, &(*d_grp)[i].rid);
- (*d_grp)[i].attr=SID_NAME_DOM_GRP;
- }
-
- SAFE_FREE(map);
-
- *p_num_entries = num_entries;
-
- DEBUG(10,("get_group_domain_entries: returning %d entries\n",
- *p_num_entries));
-
- return result;
-}
-
-/*******************************************************************
- Wrapper for enumerating local groups
- ******************************************************************/
-
-static NTSTATUS get_alias_entries( TALLOC_CTX *ctx, DOMAIN_GRP **d_grp,
- const DOM_SID *sid, uint32 start_idx,
- uint32 *p_num_entries, uint32 max_entries )
-{
- struct acct_info *info;
- int i;
- BOOL res;
-
- become_root();
- res = pdb_enum_aliases(sid, start_idx, max_entries,
- p_num_entries, &info);
- unbecome_root();
-
- if (!res)
- return NT_STATUS_ACCESS_DENIED;
-
- if (*p_num_entries == 0)
- return NT_STATUS_OK;
-
- *d_grp = TALLOC_ARRAY(ctx, DOMAIN_GRP, *p_num_entries);
-
- if (*d_grp == NULL) {
- SAFE_FREE(info);
- return NT_STATUS_NO_MEMORY;
- }
-
- for (i=0; i<*p_num_entries; i++) {
- fstrcpy((*d_grp)[i].name, info[i].acct_name);
- fstrcpy((*d_grp)[i].comment, info[i].acct_desc);
- (*d_grp)[i].rid = info[i].rid;
- (*d_grp)[i].attr = SID_NAME_ALIAS;
- }
-
- SAFE_FREE(info);
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
samr_reply_enum_dom_groups
********************************************************************/
NTSTATUS _samr_enum_dom_groups(pipes_struct *p, SAMR_Q_ENUM_DOM_GROUPS *q_u, SAMR_R_ENUM_DOM_GROUPS *r_u)
{
- DOMAIN_GRP *grp=NULL;
- uint32 num_entries;
- DOM_SID sid;
- uint32 acc_granted;
+ struct samr_info *info = NULL;
+ struct samr_displayentry *groups;
+ uint32 num_groups;
r_u->status = NT_STATUS_OK;
- if (!get_lsa_policy_samr_sid(p, &q_u->pol, &sid, &acc_granted))
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
return NT_STATUS_INVALID_HANDLE;
-
- if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, "_samr_enum_dom_groups"))) {
+
+ r_u->status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
+ "_samr_enum_dom_groups");
+ if (!NT_STATUS_IS_OK(r_u->status))
return r_u->status;
- }
DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__));
/* the domain group array is being allocated in the function below */
- r_u->status = get_group_domain_entries(p->mem_ctx, &grp, &sid,
- q_u->start_idx, &num_entries,
- MAX_SAM_ENTRIES);
- if (!NT_STATUS_IS_OK(r_u->status) &&
- !NT_STATUS_EQUAL(r_u->status, STATUS_MORE_ENTRIES))
- return r_u->status;
+ become_root();
+ if (info->disp_info.groups == NULL)
+ info->disp_info.groups = pdb_search_groups();
+ unbecome_root();
+ if (info->disp_info.groups == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+
+ become_root();
+ num_groups = pdb_search_entries(info->disp_info.groups, q_u->start_idx,
+ MAX_SAM_ENTRIES, &groups);
+ unbecome_root();
+
make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name,
- num_entries, grp);
+ num_groups, groups);
- init_samr_r_enum_dom_groups(r_u, q_u->start_idx+num_entries,
- num_entries);
+ init_samr_r_enum_dom_groups(r_u, q_u->start_idx, num_groups);
DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__));
return r_u->status;
}
-
/*******************************************************************
samr_reply_enum_dom_aliases
********************************************************************/
NTSTATUS _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, SAMR_R_ENUM_DOM_ALIASES *r_u)
{
- DOMAIN_GRP *grp=NULL;
- uint32 num_entries = 0;
- fstring sid_str;
- DOM_SID sid;
+ struct samr_info *info;
+ struct samr_displayentry *aliases;
+ struct pdb_search **search = NULL;
+ uint32 num_aliases = 0;
NTSTATUS status;
- uint32 acc_granted;
-
+
r_u->status = NT_STATUS_OK;
- if (!get_lsa_policy_samr_sid(p, &q_u->pol, &sid, &acc_granted))
+ /* find the policy handle. open a policy on it. */
+ if (!find_policy_by_hnd(p, &q_u->pol, (void **)&info))
return NT_STATUS_INVALID_HANDLE;
- if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, SA_RIGHT_DOMAIN_ENUM_ACCOUNTS, "_samr_enum_dom_aliases"))) {
+ r_u->status = access_check_samr_function(info->acc_granted,
+ SA_RIGHT_DOMAIN_ENUM_ACCOUNTS,
+ "_samr_enum_dom_aliases");
+ if (!NT_STATUS_IS_OK(r_u->status))
return r_u->status;
- }
-
- sid_to_string(sid_str, &sid);
- DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", sid_str));
- status = get_alias_entries(p->mem_ctx, &grp, &sid, q_u->start_idx,
- &num_entries, MAX_SAM_ENTRIES);
- if (!NT_STATUS_IS_OK(status)) return status;
+ DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n",
+ sid_string_static(&info->sid)));
+
+ if (sid_check_is_domain(&info->sid))
+ search = &info->disp_info.aliases;
+ if (sid_check_is_builtin(&info->sid))
+ search = &info->disp_info.builtins;
+
+ if (search == NULL) return NT_STATUS_INVALID_HANDLE;
+
+ become_root();
+ if (*search == NULL)
+ *search = pdb_search_aliases(&info->sid);
+ unbecome_root();
+
+ if (*search == NULL) return NT_STATUS_ACCESS_DENIED;
- make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, num_entries, grp);
+ become_root();
+ num_aliases = pdb_search_entries(*search, q_u->start_idx,
+ MAX_SAM_ENTRIES, &aliases);
+ unbecome_root();
+
+ make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name,
+ num_aliases, aliases);
- /*safe_free(grp);*/
+ if (!NT_STATUS_IS_OK(status)) return status;
- init_samr_r_enum_dom_aliases(r_u, q_u->start_idx + num_entries, num_entries);
+ init_samr_r_enum_dom_aliases(r_u, q_u->start_idx + num_aliases,
+ num_aliases);
DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__));
@@ -1053,6 +800,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
enum remote_arch_types ra_type = get_remote_arch();
int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K;
DOM_SID domain_sid;
+ struct samr_displayentry *entries = NULL;
DEBUG(5, ("samr_reply_query_dispinfo: %d\n", __LINE__));
r_u->status = NT_STATUS_OK;
@@ -1091,68 +839,29 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
* JFM, 12/20/2001
*/
- /* Get what we need from the password database */
- switch (q_u->switch_level) {
- case 0x1:
- /* When playing with usrmgr, this is necessary
- if you want immediate refresh after editing
- a user. I would like to do this after the
- setuserinfo2, but we do not have access to
- the domain handle in that call, only to the
- user handle. Where else does this hurt?
- -- Volker
- */
-#if 0
- /* We cannot do this here - it kills performace. JRA. */
- free_samr_users(info);
-#endif
- case 0x2:
- case 0x4:
- become_root();
- /* Level 2 is for all machines, otherwise only 'normal' users */
- r_u->status=load_sampwd_entries(info, ACB_NORMAL, q_u->switch_level==2);
- unbecome_root();
- if (!NT_STATUS_IS_OK(r_u->status)) {
- DEBUG(5, ("_samr_query_dispinfo: load_sampwd_entries failed\n"));
- return r_u->status;
- }
- num_account = info->disp_info.num_user_account;
- break;
- case 0x3:
- case 0x5:
- r_u->status = load_group_domain_entries(info, &info->sid);
- if (!NT_STATUS_IS_OK(r_u->status))
- return r_u->status;
- num_account = info->disp_info.num_group_account;
- break;
- default:
- DEBUG(0,("_samr_query_dispinfo: Unknown info level (%u)\n", (unsigned int)q_u->switch_level ));
- return NT_STATUS_INVALID_INFO_CLASS;
+ if ((q_u->switch_level < 1) || (q_u->switch_level > 5)) {
+ 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));
+ DEBUG(5, ("samr_reply_query_dispinfo: client requested %d "
+ "entries, limiting to %d\n", max_entries,
+ max_sam_entries));
max_entries = max_sam_entries;
}
- if (enum_context > num_account) {
- DEBUG(5, ("samr_reply_query_dispinfo: enumeration handle over total entries\n"));
- return NT_STATUS_NO_MORE_ENTRIES;
- }
-
- /* verify we won't overflow */
- if (max_entries > num_account-enum_context) {
- max_entries = num_account-enum_context;
- DEBUG(5, ("samr_reply_query_dispinfo: only %d entries to return\n", max_entries));
- }
+ /* calculate the size and limit on the number of entries we will
+ * return */
- /* calculate the size and limit on the number of entries we will return */
temp_size=max_entries*struct_size;
if (temp_size>max_size) {
max_entries=MIN((max_size/struct_size),max_entries);;
- DEBUG(5, ("samr_reply_query_dispinfo: buffer size limits to only %d entries\n", max_entries));
+ DEBUG(5, ("samr_reply_query_dispinfo: buffer size limits to "
+ "only %d entries\n", max_entries));
}
if (!(ctr = TALLOC_ZERO_P(p->mem_ctx,SAM_DISPINFO_CTR)))
@@ -1160,61 +869,80 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
ZERO_STRUCTP(ctr);
+ become_root();
+
+ switch (q_u->switch_level) {
+ case 0x1:
+ case 0x4:
+ if (info->disp_info.users == NULL)
+ info->disp_info.users = pdb_search_users(ACB_NORMAL);
+ if (info->disp_info.users == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ 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)
+ return NT_STATUS_ACCESS_DENIED;
+ num_account = pdb_search_entries(info->disp_info.machines,
+ enum_context, max_entries,
+ &entries);
+ break;
+ case 0x3:
+ case 0x5:
+ if (info->disp_info.groups == NULL)
+ info->disp_info.groups = pdb_search_groups();
+ if (info->disp_info.groups == NULL)
+ return NT_STATUS_ACCESS_DENIED;
+ num_account = pdb_search_entries(info->disp_info.groups,
+ enum_context, max_entries,
+ &entries);
+ break;
+ default:
+ smb_panic("info class changed");
+ break;
+ }
+ unbecome_root();
+
/* Now create reply structure */
switch (q_u->switch_level) {
case 0x1:
- if (max_entries) {
- if (!(ctr->sam.info1 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_1,max_entries)))
- return NT_STATUS_NO_MEMORY;
- }
- disp_ret = init_sam_dispinfo_1(p->mem_ctx, ctr->sam.info1, max_entries, enum_context,
- info->disp_info.disp_user_info, &domain_sid);
- if (!NT_STATUS_IS_OK(disp_ret))
- return disp_ret;
+ disp_ret = init_sam_dispinfo_1(p->mem_ctx, &ctr->sam.info1,
+ num_account, enum_context,
+ entries);
break;
case 0x2:
- if (max_entries) {
- if (!(ctr->sam.info2 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_2,max_entries)))
- return NT_STATUS_NO_MEMORY;
- }
- disp_ret = init_sam_dispinfo_2(p->mem_ctx, ctr->sam.info2, max_entries, enum_context,
- info->disp_info.disp_user_info, &domain_sid);
- if (!NT_STATUS_IS_OK(disp_ret))
- return disp_ret;
+ disp_ret = init_sam_dispinfo_2(p->mem_ctx, &ctr->sam.info2,
+ num_account, enum_context,
+ entries);
break;
case 0x3:
- if (max_entries) {
- if (!(ctr->sam.info3 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_3,max_entries)))
- return NT_STATUS_NO_MEMORY;
- }
- 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_OK(disp_ret))
- return disp_ret;
+ disp_ret = init_sam_dispinfo_3(p->mem_ctx, &ctr->sam.info3,
+ num_account, enum_context,
+ entries);
break;
case 0x4:
- if (max_entries) {
- if (!(ctr->sam.info4 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_4,max_entries)))
- return NT_STATUS_NO_MEMORY;
- }
- 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_OK(disp_ret))
- return disp_ret;
+ disp_ret = init_sam_dispinfo_4(p->mem_ctx, &ctr->sam.info4,
+ num_account, enum_context,
+ entries);
break;
case 0x5:
- if (max_entries) {
- if (!(ctr->sam.info5 = TALLOC_ZERO_ARRAY(p->mem_ctx,SAM_DISPINFO_5,max_entries)))
- return NT_STATUS_NO_MEMORY;
- }
- 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_OK(disp_ret))
- return disp_ret;
+ disp_ret = init_sam_dispinfo_5(p->mem_ctx, &ctr->sam.info5,
+ num_account, enum_context,
+ entries);
break;
-
default:
- ctr->sam.info = NULL;
- return NT_STATUS_INVALID_INFO_CLASS;
+ smb_panic("info class changed");
+ break;
}
+ if (!NT_STATUS_IS_OK(disp_ret))
+ return disp_ret;
+
/* calculate the total size */
total_data_size=num_account*struct_size;
@@ -1223,7 +951,9 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
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);
+ init_samr_r_query_dispinfo(r_u, num_account, total_data_size,
+ temp_size, q_u->switch_level, ctr,
+ r_u->status);
return r_u->status;
@@ -2106,23 +1836,11 @@ NTSTATUS _samr_query_dom_info(pipes_struct *p, SAMR_Q_QUERY_DOMAIN_INFO *q_u, SA
flag, nt_expire, nt_min_age);
break;
case 0x02:
- become_root();
- r_u->status=load_sampwd_entries(info, ACB_NORMAL, False);
+ become_root();
+ num_users=count_sam_users(&info->disp_info,
+ ACB_NORMAL);
+ num_groups=count_sam_groups(&info->disp_info);
unbecome_root();
- if (!NT_STATUS_IS_OK(r_u->status)) {
- DEBUG(5, ("_samr_query_dispinfo: load_sampwd_entries failed\n"));
- return r_u->status;
- }
- num_users=info->disp_info.num_user_account;
- free_samr_db(info);
-
- r_u->status=load_group_domain_entries(info, get_global_sam_sid());
- if (!NT_STATUS_IS_OK(r_u->status)) {
- DEBUG(5, ("_samr_query_dispinfo: load_group_domain_entries failed\n"));
- return r_u->status;
- }
- num_groups=info->disp_info.num_group_account;
- free_samr_db(info);
account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp);
u_logout = account_policy_temp;
@@ -4380,13 +4098,9 @@ NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p,
SAMR_Q_REMOVE_SID_FOREIGN_DOMAIN *q_u,
SAMR_R_REMOVE_SID_FOREIGN_DOMAIN *r_u)
{
- DOM_SID delete_sid, alias_sid;
- SAM_ACCOUNT *sam_pass=NULL;
+ DOM_SID delete_sid, domain_sid;
uint32 acc_granted;
- GROUP_MAP map;
- BOOL is_user = False;
NTSTATUS result;
- enum SID_NAME_USE type = SID_NAME_UNKNOWN;
sid_copy( &delete_sid, &q_u->sid.sid );
@@ -4395,7 +4109,8 @@ NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p,
/* Find the policy handle. Open a policy on it. */
- if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &alias_sid, &acc_granted))
+ if (!get_lsa_policy_samr_sid(p, &q_u->dom_pol, &domain_sid,
+ &acc_granted))
return NT_STATUS_INVALID_HANDLE;
result = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS,
@@ -4405,80 +4120,33 @@ NTSTATUS _samr_remove_sid_foreign_domain(pipes_struct *p,
return result;
DEBUG(8, ("_samr_remove_sid_foreign_domain:sid is %s\n",
- sid_string_static(&alias_sid)));
-
- /* make sure we can handle this */
-
- if ( sid_check_is_domain(&alias_sid) )
- type = SID_NAME_DOM_GRP;
- else if ( sid_check_is_builtin(&alias_sid) )
- type = SID_NAME_ALIAS;
-
- if ( type == SID_NAME_UNKNOWN ) {
- DEBUG(10, ("_samr_remove_sid_foreign_domain: can't operate on what we don't own!\n"));
- return NT_STATUS_OK;
- }
+ sid_string_static(&domain_sid)));
- /* check if the user exists before trying to delete */
-
- pdb_init_sam(&sam_pass);
-
- if ( pdb_getsampwsid(sam_pass, &delete_sid) ) {
- is_user = True;
- } else {
- /* maybe it is a group */
- if( !pdb_getgrsid(&map, delete_sid) ) {
- DEBUG(3,("_samr_remove_sid_foreign_domain: %s is not a user or a group!\n",
- sid_string_static(&delete_sid)));
- result = NT_STATUS_INVALID_SID;
- goto done;
- }
- }
-
/* we can only delete a user from a group since we don't have
nested groups anyways. So in the latter case, just say OK */
-
- if ( is_user ) {
- GROUP_MAP *mappings = NULL;
- int num_groups, i;
- struct group *grp2;
-
- if ( pdb_enum_group_mapping(type, &mappings, &num_groups, False) && num_groups>0 ) {
-
- /* interate over the groups */
- for ( i=0; i<num_groups; i++ ) {
- grp2 = getgrgid(mappings[i].gid);
-
- if ( !grp2 ) {
- DEBUG(0,("_samr_remove_sid_foreign_domain: group mapping without UNIX group!\n"));
- continue;
- }
-
- if ( !user_in_unix_group_list(pdb_get_username(sam_pass), grp2->gr_name) )
- continue;
-
- smb_delete_user_group(grp2->gr_name, pdb_get_username(sam_pass));
-
- if ( user_in_unix_group_list(pdb_get_username(sam_pass), grp2->gr_name) ) {
- /* should we fail here ? */
- DEBUG(0,("_samr_remove_sid_foreign_domain: Delete user [%s] from group [%s] failed!\n",
- pdb_get_username(sam_pass), grp2->gr_name ));
- continue;
- }
-
- DEBUG(10,("_samr_remove_sid_foreign_domain: Removed user [%s] from group [%s]!\n",
- pdb_get_username(sam_pass), grp2->gr_name ));
- }
-
- SAFE_FREE(mappings);
- }
+ /* TODO: The above comment nowadays is bogus. Since we have nested
+ * groups now, and aliases members are never reported out of the unix
+ * group membership, the "just say OK" makes this call a no-op. For
+ * us. This needs fixing however. */
+
+ /* I've only ever seen this in the wild when deleting a user from
+ * usrmgr.exe. domain_sid is the builtin domain, and the sid to delete
+ * is the user about to be deleted. I very much suspect this is the
+ * only application of this call. To verify this, let people report
+ * other cases. */
+
+ if (!sid_check_is_builtin(&domain_sid)) {
+ DEBUG(1,("_samr_remove_sid_foreign_domain: domain_sid = %s, "
+ "global_sam_sid() = %s\n",
+ sid_string_static(&domain_sid),
+ sid_string_static(get_global_sam_sid())));
+ DEBUGADD(1,("please report to samba-technical@samba.org!\n"));
+ return NT_STATUS_OK;
}
-
- result = NT_STATUS_OK;
-done:
- pdb_free_sam(&sam_pass);
+
+ result = NT_STATUS_OK;
return result;
}
@@ -4545,21 +4213,11 @@ NTSTATUS _samr_unknown_2e(pipes_struct *p, SAMR_Q_UNKNOWN_2E *q_u, SAMR_R_UNKNOW
break;
case 0x02:
become_root();
- r_u->status=load_sampwd_entries(info, ACB_NORMAL, False);
+ num_users = count_sam_users(&info->disp_info,
+ ACB_NORMAL);
+ num_groups = count_sam_groups(&info->disp_info);
unbecome_root();
- if (!NT_STATUS_IS_OK(r_u->status)) {
- DEBUG(5, ("_samr_unknown_2e: load_sampwd_entries failed\n"));
- return r_u->status;
- }
- num_users=info->disp_info.num_user_account;
- free_samr_db(info);
-
- r_u->status=load_group_domain_entries(info, get_global_sam_sid());
- if (NT_STATUS_IS_ERR(r_u->status)) {
- DEBUG(5, ("_samr_unknown_2e: load_group_domain_entries failed\n"));
- return r_u->status;
- }
- num_groups=info->disp_info.num_group_account;
+
free_samr_db(info);
account_policy_get(AP_TIME_TO_LOGOUT, &account_policy_temp);