Put group mapping into LDAP.
authorVolker Lendecke <vlendec@samba.org>
Wed, 19 Mar 2003 09:43:23 +0000 (09:43 +0000)
committerVolker Lendecke <vlendec@samba.org>
Wed, 19 Mar 2003 09:43:23 +0000 (09:43 +0000)
Volker
(This used to be commit da83d97eb50c3c3a67985e22410842100207431f)

examples/LDAP/samba.schema
source3/passdb/pdb_ldap.c

index f71c344e067607aadd2ef5c1171bcc1108d1630a..71689237e8d6538188cf3c83fb8e9bf3801c339a 100644 (file)
@@ -110,6 +110,19 @@ attributetype ( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID'
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
+##
+## group mapping attributes
+##
+attributetype ( 1.3.6.1.4.1.7165.2.1.19 NAME 'ntGroupType'
+       DESC 'NT Group Type'
+       EQUALITY caseIgnoreIA5Match
+       SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.20 NAME 'ntSid'
+       DESC 'Security ID'
+       EQUALITY caseIgnoreIA5Match
+       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
 ##
 ## The smbPasswordEntry objectclass has been depreciated in favor of the
 ## sambaAccount objectclass
@@ -139,6 +152,18 @@ objectclass ( 1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' SUP top AUXILIARY
                displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
                description $ userWorkstations $ primaryGroupID $ domain ))
 
+############################################################################
+##
+## Please note that this schema is really experimental and might 
+## change before the 3.0 release.
+##
+############################################################################
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY
+       DESC 'Samba Group Mapping'
+       MUST ( gidNumber $ ntSid $ ntGroupType ) 
+       MAY  ( displayName $ description ))
+
 ##
 ## Used for Winbind experimentation
 ##
index 62fc5810d1b7e817557e3dd7aa6279511aa72a95..d512a4fda32449d261258777d055f3bfa264fdfb 100644 (file)
@@ -786,8 +786,11 @@ static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, c
        if (attribute == NULL || *attribute == '\0')
                return;
 
-       if (value == NULL || *value == '\0')
+#if 0
+       /* Why do we need this??? -- vl */
+               if (value == NULL || *value == '\0')
                return;
+#endif
 
        if (mods == NULL) 
        {
@@ -1967,46 +1970,463 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCO
        return NT_STATUS_OK;
 }
 
