msDS-ReplAttributeMetaData[;binary]
authorStefan Metzmacher <metze@samba.org>
Fri, 29 Dec 2017 15:29:13 +0000 (16:29 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 29 Oct 2019 13:33:03 +0000 (14:33 +0100)
lib/ldb-samba/ldif_handlers.c
lib/ldb-samba/ldif_handlers.h
lib/util/time_basic.c
lib/util/time_basic.h
librpc/idl/drsblobs.idl
librpc/ndr/ndr_drsblobs.c
librpc/ndr/ndr_drsblobs.h
source4/dsdb/samdb/ldb_modules/operational.c

index e8759e82ab845e1f3f7aa0622d30fb4d890621b6..971856e3f9decabb1c3f07c3bb9dfb8229ae426f 100644 (file)
@@ -61,8 +61,9 @@ static void ldif_write_HEXDUMP_cb(const char *buf, void *private_data)
        state->value = v;
 }
 
-static int ldif_write_HEXDUMP(struct ldb_context *ldb, void *mem_ctx,
-                             const struct ldb_val *in, struct ldb_val *out)
+static int ldif_write_HEXDUMP_prefix(struct ldb_context *ldb, const char *prefix,
+                                    void *mem_ctx,
+                                    const struct ldb_val *in, struct ldb_val *out)
 {
        struct ldif_write_HEXDUMP_state state = {
                .error = false,
@@ -75,7 +76,8 @@ static int ldif_write_HEXDUMP(struct ldb_context *ldb, void *mem_ctx,
                return ldb_handler_copy(ldb, mem_ctx, in, out);
        }
 
-       state.value = talloc_asprintf(mem_ctx, "HEXDUMP length[%zu]\n", in->length);
+       state.value = talloc_asprintf(mem_ctx, "%sHEXDUMP length[%zu]\n",
+                                     prefix, in->length);
        if (state.value == NULL) {
                ldb_oom(ldb);
                return -1;
@@ -95,6 +97,12 @@ static int ldif_write_HEXDUMP(struct ldb_context *ldb, void *mem_ctx,
        return 0;
 }
 
+static int ldif_write_HEXDUMP(struct ldb_context *ldb, void *mem_ctx,
+                             const struct ldb_val *in, struct ldb_val *out)
+{
+       return ldif_write_HEXDUMP_prefix(ldb, "", mem_ctx, in, out);
+}
+
 /*
   use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
 
@@ -103,40 +111,163 @@ static int ldif_write_HEXDUMP(struct ldb_context *ldb, void *mem_ctx,
 
   \return 0 on success; -1 on error
 */
-static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
-                         const struct ldb_val *in, struct ldb_val *out,
-                         size_t struct_size,
-                         ndr_pull_flags_fn_t pull_fn,
-                         ndr_print_fn_t print_fn,
-                         bool mask_errors)
+static int ldif_write_NDR_v(struct ldb_context *ldb, void *mem_ctx,
+                           const struct ldb_val *in, struct ldb_val *out,
+                           size_t struct_size,
+                           ndr_pull_flags_fn_t pull_fn,
+                           ndr_push_flags_fn_t push_fn,
+                           ndr_print_fn_t print_fn,
+                           bool mask_errors)
 {
-       uint8_t *p;
+       struct ndr_pull *ndr = NULL;
+       uint32_t highest_ofs;
+       uint8_t *p = NULL;
        enum ndr_err_code err;
+       char *str = NULL;
+
        if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
                return ldb_handler_copy(ldb, mem_ctx, in, out);
        }
-       p = talloc_size(mem_ctx, struct_size);
-       err = ndr_pull_struct_blob(in, mem_ctx, 
-                                  p, pull_fn);
+
+       ndr = ndr_pull_init_blob(in, mem_ctx);
+       if (ndr == NULL) {
+               return ldb_oom(ldb);
+       }
+       p = talloc_zero_size(ndr, struct_size);
+       if (p == NULL) {
+               TALLOC_FREE(ndr);
+               return ldb_oom(ldb);
+       }
+
+       err = pull_fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
        if (err != NDR_ERR_SUCCESS) {
                /* fail in not in mask_error mode */
                if (!mask_errors) {
                        return -1;
                }
-               talloc_free(p);
-               out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>");
-               out->length = strlen((const char *)out->data);
-               return 0;
+               TALLOC_FREE(ndr);
+               return ldif_write_HEXDUMP_prefix(ldb, "<Unable to decode binary data>",
+                                                mem_ctx, in, out);
        }
-       out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
-       talloc_free(p);
-       if (out->data == NULL) {
-               return ldb_handler_copy(ldb, mem_ctx, in, out);         
+       str = ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
+       if (str == NULL) {
+               TALLOC_FREE(ndr);
+               return ldif_write_HEXDUMP_prefix(ldb, "<ndr_print_struct_string failed>",
+                                                mem_ctx, in, out);
        }
-       out->length = strlen((char *)out->data);
+
+       if (ndr->offset > ndr->relative_highest_offset) {
+               highest_ofs = ndr->offset;
+       } else {
+               highest_ofs = ndr->relative_highest_offset;
+       }
+       if (highest_ofs < ndr->data_size) {
+               int ret;
+               const char *prefix = NULL;
+
+               prefix = talloc_asprintf(ndr, "%s\n<not all bytes consumed ofs[%u] size[%u]>",
+                                        str, highest_ofs, ndr->data_size);
+               if (prefix == NULL) {
+                       TALLOC_FREE(ndr);
+                       return ldb_oom(ldb);
+               }
+               TALLOC_FREE(str);
+               ret = ldif_write_HEXDUMP_prefix(ldb, prefix, mem_ctx, in, out);
+               TALLOC_FREE(ndr);
+               return ret;
+       }
+
+       if (push_fn != NULL) {
+               const char *prefix = NULL;
+               DATA_BLOB v = data_blob_null;
+               int ret;
+               int cmp;
+
+               err = ndr_push_struct_blob(&v, ndr, p, push_fn);
+               if (err != NDR_ERR_SUCCESS) {
+                       prefix = talloc_asprintf(ndr, "%s\n<all bytes consumed ofs[%u] size[%u]>\n<ndr validate push failed>",
+                                                str, highest_ofs, ndr->data_size);
+                       TALLOC_FREE(str);
+                       if (prefix == NULL) {
+                               TALLOC_FREE(ndr);
+                               return ldb_oom(ldb);
+                       }
+                       ret = ldif_write_HEXDUMP_prefix(ldb, prefix, mem_ctx, in, out);
+                       TALLOC_FREE(ndr);
+                       return ret;
+               }
+
+               cmp = data_blob_cmp(in, &v);
+               if (cmp == 0) {
+                       prefix = talloc_asprintf(ndr, "%s\n<all bytes consumed ofs[%u] size[%u]>\n<ndr validate ok>",
+                                                str, highest_ofs, ndr->data_size);
+                       TALLOC_FREE(str);
+                       if (prefix == NULL) {
+                               TALLOC_FREE(ndr);
+                               return ldb_oom(ldb);
+                       }
+                       ret = ldif_write_HEXDUMP_prefix(ldb, prefix, mem_ctx, in, out);
+                       TALLOC_FREE(ndr);
+                       return ret;
+               }
+
+               prefix = talloc_asprintf(ndr, "%s\n<all bytes consumed ofs[%u] size[%u]>",
+                                        str, highest_ofs, ndr->data_size);
+               TALLOC_FREE(str);
+               if (prefix == NULL) {
+                       TALLOC_FREE(ndr);
+                       return ldb_oom(ldb);
+               }
+               ret = ldif_write_HEXDUMP_prefix(ldb, prefix, mem_ctx, in, out);
+               if (ret != LDB_SUCCESS) {
+                       TALLOC_FREE(ndr);
+                       return ret;
+               }
+               str = (char *)out->data;
+               *out = data_blob_null;
+               prefix = talloc_asprintf(ndr, "%s\n<ndr validate failed>",
+                                        str);
+               TALLOC_FREE(str);
+               if (prefix == NULL) {
+                       TALLOC_FREE(ndr);
+                       return ldb_oom(ldb);
+               }
+               ret = ldif_write_HEXDUMP_prefix(ldb, prefix, mem_ctx, &v, out);
+               TALLOC_FREE(ndr);
+               return ret;
+       }
+
+       if (1) {
+               int ret;
+               const char *prefix = NULL;
+
+               prefix = talloc_asprintf(ndr, "%s\n<all bytes consumed ofs[%u] size[%u]>",
+                                        str, highest_ofs, ndr->data_size);
+               TALLOC_FREE(str);
+               if (prefix == NULL) {
+                       TALLOC_FREE(ndr);
+                       return ldb_oom(ldb);
+               }
+               ret = ldif_write_HEXDUMP_prefix(ldb, prefix, mem_ctx, in, out);
+               TALLOC_FREE(ndr);
+               return ret;
+       }
+
+       TALLOC_FREE(ndr);
+       *out = data_blob_string_const(str);
        return 0;
 }
 
+static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
+                         const struct ldb_val *in, struct ldb_val *out,
+                         size_t struct_size,
+                         ndr_pull_flags_fn_t pull_fn,
+                         ndr_print_fn_t print_fn,
+                         bool mask_errors)
+{
+       return ldif_write_NDR_v(ldb, mem_ctx, in, out, struct_size, pull_fn, NULL, print_fn, mask_errors);
+}
+
 /*
   convert a ldif formatted objectSid to a NDR formatted blob
 */
@@ -1024,6 +1155,75 @@ static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ct
                              true);
 }
 
