summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2004-04-07 12:43:44 +0000
committerGerald Carter <jerry@samba.org>2004-04-07 12:43:44 +0000
commita5f89b6f8c6af1fa8156184709a196fe41f46f8a (patch)
treee94a50dd0252b4fc1f57f04094a1c06e24c80cc4
parent5f71b7bc783f3c92d199808e45bc2c8b20402552 (diff)
downloadsamba-a5f89b6f8c6af1fa8156184709a196fe41f46f8a.tar.gz
r116: volker's patch for local group and group nesting
-rw-r--r--source/Makefile.in1
-rw-r--r--source/groupdb/mapping.c460
-rw-r--r--source/include/ntdomain.h7
-rw-r--r--source/include/passdb.h81
-rw-r--r--source/include/smbldap.h3
-rw-r--r--source/lib/smbldap.c2
-rw-r--r--source/lib/util_str.c18
-rw-r--r--source/libsmb/libsmbclient.c4
-rw-r--r--source/nsswitch/wb_client.c24
-rw-r--r--source/nsswitch/wbinfo.c19
-rw-r--r--source/nsswitch/winbindd.c1
-rw-r--r--source/nsswitch/winbindd.h1
-rw-r--r--source/nsswitch/winbindd_group.c136
-rw-r--r--source/nsswitch/winbindd_nss.h3
-rw-r--r--source/nsswitch/winbindd_passdb.c339
-rw-r--r--source/nsswitch/winbindd_sid.c33
-rw-r--r--source/nsswitch/winbindd_util.c43
-rw-r--r--source/param/loadparm.c4
-rw-r--r--source/passdb/pdb_interface.c300
-rw-r--r--source/passdb/pdb_ldap.c288
-rw-r--r--source/passdb/util_sam_sid.c13
-rw-r--r--source/rpc_server/srv_lsa_nt.c5
-rw-r--r--source/rpc_server/srv_samr_nt.c451
-rw-r--r--source/utils/net_groupmap.c108
24 files changed, 2003 insertions, 341 deletions
diff --git a/source/Makefile.in b/source/Makefile.in
index 3bb578ea84b..51b32b44311 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -627,6 +627,7 @@ WINBINDD_OBJ1 = \
nsswitch/winbindd_wins.o \
nsswitch/winbindd_rpc.o \
nsswitch/winbindd_ads.o \
+ nsswitch/winbindd_passdb.o \
nsswitch/winbindd_dual.o \
nsswitch/winbindd_acct.o
diff --git a/source/groupdb/mapping.c b/source/groupdb/mapping.c
index d10a7decb7e..548651dfd53 100644
--- a/source/groupdb/mapping.c
+++ b/source/groupdb/mapping.c
@@ -28,6 +28,13 @@ static TDB_CONTEXT *tdb; /* used for driver files */
#define GROUP_PREFIX "UNIXGROUP/"
+/* Alias memberships are stored reverse, as memberships. The performance
+ * critical operation is to determine the aliases a SID is member of, not
+ * listing alias members. So we store a list of alias SIDs a SID is member of
+ * hanging of the member as key.
+ */
+#define MEMBEROF_PREFIX "MEMBEROF/"
+
PRIVS privs[] = {
{SE_PRIV_NONE, "no_privs", "No privilege" }, /* this one MUST be first */
{SE_PRIV_ADD_MACHINES, "SeMachineAccountPrivilege", "Add workstations to the domain" },
@@ -489,6 +496,284 @@ static BOOL enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
return True;
}
+/* This operation happens on session setup, so it should better be fast. We
+ * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
+
+static NTSTATUS alias_memberships(const DOM_SID *sid, DOM_SID **sids, int *num)
+{
+ fstring key, string_sid;
+ TDB_DATA kbuf, dbuf;
+ const char *p;
+
+ *num = 0;
+ *sids = NULL;
+
+ if (!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ sid_to_string(string_sid, sid);
+ slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX, string_sid);
+
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ if (dbuf.dptr == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ p = dbuf.dptr;
+
+ while (next_token(&p, string_sid, " ", sizeof(string_sid))) {
+
+ DOM_SID alias;
+
+ if (!string_to_sid(&alias, string_sid))
+ continue;
+
+ add_sid_to_array(&alias, sids, num);
+
+ if (sids == NULL)
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SAFE_FREE(dbuf.dptr);
+ return NT_STATUS_OK;
+}
+
+static BOOL is_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ DOM_SID *sids;
+ int i, num;
+
+ /* This feels the wrong way round, but the on-disk data structure
+ * dictates it this way. */
+ if (!NT_STATUS_IS_OK(alias_memberships(member, &sids, &num)))
+ return False;
+
+ for (i=0; i<num; i++) {
+ if (sid_compare(alias, &sids[i]) == 0) {
+ SAFE_FREE(sids);
+ return True;
+ }
+ }
+ SAFE_FREE(sids);
+ return False;
+}
+
+static NTSTATUS add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ GROUP_MAP map;
+ TDB_DATA kbuf, dbuf;
+ pstring key;
+ fstring string_sid;
+ char *new_memberstring;
+ int result;
+
+ if(!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (!get_group_map_from_sid(*alias, &map))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ( (map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP) )
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if (is_aliasmem(alias, member))
+ return NT_STATUS_MEMBER_IN_ALIAS;
+
+ sid_to_string(string_sid, member);
+ slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX, string_sid);
+
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+
+ dbuf = tdb_fetch(tdb, kbuf);
+
+ sid_to_string(string_sid, alias);
+
+ if (dbuf.dptr != NULL) {
+ asprintf(&new_memberstring, "%s %s", (char *)(dbuf.dptr),
+ string_sid);
+ } else {
+ new_memberstring = strdup(string_sid);
+ }
+
+ if (new_memberstring == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ SAFE_FREE(dbuf.dptr);
+ dbuf.dsize = strlen(new_memberstring)+1;
+ dbuf.dptr = new_memberstring;
+
+ result = tdb_store(tdb, kbuf, dbuf, 0);
+
+ SAFE_FREE(new_memberstring);
+
+ return (result == 0 ? NT_STATUS_OK : NT_STATUS_ACCESS_DENIED);
+}
+
+struct aliasmem_closure {
+ const DOM_SID *alias;
+ DOM_SID **sids;
+ int *num;
+};
+
+static int collect_aliasmem(TDB_CONTEXT *tdb_ctx, TDB_DATA key, TDB_DATA data,
+ void *state)
+{
+ struct aliasmem_closure *closure = (struct aliasmem_closure *)state;
+ const char *p;
+ fstring alias_string;
+
+ if (strncmp(key.dptr, MEMBEROF_PREFIX,
+ strlen(MEMBEROF_PREFIX)) != 0)
+ return 0;
+
+ p = data.dptr;
+
+ while (next_token(&p, alias_string, " ", sizeof(alias_string))) {
+
+ DOM_SID alias, member;
+ const char *member_string;
+
+
+ if (!string_to_sid(&alias, alias_string))
+ continue;
+
+ if (sid_compare(closure->alias, &alias) != 0)
+ continue;
+
+ /* Ok, we found the alias we're looking for in the membership
+ * list currently scanned. The key represents the alias
+ * member. Add that. */
+
+ member_string = strchr(key.dptr, '/');
+
+ /* Above we tested for MEMBEROF_PREFIX which includes the
+ * slash. */
+
+ SMB_ASSERT(member_string != NULL);
+ member_string += 1;
+
+ if (!string_to_sid(&member, member_string))
+ continue;
+
+ add_sid_to_array(&member, closure->sids, closure->num);
+ }
+
+ return 0;
+}
+
+static NTSTATUS enum_aliasmem(const DOM_SID *alias, DOM_SID **sids, int *num)
+{
+ GROUP_MAP map;
+ struct aliasmem_closure closure;
+
+ if(!init_group_mapping()) {
+ DEBUG(0,("failed to initialize group mapping\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (!get_group_map_from_sid(*alias, &map))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ( (map.sid_name_use != SID_NAME_ALIAS) &&
+ (map.sid_name_use != SID_NAME_WKN_GRP) )
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ *sids = NULL;
+ *num = 0;
+
+ closure.alias = alias;
+ closure.sids = sids;
+ closure.num = num;
+
+ tdb_traverse(tdb, collect_aliasmem, &closure);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS del_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ NTSTATUS result;
+ DOM_SID *sids;
+ int i, num;
+ BOOL found = False;
+ char *member_string;
+ TDB_DATA kbuf, dbuf;
+ pstring key;
+ fstring sid_string;
+
+ result = alias_memberships(member, &sids, &num);
+
+ if (!NT_STATUS_IS_OK(result))
+ return result;
+
+ for (i=0; i<num; i++) {
+ if (sid_compare(&sids[i], alias) == 0) {
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) {
+ SAFE_FREE(sids);
+ return NT_STATUS_MEMBER_NOT_IN_ALIAS;
+ }
+
+ if (i < num)
+ sids[i] = sids[num-1];
+
+ num -= 1;
+
+ sid_to_string(sid_string, member);
+ slprintf(key, sizeof(key), "%s%s", MEMBEROF_PREFIX, sid_string);
+
+ kbuf.dsize = strlen(key)+1;
+ kbuf.dptr = key;
+
+ if (num == 0)
+ return tdb_delete(tdb, kbuf) == 0 ?
+ NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+
+ member_string = strdup("");
+
+ if (member_string == NULL) {
+ SAFE_FREE(sids);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0; i<num; i++) {
+ char *s = member_string;
+
+ sid_to_string(sid_string, &sids[i]);
+ asprintf(&member_string, "%s %s", s, sid_string);
+
+ SAFE_FREE(s);
+ if (member_string == NULL) {
+ SAFE_FREE(sids);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ dbuf.dsize = strlen(member_string)+1;
+ dbuf.dptr = member_string;
+
+ result = tdb_store(tdb, kbuf, dbuf, 0) == 0 ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+
+ SAFE_FREE(sids);
+ SAFE_FREE(member_string);
+
+ return result;
+}
+
/*
*
* High level functions
@@ -568,7 +853,8 @@ BOOL get_local_group_from_sid(DOM_SID *sid, GROUP_MAP *map)
if ( !ret )
return False;
- if ( (map->sid_name_use != SID_NAME_ALIAS)
+ if ( ( (map->sid_name_use != SID_NAME_ALIAS) &&
+ (map->sid_name_use != SID_NAME_WKN_GRP) )
|| (map->gid == -1)
|| (getgrgid(map->gid) == NULL) )
{
@@ -1029,6 +1315,178 @@ NTSTATUS pdb_default_enum_group_mapping(struct pdb_methods *methods,
NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
}
+NTSTATUS pdb_default_find_alias(struct pdb_methods *methods,
+ const char *name, DOM_SID *sid)
+{
+ GROUP_MAP map;
+
+ if (!pdb_getgrnam(&map, name))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ if ((map.sid_name_use != SID_NAME_WKN_GRP) &&
+ (map.sid_name_use != SID_NAME_ALIAS))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ sid_copy(sid, &map.sid);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_create_alias(struct pdb_methods *methods,
+ const char *name, uint32 *rid)
+{
+ DOM_SID sid;
+ enum SID_NAME_USE type;
+ uint32 new_rid;
+ gid_t gid;
+
+ GROUP_MAP map;
+
+ if (lookup_name(get_global_sam_name(), name, &sid, &type))
+ return NT_STATUS_ALIAS_EXISTS;
+
+ if (!winbind_allocate_rid(&new_rid))
+ return NT_STATUS_ACCESS_DENIED;
+
+ sid_copy(&sid, get_global_sam_sid());
+ sid_append_rid(&sid, new_rid);
+
+ /* Here we allocate the gid */
+ if (!winbind_sid_to_gid(&gid, &sid)) {
+ DEBUG(0, ("Could not get gid for new RID\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ map.gid = gid;
+ sid_copy(&map.sid, &sid);
+ map.sid_name_use = SID_NAME_ALIAS;
+ fstrcpy(map.nt_name, name);
+ fstrcpy(map.comment, "");
+
+ if (!pdb_add_group_mapping_entry(&map)) {
+ DEBUG(0, ("Could not add group mapping entry for alias %s\n",
+ name));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ *rid = new_rid;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_delete_alias(struct pdb_methods *methods,
+ const DOM_SID *sid)
+{
+ return pdb_delete_group_mapping_entry(*sid) ?
+ NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
+}
+
+NTSTATUS pdb_default_enum_aliases(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ uint32 start_idx, uint32 max_entries,
+ uint32 *num_aliases,
+ struct acct_info **info)
+{
+ extern DOM_SID global_sid_Builtin;
+
+ GROUP_MAP *map;
+ int i, num_maps;
+ enum SID_NAME_USE type = SID_NAME_UNKNOWN;
+
+ if (sid_compare(sid, get_global_sam_sid()) == 0)
+ type = SID_NAME_ALIAS;
+
+ if (sid_compare(sid, &global_sid_Builtin) == 0)
+ type = SID_NAME_WKN_GRP;
+
+ if (!pdb_enum_group_mapping(type, &map, &num_maps, False) ||
+ (num_maps == 0)) {
+ *num_aliases = 0;
+ *info = NULL;
+ goto done;
+ }
+
+ if (start_idx > num_maps) {
+ *num_aliases = 0;
+ *info = NULL;
+ goto done;
+ }
+
+ *num_aliases = num_maps - start_idx;
+
+ if (*num_aliases > max_entries)
+ *num_aliases = max_entries;
+
+ *info = malloc(sizeof(struct acct_info) * (*num_aliases));
+
+ for (i=0; i<*num_aliases; i++) {
+ fstrcpy((*info)[i].acct_name, map[i+start_idx].nt_name);
+ fstrcpy((*info)[i].acct_desc, map[i+start_idx].comment);
+ sid_peek_rid(&map[i].sid, &(*info)[i+start_idx].rid);
+ }
+
+ done:
+ SAFE_FREE(map);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_get_aliasinfo(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info)
+{
+ GROUP_MAP map;
+
+ if (!pdb_getgrsid(&map, *sid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ fstrcpy(info->acct_name, map.nt_name);
+ fstrcpy(info->acct_desc, map.comment);
+ sid_peek_rid(&map.sid, &info->rid);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_set_aliasinfo(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info)
+{
+ GROUP_MAP map;
+
+ if (!pdb_getgrsid(&map, *sid))
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ fstrcpy(map.comment, info->acct_desc);
+
+ if (!pdb_update_group_mapping_entry(&map))
+ return NT_STATUS_ACCESS_DENIED;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pdb_default_add_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member)
+{
+ return add_aliasmem(alias, member);
+}
+
+NTSTATUS pdb_default_del_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member)
+{
+ return del_aliasmem(alias, member);
+}
+
+NTSTATUS pdb_default_enum_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, DOM_SID **members,
+ int *num_members)
+{
+ return enum_aliasmem(alias, members, num_members);
+}
+
+NTSTATUS pdb_default_alias_memberships(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ DOM_SID **aliases, int *num)
+{
+ return alias_memberships(sid, aliases, num);
+}
+
/**********************************************************************
no ops for passdb backends that don't implement group mapping
*********************************************************************/
diff --git a/source/include/ntdomain.h b/source/include/ntdomain.h
index b1a4107980d..9640f2e53bf 100644
--- a/source/include/ntdomain.h
+++ b/source/include/ntdomain.h
@@ -366,13 +366,6 @@ typedef struct
} rid_name;
-struct acct_info
-{
- fstring acct_name; /* account name */
- fstring acct_desc; /* account name */
- uint32 rid; /* domain-relative RID */
-};
-
/*
* higher order functions for use with msrpc client code
*/
diff --git a/source/include/passdb.h b/source/include/passdb.h
index 75c4fd215bf..d08fd13a723 100644
--- a/source/include/passdb.h
+++ b/source/include/passdb.h
@@ -223,6 +223,12 @@ typedef struct sam_group {
} SAM_GROUP;
+struct acct_info
+{
+ fstring acct_name; /* account name */
+ fstring acct_desc; /* account name */
+ uint32 rid; /* domain-relative RID */
+};
/*****************************************************************
Functions to be implemented by the new (v2) passdb API
@@ -233,7 +239,7 @@ typedef struct sam_group {
* this SAMBA will load. Increment this if *ANY* changes are made to the interface.
*/
-#define PASSDB_INTERFACE_VERSION 4
+#define PASSDB_INTERFACE_VERSION 5
typedef struct pdb_context
{
@@ -279,6 +285,46 @@ typedef struct pdb_context
GROUP_MAP **rmap, int *num_entries,
BOOL unix_only);
+ NTSTATUS (*pdb_find_alias)(struct pdb_context *context,
+ const char *name, DOM_SID *sid);
+
+ NTSTATUS (*pdb_create_alias)(struct pdb_context *context,
+ const char *name, uint32 *rid);
+
+ NTSTATUS (*pdb_delete_alias)(struct pdb_context *context,
+ const DOM_SID *sid);
+
+ NTSTATUS (*pdb_enum_aliases)(struct pdb_context *context,
+ const DOM_SID *domain_sid,
+ uint32 start_idx, uint32 num_entries,
+ uint32 *num_aliases,
+ struct acct_info **aliases);
+
+ NTSTATUS (*pdb_get_aliasinfo)(struct pdb_context *context,
+ const DOM_SID *sid,
+ struct acct_info *info);
+
+ NTSTATUS (*pdb_set_aliasinfo)(struct pdb_context *context,
+ const DOM_SID *sid,
+ struct acct_info *info);
+
+ NTSTATUS (*pdb_add_aliasmem)(struct pdb_context *context,
+ const DOM_SID *alias,
+ const DOM_SID *member);
+
+ NTSTATUS (*pdb_del_aliasmem)(struct pdb_context *context,
+ const DOM_SID *alias,
+ const DOM_SID *member);
+
+ NTSTATUS (*pdb_enum_aliasmem)(struct pdb_context *context,
+ const DOM_SID *alias,
+ DOM_SID **members, int *num_members);
+
+ NTSTATUS (*pdb_enum_alias_memberships)(struct pdb_context *context,
+ const DOM_SID *alias,
+ DOM_SID **aliases,
+ int *num);
+
void (*free_fn)(struct pdb_context **);
TALLOC_CTX *mem_ctx;
@@ -330,6 +376,39 @@ typedef struct pdb_methods
GROUP_MAP **rmap, int *num_entries,
BOOL unix_only);
+ NTSTATUS (*find_alias)(struct pdb_methods *methods,
+ const char *name, DOM_SID *sid);
+
+ NTSTATUS (*create_alias)(struct pdb_methods *methods,
+ const char *name, uint32 *rid);
+
+ NTSTATUS (*delete_alias)(struct pdb_methods *methods,
+ const DOM_SID *sid);
+
+ NTSTATUS (*enum_aliases)(struct pdb_methods *methods,
+ const DOM_SID *domain_sid,
+ uint32 start_idx, uint32 max_entries,
+ uint32 *num_aliases, struct acct_info **info);
+
+ NTSTATUS (*get_aliasinfo)(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info);
+
+ NTSTATUS (*set_aliasinfo)(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ struct acct_info *info);
+
+ NTSTATUS (*add_aliasmem)(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member);
+ NTSTATUS (*del_aliasmem)(struct pdb_methods *methods,
+ const DOM_SID *alias, const DOM_SID *member);
+ NTSTATUS (*enum_aliasmem)(struct pdb_methods *methods,
+ const DOM_SID *alias, DOM_SID **members,
+ int *num_members);
+ NTSTATUS (*enum_alias_memberships)(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ DOM_SID **aliases, int *num);
+
void *private_data; /* Private data of some kind */
void (*free_private_data)(void **);
diff --git a/source/include/smbldap.h b/source/include/smbldap.h
index 2f71f971d92..61b8df0f0ef 100644
--- a/source/include/smbldap.h
+++ b/source/include/smbldap.h
@@ -49,6 +49,7 @@
#define LDAP_ATTRIBUTE_SID "sambaSID"
#define LDAP_ATTRIBUTE_UIDNUMBER "uidNumber"
#define LDAP_ATTRIBUTE_GIDNUMBER "gidNumber"
+#define LDAP_ATTRIBUTE_SID_LIST "sambaSIDList"
/* attribute map table indexes */
@@ -93,6 +94,8 @@
#define LDAP_ATTR_MUNGED_DIAL 37
#define LDAP_ATTR_BAD_PASSWORD_TIME 38
+#define LDAP_ATTR_SID_LIST 40
+
typedef struct _attrib_map_entry {
int attrib;
const char *name;
diff --git a/source/lib/smbldap.c b/source/lib/smbldap.c
index f4f0170479f..21e2a7c1018 100644
--- a/source/lib/smbldap.c
+++ b/source/lib/smbldap.c
@@ -122,6 +122,7 @@ ATTRIB_MAP_ENTRY groupmap_attr_list[] = {
{ LDAP_ATTR_GIDNUMBER, LDAP_ATTRIBUTE_GIDNUMBER},
{ LDAP_ATTR_GROUP_SID, LDAP_ATTRIBUTE_SID },
{ LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
+ { LDAP_ATTR_SID_LIST, "sambaSIDList" },
{ LDAP_ATTR_DESC, "description" },
{ LDAP_ATTR_DISPLAY_NAME, "displayName" },
{ LDAP_ATTR_CN, "cn" },
@@ -134,6 +135,7 @@ ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = {
{ LDAP_ATTR_GROUP_TYPE, "sambaGroupType" },
{ LDAP_ATTR_DESC, "description" },
{ LDAP_ATTR_DISPLAY_NAME, "displayName" },
+ { LDAP_ATTR_SID_LIST, "sambaSIDList" },
{ LDAP_ATTR_LIST_END, NULL }
};
diff --git a/source/lib/util_str.c b/source/lib/util_str.c
index e4b07a4b731..600c830aced 100644
--- a/source/lib/util_str.c
+++ b/source/lib/util_str.c
@@ -2038,3 +2038,21 @@ SMB_BIG_UINT STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr)
return val;
}
+
+void string_append(char **left, const char *right)
+{
+ int new_len = strlen(right) + 1;
+
+ if (*left == NULL) {
+ *left = malloc(new_len);
+ *left[0] = '\0';
+ } else {
+ new_len += strlen(*left);
+ *left = Realloc(*left, new_len);
+ }
+
+ if (*left == NULL)
+ return;
+
+ safe_strcat(*left, right, new_len-1);
+}
diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c
index 68bb6661ebd..ebbf28a12db 100644
--- a/source/libsmb/libsmbclient.c
+++ b/source/libsmb/libsmbclient.c
@@ -246,7 +246,7 @@ smbc_parse_path(SMBCCTX *context,
p += 2; /* Skip the double slash */
/* See if any options were specified */
- if (q = strrchr(p, '?')) {
+ if ( (q = strrchr(p, '?')) != NULL ) {
/* There are options. Null terminate here and point to them */
*q++ = '\0';
@@ -537,9 +537,7 @@ SMBCSRV *smbc_server(SMBCCTX *context,
SMBCSRV *srv=NULL;
struct cli_state c;
struct nmb_name called, calling;
- char *p;
const char *server_n = server;
- fstring group;
pstring ipenv;
struct in_addr ip;
int tried_reverse = 0;
diff --git a/source/nsswitch/wb_client.c b/source/nsswitch/wb_client.c
index 90e4584daba..5d431392450 100644
--- a/source/nsswitch/wb_client.c
+++ b/source/nsswitch/wb_client.c
@@ -235,6 +235,30 @@ BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
return (result == NSS_STATUS_SUCCESS);
}
+BOOL winbind_allocate_rid(uint32 *rid)
+{
+ struct winbindd_request request;
+ struct winbindd_response response;
+ int result;
+
+ /* Initialise request */
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ /* Make request */
+
+ result = winbindd_request(WINBINDD_ALLOCATE_RID, &request, &response);
+
+ if (result != NSS_STATUS_SUCCESS)
+ return False;
+
+ /* Copy out result */
+ *rid = response.data.rid;
+
+ return True;
+}
+
/* Fetch the list of groups a user is a member of from winbindd. This is
used by winbind_getgroups. */
diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c
index 2cea4130adc..ce48e9ae652 100644
--- a/source/nsswitch/wbinfo.c
+++ b/source/nsswitch/wbinfo.c
@@ -436,6 +436,18 @@ static BOOL wbinfo_sid_to_gid(char *sid)
return True;
}
+static BOOL wbinfo_allocate_rid(void)
+{
+ uint32 rid;
+
+ if (!winbind_allocate_rid(&rid))
+ return False;
+
+ d_printf("New rid: %d\n", rid);
+
+ return True;
+}
+
/* Convert sid to string */
static BOOL wbinfo_lookupsid(char *sid)
@@ -1042,6 +1054,7 @@ int main(int argc, char **argv)
{ "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" },
{ "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" },
{ "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
+ { "allocate-rid", 'A', POPT_ARG_NONE, 0, 'A', "Get a new RID out of idmap" },
{ "create-user", 'c', POPT_ARG_STRING, &string_arg, 'c', "Create a local user account", "name" },
{ "delete-user", 'x', POPT_ARG_STRING, &string_arg, 'x', "Delete a local user account", "name" },
{ "create-group", 'C', POPT_ARG_STRING, &string_arg, 'C', "Create a local group", "name" },
@@ -1164,6 +1177,12 @@ int main(int argc, char **argv)
goto done;
}
break;
+ case 'A':
+ if (!wbinfo_allocate_rid()) {
+ d_printf("Could not allocate a RID\n");
+ goto done;
+ }
+ break;
case 't':
if (!wbinfo_check_secret()) {
d_printf("Could not check secret\n");
diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c
index b55ea297b49..283b2e4a89c 100644
--- a/source/nsswitch/winbindd.c
+++ b/source/nsswitch/winbindd.c
@@ -255,6 +255,7 @@ static struct dispatch_table dispatch_table[] = {
{ WINBINDD_SID_TO_GID, winbindd_sid_to_gid, "SID_TO_GID" },
{ WINBINDD_GID_TO_SID, winbindd_gid_to_sid, "GID_TO_SID" },
{ WINBINDD_UID_TO_SID, winbindd_uid_to_sid, "UID_TO_SID" },
+ { WINBINDD_ALLOCATE_RID, winbindd_allocate_rid, "ALLOCATE_RID" },
/* Miscellaneous */
diff --git a/source/nsswitch/winbindd.h b/source/nsswitch/winbindd.h
index 0087d58195d..5c05a1b0457 100644
--- a/source/nsswitch/winbindd.h
+++ b/source/nsswitch/winbindd.h
@@ -97,6 +97,7 @@ struct winbindd_domain {
BOOL native_mode; /* is this a win2k domain in native mode ? */
BOOL active_directory; /* is this a win2k active directory ? */
BOOL primary; /* is this our primary domain ? */
+ BOOL internal; /* BUILTIN and member SAM */
/* Lookup methods for this domain (LDAP or RPC) */
struct winbindd_methods *methods;
diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c
index 3ee8c0877b5..f9b6df1aed9 100644
--- a/source/nsswitch/winbindd_group.c
+++ b/source/nsswitch/winbindd_group.c
@@ -106,6 +106,15 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
DEBUG(10, ("group SID %s\n", sid_to_string(sid_string, group_sid)));
*num_gr_mem = 0;
+
+ /* HACK ALERT!! This whole routine does not cope with group members
+ * from more than one domain, ie aliases. Thus we have to work it out
+ * ourselves in a special routine. */
+
+ if (domain->internal)
+ return fill_passdb_alias_grmem(domain, group_sid,
+ num_gr_mem,
+ gr_mem, gr_mem_len);
if ( !((group_name_type==SID_NAME_DOM_GRP) ||
((group_name_type==SID_NAME_ALIAS) && domain->primary)) )
@@ -243,14 +252,11 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
/* if no domain or our local domain, then do a local tdb search */
- if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
+ if ( (!*name_domain || strequal(name_domain, get_global_sam_name())) &&
+ ((grp = wb_getgrnam(name_group)) != NULL) ) {
+
char *buffer = NULL;
- if ( !(grp=wb_getgrnam(name_group)) ) {
- DEBUG(5,("winbindd_getgrnam: lookup for %s\\%s failed\n",
- name_domain, name_group));
- return WINBINDD_ERROR;
- }
memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
@@ -262,6 +268,13 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
+ /* if no domain or our local domain and no local tdb group, default to
+ * our local domain for aliases */
+
+ if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
+ fstrcpy(name_domain, get_global_sam_name());
+ }
+
/* Get info for the domain */
if ((domain = find_domain_from_name(name_domain)) == NULL) {
@@ -287,7 +300,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
}
if ( !((name_type==SID_NAME_DOM_GRP) ||
- ((name_type==SID_NAME_ALIAS) && domain->primary)) )
+ ((name_type==SID_NAME_ALIAS) && domain->primary) ||
+ ((name_type==SID_NAME_ALIAS) && domain->internal)) )
{
DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
name_group, name_type));
@@ -378,7 +392,8 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
}
if ( !((name_type==SID_NAME_DOM_GRP) ||
- ((name_type==SID_NAME_ALIAS) && domain->primary) ))
+ ((name_type==SID_NAME_ALIAS) && domain->primary) ||
+ ((name_type==SID_NAME_ALIAS) && domain->internal)) )
{
DEBUG(1, ("name '%s' is not a local or domain group: %d\n",
group_name, name_type));
@@ -541,8 +556,8 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
/* get the domain local groups if we are a member of a native win2k domain
and are not using LDAP to get the groups */
- if ( lp_security() != SEC_ADS && domain->native_mode
- && domain->primary )
+ if ( ( lp_security() != SEC_ADS && domain->native_mode
+ && domain->primary) || domain->internal )
{
DEBUG(4,("get_sam_group_entries: Native Mode 2k domain; enumerating local groups as well\n"));
@@ -898,6 +913,61 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
return WINBINDD_OK;
}
+static void add_gid_to_array_unique(gid_t gid, gid_t **gids, int *num)
+{
+ int i;
+
+ if ((*num) >= groups_max())
+ return;
+
+ for (i=0; i<*num; i++) {
+ if ((*gids)[i] == gid)
+ return;
+ }
+
+ *gids = Realloc(*gids, (*num+1) * sizeof(gid_t));
+
+ if (*gids == NULL)
+ return;
+
+ (*gids)[*num] = gid;
+ *num += 1;
+}
+
+static void add_gids_from_sid(DOM_SID *sid, gid_t **gids, int *num)
+{
+ gid_t gid;
+ DOM_SID *aliases;
+ int j, num_aliases;
+
+ DEBUG(10, ("Adding gids from SID: %s\n", sid_string_static(sid)));
+
+ if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &gid, 0)))
+ add_gid_to_array_unique(gid, gids, num);
+
+ /* Don't expand aliases if not explicitly activated -- for now */
+ /* we don't support windows local nested groups if we are a DC.
+ refer to to sid_to_gid() in the smbd server code to see why
+ -- jerry */
+
+ if (!lp_winbind_nested_groups() || IS_DC)
+ return;
+
+ /* Add nested group memberships */
+
+ if (!pdb_enum_alias_memberships(sid, &aliases, &num_aliases))
+ return;
+
+ for (j=0; j<num_aliases; j++) {
+
+ if (!NT_STATUS_IS_OK(sid_to_gid(&aliases[j], &gid)))
+ continue;
+
+ add_gid_to_array_unique(gid, gids, num);
+ }
+ SAFE_FREE(aliases);
+}
+
/* Get user supplementary groups. This is much quicker than trying to
invert the groups database. We merge the groups from the gids and
other_sids info3 fields as trusted domain, universal group
@@ -915,7 +985,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
DOM_SID **user_grpsids;
struct winbindd_domain *domain;
enum winbindd_result result = WINBINDD_ERROR;
- gid_t *gid_list;
+ gid_t *gid_list = NULL;
unsigned int i;
TALLOC_CTX *mem_ctx;
NET_USER_INFO_3 *info3 = NULL;
@@ -963,6 +1033,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
goto done;
}
+ add_gids_from_sid(&user_sid, &gid_list, &num_gids);
+
/* Treat the info3 cache as authoritative as the
lookup_usergroups() function may return cached data. */
@@ -972,7 +1044,6 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
info3->num_groups2, info3->num_other_sids));
num_groups = info3->num_other_sids + info3->num_groups2;
- gid_list = calloc(sizeof(gid_t), num_groups);
/* Go through each other sid and convert it to a gid */
@@ -1006,23 +1077,11 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
continue;
}
- /* Map to a gid */
+ add_gids_from_sid(&info3->other_sids[i].sid,
+ &gid_list, &num_gids);
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&info3->other_sids[i].sid, &gid_list[num_gids], 0)) )
- {
- DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
- sid_string_static(&info3->other_sids[i].sid)));
- continue;
- }
-
- /* We've jumped through a lot of hoops to get here */
-
- DEBUG(10, ("winbindd_getgroups: mapped other sid %s to "
- "gid %lu\n", sid_string_static(
- &info3->other_sids[i].sid),
- (unsigned long)gid_list[num_gids]));
-
- num_gids++;
+ if (gid_list == NULL)
+ goto done;
}
for (i = 0; i < info3->num_groups2; i++) {
@@ -1032,12 +1091,10 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
sid_copy( &group_sid, &domain->sid );
sid_append_rid( &group_sid, info3->gids[i].g_rid );
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid_list[num_gids], 0)) ) {
- DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n",
- sid_string_static(&group_sid)));
- }
+ add_gids_from_sid(&group_sid, &gid_list, &num_gids);
- num_gids++;
+ if (gid_list == NULL)
+ goto done;
}
SAFE_FREE(info3);
@@ -1049,18 +1106,15 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
if (!NT_STATUS_IS_OK(status))
goto done;
- gid_list = malloc(sizeof(gid_t) * num_groups);
-
if (state->response.extra_data)
goto done;
for (i = 0; i < num_groups; i++) {
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_grpsids[i], &gid_list[num_gids], 0))) {
- DEBUG(1, ("unable to convert group sid %s to gid\n",
- sid_string_static(user_grpsids[i])));
- continue;
- }
- num_gids++;
+ add_gids_from_sid(user_grpsids[i],
+ &gid_list, &num_gids);
+
+ if (gid_list == NULL)
+ goto done;
}
}
diff --git a/source/nsswitch/winbindd_nss.h b/source/nsswitch/winbindd_nss.h
index 73b39569a96..8167cfafa86 100644
--- a/source/nsswitch/winbindd_nss.h
+++ b/source/nsswitch/winbindd_nss.h
@@ -84,6 +84,7 @@ enum winbindd_cmd {
WINBINDD_SID_TO_GID,
WINBINDD_UID_TO_SID,
WINBINDD_GID_TO_SID,
+ WINBINDD_ALLOCATE_RID,
/* Miscellaneous other stuff */
@@ -270,7 +271,7 @@ struct winbindd_response {
char user_session_key[16];
char first_8_lm_hash[8];
} auth;
- uint32 rid; /* create user or group */
+ uint32 rid; /* create user or group or allocate rid */
struct {
fstring name;
fstring alt_name;
diff --git a/source/nsswitch/winbindd_passdb.c b/source/nsswitch/winbindd_passdb.c
new file mode 100644
index 00000000000..36f5297efeb
--- /dev/null
+++ b/source/nsswitch/winbindd_passdb.c
@@ -0,0 +1,339 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind rpc backend functions
+
+ Copyright (C) Tim Potter 2000-2001,2003
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Volker Lendecke 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+static void
+add_member(const char *domain, const char *user,
+ char **members, int *num_members)
+{
+ fstring name;
+
+ fill_domain_username(name, domain, user);
+ safe_strcat(name, ",", sizeof(name)-1);
+ string_append(members, name);
+ *num_members += 1;
+}
+
+/**********************************************************************
+ Add member users resulting from sid. Expand if it is a domain group.
+**********************************************************************/
+
+static void
+add_expanded_sid(const DOM_SID *sid, char **members, int *num_members)
+{
+ DOM_SID dom_sid;
+ uint32 rid;
+ struct winbindd_domain *domain;
+ int i;
+
+ char *name = NULL;
+ enum SID_NAME_USE type;
+
+ uint32 num_names;
+ DOM_SID **sid_mem;
+ char **names;
+ uint32 *types;
+
+ NTSTATUS result;
+
+ TALLOC_CTX *mem_ctx = talloc_init("add_expanded_sid");
+
+ if (mem_ctx == NULL) {
+ DEBUG(1, ("talloc_init failed\n"));
+ return;
+ }
+
+ sid_copy(&dom_sid, sid);
+ sid_split_rid(&dom_sid, &rid);
+
+ domain = find_domain_from_sid(&dom_sid);
+
+ if (domain == NULL) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_static(sid)));
+ goto done;
+ }
+
+ result = domain->methods->sid_to_name(domain, mem_ctx, sid,
+ &name, &type);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3, ("sid_to_name failed for sid %s\n",
+ sid_string_static(sid)));
+ goto done;
+ }
+
+ DEBUG(10, ("Found name %s, type %d\n", name, type));
+
+ if (type == SID_NAME_USER) {
+ add_member(domain->name, name, members, num_members);
+ goto done;
+ }
+
+ if (type != SID_NAME_DOM_GRP) {
+ DEBUG(10, ("Alias member %s neither user nor group, ignore\n",
+ name));
+ goto done;
+ }
+
+ /* Expand the domain group */
+
+ result = domain->methods->lookup_groupmem(domain, mem_ctx,
+ sid, &num_names,
+ &sid_mem, &names,
+ &types);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("Could not lookup group members for %s: %s\n",
+ name, nt_errstr(result)));
+ goto done;
+ }
+
+ for (i=0; i<num_names; i++) {
+ DEBUG(10, ("Adding group member SID %s\n",
+ sid_string_static(sid_mem[i])));
+
+ if (types[i] != SID_NAME_USER) {
+ DEBUG(1, ("Hmmm. Member %s of group %s is no user. "
+ "Ignoring.\n", names[i], name));
+ continue;
+ }
+
+ add_member(domain->name, names[i], members, num_members);
+ }
+
+ done:
+ talloc_destroy(mem_ctx);
+ return;
+}
+
+BOOL fill_passdb_alias_grmem(struct winbindd_domain *domain,
+ DOM_SID *group_sid,
+ int *num_gr_mem, char **gr_mem, int *gr_mem_len)
+{
+ DOM_SID *members;
+ int i, num_members;
+
+ *num_gr_mem = 0;
+ *gr_mem = NULL;
+ *gr_mem_len = 0;
+
+ if (!pdb_enum_aliasmem(group_sid, &members, &num_members))
+ return True;
+
+ for (i=0; i<num_members; i++) {
+ add_expanded_sid(&members[i], gr_mem, num_gr_mem);
+ }
+
+ SAFE_FREE(members);
+
+ if (*gr_mem != NULL) {
+ int len;
+
+ /* We have at least one member, strip off the last "," */
+ len = strlen(*gr_mem);
+ (*gr_mem)[len-1] = '\0';
+ *gr_mem_len = len;
+ }
+
+ return True;
+}
+
+/* Query display info for a domain. This returns enough information plus a
+ bit extra to give an overview of domain users for the User Manager
+ application. */
+static NTSTATUS query_user_list(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ WINBIND_USERINFO **info)
+{
+ /* We don't have users */
+ *num_entries = 0;
+ *info = NULL;
+ return NT_STATUS_OK;
+}
+
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ /* We don't have domain groups */
+ *num_entries = 0;
+ *info = NULL;
+ return NT_STATUS_OK;
+}
+
+/* List all domain groups */
+
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
+{
+ struct acct_info *talloced_info;
+
+ /* Hmm. One billion aliases should be enough for a start */
+
+ if (!pdb_enum_aliases(&domain->sid, 0, 1000000000,
+ num_entries, info)) {
+ /* Nothing to report, just exit. */
+ return NT_STATUS_OK;
+ }
+
+ talloced_info = (struct acct_info *)
+ talloc_memdup(mem_ctx, *info,
+ *num_entries * sizeof(struct acct_info));
+
+ SAFE_FREE(*info);
+ *info = talloced_info;
+
+ return NT_STATUS_OK;
+}
+
+/* convert a single name to a sid in a domain */
+static NTSTATUS name_to_sid(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type)
+{
+ DEBUG(10, ("Finding name %s\n", name));
+
+ if (!pdb_find_alias(name, sid))
+ return NT_STATUS_NONE_MAPPED;
+
+ *type = SID_NAME_ALIAS;
+ return NT_STATUS_OK;
+}
+
+/*
+ convert a domain SID to a user or group name
+*/
+static NTSTATUS sid_to_name(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *sid,
+ char **name,
+ enum SID_NAME_USE *type)
+{
+ struct acct_info info;
+
+ DEBUG(10, ("Converting SID %s\n", sid_string_static(sid)));
+
+ if (!pdb_get_aliasinfo(sid, &info))
+ return NT_STATUS_NONE_MAPPED;
+
+ *name = talloc_strdup(mem_ctx, info.acct_name);
+ *type = SID_NAME_ALIAS;
+
+ return NT_STATUS_OK;
+}
+
+/* Lookup user information from a rid or username. */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ WINBIND_USERINFO *user_info)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+/* Lookup groups a user is a member of. I wish Unix had a call like this! */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID ***user_gids)
+{
+ return NT_STATUS_NO_SUCH_USER;
+}
+
+
+/* Lookup group membership given a rid. */
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID ***sid_mem, char ***names,
+ uint32 **name_types)
+{
+ return NT_STATUS_OK;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ *seq = 1;
+ return NT_STATUS_OK;
+}
+
+/* get a list of trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
+{
+ return NT_STATUS_OK;
+}
+
+/* find the domain sid for a domain */
+static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
+{
+ sid_copy(sid, &domain->sid);
+ return NT_STATUS_OK;
+}
+
+/* find alternate names list for the domain
+ * should we look for netbios aliases??
+ SSS */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+ DEBUG(3,("pdb: alternate_name\n"));
+
+ return NT_STATUS_OK;
+}
+
+
+/* the rpc backend methods are exposed via this structure */
+struct winbindd_methods passdb_methods = {
+ False,
+ query_user_list,
+ enum_dom_groups,
+ enum_local_groups,
+ name_to_sid,
+ sid_to_name,
+ query_user,
+ lookup_usergroups,
+ lookup_groupmem,
+ sequence_number,
+ trusted_domains,
+ domain_sid,
+ alternate_name
+};
diff --git a/source/nsswitch/winbindd_sid.c b/source/nsswitch/winbindd_sid.c
index 9fbf47046d6..d4206558c5e 100644
--- a/source/nsswitch/winbindd_sid.c
+++ b/source/nsswitch/winbindd_sid.c
@@ -30,10 +30,8 @@
enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
{
- extern DOM_SID global_sid_Builtin;
enum SID_NAME_USE type;
- DOM_SID sid, tmp_sid;
- uint32 rid;
+ DOM_SID sid;
fstring name;
fstring dom_name;
@@ -50,15 +48,6 @@ enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state)
return WINBINDD_ERROR;
}
- /* Don't look up BUILTIN sids */
-
- sid_copy(&tmp_sid, &sid);
- sid_split_rid(&tmp_sid, &rid);
-
- if (sid_equal(&tmp_sid, &global_sid_Builtin)) {
- return WINBINDD_ERROR;
- }
-
/* Lookup the sid */
if (!winbindd_lookup_name_by_sid(&sid, dom_name, name, &type)) {
@@ -445,3 +434,23 @@ done:
return WINBINDD_OK;
}
+
+enum winbindd_result winbindd_allocate_rid(struct winbindd_cli_state *state)
+{
+ if ( !state->privileged ) {
+ DEBUG(2, ("winbindd_allocate_rid: non-privileged access "
+ "denied!\n"));
+ return WINBINDD_ERROR;
+ }
+
+ /* We tell idmap to always allocate a user RID. There might be a good
+ * reason to keep RID allocation for users to even and groups to
+ * odd. This needs discussion I think. For now only allocate user
+ * rids. */
+
+ if (!NT_STATUS_IS_OK(idmap_allocate_rid(&state->response.data.rid,
+ USER_RID_TYPE)))
+ return WINBINDD_ERROR;
+
+ return WINBINDD_OK;
+}
diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c
index 403ba399c88..1a01f1c05e6 100644
--- a/source/nsswitch/winbindd_util.c
+++ b/source/nsswitch/winbindd_util.c
@@ -83,6 +83,20 @@ void free_domain_list(void)
}
}
+static BOOL is_internal_domain(const DOM_SID *sid)
+{
+ DOM_SID tmp_sid;
+
+ if (sid_equal(sid, get_global_sam_sid()))
+ return True;
+
+ string_to_sid(&tmp_sid, "S-1-5-32");
+ if (sid_equal(sid, &tmp_sid))
+ return True;
+
+ return False;
+}
+
/* Add a trusted domain to our list of domains */
static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
@@ -143,6 +157,7 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
domain->methods = methods;
domain->backend = NULL;
+ domain->internal = is_internal_domain(sid);
domain->sequence_number = DOM_SEQUENCE_NONE;
domain->last_seq_check = 0;
if (sid) {
@@ -150,8 +165,9 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
}
/* set flags about native_mode, active_directory */
-
- set_dc_type_and_flags( domain );
+
+ if (!domain->internal)
+ set_dc_type_and_flags( domain );
DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name,
domain->active_directory ? "ADS" : "NT4",
@@ -303,6 +319,29 @@ BOOL init_domain_list(void)
/* do an initial scan for trusted domains */
add_trusted_domains(domain);
+
+ /* Don't expand aliases if not explicitly activated -- for now */
+ /* we don't support windows local nested groups if we are a DC.
+ refer to to sid_to_gid() in the smbd server code to see why
+ -- jerry */
+
+
+ if (lp_winbind_nested_groups() || IS_DC) {
+
+ /* Add our local SAM domains */
+ DOM_SID sid;
+ extern struct winbindd_methods passdb_methods;
+ struct winbindd_domain *dom;
+
+ string_to_sid(&sid, "S-1-5-32");
+
+ dom = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
+ &sid);
+
+ dom = add_trusted_domain(get_global_sam_name(), NULL,
+ &passdb_methods,
+ get_global_sam_sid());
+ }
/* avoid rescanning this right away */
last_trustdom_scan = time(NULL);
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index 6b09faf7bf9..894e7ecc9c1 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -174,6 +174,7 @@ typedef struct
BOOL bWinbindEnumGroups;
BOOL bWinbindUseDefaultDomain;
BOOL bWinbindTrustedDomainsOnly;
+ BOOL bWinbindNestedGroups;
char *szWinbindBackend;
char *szIdmapBackend;
char *szAddShareCommand;
@@ -1168,6 +1169,7 @@ static struct parm_struct parm_table[] = {
{"winbind enum groups", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumGroups, NULL, NULL, FLAG_ADVANCED},
{"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED},
{"winbind trusted domains only", P_BOOL, P_GLOBAL, &Globals.bWinbindTrustedDomainsOnly, NULL, NULL, FLAG_ADVANCED},
+ {"winbind nested groups", P_BOOL, P_GLOBAL, &Globals.bWinbindNestedGroups, NULL, NULL, FLAG_ADVANCED},
{NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
};
@@ -1515,6 +1517,7 @@ static void init_globals(void)
Globals.bWinbindEnumGroups = True;
Globals.bWinbindUseDefaultDomain = False;
Globals.bWinbindTrustedDomainsOnly = False;
+ Globals.bWinbindNestedGroups = False;
Globals.bEnableRidAlgorithm = True;
@@ -1687,6 +1690,7 @@ FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
FN_GLOBAL_BOOL(lp_winbind_trusted_domains_only, &Globals.bWinbindTrustedDomainsOnly)
+FN_GLOBAL_BOOL(lp_winbind_nested_groups, &Globals.bWinbindNestedGroups)
FN_GLOBAL_STRING(lp_idmap_backend, &Globals.szIdmapBackend)
FN_GLOBAL_BOOL(lp_enable_rid_algorithm, &Globals.bEnableRidAlgorithm)
diff --git a/source/passdb/pdb_interface.c b/source/passdb/pdb_interface.c
index 06097d3557b..a3b2706c35b 100644
--- a/source/passdb/pdb_interface.c
+++ b/source/passdb/pdb_interface.c
@@ -452,6 +452,156 @@ static NTSTATUS context_enum_group_mapping(struct pdb_context *context,
num_entries, unix_only);
}
+static NTSTATUS context_find_alias(struct pdb_context *context,
+ const char *name, DOM_SID *sid)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->find_alias(context->pdb_methods,
+ name, sid);
+}
+
+static NTSTATUS context_create_alias(struct pdb_context *context,
+ const char *name, uint32 *rid)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->create_alias(context->pdb_methods,
+ name, rid);
+}
+
+static NTSTATUS context_delete_alias(struct pdb_context *context,
+ const DOM_SID *sid)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->delete_alias(context->pdb_methods, sid);
+}
+
+static NTSTATUS context_enum_aliases(struct pdb_context *context,
+ const DOM_SID *sid,
+ uint32 start_idx, uint32 max_entries,
+ uint32 *num_aliases,
+ struct acct_info **info)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->enum_aliases(context->pdb_methods,
+ sid, start_idx, max_entries,
+ num_aliases, info);
+}
+
+static NTSTATUS context_get_aliasinfo(struct pdb_context *context,
+ const DOM_SID *sid,
+ struct acct_info *info)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->get_aliasinfo(context->pdb_methods,
+ sid, info);
+}
+
+static NTSTATUS context_set_aliasinfo(struct pdb_context *context,
+ const DOM_SID *sid,
+ struct acct_info *info)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->set_aliasinfo(context->pdb_methods,
+ sid, info);
+}
+
+static NTSTATUS context_add_aliasmem(struct pdb_context *context,
+ const DOM_SID *alias,
+ const DOM_SID *member)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->add_aliasmem(context->pdb_methods,
+ alias, member);
+}
+
+static NTSTATUS context_del_aliasmem(struct pdb_context *context,
+ const DOM_SID *alias,
+ const DOM_SID *member)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->del_aliasmem(context->pdb_methods,
+ alias, member);
+}
+
+static NTSTATUS context_enum_aliasmem(struct pdb_context *context,
+ const DOM_SID *alias, DOM_SID **members,
+ int *num)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->enum_aliasmem(context->pdb_methods,
+ alias, members, num);
+}
+
+static NTSTATUS context_enum_alias_memberships(struct pdb_context *context,
+ const DOM_SID *sid,
+ DOM_SID **aliases, int *num)
+{
+ NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+
+ if ((!context) || (!context->pdb_methods)) {
+ DEBUG(0, ("invalid pdb_context specified!\n"));
+ return ret;
+ }
+
+ return context->pdb_methods->
+ enum_alias_memberships(context->pdb_methods, sid, aliases,
+ num);
+}
+
/******************************************************************
Free and cleanup a pdb context, any associated data and anything
that the attached modules might have associated.
@@ -568,6 +718,17 @@ static NTSTATUS make_pdb_context(struct pdb_context **context)
(*context)->pdb_delete_group_mapping_entry = context_delete_group_mapping_entry;
(*context)->pdb_enum_group_mapping = context_enum_group_mapping;
+ (*context)->pdb_find_alias = context_find_alias;
+ (*context)->pdb_create_alias = context_create_alias;
+ (*context)->pdb_delete_alias = context_delete_alias;
+ (*context)->pdb_enum_aliases = context_enum_aliases;
+ (*context)->pdb_get_aliasinfo = context_get_aliasinfo;
+ (*context)->pdb_set_aliasinfo = context_set_aliasinfo;
+ (*context)->pdb_add_aliasmem = context_add_aliasmem;
+ (*context)->pdb_del_aliasmem = context_del_aliasmem;
+ (*context)->pdb_enum_aliasmem = context_enum_aliasmem;
+ (*context)->pdb_enum_alias_memberships = context_enum_alias_memberships;
+
(*context)->free_fn = free_pdb_context;
return NT_STATUS_OK;
@@ -850,6 +1011,135 @@ BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **rmap,
rmap, num_entries, unix_only));
}
+BOOL pdb_find_alias(const char *name, DOM_SID *sid)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->pdb_find_alias(pdb_context,
+ name, sid));
+}
+
+BOOL pdb_create_alias(const char *name, uint32 *rid)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->pdb_create_alias(pdb_context,
+ name, rid));
+}
+
+BOOL pdb_delete_alias(const DOM_SID *sid)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->pdb_delete_alias(pdb_context,
+ sid));
+
+}
+
+BOOL pdb_enum_aliases(const DOM_SID *sid, uint32 start_idx, uint32 max_entries,
+ uint32 *num_aliases, struct acct_info **info)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->pdb_enum_aliases(pdb_context, sid,
+ start_idx,
+ max_entries,
+ num_aliases,
+ info));
+}
+
+BOOL pdb_get_aliasinfo(const DOM_SID *sid, struct acct_info *info)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->pdb_get_aliasinfo(pdb_context, sid,
+ info));
+}
+
+BOOL pdb_set_aliasinfo(const DOM_SID *sid, struct acct_info *info)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->pdb_set_aliasinfo(pdb_context, sid,
+ info));
+}
+
+BOOL pdb_add_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->
+ pdb_add_aliasmem(pdb_context, alias, member));
+}
+
+BOOL pdb_del_aliasmem(const DOM_SID *alias, const DOM_SID *member)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->
+ pdb_del_aliasmem(pdb_context, alias, member));
+}
+
+BOOL pdb_enum_aliasmem(const DOM_SID *alias,
+ DOM_SID **members, int *num_members)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->
+ pdb_enum_aliasmem(pdb_context, alias,
+ members, num_members));
+}
+
+BOOL pdb_enum_alias_memberships(const DOM_SID *sid,
+ DOM_SID **aliases, int *num)
+{
+ struct pdb_context *pdb_context = pdb_get_static_context(False);
+
+ if (!pdb_context) {
+ return False;
+ }
+
+ return NT_STATUS_IS_OK(pdb_context->
+ pdb_enum_alias_memberships(pdb_context, sid,
+ aliases, num));
+}
+
/***************************************************************
Initialize the static context (at smbd startup etc).
@@ -933,6 +1223,16 @@ 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)->find_alias = pdb_default_find_alias;
+ (*methods)->create_alias = pdb_default_create_alias;
+ (*methods)->delete_alias = pdb_default_delete_alias;
+ (*methods)->enum_aliases = pdb_default_enum_aliases;
+ (*methods)->get_aliasinfo = pdb_default_get_aliasinfo;
+ (*methods)->set_aliasinfo = pdb_default_set_aliasinfo;
+ (*methods)->add_aliasmem = pdb_default_add_aliasmem;
+ (*methods)->del_aliasmem = pdb_default_del_aliasmem;
+ (*methods)->enum_aliasmem = pdb_default_enum_aliasmem;
+ (*methods)->enum_alias_memberships = pdb_default_alias_memberships;
return NT_STATUS_OK;
}
diff --git a/source/passdb/pdb_ldap.c b/source/passdb/pdb_ldap.c
index 307d187f667..15635a034cc 100644
--- a/source/passdb/pdb_ldap.c
+++ b/source/passdb/pdb_ldap.c
@@ -1989,8 +1989,8 @@ static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state,
{
pstring filter;
- pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
- LDAP_OBJ_POSIXGROUP,
+ pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%lu))",
+ LDAP_OBJ_POSIXGROUP, LDAP_OBJ_IDMAP_ENTRY,
get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
(unsigned long)gid);
@@ -2032,6 +2032,37 @@ static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
if ( count == 0 ) {
+ /* There's no posixGroup account, let's try to find an
+ * appropriate idmap entry for aliases */
+
+ pstring suffix;
+ pstring filter;
+ char **attr_list;
+
+ ldap_msgfree(result);
+
+ pstrcpy( suffix, lp_ldap_idmap_suffix() );
+ pstr_sprintf(filter, "(&(objectClass=%s)(%s=%u))",
+ LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_GIDNUMBER,
+ map->gid);
+
+ attr_list = get_attr_list( sidmap_attr_list );
+ rc = smbldap_search(ldap_state->smbldap_state, suffix,
+ LDAP_SCOPE_SUBTREE, filter, attr_list,
+ 0, &result);
+
+ free_attr_list(attr_list);
+
+ if (rc != LDAP_SUCCESS) {
+ DEBUG(3,("Failure looking up entry (%s)\n",
+ ldap_err2string(rc) ));
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
+ if ( count == 0 ) {
ldap_msgfree(result);
return NT_STATUS_UNSUCCESSFUL;
}
@@ -2306,6 +2337,254 @@ static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
return NT_STATUS_OK;
}
+static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ const DOM_SID *member,
+ int modop)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ char *dn;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ LDAPMod **mods = NULL;
+ int rc;
+
+ pstring filter;
+
+ pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%s))",
+ LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GROUP_SID),
+ sid_string_static(alias));
+
+ if (ldapsam_search_one_group(ldap_state, filter,
+ &result) != LDAP_SUCCESS)
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_add_aliasmem: Did not find alias\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: "
+ "count=%d\n", filter, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry);
+ if (!dn) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ smbldap_set_mod(&mods, modop,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST),
+ sid_string_static(member));
+
+ rc = smbldap_modify(ldap_state->smbldap_state, dn, mods);
+
+ ldap_mods_free(mods, True);
+ ldap_msgfree(result);
+
+ if (rc != LDAP_SUCCESS) {
+ char *ld_error = NULL;
+ ldap_get_option(ldap_state->smbldap_state->ldap_struct,
+ LDAP_OPT_ERROR_STRING,&ld_error);
+
+ DEBUG(0, ("ldapsam_delete_entry: Could not delete attributes "
+ "for %s, error: %s (%s)\n", dn, ldap_err2string(rc),
+ ld_error?ld_error:"unknown"));
+ SAFE_FREE(ld_error);
+ SAFE_FREE(dn);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ SAFE_FREE(dn);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_add_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ const DOM_SID *member)
+{
+ return ldapsam_modify_aliasmem(methods, alias, member, LDAP_MOD_ADD);
+}
+
+static NTSTATUS ldapsam_del_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias,
+ const DOM_SID *member)
+{
+ return ldapsam_modify_aliasmem(methods, alias, member,
+ LDAP_MOD_DELETE);
+}
+
+static NTSTATUS ldapsam_enum_aliasmem(struct pdb_methods *methods,
+ const DOM_SID *alias, DOM_SID **members,
+ int *num_members)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ char **values;
+ int i;
+ pstring filter;
+
+ *members = NULL;
+ *num_members = 0;
+
+ pstr_sprintf(filter, "(&(|(objectClass=%s)(objectclass=%s))(%s=%s))",
+ LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_GROUP_SID),
+ sid_string_static(alias));
+
+ if (ldapsam_search_one_group(ldap_state, filter,
+ &result) != LDAP_SUCCESS)
+ return NT_STATUS_NO_SUCH_ALIAS;
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (count < 1) {
+ DEBUG(4, ("ldapsam_add_aliasmem: Did not find alias\n"));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ if (count > 1) {
+ DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: "
+ "count=%d\n", filter, count));
+ ldap_msgfree(result);
+ return NT_STATUS_NO_SUCH_ALIAS;
+ }
+
+ entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (!entry) {
+ ldap_msgfree(result);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ values = ldap_get_values(ldap_state->smbldap_state->ldap_struct,
+ entry,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST));
+
+ if (values == NULL) {
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+ }
+
+ count = ldap_count_values(values);
+
+ for (i=0; i<count; i++) {
+ DOM_SID member;
+
+ if (!string_to_sid(&member, values[i]))
+ continue;
+
+ add_sid_to_array(&member, members, num_members);
+ }
+
+ ldap_value_free(values);
+ ldap_msgfree(result);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_alias_memberships(struct pdb_methods *methods,
+ const DOM_SID *sid,
+ DOM_SID **aliases, int *num)
+{
+ struct ldapsam_privates *ldap_state =
+ (struct ldapsam_privates *)methods->private_data;
+
+ fstring sid_string;
+ const char *attrs[] = { LDAP_ATTRIBUTE_SID, NULL };
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ int count;
+ int rc;
+ pstring filter;
+
+ sid_to_string(sid_string, sid);
+ pstr_sprintf(filter, "(&(|(objectclass=%s)(objectclass=%s))(%s=%s))",
+ LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY,
+ get_attr_key2string(groupmap_attr_list,
+ LDAP_ATTR_SID_LIST), sid_string);
+
+ rc = smbldap_search(ldap_state->smbldap_state, lp_ldap_group_suffix(),
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
+
+ if (rc != LDAP_SUCCESS)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ *aliases = NULL;
+ *num = 0;
+
+ count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct,
+ result);
+
+ if (count < 1) {
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+ }
+
+
+ for (entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct,
+ result);
+ entry != NULL;
+ entry = ldap_next_entry(ldap_state->smbldap_state->ldap_struct,
+ entry))
+ {
+ DOM_SID alias;
+ char **vals;
+ vals = ldap_get_values(ldap_state->smbldap_state->ldap_struct,
+ entry, LDAP_ATTRIBUTE_SID);
+
+ if (vals == NULL)
+ continue;
+
+ if (vals[0] == NULL) {
+ ldap_value_free(vals);
+ continue;
+ }
+
+ if (!string_to_sid(&alias, vals[0])) {
+ ldap_value_free(vals);
+ continue;
+ }
+
+ add_sid_to_array(&alias, aliases, num);
+ ldap_value_free(vals);
+ }
+
+ ldap_msgfree(result);
+ return NT_STATUS_OK;
+}
+
/**********************************************************************
Housekeeping
*********************************************************************/
@@ -2444,6 +2723,11 @@ static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_met
(*pdb_method)->name = "ldapsam";
+ (*pdb_method)->add_aliasmem = ldapsam_add_aliasmem;
+ (*pdb_method)->del_aliasmem = ldapsam_del_aliasmem;
+ (*pdb_method)->enum_aliasmem = ldapsam_enum_aliasmem;
+ (*pdb_method)->enum_alias_memberships = ldapsam_alias_memberships;
+
ldap_state = (*pdb_method)->private_data;
ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;
diff --git a/source/passdb/util_sam_sid.c b/source/passdb/util_sam_sid.c
index f6cc2491a8b..63ef5914af8 100644
--- a/source/passdb/util_sam_sid.c
+++ b/source/passdb/util_sam_sid.c
@@ -305,3 +305,16 @@ BOOL map_name_to_wellknown_sid(DOM_SID *sid, enum SID_NAME_USE *use, const char
return False;
}
+
+void add_sid_to_array(const DOM_SID *sid, DOM_SID **sids, int *num)
+{
+ *sids = Realloc(*sids, ((*num)+1) * sizeof(DOM_SID));
+
+ if (*sids == NULL)
+ return;
+
+ sid_copy(&((*sids)[*num]), sid);
+ *num += 1;
+
+ return;
+}
diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c
index 9801ce47f8f..de4fdceba7a 100644
--- a/source/rpc_server/srv_lsa_nt.c
+++ b/source/rpc_server/srv_lsa_nt.c
@@ -171,6 +171,11 @@ static void init_lsa_rid2s(DOM_R_REF *ref, DOM_RID2 *rid2,
status = lookup_name(dom_name, user, &sid, &name_type);
}
+ if (name_type == SID_NAME_WKN_GRP) {
+ /* BUILTIN aliases are still aliases :-) */
+ name_type = SID_NAME_ALIAS;
+ }
+
DEBUG(5, ("init_lsa_rid2s: %s\n", status ? "found" :
"not found"));
diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c
index 70ae4d170e4..2e5fe295ecb 100644
--- a/source/rpc_server/srv_samr_nt.c
+++ b/source/rpc_server/srv_samr_nt.c
@@ -879,7 +879,7 @@ 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_entries( enum SID_NAME_USE type, TALLOC_CTX *ctx,
+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 )
{
@@ -894,7 +894,8 @@ static NTSTATUS get_group_entries( enum SID_NAME_USE type, TALLOC_CTX *ctx,
needed for some passdb backends to enumerate groups */
become_root();
- pdb_enum_group_mapping(type, &map, (int *)&group_entries, ENUM_ONLY_MAPPED);
+ pdb_enum_group_mapping(SID_NAME_DOM_GRP, &map, (int *)&group_entries,
+ ENUM_ONLY_MAPPED);
unbecome_root();
num_entries=group_entries-start_idx;
@@ -915,51 +916,57 @@ static NTSTATUS get_group_entries( enum SID_NAME_USE type, TALLOC_CTX *ctx,
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=type;
+ (*d_grp)[i].attr=SID_NAME_DOM_GRP;
}
SAFE_FREE(map);
*p_num_entries = num_entries;
- DEBUG(10,("get_group_entries: returning %d entries\n", *p_num_entries));
+ DEBUG(10,("get_group_domain_entries: returning %d entries\n",
+ *p_num_entries));
return NT_STATUS_OK;
}
/*******************************************************************
- Wrapper for enuemrating domain groups
+ Wrapper for enumerating local groups
******************************************************************/
-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 )
+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 )
{
- return get_group_entries( SID_NAME_DOM_GRP, ctx, d_grp, sid, start_idx,
- p_num_entries, max_entries );
-}
+ struct acct_info *info;
+ int i;
+ BOOL res;
-/*******************************************************************
- Wrapper for enumerating local groups
- ******************************************************************/
+ become_root();
+ res = pdb_enum_aliases(sid, start_idx, max_entries,
+ p_num_entries, &info);
+ unbecome_root();
-static NTSTATUS get_group_alias_entries( TALLOC_CTX *ctx, DOMAIN_GRP **d_grp,
- DOM_SID *sid, uint32 start_idx,
- uint32 *p_num_entries, uint32 max_entries)
-{
- if ( sid_equal(sid, &global_sid_Builtin) ) {
- return get_group_entries( SID_NAME_WKN_GRP, ctx, d_grp,
- sid, start_idx, p_num_entries, max_entries );
- }
- else if ( sid_equal(sid, get_global_sam_sid()) ) {
- return get_group_entries( SID_NAME_ALIAS, ctx, d_grp,
- sid, start_idx, p_num_entries, max_entries );
+ if (!res)
+ return NT_STATUS_ACCESS_DENIED;
+
+ if (*p_num_entries == 0)
+ return NT_STATUS_OK;
+
+ *d_grp = talloc(ctx, sizeof(DOMAIN_GRP) * (*p_num_entries));
+
+ if (*d_grp == NULL) {
+ SAFE_FREE(info);
+ return NT_STATUS_NO_MEMORY;
}
- /* can't do anything with this SID */
-
- *p_num_entries = 0;
+ 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;
}
@@ -1025,9 +1032,9 @@ NTSTATUS _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, S
sid_to_string(sid_str, &sid);
DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", sid_str));
- status = get_group_alias_entries(p->mem_ctx, &grp, &sid, q_u->start_idx,
- &num_entries, MAX_SAM_ENTRIES);
- if (NT_STATUS_IS_ERR(status)) return status;
+ 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;
make_group_sam_entry_list(p->mem_ctx, &r_u->sam, &r_u->uni_grp_name, num_entries, grp);
@@ -1244,7 +1251,7 @@ NTSTATUS _samr_query_dispinfo(pipes_struct *p, SAMR_Q_QUERY_DISPINFO *q_u,
NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAMR_R_QUERY_ALIASINFO *r_u)
{
DOM_SID sid;
- GROUP_MAP map;
+ struct acct_info info;
uint32 acc_granted;
BOOL ret;
@@ -1259,12 +1266,8 @@ NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAM
return r_u->status;
}
- if (!sid_check_is_in_our_domain(&sid) &&
- !sid_check_is_in_builtin(&sid))
- return NT_STATUS_OBJECT_TYPE_MISMATCH;
-
become_root();
- ret = pdb_getgrsid(&map, sid);
+ ret = pdb_get_aliasinfo(&sid, &info);
unbecome_root();
if ( !ret )
@@ -1274,12 +1277,13 @@ NTSTATUS _samr_query_aliasinfo(pipes_struct *p, SAMR_Q_QUERY_ALIASINFO *q_u, SAM
case 1:
r_u->ptr = 1;
r_u->ctr.switch_value1 = 1;
- init_samr_alias_info1(&r_u->ctr.alias.info1, map.nt_name, 1, map.comment);
+ init_samr_alias_info1(&r_u->ctr.alias.info1,
+ info.acct_name, 1, info.acct_desc);
break;
case 3:
r_u->ptr = 1;
r_u->ctr.switch_value1 = 3;
- init_samr_alias_info3(&r_u->ctr.alias.info3, map.comment);
+ init_samr_alias_info3(&r_u->ctr.alias.info3, info.acct_desc);
break;
default:
return NT_STATUS_INVALID_INFO_CLASS;
@@ -3191,15 +3195,11 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_
{
int i;
- GROUP_MAP map;
int num_sids = 0;
DOM_SID2 *sid;
DOM_SID *sids=NULL;
DOM_SID alias_sid;
- DOM_SID als_sid;
- uint32 alias_rid;
- fstring alias_sid_str;
uint32 acc_granted;
@@ -3211,35 +3211,12 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_
access_check_samr_function(acc_granted, SA_RIGHT_ALIAS_GET_MEMBERS, "_samr_query_aliasmem"))) {
return r_u->status;
}
-
- sid_copy(&als_sid, &alias_sid);
- sid_to_string(alias_sid_str, &alias_sid);
- sid_split_rid(&alias_sid, &alias_rid);
- DEBUG(10, ("sid is %s\n", alias_sid_str));
+ DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid)));
- if (sid_equal(&alias_sid, &global_sid_Builtin)) {
- DEBUG(10, ("lookup on Builtin SID (S-1-5-32)\n"));
- if(!get_builtin_group_from_sid(&als_sid, &map))
- return NT_STATUS_NO_SUCH_ALIAS;
- } else {
- if (sid_equal(&alias_sid, get_global_sam_sid())) {
- DEBUG(10, ("lookup on Server SID\n"));
- if(!get_local_group_from_sid(&als_sid, &map)) {
- fstring alias_sid_string;
- DEBUG(10, ("Alias %s not found\n", sid_to_string(alias_sid_string, &als_sid)));
- return NT_STATUS_NO_SUCH_ALIAS;
- }
- }
- }
-
- if (!get_sid_list_of_group(map.gid, &sids, &num_sids)) {
- fstring alias_sid_string;
- DEBUG(10, ("Alias %s found, but member list unavailable\n", sid_to_string(alias_sid_string, &als_sid)));
+ if (!pdb_enum_aliasmem(&alias_sid, &sids, &num_sids))
return NT_STATUS_NO_SUCH_ALIAS;
- }
- DEBUG(10, ("sid is %s\n", alias_sid_str));
sid = (DOM_SID2 *)talloc_zero(p->mem_ctx, sizeof(DOM_SID2) * num_sids);
if (num_sids!=0 && sid == NULL) {
SAFE_FREE(sids);
@@ -3250,7 +3227,6 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_
init_dom_sid2(&sid[i], &sids[i]);
}
- DEBUG(10, ("sid is %s\n", alias_sid_str));
init_samr_r_query_aliasmem(r_u, num_sids, sid, NT_STATUS_OK);
SAFE_FREE(sids);
@@ -3258,20 +3234,89 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_
return NT_STATUS_OK;
}
+static void add_uid_to_array_unique(uid_t uid, uid_t **uids, int *num)
+{
+ int i;
+
+ if ((*num) >= groups_max())
+ return;
+
+ for (i=0; i<*num; i++) {
+ if ((*uids)[i] == uid)
+ return;
+ }
+
+ *uids = Realloc(*uids, (*num+1) * sizeof(uid_t));
+
+ if (*uids == NULL)
+ return;
+
+ (*uids)[*num] = uid;
+ *num += 1;
+}
+
+
+static BOOL get_memberuids(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(user->pw_uid, uids, num);
+ }
+
+ pwent_free(userlist);
+
+ /* Secondary group members */
+
+ gr = grp->gr_mem;
+ while ((*gr != NULL) && ((*gr)[0] != '\0')) {
+ struct passwd *pw = getpwnam(*gr);
+
+ if (pw == NULL)
+ continue;
+
+ add_uid_to_array_unique(pw->pw_uid, uids, num);
+
+ gr += 1;
+ }
+
+ winbind_on();
+
+ return True;
+}
+
/*********************************************************************
_samr_query_groupmem
*********************************************************************/
NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_R_QUERY_GROUPMEM *r_u)
{
- int num_sids = 0;
- int final_num_sids = 0;
- int i;
+ int final_num_rids, i;
DOM_SID group_sid;
fstring group_sid_str;
- DOM_SID *sids=NULL;
-
- GROUP_MAP map;
+ uid_t *uids;
+ int num;
+ gid_t gid;
uint32 *rid=NULL;
uint32 *attr=NULL;
@@ -3296,35 +3341,46 @@ NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_
DEBUG(10, ("lookup on Domain SID\n"));
- if(!get_domain_group_from_sid(group_sid, &map))
+ if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid)))
return NT_STATUS_NO_SUCH_GROUP;
- if(!get_sid_list_of_group(map.gid, &sids, &num_sids))
+ if(!get_memberuids(gid, &uids, &num))
return NT_STATUS_NO_SUCH_GROUP;
- rid=talloc_zero(p->mem_ctx, sizeof(uint32)*num_sids);
- attr=talloc_zero(p->mem_ctx, sizeof(uint32)*num_sids);
+ rid=talloc_zero(p->mem_ctx, sizeof(uint32)*num);
+ attr=talloc_zero(p->mem_ctx, sizeof(uint32)*num);
- if (num_sids!=0 && (rid==NULL || attr==NULL))
+ if (num!=0 && (rid==NULL || attr==NULL))
return NT_STATUS_NO_MEMORY;
- for (i=0; i<num_sids; i++) {
- uint32 urid;
+ final_num_rids = 0;
- if (sid_peek_check_rid(get_global_sam_sid(), &sids[i], &urid)) {
- rid[final_num_sids] = urid;
- attr[final_num_sids] = SID_NAME_USER;
- final_num_sids++;
- } else {
- fstring user_sid_str, domain_sid_str;
- DEBUG(1, ("_samr_query_groupmem: SID %s in group %s is not in our domain %s\n",
- sid_to_string(user_sid_str, &sids[i]),
- sid_to_string(group_sid_str, &group_sid),
- sid_to_string(domain_sid_str, get_global_sam_sid())));
+ 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;
}
- init_samr_r_query_groupmem(r_u, final_num_sids, rid, attr, NT_STATUS_OK);
+ SAFE_FREE(uids);
+
+ init_samr_r_query_groupmem(r_u, final_num_rids, rid, attr,
+ NT_STATUS_OK);
return NT_STATUS_OK;
}
@@ -3336,15 +3392,6 @@ NTSTATUS _samr_query_groupmem(pipes_struct *p, SAMR_Q_QUERY_GROUPMEM *q_u, SAMR_
NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_ADD_ALIASMEM *r_u)
{
DOM_SID alias_sid;
- fstring alias_sid_str;
- uid_t uid;
- struct passwd *pwd;
- struct group *grp;
- fstring grp_name;
- GROUP_MAP map;
- NTSTATUS ret;
- SAM_ACCOUNT *sam_user = NULL;
- BOOL check;
uint32 acc_granted;
/* Find the policy handle. Open a policy on it. */
@@ -3355,74 +3402,11 @@ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_AD
return r_u->status;
}
- sid_to_string(alias_sid_str, &alias_sid);
- DEBUG(10, ("sid is %s\n", alias_sid_str));
-
- if (sid_compare(&alias_sid, get_global_sam_sid())>0) {
- DEBUG(10, ("adding member on Server SID\n"));
- if(!get_local_group_from_sid(&alias_sid, &map))
- return NT_STATUS_NO_SUCH_ALIAS;
-
- } else {
- if (sid_compare(&alias_sid, &global_sid_Builtin)>0) {
- DEBUG(10, ("adding member on BUILTIN SID\n"));
- if( !get_builtin_group_from_sid(&alias_sid, &map))
- return NT_STATUS_NO_SUCH_ALIAS;
-
- } else
- return NT_STATUS_NO_SUCH_ALIAS;
- }
+ DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid)));
- ret = pdb_init_sam(&sam_user);
- if (!NT_STATUS_IS_OK(ret))
- return ret;
-
- check = pdb_getsampwsid(sam_user, &q_u->sid.sid);
-
- if (check != True) {
- pdb_free_sam(&sam_user);
- return NT_STATUS_NO_SUCH_USER;
- }
-
- /* check a real user exist before we run the script to add a user to a group */
- if (!NT_STATUS_IS_OK(sid_to_uid(pdb_get_user_sid(sam_user), &uid))) {
- pdb_free_sam(&sam_user);
- return NT_STATUS_NO_SUCH_USER;
- }
-
- pdb_free_sam(&sam_user);
-
- if ((pwd=getpwuid_alloc(uid)) == NULL) {
- return NT_STATUS_NO_SUCH_USER;
- }
-
- if ((grp=getgrgid(map.gid)) == NULL) {
- passwd_free(&pwd);
- return NT_STATUS_NO_SUCH_ALIAS;
- }
-
- /* we need to copy the name otherwise it's overloaded in user_in_group_list */
- fstrcpy(grp_name, grp->gr_name);
-
- /* if the user is already in the group */
- if(user_in_unix_group_list(pwd->pw_name, grp_name)) {
- passwd_free(&pwd);
- return NT_STATUS_MEMBER_IN_ALIAS;
- }
-
- /*
- * ok, the group exist, the user exist, the user is not in the group,
- * we can (finally) add it to the group !
- */
- smb_add_user_group(grp_name, pwd->pw_name);
-
- /* check if the user has been added then ... */
- if(!user_in_unix_group_list(pwd->pw_name, grp_name)) {
- passwd_free(&pwd);
- return NT_STATUS_MEMBER_NOT_IN_ALIAS; /* don't know what to reply else */
- }
+ if (!pdb_add_aliasmem(&alias_sid, &q_u->sid.sid))
+ return NT_STATUS_ACCESS_DENIED;
- passwd_free(&pwd);
return NT_STATUS_OK;
}
@@ -3433,11 +3417,6 @@ NTSTATUS _samr_add_aliasmem(pipes_struct *p, SAMR_Q_ADD_ALIASMEM *q_u, SAMR_R_AD
NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DEL_ALIASMEM *r_u)
{
DOM_SID alias_sid;
- fstring alias_sid_str;
- struct group *grp;
- fstring grp_name;
- GROUP_MAP map;
- SAM_ACCOUNT *sam_pass=NULL;
uint32 acc_granted;
/* Find the policy handle. Open a policy on it. */
@@ -3448,47 +3427,12 @@ NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DE
return r_u->status;
}
- sid_to_string(alias_sid_str, &alias_sid);
- DEBUG(10, ("_samr_del_aliasmem:sid is %s\n", alias_sid_str));
-
- if (!sid_check_is_in_our_domain(&alias_sid) &&
- !sid_check_is_in_builtin(&alias_sid)) {
- DEBUG(10, ("_samr_del_aliasmem:invalid alias group\n"));
- return NT_STATUS_NO_SUCH_ALIAS;
- }
-
- if( !get_local_group_from_sid(&alias_sid, &map))
- return NT_STATUS_NO_SUCH_ALIAS;
-
- if ((grp=getgrgid(map.gid)) == NULL)
- return NT_STATUS_NO_SUCH_ALIAS;
-
- /* we need to copy the name otherwise it's overloaded in user_in_unix_group_list */
- fstrcpy(grp_name, grp->gr_name);
-
- /* check if the user exists before trying to remove it from the group */
- pdb_init_sam(&sam_pass);
- if(!pdb_getsampwsid(sam_pass, &q_u->sid.sid)) {
- DEBUG(5,("_samr_del_aliasmem:User %s doesn't exist.\n", pdb_get_username(sam_pass)));
- pdb_free_sam(&sam_pass);
- return NT_STATUS_NO_SUCH_USER;
- }
-
- /* if the user is not in the group */
- if(!user_in_unix_group_list(pdb_get_username(sam_pass), grp_name)) {
- pdb_free_sam(&sam_pass);
- return NT_STATUS_MEMBER_NOT_IN_ALIAS;
- }
-
- smb_delete_user_group(grp_name, pdb_get_username(sam_pass));
-
- /* check if the user has been removed then ... */
- if(user_in_unix_group_list(pdb_get_username(sam_pass), grp_name)) {
- pdb_free_sam(&sam_pass);
- return NT_STATUS_MEMBER_NOT_IN_ALIAS; /* don't know what to reply else */
- }
+ DEBUG(10, ("_samr_del_aliasmem:sid is %s\n",
+ sid_string_static(&alias_sid)));
- pdb_free_sam(&sam_pass);
+ if (!pdb_del_aliasmem(&alias_sid, &q_u->sid.sid))
+ return NT_STATUS_ACCESS_DENIED;
+
return NT_STATUS_OK;
}
@@ -3815,12 +3759,6 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S
NTSTATUS _samr_delete_dom_alias(pipes_struct *p, SAMR_Q_DELETE_DOM_ALIAS *q_u, SAMR_R_DELETE_DOM_ALIAS *r_u)
{
DOM_SID alias_sid;
- DOM_SID dom_sid;
- uint32 alias_rid;
- fstring alias_sid_str;
- gid_t gid;
- struct group *grp;
- GROUP_MAP map;
uint32 acc_granted;
DEBUG(5, ("_samr_delete_dom_alias: %d\n", __LINE__));
@@ -3832,38 +3770,18 @@ NTSTATUS _samr_delete_dom_alias(pipes_struct *p, SAMR_Q_DELETE_DOM_ALIAS *q_u, S
if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS, "_samr_delete_dom_alias"))) {
return r_u->status;
}
-
- sid_copy(&dom_sid, &alias_sid);
- sid_to_string(alias_sid_str, &dom_sid);
- sid_split_rid(&dom_sid, &alias_rid);
- DEBUG(10, ("sid is %s\n", alias_sid_str));
+ DEBUG(10, ("sid is %s\n", sid_string_static(&alias_sid)));
- /* we check if it's our SID before deleting */
- if (!sid_equal(&dom_sid, get_global_sam_sid()))
+ if (!sid_check_is_in_our_domain(&alias_sid))
return NT_STATUS_NO_SUCH_ALIAS;
-
+
DEBUG(10, ("lookup on Local SID\n"));
- if(!get_local_group_from_sid(&alias_sid, &map))
- return NT_STATUS_NO_SUCH_ALIAS;
-
- gid=map.gid;
-
- /* check if group really exists */
- if ( (grp=getgrgid(gid)) == NULL)
- return NT_STATUS_NO_SUCH_ALIAS;
-
- /* we can delete the UNIX group */
- smb_delete_group(grp->gr_name);
-
- /* check if the group has been successfully deleted */
- if ( (grp=getgrgid(gid)) != NULL)
+ /* Have passdb delete the alias */
+ if (!pdb_delete_alias(&alias_sid))
return NT_STATUS_ACCESS_DENIED;
- /* don't check if we removed it as it could be an un-mapped group */
- pdb_delete_group_mapping_entry(alias_sid);
-
if (!close_policy_hnd(p, &q_u->alias_pol))
return NT_STATUS_OBJECT_NAME_INVALID;
@@ -3941,7 +3859,6 @@ NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, S
DOM_SID dom_sid;
DOM_SID info_sid;
fstring name;
- fstring sid_string;
struct group *grp;
struct samr_info *info;
uint32 acc_granted;
@@ -3962,26 +3879,18 @@ NTSTATUS _samr_create_dom_alias(pipes_struct *p, SAMR_Q_CREATE_DOM_ALIAS *q_u, S
unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1);
- /* check if group already exists */
- if ( (grp=getgrnam(name)) != NULL)
- return NT_STATUS_ALIAS_EXISTS;
-
- /* we can create the UNIX group */
- if (smb_create_group(name, &gid) != 0)
- return NT_STATUS_ACCESS_DENIED;
-
- /* check if the group has been successfully created */
- if ((grp=getgrgid(gid)) == NULL)
+ /* Have passdb create the alias */
+ if (!pdb_create_alias(name, &r_u->rid))
return NT_STATUS_ACCESS_DENIED;
- r_u->rid=pdb_gid_to_group_rid(grp->gr_gid);
-
sid_copy(&info_sid, get_global_sam_sid());
sid_append_rid(&info_sid, r_u->rid);
- sid_to_string(sid_string, &info_sid);
- /* add the group to the mapping table */
- if(!add_initial_entry(grp->gr_gid, sid_string, SID_NAME_ALIAS, name, NULL))
+ if (!NT_STATUS_IS_OK(sid_to_gid(&info_sid, &gid)))
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* check if the group has been successfully created */
+ if ((grp=getgrgid(gid)) == NULL)
return NT_STATUS_ACCESS_DENIED;
if ((info = get_samr_info_by_sid(&info_sid)) == NULL)
@@ -4006,7 +3915,8 @@ NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAM
DOM_SID group_sid;
GROUP_MAP map;
DOM_SID *sids=NULL;
- int num_sids=0;
+ uid_t *uids;
+ int num=0;
GROUP_INFO_CTR *ctr;
uint32 acc_granted;
BOOL ret;
@@ -4031,9 +3941,10 @@ NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAM
switch (q_u->switch_level) {
case 1:
ctr->switch_value1 = 1;
- if(!get_sid_list_of_group(map.gid, &sids, &num_sids))
+ if(!get_memberuids(map.gid, &uids, &num))
return NT_STATUS_NO_SUCH_GROUP;
- init_samr_group_info1(&ctr->group.info1, map.nt_name, map.comment, num_sids);
+ SAFE_FREE(uids);
+ init_samr_group_info1(&ctr->group.info1, map.nt_name, map.comment, num);
SAFE_FREE(sids);
break;
case 3:
@@ -4105,7 +4016,7 @@ NTSTATUS _samr_set_groupinfo(pipes_struct *p, SAMR_Q_SET_GROUPINFO *q_u, SAMR_R_
NTSTATUS _samr_set_aliasinfo(pipes_struct *p, SAMR_Q_SET_ALIASINFO *q_u, SAMR_R_SET_ALIASINFO *r_u)
{
DOM_SID group_sid;
- GROUP_MAP map;
+ struct acct_info info;
ALIAS_INFO_CTR *ctr;
uint32 acc_granted;
@@ -4116,22 +4027,20 @@ NTSTATUS _samr_set_aliasinfo(pipes_struct *p, SAMR_Q_SET_ALIASINFO *q_u, SAMR_R_
return r_u->status;
}
- if (!get_local_group_from_sid(&group_sid, &map) &&
- !get_builtin_group_from_sid(&group_sid, &map))
- return NT_STATUS_NO_SUCH_GROUP;
-
ctr=&q_u->ctr;
switch (ctr->switch_value1) {
case 3:
- unistr2_to_ascii(map.comment, &(ctr->alias.info3.uni_acct_desc), sizeof(map.comment)-1);
+ unistr2_to_ascii(info.acct_desc,
+ &(ctr->alias.info3.uni_acct_desc),
+ sizeof(info.acct_desc)-1);
break;
default:
return NT_STATUS_INVALID_INFO_CLASS;
}
- if(!pdb_update_group_mapping_entry(&map)) {
- return NT_STATUS_NO_SUCH_GROUP;
+ if(!pdb_set_aliasinfo(&group_sid, &info)) {
+ return NT_STATUS_ACCESS_DENIED;
}
return NT_STATUS_OK;
diff --git a/source/utils/net_groupmap.c b/source/utils/net_groupmap.c
index 2b487ef17b4..a3a13e1dd88 100644
--- a/source/utils/net_groupmap.c
+++ b/source/utils/net_groupmap.c
@@ -608,6 +608,102 @@ static int net_groupmap_cleanup(int argc, const char **argv)
return 0;
}
+static int net_groupmap_addmem(int argc, const char **argv)
+{
+ DOM_SID alias, member;
+
+ if ( (argc != 2) ||
+ !string_to_sid(&alias, argv[0]) ||
+ !string_to_sid(&member, argv[1]) ) {
+ d_printf("Usage: net groupmap addmem alias-sid member-sid\n");
+ return -1;
+ }
+
+ if (!pdb_add_aliasmem(&alias, &member)) {
+ d_printf("Could not add sid %s to alias %s\n",
+ argv[1], argv[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int net_groupmap_delmem(int argc, const char **argv)
+{
+ DOM_SID alias, member;
+
+ if ( (argc != 2) ||
+ !string_to_sid(&alias, argv[0]) ||
+ !string_to_sid(&member, argv[1]) ) {
+ d_printf("Usage: net groupmap delmem alias-sid member-sid\n");
+ return -1;
+ }
+
+ if (!pdb_del_aliasmem(&alias, &member)) {
+ d_printf("Could not delete sid %s from alias %s\n",
+ argv[1], argv[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int net_groupmap_listmem(int argc, const char **argv)
+{
+ DOM_SID alias;
+ DOM_SID *members;
+ int i, num;
+ NTSTATUS result;
+
+ if ( (argc != 1) ||
+ !string_to_sid(&alias, argv[0]) ) {
+ d_printf("Usage: net groupmap listmem alias-sid\n");
+ return -1;
+ }
+
+ if (!pdb_enum_aliasmem(&alias, &members, &num)) {
+ d_printf("Could not list members for sid %s: %s\n",
+ argv[0], nt_errstr(result));
+ return -1;
+ }
+
+ for (i = 0; i < num; i++) {
+ printf("%s\n", sid_string_static(&(members[i])));
+ }
+
+ SAFE_FREE(members);
+
+ return 0;
+}
+
+static int net_groupmap_memberships(int argc, const char **argv)
+{
+ DOM_SID member;
+ DOM_SID *aliases;
+ int i, num;
+ NTSTATUS result;
+
+ if ( (argc != 1) ||
+ !string_to_sid(&member, argv[0]) ) {
+ d_printf("Usage: net groupmap memberof sid\n");
+ return -1;
+ }
+
+ if (!pdb_enum_alias_memberships(&member, &aliases, &num)) {
+ d_printf("Could not list memberships for sid %s: %s\n",
+ argv[0], nt_errstr(result));
+ return -1;
+ }
+
+ for (i = 0; i < num; i++) {
+ printf("%s\n", sid_string_static(&(aliases[i])));
+ }
+
+ SAFE_FREE(aliases);
+
+ return 0;
+}
+
int net_help_groupmap(int argc, const char **argv)
{
d_printf("net groupmap add"\
@@ -616,6 +712,14 @@ int net_help_groupmap(int argc, const char **argv)
"\n Update a group mapping\n");
d_printf("net groupmap delete"\
"\n Remove a group mapping\n");
+ d_printf("net groupmap addmember"\
+ "\n Add a foreign alias member\n");
+ d_printf("net groupmap delmember"\
+ "\n Delete a foreign alias member\n");
+ d_printf("net groupmap listmembers"\
+ "\n List foreign group members\n");
+ d_printf("net groupmap memberships"\
+ "\n List foreign group memberships\n");
d_printf("net groupmap list"\
"\n List current group map\n");
d_printf("net groupmap set"\
@@ -638,6 +742,10 @@ int net_groupmap(int argc, const char **argv)
{"delete", net_groupmap_delete},
{"set", net_groupmap_set},
{"cleanup", net_groupmap_cleanup},
+ {"addmem", net_groupmap_addmem},
+ {"delmem", net_groupmap_delmem},
+ {"listmem", net_groupmap_listmem},
+ {"memberships", net_groupmap_memberships},
{"list", net_groupmap_list},
{"help", net_help_groupmap},
{NULL, NULL}