r9908: Generate posixUser and posixGroup as well
authorJelmer Vernooij <jelmer@samba.org>
Thu, 1 Sep 2005 18:04:23 +0000 (18:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:36:21 +0000 (13:36 -0500)
source/dsdb/samdb/ldb_modules/samba3sam.c
source/lib/ldb/modules/ldb_map.c
source/lib/samba3/PLAN
testprogs/ejs/samba3sam

index 9730363e92adee90c98bbc78e7c78da3523d1615..41228e52f83a65df8074f2962a499a4e768d3b9e 100644 (file)
@@ -9,8 +9,9 @@
 #include "ldb/include/ldb.h"
 #include "ldb/include/ldb_private.h"
 #include "librpc/gen_ndr/ndr_security.h"
+#include "system/passwd.h"
 
-/* FIXME: 
+/* 
  * sambaSID -> member  (dn!)
  * sambaSIDList -> member (dn!) 
  * sambaDomainName -> name 
 /* In Samba4 but not in Samba3:
 */
 
-static struct ldb_val convert_sid_rid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+
+static struct ldb_message_element *generate_primaryGroupID(struct ldb_module *module, TALLOC_CTX *ctx, const char *attr, const struct ldb_message *remote)
+{
+       struct ldb_message_element *el;
+       const char *sid = ldb_msg_find_string(remote, attr, NULL);
+
+       if (!sid)
+               return NULL;
+
+       if (strchr(sid, '-') == NULL)
+               return NULL;
+
+       el = talloc_zero(ctx, struct ldb_message_element);
+       el->name = talloc_strdup(ctx, "primaryGroupID");
+       el->num_values = 1;
+       el->values = talloc_array(ctx, struct ldb_val, 1);
+       el->values[0].data = (uint8_t *)talloc_strdup(ctx, strchr(sid, '-')+1);
+       el->values[0].length = strlen((char *)el->values[0].data);
+
+       return el;
+}
+
+static void generate_sambaPrimaryGroupSID(struct ldb_module *module, const char *local_attr, const struct ldb_message *local, struct ldb_message *remote_mp, struct ldb_message *remote_fb)
 {
-       printf("Converting SID TO RID *\n");
+       const struct ldb_val *sidval;
+       struct dom_sid *sid;
+       struct ldb_val out;
+       NTSTATUS status;
+
+       sidval = ldb_msg_find_ldb_val(local, "objectSid");
+
+       if (!sidval) 
+               return; /* Sorry, no SID today.. */
+
+       sid = talloc(remote_mp, struct dom_sid);
+       if (sid == NULL) {
+               return;
+       }
+       status = ndr_pull_struct_blob(sidval, sid, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(sid);
+               return;
+       }
+
+       if (!ldb_msg_find_ldb_val(local, "primaryGroupID"))
+               return; /* Sorry, no SID today.. */
 
-       /* FIXME */
+       sid->sub_auths[sid->num_auths-1] = ldb_msg_find_uint(local, "primaryGroupID", 0);
 
-       return ldb_val_dup(ctx, val);
+       status = ndr_push_struct_blob(&out, remote_mp, sid, (ndr_push_flags_fn_t)ndr_push_dom_sid);
+       talloc_free(sid);
+       if (!NT_STATUS_IS_OK(status)) {
+               return;
+       }
+
+       ldb_msg_add_value(module->ldb, remote_mp, "sambaPrimaryGroupSID", &out);
 }
 
-static struct ldb_val convert_rid_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+
+static struct ldb_val lookup_homedir(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
 {
-       printf("Converting RID TO SID *\n");
+       struct passwd *pwd; 
+       struct ldb_val retval;
+       
+       pwd = getpwnam((char *)val->data);
+
+       if (!pwd) {
+               return *talloc_zero(ctx, struct ldb_val);
+       }
 
-       /* FIXME */
+       retval.data = (uint8_t *)talloc_strdup(ctx, pwd->pw_dir);
+       retval.length = strlen((char *)retval.data);
 
-       return ldb_val_dup(ctx, val);
+       return retval;
 }
 
-static struct ldb_val convert_unix_id2name(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+static struct ldb_val lookup_gid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
 {
-       printf("Converting UNIX ID to name\n");
+       struct passwd *pwd; 
+       struct ldb_val retval;
+       
+       pwd = getpwnam((char *)val->data);
 
-       /* FIXME */
+       if (!pwd) {
+               return *talloc_zero(ctx, struct ldb_val);
+       }
 
-       return ldb_val_dup(ctx, val);
+       retval.data = (uint8_t *)talloc_asprintf(ctx, "%d", pwd->pw_gid);
+       retval.length = strlen((char *)retval.data);
+
+       return retval;
 }
 
-static struct ldb_val convert_unix_name2id(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
+static struct ldb_val lookup_uid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
 {
-       printf("Converting UNIX name to ID\n");
+       struct passwd *pwd; 
+       struct ldb_val retval;
+       
+       pwd = getpwnam((char *)val->data);
 
-       /* FIXME */
+       if (!pwd) {
+               return *talloc_zero(ctx, struct ldb_val);
+       }
+
+       retval.data = (uint8_t *)talloc_asprintf(ctx, "%d", pwd->pw_uid);
+       retval.length = strlen((char *)retval.data);
 
-       return ldb_val_dup(ctx, val);
+       return retval;
 }
 
 static struct ldb_val encode_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
@@ -128,16 +203,31 @@ static struct ldb_val decode_sid(struct ldb_module *module, TALLOC_CTX *ctx, con
 }
 
 const struct ldb_map_objectclass samba3_objectclasses[] = {
+       {
+               .local_name = "user",
+               .remote_name = "posixAccount",
+               .base_classes = { "top", NULL },
+               .musts = { "cn", "uid", "uidNumber", "gidNumber", "homeDirectory", NULL },
+               .mays = { "userPassword", "loginShell", "gecos", "description", NULL },
+       },
+       {
+               .local_name = "group",
+               .remote_name = "posixGroup",
+               .base_classes = { "top", NULL },
+               .musts = { "cn", "gidNumber", NULL },
+               .mays = { "userPassword", "memberUid", "description", NULL },
+       },
        { 
                .local_name = "group", 
                .remote_name = "sambaGroupMapping",
+               .base_classes = { "top", "posixGroup", NULL },
                .musts = { "gidNumber", "sambaSID", "sambaGroupType", NULL },
                .mays = { "displayName", "description", "sambaSIDList", NULL },
        },
        { 
                .local_name = "user", 
                .remote_name = "sambaSAMAccount",
-               .base_classes = { "top", NULL },
+               .base_classes = { "top", "posixAccount", NULL },
                .musts = { "uid", "sambaSID", NULL },
                .mays = { "cn", "sambaLMPassword", "sambaNTPassword",
                        "sambaPwdLastSet", "sambaLogonTime", "sambaLogoffTime",
@@ -156,7 +246,7 @@ const struct ldb_map_objectclass samba3_objectclasses[] = {
                .musts = { "sambaDomainName", "sambaSID", NULL },
                .mays = { "sambaNextRid", "sambaNextGroupRid", "sambaNextUserRid", "sambaAlgorithmicRidBase", NULL },
        },
-       { NULL, NULL }
+               { NULL, NULL }
 };
 
 const struct ldb_map_attribute samba3_attributes[] = 
@@ -219,12 +309,12 @@ const struct ldb_map_attribute samba3_attributes[] =
        /* sambaPrimaryGroupSID -> primaryGroupID */
        {
                .local_name = "primaryGroupID",
-               .type = MAP_CONVERT,
+               .type = MAP_GENERATE,
                .u = {
-                       .convert = {
-                               .remote_name = "sambaPrimaryGroupSID",
-                               .convert_local = convert_rid_sid,
-                               .convert_remote = convert_sid_rid
+                       .generate = {
+                               .remote_names = { "sambaPrimaryGroupSID", NULL },
+                               .generate_local = generate_primaryGroupID,
+                               .generate_remote = generate_sambaPrimaryGroupSID
                        },
                },
        },
@@ -267,7 +357,7 @@ const struct ldb_map_attribute samba3_attributes[] =
                .local_name = "unixName",
                .type = MAP_RENAME,
                .u = {
-                       .convert = {
+                       .rename = {
                                .remote_name = "uid",
                        },
                },
@@ -723,6 +813,42 @@ const struct ldb_map_attribute samba3_attributes[] =
                .type = MAP_IGNORE,
        },
 
+       /* uidNumber */
+       {
+               .local_name = "unixName",
+               .type = MAP_CONVERT,
+               .u = {
+                       .convert = {
+                               .remote_name = "uidNumber",
+                               .convert_local = lookup_uid,
+                       },
+               },
+       },
+
+       /* gidNumber. Perhaps make into generate so we can distinguish between 
+        * groups and accounts? */
+       {
+               .local_name = "unixName",
+               .type = MAP_CONVERT,
+               .u = {
+                       .convert = {
+                               .remote_name = "gidNumber",
+                               .convert_local = lookup_gid,
+                       },
+               },
+       },
+
+       /* homeDirectory */
+       {
+               .local_name = "unixName",
+               .type = MAP_CONVERT,
+               .u = {
+                       .convert = {
+                               .remote_name = "homeDirectory",
+                               .convert_local = lookup_homedir,
+                       },
+               },
+       },
        {
                .local_name = NULL,
        }
index 5a5575d1e0491385742cdb6ee9889423c97d5d76..f3ece2621ed4ad550fe76c5d10dd52a76d108061 100644 (file)
 #include "ldb/include/ldb_private.h"
 #include "ldb/modules/ldb_map.h"
 
-/* FIXME:
- *  - per remote objectclass: 
- *     - remote name
- *     - local name
- *     - remote bases
- *     - musts
- *     - mays
- */
-
 /*
  - special attribute 'isMapped'
  - add/modify
@@ -164,33 +155,39 @@ static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_contex
 /* Check if a given attribute can be created by doing mapping from a local attribute to a remote one */
 static int map_msg_can_map_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr_name)
 {
-       struct ldb_map_context *map = module->private_data;
-       int i, j;
-       
-       for (i = 0; i < msg->num_elements; i++) {
-               const struct ldb_map_attribute *attr = map_find_attr_local(map, msg->elements[i].name);
+       struct ldb_map_context *privdat = module->private_data;
+       int i,j;
 
-               if (!attr) 
+       for (i = 0; privdat->attribute_maps[i].local_name; i++) {
+               switch (privdat->attribute_maps[i].type) {
+               case MAP_IGNORE: /* No remote name at all */
                        continue;
-
-               switch (attr->type) {
-               case MAP_IGNORE: continue;
                case MAP_KEEP:
-                               if (ldb_attr_cmp(attr->local_name, attr_name) == 0) return 1;
-                               break;
+                       if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].local_name) == 0)
+                               goto found;
+                       break;
                case MAP_RENAME:
                case MAP_CONVERT:
-                               if (ldb_attr_cmp(attr->u.rename.remote_name, attr_name) == 0) return 1;
-                               break;
+                       if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].u.rename.remote_name) == 0)
+                               goto found;
+                       break;
                case MAP_GENERATE:
-                               for (j = 0; attr->u.generate.remote_names[j]; j++) {
-                                       if (ldb_attr_cmp(attr->u.generate.remote_names[j], attr_name) == 0) return 1;
-                               }
-                               break;
+                       for (j = 0; privdat->attribute_maps[i].u.generate.remote_names[j]; j++) {
+                               if (ldb_attr_cmp(attr_name, privdat->attribute_maps[i].u.generate.remote_names[j]) == 0)
+                                       goto found;
+                       }
+                       break;
                }
        }
 
        return 0;
+
+found:
+
+       if (ldb_msg_find_element(msg, privdat->attribute_maps[i].local_name))
+               return 1;
+
+       return 0;
 }
 
 
@@ -684,29 +681,28 @@ static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, con
 {
        struct ldb_map_context *privdat = map_get_privdat(module);
        struct ldb_dn *n_olddn, *n_newdn;
-       int fb_ret, mp_ret;
+       int ret;
 
-       fb_ret = ldb_next_rename_record(module, olddn, newdn);
-       
-       if (fb_ret != -1) {
-               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed");
-               return fb_ret;
-       }
-       
        n_olddn = map_local_dn(module, module, olddn);
        n_newdn = map_local_dn(module, module, newdn);
 
-       mp_ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
-       if (mp_ret != -1) {
+       ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn);
+       if (ret != -1) {
                ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record renamed");
+               ldb_next_rename_record(module, olddn, newdn);
+       } else {
+               ret = ldb_next_rename_record(module, olddn, newdn);
+       
+               if (ret != -1) {
+                       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed");
+               }
        }
 
-       ldb_next_rename_record(module, olddn, newdn);
        
        talloc_free(n_olddn);
        talloc_free(n_newdn);
        
-       return mp_ret;
+       return ret;
 }
 
 /*
@@ -716,26 +712,25 @@ static int map_delete(struct ldb_module *module, const struct ldb_dn *dn)
 {
        struct ldb_map_context *privdat = map_get_privdat(module);
        struct ldb_dn *newdn;
-       int fb_ret, mp_ret;
-
-       fb_ret = ldb_next_delete_record(module, dn);
-       if (fb_ret != -1) {
-               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted");
-               return fb_ret;
-       }
+       int ret;
 
        newdn = map_local_dn(module, module, dn);
 
-       mp_ret = ldb_delete(privdat->mapped_ldb, newdn);
-       if (mp_ret != -1) {
+       ret = ldb_delete(privdat->mapped_ldb, newdn);
+       if (ret != -1) {
                ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record deleted");
+       } else {
+               ret = ldb_next_delete_record(module, dn);
+               if (ret != -1) {
+                       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted");
+               }
        }
 
        ldb_next_delete_record(module, newdn);
 
        talloc_free(newdn);
 
-       return mp_ret;
+       return ret;
 }
 
 /* search fallback database */
@@ -868,7 +863,7 @@ static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *bas
                              enum ldb_scope scope, struct ldb_parse_tree *tree,
                              const char * const *attrs, struct ldb_message ***res)
 {
-       struct ldb_message **fbres, **mpres;
+       struct ldb_message **fbres, **mpres = NULL;
        int i;
        int ret_fb, ret_mp;
 
@@ -968,16 +963,20 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                
                /* Add this objectClass to the list if all musts are present */
                for (j = 0; privdat->objectclass_maps[i].musts[j]; j++) {
-                       if (!map_msg_can_map_attr(module, msg, privdat->objectclass_maps[i].musts[j])) 
+                       if (!map_msg_can_map_attr(module, msg, privdat->objectclass_maps[i].musts[j])) {
+                               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "map_add: Not adding objectClass %s because it is not possible to create remote attribute %s", privdat->objectclass_maps[i].local_name, privdat->objectclass_maps[i].musts[j]);
                                break;
+                       }
                }
 
                has_musts = (privdat->objectclass_maps[i].musts[j] == NULL);
 
                /* Check if base classes are present as well */
                for (j = 0; privdat->objectclass_maps[i].base_classes[j]; j++) {
-                       if (!msg_contains_objectclass(mp, privdat->objectclass_maps[i].base_classes[j]))
+                       if (!msg_contains_objectclass(mp, privdat->objectclass_maps[i].base_classes[j])) {
+                               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "map_add: Not adding objectClass %s of missing base class %s", privdat->objectclass_maps[i].local_name, privdat->objectclass_maps[i].base_classes[j]);
                                break;
+                       }
                }
 
                has_baseclasses = (privdat->objectclass_maps[i].base_classes[j] == NULL);
