root/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. encode_guid
  2. guid_always_string
  3. encode_ns_guid
  4. guid_ns_string
  5. val_copy
  6. sid_always_binary
  7. objectCategory_always_dn
  8. normalise_to_signed32
  9. usn_to_entryCSN
  10. entryCSN_to_usn_int
  11. entryCSN_to_usn
  12. usn_to_timestamp
  13. timestamp_to_usn
  14. entryuuid_init
  15. nsuniqueid_init
  16. get_seq_callback
  17. entryuuid_sequence_number
  18. entryuuid_extended

   1 /* 
   2    ldb database module
   3 
   4    LDAP semantics mapping module
   5 
   6    Copyright (C) Jelmer Vernooij 2005
   7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
   8 
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 /* 
  24    This module relies on ldb_map to do all the real work, but performs
  25    some of the trivial mappings between AD semantics and that provided
  26    by OpenLDAP and similar servers.
  27 */
  28 
  29 #include "includes.h"
  30 #include "ldb/include/ldb_module.h"
  31 #include "ldb/ldb_map/ldb_map.h"
  32 
  33 #include "librpc/gen_ndr/ndr_misc.h"
  34 #include "librpc/ndr/libndr.h"
  35 #include "dsdb/samdb/samdb.h"
  36 
  37 struct entryuuid_private {
  38         struct ldb_context *ldb;
  39         struct ldb_dn **base_dns;
  40 };
  41 
  42 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
  43 {
  44         struct GUID guid;
  45         NTSTATUS status = GUID_from_data_blob(val, &guid);
  46         enum ndr_err_code ndr_err;
  47         struct ldb_val out = data_blob(NULL, 0);
  48 
  49         if (!NT_STATUS_IS_OK(status)) {
  50                 return out;
  51         }
  52         ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
  53                                        (ndr_push_flags_fn_t)ndr_push_GUID);
  54         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  55                 return out;
  56         }
  57 
  58         return out;
  59 }
  60 
  61 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
  62 {
  63         struct ldb_val out = data_blob(NULL, 0);
  64         struct GUID guid;
  65         NTSTATUS status = GUID_from_data_blob(val, &guid);
  66         if (!NT_STATUS_IS_OK(status)) {
  67                 return out;
  68         }
  69         return data_blob_string_const(GUID_string(ctx, &guid));
  70 }
  71 
  72 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
  73 {
  74         struct GUID guid;
  75         NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
  76         enum ndr_err_code ndr_err;
  77         struct ldb_val out = data_blob(NULL, 0);
  78 
  79         if (!NT_STATUS_IS_OK(status)) {
  80                 return out;
  81         }
  82         ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
  83                                        (ndr_push_flags_fn_t)ndr_push_GUID);
  84         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  85                 return out;
  86         }
  87 
  88         return out;
  89 }
  90 
  91 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93         struct ldb_val out = data_blob(NULL, 0);
  94         struct GUID guid;
  95         NTSTATUS status = GUID_from_data_blob(val, &guid);
  96         if (!NT_STATUS_IS_OK(status)) {
  97                 return out;
  98         }
  99         return data_blob_string_const(NS_GUID_string(ctx, &guid));
 100 }
 101 
 102 /* The backend holds binary sids, so just copy them back */
 103 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105         struct ldb_val out = data_blob(NULL, 0);
 106         out = ldb_val_dup(ctx, val);
 107 
 108         return out;
 109 }
 110 
 111 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
 112 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 113 {
 114         struct ldb_context *ldb = ldb_module_get_ctx(module);
 115         struct ldb_val out = data_blob(NULL, 0);
 116         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectSid");
 117 
 118         if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
 119                 return data_blob(NULL, 0);
 120         }
 121 
 122         return out;
 123 }
 124 
 125 /* Ensure we always convert objectCategory into a DN */
 126 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 127 {
 128         struct ldb_context *ldb = ldb_module_get_ctx(module);
 129         struct ldb_dn *dn;
 130         struct ldb_val out = data_blob(NULL, 0);
 131         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectCategory");
 132 
 133         dn = ldb_dn_from_ldb_val(ctx, ldb, val);
 134         if (dn && ldb_dn_validate(dn)) {
 135                 talloc_free(dn);
 136                 return val_copy(module, ctx, val);
 137         }
 138         talloc_free(dn);
 139 
 140         if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
 141                 return data_blob(NULL, 0);
 142         }
 143 
 144         return out;
 145 }
 146 
 147 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 148 {
 149         long long int signed_ll = strtoll((const char *)val->data, NULL, 10);
 150         if (signed_ll >= 0x80000000LL) {
 151                 union {
 152                         int32_t signed_int;
 153                         uint32_t unsigned_int;
 154                 } u = {
 155                         .unsigned_int = strtoul((const char *)val->data, NULL, 10)
 156                 };
 157 
 158                 struct ldb_val out = data_blob_string_const(talloc_asprintf(ctx, "%d", u.signed_int));
 159                 return out;
 160         }
 161         return val_copy(module, ctx, val);
 162 }
 163 
 164 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 165 {
 166         struct ldb_val out;
 167         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
 168         time_t t = (usn >> 24);
 169         out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
 170         return out;
 171 }
 172 
 173 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val) 
     /* [<][>][^][v][top][bottom][index][help] */
 174 {
 175         char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
 176         char *mod_per_sec;
 177         time_t t;
 178         unsigned long long usn;
 179         char *p;
 180         if (!entryCSN) {
 181                 return 0;
 182         }
 183         p = strchr(entryCSN, '#');
 184         if (!p) {
 185                 return 0;
 186         }
 187         p[0] = '\0';
 188         p++;
 189         mod_per_sec = p;
 190 
 191         p = strchr(p, '#');
 192         if (!p) {
 193                 return 0;
 194         }
 195         p[0] = '\0';
 196         p++;
 197 
 198         usn = strtol(mod_per_sec, NULL, 16);
 199 
 200         t = ldb_string_to_time(entryCSN);
 201         
 202         usn = usn | ((unsigned long long)t <<24);
 203         return usn;
 204 }
 205 
 206 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 207 {
 208         struct ldb_val out;
 209         unsigned long long usn = entryCSN_to_usn_int(ctx, val);
 210         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
 211         return out;
 212 }
 213 
 214 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 215 {
 216         struct ldb_val out;
 217         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
 218         time_t t = (usn >> 24);
 219         out = data_blob_string_const(ldb_timestring(ctx, t));
 220         return out;
 221 }
 222 
 223 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
     /* [<][>][^][v][top][bottom][index][help] */
 224 {
 225         struct ldb_val out;
 226         time_t t;
 227         unsigned long long usn;
 228 
 229         t = ldb_string_to_time((const char *)val->data);
 230         
 231         usn = ((unsigned long long)t <<24);
 232 
 233         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
 234         return out;
 235 }
 236 
 237 
 238 static const struct ldb_map_attribute entryuuid_attributes[] = 
 239 {
 240         /* objectGUID */
 241         {
 242                 .local_name = "objectGUID",
 243                 .type = MAP_CONVERT,
 244                 .u = {
 245                         .convert = {
 246                                 .remote_name = "entryUUID", 
 247                                 .convert_local = guid_always_string,
 248                                 .convert_remote = encode_guid,
 249                         },
 250                 },
 251         },
 252         /* invocationId */
 253         {
 254                 .local_name = "invocationId",
 255                 .type = MAP_CONVERT,
 256                 .u = {
 257                         .convert = {
 258                                 .remote_name = "invocationId", 
 259                                 .convert_local = guid_always_string,
 260                                 .convert_remote = encode_guid,
 261                         },
 262                 },
 263         },
 264         /* objectSid */
 265         {
 266                 .local_name = "objectSid",
 267                 .type = MAP_CONVERT,
 268                 .u = {
 269                         .convert = {
 270                                 .remote_name = "objectSid", 
 271                                 .convert_local = sid_always_binary,
 272                                 .convert_remote = val_copy,
 273                         },
 274                 },
 275         },
 276         {
 277                 .local_name = "name",
 278                 .type = MAP_RENAME,
 279                 .u = {
 280                         .rename = {
 281                                  .remote_name = "samba4RDN"
 282                          }
 283                 }
 284         },
 285         {
 286                 .local_name = "whenCreated",
 287                 .type = MAP_RENAME,
 288                 .u = {
 289                         .rename = {
 290                                  .remote_name = "createTimestamp"
 291                          }
 292                 }
 293         },
 294         {
 295                 .local_name = "whenChanged",
 296                 .type = MAP_RENAME,
 297                 .u = {
 298                         .rename = {
 299                                  .remote_name = "modifyTimestamp"
 300                          }
 301                 }
 302         },
 303         {
 304                 .local_name = "objectClasses",
 305                 .type = MAP_RENAME,
 306                 .u = {
 307                         .rename = {
 308                                  .remote_name = "samba4ObjectClasses"
 309                          }
 310                 }
 311         },
 312         {
 313                 .local_name = "dITContentRules",
 314                 .type = MAP_RENAME,
 315                 .u = {
 316                         .rename = {
 317                                  .remote_name = "samba4DITContentRules"
 318                          }
 319                 }
 320         },
 321         {
 322                 .local_name = "attributeTypes",
 323                 .type = MAP_RENAME,
 324                 .u = {
 325                         .rename = {
 326                                  .remote_name = "samba4AttributeTypes"
 327                          }
 328                 }
 329         },
 330         {
 331                 .local_name = "objectCategory",
 332                 .type = MAP_CONVERT,
 333                 .u = {
 334                         .convert = {
 335                                 .remote_name = "objectCategory", 
 336                                 .convert_local = objectCategory_always_dn,
 337                                 .convert_remote = val_copy,
 338                         },
 339                 },
 340         },
 341         {
 342                 .local_name = "distinguishedName",
 343                 .type = MAP_RENAME,
 344                 .u = {
 345                         .rename = {
 346                                  .remote_name = "entryDN"
 347                          }
 348                 }
 349         },
 350         {
 351                 .local_name = "groupType",
 352                 .type = MAP_CONVERT,
 353                 .u = {
 354                         .convert = {
 355                                  .remote_name = "groupType",
 356                                  .convert_local = normalise_to_signed32,
 357                                  .convert_remote = val_copy,
 358                          },
 359                 }
 360         },
 361         {
 362                 .local_name = "sAMAccountType",
 363                 .type = MAP_CONVERT,
 364                 .u = {
 365                         .convert = {
 366                                  .remote_name = "sAMAccountType",
 367                                  .convert_local = normalise_to_signed32,
 368                                  .convert_remote = val_copy,
 369                          },
 370                 }
 371         },
 372         {
 373                 .local_name = "usnChanged",
 374                 .type = MAP_CONVERT,
 375                 .u = {
 376                         .convert = {
 377                                  .remote_name = "entryCSN",
 378                                  .convert_local = usn_to_entryCSN,
 379                                  .convert_remote = entryCSN_to_usn
 380                          },
 381                 },
 382         },
 383         {
 384                 .local_name = "usnCreated",
 385                 .type = MAP_CONVERT,
 386                 .u = {
 387                         .convert = {
 388                                  .remote_name = "createTimestamp",
 389                                  .convert_local = usn_to_timestamp,
 390                                  .convert_remote = timestamp_to_usn,
 391                          },
 392                 },
 393         },
 394         {
 395                 .local_name = "*",
 396                 .type = MAP_KEEP,
 397         },
 398         {
 399                 .local_name = NULL,
 400         }
 401 };
 402 
 403 /* This objectClass conflicts with builtin classes on OpenLDAP */
 404 const struct ldb_map_objectclass entryuuid_objectclasses[] =
 405 {
 406         {
 407                 .local_name = "subSchema",
 408                 .remote_name = "samba4SubSchema"
 409         },
 410         {
 411                 .local_name = NULL
 412         }
 413 };
 414 
 415 /* These things do not show up in wildcard searches in OpenLDAP, but
 416  * we need them to show up in the AD-like view */
 417 static const char * const entryuuid_wildcard_attributes[] = {
 418         "objectGUID", 
 419         "whenCreated", 
 420         "whenChanged",
 421         "usnCreated",
 422         "usnChanged",
 423         "memberOf",
 424         NULL
 425 };
 426 
 427 static const struct ldb_map_attribute nsuniqueid_attributes[] = 
 428 {
 429         /* objectGUID */
 430         {
 431                 .local_name = "objectGUID",
 432                 .type = MAP_CONVERT,
 433                 .u = {
 434                         .convert = {
 435                                 .remote_name = "nsuniqueid", 
 436                                 .convert_local = guid_ns_string,
 437                                 .convert_remote = encode_ns_guid,
 438                         },
 439                 },
 440         },
 441         /* objectSid */ 
 442         {
 443                 .local_name = "objectSid",
 444                 .type = MAP_CONVERT,
 445                 .u = {
 446                         .convert = {
 447                                 .remote_name = "objectSid", 
 448                                 .convert_local = sid_always_binary,
 449                                 .convert_remote = val_copy,
 450                         },
 451                 },
 452         },
 453         {
 454                 .local_name = "whenCreated",
 455                 .type = MAP_RENAME,
 456                 .u = {
 457                         .rename = {
 458                                  .remote_name = "createTimestamp"
 459                          }
 460                 }
 461         },
 462         {
 463                 .local_name = "whenChanged",
 464                 .type = MAP_RENAME,
 465                 .u = {
 466                         .rename = {
 467                                  .remote_name = "modifyTimestamp"
 468                          }
 469                 }
 470         },
 471         {
 472                 .local_name = "objectCategory",
 473                 .type = MAP_CONVERT,
 474                 .u = {
 475                         .convert = {
 476                                 .remote_name = "objectCategory", 
 477                                 .convert_local = objectCategory_always_dn,
 478                                 .convert_remote = val_copy,
 479                         },
 480                 },
 481         },
 482         {
 483                 .local_name = "distinguishedName",
 484                 .type = MAP_RENAME,
 485                 .u = {
 486                         .rename = {
 487                                  .remote_name = "entryDN"
 488                          }
 489                 }
 490         },
 491         {
 492                 .local_name = "groupType",
 493                 .type = MAP_CONVERT,
 494                 .u = {
 495                         .convert = {
 496                                  .remote_name = "groupType",
 497                                  .convert_local = normalise_to_signed32,
 498                                  .convert_remote = val_copy,
 499                          },
 500                 }
 501         },
 502         {
 503                 .local_name = "sAMAccountType",
 504                 .type = MAP_CONVERT,
 505                 .u = {
 506                         .convert = {
 507                                  .remote_name = "sAMAccountType",
 508                                  .convert_local = normalise_to_signed32,
 509                                  .convert_remote = val_copy,
 510                          },
 511                 }
 512         },
 513         {
 514                 .local_name = "usnChanged",
 515                 .type = MAP_CONVERT,
 516                 .u = {
 517                         .convert = {
 518                                  .remote_name = "modifyTimestamp",
 519                                  .convert_local = usn_to_timestamp,
 520                                  .convert_remote = timestamp_to_usn,
 521                          },
 522                 },
 523         },
 524         {
 525                 .local_name = "usnCreated",
 526                 .type = MAP_CONVERT,
 527                 .u = {
 528                         .convert = {
 529                                  .remote_name = "createTimestamp",
 530                                  .convert_local = usn_to_timestamp,
 531                                  .convert_remote = timestamp_to_usn,
 532                          },
 533                 },
 534         },
 535         {
 536                 .local_name = "*",
 537                 .type = MAP_KEEP,
 538         },
 539         {
 540                 .local_name = NULL,
 541         }
 542 };
 543 
 544 /* These things do not show up in wildcard searches in OpenLDAP, but
 545  * we need them to show up in the AD-like view */
 546 static const char * const nsuniqueid_wildcard_attributes[] = {
 547         "objectGUID", 
 548         "whenCreated", 
 549         "whenChanged",
 550         "usnCreated",
 551         "usnChanged",
 552         NULL
 553 };
 554 
 555 /* the context init function */
 556 static int entryuuid_init(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 557 {
 558         int ret;
 559         ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
 560         if (ret != LDB_SUCCESS)
 561                 return ret;
 562 
 563         return ldb_next_init(module);
 564 }
 565 
 566 /* the context init function */
 567 static int nsuniqueid_init(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
 568 {
 569         int ret;
 570         ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
 571         if (ret != LDB_SUCCESS)
 572                 return ret;
 573 
 574         return ldb_next_init(module);
 575 }
 576 
 577 static int get_seq_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 578                             struct ldb_reply *ares)
 579 {
 580         unsigned long long *seq = (unsigned long long *)req->context;
 581 
 582         if (!ares) {
 583                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
 584         }
 585         if (ares->error != LDB_SUCCESS) {
 586                 return ldb_request_done(req, ares->error);
 587         }
 588 
 589         if (ares->type == LDB_REPLY_ENTRY) {
 590                 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
 591                 if (el) {
 592                         *seq = entryCSN_to_usn_int(ares, &el->values[0]);
 593                 }
 594         }
 595 
 596         if (ares->type == LDB_REPLY_DONE) {
 597                 return ldb_request_done(req, LDB_SUCCESS);
 598         }
 599 
 600         talloc_free(ares);
 601         return LDB_SUCCESS;
 602 }
 603 
 604 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 605 {
 606         struct ldb_context *ldb;
 607         int ret;
 608         struct map_private *map_private;
 609         struct entryuuid_private *entryuuid_private;
 610         unsigned long long seq_num = 0;
 611         struct ldb_request *search_req;
 612 
 613         const struct ldb_control *partition_ctrl;
 614         const struct dsdb_control_current_partition *partition;
 615  
 616         static const char *contextCSN_attr[] = {
 617                 "contextCSN", NULL
 618         };
 619 
 620         struct ldb_seqnum_request *seq;
 621         struct ldb_seqnum_result *seqr;
 622         struct ldb_extended *ext;
 623 
 624         ldb = ldb_module_get_ctx(module);
 625 
 626         seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
 627 
 628         map_private = talloc_get_type(ldb_module_get_private(module), struct map_private);
 629 
 630         entryuuid_private = talloc_get_type(map_private->caller_private, struct entryuuid_private);
 631 
 632         /* All this to get the DN of the parition, so we can search the right thing */
 633         partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
 634         if (!partition_ctrl) {
 635                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
 636                               "entryuuid_sequence_number: no current partition control found");
 637                 return LDB_ERR_CONSTRAINT_VIOLATION;
 638         }
 639 
 640         partition = talloc_get_type(partition_ctrl->data,
 641                                     struct dsdb_control_current_partition);
 642         SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
 643 
 644         ret = ldb_build_search_req(&search_req, ldb, req,
 645                                    partition->dn, LDB_SCOPE_BASE,
 646                                    NULL, contextCSN_attr, NULL,
 647                                    &seq_num, get_seq_callback,
 648                                    NULL);
 649         if (ret != LDB_SUCCESS) {
 650                 return ret;
 651         }
 652 
 653         ret = ldb_next_request(module, search_req);
 654 
 655         if (ret == LDB_SUCCESS) {
 656                 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
 657         }
 658 
 659         talloc_free(search_req);
 660         if (ret != LDB_SUCCESS) {
 661                 return ret;
 662         }
 663 
 664         ext = talloc_zero(req, struct ldb_extended);
 665         if (!ext) {
 666                 return LDB_ERR_OPERATIONS_ERROR;
 667         }
 668         seqr = talloc_zero(req, struct ldb_seqnum_result);
 669         if (seqr == NULL) {
 670                 talloc_free(ext);
 671                 return LDB_ERR_OPERATIONS_ERROR;
 672         }
 673         ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
 674         ext->data = seqr;
 675 
 676         switch (seq->type) {
 677         case LDB_SEQ_HIGHEST_SEQ:
 678                 seqr->seq_num = seq_num;
 679                 break;
 680         case LDB_SEQ_NEXT:
 681                 seqr->seq_num = seq_num;
 682                 seqr->seq_num++;
 683                 break;
 684         case LDB_SEQ_HIGHEST_TIMESTAMP:
 685         {
 686                 seqr->seq_num = (seq_num >> 24);
 687                 break;
 688         }
 689         }
 690         seqr->flags = 0;
 691         seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
 692         seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
 693 
 694         /* send request done */
 695         return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
 696 }
 697 
 698 static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 699 {
 700         if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
 701                 return entryuuid_sequence_number(module, req);
 702         }
 703 
 704         return ldb_next_request(module, req);
 705 }
 706 
 707 _PUBLIC_ const struct ldb_module_ops ldb_entryuuid_module_ops = {
 708         .name              = "entryuuid",
 709         .init_context      = entryuuid_init,
 710         .extended          = entryuuid_extended,
 711         LDB_MAP_OPS
 712 };
 713 
 714 _PUBLIC_ const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
 715         .name              = "nsuniqueid",
 716         .init_context      = nsuniqueid_init,
 717         .extended          = entryuuid_extended,
 718         LDB_MAP_OPS
 719 };

/* [<][>][^][v][top][bottom][index][help] */