+static bool is_xml_value(const struct ldb_val *in)
+{
+       if (in->length < 4) {
+               return false;
+       }
+
+       if (in->data[0] != '<') {
+               return false;
+       }
+
+       if (in->data[in->length - 3] != '>') {
+               return false;
+       }
+
+       if (in->data[in->length - 2] != '\n') {
+               return false;
+       }
+
+       if (in->data[in->length - 1] != '\0') {
+               return false;
+       }
+
+       return true;
+}
+
+/*
+  convert a NDR formatted blob to a ldif formatted
+  "msDs-replAttributeMetaData" => XML
+  "msDs-replAttributeMetaData;binary" => msDS_ReplAttributeMetaDataBlob
+*/
+static int ldif_write_msDS_ReplAttributeMetaData(struct ldb_context *ldb,
+                               void *mem_ctx,
+                               const struct ldb_val *in,
+                               struct ldb_val *out)
+{
+       if (is_xml_value(in)) {
+               return ldb_handler_copy(ldb, mem_ctx, in, out);
+       }
+
+       return ldif_write_NDR_v(ldb, mem_ctx, in, out,
+                               sizeof(struct msDS_ReplAttributeMetaDataBlob),
+                               (ndr_pull_flags_fn_t)ndr_pull_msDS_ReplAttributeMetaDataBlob,
+                               (ndr_push_flags_fn_t)ndr_push_msDS_ReplAttributeMetaDataBlob,
+                               (ndr_print_fn_t)ndr_print_msDS_ReplAttributeMetaDataBlob,
+                               true);
+}
+
+/*
+  convert a NDR formatted blob to a ldif formatted
+  "msDs-replValueMetaData" or
+  "msDs-replValueMetaData;binary"
+*/
+static int ldif_write_msDS_ReplValueMetaData(struct ldb_context *ldb,
+                               void *mem_ctx,
+                               const struct ldb_val *in,
+                               struct ldb_val *out)
+{
+       if (is_xml_value(in)) {
+               return ldb_handler_copy(ldb, mem_ctx, in, out);
+       }
+
+       return ldif_write_NDR_v(ldb, mem_ctx, in, out,
+                               sizeof(struct msDS_ReplValueMetaDataBlob),
+                               (ndr_pull_flags_fn_t)ndr_pull_msDS_ReplValueMetaDataBlob,
+                               (ndr_push_flags_fn_t)ndr_push_msDS_ReplValueMetaDataBlob,
+                               (ndr_print_fn_t)ndr_print_msDS_ReplValueMetaDataBlob,
+                               true);
+}
+
 /*
   convert a NDR formatted blob to a ldif formatted replUpToDateVector
 */
