summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/LDAP/samba.schema25
-rw-r--r--source3/passdb/pdb_ldap.c502
2 files changed, 526 insertions, 1 deletions
diff --git a/examples/LDAP/samba.schema b/examples/LDAP/samba.schema
index f71c344e06..71689237e8 100644
--- a/examples/LDAP/samba.schema
+++ b/examples/LDAP/samba.schema
@@ -111,6 +111,19 @@ attributetype ( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID'
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
##
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
index 46e0994379..d512a4fda3 100644
--- a/source3/passdb/pdb_ldap.c
+++ b/source3/passdb/pdb_ldap.c
@@ -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)
{
@@ -1987,6 +1990,495 @@ static void free_private_data(void **vp)
/* 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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)
+{
+ 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,
+ enum SID_NAME_USE sid_name_use,
+ GROUP_MAP **rmap, int *num_entries,
+ BOOL unix_only, BOOL with_priv)
+{
+ GROUP_MAP map;
+ GROUP_MAP *mapt;
+ int entries = 0;
+ NTSTATUS nt_status;
+
+ *num_entries = 0;
+ *rmap = NULL;
+
+ if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
+ DEBUG(0, ("Unable to open passdb\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ 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;
+ }
+
+ 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;
+
+ 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)
{
NTSTATUS nt_status;
@@ -2007,6 +2499,14 @@ NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, co
(*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;
+ (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
+ (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
+ (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
+ (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
+
/* TODO: Setup private data and free */
ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));