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

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

DEFINITIONS

This source file includes following definitions.
  1. samldb_ctx_init
  2. samldb_add_step
  3. samldb_first_step
  4. samldb_next_step
  5. samldb_search_template_callback
  6. samldb_search_template
  7. samldb_apply_template
  8. samldb_get_parent_domain_callback
  9. samldb_get_parent_domain
  10. samldb_generate_samAccountName
  11. samldb_check_samAccountName_callback
  12. samldb_check_samAccountName
  13. samldb_check_samAccountType
  14. samldb_get_sid_domain_callback
  15. samldb_get_sid_domain
  16. samldb_msg_add_sid
  17. samldb_new_sid
  18. samldb_check_sid_callback
  19. samldb_check_sid
  20. samldb_notice_sid_callback
  21. samldb_notice_sid
  22. samldb_add_entry_callback
  23. samldb_add_entry
  24. samldb_fill_object
  25. samldb_foreign_notice_sid_callback
  26. samldb_foreign_notice_sid
  27. samldb_fill_foreignSecurityPrincipal_object
  28. samldb_check_rdn
  29. samldb_add
  30. samldb_modify
  31. samldb_init

   1 /*
   2    SAM ldb module
   3 
   4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
   5    Copyright (C) Simo Sorce  2004-2008
   6 
   7    * NOTICE: this module is NOT released under the GNU LGPL license as
   8    * other ldb code. This module is release under the GNU GPL v3 or
   9    * later license.
  10 
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15 
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 /*
  26  *  Name: ldb
  27  *
  28  *  Component: ldb samldb module
  29  *
  30  *  Description: add embedded user/group creation functionality
  31  *
  32  *  Author: Simo Sorce
  33  */
  34 
  35 #include "includes.h"
  36 #include "libcli/ldap/ldap_ndr.h"
  37 #include "ldb_module.h"
  38 #include "dsdb/samdb/samdb.h"
  39 #include "libcli/security/security.h"
  40 #include "librpc/gen_ndr/ndr_security.h"
  41 #include "../lib/util/util_ldb.h"
  42 #include "ldb_wrap.h"
  43 
  44 struct samldb_ctx;
  45 
  46 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
  47 
  48 struct samldb_step {
  49         struct samldb_step *next;
  50         samldb_step_fn_t fn;
  51 };
  52 
  53 struct samldb_ctx {
  54         struct ldb_module *module;
  55         struct ldb_request *req;
  56 
  57         /* the resulting message */
  58         struct ldb_message *msg;
  59 
  60         /* used to apply templates */
  61         const char *type;
  62 
  63         /* used to find parent domain */
  64         struct ldb_dn *check_dn;
  65         struct ldb_dn *domain_dn;
  66         struct dom_sid *domain_sid;
  67         uint32_t next_rid;
  68 
  69         /* generic storage, remember to zero it before use */
  70         struct ldb_reply *ares;
  71 
  72         /* holds the entry SID */
  73         struct dom_sid *sid;
  74 
  75         /* all the async steps necessary to complete the operation */
  76         struct samldb_step *steps;
  77         struct samldb_step *curstep;
  78 };
  79 
  80 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
  81                                           struct ldb_request *req)
  82 {
  83         struct ldb_context *ldb;
  84         struct samldb_ctx *ac;
  85 
  86         ldb = ldb_module_get_ctx(module);
  87 
  88         ac = talloc_zero(req, struct samldb_ctx);
  89         if (ac == NULL) {
  90                 ldb_oom(ldb);
  91                 return NULL;
  92         }
  93 
  94         ac->module = module;
  95         ac->req = req;
  96 
  97         return ac;
  98 }
  99 
 100 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
     /* [<][>][^][v][top][bottom][index][help] */
 101 {
 102         struct samldb_step *step;
 103 
 104         step = talloc_zero(ac, struct samldb_step);
 105         if (step == NULL) {
 106                 return LDB_ERR_OPERATIONS_ERROR;
 107         }
 108 
 109         if (ac->steps == NULL) {
 110                 ac->steps = step;
 111                 ac->curstep = step;
 112         } else {
 113                 ac->curstep->next = step;
 114                 ac->curstep = step;
 115         }
 116 
 117         step->fn = fn;
 118 
 119         return LDB_SUCCESS;
 120 }
 121 
 122 static int samldb_first_step(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 123 {
 124         if (ac->steps == NULL) {
 125                 return LDB_ERR_OPERATIONS_ERROR;
 126         }
 127 
 128         ac->curstep = ac->steps;
 129         return ac->curstep->fn(ac);
 130 }
 131 
 132 static int samldb_next_step(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 133 {
 134         if (ac->curstep->next) {
 135                 ac->curstep = ac->curstep->next;
 136                 return ac->curstep->fn(ac);
 137         }
 138 
 139         /* it is an error if the last step does not properly
 140          * return to the upper module by itself */
 141         return LDB_ERR_OPERATIONS_ERROR;
 142 }
 143 
 144 static int samldb_search_template_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 145                                            struct ldb_reply *ares)
 146 {
 147         struct ldb_context *ldb;
 148         struct samldb_ctx *ac;
 149         int ret;
 150 
 151         ac = talloc_get_type(req->context, struct samldb_ctx);
 152         ldb = ldb_module_get_ctx(ac->module);
 153 
 154         if (!ares) {
 155                 ret = LDB_ERR_OPERATIONS_ERROR;
 156                 goto done;
 157         }
 158         if (ares->error != LDB_SUCCESS) {
 159                 return ldb_module_done(ac->req, ares->controls,
 160                                         ares->response, ares->error);
 161         }
 162 
 163         switch (ares->type) {
 164         case LDB_REPLY_ENTRY:
 165                 /* save entry */
 166                 if (ac->ares != NULL) {
 167                         /* one too many! */
 168                         ldb_set_errstring(ldb,
 169                                 "Invalid number of results while searching "
 170                                 "for template objects");
 171                         ret = LDB_ERR_OPERATIONS_ERROR;
 172                         goto done;
 173                 }
 174 
 175                 ac->ares = talloc_steal(ac, ares);
 176                 ret = LDB_SUCCESS;
 177                 break;
 178 
 179         case LDB_REPLY_REFERRAL:
 180                 /* ignore */
 181                 talloc_free(ares);
 182                 ret = LDB_SUCCESS;
 183                 break;
 184 
 185         case LDB_REPLY_DONE:
 186 
 187                 talloc_free(ares);
 188                 ret = samldb_next_step(ac);
 189                 break;
 190         }
 191 
 192 done:
 193         if (ret != LDB_SUCCESS) {
 194                 return ldb_module_done(ac->req, NULL, NULL, ret);
 195         }
 196 
 197         return LDB_SUCCESS;
 198 }
 199 
 200 static int samldb_search_template(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 201 {
 202         struct ldb_context *ldb;
 203         struct tevent_context *ev;
 204         struct loadparm_context *lparm_ctx;
 205         struct ldb_context *templates_ldb;
 206         char *templates_ldb_path;
 207         struct ldb_request *req;
 208         struct ldb_dn *basedn;
 209         void *opaque;
 210         int ret;
 211 
 212         ldb = ldb_module_get_ctx(ac->module);
 213 
 214         opaque = ldb_get_opaque(ldb, "loadparm");
 215         lparm_ctx = talloc_get_type(opaque, struct loadparm_context);
 216         if (lparm_ctx == NULL) {
 217                 ldb_set_errstring(ldb,
 218                         "Unable to find loadparm context\n");
 219                 return LDB_ERR_OPERATIONS_ERROR;
 220         }
 221 
 222         opaque = ldb_get_opaque(ldb, "templates_ldb");
 223         templates_ldb = talloc_get_type(opaque, struct ldb_context);
 224 
 225         /* make sure we have the templates ldb */
 226         if (!templates_ldb) {
 227                 templates_ldb_path = samdb_relative_path(ldb, ac,
 228                                                          "templates.ldb");
 229                 if (!templates_ldb_path) {
 230                         ldb_set_errstring(ldb,
 231                                         "samldb_init_template: ERROR: Failed "
 232                                         "to contruct path for template db");
 233                         return LDB_ERR_OPERATIONS_ERROR;
 234                 }
 235 
 236                 ev = ldb_get_event_context(ldb);
 237 
 238                 templates_ldb = ldb_wrap_connect(ldb, ev,
 239                                                 lparm_ctx, templates_ldb_path,
 240                                                 NULL, NULL, 0, NULL);
 241                 talloc_free(templates_ldb_path);
 242 
 243                 if (!templates_ldb) {
 244                         return LDB_ERR_OPERATIONS_ERROR;
 245                 }
 246 
 247                 if (!talloc_reference(templates_ldb, ev)) {
 248                         return LDB_ERR_OPERATIONS_ERROR;
 249                 }
 250 
 251                 ret = ldb_set_opaque(ldb,
 252                                         "templates_ldb", templates_ldb);
 253                 if (ret != LDB_SUCCESS) {
 254                         return ret;
 255                 }
 256         }
 257 
 258         /* search template */
 259         basedn = ldb_dn_new_fmt(ac, templates_ldb,
 260                             "cn=Template%s,cn=Templates", ac->type);
 261         if (basedn == NULL) {
 262                 ldb_set_errstring(ldb,
 263                         "samldb_init_template: ERROR: Failed "
 264                         "to contruct DN for template");
 265                 return LDB_ERR_OPERATIONS_ERROR;
 266         }
 267 
 268         /* pull the template record */
 269         ret = ldb_build_search_req(&req, templates_ldb, ac,
 270                                    basedn, LDB_SCOPE_BASE,
 271                                   "(distinguishedName=*)", NULL,
 272                                   NULL,
 273                                   ac, samldb_search_template_callback,
 274                                   ac->req);
 275         if (ret != LDB_SUCCESS) {
 276                 return ret;
 277         }
 278 
 279         talloc_steal(req, basedn);
 280         ac->ares = NULL;
 281 
 282         return ldb_request(templates_ldb, req);
 283 }
 284 
 285 static int samldb_apply_template(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 286 {
 287         struct ldb_context *ldb;
 288         struct ldb_message_element *el;
 289         struct ldb_message *msg;
 290         int i, j;
 291         int ret;
 292 
 293         ldb = ldb_module_get_ctx(ac->module);
 294         msg = ac->ares->message;
 295 
 296         for (i = 0; i < msg->num_elements; i++) {
 297                 el = &msg->elements[i];
 298                 /* some elements should not be copied */
 299                 if (ldb_attr_cmp(el->name, "cn") == 0 ||
 300                     ldb_attr_cmp(el->name, "name") == 0 ||
 301                     ldb_attr_cmp(el->name, "objectClass") == 0 ||
 302                     ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
 303                     ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
 304                     ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
 305                     ldb_attr_cmp(el->name, "objectGUID") == 0) {
 306                         continue;
 307                 }
 308                 for (j = 0; j < el->num_values; j++) {
 309                         ret = samdb_find_or_add_attribute(
 310                                         ldb, ac->msg, el->name,
 311                                         (char *)el->values[j].data);
 312                         if (ret != LDB_SUCCESS) {
 313                                 ldb_set_errstring(ldb,
 314                                           "Failed adding template attribute\n");
 315                                 return LDB_ERR_OPERATIONS_ERROR;
 316                         }
 317                 }
 318         }
 319 
 320         return samldb_next_step(ac);
 321 }
 322 
 323 static int samldb_get_parent_domain(struct samldb_ctx *ac);
 324 
 325 static int samldb_get_parent_domain_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 326                                              struct ldb_reply *ares)
 327 {
 328         struct ldb_context *ldb;
 329         struct samldb_ctx *ac;
 330         const char *nextRid;
 331         int ret;
 332 
 333         ac = talloc_get_type(req->context, struct samldb_ctx);
 334         ldb = ldb_module_get_ctx(ac->module);
 335 
 336         if (!ares) {
 337                 ret = LDB_ERR_OPERATIONS_ERROR;
 338                 goto done;
 339         }
 340         if (ares->error != LDB_SUCCESS) {
 341                 return ldb_module_done(ac->req, ares->controls,
 342                                         ares->response, ares->error);
 343         }
 344 
 345         switch (ares->type) {
 346         case LDB_REPLY_ENTRY:
 347                 /* save entry */
 348                 if (ac->domain_dn != NULL) {
 349                         /* one too many! */
 350                         ldb_set_errstring(ldb,
 351                                 "Invalid number of results while searching "
 352                                 "for domain object");
 353                         ret = LDB_ERR_OPERATIONS_ERROR;
 354                         break;
 355                 }
 356 
 357                 nextRid = ldb_msg_find_attr_as_string(ares->message,
 358                                                       "nextRid", NULL);
 359                 if (nextRid == NULL) {
 360                         ldb_asprintf_errstring(ldb,
 361                                 "while looking for domain above %s attribute nextRid not found in %s\n",
 362                                                ldb_dn_get_linearized(ac->req->op.add.message->dn), 
 363                                                ldb_dn_get_linearized(ares->message->dn));
 364                         ret = LDB_ERR_OPERATIONS_ERROR;
 365                         break;
 366                 }
 367 
 368                 ac->next_rid = strtol(nextRid, NULL, 0);
 369 
 370                 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
 371                                                                 "objectSid");
 372                 if (ac->domain_sid == NULL) {
 373                         ldb_set_errstring(ldb,
 374                                 "error retrieving parent domain domain sid!\n");
 375                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
 376                         break;
 377                 }
 378                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
 379 
 380                 talloc_free(ares);
 381                 ret = LDB_SUCCESS;
 382                 ldb_reset_err_string(ldb);
 383                 break;
 384 
 385         case LDB_REPLY_REFERRAL:
 386                 /* ignore */
 387                 talloc_free(ares);
 388                 ret = LDB_SUCCESS;
 389                 break;
 390 
 391         case LDB_REPLY_DONE:
 392 
 393                 talloc_free(ares);
 394                 if (ac->domain_dn == NULL) {
 395                         /* search again */
 396                         ret = samldb_get_parent_domain(ac);
 397                 } else {
 398                         /* found, go on */
 399                         ret = samldb_next_step(ac);
 400                 }
 401                 break;
 402         }
 403 
 404 done:
 405         if (ret != LDB_SUCCESS) {
 406                 return ldb_module_done(ac->req, NULL, NULL, ret);
 407         }
 408 
 409         return LDB_SUCCESS;
 410 }
 411 
 412 /* Find a domain object in the parents of a particular DN.  */
 413 static int samldb_get_parent_domain(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 414 {
 415         struct ldb_context *ldb;
 416         static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
 417         struct ldb_request *req;
 418         struct ldb_dn *dn;
 419         int ret;
 420 
 421         ldb = ldb_module_get_ctx(ac->module);
 422 
 423         if (ac->check_dn == NULL) {
 424                 return LDB_ERR_OPERATIONS_ERROR;
 425         }
 426 
 427         dn = ldb_dn_get_parent(ac, ac->check_dn);
 428         if (dn == NULL) {
 429                 ldb_set_errstring(ldb,
 430                         "Unable to find parent domain object");
 431                 return LDB_ERR_CONSTRAINT_VIOLATION;
 432         }
 433 
 434         ac->check_dn = dn;
 435 
 436         ret = ldb_build_search_req(&req, ldb, ac,
 437                                    dn, LDB_SCOPE_BASE,
 438                                    "(|(objectClass=domain)"
 439                                      "(objectClass=builtinDomain)"
 440                                      "(objectClass=samba4LocalDomain))",
 441                                    attrs,
 442                                    NULL,
 443                                    ac, samldb_get_parent_domain_callback,
 444                                    ac->req);
 445 
 446         if (ret != LDB_SUCCESS) {
 447                 return ret;
 448         }
 449 
 450         return ldb_next_request(ac->module, req);
 451 }
 452 
 453 static int samldb_generate_samAccountName(struct ldb_message *msg)
     /* [<][>][^][v][top][bottom][index][help] */
 454 {
 455         char *name;
 456 
 457         /* Format: $000000-000000000000 */
 458 
 459         name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
 460                                 (unsigned int)generate_random(),
 461                                 (unsigned int)generate_random(),
 462                                 (unsigned int)generate_random());
 463         if (name == NULL) {
 464                 return LDB_ERR_OPERATIONS_ERROR;
 465         }
 466         return ldb_msg_add_steal_string(msg, "samAccountName", name);
 467 }
 468 
 469 static int samldb_check_samAccountName_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 470                                                 struct ldb_reply *ares)
 471 {
 472         struct samldb_ctx *ac;
 473         int ret;
 474 
 475         ac = talloc_get_type(req->context, struct samldb_ctx);
 476 
 477         if (!ares) {
 478                 ret = LDB_ERR_OPERATIONS_ERROR;
 479                 goto done;
 480         }
 481         if (ares->error != LDB_SUCCESS) {
 482                 return ldb_module_done(ac->req, ares->controls,
 483                                         ares->response, ares->error);
 484         }
 485 
 486         switch (ares->type) {
 487         case LDB_REPLY_ENTRY:
 488 
 489                 /* if we get an entry it means this samAccountName
 490                  * already exists */
 491                 return ldb_module_done(ac->req, NULL, NULL,
 492                                         LDB_ERR_ENTRY_ALREADY_EXISTS);
 493 
 494         case LDB_REPLY_REFERRAL:
 495                 /* ignore */
 496                 talloc_free(ares);
 497                 ret = LDB_SUCCESS;
 498                 break;
 499 
 500         case LDB_REPLY_DONE:
 501 
 502                 /* not found, go on */
 503                 talloc_free(ares);
 504                 ret = samldb_next_step(ac);
 505                 break;
 506         }
 507 
 508 done:
 509         if (ret != LDB_SUCCESS) {
 510                 return ldb_module_done(ac->req, NULL, NULL, ret);
 511         }
 512 
 513         return LDB_SUCCESS;
 514 }
 515 
 516 static int samldb_check_samAccountName(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 517 {
 518         struct ldb_context *ldb;
 519         struct ldb_request *req;
 520         const char *name;
 521         char *filter;
 522         int ret;
 523 
 524         ldb = ldb_module_get_ctx(ac->module);
 525 
 526         if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
 527                 ret = samldb_generate_samAccountName(ac->msg);
 528                 if (ret != LDB_SUCCESS) {
 529                         return ret;
 530                 }
 531         }
 532 
 533         name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
 534         if (name == NULL) {
 535                 return LDB_ERR_OPERATIONS_ERROR;
 536         }
 537         filter = talloc_asprintf(ac, "samAccountName=%s", name);
 538         if (filter == NULL) {
 539                 return LDB_ERR_OPERATIONS_ERROR;
 540         }
 541 
 542         ret = ldb_build_search_req(&req, ldb, ac,
 543                                 ac->domain_dn, LDB_SCOPE_SUBTREE,
 544                                 filter, NULL,
 545                                 NULL,
 546                                 ac, samldb_check_samAccountName_callback,
 547                                 ac->req);
 548         talloc_free(filter);
 549         if (ret != LDB_SUCCESS) {
 550                 return ret;
 551         }
 552         ac->ares = NULL;
 553         return ldb_next_request(ac->module, req);
 554 }
 555 
 556 static int samldb_check_samAccountType(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 557 {
 558         struct ldb_context *ldb;
 559         unsigned int account_type;
 560         unsigned int group_type;
 561         unsigned int uac;
 562         int ret;
 563 
 564         ldb = ldb_module_get_ctx(ac->module);
 565 
 566         /* make sure sAMAccountType is not specified */
 567         if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
 568                 ldb_asprintf_errstring(ldb,
 569                                         "sAMAccountType must not be specified");
 570                 return LDB_ERR_UNWILLING_TO_PERFORM;
 571         }
 572 
 573         if (strcmp("user", ac->type) == 0) {
 574                 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
 575                 if (uac == 0) {
 576                         ldb_asprintf_errstring(ldb,
 577                                                 "userAccountControl invalid");
 578                         return LDB_ERR_UNWILLING_TO_PERFORM;
 579                 } else {
 580                         account_type = samdb_uf2atype(uac);
 581                         ret = samdb_msg_add_uint(ldb,
 582                                                  ac->msg, ac->msg,
 583                                                  "sAMAccountType",
 584                                                  account_type);
 585                         if (ret != LDB_SUCCESS) {
 586                                 return ret;
 587                         }
 588                 }
 589         } else
 590         if (strcmp("group", ac->type) == 0) {
 591 
 592                 group_type = samdb_result_uint(ac->msg, "groupType", 0);
 593                 if (group_type == 0) {
 594                         ldb_asprintf_errstring(ldb,
 595                                                 "groupType invalid");
 596                         return LDB_ERR_UNWILLING_TO_PERFORM;
 597                 } else {
 598                         account_type = samdb_gtype2atype(group_type);
 599                         ret = samdb_msg_add_uint(ldb,
 600                                                  ac->msg, ac->msg,
 601                                                  "sAMAccountType",
 602                                                  account_type);
 603                         if (ret != LDB_SUCCESS) {
 604                                 return ret;
 605                         }
 606                 }
 607         }
 608 
 609         return samldb_next_step(ac);
 610 }
 611 
 612 static int samldb_get_sid_domain_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 613                                           struct ldb_reply *ares)
 614 {
 615         struct ldb_context *ldb;
 616         struct samldb_ctx *ac;
 617         const char *nextRid;
 618         int ret;
 619 
 620         ac = talloc_get_type(req->context, struct samldb_ctx);
 621         ldb = ldb_module_get_ctx(ac->module);
 622 
 623         if (!ares) {
 624                 ret = LDB_ERR_OPERATIONS_ERROR;
 625                 goto done;
 626         }
 627         if (ares->error != LDB_SUCCESS) {
 628                 return ldb_module_done(ac->req, ares->controls,
 629                                         ares->response, ares->error);
 630         }
 631 
 632         switch (ares->type) {
 633         case LDB_REPLY_ENTRY:
 634                 /* save entry */
 635                 if (ac->next_rid != 0) {
 636                         /* one too many! */
 637                         ldb_set_errstring(ldb,
 638                                 "Invalid number of results while searching "
 639                                 "for domain object");
 640                         ret = LDB_ERR_OPERATIONS_ERROR;
 641                         break;
 642                 }
 643 
 644                 nextRid = ldb_msg_find_attr_as_string(ares->message,
 645                                                         "nextRid", NULL);
 646                 if (nextRid == NULL) {
 647                         ldb_asprintf_errstring(ldb,
 648                                 "attribute nextRid not found in %s\n",
 649                                 ldb_dn_get_linearized(ares->message->dn));
 650                         ret = LDB_ERR_OPERATIONS_ERROR;
 651                         break;
 652                 }
 653 
 654                 ac->next_rid = strtol(nextRid, NULL, 0);
 655 
 656                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
 657 
 658                 talloc_free(ares);
 659                 ret = LDB_SUCCESS;
 660                 break;
 661 
 662         case LDB_REPLY_REFERRAL:
 663                 /* ignore */
 664                 talloc_free(ares);
 665                 ret = LDB_SUCCESS;
 666                 break;
 667 
 668         case LDB_REPLY_DONE:
 669 
 670                 if (ac->next_rid == 0) {
 671                         ldb_asprintf_errstring(ldb,
 672                                 "Unable to get nextRid from domain entry\n");
 673                         ret = LDB_ERR_OPERATIONS_ERROR;
 674                         break;
 675                 }
 676 
 677                 /* found, go on */
 678                 ret = samldb_next_step(ac);
 679                 break;
 680         }
 681 
 682 done:
 683         if (ret != LDB_SUCCESS) {
 684                 return ldb_module_done(ac->req, NULL, NULL, ret);
 685         }
 686 
 687         return LDB_SUCCESS;
 688 }
 689 
 690 /* Find a domain object in the parents of a particular DN.  */
 691 static int samldb_get_sid_domain(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 692 {
 693         struct ldb_context *ldb;
 694         static const char * const attrs[2] = { "nextRid", NULL };
 695         struct ldb_request *req;
 696         char *filter;
 697         int ret;
 698 
 699         ldb = ldb_module_get_ctx(ac->module);
 700 
 701         if (ac->sid == NULL) {
 702                 return LDB_ERR_OPERATIONS_ERROR;
 703         }
 704 
 705         ac->domain_sid = dom_sid_dup(ac, ac->sid);
 706         if (!ac->domain_sid) {
 707                 return LDB_ERR_OPERATIONS_ERROR;
 708         }
 709         /* get the domain component part of the provided SID */
 710         ac->domain_sid->num_auths--;
 711 
 712         filter = talloc_asprintf(ac, "(&(objectSid=%s)"
 713                                        "(|(objectClass=domain)"
 714                                          "(objectClass=builtinDomain)"
 715                                          "(objectClass=samba4LocalDomain)))",
 716                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
 717         if (filter == NULL) {
 718                 return LDB_ERR_OPERATIONS_ERROR;
 719         }
 720 
 721         ret = ldb_build_search_req(&req, ldb, ac,
 722                                    ldb_get_default_basedn(ldb),
 723                                    LDB_SCOPE_SUBTREE,
 724                                    filter, attrs,
 725                                    NULL,
 726                                    ac, samldb_get_sid_domain_callback,
 727                                    ac->req);
 728 
 729         if (ret != LDB_SUCCESS) {
 730                 return ret;
 731         }
 732 
 733         ac->next_rid = 0;
 734         return ldb_next_request(ac->module, req);
 735 }
 736 
 737 static bool samldb_msg_add_sid(struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 738                                 const char *name,
 739                                 const struct dom_sid *sid)
 740 {
 741         struct ldb_val v;
 742         enum ndr_err_code ndr_err;
 743 
 744         ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
 745                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
 746         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 747                 return false;
 748         }
 749         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
 750 }
 751 
 752 static int samldb_new_sid(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 753 {
 754 
 755         if (ac->domain_sid == NULL || ac->next_rid == 0) {
 756                 return LDB_ERR_OPERATIONS_ERROR;
 757         }
 758 
 759         ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
 760         if (ac->sid == NULL) {
 761                 return LDB_ERR_OPERATIONS_ERROR;
 762         }
 763 
 764         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
 765                 return LDB_ERR_OPERATIONS_ERROR;
 766         }
 767 
 768         return samldb_next_step(ac);
 769 }
 770 
 771 static int samldb_check_sid_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 772                                      struct ldb_reply *ares)
 773 {
 774         struct samldb_ctx *ac;
 775         int ret;
 776 
 777         ac = talloc_get_type(req->context, struct samldb_ctx);
 778 
 779         if (!ares) {
 780                 ret = LDB_ERR_OPERATIONS_ERROR;
 781                 goto done;
 782         }
 783         if (ares->error != LDB_SUCCESS) {
 784                 return ldb_module_done(ac->req, ares->controls,
 785                                         ares->response, ares->error);
 786         }
 787 
 788         switch (ares->type) {
 789         case LDB_REPLY_ENTRY:
 790 
 791                 /* if we get an entry it means an object with the
 792                  * requested sid exists */
 793                 return ldb_module_done(ac->req, NULL, NULL,
 794                                         LDB_ERR_CONSTRAINT_VIOLATION);
 795 
 796         case LDB_REPLY_REFERRAL:
 797                 /* ignore */
 798                 talloc_free(ares);
 799                 break;
 800 
 801         case LDB_REPLY_DONE:
 802 
 803                 /* not found, go on */
 804                 talloc_free(ares);
 805                 ret = samldb_next_step(ac);
 806                 break;
 807         }
 808 
 809 done:
 810         if (ret != LDB_SUCCESS) {
 811                 return ldb_module_done(ac->req, NULL, NULL, ret);
 812         }
 813 
 814         return LDB_SUCCESS;
 815 }
 816 
 817 static int samldb_check_sid(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 818 {
 819         struct ldb_context *ldb;
 820         const char *const attrs[2] = { "objectSid", NULL };
 821         struct ldb_request *req;
 822         char *filter;
 823         int ret;
 824 
 825         if (ac->sid == NULL) {
 826                 return LDB_ERR_OPERATIONS_ERROR;
 827         }
 828 
 829         ldb = ldb_module_get_ctx(ac->module);
 830 
 831         filter = talloc_asprintf(ac, "(objectSid=%s)",
 832                                  ldap_encode_ndr_dom_sid(ac, ac->sid));
 833         if (filter == NULL) {
 834                 return LDB_ERR_OPERATIONS_ERROR;
 835         }
 836 
 837         ret = ldb_build_search_req(&req, ldb, ac,
 838                                    ldb_get_default_basedn(ldb),
 839                                    LDB_SCOPE_SUBTREE,
 840                                    filter, attrs,
 841                                    NULL,
 842                                    ac, samldb_check_sid_callback,
 843                                    ac->req);
 844 
 845         if (ret != LDB_SUCCESS) {
 846                 return ret;
 847         }
 848 
 849         return ldb_next_request(ac->module, req);
 850 }
 851 
 852 static int samldb_notice_sid_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 853                                         struct ldb_reply *ares)
 854 {
 855         struct ldb_context *ldb;
 856         struct samldb_ctx *ac;
 857         int ret;
 858 
 859         ac = talloc_get_type(req->context, struct samldb_ctx);
 860         ldb = ldb_module_get_ctx(ac->module);
 861 
 862         if (!ares) {
 863                 ret = LDB_ERR_OPERATIONS_ERROR;
 864                 goto done;
 865         }
 866         if (ares->error != LDB_SUCCESS) {
 867                 return ldb_module_done(ac->req, ares->controls,
 868                                         ares->response, ares->error);
 869         }
 870         if (ares->type != LDB_REPLY_DONE) {
 871                 ldb_set_errstring(ldb,
 872                         "Invalid reply type!\n");
 873                 ret = LDB_ERR_OPERATIONS_ERROR;
 874                 goto done;
 875         }
 876 
 877         ret = samldb_next_step(ac);
 878 
 879 done:
 880         if (ret != LDB_SUCCESS) {
 881                 return ldb_module_done(ac->req, NULL, NULL, ret);
 882         }
 883 
 884         return LDB_SUCCESS;
 885 }
 886 
 887 /* If we are adding new users/groups, we need to update the nextRid
 888  * attribute to be 'above' the new/incoming RID. Attempt to do it
 889  *atomically. */
 890 static int samldb_notice_sid(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 891 {
 892         struct ldb_context *ldb;
 893         uint32_t old_id, new_id;
 894         struct ldb_request *req;
 895         struct ldb_message *msg;
 896         struct ldb_message_element *els;
 897         struct ldb_val *vals;
 898         int ret;
 899 
 900         ldb = ldb_module_get_ctx(ac->module);
 901         old_id = ac->next_rid;
 902         new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
 903 
 904         if (old_id >= new_id) {
 905                 /* no need to update the domain nextRid attribute */
 906                 return samldb_next_step(ac);
 907         }
 908 
 909         /* we do a delete and add as a single operation. That prevents
 910            a race, in case we are not actually on a transaction db */
 911         msg = talloc_zero(ac, struct ldb_message);
 912         if (msg == NULL) {
 913                 ldb_oom(ldb);
 914                 return LDB_ERR_OPERATIONS_ERROR;
 915         }
 916         els = talloc_array(msg, struct ldb_message_element, 2);
 917         if (els == NULL) {
 918                 ldb_oom(ldb);
 919                 return LDB_ERR_OPERATIONS_ERROR;
 920         }
 921         vals = talloc_array(msg, struct ldb_val, 2);
 922         if (vals == NULL) {
 923                 ldb_oom(ldb);
 924                 return LDB_ERR_OPERATIONS_ERROR;
 925         }
 926         msg->dn = ac->domain_dn;
 927         msg->num_elements = 2;
 928         msg->elements = els;
 929 
 930         els[0].num_values = 1;
 931         els[0].values = &vals[0];
 932         els[0].flags = LDB_FLAG_MOD_DELETE;
 933         els[0].name = talloc_strdup(msg, "nextRid");
 934         if (!els[0].name) {
 935                 ldb_oom(ldb);
 936                 return LDB_ERR_OPERATIONS_ERROR;
 937         }
 938 
 939         els[1].num_values = 1;
 940         els[1].values = &vals[1];
 941         els[1].flags = LDB_FLAG_MOD_ADD;
 942         els[1].name = els[0].name;
 943 
 944         vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
 945         if (!vals[0].data) {
 946                 ldb_oom(ldb);
 947                 return LDB_ERR_OPERATIONS_ERROR;
 948         }
 949         vals[0].length = strlen((char *)vals[0].data);
 950 
 951         vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
 952         if (!vals[1].data) {
 953                 ldb_oom(ldb);
 954                 return LDB_ERR_OPERATIONS_ERROR;
 955         }
 956         vals[1].length = strlen((char *)vals[1].data);
 957 
 958         ret = ldb_build_mod_req(&req, ldb, ac,
 959                                 msg, NULL,
 960                                 ac, samldb_notice_sid_callback,
 961                                 ac->req);
 962         if (ret != LDB_SUCCESS) {
 963                 return ret;
 964         }
 965 
 966         return ldb_next_request(ac->module, req);
 967 }
 968 
 969 static int samldb_add_entry_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 970                                         struct ldb_reply *ares)
 971 {
 972         struct ldb_context *ldb;
 973         struct samldb_ctx *ac;
 974 
 975         ac = talloc_get_type(req->context, struct samldb_ctx);
 976         ldb = ldb_module_get_ctx(ac->module);
 977 
 978         if (!ares) {
 979                 return ldb_module_done(ac->req, NULL, NULL,
 980                                         LDB_ERR_OPERATIONS_ERROR);
 981         }
 982         if (ares->error != LDB_SUCCESS) {
 983                 return ldb_module_done(ac->req, ares->controls,
 984                                         ares->response, ares->error);
 985         }
 986         if (ares->type != LDB_REPLY_DONE) {
 987                 ldb_set_errstring(ldb,
 988                         "Invalid reply type!\n");
 989                 return ldb_module_done(ac->req, NULL, NULL,
 990                                         LDB_ERR_OPERATIONS_ERROR);
 991         }
 992 
 993         /* we exit the samldb module here */
 994         return ldb_module_done(ac->req, ares->controls,
 995                                 ares->response, LDB_SUCCESS);
 996 }
 997 
 998 static int samldb_add_entry(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
 999 {
1000         struct ldb_context *ldb;
1001         struct ldb_request *req;
1002         int ret;
1003 
1004         ldb = ldb_module_get_ctx(ac->module);
1005 
1006         ret = ldb_build_add_req(&req, ldb, ac,
1007                                 ac->msg,
1008                                 ac->req->controls,
1009                                 ac, samldb_add_entry_callback,
1010                                 ac->req);
1011         if (ret != LDB_SUCCESS) {
1012                 return ret;
1013         }
1014 
1015         return ldb_next_request(ac->module, req);
1016 }
1017 
1018 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
     /* [<][>][^][v][top][bottom][index][help] */
1019 {
1020         int ret;
1021 
1022         /* first look for the template */
1023         ac->type = type;
1024         ret = samldb_add_step(ac, samldb_search_template);
1025         if (ret != LDB_SUCCESS) return ret;
1026 
1027         /* then apply it */
1028         ret = samldb_add_step(ac, samldb_apply_template);
1029         if (ret != LDB_SUCCESS) return ret;
1030 
1031         /* search for a parent domain objet */
1032         ac->check_dn = ac->req->op.add.message->dn;
1033         ret = samldb_add_step(ac, samldb_get_parent_domain);
1034         if (ret != LDB_SUCCESS) return ret;
1035 
1036         /* check if we have a valid samAccountName */
1037         ret = samldb_add_step(ac, samldb_check_samAccountName);
1038         if (ret != LDB_SUCCESS) return ret;
1039 
1040         /* check account_type/group_type */
1041         ret = samldb_add_step(ac, samldb_check_samAccountType);
1042         if (ret != LDB_SUCCESS) return ret;
1043 
1044         /* check if we have a valid SID */
1045         ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1046         if ( ! ac->sid) {
1047                 ret = samldb_add_step(ac, samldb_new_sid);
1048                 if (ret != LDB_SUCCESS) return ret;
1049         } else {
1050                 ret = samldb_add_step(ac, samldb_get_sid_domain);
1051                 if (ret != LDB_SUCCESS) return ret;
1052         }
1053 
1054         ret = samldb_add_step(ac, samldb_check_sid);
1055         if (ret != LDB_SUCCESS) return ret;
1056 
1057         ret = samldb_add_step(ac, samldb_notice_sid);
1058         if (ret != LDB_SUCCESS) return ret;
1059 
1060         /* finally proceed with adding the entry */
1061         ret = samldb_add_step(ac, samldb_add_entry);
1062         if (ret != LDB_SUCCESS) return ret;
1063 
1064         return samldb_first_step(ac);
1065 
1066         /* TODO: userAccountControl, badPwdCount, codePage,
1067          *       countryCode, badPasswordTime, lastLogoff, lastLogon,
1068          *       pwdLastSet, primaryGroupID, accountExpires, logonCount */
1069 
1070 }
1071 
1072 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
1073                                                 struct ldb_reply *ares)
1074 {
1075         struct ldb_context *ldb;
1076         struct samldb_ctx *ac;
1077         const char *nextRid;
1078         const char *name;
1079         int ret;
1080 
1081         ac = talloc_get_type(req->context, struct samldb_ctx);
1082         ldb = ldb_module_get_ctx(ac->module);
1083 
1084         if (!ares) {
1085                 ret = LDB_ERR_OPERATIONS_ERROR;
1086                 goto done;
1087         }
1088         if (ares->error != LDB_SUCCESS) {
1089                 return ldb_module_done(ac->req, ares->controls,
1090                                         ares->response, ares->error);
1091         }
1092 
1093         switch (ares->type) {
1094         case LDB_REPLY_ENTRY:
1095                 /* save entry */
1096                 if (ac->next_rid != 0) {
1097                         /* one too many! */
1098                         ldb_set_errstring(ldb,
1099                                 "Invalid number of results while searching "
1100                                 "for domain object");
1101                         ret = LDB_ERR_OPERATIONS_ERROR;
1102                         break;
1103                 }
1104 
1105                 nextRid = ldb_msg_find_attr_as_string(ares->message,
1106                                                         "nextRid", NULL);
1107                 if (nextRid == NULL) {
1108                         ldb_asprintf_errstring(ldb,
1109                                 "while looking for forign sid %s attribute nextRid not found in %s\n",
1110                                                dom_sid_string(ares, ac->sid), ldb_dn_get_linearized(ares->message->dn));
1111                         ret = LDB_ERR_OPERATIONS_ERROR;
1112                         break;
1113                 }
1114 
1115                 ac->next_rid = strtol(nextRid, NULL, 0);
1116 
1117                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1118 
1119                 name = samdb_result_string(ares->message, "name", NULL);
1120                 ldb_debug(ldb, LDB_DEBUG_TRACE,
1121                          "NOTE (strange but valid): Adding foreign SID "
1122                          "record with SID %s, but this domain (%s) is "
1123                          "not foreign in the database",
1124                          dom_sid_string(ares, ac->sid), name);
1125 
1126                 talloc_free(ares);
1127                 break;
1128 
1129         case LDB_REPLY_REFERRAL:
1130                 /* ignore */
1131                 talloc_free(ares);
1132                 break;
1133 
1134         case LDB_REPLY_DONE:
1135 
1136                 /* if this is a fake foreign SID, notice the SID */
1137                 if (ac->domain_dn) {
1138                         ret = samldb_notice_sid(ac);
1139                         break;
1140                 }
1141 
1142                 /* found, go on */
1143                 ret = samldb_next_step(ac);
1144                 break;
1145         }
1146 
1147 done:
1148         if (ret != LDB_SUCCESS) {
1149                 return ldb_module_done(ac->req, NULL, NULL, ret);
1150         }
1151 
1152         return LDB_SUCCESS;
1153 }
1154 
1155 /* Find a domain object in the parents of a particular DN. */
1156 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
1157 {
1158         struct ldb_context *ldb;
1159         static const char * const attrs[3] = { "nextRid", "name", NULL };
1160         struct ldb_request *req;
1161         NTSTATUS status;
1162         char *filter;
1163         int ret;
1164 
1165         ldb = ldb_module_get_ctx(ac->module);
1166 
1167         if (ac->sid == NULL) {
1168                 return LDB_ERR_OPERATIONS_ERROR;
1169         }
1170 
1171         status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1172         if (!NT_STATUS_IS_OK(status)) {
1173                 return LDB_ERR_OPERATIONS_ERROR;
1174         }
1175 
1176         filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1177                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1178         if (filter == NULL) {
1179                 return LDB_ERR_OPERATIONS_ERROR;
1180         }
1181 
1182         ret = ldb_build_search_req(&req, ldb, ac,
1183                                    ldb_get_default_basedn(ldb),
1184                                    LDB_SCOPE_SUBTREE,
1185                                    filter, attrs,
1186                                    NULL,
1187                                    ac, samldb_foreign_notice_sid_callback,
1188                                    ac->req);
1189 
1190         if (ret != LDB_SUCCESS) {
1191                 return ret;
1192         }
1193 
1194         ac->next_rid = 0;
1195         return ldb_next_request(ac->module, req);
1196 }
1197 
1198 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
     /* [<][>][^][v][top][bottom][index][help] */