@@ -1565,6 +1765,20 @@ static const struct ldb_schema_syntax samba_syntaxes[] = {
                .canonicalise_fn  = ldb_handler_copy,
                .comparison_fn    = samba_ldb_comparison_binary,
                .operator_fn      = samba_syntax_binary_operator_fn
+       },{
+               .name             = LDB_SYNTAX_SAMBA_REPLATTRIBUTEMETADATA,
+               .ldif_read_fn     = ldb_handler_copy,
+               .ldif_write_fn    = ldif_write_msDS_ReplAttributeMetaData,
+               .canonicalise_fn  = ldb_handler_copy,
+               .comparison_fn    = samba_ldb_comparison_binary,
+               .operator_fn      = samba_syntax_binary_operator_fn
+       },{
+               .name             = LDB_SYNTAX_SAMBA_REPLVALUEMETADATA,
+               .ldif_read_fn     = ldb_handler_copy,
+               .ldif_write_fn    = ldif_write_msDS_ReplValueMetaData,
+               .canonicalise_fn  = ldb_handler_copy,
+               .comparison_fn    = samba_ldb_comparison_binary,
+               .operator_fn      = samba_syntax_binary_operator_fn
        },{
                .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
                .ldif_read_fn     = ldb_handler_copy,
@@ -1726,6 +1940,10 @@ static const struct {
        { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
        { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
        { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
+       { "msDS-replAttributeMetaData", LDB_SYNTAX_SAMBA_REPLATTRIBUTEMETADATA },
+       { "msDS-replAttributeMetaData;binary", LDB_SYNTAX_SAMBA_REPLATTRIBUTEMETADATA },
+       { "msDS-replValueMetaData",     LDB_SYNTAX_SAMBA_REPLVALUEMETADATA },
+       { "msDS-replValueMetaData;binary",     LDB_SYNTAX_SAMBA_REPLVALUEMETADATA },
        { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
        { "msDS-RevealedUsers",         LDB_SYNTAX_SAMBA_REVEALEDUSERS },
        { "trustAuthIncoming",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
index 8b2ade662a76570e9f511637d0855eac00e81350..faf44f163735b91492b3d72e92be9b1d8b3091dc 100644 (file)
@@ -10,6 +10,8 @@
 #define LDB_SYNTAX_SAMBA_INT32                 "LDB_SYNTAX_SAMBA_INT32"
 #define LDB_SYNTAX_SAMBA_REPSFROMTO            "LDB_SYNTAX_SAMBA_REPSFROMTO"
 #define LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA   "LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA"
+#define LDB_SYNTAX_SAMBA_REPLATTRIBUTEMETADATA  "LDB_SYNTAX_SAMBA_REPLATTRIBUTEMETADATA"
+#define LDB_SYNTAX_SAMBA_REPLVALUEMETADATA      "LDB_SYNTAX_SAMBA_REPLVALUEMETADATA"
 #define LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR     "LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR"
 #define LDB_SYNTAX_SAMBA_REVEALEDUSERS          "LDB_SYNTAX_SAMBA_REVEALEDUSERS"
 #define LDB_SYNTAX_SAMBA_RANGE64               "LDB_SYNTAX_SAMBA_RANGE64"
index 095236bf78ad6f4e5abde1439d2e526881c13032..42d1007153190e75b5776c0804581359f57b1fd1 100644 (file)
@@ -41,15 +41,20 @@ _PUBLIC_ void GetTimeOfDay(struct timeval *tval)
  Return the date and time as a string
 ****************************************************************************/
 
-char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
-                     struct timeval_buf *dst)
+static char *timeval_str_buf_internal(const struct timeval *tp,
+                                     bool utc, bool rfc5424, bool hires,
+                                     struct timeval_buf *dst)
 {
        time_t t;
        struct tm *tm;
        size_t len;
 
        t = (time_t)tp->tv_sec;
-       tm = localtime(&t);
+       if (utc) {
+               tm = gmtime(&t);
+       } else {
+               tm = localtime(&t);
+       }
 
        if (tm == NULL) {
                if (hires) {
@@ -70,12 +75,14 @@ char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
                       1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
                       tm->tm_hour, tm->tm_min, tm->tm_sec);
 
-       if ((rfc5424 || hires) && (len < sizeof(dst->buf))) {
+       if (hires && (len < sizeof(dst->buf))) {
                len += snprintf(dst->buf + len, sizeof(dst->buf) - len,
                                ".%06ld", (long)tp->tv_usec);
        }
 
-       if (rfc5424 && (len < sizeof(dst->buf))) {
+       if (utc && rfc5424 && (len < sizeof(dst->buf))) {
+               snprintf(dst->buf + len, sizeof(dst->buf) - len, "Z");
+       } else if (rfc5424 && (len < sizeof(dst->buf))) {
                struct tm tm_utc, tm_local;
                int offset;
 
@@ -97,3 +104,18 @@ char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
 
        return dst->buf;
 }
+
+char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
+                     struct timeval_buf *dst)
+{
+       const bool utc = false;
+       return timeval_str_buf_internal(tp, utc, rfc5424, hires, dst);
+}
+
+char *timeval_str_utc_buf(const struct timeval *tp, bool hires,
+                         struct timeval_buf *dst)
+{
+       const bool utc = true;
+       const bool rfc5424 = true;
+       return timeval_str_buf_internal(tp, utc, rfc5424, hires, dst);
+}
index e04cf1c79c5fbbde134632fb6d00e2f575c1f505..13f3eeb62ce26b470619d677a4afb158611d141f 100644 (file)
@@ -41,9 +41,26 @@ struct timeval_buf { char buf[128]; };
  is a stricter instance of RFC3339 and is used for syslog). For
  example: 2003-08-24T05:14:15.000003-07:00.  Otherwise,
  format is %Y/%m/%d %H:%M:%S
+
+ This is based on the local time.
 **/
 
 char *timeval_str_buf(const struct timeval *tp, bool rfc5424, bool hires,
                      struct timeval_buf *dst);
 
+/**
+ Put a date and time into dst->buf, return it dst->buf
+ (optionally with microseconds)
+
+ If rfc5424 is true then produce the RFC5424 timestamp format (which
+ is a stricter instance of RFC3339 and is used for syslog). For
+ example: 2003-08-24T05:14:15.000003Z.
+ or: 2003-08-24T05:14:15Z (with hires = false).
+
+ The value is based on UTC.
+**/
+
+char *timeval_str_utc_buf(const struct timeval *tp, bool hires,
+                         struct timeval_buf *dst);
+
 #endif /* _SAMBA_TIME_BASIC_H_ */
index 072546a43694d6ae2b28e0a2be1a619b43f03bc5..7bd1dd0c1694e869c22942d593e67dade351a93e 100644 (file)
@@ -46,6 +46,45 @@ interface drsblobs {
                [switch_is(version)] replPropertyMetaDataCtr ctr;
        } replPropertyMetaDataBlob;
 
+       typedef [public,gensize] struct {
+               [relative] nstring *attribute_name;
+               uint32 version;
+               NTTIME originating_change_time;
+               GUID originating_invocation_id;
+               hyper originating_usn;
+               hyper local_usn;
+               [relative] nstring *originating_dsa_dn;
+               [flag(NDR_ALIGN8)] DATA_BLOB __padding;
+       } msDS_ReplAttributeMetaData;
+
+       typedef [public] struct {
+               [subcontext(0)]
+               [subcontext_size(_ndr_size_msDS_ReplAttributeMetaData(ndr, &stamp))]
+               msDS_ReplAttributeMetaData stamp;
+       } msDS_ReplAttributeMetaDataBlob;
+
+       typedef [public,gensize] struct {
+               [relative] nstring *attribute_name;
+               [relative] nstring *object_dn;
+               [value(ndr_size_DATA_BLOB(0,binary,0))] uint32 __ndr_size_binary;
+               [relative,subcontext(0),subcontext_size(__ndr_size_binary),flag(NDR_REMAINING)] DATA_BLOB *binary;
+               NTTIME deleted;
+               NTTIME created;
+               uint32 version;
+               NTTIME originating_change_time;
+               GUID originating_invocation_id;
+               hyper originating_usn;
+               hyper local_usn;
+               [relative] nstring *originating_dsa_dn;
+               [flag(NDR_ALIGN8)] DATA_BLOB __padding;
+       } msDS_ReplValueMetaData;
+
+       typedef [public] struct {
+               [subcontext(0)]
+               [subcontext_size(_ndr_size_msDS_ReplValueMetaData(ndr, &stamp))]
+               msDS_ReplValueMetaData stamp;
+       } msDS_ReplValueMetaDataBlob;
+
        /*
         * replUpToDateVector
         * w2k  uses version 1
index b0d3f50b4a41f68f745fe936e8c4e7585b65791f..b4a21d5399513bfeb9d761e5254909432682e34e 100644 (file)
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "../lib/util/asn1.h"
 
+_PUBLIC_ size_t _ndr_size_msDS_ReplAttributeMetaData(const void *ndr, const struct msDS_ReplAttributeMetaData *r)
+{
+       struct ndr_push *push = talloc_get_type(ndr, struct ndr_push);
+       struct ndr_pull *pull = talloc_get_type(ndr, struct ndr_pull);
+       size_t s = 0;
+
+       if (push != NULL) {
+               s = ndr_size_msDS_ReplAttributeMetaData(r, 0);
+       }
+
+       if (pull != NULL) {
+               s = pull->data_size;
+       }
+
+       return NDR_ROUND(s, 4);
+}
+
+_PUBLIC_ size_t _ndr_size_msDS_ReplValueMetaData(const void *ndr, const struct msDS_ReplValueMetaData *r)
+{
+       struct ndr_push *push = talloc_get_type(ndr, struct ndr_push);
+       struct ndr_pull *pull = talloc_get_type(ndr, struct ndr_pull);
+       size_t s = 0;
+
+       if (push != NULL) {
+               s = ndr_size_msDS_ReplValueMetaData(r, 0);
+       }
+
+       if (pull != NULL) {
+               s = pull->data_size;
+       }
+
+       return NDR_ROUND(s, 4);
+}
+
 _PUBLIC_ enum ndr_err_code ndr_push_AuthenticationInformationArray(struct ndr_push *ndr, int ndr_flags, const struct AuthenticationInformationArray *r)
 {
        uint32_t cntr_array_0;
index eb7993c3142c477d69421054149adc2c31b25118..866b4bee963133f429ac54538cec01f2cd14744d 100644 (file)
@@ -19,5 +19,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+_PUBLIC_ size_t _ndr_size_msDS_ReplAttributeMetaData(const void *ndr, const struct msDS_ReplAttributeMetaData *r);
+_PUBLIC_ size_t _ndr_size_msDS_ReplValueMetaData(const void *ndr, const struct msDS_ReplValueMetaData *r);
 _PUBLIC_ enum ndr_err_code ndr_pull_trustDomainPasswords(struct ndr_pull *ndr, int ndr_flags, struct trustDomainPasswords *r);
 _PUBLIC_ void ndr_print_drsuapi_MSPrefixMap_Entry(struct ndr_print *ndr, const char *name, const struct drsuapi_MSPrefixMap_Entry *r);
index 5eaebf981417547d8a86c839698f6a442ea80d27..9f2d09cee0f409febee911b5795712c9b1a9daaa 100644 (file)
 #include <ldb.h>
 #include <ldb_module.h>
 
+#include <tdb.h>
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_drsblobs.h"
 #include "param/param.h"
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/samdb/ldb_modules/util.h"
 
+#include "lib/util/time_basic.h"
+#include "libcli/ldap/ldap_ndr.h"
+
 #include "libcli/security/security.h"
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
 #endif
 
+struct operational_context {
+       struct ldb_module *module;
+       struct ldb_request *req;
+       enum ldb_scope scope;
+       const char * const *attrs;
+       struct op_controls_flags* controls_flags;
+       struct op_attributes_operations *list_operations;
+       unsigned int list_operations_size;
+       struct op_attributes_replace *attrs_to_replace;
+       unsigned int attrs_to_replace_size;
+       const struct dsdb_schema *schema;
+       struct db_context *dsa_cache;
+       struct ldb_dn *sites_dn;
+};
+
 struct operational_data {
        struct ldb_dn *aggregate_dn;
 };
@@ -1302,6 +1324,262 @@ static int construct_resultant_pso(struct ldb_module *module,
        return LDB_SUCCESS;
 }
 
+struct operational_dsa_by_invocation_id_state {
+       struct ldb_dn *dn;
+};
+
+static void operational_dsa_by_invocation_id_parser(TDB_DATA key, TDB_DATA data, void *private_data)
+{
+       struct operational_dsa_by_invocation_id_state *state =
+               (struct operational_dsa_by_invocation_id_state *)private_data;
+       void *ptr = NULL;
+
+       state->dn = NULL;
+
+       if (data.dsize == 0) {
+               return;
+       }
+
+       if (data.dsize != sizeof(ptr)) {
+               smb_panic(__location__);
+       }
+
+       memcpy(&ptr, data.dptr, sizeof(ptr));
+       state->dn = talloc_get_type_abort(ptr, struct ldb_dn);
+}
+
+static const char *operational_dsa_by_invocation_id(struct operational_context *ac,
+                                                   const struct GUID *invocation_id)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+       struct operational_dsa_by_invocation_id_state state = {
+               .dn = NULL,
+       };
+       TDB_DATA key = {
+               .dptr = discard_const_p(uint8_t, invocation_id),
+               .dsize = sizeof(*invocation_id),
+       };
+       void *ptr = NULL;
+       TDB_DATA value = {
+               .dptr = (uint8_t *)&ptr,
+               .dsize = sizeof(ptr),
+       };
+       char *encoded_id = NULL;
+       struct ldb_message *msg = NULL;
+       NTSTATUS status;
+       int ret;
+
+       if (ac->dsa_cache == NULL) {
+               ac->dsa_cache = db_open_rbt(ac);
+               if (ac->dsa_cache == NULL) {
+                       return NULL;
+               }
+       }
+
+       if (ac->sites_dn == NULL) {
+               ac->sites_dn = samdb_sites_dn(ldb, ac);
+               if (ac->sites_dn == NULL) {
+                       return NULL;
+               }
+       }
+
+       status = dbwrap_parse_record(ac->dsa_cache, key,
+                                    operational_dsa_by_invocation_id_parser,
+                                    &state);
+       if (NT_STATUS_IS_OK(status) && state.dn != NULL) {
+               return ldb_dn_get_linearized(state.dn);
+       }
+
+       encoded_id = ldap_encode_ndr_GUID(ac->dsa_cache, invocation_id);
+       if (encoded_id == NULL) {
+               return NULL;
+       }
+
+       // TODO DSDB_SEARCH_SHOW_RECYCLED ok???
+       ret = dsdb_search_one(ldb, ac->dsa_cache, &msg, ac->sites_dn,
+                             LDB_SCOPE_SUBTREE, NULL,
+                             DSDB_FLAG_AS_SYSTEM |
+                             DSDB_SEARCH_SHOW_RECYCLED,
+                             "(invocationId=%s)",
+                             encoded_id);
+       TALLOC_FREE(encoded_id);
+       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+               return "<unknown-todo>";
+       }
+       if (ret != LDB_SUCCESS) {
+               return NULL;
+       }
+
+       state.dn = talloc_move(ac->dsa_cache, &msg->dn);
+       TALLOC_FREE(msg);
+       ptr = state.dn;
+
+       status = dbwrap_store(ac->dsa_cache, key, value, TDB_INSERT);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(state.dn);
+               return NULL;
+       }
+
+       return ldb_dn_get_linearized(state.dn);
+}
+
+static int construct_msDS_ReplAttributeMetaData(struct ldb_module *module,
+                                               struct ldb_message *msg,
+                                               enum ldb_scope scope,
+                                               struct ldb_request *parent,
+                                               bool xml)
+{
+       struct operational_context *ac =
+               talloc_get_type_abort(parent->context,
+               struct operational_context);
+       struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+       uint32_t i;
+       enum ndr_err_code ndr_err;
+       const struct ldb_val *omd_value = NULL;
+       struct replPropertyMetaDataBlob *omd = NULL;
+       int ret;
+
+       if (ac->schema == NULL) {
+               ac->schema = dsdb_get_schema(ldb, ac);
+               if (ac->schema == NULL) {
+                       /* We can't make up anything without a schema */
+                       return LDB_SUCCESS;
+               }
+       }
+
+       omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
+       if (!omd_value) {
+               /* We can't make up anything without meta data */
+               return LDB_SUCCESS;
+       }
+
+       omd = talloc_zero(msg, struct replPropertyMetaDataBlob);
+       if (omd == NULL) {
+               return ldb_module_oom(module);
+       }
+
+       ndr_err = ndr_pull_struct_blob(omd_value, omd, omd,
+                                      (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s when trying to add msDS-KeyVersionNumber\n",
+                        ldb_dn_get_linearized(msg->dn)));
+               return ldb_operr(ldb_module_get_ctx(module));
+       }
+
+       if (omd->version != 1) {
+               DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s when trying to add msDS-KeyVersionNumber\n",
+                        omd->version, ldb_dn_get_linearized(msg->dn)));
+               talloc_free(omd);
+               return LDB_SUCCESS;
+       }
+
+       for (i=0; i<omd->ctr.ctr1.count; i++) {
+               struct msDS_ReplAttributeMetaDataBlob _r;
+               struct msDS_ReplAttributeMetaData *r = &_r.stamp;
+               const struct replPropertyMetaData1 *m =  &omd->ctr.ctr1.array[i];
+               const struct dsdb_attribute *a = NULL;
+               const char *dsa_dn = NULL;
+               const char *attr_name = NULL;
+               struct ldb_val val = data_blob_null;
+
+               a = dsdb_attribute_by_attributeID_id(ac->schema, m->attid);
+               if (a == NULL) {
+                       return ldb_module_operr(module);
+               }
+
+               dsa_dn = operational_dsa_by_invocation_id(ac,
+                                               &m->originating_invocation_id);
+               if (dsa_dn == NULL) {
+                       return ldb_module_operr(module);
+               }
+
+               r->attribute_name = a->lDAPDisplayName;
+               r->version = m->version;
+               r->originating_change_time = m->originating_change_time;
+               r->originating_invocation_id = m->originating_invocation_id;
+               r->originating_usn = m->originating_usn;
+               r->local_usn = m->local_usn;
+               r->originating_dsa_dn = dsa_dn;
+
+               if (xml) {
+                       struct timeval_buf tv_buf;
+                       struct timeval change_tv;
+                       struct GUID_txt_buf iv_buf;
+                       char *str = NULL;
+
+                       nttime_to_timeval(&change_tv,
+                                         r->originating_change_time);
+
+                       str = talloc_asprintf(msg,
+                               "<DS_REPL_ATTR_META_DATA>\n"
+                               "\t<pszAttributeName>%s"
+                               "</pszAttributeName>\n"
+                               "\t<dwVersion>%u</dwVersion>\n"
+                               "\t<ftimeLastOriginatingChange>%s"
+                               "</ftimeLastOriginatingChange>\n"
+                               "\t<uuidLastOriginatingDsaInvocationID>%s"
+                               "</uuidLastOriginatingDsaInvocationID>\n"
+                               "\t<usnOriginatingChange>%llu"
+                               "</usnOriginatingChange>\n"
+                               "\t<usnLocalChange>%llu</usnLocalChange>\n"
+                               "\t<pszLastOriginatingDsaDN>%s"
+                               "</pszLastOriginatingDsaDN>\n"
+                               "</DS_REPL_ATTR_META_DATA>\n",
+                               r->attribute_name,
+                               (unsigned)r->version,
+                               timeval_str_utc_buf(&change_tv, false, &tv_buf),
+                               GUID_buf_string(&r->originating_invocation_id,
+                                               &iv_buf),
+                               (unsigned long long)r->originating_usn,
+                               (unsigned long long)r->local_usn,
+                               dsa_dn);
+                       if (str == NULL) {
+                               return ldb_module_oom(module);
+                       }
+
+                       attr_name = "msDS-ReplAttributeMetaData";
+                       val.data = (uint8_t *)str;
+                       val.length = strlen(str) + 1;
+               } else {
+
+                       attr_name = "msDS-ReplAttributeMetaData;binary";
+                       ndr_err = ndr_push_struct_blob(&val, msg, &_r,
+                               (ndr_push_flags_fn_t)ndr_push_msDS_ReplAttributeMetaDataBlob);
+                       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                               DEBUG(0,(__location__ ": Failed to marshall msDS_ReplAttributeMetaDataBlob for %s\n",
+                                        ldb_dn_get_linearized(msg->dn)));
+                               return ldb_module_operr(module);
+                       }
+               }
+
+               ret = ldb_msg_add_steal_value(msg, attr_name, &val);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       talloc_free(omd);
+       return LDB_SUCCESS;
+}
+
+static int construct_msDS_ReplAttributeMetaData_xml(struct ldb_module *module,
+                                                   struct ldb_message *msg,
+                                                   enum ldb_scope scope,
+                                                   struct ldb_request *parent)
+{
+       return construct_msDS_ReplAttributeMetaData(module, msg, scope,
+                                                   parent, true);
+}
+
+static int construct_msDS_ReplAttributeMetaData_blob(struct ldb_module *module,
+                                                    struct ldb_message *msg,
+                                                    enum ldb_scope scope,
+                                                    struct ldb_request *parent)
+{
+       return construct_msDS_ReplAttributeMetaData(module, msg, scope,
+                                                   parent, false);
+}
+
 struct op_controls_flags {
        bool sd;
        bool bypassoperational;
@@ -1408,7 +1686,11 @@ static const struct op_attributes_replace search_sub[] = {
        { "msDS-UserPasswordExpiryTimeComputed", "userAccountControl", user_password_expiry_time_computed_attrs,
          construct_msds_user_password_expiry_time_computed },
        { "msDS-ResultantPSO", "objectClass", resultant_pso_computed_attrs,
-         construct_resultant_pso }
+         construct_resultant_pso },
+       { "msDS-ReplAttributeMetaData", "replPropertyMetaData", NULL,
+         construct_msDS_ReplAttributeMetaData_xml },
+       { "msDS-ReplAttributeMetaData;binary", "replPropertyMetaData", NULL,
+         construct_msDS_ReplAttributeMetaData_blob },
 };
 
 
@@ -1525,18 +1807,6 @@ failed:
   hook search operations
 */
 
-struct operational_context {
-       struct ldb_module *module;
-       struct ldb_request *req;
-       enum ldb_scope scope;
-       const char * const *attrs;
-       struct op_controls_flags* controls_flags;
-       struct op_attributes_operations *list_operations;
-       unsigned int list_operations_size;
-       struct op_attributes_replace *attrs_to_replace;
-       unsigned int attrs_to_replace_size;
-};
-
 static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct operational_context *ac;
@@ -1671,7 +1941,7 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
 
        ldb = ldb_module_get_ctx(module);
 
-       ac = talloc(req, struct operational_context);
+       ac = talloc_zero(req, struct operational_context);
        if (ac == NULL) {
                return ldb_oom(ldb);
        }
@@ -1701,6 +1971,7 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
 
        ac->attrs_to_replace = NULL;
        ac->attrs_to_replace_size = 0;
+
        /* in the list of attributes we are looking for, rename any
           attributes to the alias for any hidden attributes that can
           be fetched directly using non-hidden names.