+static void free_private_data(void **vp) 
+{
+       struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
+
+       ldapsam_close(*ldap_state);
+
+       if ((*ldap_state)->bind_secret) {
+               memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
+       }
+
+       ldapsam_close(*ldap_state);
+               
+       SAFE_FREE((*ldap_state)->bind_dn);
+       SAFE_FREE((*ldap_state)->bind_secret);
+
+       *ldap_state = NULL;
+
+       /* No need to free any further, as it is talloc()ed */
+}
+
+static const char *group_attr[] = {"gid", "ntSid", "ntGroupType",
+                                  "gidNumber",
+                                  "displayName", "description",
+                                  NULL };
+                                  
+static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
+                                    const char *filter,
+                                    LDAPMessage ** result)
+{
+       int scope = LDAP_SCOPE_SUBTREE;
+       int rc;
+
+       DEBUG(2, ("ldapsam_search_one_group: searching for:[%s]\n", filter));
+
+       rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope,
+                           filter, group_attr, 0, result);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(0, ("ldapsam_search_one_group: "
+                         "Problem during the LDAP search: %s\n",
+                         ldap_err2string(rc)));
+               DEBUG(3, ("ldapsam_search_one_group: Query was: %s, %s\n",
+                         lp_ldap_suffix(), filter));
+       }
+
+       return rc;
+}
+
+static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
+                                GROUP_MAP *map, LDAPMessage *entry)
+{
+       pstring temp;
+
+       if (ldap_state == NULL || map == NULL || entry == NULL ||
+           ldap_state->ldap_struct == NULL) {
+               DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
+               return False;
+       }
+
+       if (!get_single_attribute(ldap_state->ldap_struct, entry, "gidNumber",
+                                 temp)) {
+               DEBUG(0, ("Mandatory attribute gidNumber not found\n"));
+               return False;
+       }
+       DEBUG(2, ("Entry found for group: %s\n", temp));
+
+       map->gid = (uint32)atol(temp);
+
+       if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntSid",
+                                 temp)) {
+               DEBUG(0, ("Mandatory attribute ntSid not found\n"));
+               return False;
+       }
+       string_to_sid(&map->sid, temp);
+
+       if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntGroupType",
+                                 temp)) {
+               DEBUG(0, ("Mandatory attribute ntGroupType not found\n"));
+               return False;
+       }
+       map->sid_name_use = (uint32)atol(temp);
+
+       if ((map->sid_name_use < SID_NAME_USER) ||
+           (map->sid_name_use > SID_NAME_UNKNOWN)) {
+               DEBUG(0, ("Unknown Group type: %d\n", map->sid_name_use));
+               return False;
+       }
+
+       if (!get_single_attribute(ldap_state->ldap_struct, entry, "displayName",
+                                 temp)) {
+               DEBUG(3, ("Attribute displayName not found\n"));
+               temp[0] = '\0';
+       }
+       fstrcpy(map->nt_name, temp);
+
+       if (!get_single_attribute(ldap_state->ldap_struct, entry, "description",
+                                 temp)) {
+               DEBUG(3, ("Attribute description not found\n"));
+               temp[0] = '\0';
+       }
+       fstrcpy(map->comment, temp);
+
+       map->systemaccount = 0;
+       init_privilege(&map->priv_set);
+
+       return True;
+}
+
+static BOOL init_ldap_from_group(struct ldapsam_privates *ldap_state,
+                                LDAPMod ***mods, int ldap_op,
+                                const GROUP_MAP *map)
+{
+       pstring tmp;
+
+       if (mods == NULL || map == NULL) {
+               DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n"));
+               return False;
+       }
+
+       *mods = NULL;
+
+       sid_to_string(tmp, &map->sid);
+       make_a_mod(mods, ldap_op, "ntSid", tmp);
+
+       snprintf(tmp, sizeof(tmp)-1, "%i", map->sid_name_use);
+       make_a_mod(mods, ldap_op, "ntGroupType", tmp);
+
+       make_a_mod(mods, ldap_op, "displayName", map->nt_name);
+       make_a_mod(mods, ldap_op, "description", map->comment);
+
+       return True;
+}
+
+static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
+                                const char *filter,
+                                GROUP_MAP *map)
+{
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)methods->private_data;
+       LDAPMessage *result;
+       LDAPMessage *entry;
+       int count;
+
+       if (ldapsam_search_one_group(ldap_state, filter, &result)
+           != LDAP_SUCCESS) {
+               return NT_STATUS_NO_SUCH_GROUP;
+       }
+
+       count = ldap_count_entries(ldap_state->ldap_struct, result);
+
+       if (count < 1) {
+               DEBUG(4, ("Did not find group for filter %s\n", filter));
+               return NT_STATUS_NO_SUCH_GROUP;
+       }
+
+       if (count > 1) {
+               DEBUG(1, ("Duplicate entries for filter %s: count=%d\n",
+                         filter, count));
+               return NT_STATUS_NO_SUCH_GROUP;
+       }
+
+       entry = ldap_first_entry(ldap_state->ldap_struct, result);
+
+       if (!entry) {
+               ldap_msgfree(result);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (!init_group_from_ldap(ldap_state, map, entry)) {
+               DEBUG(1, ("init_group_from_ldap failed for group filter %s\n",
+                         filter));
+               ldap_msgfree(result);
+               return NT_STATUS_NO_SUCH_GROUP;
+       }
+
+       ldap_msgfree(result);
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
                                 DOM_SID sid, BOOL with_priv)
 {
-       return get_group_map_from_sid(sid, map, with_priv) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+       pstring filter;
+
+       snprintf(filter, sizeof(filter)-1,
+                "(&(objectClass=sambaGroupMapping)(ntSid=%s))",
+                sid_string_static(&sid));
+
+       return ldapsam_getgroup(methods, filter, map);
 }
 
 static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
                                 gid_t gid, BOOL with_priv)
 {
-       return get_group_map_from_gid(gid, map, with_priv) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+       pstring filter;
+
+       snprintf(filter, sizeof(filter)-1,
+                "(&(objectClass=sambaGroupMapping)(gidNumber=%d))",
+                gid);
+
+       return ldapsam_getgroup(methods, filter, map);
 }
 
 static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
                                 char *name, BOOL with_priv)
 {
-       return get_group_map_from_ntname(name, map, with_priv) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+       pstring filter;
+
+       /* TODO: Escaping of name? */
+
+       snprintf(filter, sizeof(filter)-1,
+                "(&(objectClass=sambaGroupMapping)(displayName=%s))",
+                name);
+
+       return ldapsam_getgroup(methods, filter, map);
+}
+
+static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state,
+                                          gid_t gid,
+                                          LDAPMessage **result)
+{
+       pstring filter;
+
+       snprintf(filter, sizeof(filter)-1,
+                "(&(objectClass=posixGroup)(gidNumber=%i))", gid);
+
+       return ldapsam_search_one_group(ldap_state, filter, result);
 }
 
 static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
                                                GROUP_MAP *map)
 {
-       return add_mapping_entry(map, TDB_INSERT) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)methods->private_data;
+       LDAPMessage *result = NULL;
+       LDAPMod **mods = NULL;
+
+       char *tmp;
+       pstring dn;
+       LDAPMessage *entry;
+
+       GROUP_MAP dummy;
+
+       int rc;
+
+       if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy,
+                                            map->gid, False))) {
+               DEBUG(0, ("Group %i already exists in LDAP\n", map->gid));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
+       if (rc != LDAP_SUCCESS) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (ldap_count_entries(ldap_state->ldap_struct, result) != 1) {
+               DEBUG(2, ("Group %i must exist exactly once in LDAP\n",
+                         map->gid));
+               ldap_msgfree(result);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       entry = ldap_first_entry(ldap_state->ldap_struct, result);
+       tmp = ldap_get_dn(ldap_state->ldap_struct, entry);
+       pstrcpy(dn, tmp);
+       ldap_memfree(tmp);
+       ldap_msgfree(result);
+
+       if (!init_ldap_from_group(ldap_state, &mods, LDAP_MOD_ADD, map)) {
+               DEBUG(0, ("init_ldap_from_group failed!\n"));
+               ldap_mods_free(mods, 1);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (mods == NULL) {
+               DEBUG(0, ("mods is empty\n"));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       make_a_mod(&mods, LDAP_MOD_ADD, "objectClass",
+                  "sambaGroupMapping");
+
+       rc = ldapsam_modify(ldap_state, dn, mods);
+       ldap_mods_free(mods, 1);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(0, ("failed to modify group %i\n", map->gid));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
+       return NT_STATUS_OK;
 }
 
 static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
                                                   GROUP_MAP *map)
 {
-       return add_mapping_entry(map, TDB_REPLACE) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)methods->private_data;
+       int rc;
+       char *dn;
+       LDAPMessage *result;
+       LDAPMessage *entry;
+       LDAPMod **mods;
+
+       if (!init_ldap_from_group(ldap_state, &mods, LDAP_MOD_REPLACE, map)) {
+               DEBUG(0, ("init_ldap_from_group failed\n"));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (mods == NULL) {
+               DEBUG(4, ("mods is empty: nothing to do\n"));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
+
+       if (rc != LDAP_SUCCESS) {
+               ldap_mods_free(mods, 1);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
+               DEBUG(0, ("No group to modify!\n"));
+               ldap_msgfree(result);
+               ldap_mods_free(mods, 1);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       entry = ldap_first_entry(ldap_state->ldap_struct, result);
+       dn = ldap_get_dn(ldap_state->ldap_struct, entry);
+        ldap_msgfree(result);
+
+       rc = ldapsam_modify(ldap_state, dn, mods);
+
+       ldap_mods_free(mods, 1);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(0, ("failed to modify group %i\n", map->gid));
+       }
+
+       DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
+       return NT_STATUS_OK;
 }
 
 static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
                                                   DOM_SID sid)
 {
-       return group_map_remove(sid) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)methods->private_data;
+       pstring sidstring, filter;
+       int rc;
+       char *dn;
+       LDAPMessage *result;
+       LDAPMessage *entry;
+       LDAPMod **mods;
+
+       sid_to_string(sidstring, &sid);
+       snprintf(filter, sizeof(filter)-1,
+                "(&(objectClass=sambaGroupMapping)(ntSid=%s))", sidstring);
+
+       rc = ldapsam_search_one_group(ldap_state, filter, &result);
+
+       if (rc != LDAP_SUCCESS) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (ldap_count_entries(ldap_state->ldap_struct, result) != 1) {
+               DEBUG(0, ("Group must exist exactly once\n"));
+               ldap_msgfree(result);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       entry = ldap_first_entry(ldap_state->ldap_struct, result);
+       dn = ldap_get_dn(ldap_state->ldap_struct, entry);
+        ldap_msgfree(result);
+
+       mods = NULL;
+       make_a_mod(&mods, LDAP_MOD_DELETE, "objectClass", "sambaGroupMapping");
+       make_a_mod(&mods, LDAP_MOD_DELETE, "ntSid", NULL);
+       make_a_mod(&mods, LDAP_MOD_DELETE, "ntGroupType", NULL);
+       make_a_mod(&mods, LDAP_MOD_DELETE, "description", NULL);
+       make_a_mod(&mods, LDAP_MOD_DELETE, "displayName", NULL);
+       
+       rc = ldapsam_modify(ldap_state, dn, mods);
+
+       ldap_mods_free(mods, 1);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(0, ("failed to delete group %s\n", sidstring));
+       }
+
+       DEBUG(2, ("successfully delete group mapping %s in LDAP\n",
+                 sidstring));
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods,
+                                   BOOL update)
+{
+       struct ldapsam_privates *ldap_state =
+               (struct ldapsam_privates *)my_methods->private_data;
+       const char *filter = "(objectClass=sambaGroupMapping)";
+       int rc;
+
+       rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
+                           LDAP_SCOPE_SUBTREE, filter,
+                           group_attr, 0, &ldap_state->result);
+
+       if (rc != LDAP_SUCCESS) {
+               DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
+               DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
+               ldap_msgfree(ldap_state->result);
+               ldap_state->result = NULL;
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
+                 ldap_count_entries(ldap_state->ldap_struct,
+                                    ldap_state->result)));
+
+       ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
+                                ldap_state->result);
+       ldap_state->index = 0;
+
+       return NT_STATUS_OK;
+}
+
+static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
+{
+       return ldapsam_endsampwent(my_methods);
+}
+
+static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
+                                   GROUP_MAP *map)
+{
+       NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
+       struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
+       BOOL bret = False;
+
+       /* The rebind proc needs this *HACK*.  We are not multithreaded, so
+          this will work, but it's not nice. */
+       static_ldap_state = ldap_state;
+
+       while (!bret) {
+               if (!ldap_state->entry)
+                       return ret;
+               
+               ldap_state->index++;
+               bret = init_group_from_ldap(ldap_state, map, ldap_state->entry);
+               
+               ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
+                                           ldap_state->entry); 
+       }
+
+       return NT_STATUS_OK;
 }
 
 static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