@@ -985,6 +984,7 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                /* Apparently, it contains all required elements */
                if (has_musts && has_baseclasses) {
                        ldb_msg_add_string(module->ldb, mp, "objectClass", privdat->objectclass_maps[i].remote_name);   
+                       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "map_add: Adding objectClass %s", privdat->objectclass_maps[i].remote_name);
                }
        }
 
@@ -1000,7 +1000,7 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
         */
        for (i = 0; i < msg->num_elements; i++) {
                const struct ldb_map_attribute *attr;
-               struct ldb_message_element *elm;
+               struct ldb_message_element *elm = NULL;
                enum ldb_map_attr_type map_type;
                int j;
                int mapped = 0;
@@ -1018,10 +1018,12 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                /* Decide whether or not we need to map or fallback */
                switch (map_type) {
                case MAP_GENERATE:
+                       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Generating from %s", attr->local_name);
                        attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb);
                        continue;
                case MAP_KEEP:
                        mapped = map_msg_valid_attr(module, mp, attr->local_name);
+                       break;
                case MAP_IGNORE: mapped = 0; break;
                case MAP_CONVERT:
                case MAP_RENAME: mapped = map_msg_valid_attr(module, mp, attr->u.rename.remote_name);
@@ -1031,6 +1033,7 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                if (mapped) {
                        switch (map_type) {
                        case MAP_KEEP:
+                               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Keeping %s", attr->local_name);
                                elm = talloc(fb, struct ldb_message_element);
 
                                elm->num_values = msg->elements[i].num_values;
@@ -1039,6 +1042,7 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                                break;
 
                        case MAP_RENAME:
+                               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Renaming %s -> %s", attr->local_name, attr->u.rename.remote_name);
                                elm = talloc(mp, struct ldb_message_element);
 
                                elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
@@ -1047,6 +1051,7 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                                break;
 
                        case MAP_CONVERT:
+                               ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Converting %s -> %s", attr->local_name, attr->u.convert.remote_name);
                                elm = talloc(mp, struct ldb_message_element);
 
                                elm->name = talloc_strdup(elm, attr->u.rename.remote_name);
@@ -1064,10 +1069,11 @@ static int map_add(struct ldb_module *module, const struct ldb_message *msg)
                        case MAP_GENERATE:
                        case MAP_IGNORE:
                                ldb_debug(module->ldb, LDB_DEBUG_FATAL, "This line should never be reached");
-                               break;
+                               continue;
                        } 
                        ldb_msg_add(module->ldb, mp, elm, 0);
                } else {
+                       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback storing %s", msg->elements[i].name);
                        elm = talloc(fb, struct ldb_message_element);
 
                        elm->num_values = msg->elements[i].num_values;
@@ -1197,13 +1203,13 @@ static int map_modify(struct ldb_module *module, const struct ldb_message *msg)
                        ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE");
                        fb_ret = ldb_next_add_record(module, fb);
                }
-       }
+       } else fb_ret = 0;
        talloc_free(fb);
 
        if (mp->num_elements > 0) {
                ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying mapped record with %d elements", mp->num_elements);
                mp_ret = ldb_modify(privdat->mapped_ldb, mp);
-       }
+       } else mp_ret = 0;
        talloc_free(mp);
 
        return (mp_ret == -1 || fb_ret == -1)?-1:0;
