The branch, master has been updated
       via  7eab9e5 s4:selftest: run samba4.ldap.notification.python
       via  df04a2e s4:dsdb/tests: add notification.py with some basic tests
       via  e7dd980 s4:dsdb: let samba_dsdb make use of the dsdb_notification 
module
       via  6e88639 s4:ldap_server: add support for async notification requests
       via  46243e4 s4:dsdb: add dsdb_notification module
       via  3f0fbfa s4:dsdb/samldb: check for valid lDAPDisplayName vaues on 
add()
       via  ab16d11 s4:dsdb/tests: don't use spaces in lDAPDisplayName in 
urgent_replication.py
       via  29e3fc1 s4:ldap_server: make sure we only have one 
tstream_read_pdu_blob_send() on a connection
       via  d104d6e s4:libcli/ldap: add support for LDB_CONTROL_DIRSYNC_EX_OID
       via  fb705e1 ldb: version 1.1.26
       via  ad2b5fa ldb: add support for LDB_CONTROL_DIRSYNC_EX
       via  f721f27 ldb: add LDB_ATTR_FLAG_FORCE_BASE64_LDIF support
       via  6c8ab59 pyldb: eliminate warnings from python api test
       via  13e981d pyldb: add api tests for search_iterator()
       via  77ca078 pyldb: add ldb.search_iterator()
       via  e96fa7b pyldb: fix help message for ldb.search()
       via  2c2a254 pyldb: fix memory leak in py_ldb_search()
       via  e7bdd30 pyldb: Free correct context when pyldb_Object_AsDn() fails
       via  2b1cd4a ldb: allow a timeout of -1 result in no timeout timer at 
all.
       via  5db9f86 ldb-samba: fix the timeout setup in ildb_request_send()
       via  cd77b0bb s4:libcli/ldap: send AbandonRequests for cancelled requests
      from  a077e2a FIXUP: s3: VFS: Modify SMB_VFS_GET_NT_ACL to take a const 
struct smb_filename *

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 7eab9e5fbd40e336d0345bea63b1a2541894ac64
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Feb 1 12:27:18 2016 +0100

    s4:selftest: run samba4.ldap.notification.python
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>
    
    Autobuild-User(master): Garming Sam <[email protected]>
    Autobuild-Date(master): Wed Feb 17 06:54:48 CET 2016 on sn-devel-144

commit df04a2eee26499066985431f7d930cdf0a4a74aa
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Feb 1 10:58:41 2016 +0100

    s4:dsdb/tests: add notification.py with some basic tests
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit e7dd9808b1970b56c50510d8847af7d5a542bd5a
Author: Stefan Metzmacher <[email protected]>
Date:   Thu Jul 23 12:09:45 2015 +0200

    s4:dsdb: let samba_dsdb make use of the dsdb_notification module
    
    This means our LDAP server will support LDB_CONTROL_NOTIFICATION_OID now.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 6e88639ed99564b92da9a069ae6c42d1ebe09678
Author: Stefan Metzmacher <[email protected]>
Date:   Thu Jul 23 12:08:42 2015 +0200

    s4:ldap_server: add support for async notification requests
    
    This is a simplified version that works with the current
    dsdb_notification module that requires the caller to retry
    periodically. We do that every 5 seconds or 100 microseconds
    if we're forcing a retry.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 46243e4d80b7a1df8920d80af70c7ecca380b5a5
