diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/passdb.h | 12 | ||||
-rw-r--r-- | source3/passdb/pdb_interface.c | 146 | ||||
-rw-r--r-- | source3/passdb/pdb_ldap.c | 208 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr_nt.c | 52 |
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; } |