index 4351ce2e61fe6f3c402594ce3274dff66b186120..916617638b5165776892c19c50077a18ac5e69c8 100644 (file)
@@ -1,3 +1,7 @@
 TODO (SoC project):
- - [ldb_map] some more strict checking when sending data to an LDAP server
  - fix ntPwdHash / lmPwdHash bug
+ - ldb_map
+  - convert_remote() can be NULL!
+  - new way of finding remote attribute in map_add()
+   - loop over all attributes 
+    - if local one present, run!
index c422bce16b4e4083161c0d0ed540d9091a5dcedc..6ca759265065c69ff343cea203c82947b0cd9d96 100755 (executable)
@@ -126,7 +126,7 @@ assert(msg.length == 1);
 assert(msg[0].cn == "Niemand");
 
 println("Checking for data in destination database");
-msg = s3.search("(displayName=Niemand)");
+msg = s3.search("(cn=Niemand)");
 assert(msg.length >= 1);
 assert(msg[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001");
 assert(msg[0].displayName == "Niemand");
@@ -143,7 +143,6 @@ assert(ok);
 println("Checking whether changes are still there...");
 msg = s4.search("(cn=Niemand)");
 assert(msg.length >= 1);
-printVars(msg);
 assert(msg[0].cn == "Niemand");
 assert(msg[0].description == "Blah");