r116: volker's patch for local group and group nesting
authorGerald Carter <jerry@samba.org>
Wed, 7 Apr 2004 12:43:44 +0000 (12:43 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:51:10 +0000 (10:51 -0500)
(This used to be commit b393469d9581f20e4d4c52633b952ee984cca36f)

24 files changed:
source3/Makefile.in
source3/groupdb/mapping.c
source3/include/ntdomain.h
source3/include/passdb.h
source3/include/smbldap.h
source3/lib/smbldap.c
source3/lib/util_str.c
source3/libsmb/libsmbclient.c
source3/nsswitch/wb_client.c
source3/nsswitch/wbinfo.c
source3/nsswitch/winbindd.c
source3/nsswitch/winbindd.h
source3/nsswitch/winbindd_group.c
source3/nsswitch/winbindd_nss.h
source3/nsswitch/winbindd_passdb.c [new file with mode: 0644]
source3/nsswitch/winbindd_sid.c
source3/nsswitch/winbindd_util.c
source3/param/loadparm.c
source3/passdb/pdb_interface.c
source3/passdb/pdb_ldap.c
source3/passdb/util_sam_sid.c
source3/rpc_server/srv_lsa_nt.c
source3/rpc_server/srv_samr_nt.c
source3/utils/net_groupmap.c

index 3bb578ea84b8a9d62c4559fabd36b851450b058c..51b32b4431101424bd6c8aee4feb85861527ab47 100644 (file)
@@ -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
 
index d10a7decb7e717efe0593ecd1acd6cf407b050ed..548651dfd538c6b1453c887f63525d543e8a56f5 100644 (file)
@@ -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
  *********************************************************************/
index b1a4107980d55a2c7cb5067163c4f65523ef1999..9640f2e53bfeff9afa6b5bc7eab3c50abbbad208 100644 (file)
@@ -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
  */
index 75c4fd215bffeab9745e86402b5300e2fdaa45de..d08fd13a72321e59e77bf0be26ba40dd0601eb3f 100644 (file)
@@ -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 **);
index 2f71f971d92c2389c3285a4016c355f10189d9c4..61b8df0f0efb5f9e6c6ea95dd03db0d99fa75638 100644 (file)
@@ -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;
index f4f0170479f10086b3d846b544d72c697f08344b..21e2a7c1018ec84a180226a5b4f9e4d545ac35d8 100644 (file)
@@ -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                    }       
 };
 
index e4b07a4b731d04a662d596f2af9cfd00fa45d2b2..600c830aced096b8ab6dcc7967224ec37428deef 100644 (file)
@@ -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);
+}
index 68bb6661ebdd6041a0c2ede5d2cf10b676db46c6..ebbf28a12dbb3561f35a00412f7272a05b437d32 100644 (file)
@@ -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;
index 90e4584daba026676b7d0f42acea0de2e13e9527..5d431392450f9b561915cffa7478bca953487c49 100644 (file)
@@ -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. */
 
index 2cea4130adcd0b650e4ef993d1a68870fcedcee4..ce48e9ae6521741279157a7e100d8128fb0abc7d 100644 (file)
@@ -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");
index b55ea297b493ec0d78e641390976b435a92ff18f..283b2e4a89c3f07d902b89b53655fa33707dfa69 100644 (file)
@@ -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 */
 
index 0087d58195d8eb938ff69a09bbeb352a5e22470b..5c05a1b0457bf489492d24a3e44298056a40c940 100644 (file)
@@ -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;
index 3ee8c0877b5aec1ae7ffae03e79f9e8d3afb23da..f9b6df1aed968af4c583995328f02222da428133 100644 (file)
@@ -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;
                }
        }
 
index 73b39569a964cbc19fb1ed4cb2bddccd3cbfad52..8167cfafa860b65d03ca4782a9b2324b7add0890 100644 (file)
@@ -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/source3/nsswitch/winbindd_passdb.c b/source3/nsswitch/winbindd_passdb.c
new file mode 100644 (file)
index 0000000..36f5297
--- /dev/null
@@ -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
+};
index 9fbf47046d651e684d30f14f9083c207abddb24c..d4206558c5ec6d6e775e2b55a3fa131d5d7b353c 100644 (file)
 
 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;
+}
index 403ba399c88d1f6ec75dd3cdd86bd89a59d28ba1..1a01f1c05e6d5f0e871d4a4b81ce4793121cfde9 100644 (file)
@@ -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);
index 6b09faf7bf9bdfba5d26a79c67fde508d2cdb036..894e7ecc9c1ab1f94d943928d648461ba914d665 100644 (file)
@@ -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)
index 06097d3557ba7d737ef8ad54c20d86840980d797..a3b2706c35b96bc519d5f0c1d0cbf9cdafc95654 100644 (file)
@@ -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;
 }
index 307d187f66721aad9400f4b60613369a1a97e8b3..15635a034ccfb7dd4d16c4823cf4854582868945 100644 (file)
@@ -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);
 
@@ -2031,6 +2031,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;
 
index f6cc2491a8b1169a590f9f2d583e0950295040b9..63ef5914af81d6d945b216d71c26ab42ba92bf26 100644 (file)
@@ -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;
+}
index 9801ce47f8fab2a7c16d2c3f947c33c031fb5264..de4fdceba7a0778547a1dabdff10121cf8d377f7 100644 (file)
@@ -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"));
 
index 70ae4d170e4276cd297b763c7de89309e3ed26f4..2e5fe295ecb15aeb994273b0cdfde2baf325398f 100644 (file)
@@ -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;
index 2b487ef17b4cb825644f5d1e3a99e3dc08942d59..a3a13e1dd88efda2c7544cf475e12e40bf7ab383 100644 (file)
@@ -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}