Author: Stefan Metzmacher <[email protected]>
Date:   Thu Jul 23 12:09:45 2015 +0200

    s4:dsdb: add dsdb_notification module
    
    This adds a simple implementation of LDB_CONTROL_NOTIFICATION_OID.
    It requires caller (the ldap server task) to retry the request peridically,
    using the same ldb_control structure in order to get some progress and
    the never ending search behaviour an LDAP client expects.
    
    For now we remember the known_usn in a cookie stored
    in the otherwise unused ldb_control->data fielf
    and we do a simple search using (uSNChanged>=${known_usn}+1).
    
    In future we may do things based on the uSNChanged value.
    
    for (i = old_highest + 1; i <= current_highest; i) {
        search for (uSNChanged=i)
    }
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 3f0fbfa7b2eac8e54ce165564cf6f33dd1821644
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Feb 1 23:04:04 2016 +0100

    s4:dsdb/samldb: check for valid lDAPDisplayName vaues on add()
    
    This still leaves modifies(), but that's a task for another day.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit ab16d11e322d3183d7f43fd0cef6f36440ce8639
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Feb 1 23:02:14 2016 +0100

    s4:dsdb/tests: don't use spaces in lDAPDisplayName in urgent_replication.py
    
    This should result in 
LDAP_UNWILLING_TO_PERFORM/WERR_DS_INVALID_LDAP_DISPLAY_NAME,
    so better use a useful value without spaces.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 29e3fc1cff557525fde2cc2d7347b540672440de
Author: Stefan Metzmacher <[email protected]>
Date:   Thu Jul 23 12:06:11 2015 +0200

    s4:ldap_server: make sure we only have one tstream_read_pdu_blob_send() on 
a connection
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit d104d6e04ff8ad8274db1a63f53a5c2b93e3e10b
Author: Stefan Metzmacher <[email protected]>
Date:   Tue Jan 26 09:37:13 2016 +0100

    s4:libcli/ldap: add support for LDB_CONTROL_DIRSYNC_EX_OID
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit fb705e19e8a8e727908c8913604c4cbffdb30c96
Author: Stefan Metzmacher <[email protected]>
Date:   Tue Feb 2 10:04:20 2016 +0100

    ldb: version 1.1.26
    
    * let a timeout of -1 indicate no timeout for a given request
    * fix memory leaks in pyldb ldb.search()
    * build fixes
    * improve pyldb ldb.search() help message
    * add pyldb ldb.search_iterator() api
    * add LDB_ATTR_FLAG_FORCE_BASE64_LDIF as optional argument
      to ldb_schema_attribute_add()
    * add client support for LDB_CONTROL_DIRSYNC_EX
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit ad2b5fae7f9b1437e6fcf73a0be3ca5d3ba0d5dc
Author: Stefan Metzmacher <[email protected]>
Date:   Tue Jan 26 09:36:56 2016 +0100

    ldb: add support for LDB_CONTROL_DIRSYNC_EX
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit f721f27da5f9ebb41639b70986ad1acb83206ed6
Author: Stefan Metzmacher <[email protected]>
Date:   Fri Feb 5 13:55:31 2016 +0100

    ldb: add LDB_ATTR_FLAG_FORCE_BASE64_LDIF support
    
    This can be used to force ldb_write_ldif() to use base64 for
    a specific attribute.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 6c8ab59d068101caa40f9b15ed70a115b5612f47
Author: Michael Adam <[email protected]>
Date:   Sun Feb 14 16:50:38 2016 +0100

    pyldb: eliminate warnings from python api test
    
    Signed-off-by: Michael Adam <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 13e981d3d822876f6f6e741606dc5a772ab2cca5
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Feb 1 02:30:56 2016 +0100

    pyldb: add api tests for search_iterator()
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 77ca07801c81558d95b95e9120511cb2e00f3d03
Author: Stefan Metzmacher <[email protected]>
Date:   Fri Jan 22 00:06:45 2016 +0100

    pyldb: add ldb.search_iterator()
    
    This is able to handle async requests, e.g. with a notification control
    and processes results as they arrive instead of waiting for all results
    before returning.
    
    search_handle = ldb.search_iterator(...)
    
    for e in search_handle:
        if not isinstance(msg, ldb.Message):
            # referral
            continue
    
        name = e["name"][0]
    
    result = search_handle.result()
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit e96fa7b10c5c6ee2cdd57c2aa553593c9372f87b
Author: Stefan Metzmacher <[email protected]>
Date:   Fri Jan 22 00:06:04 2016 +0100

    pyldb: fix help message for ldb.search()
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 2c2a2540f4076debdf2993781958b546c269aa49
Author: Stefan Metzmacher <[email protected]>
Date:   Fri Jan 22 00:05:09 2016 +0100

    pyldb: fix memory leak in py_ldb_search()
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit e7bdd30be54f3652cf060f4252f9eed3ea82078f
Author: Andrew Bartlett <[email protected]>
Date:   Tue Jan 5 17:59:32 2016 +1300

    pyldb: Free correct context when pyldb_Object_AsDn() fails
    
    Signed-off-by: Andrew Bartlett <[email protected]>
    Reviewed-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 2b1cd4a1147a8d5ba10ddcef4c2d258df2bd5dd4