@@ -2014,29 +2434,49 @@ static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
                                           GROUP_MAP **rmap, int *num_entries,
                                           BOOL unix_only, BOOL with_priv)
 {
-       return enum_group_mapping(sid_name_use, rmap, num_entries, unix_only,
-                                 with_priv) ?
-               NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
-}
+       GROUP_MAP map;
+       GROUP_MAP *mapt;
+       int entries = 0;
+       NTSTATUS nt_status;
 
-static void free_private_data(void **vp) 
-{
-       struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
+       *num_entries = 0;
+       *rmap = NULL;
 
-       ldapsam_close(*ldap_state);
-
-       if ((*ldap_state)->bind_secret) {
-               memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
+       if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
+               DEBUG(0, ("Unable to open passdb\n"));
+               return NT_STATUS_ACCESS_DENIED;
        }
 
-       ldapsam_close(*ldap_state);
-               
-       SAFE_FREE((*ldap_state)->bind_dn);
-       SAFE_FREE((*ldap_state)->bind_secret);
+       while (NT_STATUS_IS_OK(nt_status = ldapsam_getsamgrent(methods, &map))) {
+               if (sid_name_use != SID_NAME_UNKNOWN &&
+                   sid_name_use != map.sid_name_use) {
+                       DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
+                       continue;
+               }
+               if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
+                       DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
+                       continue;
+               }
 
-       *ldap_state = NULL;
+               mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
+               if (!mapt) {
+                       DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
+                       SAFE_FREE(*rmap);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+               else
+                       (*rmap) = mapt;
 
-       /* No need to free any further, as it is talloc()ed */
+               mapt[entries] = map;
+
+               entries += 1;
+
+       }
+       ldapsam_endsamgrent(methods);
+
+       *num_entries = entries;
+
+       return NT_STATUS_OK;
 }
 
 NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
@@ -2058,6 +2498,7 @@ NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, co
        (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
        (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
        (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
+
        (*pdb_method)->getgrsid = ldapsam_getgrsid;
        (*pdb_method)->getgrgid = ldapsam_getgrgid;
        (*pdb_method)->getgrnam = ldapsam_getgrnam;