summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/passdb.h12
-rw-r--r--source3/passdb/pdb_interface.c146
-rw-r--r--source3/passdb/pdb_ldap.c208
-rw-r--r--source3/rpc_server/srv_samr_nt.c52
4 files changed, 380 insertions, 38 deletions
diff --git a/source3/include/passdb.h b/source3/include/passdb.h
index 42f38e5b6a..3c244e7625 100644
--- a/source3/include/passdb.h
+++ b/source3/include/passdb.h
@@ -287,6 +287,12 @@ typedef struct pdb_context
GROUP_MAP **rmap, int *num_entries,
BOOL unix_only);
+ NTSTATUS (*pdb_enum_group_members)(struct pdb_context *context,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **member_rids,
+ int *num_members);
+
NTSTATUS (*pdb_enum_group_memberships)(struct pdb_context *context,
const char *username,
gid_t primary_gid,
@@ -385,6 +391,12 @@ typedef struct pdb_methods
GROUP_MAP **rmap, int *num_entries,
BOOL unix_only);
+ NTSTATUS (*enum_group_members)(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **member_rids,
+ int *num_members);
+
NTSTATUS (*enum_group_memberships)(struct pdb_methods *methods,
const char *username,
gid_t primary_gid,
diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c
index 382c028b0c..36a575214b 100644
--- a/source3/passdb/pdb_interface.c
+++ b/source3/passdb/pdb_interface.c
@@ -453,6 +453,25 @@ static NTSTATUS context_enum_group_mapping(struct pdb_context *context,
num_entries, unix_only);
}
+static NTSTATUS context_enum_group_members(struct pdb_context *context,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **member_rids,
+ int *num_members)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->enum_group_members(context->pdb_methods,
+ mem_ctx, group,
+ member_rids,
+ num_members);
+}
+
static NTSTATUS context_enum_group_memberships(struct pdb_context *context,
const char *username,
gid_t primary_gid,
@@ -737,6 +756,7 @@ static NTSTATUS make_pdb_context(struct pdb_context **context)
(*context)->pdb_update_group_mapping_entry = context_update_group_mapping_entry;
(*context)->pdb_delete_group_mapping_entry = context_delete_group_mapping_entry;
(*context)->pdb_enum_group_mapping = context_enum_group_mapping;
+ (*context)->pdb_enum_group_members = context_enum_group_members;
(*context)->pdb_enum_group_memberships = context_enum_group_memberships;
(*context)->pdb_find_alias = context_find_alias;
@@ -1058,6 +1078,21 @@ BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
rmap, num_entries, unix_only));
}
+NTSTATUS pdb_enum_group_members(TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ uint32 **member_rids,
+ int *num_members)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return pdb_context->pdb_enum_group_members(pdb_context, mem_ctx, sid,
+ member_rids, num_members);
+}
+
NTSTATUS pdb_enum_group_memberships(const char *username, gid_t primary_gid,
DOM_SID **sids, gid_t **gids,
int *num_groups)
@@ -1259,6 +1294,116 @@ static void pdb_default_endsampwent(struct pdb_methods *methods)
return; /* NT_STATUS_NOT_IMPLEMENTED; */
}
+static void add_uid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uid_t uid, uid_t **uids, int *num)
+{
+ int i;
+
+ for (i=0; i<*num; i++) {
+ if ((*uids)[i] == uid)
+ return;
+ }
+
+ *uids = TALLOC_REALLOC_ARRAY(mem_ctx, *uids, uid_t, *num+1);
+
+ if (*uids == NULL)
+ return;
+
+ (*uids)[*num] = uid;
+ *num += 1;
+}
+
+static BOOL get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **uids,
+ int *num)
+{
+ struct group *grp;
+ char **gr;
+ struct sys_pwent *userlist, *user;
+
+ *uids = NULL;
+ *num = 0;
+
+ /* We only look at our own sam, so don't care about imported stuff */
+
+ winbind_off();
+
+ if ((grp = getgrgid(gid)) == NULL) {
+ winbind_on();
+ return False;
+ }
+
+ /* Primary group members */
+
+ userlist = getpwent_list();
+
+ for (user = userlist; user != NULL; user = user->next) {
+ if (user->pw_gid != gid)
+ continue;
+ add_uid_to_array_unique(mem_ctx, user->pw_uid, uids, num);
+ }
+
+ pwent_free(userlist);
+
+ /* Secondary group members */
+
+ for (gr = grp->gr_mem; (*gr != NULL) && ((*gr)[0] != '\0'); gr += 1) {
+ struct passwd *pw = getpwnam(*gr);
+
+ if (pw == NULL)
+ continue;
+ add_uid_to_array_unique(mem_ctx, pw->pw_uid, uids, num);
+ }
+
+ winbind_on();
+
+ return True;
+}
+
+NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **member_rids,
+ int *num_members)
+{
+ gid_t gid;
+ uid_t *uids;
+ int i, num_uids;
+
+ *member_rids = NULL;
+ *num_members = 0;
+
+ if (!NT_STATUS_IS_OK(sid_to_gid(group, &gid)))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if(!get_memberuids(mem_ctx, gid, &uids, &num_uids))
+ return NT_STATUS_NO_SUCH_GROUP;
+
+ if (num_uids == 0)
+ return NT_STATUS_OK;
+
+ *member_rids = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_uids);
+
+ for (i=0; i<num_uids; i++) {
+ DOM_SID sid;
+
+ if (!NT_STATUS_IS_OK(uid_to_sid(&sid, uids[i]))) {
+ DEBUG(1, ("Could not map member uid to SID\n"));
+ continue;
+ }
+
+ if (!sid_check_is_in_our_domain(&sid)) {
+ DEBUG(1, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ continue;
+ }
+
+ sid_peek_rid(&sid, &(*member_rids)[*num_members]);
+ *num_members += 1;
+ }
+
+ return NT_STATUS_OK;
+}
+
NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
{
*methods = TALLOC_P(mem_ctx, struct pdb_methods);
@@ -1285,6 +1430,7 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods)
(*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry;
(*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry;
(*methods)->enum_group_mapping = pdb_default_enum_group_mapping;
+ (*methods)->enum_group_members = pdb_default_enum_group_members;
(*methods)->enum_group_memberships = pdb_default_enum_group_memberships;
(*methods)->find_alias = pdb_default_find_alias;
(*methods)->create_alias = pdb_default_create_alias;
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
index 207b587685..e8facf1c2e 100644
--- a/source3/passdb/pdb_ldap.c
+++ b/source3/passdb/pdb_ldap.c
@@ -2165,6 +2165,213 @@ static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
return ldapsam_getgroup(methods, filter, map);
}
+static void add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32 rid, uint32 **rids, int *num)
+{
+ int i;
+
+ for (i=0; i<*num; i++) {
+ if ((*rids)[i] == rid)
+ return;
+ }
+
+ *rids = TALLOC_REALLOC_ARRAY(mem_ctx, *rids, uint32, *num+1);
+
+ if (*rids == NULL)
+ return;
+
+ (*rids)[*num] = rid;
+ *num += 1;
+}
+
+static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group,
+ uint32 **member_rids,
+ int *num_members)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ struct smbldap_state *conn = ldap_state->smbldap_state;
+ pstring filter;
+ int rc, count;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *entry;
+ char **values = NULL;
+ char **memberuid;
+ char *sid_filter = NULL;
+ char *tmp;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (!lp_parm_bool(-1, "ldapsam", "trusted", False))
+ return pdb_default_enum_group_members(methods, mem_ctx, group,
+ member_rids,
+ num_members);
+
+ *member_rids = NULL;
+ *num_members = 0;
+
+ pstr_sprintf(filter,
+ "(&(objectClass=sambaSamAccount)"
+ "(sambaPrimaryGroupSid=%s))",
+ sid_string_static(group));
+
+ {
+ const char *attrs[] = { "sambaSID", NULL };
+ rc = smbldap_search(conn, lp_ldap_user_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0,
+ &msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ for (entry = ldap_first_entry(conn->ldap_struct, msg);
+ entry != NULL;
+ entry = ldap_next_entry(conn->ldap_struct, entry))
+ {
+ fstring str;
+ DOM_SID sid;
+ uint32 rid;
+
+ if (!smbldap_get_single_attribute(conn->ldap_struct,
+ entry, "sambaSID",
+ str, sizeof(str)-1))
+ continue;
+
+ if (!string_to_sid(&sid, str))
+ goto done;
+
+ if (!sid_check_is_in_our_domain(&sid)) {
+ DEBUG(1, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ continue;
+ }
+
+ sid_peek_rid(&sid, &rid);
+
+ add_rid_to_array_unique(mem_ctx, rid, member_rids,
+ num_members);
+ }
+
+ if (msg != NULL)
+ ldap_msgfree(msg);
+
+ pstr_sprintf(filter,
+ "(&(objectClass=sambaGroupMapping)"
+ "(objectClass=posixGroup)"
+ "(sambaSID=%s))",
+ sid_string_static(group));
+
+ {
+ const char *attrs[] = { "memberUid", NULL };
+ rc = smbldap_search(conn, lp_ldap_user_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0,
+ &msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ count = ldap_count_entries(conn->ldap_struct, msg);
+
+ if (count > 1) {
+ DEBUG(1, ("Found more than one groupmap entry for %s\n",
+ sid_string_static(group)));
+ goto done;
+ }
+
+ if (count == 0) {
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ entry = ldap_first_entry(conn->ldap_struct, msg);
+ if (entry == NULL)
+ goto done;
+
+ values = ldap_get_values(conn->ldap_struct, msg, "memberUid");
+ if (values == NULL) {
+ result = NT_STATUS_OK;
+ goto done;
+ }
+
+ sid_filter = strdup("(&(objectClass=sambaSamAccount)(|");
+ if (sid_filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (memberuid = values; *memberuid != NULL; memberuid += 1) {
+ tmp = sid_filter;
+ asprintf(&sid_filter, "%s(uid=%s)", tmp, *memberuid);
+ free(tmp);
+ if (sid_filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ tmp = sid_filter;
+ asprintf(&sid_filter, "%s))", sid_filter);
+ free(tmp);
+ if (sid_filter == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ {
+ const char *attrs[] = { "sambaSID", NULL };
+ rc = smbldap_search(conn, lp_ldap_user_suffix(),
+ LDAP_SCOPE_SUBTREE, sid_filter, attrs, 0,
+ &msg);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ goto done;
+
+ for (entry = ldap_first_entry(conn->ldap_struct, msg);
+ entry != NULL;
+ entry = ldap_next_entry(conn->ldap_struct, entry))
+ {
+ fstring str;
+ DOM_SID sid;
+ uint32 rid;
+
+ if (!smbldap_get_single_attribute(conn->ldap_struct,
+ entry, "sambaSID",
+ str, sizeof(str)-1))
+ continue;
+
+ if (!string_to_sid(&sid, str))
+ goto done;
+
+ if (!sid_check_is_in_our_domain(&sid)) {
+ DEBUG(1, ("Inconsistent SAM -- group member uid not "
+ "in our domain\n"));
+ continue;
+ }
+
+ sid_peek_rid(&sid, &rid);
+
+ add_rid_to_array_unique(mem_ctx, rid, member_rids,
+ num_members);
+ }
+
+ result = NT_STATUS_OK;
+
+ done:
+ SAFE_FREE(sid_filter);
+
+ if (values != NULL)
+ ldap_value_free(values);
+
+ if (msg != NULL)
+ ldap_msgfree(msg);
+
+ return result;
+}
+
static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
const char *username,
gid_t primary_gid,
@@ -2936,6 +3143,7 @@ static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **
(*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
(*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
(*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
+ (*pdb_method)->enum_group_members = ldapsam_enum_group_members;
(*pdb_method)->enum_group_memberships = ldapsam_enum_group_memberships;
/* TODO: Setup private data and free */
diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c
index ec85981cbe..7a436e23e9 100644
--- a/source3/rpc_server/srv_samr_nt.c
+++ b/source3/rpc_server/srv_samr_nt.c
@@ -3434,18 +3434,17 @@ static BOOL get_memberuids(gid_t gid, uid_t **uids, int *num)
NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_R_QUERY_GROUPMEM *r_u)
{
- int final_num_rids, i;
DOM_SID group_sid;
fstring group_sid_str;
- uid_t *uids;
- int num;
- gid_t gid;
+ int i, num_members;
uint32 *rid=NULL;
uint32 *attr=NULL;
uint32 acc_granted;
+ NTSTATUS result;
+
/* find the policy handle. open a policy on it. */
if (!get_lsa_policy_samr_sid(p, &q_u->group_pol, &group_sid, &acc_granted))
return NT_STATUS_INVALID_HANDLE;
@@ -3464,46 +3463,23 @@ NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_
DEBUG(10, ("lookup on Domain SID\n"));
- if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid)))
- return NT_STATUS_NO_SUCH_GROUP;
+ become_root();
+ result = pdb_enum_group_members(p->mem_ctx, &group_sid,
+ &rid, &num_members);
+ unbecome_root();
- if(!get_memberuids(gid, &uids, &num))
- return NT_STATUS_NO_SUCH_GROUP;
+ if (!NT_STATUS_IS_OK(result))
+ return result;
- rid=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num);
- attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num);
+ attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_members);
- if (num!=0 && (rid==NULL || attr==NULL))
+ if ((num_members!=0) && (rid==NULL))
return NT_STATUS_NO_MEMORY;
- final_num_rids = 0;
-
- for (i=0; i<num; i++) {
- DOM_SID sid;
-
- if (!NT_STATUS_IS_OK(uid_to_sid(&sid, uids[i]))) {
- DEBUG(1, ("Could not map member uid to SID\n"));
- continue;
- }
-
- if (!sid_check_is_in_our_domain(&sid)) {
- DEBUG(1, ("Inconsistent SAM -- group member uid not "
- "in our domain\n"));
- continue;
- }
-
- sid_peek_rid(&sid, &rid[final_num_rids]);
-
- /* Hmm. In a trace I got the constant 7 here from NT. */
- attr[final_num_rids] = SID_NAME_USER;
-
- final_num_rids += 1;
- }
-
- SAFE_FREE(uids);
+ for (i=0; i<num_members; i++)
+ attr[i] = SID_NAME_USER;
- init_samr_r_query_groupmem(r_u, final_num_rids, rid, attr,
- NT_STATUS_OK);
+ init_samr_r_query_groupmem(r_u, num_members, rid, attr, NT_STATUS_OK);
return NT_STATUS_OK;
}