Author: Stefan Metzmacher <[email protected]>
Date:   Fri Jan 22 08:53:57 2016 +0100

    ldb: allow a timeout of -1 result in no timeout timer at all.
    
    This is required in order to have long running async searches,
    e.g. with LDB_CONTROL_NOTIFICATION_OID.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit 5db9f865bca818da8d2334208f3141f7f5c7286d
Author: Stefan Metzmacher <[email protected]>
Date:   Fri Jan 22 08:53:57 2016 +0100

    ldb-samba: fix the timeout setup in ildb_request_send()
    
    We need to use the startime as reference not the current time.
    
    We also allow timeout == -1 to indicate no timeout at all.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

commit cd77b0bba434139e13db5ec2096ca99b6b3f084d
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Feb 1 11:00:14 2016 +0100

    s4:libcli/ldap: send AbandonRequests for cancelled requests
    
    This happens on a local timeout of an talloc_free() of the request.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Garming Sam <[email protected]>
    Reviewed-by: Andrew Bartlett <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 lib/ldb-samba/ldb_ildap.c                          |  12 +-
 lib/ldb/ABI/{ldb-1.1.25.sigs => ldb-1.1.26.sigs}   |   0
 ...ldb-util-1.1.10.sigs => pyldb-util-1.1.26.sigs} |   0
 ...util-1.1.10.sigs => pyldb-util.py3-1.1.26.sigs} |   0
 lib/ldb/common/ldb_controls.c                      |  65 ++++
 lib/ldb/common/ldb_ldif.c                          |  14 +-
 lib/ldb/include/ldb.h                              |   7 +
 lib/ldb/ldb_ldap/ldb_ldap.c                        |  18 +-
 lib/ldb/ldb_sqlite3/ldb_sqlite3.c                  |  11 +-
 lib/ldb/ldb_tdb/ldb_tdb.c                          |  14 +-
 lib/ldb/pyldb.c                                    | 385 ++++++++++++++++++++-
 lib/ldb/tests/python/api.py                        | 108 +++++-
 lib/ldb/tools/cmdline.c                            |  33 ++
 lib/ldb/wscript                                    |   2 +-
 source4/dsdb/samdb/ldb_modules/dsdb_notification.c | 262 ++++++++++++++
 source4/dsdb/samdb/ldb_modules/samba_dsdb.c        |   1 +
 source4/dsdb/samdb/ldb_modules/samldb.c            |  30 ++
 .../dsdb/samdb/ldb_modules/wscript_build_server    |   9 +
 source4/dsdb/tests/python/notification.py          | 352 +++++++++++++++++++
 source4/dsdb/tests/python/urgent_replication.py    |   8 +-
 source4/ldap_server/ldap_backend.c                 |  82 ++++-
 source4/ldap_server/ldap_bind.c                    |  22 +-
 source4/ldap_server/ldap_extended.c                |   8 +-
 source4/ldap_server/ldap_server.c                  | 146 +++++++-
 source4/ldap_server/ldap_server.h                  |  16 +
 source4/libcli/ldap/ldap_client.c                  |  50 +++
 source4/libcli/ldap/ldap_controls.c                |   1 +
 source4/selftest/tests.py                          |   1 +
 28 files changed, 1603 insertions(+), 54 deletions(-)
 copy lib/ldb/ABI/{ldb-1.1.25.sigs => ldb-1.1.26.sigs} (100%)
 copy lib/ldb/ABI/{pyldb-util-1.1.10.sigs => pyldb-util-1.1.26.sigs} (100%)
 copy lib/ldb/ABI/{pyldb-util-1.1.10.sigs => pyldb-util.py3-1.1.26.sigs} (100%)
 create mode 100644 source4/dsdb/samdb/ldb_modules/dsdb_notification.c
 create mode 100755 source4/dsdb/tests/python/notification.py