1199 {
1200         struct ldb_context *ldb;
1201         int ret;
1202 
1203         ldb = ldb_module_get_ctx(ac->module);
1204 
1205         ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1206         if (ac->sid == NULL) {
1207                 ac->sid = dom_sid_parse_talloc(ac->msg,
1208                            (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1209                 if (!ac->sid) {
1210                         ldb_set_errstring(ldb,
1211                                         "No valid found SID in "
1212                                         "ForeignSecurityPrincipal CN!");
1213                         talloc_free(ac);
1214                         return LDB_ERR_CONSTRAINT_VIOLATION;
1215                 }
1216                 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1217                         talloc_free(ac);
1218                         return LDB_ERR_OPERATIONS_ERROR;
1219                 }
1220         }
1221 
1222         /* first look for the template */
1223         ac->type = "foreignSecurityPrincipal";
1224         ret = samldb_add_step(ac, samldb_search_template);
1225         if (ret != LDB_SUCCESS) return ret;
1226 
1227         /* then apply it */
1228         ret = samldb_add_step(ac, samldb_apply_template);
1229         if (ret != LDB_SUCCESS) return ret;
1230 
1231         /* check we do not already have this SID */
1232         ret = samldb_add_step(ac, samldb_check_sid);
1233         if (ret != LDB_SUCCESS) return ret;
1234 
1235         /* check if we need to notice this SID */
1236         ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1237         if (ret != LDB_SUCCESS) return ret;
1238 
1239         /* finally proceed with adding the entry */
1240         ret = samldb_add_step(ac, samldb_add_entry);
1241         if (ret != LDB_SUCCESS) return ret;
1242 
1243         return samldb_first_step(ac);
1244 }
1245 
1246 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
     /* [<][>][^][v][top][bottom][index][help] */
1247 {
1248         struct ldb_context *ldb;
1249         const char *rdn_name;
1250 
1251         ldb = ldb_module_get_ctx(module);
1252         rdn_name = ldb_dn_get_rdn_name(dn);
1253 
1254         if (strcasecmp(rdn_name, "cn") != 0) {
1255                 ldb_asprintf_errstring(ldb,
1256                                         "Bad RDN (%s=) for samldb object, "
1257                                         "should be CN=!\n", rdn_name);
1258                 return LDB_ERR_CONSTRAINT_VIOLATION;
1259         }
1260 
1261         return LDB_SUCCESS;
1262 }
1263 
1264 /* add_record */
1265 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1266 {
1267         struct ldb_context *ldb;
1268         struct samldb_ctx *ac;
1269         int ret;
1270 
1271         ldb = ldb_module_get_ctx(module);
1272         ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1273 
1274         /* do not manipulate our control entries */
1275         if (ldb_dn_is_special(req->op.add.message->dn)) {
1276                 return ldb_next_request(module, req);
1277         }
1278 
1279         ac = samldb_ctx_init(module, req);
1280         if (ac == NULL) {
1281                 return LDB_ERR_OPERATIONS_ERROR;
1282         }
1283 
1284         /* build the new msg */
1285         ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1286         if (!ac->msg) {
1287                 talloc_free(ac);
1288                 ldb_debug(ldb, LDB_DEBUG_FATAL,
1289                           "samldb_add: ldb_msg_copy failed!\n");
1290                 return LDB_ERR_OPERATIONS_ERROR;
1291         }
1292 
1293         if (samdb_find_attribute(ldb, ac->msg,
1294                                  "objectclass", "computer") != NULL) {
1295 
1296                 /* make sure the computer object also has the 'user'
1297                  * objectclass so it will be handled by the next call */
1298                 ret = samdb_find_or_add_value(ldb, ac->msg,
1299                                                 "objectclass", "user");
1300                 if (ret != LDB_SUCCESS) {
1301                         talloc_free(ac);
1302                         return ret;
1303                 }
1304         }
1305 
1306         if (samdb_find_attribute(ldb, ac->msg,
1307                                  "objectclass", "user") != NULL) {
1308 
1309                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1310                 if (ret != LDB_SUCCESS) {
1311                         talloc_free(ac);
1312                         return ret;
1313                 }
1314 
1315                 return samldb_fill_object(ac, "user");
1316         }
1317 
1318         if (samdb_find_attribute(ldb, ac->msg,
1319                                  "objectclass", "group") != NULL) {
1320 
1321                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1322                 if (ret != LDB_SUCCESS) {
1323                         talloc_free(ac);
1324                         return ret;
1325                 }
1326 
1327                 return samldb_fill_object(ac, "group");
1328         }
1329 
1330         /* perhaps a foreignSecurityPrincipal? */
1331         if (samdb_find_attribute(ldb, ac->msg,
1332                                  "objectclass",
1333                                  "foreignSecurityPrincipal") != NULL) {
1334 
1335                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1336                 if (ret != LDB_SUCCESS) {
1337                         talloc_free(ac);
1338                         return ret;
1339                 }
1340 
1341                 return samldb_fill_foreignSecurityPrincipal_object(ac);
1342         }
1343 
1344         talloc_free(ac);
1345 
1346         /* nothing matched, go on */
1347         return ldb_next_request(module, req);
1348 }
1349 
1350 /* modify */
1351 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1352 {
1353         struct ldb_context *ldb;
1354         struct ldb_message *msg;
1355         struct ldb_message_element *el, *el2;
1356         int ret;
1357         unsigned int group_type, user_account_control, account_type;
1358         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1359                 return ldb_next_request(module, req);
1360         }
1361 
1362         ldb = ldb_module_get_ctx(module);
1363 
1364         if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1365                 ldb_asprintf_errstring(ldb, "sAMAccountType must not be specified");
1366                 return LDB_ERR_UNWILLING_TO_PERFORM;
1367         }
1368 
1369         /* TODO: do not modify original request, create a new one */
1370 
1371         el = ldb_msg_find_element(req->op.mod.message, "groupType");
1372         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1373                 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1374 
1375                 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1376                 account_type =  samdb_gtype2atype(group_type);
1377                 ret = samdb_msg_add_uint(ldb, msg, msg,
1378                                          "sAMAccountType",
1379                                          account_type);
1380                 if (ret != LDB_SUCCESS) {
1381                         return ret;
1382                 }
1383                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1384                 el2->flags = LDB_FLAG_MOD_REPLACE;
1385         }
1386 
1387         el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1388         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1389                 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1390 
1391                 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1392                 account_type = samdb_uf2atype(user_account_control);
1393                 ret = samdb_msg_add_uint(ldb, msg, msg,
1394                                          "sAMAccountType",
1395                                          account_type);
1396                 if (ret != LDB_SUCCESS) {
1397                         return ret;
1398                 }
1399                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1400                 el2->flags = LDB_FLAG_MOD_REPLACE;
1401         }
1402         return ldb_next_request(module, req);
1403 }
1404 
1405 
1406 static int samldb_init(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
1407 {
1408         return ldb_next_init(module);
1409 }
1410 
1411 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1412         .name          = "samldb",
1413         .init_context  = samldb_init,
1414         .add           = samldb_add,
1415         .modify        = samldb_modify
1416 };

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