[PATCH] s4-drs: replmd_delete implementation

Eduardo Lima eduardoll at gmail.com
Mon Nov 23 10:52:20 MST 2009


>your code is doing a ldb modify, so in the modify you would need toget
>list them as LDB_FLAG_MOD_DELETE. So you actually should use a
>db_msg_add_*() call, but sets the element flags to mark it as an
>element to delete.

I'm inserting a new element to the "msg" using ldb_msg_add_empty():

ret = ldb_msg_add_empty(msg, "badPwdCount", LDB_FLAG_MOD_DELETE, &el);
if (ret != LDB_SUCCESS) {
    DEBUG(0,(__location__ ": Failed to remove badPwdCount element\n"));
    ret = LDB_ERR_OTHER;
    goto done;

But when I run this code, the field is not deleted and isDeleted and
lastKnownParent are not added to the object. (If I don't use this code,
isDeleted and lastKnownParent are inserted correctly).

Is that what I was expected to do?

Another question, how can I find the element "badPwdCount"?

I've already tried to do :

element = ldb_msg_find_element(msg, "badPwdCount");

but I think I'm using the wrong ldb_message var. How can I find it? If I
have the element, can I use ldb_msg_remove_element() ?


Eduardo Lima
Sent from Campinas, SP, Brazil

On Wed, Nov 18, 2009 at 23:40, Eduardo Lima <eduardoll at gmail.com> wrote:

> Hi Tridge,
> My GIT tree was not updated.. I just did a commit with a newer (but not the
> latest) version..
> The version that is now on the git tree is the one that I was doing tests
> to remove some fields from a deleted object.
> Tomorrow I will ready more carefully your email.
> Thanks!
> --
> Eduardo Lima
> Sent from Campinas, SP, Brazil
> On Wed, Nov 18, 2009 at 23:16, <tridge at samba.org> wrote:
>> Hi Eduardo,
>>  > I created this utility function that gets the defaultNamingContext and
>> put
>>  > "CN=Deleted Objects" in front of the DN.
>> I found your git tree at git://repo.or.cz/Samba/eduardoll.git and had
>> a look at the function. It has a couple of problems:
>>  1) it suffers from the very common cut&paste problem with error
>>  messages - I think 'dsServiceName' in the error message should be
>>  'defaultNamingContext'
>>  2) it doesn't add the "Deleted Objects" rDN to the returned
>>  result. You could use ldb_dn_add_child_fmt() to add it like this:
>>   deleted_dn = ldb_dn_add_child_fmt(base_dn, "Deleted Objects");
>>  3) I don't think you actually need to do the search for
>>  defaultNamingContext. Take a look at the function
>>  samdb_partitions_dn() for what would be a closer example to what you
>>  need. That one adds "CN=Partitions" to samdb_config_dn(). If you
>>  instead add "CN=Deleted Objects" to samdb_base_dn() then I think
>>  you'll have what you want.
>>  > Will this work for every type of object? (every object in the
>>  > domain - even if it's in the deepest depth - should be moved
>>  > directly to CN=Deleted Objects,DC=w2k8... when deleted?)
>> hmm, looking at a w2k8 server, it looks like there is a separate
>> "Deleted Objects" container in the configuration partition. That means
>> my suggestion above is wrong, and you'll instead need to work out the
>> correct "Deleted Objects" location based upon the DN of the object
>> being deleted.
>> One curious thing is that there is no "Deleted Objects" container in
>> the schema partition on w2k8. I think you should investigate what
>> happens to deleted objects in the schema partition. Perhaps if a
>> partition does not have a Deleted Objects container then
>> the repl_meta_data module should not do the rename/modify change and
>> instead should just delete it? Or maybe it get moved into the Deleted
>> Objects container of the next partition up?
>> You should investigate this by creating and then deleting an object in
>> a schema partitino of a w2k8 server and see what happens to the
>> object. If you run something like this:
>>  bin/ldbsearch -H ldap://w2k8 -Uadministrator%password --controls
>> show_deleted:1,search_options:1:2 'isDeleted=TRUE' dn objectclass
>> lastKnownParent
>> then it will give you an idea of where the deleted objects are going.
>> Once you've done that, you'll need to add a function in
>> repl_meta_data.c that works out the DN of the Deleted Objects
>> container given the DN of an object being deleted. There are several
>> ways to do this. One reasonable approach would be to add a function in
>> dsdb/common/util.c like this:
>>  struct ldb_dn *dsdb_find_nc_root(struct ldb_context *samdb, struct ldb_dn
>> *dn);
>> it would work by chopping off components from the DN (using
>> ldb_dn_get_parent()) one at a time until it found a DN that has an
>> instanceType with INSTANCE_TYPE_IS_NC_HEAD set. You'll need to do a
>> base search for instanceType for each DN as you loop.
>> Then you'd add the "CN=Deleted Objects" to that, and see if it
>> exists. If it does then you can do the rename/modify. If not then just
>> pass the original delete request down to the next module.
>> You will also need to change our provision to add a "Deleted Objects"
>> container for the configuration partition. If you look at
>> setup/provision.ldif you'll see that it has adds "Deleted Objects"
>> container for the DOMAINDN, but not for the configuration
>> partition. You'll need to add it to
>> setup/provision_configuration_basedn.ldif.
>>  > This is the part that I'm having more difficulty. I still can't
>> understand
>>  > well what the modules are and the way that they work in the Samba
>> source.  I
>>  > saw that ldb_module structure has *prev and *next fields and modules
>> might
>>  > be linked together but why would all the modules be renamed if I use
>> the
>>  > ldb_rename with the top level ldb context? When I do a bin/ldbdel
>> operation,
>>  > what is the execution's flow that the modules follow?
>> This is one of the more complex aspects of Samba. I'll try and explain
>> it, and if you have any more questions then please ask.
>> Plain ldb is very simple. It knows nothing about the complexities of
>> active directory. It knows nothing about schemas, or objectclasses or
>> any of the things that go to make up a AD compatible system. It just
>> knows how to store, retrieve and modify objects in a dumb fashion.
>> The way it becomes more like AD is to have a series of modules. If you
>> do this search:
>>  bin/ldbsearch -H $PREFIX/private/sam.ldb -b @MODULES -s base
>> then you'll see the list of modules that are in your database. That
>> list currently looks like this:
>> @LIST:
>> resolve_oids,rootdse,lazy_commit,paged_results,ranged_results,anr,server_sort,asq,extended_dn_store,extended_dn_in,rdn_name,objectclass,descriptor,acl,samldb,password_hash,operational,kludge_acl,instancetype,repl_meta_data,subtree_rename,subtree_delete,linked_attributes,extended_dn_out_ldb,show_deleted,schema_load,new_partition,partition
>> as you can see, there are a lot of modules!
>> When you call an ldb operation, for example a ldb_delete() call, then
>> the ldb code will check with each of these modules in the order they
>> are listed, and if the module has a registered 'delete' function then
>> that function is called.
>> If you look at the first module in the list (the resolve_oids module)
>> and look near the bottom of resolve_oids.c you'll see that it doesn't
>> have a function for delete. That means that the resolve_oids module
>> will not affect delete operations.
>> It does however have a method for 'add'. So let's look at what that
>> does.
>> Imagine we called ldb_add() to add an object to the database. The ldb
>> code will see that the resolve_oids module has an 'add' method, so it
>> will call resolve_oids_add(). If you look inside that function you'll
>> see that it can complete in a number of ways:
>>  1) if it decides that it doesn't need to do anything, it can call
>>  ldb_next_request() passing the original request (the 'req'
>>  argument). That asks ldb to call the next module in the list that has
>>  an 'add' method.
>>  2) it can return an error. You can see for examples places where it
>>  returns LDB_ERR_OPERATIONS_ERROR when it fails to allocate some
>>  memory.
>>  3) it can construct a new request which does something different, and
>>  then call ldb_next_request() with that new request. This is what it
>>  does in this line:
>>        return ldb_next_request(module, down_req);
>>  That asks ldb to pass a newly constructed request down to the next
>>  module. Notice that it has specified a callback
>>  (resolve_oids_callback) that should be called when this new request
>>  is finished.
>> In this way, each ldb request passes through each of the modules that
>> wants to be involved with that type of request. Eventually the request
>> gets down to the last module in the chain, which is the ldb_tdb module
>> that actually implements the backend (that is not shown in the @LIST
>> above, it is implied). The ldb_tdb module, which just implements dumb
>> message storage, does the actual change to the database.
>> So, back to my original comment on using ldb_rename() with a ldb
>> context. The way you had done it will work, but it probably isn't
>> quite the right thing to do. You are calling it from within the
>> repl_meta_data module. That means you are half way through the list of
>> modules above. All of the modules above have either done what they
>> want to do to this request, or don't want to do anything.
>> By calling ldb_rename() you are starting at the top of the module list
>> again. This means every module above you will see the rename. Do you
>> want that? I think in this case you probably don't, and what you
>> really want to do is pass the rename down to the modules below you,
>> skipping the ones above.
>> One of the reasons we try to do this is to avoid looping forever. If
>> we go to the top of the stack for this rename, then that means the
>> rename will come back down to the repl_meta_data module again. So
>> we'll be calling our own module. I think in this case it will work,
>> but it can be a bit hard to follow sometimes!
>> If you look at dsdb/samdb/ldb_modules/util.c then you can see some
>> helper functions have been added to make this sort of "do an operation
>> on the rest of the modules" call a bit easier. The helper functions
>> are currently only for search, but you could add a new one for doing a
>> rename starting at the current module. Following the pattern in that
>> file, you'd add a new function:
>>  int dsdb_module_rename(struct ldb_module *module,
>>                        struct ldb_dn *olddn, struct ldb_dn *newdn);
>> it would call ldb_build_rename_req() to build a new rename request
>> structure, then it would call ldb_next_request() and then call
>> ldb_wait(), in much the same way that dsdb_module_search() works.
>> If you then use dsdb_module_rename() in your new code, then you will
>> be doing the rename only on the modules below you in the stack. You
>> should similarly add a dsdb_module_modify() call that follows the same
>> pattern.
>> The only caveat to this is if there is a module above you in the stack
>> that you actually want to see the rename. For example, the rdn_name
>> module (in lib/ldb/modules/rdn_name.c) has special handling for rename
>> operations to fix the 'name' field. If you follow my suggestion above
>> then this special handling won't happen. What you need to do is check
>> on a w2k8 server and see if the 'name' attribute is changed when you
>> delete an object.
>> If I do this:
>>  bin/ldbsearch -H ldap://w2k8 -Uadministrator%password --controls
>> show_deleted:1,search_options:1:2 'isDeleted=TRUE' dn objectclass
>> lastKnownParent name --show-binary
>> then I can see that, yes, the 'name' attribute does look like it is
>> being modified when you do a delete. That means we have two choices:
>>  1) also fix the 'name' attribute in the modify operation that you
>>  will do as part of the delete handling in repl_meta_data.c. Add it
>>  to the same modify that adds the isDeleted=TRUE attribute.
>>  2) forget what I said above and just use ldb_rename(). That means
>>  that the rdn_name modules will do the fixup of 'name' for you.
>> I think that (1) is a better choice, as I think it makes it clearer
>> exactly what a delete does in the repl_meta_data module.
>> I hope this helps!
>> Cheers, Tridge

More information about the samba-technical mailing list