Changeset truncated at 500 lines:

diff --git a/lib/ldb-samba/ldb_ildap.c b/lib/ldb-samba/ldb_ildap.c
index 6ec363d..65f11db 100644
--- a/lib/ldb-samba/ldb_ildap.c
+++ b/lib/ldb-samba/ldb_ildap.c
@@ -418,11 +418,13 @@ static int ildb_request_send(struct ildb_context *ac, 
struct ldap_message *msg)
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       talloc_free(req->time_event);
-       req->time_event = NULL;
-       if (ac->req->timeout) {
-               req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac,
-                                                  
timeval_current_ofs(ac->req->timeout, 0),
+       TALLOC_FREE(req->time_event);
+       if (ac->req->timeout > 0) {
+               struct timeval tv = {
+                       .tv_sec = ac->req->starttime + ac->req->timeout,
+               };
+
+               req->time_event = tevent_add_timer(ac->ildb->event_ctx, ac, tv,
                                                   ildb_request_timeout, ac);
        }
 
diff --git a/lib/ldb/ABI/ldb-1.1.25.sigs b/lib/ldb/ABI/ldb-1.1.26.sigs
similarity index 100%
copy from lib/ldb/ABI/ldb-1.1.25.sigs
copy to lib/ldb/ABI/ldb-1.1.26.sigs
diff --git a/lib/ldb/ABI/pyldb-util-1.1.10.sigs 
b/lib/ldb/ABI/pyldb-util-1.1.26.sigs
similarity index 100%
copy from lib/ldb/ABI/pyldb-util-1.1.10.sigs
copy to lib/ldb/ABI/pyldb-util-1.1.26.sigs
diff --git a/lib/ldb/ABI/pyldb-util-1.1.10.sigs 
b/lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs
similarity index 100%
copy from lib/ldb/ABI/pyldb-util-1.1.10.sigs
copy to lib/ldb/ABI/pyldb-util.py3-1.1.26.sigs
diff --git a/lib/ldb/common/ldb_controls.c b/lib/ldb/common/ldb_controls.c
index 7346326..af056d0 100644
--- a/lib/ldb/common/ldb_controls.c
+++ b/lib/ldb/common/ldb_controls.c
@@ -367,6 +367,26 @@ char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const 
struct ldb_control *contr
                talloc_free(cookie);
                return res;
        }
+       if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_EX_OID) == 0) {
+               char *cookie;
+               struct ldb_dirsync_control *rep_control = 
talloc_get_type(control->data,
+                                                               struct 
ldb_dirsync_control);
+
+               cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
+                               rep_control->cookie_len);
+               if (cookie == NULL) {
+                       return NULL;
+               }
+               res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s",
+                                       LDB_CONTROL_DIRSYNC_EX_NAME,
+                                       control->critical,
+                                       rep_control->flags,
+                                       rep_control->max_attributes,
+                                       cookie);
+
+               talloc_free(cookie);
+               return res;
+       }
 
        if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) {
                struct ldb_verify_name_control *rep_control = 
talloc_get_type(control->data, struct ldb_verify_name_control);
@@ -525,6 +545,51 @@ struct ldb_control *ldb_parse_control_from_string(struct 
ldb_context *ldb, TALLO
 
                return ctrl;
        }
+       if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_EX_NAME) == 0) 
{
+               struct ldb_dirsync_control *control;
+               const char *p;
+               char cookie[1024];
+               int crit, max_attrs, ret;
+               uint32_t flags;
+
+               cookie[0] = '\0';
+               p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_EX_NAME)]);
+               ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, 
&max_attrs, cookie);
+
+               if ((ret < 3) || (crit < 0) || (crit > 1) || (max_attrs < 0)) {
+                       error_string = talloc_asprintf(mem_ctx, "invalid %s 
control syntax\n",
+                                                      
LDB_CONTROL_DIRSYNC_EX_NAME);
+                       error_string = talloc_asprintf_append(error_string, " 
syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
+                       error_string = talloc_asprintf_append(error_string, "   
note: b = boolean, n = number, o = b64 binary blob");
+                       ldb_set_errstring(ldb, error_string);
+                       talloc_free(error_string);
+                       talloc_free(ctrl);
+                       return NULL;
+               }
+
+               /* w2k3 seems to ignore the parameter,
+                * but w2k sends a wrong cookie when this value is to small
+                * this would cause looping forever, while getting
+                * the same data and same cookie forever
+                */
+               if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
+
+               ctrl->oid = LDB_CONTROL_DIRSYNC_EX_OID;
+               ctrl->critical = crit;
+               control = talloc(ctrl, struct ldb_dirsync_control);
+               control->flags = flags;
+               control->max_attributes = max_attrs;
+               if (*cookie) {
+                       control->cookie_len = ldb_base64_decode(cookie);
+                       control->cookie = (char *)talloc_memdup(control, 
cookie, control->cookie_len);
+               } else {
+                       control->cookie = NULL;
+                       control->cookie_len = 0;
+               }
+               ctrl->data = control;
+
+               return ctrl;
+       }
 
        if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_ASQ_NAME) == 0) {
                struct ldb_asq_control *control;
diff --git a/lib/ldb/common/ldb_ldif.c b/lib/ldb/common/ldb_ldif.c
index 07de517..0aeda94b 100644
--- a/lib/ldb/common/ldb_ldif.c
+++ b/lib/ldb/common/ldb_ldif.c
@@ -348,13 +348,21 @@ static int ldb_ldif_write_trace(struct ldb_context *ldb,
 
                for (j=0;j<msg->elements[i].num_values;j++) {
                        struct ldb_val v;
-                       bool use_b64_encode;
+                       bool use_b64_encode = false;
+
                        ret = a->syntax->ldif_write_fn(ldb, mem_ctx, 
&msg->elements[i].values[j], &v);
                        if (ret != LDB_SUCCESS) {
                                v = msg->elements[i].values[j];
                        }
-                       use_b64_encode = !(ldb->flags & LDB_FLG_SHOW_BINARY)
-                                       && ldb_should_b64_encode(ldb, &v);
+
+                       if (ldb->flags & LDB_FLG_SHOW_BINARY) {
+                               use_b64_encode = false;
+                       } else if (a->flags & LDB_ATTR_FLAG_FORCE_BASE64_LDIF) {
+                               use_b64_encode = true;
+                       } else {
+                               use_b64_encode = ldb_should_b64_encode(ldb, &v);
+                       }
+
                        if (ret != LDB_SUCCESS || use_b64_encode) {
                                ret = fprintf_fn(private_data, "%s:: ",
                                                 msg->elements[i].name);
diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
index f48f753..e715b92 100644
--- a/lib/ldb/include/ldb.h
+++ b/lib/ldb/include/ldb.h
@@ -422,6 +422,11 @@ const struct ldb_dn_extended_syntax 
*ldb_dn_extended_syntax_by_name(struct ldb_c
  */
 #define LDB_ATTR_FLAG_SINGLE_VALUE (1<<4)
 
+/*
+ * The values should always be base64 encoded
+ */
+#define LDB_ATTR_FLAG_FORCE_BASE64_LDIF        (1<<5)
+
 /**
   LDAP attribute syntax for a DN
 
@@ -652,6 +657,8 @@ typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void 
*opaque);
 */
 #define LDB_CONTROL_DIRSYNC_OID                "1.2.840.113556.1.4.841"
 #define LDB_CONTROL_DIRSYNC_NAME       "dirsync"
+#define LDB_CONTROL_DIRSYNC_EX_OID     "1.2.840.113556.1.4.2090"
+#define LDB_CONTROL_DIRSYNC_EX_NAME    "dirsync_ex"
 
 
 /**
diff --git a/lib/ldb/ldb_ldap/ldb_ldap.c b/lib/ldb/ldb_ldap/ldb_ldap.c
index 7e6ac90..29f8938 100644
--- a/lib/ldb/ldb_ldap/ldb_ldap.c
+++ b/lib/ldb/ldb_ldap/ldb_ldap.c
@@ -252,8 +252,11 @@ static int lldb_search(struct lldb_context *lldb_ac)
                break;
        }
 
-       tv.tv_sec = req->timeout;
+       tv.tv_sec = 0;
        tv.tv_usec = 0;
+       if (req->timeout > 0) {
+               tv.tv_sec = req->timeout;
+       }
 
        ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, 
                              expression, 
@@ -836,12 +839,13 @@ static int lldb_handle_request(struct ldb_module *module, 
struct ldb_request *re
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-
-       tv.tv_sec = req->starttime + req->timeout;
-       tv.tv_usec = 0;
-       te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
-       if (NULL == te) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       if (req->timeout > 0) {
+               tv.tv_sec = req->starttime + req->timeout;
+               tv.tv_usec = 0;
+               te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
+               if (NULL == te) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
        }
 
        return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c 
b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
index 223868a..60b39e8 100644
--- a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
+++ b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
@@ -1566,10 +1566,13 @@ static int lsql_handle_request(struct ldb_module 
*module, struct ldb_request *re
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       tv.tv_sec = req->starttime + req->timeout;
-       ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, ac);
-       if (NULL == ac->timeout_event) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       if (req->timeout > 0) {
+               tv.tv_sec = req->starttime + req->timeout;
+               tv.tv_usec = 0;
+               ac->timeout_event = tevent_add_timer(ev, ac, tv, lsql_timeout, 
ac);
+               if (NULL == ac->timeout_event) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
        }
 
        return LDB_SUCCESS;
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index bcb8f0f..8d1fd36 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -1469,11 +1469,15 @@ static int ltdb_handle_request(struct ldb_module 
*module,
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       tv.tv_sec = req->starttime + req->timeout;
-       ac->timeout_event = tevent_add_timer(ev, ac, tv, ltdb_timeout, ac);
-       if (NULL == ac->timeout_event) {
-               talloc_free(ac);
-               return LDB_ERR_OPERATIONS_ERROR;
+       if (req->timeout > 0) {
+               tv.tv_sec = req->starttime + req->timeout;
+               tv.tv_usec = 0;
+               ac->timeout_event = tevent_add_timer(ev, ac, tv,
+                                                    ltdb_timeout, ac);
+               if (NULL == ac->timeout_event) {
+                       talloc_free(ac);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
        }
 
        /* set a spy so that we do not try to use the request context
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index 3daed96..bea837f 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -32,6 +32,27 @@
 #include "ldb_private.h"
 #include "ldb_handlers.h"
 #include "pyldb.h"
+#include "dlinklist.h"
+
+struct py_ldb_search_iterator_reply;
+
+typedef struct {
+       PyObject_HEAD
+       TALLOC_CTX *mem_ctx;
+       PyLdbObject *ldb;
+       struct {
+               struct ldb_request *req;
+               struct py_ldb_search_iterator_reply *next;
+               struct py_ldb_search_iterator_reply *result;
+               PyObject *exception;
+       } state;
+} PyLdbSearchIteratorObject;
+
+struct py_ldb_search_iterator_reply {
+       struct py_ldb_search_iterator_reply *prev, *next;
+       PyLdbSearchIteratorObject *py_iter;
+       PyObject *obj;
+};
 
 void initldb(void);
 static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg);
@@ -39,6 +60,7 @@ static PyObject *PyExc_LdbError;
 
 static PyTypeObject PyLdbControl;
 static PyTypeObject PyLdbResult;
+static PyTypeObject PyLdbSearchIterator;
 static PyTypeObject PyLdbMessage;
 #define PyLdbMessage_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
 static PyTypeObject PyLdbModule;
@@ -1807,8 +1829,8 @@ static PyObject *py_ldb_search(PyLdbObject *self, 
PyObject *args, PyObject *kwar
        if (py_base == Py_None) {
                base = ldb_get_default_basedn(ldb_ctx);
        } else {
-               if (!pyldb_Object_AsDn(ldb_ctx, py_base, ldb_ctx, &base)) {
-                       talloc_free(attrs);
+               if (!pyldb_Object_AsDn(mem_ctx, py_base, ldb_ctx, &base)) {
+                       talloc_free(mem_ctx);
                        return NULL;
                }
        }
@@ -1869,6 +1891,200 @@ static PyObject *py_ldb_search(PyLdbObject *self, 
PyObject *args, PyObject *kwar
        return py_ret;
 }
 
+static int py_ldb_search_iterator_reply_destructor(struct 
py_ldb_search_iterator_reply *reply)
+{
+       if (reply->py_iter != NULL) {
+               DLIST_REMOVE(reply->py_iter->state.next, reply);
+               if (reply->py_iter->state.result == reply) {
+                       reply->py_iter->state.result = NULL;
+               }
+               reply->py_iter = NULL;
+       }
+
+       if (reply->obj != NULL) {
+               Py_DECREF(reply->obj);
+               reply->obj = NULL;
+       }
+
+       return 0;
+}
+
+static int py_ldb_search_iterator_callback(struct ldb_request *req,
+                                          struct ldb_reply *ares)
+{
+       PyLdbSearchIteratorObject *py_iter = (PyLdbSearchIteratorObject 
*)req->context;
+       struct ldb_result result = { .msgs = NULL };
+       struct py_ldb_search_iterator_reply *reply = NULL;
+
+       if (ares == NULL) {
+               return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       if (ares->error != LDB_SUCCESS) {
+               int ret = ares->error;
+               TALLOC_FREE(ares);
+               return ldb_request_done(req, ret);
+       }
+
+       reply = talloc_zero(py_iter->mem_ctx,
+                           struct py_ldb_search_iterator_reply);
+       if (reply == NULL) {
+               TALLOC_FREE(ares);
+               return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+       }
+       reply->py_iter = py_iter;
+       talloc_set_destructor(reply, py_ldb_search_iterator_reply_destructor);
+
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+               reply->obj = PyLdbMessage_FromMessage(ares->message);
+               if (reply->obj == NULL) {
+                       TALLOC_FREE(ares);
+                       return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+               }
+               DLIST_ADD_END(py_iter->state.next, reply);
+               TALLOC_FREE(ares);
+               return LDB_SUCCESS;
+
+       case LDB_REPLY_REFERRAL:
+               reply->obj = PyStr_FromString(ares->referral);
+               if (reply->obj == NULL) {
+                       TALLOC_FREE(ares);
+                       return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+               }
+               DLIST_ADD_END(py_iter->state.next, reply);
+               TALLOC_FREE(ares);
+               return LDB_SUCCESS;
+
+       case LDB_REPLY_DONE:
+               result = (struct ldb_result) { .controls = ares->controls };
+               reply->obj = PyLdbResult_FromResult(&result);
+               if (reply->obj == NULL) {
+                       TALLOC_FREE(ares);
+                       return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+               }
+               py_iter->state.result = reply;
+               TALLOC_FREE(ares);
+               return ldb_request_done(req, LDB_SUCCESS);
+       }
+
+       TALLOC_FREE(ares);
+       return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+}
+
+static PyObject *py_ldb_search_iterator(PyLdbObject *self, PyObject *args, 
PyObject *kwargs)
+{
+       PyObject *py_base = Py_None;
+       int scope = LDB_SCOPE_DEFAULT;
+       int timeout = 0;
+       char *expr = NULL;
+       PyObject *py_attrs = Py_None;
+       PyObject *py_controls = Py_None;
+       const char * const kwnames[] = { "base", "scope", "expression", 
"attrs", "controls", "timeout", NULL };
+       int ret;
+       const char **attrs;
+       struct ldb_context *ldb_ctx;
+       struct ldb_control **parsed_controls;
+       struct ldb_dn *base;
+       PyLdbSearchIteratorObject *py_iter;
+
+       /* type "int" rather than "enum" for "scope" is intentional */
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOOi",
+                                        discard_const_p(char *, kwnames),
+                                        &py_base, &scope, &expr, &py_attrs, 
&py_controls, &timeout))
+               return NULL;
+
+       py_iter = (PyLdbSearchIteratorObject 
*)PyLdbSearchIterator.tp_alloc(&PyLdbSearchIterator, 0);
+       if (py_iter == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
+       py_iter->ldb = self;
+       Py_INCREF(self);
+       ZERO_STRUCT(py_iter->state);
+       py_iter->mem_ctx = talloc_new(NULL);
+       if (py_iter->mem_ctx == NULL) {
+               Py_DECREF(py_iter);
+               PyErr_NoMemory();
+               return NULL;
+       }
+
+       ldb_ctx = pyldb_Ldb_AsLdbContext(self);
+
+       if (py_attrs == Py_None) {
+               attrs = NULL;
+       } else {
+               attrs = PyList_AsStrList(py_iter->mem_ctx, py_attrs, "attrs");
+               if (attrs == NULL) {
+                       Py_DECREF(py_iter);
+                       PyErr_NoMemory();
+                       return NULL;
+               }
+       }
+
+       if (py_base == Py_None) {
+               base = ldb_get_default_basedn(ldb_ctx);
+       } else {
+               if (!pyldb_Object_AsDn(py_iter->mem_ctx, py_base, ldb_ctx, 
&base)) {
+                       Py_DECREF(py_iter);
+                       PyErr_NoMemory();
+                       return NULL;
+               }
+       }
+
+       if (py_controls == Py_None) {
+               parsed_controls = NULL;
+       } else {
+               const char **controls = NULL;
+
+               controls = PyList_AsStrList(py_iter->mem_ctx,
+                                           py_controls, "controls");
+               if (controls == NULL) {
+                       Py_DECREF(py_iter);
+                       PyErr_NoMemory();
+                       return NULL;
+               }
+
+               parsed_controls = ldb_parse_control_strings(ldb_ctx,
+                                                           py_iter->mem_ctx,
+                                                           controls);
+               if (controls[0] != NULL && parsed_controls == NULL) {
+                       Py_DECREF(py_iter);
+                       PyErr_NoMemory();
+                       return NULL;
+               }
+               talloc_free(controls);
+       }
+
+       ret = ldb_build_search_req(&py_iter->state.req,
+                                  ldb_ctx,
+                                  py_iter->mem_ctx,
+                                  base,
+                                  scope,
+                                  expr,
+                                  attrs,
+                                  parsed_controls,
+                                  py_iter,
+                                  py_ldb_search_iterator_callback,
+                                  NULL);
+       if (ret != LDB_SUCCESS) {
+               Py_DECREF(py_iter);
+               PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+               return NULL;
+       }
+
+       ldb_set_timeout(ldb_ctx, py_iter->state.req, timeout);
+
+       ret = ldb_request(ldb_ctx, py_iter->state.req);
+       if (ret != LDB_SUCCESS) {
+               Py_DECREF(py_iter);
+               PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
+               return NULL;


-- 
Samba Shared Repository

Reply via email to