s4-dsdb: Use data_blob_string_const and add explaination for open-coded function...
[samba.git] / source4 / dsdb / samdb / ldb_modules / samldb.c
1 /*
2    SAM ldb module
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
5    Copyright (C) Simo Sorce  2004-2008
6    Copyright (C) Matthias Dieter Wallnöfer 2009-2011
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: ldb samldb module
26  *
27  *  Description: various internal DSDB triggers - most for SAM specific objects
28  *
29  *  Author: Simo Sorce
30  */
31
32 #include "includes.h"
33 #include "libcli/ldap/ldap_ndr.h"
34 #include "ldb_module.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "dsdb/samdb/ldb_modules/util.h"
37 #include "dsdb/samdb/ldb_modules/ridalloc.h"
38 #include "libcli/security/security.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40 #include "ldb_wrap.h"
41 #include "param/param.h"
42 #include "libds/common/flag_mapping.h"
43
44 struct samldb_ctx;
45 enum samldb_add_type {
46         SAMLDB_TYPE_USER,
47         SAMLDB_TYPE_GROUP,
48         SAMLDB_TYPE_CLASS,
49         SAMLDB_TYPE_ATTRIBUTE
50 };
51
52 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
53
54 struct samldb_step {
55         struct samldb_step *next;
56         samldb_step_fn_t fn;
57 };
58
59 struct samldb_ctx {
60         struct ldb_module *module;
61         struct ldb_request *req;
62
63         /* used for add operations */
64         enum samldb_add_type type;
65
66         /* the resulting message */
67         struct ldb_message *msg;
68
69         /* used in "samldb_find_for_defaultObjectCategory" */
70         struct ldb_dn *dn, *res_dn;
71
72         /* all the async steps necessary to complete the operation */
73         struct samldb_step *steps;
74         struct samldb_step *curstep;
75
76         /* If someone set an ares to forward controls and response back to the caller */
77         struct ldb_reply *ares;
78 };
79
80 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
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)
101 {
102         struct samldb_step *step, *stepper;
103
104         step = talloc_zero(ac, struct samldb_step);
105         if (step == NULL) {
106                 return ldb_oom(ldb_module_get_ctx(ac->module));
107         }
108
109         step->fn = fn;
110
111         if (ac->steps == NULL) {
112                 ac->steps = step;
113                 ac->curstep = step;
114         } else {
115                 if (ac->curstep == NULL)
116                         return ldb_operr(ldb_module_get_ctx(ac->module));
117                 for (stepper = ac->curstep; stepper->next != NULL;
118                         stepper = stepper->next);
119                 stepper->next = step;
120         }
121
122         return LDB_SUCCESS;
123 }
124
125 static int samldb_first_step(struct samldb_ctx *ac)
126 {
127         if (ac->steps == NULL) {
128                 return ldb_operr(ldb_module_get_ctx(ac->module));
129         }
130
131         ac->curstep = ac->steps;
132         return ac->curstep->fn(ac);
133 }
134
135 static int samldb_next_step(struct samldb_ctx *ac)
136 {
137         if (ac->curstep->next) {
138                 ac->curstep = ac->curstep->next;
139                 return ac->curstep->fn(ac);
140         }
141
142         /* We exit the samldb module here. If someone set an "ares" to forward
143          * controls and response back to the caller, use them. */
144         if (ac->ares) {
145                 return ldb_module_done(ac->req, ac->ares->controls,
146                                        ac->ares->response, LDB_SUCCESS);
147         } else {
148                 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
149         }
150 }
151
152
153 /* sAMAccountName handling */
154
155 static int samldb_generate_sAMAccountName(struct ldb_context *ldb,
156                                           struct ldb_message *msg)
157 {
158         char *name;
159
160         /* Format: $000000-000000000000 */
161
162         name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
163                                 (unsigned int)generate_random(),
164                                 (unsigned int)generate_random(),
165                                 (unsigned int)generate_random());
166         if (name == NULL) {
167                 return ldb_oom(ldb);
168         }
169         return ldb_msg_add_steal_string(msg, "sAMAccountName", name);
170 }
171
172 static int samldb_check_sAMAccountName(struct samldb_ctx *ac)
173 {
174         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
175         const char *name;
176         int ret;
177         struct ldb_result *res;
178         const char * const noattrs[] = { NULL };
179
180         if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
181                 ret = samldb_generate_sAMAccountName(ldb, ac->msg);
182                 if (ret != LDB_SUCCESS) {
183                         return ret;
184                 }
185         }
186
187         name = ldb_msg_find_attr_as_string(ac->msg, "sAMAccountName", NULL);
188         if (name == NULL) {
189                 /* The "sAMAccountName" cannot be nothing */
190                 ldb_set_errstring(ldb,
191                                   "samldb: Empty account names aren't allowed!");
192                 return LDB_ERR_CONSTRAINT_VIOLATION;
193         }
194
195         ret = dsdb_module_search(ac->module, ac, &res,
196                                  ldb_get_default_basedn(ldb), LDB_SCOPE_SUBTREE, noattrs,
197                                  DSDB_FLAG_NEXT_MODULE,
198                                  ac->req,
199                                  "(sAMAccountName=%s)",
200                                  ldb_binary_encode_string(ac, name));
201         if (ret != LDB_SUCCESS) {
202                 return ret;
203         }
204         if (res->count != 0) {
205                 ldb_asprintf_errstring(ldb,
206                                        "samldb: Account name (sAMAccountName) '%s' already in use!",
207                                        name);
208                 talloc_free(res);
209                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
210         }
211         talloc_free(res);
212
213         return samldb_next_step(ac);
214 }
215
216
217 static bool samldb_msg_add_sid(struct ldb_message *msg,
218                                 const char *name,
219                                 const struct dom_sid *sid)
220 {
221         struct ldb_val v;
222         enum ndr_err_code ndr_err;
223
224         ndr_err = ndr_push_struct_blob(&v, msg, sid,
225                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
226         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
227                 return false;
228         }
229         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
230 }
231
232
233 /* allocate a SID using our RID Set */
234 static int samldb_allocate_sid(struct samldb_ctx *ac)
235 {
236         uint32_t rid;
237         struct dom_sid *sid;
238         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
239         int ret;
240
241         ret = ridalloc_allocate_rid(ac->module, &rid, ac->req);
242         if (ret != LDB_SUCCESS) {
243                 return ret;
244         }
245
246         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
247         if (sid == NULL) {
248                 return ldb_module_oom(ac->module);
249         }
250
251         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
252                 return ldb_operr(ldb);
253         }
254
255         return samldb_next_step(ac);
256 }
257
258 /*
259   see if a krbtgt_number is available
260  */
261 static bool samldb_krbtgtnumber_available(struct samldb_ctx *ac,
262                                           uint32_t krbtgt_number)
263 {
264         TALLOC_CTX *tmp_ctx = talloc_new(ac);
265         struct ldb_result *res;
266         const char * const no_attrs[] = { NULL };
267         int ret;
268
269         ret = dsdb_module_search(ac->module, tmp_ctx, &res,
270                                  ldb_get_default_basedn(ldb_module_get_ctx(ac->module)),
271                                  LDB_SCOPE_SUBTREE, no_attrs,
272                                  DSDB_FLAG_NEXT_MODULE,
273                                  ac->req,
274                                  "(msDC-SecondaryKrbTgtNumber=%u)",
275                                  krbtgt_number);
276         if (ret == LDB_SUCCESS && res->count == 0) {
277                 talloc_free(tmp_ctx);
278                 return true;
279         }
280         talloc_free(tmp_ctx);
281         return false;
282 }
283
284 /* special handling for add in RODC join */
285 static int samldb_rodc_add(struct samldb_ctx *ac)
286 {
287         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
288         uint32_t krbtgt_number, i_start, i;
289         int ret;
290         char *newpass;
291         struct ldb_val newpass_utf16;
292
293         /* find a unused msDC-SecondaryKrbTgtNumber */
294         i_start = generate_random() & 0xFFFF;
295         if (i_start == 0) {
296                 i_start = 1;
297         }
298
299         for (i=i_start; i<=0xFFFF; i++) {
300                 if (samldb_krbtgtnumber_available(ac, i)) {
301                         krbtgt_number = i;
302                         goto found;
303                 }
304         }
305         for (i=1; i<i_start; i++) {
306                 if (samldb_krbtgtnumber_available(ac, i)) {
307                         krbtgt_number = i;
308                         goto found;
309                 }
310         }
311
312         ldb_asprintf_errstring(ldb,
313                                "%08X: Unable to find available msDS-SecondaryKrbTgtNumber",
314                                W_ERROR_V(WERR_NO_SYSTEM_RESOURCES));
315         return LDB_ERR_OTHER;
316
317 found:
318         ret = ldb_msg_add_empty(ac->msg, "msDS-SecondaryKrbTgtNumber",
319                                 LDB_FLAG_INTERNAL_DISABLE_VALIDATION, NULL);
320         if (ret != LDB_SUCCESS) {
321                 return ldb_operr(ldb);
322         }
323
324         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
325                                  "msDS-SecondaryKrbTgtNumber", krbtgt_number);
326         if (ret != LDB_SUCCESS) {
327                 return ldb_operr(ldb);
328         }
329
330         ret = ldb_msg_add_fmt(ac->msg, "sAMAccountName", "krbtgt_%u",
331                               krbtgt_number);
332         if (ret != LDB_SUCCESS) {
333                 return ldb_operr(ldb);
334         }
335
336         newpass = generate_random_password(ac->msg, 128, 255);
337         if (newpass == NULL) {
338                 return ldb_operr(ldb);
339         }
340
341         if (!convert_string_talloc(ac,
342                                    CH_UNIX, CH_UTF16,
343                                    newpass, strlen(newpass),
344                                    (void *)&newpass_utf16.data,
345                                    &newpass_utf16.length)) {
346                 ldb_asprintf_errstring(ldb,
347                                        "samldb_rodc_add: "
348                                        "failed to generate UTF16 password from random password");
349                 return LDB_ERR_OPERATIONS_ERROR;
350         }
351         ret = ldb_msg_add_steal_value(ac->msg, "clearTextPassword", &newpass_utf16);
352         if (ret != LDB_SUCCESS) {
353                 return ldb_operr(ldb);
354         }
355
356         return samldb_next_step(ac);
357 }
358
359 static int samldb_find_for_defaultObjectCategory(struct samldb_ctx *ac)
360 {
361         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
362         struct ldb_result *res;
363         const char * const no_attrs[] = { NULL };
364         int ret;
365
366         ac->res_dn = NULL;
367
368         ret = dsdb_module_search(ac->module, ac, &res,
369                                  ac->dn, LDB_SCOPE_BASE, no_attrs,
370                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
371                                  | DSDB_FLAG_NEXT_MODULE,
372                                  ac->req,
373                                  "(objectClass=classSchema)");
374         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
375                 /* Don't be pricky when the DN doesn't exist if we have the */
376                 /* RELAX control specified */
377                 if (ldb_request_get_control(ac->req,
378                                             LDB_CONTROL_RELAX_OID) == NULL) {
379                         ldb_set_errstring(ldb,
380                                           "samldb_find_defaultObjectCategory: "
381                                           "Invalid DN for 'defaultObjectCategory'!");
382                         return LDB_ERR_CONSTRAINT_VIOLATION;
383                 }
384         }
385         if ((ret != LDB_ERR_NO_SUCH_OBJECT) && (ret != LDB_SUCCESS)) {
386                 return ret;
387         }
388
389         if (ret == LDB_SUCCESS) {
390                 /* ensure the defaultObjectCategory has a full GUID */
391                 struct ldb_message *m;
392                 m = ldb_msg_new(ac->msg);
393                 if (m == NULL) {
394                         return ldb_oom(ldb);
395                 }
396                 m->dn = ac->msg->dn;
397                 if (ldb_msg_add_string(m, "defaultObjectCategory",
398                                        ldb_dn_get_extended_linearized(m, res->msgs[0]->dn, 1)) !=
399                     LDB_SUCCESS) {
400                         return ldb_oom(ldb);
401                 }
402                 m->elements[0].flags = LDB_FLAG_MOD_REPLACE;
403
404                 ret = dsdb_module_modify(ac->module, m,
405                                          DSDB_FLAG_NEXT_MODULE,
406                                          ac->req);
407                 if (ret != LDB_SUCCESS) {
408                         return ret;
409                 }
410         }
411
412
413         ac->res_dn = ac->dn;
414
415         return samldb_next_step(ac);
416 }
417
418 /**
419  * msDS-IntId attributeSchema attribute handling
420  * during LDB_ADD request processing
421  */
422 static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac)
423 {
424         int ret;
425         bool id_exists;
426         uint32_t msds_intid;
427         int32_t system_flags;
428         struct ldb_context *ldb;
429         struct ldb_result *ldb_res;
430         struct ldb_dn *schema_dn;
431
432         ldb = ldb_module_get_ctx(ac->module);
433         schema_dn = ldb_get_schema_basedn(ldb);
434
435         /* replicated update should always go through */
436         if (ldb_request_get_control(ac->req,
437                                     DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
438                 return LDB_SUCCESS;
439         }
440
441         /* msDS-IntId is handled by system and should never be
442          * passed by clients */
443         if (ldb_msg_find_element(ac->msg, "msDS-IntId")) {
444                 return LDB_ERR_UNWILLING_TO_PERFORM;
445         }
446
447         /* do not generate msDS-IntId if Relax control is passed */
448         if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
449                 return LDB_SUCCESS;
450         }
451
452         /* check Functional Level */
453         if (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003) {
454                 return LDB_SUCCESS;
455         }
456
457         /* check systemFlags for SCHEMA_BASE_OBJECT flag */
458         system_flags = ldb_msg_find_attr_as_int(ac->msg, "systemFlags", 0);
459         if (system_flags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) {
460                 return LDB_SUCCESS;
461         }
462
463         /* Generate new value for msDs-IntId
464          * Value should be in 0x80000000..0xBFFFFFFF range */
465         msds_intid = generate_random() % 0X3FFFFFFF;
466         msds_intid += 0x80000000;
467
468         /* probe id values until unique one is found */
469         do {
470                 msds_intid++;
471                 if (msds_intid > 0xBFFFFFFF) {
472                         msds_intid = 0x80000001;
473                 }
474
475                 ret = dsdb_module_search(ac->module, ac,
476                                          &ldb_res,
477                                          schema_dn, LDB_SCOPE_ONELEVEL, NULL,
478                                          DSDB_FLAG_NEXT_MODULE,
479                                          ac->req,
480                                          "(msDS-IntId=%d)", msds_intid);
481                 if (ret != LDB_SUCCESS) {
482                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
483                                       __location__": Searching for msDS-IntId=%d failed - %s\n",
484                                       msds_intid,
485                                       ldb_errstring(ldb));
486                         return ldb_operr(ldb);
487                 }
488                 id_exists = (ldb_res->count > 0);
489
490                 talloc_free(ldb_res);
491         } while(id_exists);
492
493         return samdb_msg_add_int(ldb, ac->msg, ac->msg, "msDS-IntId",
494                                  msds_intid);
495 }
496
497
498 /*
499  * samldb_add_entry (async)
500  */
501
502 static int samldb_add_entry_callback(struct ldb_request *req,
503                                         struct ldb_reply *ares)
504 {
505         struct ldb_context *ldb;
506         struct samldb_ctx *ac;
507         int ret;
508
509         ac = talloc_get_type(req->context, struct samldb_ctx);
510         ldb = ldb_module_get_ctx(ac->module);
511
512         if (!ares) {
513                 return ldb_module_done(ac->req, NULL, NULL,
514                                         LDB_ERR_OPERATIONS_ERROR);
515         }
516
517         if (ares->type == LDB_REPLY_REFERRAL) {
518                 return ldb_module_send_referral(ac->req, ares->referral);
519         }
520
521         if (ares->error != LDB_SUCCESS) {
522                 return ldb_module_done(ac->req, ares->controls,
523                                         ares->response, ares->error);
524         }
525         if (ares->type != LDB_REPLY_DONE) {
526                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
527                 return ldb_module_done(ac->req, NULL, NULL,
528                                         LDB_ERR_OPERATIONS_ERROR);
529         }
530
531         /* The caller may wish to get controls back from the add */
532         ac->ares = talloc_steal(ac, ares);
533
534         ret = samldb_next_step(ac);
535         if (ret != LDB_SUCCESS) {
536                 return ldb_module_done(ac->req, NULL, NULL, ret);
537         }
538         return ret;
539 }
540
541 static int samldb_add_entry(struct samldb_ctx *ac)
542 {
543         struct ldb_context *ldb;
544         struct ldb_request *req;
545         int ret;
546
547         ldb = ldb_module_get_ctx(ac->module);
548
549         ret = ldb_build_add_req(&req, ldb, ac,
550                                 ac->msg,
551                                 ac->req->controls,
552                                 ac, samldb_add_entry_callback,
553                                 ac->req);
554         LDB_REQ_SET_LOCATION(req);
555         if (ret != LDB_SUCCESS) {
556                 return ret;
557         }
558
559         return ldb_next_request(ac->module, req);
560 }
561
562 /*
563  * return true if msg carries an attributeSchema that is intended to be RODC
564  * filtered but is also a system-critical attribute.
565  */
566 static bool check_rodc_critical_attribute(struct ldb_message *msg)
567 {
568         uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
569
570         schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
571         searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
572         rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE
573                               | SEARCH_FLAG_CONFIDENTIAL);
574
575         if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
576                 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
577                 return true;
578         } else {
579                 return false;
580         }
581 }
582
583
584 static int samldb_fill_object(struct samldb_ctx *ac)
585 {
586         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
587         int ret;
588
589         /* Add information for the different account types */
590         switch(ac->type) {
591         case SAMLDB_TYPE_USER: {
592                 struct ldb_control *rodc_control = ldb_request_get_control(ac->req,
593                                                                            LDB_CONTROL_RODC_DCPROMO_OID);
594                 if (rodc_control != NULL) {
595                         /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
596                         rodc_control->critical = false;
597                         ret = samldb_add_step(ac, samldb_rodc_add);
598                         if (ret != LDB_SUCCESS) return ret;
599                 }
600
601                 /* check if we have a valid sAMAccountName */
602                 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
603                 if (ret != LDB_SUCCESS) return ret;
604
605                 ret = samldb_add_step(ac, samldb_add_entry);
606                 if (ret != LDB_SUCCESS) return ret;
607                 break;
608         }
609
610         case SAMLDB_TYPE_GROUP: {
611                 /* check if we have a valid sAMAccountName */
612                 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
613                 if (ret != LDB_SUCCESS) return ret;
614
615                 ret = samldb_add_step(ac, samldb_add_entry);
616                 if (ret != LDB_SUCCESS) return ret;
617                 break;
618         }
619
620         case SAMLDB_TYPE_CLASS: {
621                 const struct ldb_val *rdn_value, *def_obj_cat_val;
622                 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "objectClassCategory", -2);
623
624                 /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
625                 if (!ldb_msg_find_element(ac->msg, "subClassOf")) {
626                         ret = ldb_msg_add_string(ac->msg, "subClassOf", "top");
627                         if (ret != LDB_SUCCESS) return ret;
628                 }
629
630                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
631                                                   "rdnAttId", "cn");
632                 if (ret != LDB_SUCCESS) return ret;
633
634                 /* do not allow to mark an attributeSchema as RODC filtered if it
635                  * is system-critical */
636                 if (check_rodc_critical_attribute(ac->msg)) {
637                         ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
638                                                ldb_dn_get_linearized(ac->msg->dn));
639                         return LDB_ERR_UNWILLING_TO_PERFORM;
640                 }
641
642                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
643                 if (rdn_value == NULL) {
644                         return ldb_operr(ldb);
645                 }
646                 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
647                         /* the RDN has prefix "CN" */
648                         ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
649                                 samdb_cn_to_lDAPDisplayName(ac->msg,
650                                                             (const char *) rdn_value->data));
651                         if (ret != LDB_SUCCESS) {
652                                 ldb_oom(ldb);
653                                 return ret;
654                         }
655                 }
656
657                 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
658                         struct GUID guid;
659                         /* a new GUID */
660                         guid = GUID_random();
661                         ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
662                         if (ret != LDB_SUCCESS) {
663                                 ldb_oom(ldb);
664                                 return ret;
665                         }
666                 }
667
668                 def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
669                                                        "defaultObjectCategory");
670                 if (def_obj_cat_val != NULL) {
671                         /* "defaultObjectCategory" has been set by the caller.
672                          * Do some checks for consistency.
673                          * NOTE: The real constraint check (that
674                          * 'defaultObjectCategory' is the DN of the new
675                          * objectclass or any parent of it) is still incomplete.
676                          * For now we say that 'defaultObjectCategory' is valid
677                          * if it exists and it is of objectclass "classSchema".
678                          */
679                         ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
680                         if (ac->dn == NULL) {
681                                 ldb_set_errstring(ldb,
682                                                   "Invalid DN for 'defaultObjectCategory'!");
683                                 return LDB_ERR_CONSTRAINT_VIOLATION;
684                         }
685                 } else {
686                         /* "defaultObjectCategory" has not been set by the
687                          * caller. Use the entry DN for it. */
688                         ac->dn = ac->msg->dn;
689
690                         ret = ldb_msg_add_string(ac->msg, "defaultObjectCategory",
691                                                  ldb_dn_alloc_linearized(ac->msg, ac->dn));
692                         if (ret != LDB_SUCCESS) {
693                                 ldb_oom(ldb);
694                                 return ret;
695                         }
696                 }
697
698                 ret = samldb_add_step(ac, samldb_add_entry);
699                 if (ret != LDB_SUCCESS) return ret;
700
701                 /* Now perform the checks for the 'defaultObjectCategory'. The
702                  * lookup DN was already saved in "ac->dn" */
703                 ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
704                 if (ret != LDB_SUCCESS) return ret;
705
706                 /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
707                 if (v == -2) {
708                         /* Windows 2003 does this*/
709                         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "objectClassCategory", 0);
710                         if (ret != LDB_SUCCESS) {
711                                 return ret;
712                         }
713                 }
714                 break;
715         }
716
717         case SAMLDB_TYPE_ATTRIBUTE: {
718                 const struct ldb_val *rdn_value;
719                 struct ldb_message_element *el;
720                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
721                 if (rdn_value == NULL) {
722                         return ldb_operr(ldb);
723                 }
724                 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
725                         /* the RDN has prefix "CN" */
726                         ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
727                                 samdb_cn_to_lDAPDisplayName(ac->msg,
728                                                             (const char *) rdn_value->data));
729                         if (ret != LDB_SUCCESS) {
730                                 ldb_oom(ldb);
731                                 return ret;
732                         }
733                 }
734
735                 /* do not allow to mark an attributeSchema as RODC filtered if it
736                  * is system-critical */
737                 if (check_rodc_critical_attribute(ac->msg)) {
738                         ldb_asprintf_errstring(ldb,
739                                                "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
740                                                ldb_dn_get_linearized(ac->msg->dn));
741                         return LDB_ERR_UNWILLING_TO_PERFORM;
742                 }
743
744                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
745                                                   "isSingleValued", "FALSE");
746                 if (ret != LDB_SUCCESS) return ret;
747
748                 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
749                         struct GUID guid;
750                         /* a new GUID */
751                         guid = GUID_random();
752                         ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
753                         if (ret != LDB_SUCCESS) {
754                                 ldb_oom(ldb);
755                                 return ret;
756                         }
757                 }
758
759                 el = ldb_msg_find_element(ac->msg, "attributeSyntax");
760                 if (el) {
761                         /*
762                          * No need to scream if there isn't as we have code later on
763                          * that will take care of it.
764                          */
765                         const struct dsdb_syntax *syntax = find_syntax_map_by_ad_oid((const char *)el->values[0].data);
766                         if (!syntax) {
767                                 DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
768                                                 (const char *)el->values[0].data));
769                         } else {
770                                 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "oMSyntax", 0);
771                                 const struct ldb_val *val = ldb_msg_find_ldb_val(ac->msg, "oMObjectClass");
772
773                                 if (v == 0) {
774                                         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "oMSyntax", syntax->oMSyntax);
775                                         if (ret != LDB_SUCCESS) {
776                                                 return ret;
777                                         }
778                                 }
779                                 if (!val) {
780                                         struct ldb_val val2 = ldb_val_dup(ldb, &syntax->oMObjectClass);
781                                         if (val2.length > 0) {
782                                                 ret = ldb_msg_add_value(ac->msg, "oMObjectClass", &val2, NULL);
783                                                 if (ret != LDB_SUCCESS) {
784                                                         return ret;
785                                                 }
786                                         }
787                                 }
788                         }
789                 }
790
791                 /* handle msDS-IntID attribute */
792                 ret = samldb_add_handle_msDS_IntId(ac);
793                 if (ret != LDB_SUCCESS) return ret;
794
795                 ret = samldb_add_step(ac, samldb_add_entry);
796                 if (ret != LDB_SUCCESS) return ret;
797                 break;
798         }
799
800         default:
801                 ldb_asprintf_errstring(ldb, "Invalid entry type!");
802                 return LDB_ERR_OPERATIONS_ERROR;
803                 break;
804         }
805
806         return samldb_first_step(ac);
807 }
808
809 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
810 {
811         struct ldb_context *ldb;
812         const struct ldb_val *rdn_value;
813         struct dom_sid *sid;
814         int ret;
815
816         ldb = ldb_module_get_ctx(ac->module);
817
818         sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
819         if (sid == NULL) {
820                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
821                 if (rdn_value == NULL) {
822                         return ldb_operr(ldb);
823                 }
824                 sid = dom_sid_parse_talloc(ac->msg,
825                                            (const char *)rdn_value->data);
826                 if (sid == NULL) {
827                         ldb_set_errstring(ldb,
828                                           "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
829                         return LDB_ERR_CONSTRAINT_VIOLATION;
830                 }
831                 if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
832                         return ldb_operr(ldb);
833                 }
834         }
835
836         /* finally proceed with adding the entry */
837         ret = samldb_add_step(ac, samldb_add_entry);
838         if (ret != LDB_SUCCESS) return ret;
839
840         return samldb_first_step(ac);
841 }
842
843 static int samldb_schema_info_update(struct samldb_ctx *ac)
844 {
845         int ret;
846         struct ldb_context *ldb;
847         struct dsdb_schema *schema;
848
849         /* replicated update should always go through */
850         if (ldb_request_get_control(ac->req,
851                                     DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
852                 return LDB_SUCCESS;
853         }
854
855         /* do not update schemaInfo during provisioning */
856         if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
857                 return LDB_SUCCESS;
858         }
859
860         ldb = ldb_module_get_ctx(ac->module);
861         schema = dsdb_get_schema(ldb, NULL);
862         if (!schema) {
863                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
864                               "samldb_schema_info_update: no dsdb_schema loaded");
865                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
866                 return ldb_operr(ldb);
867         }
868
869         ret = dsdb_module_schema_info_update(ac->module, schema,
870                                              DSDB_FLAG_NEXT_MODULE|
871                                              DSDB_FLAG_AS_SYSTEM,
872                                              ac->req);
873         if (ret != LDB_SUCCESS) {
874                 ldb_asprintf_errstring(ldb,
875                                        "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
876                                        ldb_errstring(ldb));
877                 return ret;
878         }
879
880         return LDB_SUCCESS;
881 }
882
883 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
884
885 /*
886  * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
887  *
888  * Has to be invoked on "add" and "modify" operations on "user", "computer" and
889  * "group" objects.
890  * ac->msg contains the "add"/"modify" message
891  * ac->type contains the object type (main objectclass)
892  */
893 static int samldb_objectclass_trigger(struct samldb_ctx *ac)
894 {
895         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
896         void *skip_allocate_sids = ldb_get_opaque(ldb,
897                                                   "skip_allocate_sids");
898         struct ldb_message_element *el, *el2;
899         struct dom_sid *sid;
900         int ret;
901
902         /* make sure that "sAMAccountType" is not specified */
903         el = ldb_msg_find_element(ac->msg, "sAMAccountType");
904         if (el != NULL) {
905                 ldb_set_errstring(ldb,
906                                   "samldb: sAMAccountType must not be specified!");
907                 return LDB_ERR_UNWILLING_TO_PERFORM;
908         }
909
910         /* Step 1: objectSid assignment */
911
912         /* Don't allow the objectSid to be changed. But beside the RELAX
913          * control we have also to guarantee that it can always be set with
914          * SYSTEM permissions. This is needed for the "samba3sam" backend. */
915         sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
916         if ((sid != NULL) && (!dsdb_module_am_system(ac->module)) &&
917             (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
918                 ldb_set_errstring(ldb,
919                                   "samldb: objectSid must not be specified!");
920                 return LDB_ERR_UNWILLING_TO_PERFORM;
921         }
922
923         /* but generate a new SID when we do have an add operations */
924         if ((sid == NULL) && (ac->req->operation == LDB_ADD) && !skip_allocate_sids) {
925                 ret = samldb_add_step(ac, samldb_allocate_sid);
926                 if (ret != LDB_SUCCESS) return ret;
927         }
928
929         switch(ac->type) {
930         case SAMLDB_TYPE_USER: {
931                 bool uac_generated = false;
932
933                 /* Step 1.2: Default values */
934                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
935                         "accountExpires", "9223372036854775807");
936                 if (ret != LDB_SUCCESS) return ret;
937                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
938                         "badPasswordTime", "0");
939                 if (ret != LDB_SUCCESS) return ret;
940                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
941                         "badPwdCount", "0");
942                 if (ret != LDB_SUCCESS) return ret;
943                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
944                         "codePage", "0");
945                 if (ret != LDB_SUCCESS) return ret;
946                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
947                         "countryCode", "0");
948                 if (ret != LDB_SUCCESS) return ret;
949                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
950                         "lastLogoff", "0");
951                 if (ret != LDB_SUCCESS) return ret;
952                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
953                         "lastLogon", "0");
954                 if (ret != LDB_SUCCESS) return ret;
955                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
956                         "logonCount", "0");
957                 if (ret != LDB_SUCCESS) return ret;
958                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
959                         "pwdLastSet", "0");
960                 if (ret != LDB_SUCCESS) return ret;
961
962                 /* On add operations we might need to generate a
963                  * "userAccountControl" (if it isn't specified). */
964                 el = ldb_msg_find_element(ac->msg, "userAccountControl");
965                 if ((el == NULL) && (ac->req->operation == LDB_ADD)) {
966                         ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
967                                                  "userAccountControl",
968                                                  UF_NORMAL_ACCOUNT);
969                         if (ret != LDB_SUCCESS) {
970                                 return ret;
971                         }
972                         uac_generated = true;
973                 }
974
975                 el = ldb_msg_find_element(ac->msg, "userAccountControl");
976                 if (el != NULL) {
977                         uint32_t user_account_control, account_type;
978
979                         /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
980                         user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
981                                                                          "userAccountControl",
982                                                                          0);
983
984                         /* Temporary duplicate accounts aren't allowed */
985                         if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) != 0) {
986                                 return LDB_ERR_OTHER;
987                         }
988
989                         /* Workstation and (read-only) DC objects do need objectclass "computer" */
990                         if ((samdb_find_attribute(ldb, ac->msg,
991                                                   "objectclass", "computer") == NULL) &&
992                             (user_account_control &
993                              (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) {
994                                 ldb_set_errstring(ldb,
995                                                   "samldb: Requested account type does need objectclass 'computer'!");
996                                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
997                         }
998
999                         account_type = ds_uf2atype(user_account_control);
1000                         if (account_type == 0) {
1001                                 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1002                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1003                         }
1004                         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1005                                                  "sAMAccountType",
1006                                                  account_type);
1007                         if (ret != LDB_SUCCESS) {
1008                                 return ret;
1009                         }
1010                         el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1011                         el2->flags = LDB_FLAG_MOD_REPLACE;
1012
1013                         /* "isCriticalSystemObject" might be set */
1014                         if (user_account_control &
1015                             (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1016                                 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1017                                                          "TRUE");
1018                                 if (ret != LDB_SUCCESS) {
1019                                         return ret;
1020                                 }
1021                                 el2 = ldb_msg_find_element(ac->msg,
1022                                                            "isCriticalSystemObject");
1023                                 el2->flags = LDB_FLAG_MOD_REPLACE;
1024                         } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
1025                                 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1026                                                          "FALSE");
1027                                 if (ret != LDB_SUCCESS) {
1028                                         return ret;
1029                                 }
1030                                 el2 = ldb_msg_find_element(ac->msg,
1031                                                            "isCriticalSystemObject");
1032                                 el2->flags = LDB_FLAG_MOD_REPLACE;
1033                         }
1034
1035                         /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
1036                         if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1037                                 uint32_t rid = ds_uf2prim_group_rid(user_account_control);
1038
1039                                 /*
1040                                  * Older AD deployments don't know about the
1041                                  * RODC group
1042                                  */
1043                                 if (rid == DOMAIN_RID_READONLY_DCS) {
1044                                         ret = samldb_prim_group_tester(ac, rid);
1045                                         if (ret != LDB_SUCCESS) {
1046                                                 return ret;
1047                                         }
1048                                 }
1049
1050                                 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1051                                                          "primaryGroupID", rid);
1052                                 if (ret != LDB_SUCCESS) {
1053                                         return ret;
1054                                 }
1055                                 el2 = ldb_msg_find_element(ac->msg,
1056                                                            "primaryGroupID");
1057                                 el2->flags = LDB_FLAG_MOD_REPLACE;
1058                         }
1059
1060                         /* Step 1.5: Add additional flags when needed */
1061                         /* Obviously this is done when the "userAccountControl"
1062                          * has been generated here (tested against Windows
1063                          * Server) */
1064                         if (uac_generated) {
1065                                 user_account_control |= UF_ACCOUNTDISABLE;
1066                                 user_account_control |= UF_PASSWD_NOTREQD;
1067
1068                                 ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1069                                                          "userAccountControl",
1070                                                          user_account_control);
1071                                 if (ret != LDB_SUCCESS) {
1072                                         return ret;
1073                                 }
1074                         }
1075                 }
1076                 break;
1077         }
1078
1079         case SAMLDB_TYPE_GROUP: {
1080                 const char *tempstr;
1081
1082                 /* Step 2.2: Default values */
1083                 tempstr = talloc_asprintf(ac->msg, "%d",
1084                                           GTYPE_SECURITY_GLOBAL_GROUP);
1085                 if (tempstr == NULL) return ldb_operr(ldb);
1086                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
1087                         "groupType", tempstr);
1088                 if (ret != LDB_SUCCESS) return ret;
1089
1090                 /* Step 2.3: "groupType" -> "sAMAccountType" */
1091                 el = ldb_msg_find_element(ac->msg, "groupType");
1092                 if (el != NULL) {
1093                         uint32_t group_type, account_type;
1094
1095                         group_type = ldb_msg_find_attr_as_uint(ac->msg,
1096                                                                "groupType", 0);
1097
1098                         /* The creation of builtin groups requires the
1099                          * RELAX control */
1100                         if (group_type == GTYPE_SECURITY_BUILTIN_LOCAL_GROUP) {
1101                                 if (ldb_request_get_control(ac->req,
1102                                                             LDB_CONTROL_RELAX_OID) == NULL) {
1103                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1104                                 }
1105                         }
1106
1107                         account_type = ds_gtype2atype(group_type);
1108                         if (account_type == 0) {
1109                                 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1110                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1111                         }
1112                         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1113                                                  "sAMAccountType",
1114                                                  account_type);
1115                         if (ret != LDB_SUCCESS) {
1116                                 return ret;
1117                         }
1118                         el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1119                         el2->flags = LDB_FLAG_MOD_REPLACE;
1120                 }
1121                 break;
1122         }
1123
1124         default:
1125                 ldb_asprintf_errstring(ldb,
1126                                 "Invalid entry type!");
1127                 return LDB_ERR_OPERATIONS_ERROR;
1128                 break;
1129         }
1130
1131         return LDB_SUCCESS;
1132 }
1133
1134 /*
1135  * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
1136  *
1137  * Has to be invoked on "add" and "modify" operations on "user" and "computer"
1138  * objects.
1139  * ac->msg contains the "add"/"modify" message
1140  */
1141
1142 static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid)
1143 {
1144         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1145         struct dom_sid *sid;
1146         struct ldb_result *res;
1147         int ret;
1148         const char * const noattrs[] = { NULL };
1149
1150         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
1151         if (sid == NULL) {
1152                 return ldb_operr(ldb);
1153         }
1154
1155         ret = dsdb_module_search(ac->module, ac, &res,
1156                                  ldb_get_default_basedn(ldb),
1157                                  LDB_SCOPE_SUBTREE,
1158                                  noattrs, DSDB_FLAG_NEXT_MODULE,
1159                                  ac->req,
1160                                  "(objectSid=%s)",
1161                                  ldap_encode_ndr_dom_sid(ac, sid));
1162         if (ret != LDB_SUCCESS) {
1163                 return ret;
1164         }
1165         if (res->count != 1) {
1166                 talloc_free(res);
1167                 ldb_asprintf_errstring(ldb,
1168                                        "Failed to find primary group with RID %u!",
1169                                        rid);
1170                 return LDB_ERR_UNWILLING_TO_PERFORM;
1171         }
1172         talloc_free(res);
1173
1174         return LDB_SUCCESS;
1175 }
1176
1177 static int samldb_prim_group_set(struct samldb_ctx *ac)
1178 {
1179         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1180         uint32_t rid;
1181
1182         rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
1183         if (rid == (uint32_t) -1) {
1184                 /* we aren't affected of any primary group set */
1185                 return LDB_SUCCESS;
1186
1187         } else if (!ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1188                 ldb_set_errstring(ldb,
1189                                   "The primary group isn't settable on add operations!");
1190                 return LDB_ERR_UNWILLING_TO_PERFORM;
1191         }
1192
1193         return samldb_prim_group_tester(ac, rid);
1194 }
1195
1196 static int samldb_prim_group_change(struct samldb_ctx *ac)
1197 {
1198         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1199         const char * const attrs[] = { "primaryGroupID", "memberOf", NULL };
1200         struct ldb_result *res, *group_res;
1201         struct ldb_message_element *el;
1202         struct ldb_message *msg;
1203         uint32_t prev_rid, new_rid;
1204         struct dom_sid *prev_sid, *new_sid;
1205         struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
1206         int ret;
1207         const char * const noattrs[] = { NULL };
1208
1209         el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
1210                                          ac->req->operation);
1211         if (el == NULL) {
1212                 /* we are not affected */
1213                 return LDB_SUCCESS;
1214         }
1215
1216         /* Fetch information from the existing object */
1217
1218         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1219                                     DSDB_FLAG_NEXT_MODULE, ac->req);
1220         if (ret != LDB_SUCCESS) {
1221                 return ret;
1222         }
1223
1224         /* Finds out the DN of the old primary group */
1225
1226         prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
1227                                              (uint32_t) -1);
1228         if (prev_rid == (uint32_t) -1) {
1229                 /* User objects do always have a mandatory "primaryGroupID"
1230                  * attribute. If this doesn't exist then the object is of the
1231                  * wrong type. This is the exact Windows error code */
1232                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1233         }
1234
1235         prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
1236         if (prev_sid == NULL) {
1237                 return ldb_operr(ldb);
1238         }
1239
1240         /* Finds out the DN of the new primary group
1241          * Notice: in order to parse the primary group ID correctly we create
1242          * a temporary message here. */
1243
1244         msg = ldb_msg_new(ac->msg);
1245         if (msg == NULL) {
1246                 return ldb_module_oom(ac->module);
1247         }
1248         ret = ldb_msg_add(msg, el, 0);
1249         if (ret != LDB_SUCCESS) {
1250                 return ret;
1251         }
1252         new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
1253         talloc_free(msg);
1254         if (new_rid == (uint32_t) -1) {
1255                 /* we aren't affected of any primary group change */
1256                 return LDB_SUCCESS;
1257         }
1258
1259         if (prev_rid == new_rid) {
1260                 return LDB_SUCCESS;
1261         }
1262
1263         ret = dsdb_module_search(ac->module, ac, &group_res,
1264                                  ldb_get_default_basedn(ldb),
1265                                  LDB_SCOPE_SUBTREE,
1266                                  noattrs, DSDB_FLAG_NEXT_MODULE,
1267                                  ac->req,
1268                                  "(objectSid=%s)",
1269                                  ldap_encode_ndr_dom_sid(ac, prev_sid));
1270         if (ret != LDB_SUCCESS) {
1271                 return ret;
1272         }
1273         if (group_res->count != 1) {
1274                 return ldb_operr(ldb);
1275         }
1276         prev_prim_group_dn = group_res->msgs[0]->dn;
1277
1278         new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
1279         if (new_sid == NULL) {
1280                 return ldb_operr(ldb);
1281         }
1282
1283         ret = dsdb_module_search(ac->module, ac, &group_res,
1284                                  ldb_get_default_basedn(ldb),
1285                                  LDB_SCOPE_SUBTREE,
1286                                  noattrs, DSDB_FLAG_NEXT_MODULE,
1287                                  ac->req,
1288                                  "(objectSid=%s)",
1289                                  ldap_encode_ndr_dom_sid(ac, new_sid));
1290         if (ret != LDB_SUCCESS) {
1291                 return ret;
1292         }
1293         if (group_res->count != 1) {
1294                 /* Here we know if the specified new primary group candidate is
1295                  * valid or not. */
1296                 return LDB_ERR_UNWILLING_TO_PERFORM;
1297         }
1298         new_prim_group_dn = group_res->msgs[0]->dn;
1299
1300         /* We need to be already a normal member of the new primary
1301          * group in order to be successful. */
1302         el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
1303                                   ldb_dn_get_linearized(new_prim_group_dn));
1304         if (el == NULL) {
1305                 return LDB_ERR_UNWILLING_TO_PERFORM;
1306         }
1307
1308         /* Remove the "member" attribute on the new primary group */
1309         msg = ldb_msg_new(ac->msg);
1310         if (msg == NULL) {
1311                 return ldb_module_oom(ac->module);
1312         }
1313         msg->dn = new_prim_group_dn;
1314
1315         ret = samdb_msg_add_delval(ldb, msg, msg, "member",
1316                                    ldb_dn_get_linearized(ac->msg->dn));
1317         if (ret != LDB_SUCCESS) {
1318                 return ret;
1319         }
1320
1321         ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1322         if (ret != LDB_SUCCESS) {
1323                 return ret;
1324         }
1325         talloc_free(msg);
1326
1327         /* Add a "member" attribute for the previous primary group */
1328         msg = ldb_msg_new(ac->msg);
1329         if (msg == NULL) {
1330                 return ldb_module_oom(ac->module);
1331         }
1332         msg->dn = prev_prim_group_dn;
1333
1334         ret = samdb_msg_add_addval(ldb, msg, msg, "member",
1335                                    ldb_dn_get_linearized(ac->msg->dn));
1336         if (ret != LDB_SUCCESS) {
1337                 return ret;
1338         }
1339
1340         ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1341         if (ret != LDB_SUCCESS) {
1342                 return ret;
1343         }
1344         talloc_free(msg);
1345
1346         return LDB_SUCCESS;
1347 }
1348
1349 static int samldb_prim_group_trigger(struct samldb_ctx *ac)
1350 {
1351         int ret;
1352
1353         if (ac->req->operation == LDB_ADD) {
1354                 ret = samldb_prim_group_set(ac);
1355         } else {
1356                 ret = samldb_prim_group_change(ac);
1357         }
1358
1359         return ret;
1360 }
1361
1362
1363 /**
1364  * This function is called on LDB modify operations. It performs some additions/
1365  * replaces on the current LDB message when "userAccountControl" changes.
1366  */
1367 static int samldb_user_account_control_change(struct samldb_ctx *ac)
1368 {
1369         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1370         uint32_t user_account_control, old_user_account_control, account_type;
1371         struct ldb_message_element *el;
1372         struct ldb_message *tmp_msg;
1373         int ret;
1374         struct ldb_result *res;
1375         const char * const attrs[] = { "userAccountControl", "objectClass", NULL };
1376         unsigned int i;
1377         bool is_computer = false;
1378
1379         el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
1380                                          ac->req->operation);
1381         if (el == NULL) {
1382                 /* we are not affected */
1383                 return LDB_SUCCESS;
1384         }
1385
1386         /* Create a temporary message for fetching the "userAccountControl" */
1387         tmp_msg = ldb_msg_new(ac->msg);
1388         if (tmp_msg == NULL) {
1389                 return ldb_module_oom(ac->module);
1390         }
1391         ret = ldb_msg_add(tmp_msg, el, 0);
1392         if (ret != LDB_SUCCESS) {
1393                 return ret;
1394         }
1395         user_account_control = ldb_msg_find_attr_as_uint(tmp_msg,
1396                                                          "userAccountControl",
1397                                                          0);
1398         talloc_free(tmp_msg);
1399
1400         /* Temporary duplicate accounts aren't allowed */
1401         if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) != 0) {
1402                 return LDB_ERR_OTHER;
1403         }
1404
1405         /* Fetch the old "userAccountControl" and "objectClass" */
1406         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1407                                     DSDB_FLAG_NEXT_MODULE, ac->req);
1408         if (ret != LDB_SUCCESS) {
1409                 return ret;
1410         }
1411         old_user_account_control = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
1412         if (old_user_account_control == 0) {
1413                 return ldb_operr(ldb);
1414         }
1415         el = ldb_msg_find_element(res->msgs[0], "objectClass");
1416         if (el == NULL) {
1417                 return ldb_operr(ldb);
1418         }
1419
1420         /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
1421         for (i = 0; i < el->num_values; i++) {
1422                 if (ldb_attr_cmp((char *)el->values[i].data, "computer") == 0) {
1423                         is_computer = true;
1424                         break;
1425                 }
1426         }
1427         if (!is_computer &&
1428             (user_account_control & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT))) {
1429                 ldb_set_errstring(ldb,
1430                                   "samldb: Requested account type does need objectclass 'computer'!");
1431                 return LDB_ERR_UNWILLING_TO_PERFORM;
1432         }
1433
1434         /*
1435          * The functions "ds_uf2atype" and "ds_uf2prim_group_rid" are used as
1436          * detectors for account type changes.
1437          * So if the account type does change then we need to adjust the
1438          * "sAMAccountType", the "isCriticalSystemObject" and the
1439          * "primaryGroupID" attribute.
1440          */
1441         if ((ds_uf2atype(user_account_control)
1442              == ds_uf2atype(old_user_account_control)) &&
1443             (ds_uf2prim_group_rid(user_account_control)
1444              == ds_uf2prim_group_rid(old_user_account_control))) {
1445                 return LDB_SUCCESS;
1446         }
1447
1448         account_type = ds_uf2atype(user_account_control);
1449         if (account_type == 0) {
1450                 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1451                 return LDB_ERR_UNWILLING_TO_PERFORM;
1452         }
1453         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
1454                                  account_type);
1455         if (ret != LDB_SUCCESS) {
1456                 return ret;
1457         }
1458         el = ldb_msg_find_element(ac->msg, "sAMAccountType");
1459         el->flags = LDB_FLAG_MOD_REPLACE;
1460
1461         /* "isCriticalSystemObject" might be set/changed */
1462         if (user_account_control
1463             & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1464                 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1465                                          "TRUE");
1466                 if (ret != LDB_SUCCESS) {
1467                         return ret;
1468                 }
1469                 el = ldb_msg_find_element(ac->msg,
1470                                            "isCriticalSystemObject");
1471                 el->flags = LDB_FLAG_MOD_REPLACE;
1472         } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
1473                 ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1474                                          "FALSE");
1475                 if (ret != LDB_SUCCESS) {
1476                         return ret;
1477                 }
1478                 el = ldb_msg_find_element(ac->msg,
1479                                            "isCriticalSystemObject");
1480                 el->flags = LDB_FLAG_MOD_REPLACE;
1481         }
1482
1483         if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1484                 uint32_t rid = ds_uf2prim_group_rid(user_account_control);
1485
1486                 /* Older AD deployments don't know about the RODC group */
1487                 if (rid == DOMAIN_RID_READONLY_DCS) {
1488                         ret = samldb_prim_group_tester(ac, rid);
1489                         if (ret != LDB_SUCCESS) {
1490                                 return ret;
1491                         }
1492                 }
1493
1494                 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1495                                          "primaryGroupID", rid);
1496                 if (ret != LDB_SUCCESS) {
1497                         return ret;
1498                 }
1499                 el = ldb_msg_find_element(ac->msg,
1500                                            "primaryGroupID");
1501                 el->flags = LDB_FLAG_MOD_REPLACE;
1502         }
1503
1504         return LDB_SUCCESS;
1505 }
1506
1507 static int samldb_group_type_change(struct samldb_ctx *ac)
1508 {
1509         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1510         uint32_t group_type, old_group_type, account_type;
1511         struct ldb_message_element *el;
1512         struct ldb_message *tmp_msg;
1513         int ret;
1514         struct ldb_result *res;
1515         const char * const attrs[] = { "groupType", NULL };
1516
1517         el = dsdb_get_single_valued_attr(ac->msg, "groupType",
1518                                          ac->req->operation);
1519         if (el == NULL) {
1520                 /* we are not affected */
1521                 return LDB_SUCCESS;
1522         }
1523
1524         /* Create a temporary message for fetching the "groupType" */
1525         tmp_msg = ldb_msg_new(ac->msg);
1526         if (tmp_msg == NULL) {
1527                 return ldb_module_oom(ac->module);
1528         }
1529         ret = ldb_msg_add(tmp_msg, el, 0);
1530         if (ret != LDB_SUCCESS) {
1531                 return ret;
1532         }
1533         group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
1534         talloc_free(tmp_msg);
1535
1536         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1537                                     DSDB_FLAG_NEXT_MODULE |
1538                                     DSDB_SEARCH_SHOW_DELETED, ac->req);
1539         if (ret != LDB_SUCCESS) {
1540                 return ret;
1541         }
1542         old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
1543         if (old_group_type == 0) {
1544                 return ldb_operr(ldb);
1545         }
1546
1547         /* Group type switching isn't so easy as it seems: We can only
1548          * change in this directions: global <-> universal <-> local
1549          * On each step also the group type itself
1550          * (security/distribution) is variable. */
1551
1552         if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
1553                 switch (group_type) {
1554                 case GTYPE_SECURITY_GLOBAL_GROUP:
1555                 case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
1556                         /* change to "universal" allowed */
1557                         if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
1558                         (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
1559                                 ldb_set_errstring(ldb,
1560                                         "samldb: Change from security/distribution local group forbidden!");
1561                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1562                         }
1563                 break;
1564
1565                 case GTYPE_SECURITY_UNIVERSAL_GROUP:
1566                 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
1567                         /* each change allowed */
1568                 break;
1569                 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
1570                 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
1571                         /* change to "universal" allowed */
1572                         if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
1573                         (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
1574                                 ldb_set_errstring(ldb,
1575                                         "samldb: Change from security/distribution global group forbidden!");
1576                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1577                         }
1578                 break;
1579
1580                 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
1581                 default:
1582                         /* we don't allow this "groupType" values */
1583                         return LDB_ERR_UNWILLING_TO_PERFORM;
1584                 break;
1585                 }
1586         }
1587
1588         account_type =  ds_gtype2atype(group_type);
1589         if (account_type == 0) {
1590                 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1591                 return LDB_ERR_UNWILLING_TO_PERFORM;
1592         }
1593         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
1594                                  account_type);
1595         if (ret != LDB_SUCCESS) {
1596                 return ret;
1597         }
1598         el = ldb_msg_find_element(ac->msg, "sAMAccountType");
1599         el->flags = LDB_FLAG_MOD_REPLACE;
1600
1601         return LDB_SUCCESS;
1602 }
1603
1604 static int samldb_sam_accountname_check(struct samldb_ctx *ac)
1605 {
1606         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1607         const char * const no_attrs[] = { NULL };
1608         struct ldb_result *res;
1609         const char *sam_accountname, *enc_str;
1610         struct ldb_message_element *el;
1611         struct ldb_message *tmp_msg;
1612         int ret;
1613
1614         el = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
1615                                          ac->req->operation);
1616         if (el == NULL) {
1617                 /* we are not affected */
1618                 return LDB_SUCCESS;
1619         }
1620
1621         /* Create a temporary message for fetching the "sAMAccountName" */
1622         tmp_msg = ldb_msg_new(ac->msg);
1623         if (tmp_msg == NULL) {
1624                 return ldb_module_oom(ac->module);
1625         }
1626         ret = ldb_msg_add(tmp_msg, el, 0);
1627         if (ret != LDB_SUCCESS) {
1628                 return ret;
1629         }
1630         sam_accountname = talloc_steal(ac,
1631                                        ldb_msg_find_attr_as_string(tmp_msg, "sAMAccountName", NULL));
1632         talloc_free(tmp_msg);
1633
1634         if (sam_accountname == NULL) {
1635                 /* The "sAMAccountName" cannot be nothing */
1636                 ldb_set_errstring(ldb,
1637                                   "samldb: Empty account names aren't allowed!");
1638                 return LDB_ERR_UNWILLING_TO_PERFORM;
1639         }
1640
1641         enc_str = ldb_binary_encode_string(ac, sam_accountname);
1642         if (enc_str == NULL) {
1643                 return ldb_module_oom(ac->module);
1644         }
1645
1646         /* Make sure that a "sAMAccountName" is only used once */
1647
1648         ret = dsdb_module_search(ac->module, ac, &res,
1649                                  ldb_get_default_basedn(ldb),
1650                                  LDB_SCOPE_SUBTREE, no_attrs,
1651                                  DSDB_FLAG_NEXT_MODULE, ac->req,
1652                                  "(sAMAccountName=%s)", enc_str);
1653         if (ret != LDB_SUCCESS) {
1654                 return ret;
1655         }
1656         if (res->count > 1) {
1657                 return ldb_operr(ldb);
1658         } else if (res->count == 1) {
1659                 if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0) {
1660                         ldb_asprintf_errstring(ldb,
1661                                                "samldb: Account name (sAMAccountName) '%s' already in use!",
1662                                                sam_accountname);
1663                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1664                 }
1665         }
1666         talloc_free(res);
1667
1668         return LDB_SUCCESS;
1669 }
1670
1671 static int samldb_member_check(struct samldb_ctx *ac)
1672 {
1673         const char * const attrs[] = { "objectSid", "member", NULL };
1674         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1675         struct ldb_message_element *el;
1676         struct ldb_dn *member_dn;
1677         struct dom_sid *sid;
1678         struct ldb_result *res;
1679         struct dom_sid *group_sid;
1680         unsigned int i, j;
1681         int ret;
1682
1683         /* Fetch information from the existing object */
1684
1685         ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
1686                                  DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
1687         if (ret != LDB_SUCCESS) {
1688                 return ret;
1689         }
1690         if (res->count != 1) {
1691                 return ldb_operr(ldb);
1692         }
1693
1694         group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
1695         if (group_sid == NULL) {
1696                 return ldb_operr(ldb);
1697         }
1698
1699         /* We've to walk over all modification entries and consider the "member"
1700          * ones. */
1701         for (i = 0; i < ac->msg->num_elements; i++) {
1702                 if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
1703                         continue;
1704                 }
1705
1706                 el = &ac->msg->elements[i];
1707                 for (j = 0; j < el->num_values; j++) {
1708                         struct ldb_result *group_res;
1709                         const char *group_attrs[] = { "primaryGroupID" , NULL };
1710                         uint32_t prim_group_rid;
1711
1712                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1713                                 /* Deletes will be handled in
1714                                  * repl_meta_data, and deletes not
1715                                  * matching a member will return
1716                                  * LDB_ERR_UNWILLING_TO_PERFORM
1717                                  * there */
1718                                 continue;
1719                         }
1720
1721                         member_dn = ldb_dn_from_ldb_val(ac, ldb,
1722                                                         &el->values[j]);
1723                         if (!ldb_dn_validate(member_dn)) {
1724                                 return ldb_operr(ldb);
1725                         }
1726
1727                         /* Denies to add "member"s to groups which are primary
1728                          * ones for them - in this case return
1729                          * ERR_ENTRY_ALREADY_EXISTS. */
1730
1731                         ret = dsdb_module_search_dn(ac->module, ac, &group_res,
1732                                                     member_dn, group_attrs,
1733                                                     DSDB_FLAG_NEXT_MODULE, ac->req);
1734                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1735                                 /* member DN doesn't exist yet */
1736                                 continue;
1737                         }
1738                         if (ret != LDB_SUCCESS) {
1739                                 return ret;
1740                         }
1741                         prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
1742                         if (prim_group_rid == (uint32_t) -1) {
1743                                 /* the member hasn't to be a user account ->
1744                                  * therefore no check needed in this case. */
1745                                 continue;
1746                         }
1747
1748                         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
1749                                               prim_group_rid);
1750                         if (sid == NULL) {
1751                                 return ldb_operr(ldb);
1752                         }
1753
1754                         if (dom_sid_equal(group_sid, sid)) {
1755                                 ldb_asprintf_errstring(ldb,
1756                                                        "samldb: member %s already set via primaryGroupID %u",
1757                                                        ldb_dn_get_linearized(member_dn), prim_group_rid);
1758                                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
1759                         }
1760                 }
1761         }
1762
1763         talloc_free(res);
1764
1765         return LDB_SUCCESS;
1766 }
1767
1768 /* SAM objects have special rules regarding the "description" attribute on
1769  * modify operations. */
1770 static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
1771 {
1772         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1773         const char * const attrs[] = { "objectClass", "description", NULL };
1774         struct ldb_result *res;
1775         unsigned int i;
1776         int ret;
1777
1778         /* Fetch information from the existing object */
1779         ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
1780                                  DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
1781                                  "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
1782         if (ret != LDB_SUCCESS) {
1783                 /* don't treat it specially ... let normal error codes
1784                    happen from other places */
1785                 ldb_reset_err_string(ldb);
1786                 return LDB_SUCCESS;
1787         }
1788         if (res->count == 0) {
1789                 /* we didn't match the filter */
1790                 talloc_free(res);
1791                 return LDB_SUCCESS;
1792         }
1793
1794         /* We've to walk over all modification entries and consider the
1795          * "description" ones. */
1796         for (i = 0; i < ac->msg->num_elements; i++) {
1797                 if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
1798                         ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
1799                         *modified = true;
1800                 }
1801         }
1802
1803         talloc_free(res);
1804
1805         return LDB_SUCCESS;
1806 }
1807
1808 /* This trigger adapts the "servicePrincipalName" attributes if the
1809  * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
1810 static int samldb_service_principal_names_change(struct samldb_ctx *ac)
1811 {
1812         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1813         struct ldb_message_element *el = NULL, *el2 = NULL;
1814         struct ldb_message *msg;
1815         const char * const attrs[] = { "servicePrincipalName", NULL };
1816         struct ldb_result *res;
1817         const char *dns_hostname = NULL, *old_dns_hostname = NULL,
1818                    *sam_accountname = NULL, *old_sam_accountname = NULL;
1819         unsigned int i, j;
1820         int ret;
1821
1822         el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
1823                                          ac->req->operation);
1824         el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
1825                                           ac->req->operation);
1826         if ((el == NULL) && (el2 == NULL)) {
1827                 /* we are not affected */
1828                 return LDB_SUCCESS;
1829         }
1830
1831         /* Create a temporary message for fetching the "dNSHostName" */
1832         if (el != NULL) {
1833                 const char *dns_attrs[] = { "dNSHostName", NULL };
1834                 msg = ldb_msg_new(ac->msg);
1835                 if (msg == NULL) {
1836                         return ldb_module_oom(ac->module);
1837                 }
1838                 ret = ldb_msg_add(msg, el, 0);
1839                 if (ret != LDB_SUCCESS) {
1840                         return ret;
1841                 }
1842                 dns_hostname = talloc_steal(ac,
1843                                             ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
1844                 talloc_free(msg);
1845
1846                 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
1847                                             dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
1848                 if (ret == LDB_SUCCESS) {
1849                         old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
1850                 }
1851         }
1852
1853         /* Create a temporary message for fetching the "sAMAccountName" */
1854         if (el2 != NULL) {
1855                 char *tempstr, *tempstr2;
1856                 const char *acct_attrs[] = { "sAMAccountName", NULL };
1857
1858                 msg = ldb_msg_new(ac->msg);
1859                 if (msg == NULL) {
1860                         return ldb_module_oom(ac->module);
1861                 }
1862                 ret = ldb_msg_add(msg, el2, 0);
1863                 if (ret != LDB_SUCCESS) {
1864                         return ret;
1865                 }
1866                 tempstr = talloc_strdup(ac,
1867                                         ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
1868                 talloc_free(msg);
1869
1870                 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
1871                                             DSDB_FLAG_NEXT_MODULE, ac->req);
1872                 if (ret == LDB_SUCCESS) {
1873                         tempstr2 = talloc_strdup(ac,
1874                                                  ldb_msg_find_attr_as_string(res->msgs[0],
1875                                                                              "sAMAccountName", NULL));
1876                 }
1877
1878
1879                 /* The "sAMAccountName" needs some additional trimming: we need
1880                  * to remove the trailing "$"s if they exist. */
1881                 if ((tempstr != NULL) && (tempstr[0] != '\0') &&
1882                     (tempstr[strlen(tempstr) - 1] == '$')) {
1883                         tempstr[strlen(tempstr) - 1] = '\0';
1884                 }
1885                 if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
1886                     (tempstr2[strlen(tempstr2) - 1] == '$')) {
1887                         tempstr2[strlen(tempstr2) - 1] = '\0';
1888                 }
1889                 sam_accountname = tempstr;
1890                 old_sam_accountname = tempstr2;
1891         }
1892
1893         if (old_dns_hostname == NULL) {
1894                 /* we cannot change when the old name is unknown */
1895                 dns_hostname = NULL;
1896         }
1897         if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
1898             (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
1899                 /* The "dNSHostName" didn't change */
1900                 dns_hostname = NULL;
1901         }
1902
1903         if (old_sam_accountname == NULL) {
1904                 /* we cannot change when the old name is unknown */
1905                 sam_accountname = NULL;
1906         }
1907         if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
1908             (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
1909                 /* The "sAMAccountName" didn't change */
1910                 sam_accountname = NULL;
1911         }
1912
1913         if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
1914                 /* Well, there are information missing (old name(s)) or the
1915                  * names didn't change. We've nothing to do and can exit here */
1916                 return LDB_SUCCESS;
1917         }
1918
1919         /* Potential "servicePrincipalName" changes in the same request have to
1920          * be handled before the update (Windows behaviour). */
1921         el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
1922         if (el != NULL) {
1923                 msg = ldb_msg_new(ac->msg);
1924                 if (msg == NULL) {
1925                         return ldb_module_oom(ac->module);
1926                 }
1927                 msg->dn = ac->msg->dn;
1928
1929                 do {
1930                         ret = ldb_msg_add(msg, el, el->flags);
1931                         if (ret != LDB_SUCCESS) {
1932                                 return ret;
1933                         }
1934
1935                         ldb_msg_remove_element(ac->msg, el);
1936
1937                         el = ldb_msg_find_element(ac->msg,
1938                                                   "servicePrincipalName");
1939                 } while (el != NULL);
1940
1941                 ret = dsdb_module_modify(ac->module, msg,
1942                                          DSDB_FLAG_NEXT_MODULE, ac->req);
1943                 if (ret != LDB_SUCCESS) {
1944                         return ret;
1945                 }
1946                 talloc_free(msg);
1947         }
1948
1949         /* Fetch the "servicePrincipalName"s if any */
1950         ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
1951                                  DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
1952         if (ret != LDB_SUCCESS) {
1953                 return ret;
1954         }
1955         if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
1956                 return ldb_operr(ldb);
1957         }
1958
1959         if (res->msgs[0]->num_elements == 1) {
1960                 /*
1961                  * Yes, we do have "servicePrincipalName"s. First we update them
1962                  * locally, that means we do always substitute the current
1963                  * "dNSHostName" with the new one and/or "sAMAccountName"
1964                  * without "$" with the new one and then we append the
1965                  * modified "servicePrincipalName"s as a message element
1966                  * replace to the modification request (Windows behaviour). We
1967                  * need also to make sure that the values remain case-
1968                  * insensitively unique.
1969                  */
1970
1971                 ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
1972                                         LDB_FLAG_MOD_REPLACE, &el);
1973                 if (ret != LDB_SUCCESS) {
1974                         return ret;
1975                 }
1976
1977                 for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
1978                         char *old_str, *new_str, *pos;
1979                         const char *tok;
1980                         struct ldb_val *vals;
1981                         bool found = false;
1982
1983                         old_str = (char *)
1984                                 res->msgs[0]->elements[0].values[i].data;
1985
1986                         new_str = talloc_strdup(ac->msg,
1987                                                 strtok_r(old_str, "/", &pos));
1988                         if (new_str == NULL) {
1989                                 return ldb_module_oom(ac->module);
1990                         }
1991
1992                         while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
1993                                 if ((dns_hostname != NULL) &&
1994                                     (strcasecmp_m(tok, old_dns_hostname) == 0)) {
1995                                         tok = dns_hostname;
1996                                 }
1997                                 if ((sam_accountname != NULL) &&
1998                                     (strcasecmp_m(tok, old_sam_accountname) == 0)) {
1999                                         tok = sam_accountname;
2000                                 }
2001
2002                                 new_str = talloc_asprintf(ac->msg, "%s/%s",
2003                                                           new_str, tok);
2004                                 if (new_str == NULL) {
2005                                         return ldb_module_oom(ac->module);
2006                                 }
2007                         }
2008
2009                         /* Uniqueness check */
2010                         for (j = 0; (!found) && (j < el->num_values); j++) {
2011                                 if (strcasecmp_m((char *)el->values[j].data,
2012                                                new_str) == 0) {
2013                                         found = true;
2014                                 }
2015                         }
2016                         if (found) {
2017                                 continue;
2018                         }
2019
2020                         /*
2021                          * append the new "servicePrincipalName" -
2022                          * code derived from ldb_msg_add_value().
2023                          *
2024                          * Open coded to make it clear that we must
2025                          * append to the MOD_REPLACE el created above.
2026                          */
2027                         vals = talloc_realloc(ac->msg, el->values,
2028                                               struct ldb_val,
2029                                               el->num_values + 1);
2030                         if (vals == NULL) {
2031                                 return ldb_module_oom(ac->module);
2032                         }
2033                         el->values = vals;
2034                         el->values[el->num_values] = data_blob_string_const(new_str);
2035                         ++(el->num_values);
2036                 }
2037         }
2038
2039         talloc_free(res);
2040
2041         return LDB_SUCCESS;
2042 }
2043
2044 /* This checks the "fSMORoleOwner" attributes */
2045 static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
2046 {
2047         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2048         const char * const no_attrs[] = { NULL };
2049         struct ldb_message_element *el;
2050         struct ldb_message *tmp_msg;
2051         struct ldb_dn *res_dn;
2052         struct ldb_result *res;
2053         int ret;
2054
2055         el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
2056                                          ac->req->operation);
2057         if (el == NULL) {
2058                 /* we are not affected */
2059                 return LDB_SUCCESS;
2060         }
2061
2062         /* Create a temporary message for fetching the "fSMORoleOwner" */
2063         tmp_msg = ldb_msg_new(ac->msg);
2064         if (tmp_msg == NULL) {
2065                 return ldb_module_oom(ac->module);
2066         }
2067         ret = ldb_msg_add(tmp_msg, el, 0);
2068         if (ret != LDB_SUCCESS) {
2069                 return ret;
2070         }
2071         res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
2072         talloc_free(tmp_msg);
2073
2074         if (res_dn == NULL) {
2075                 ldb_set_errstring(ldb,
2076                                   "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
2077                 if (ac->req->operation == LDB_ADD) {
2078                         return LDB_ERR_CONSTRAINT_VIOLATION;
2079                 } else {
2080                         return LDB_ERR_UNWILLING_TO_PERFORM;
2081                 }
2082         }
2083
2084         /* Fetched DN has to reference a "nTDSDSA" entry */
2085         ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
2086                                  no_attrs,
2087                                  DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2088                                  ac->req, "(objectClass=nTDSDSA)");
2089         if (ret != LDB_SUCCESS) {
2090                 return ret;
2091         }
2092         if (res->count != 1) {
2093                 ldb_set_errstring(ldb,
2094                                   "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
2095                 return LDB_ERR_UNWILLING_TO_PERFORM;
2096         }
2097
2098         talloc_free(res);
2099
2100         return LDB_SUCCESS;
2101 }
2102
2103
2104 /* add */
2105 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
2106 {
2107         struct ldb_context *ldb;
2108         struct samldb_ctx *ac;
2109         struct ldb_message_element *el;
2110         int ret;
2111
2112         ldb = ldb_module_get_ctx(module);
2113         ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
2114
2115         /* do not manipulate our control entries */
2116         if (ldb_dn_is_special(req->op.add.message->dn)) {
2117                 return ldb_next_request(module, req);
2118         }
2119
2120         ac = samldb_ctx_init(module, req);
2121         if (ac == NULL) {
2122                 return ldb_operr(ldb);
2123         }
2124
2125         /* build the new msg */
2126         ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
2127         if (ac->msg == NULL) {
2128                 talloc_free(ac);
2129                 ldb_debug(ldb, LDB_DEBUG_FATAL,
2130                           "samldb_add: ldb_msg_copy_shallow failed!\n");
2131                 return ldb_operr(ldb);
2132         }
2133
2134         el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
2135         if (el != NULL) {
2136                 ret = samldb_fsmo_role_owner_check(ac);
2137                 if (ret != LDB_SUCCESS) {
2138                         return ret;
2139                 }
2140         }
2141
2142         if (samdb_find_attribute(ldb, ac->msg,
2143                                  "objectclass", "user") != NULL) {
2144                 ac->type = SAMLDB_TYPE_USER;
2145
2146                 ret = samldb_prim_group_trigger(ac);
2147                 if (ret != LDB_SUCCESS) {
2148                         return ret;
2149                 }
2150
2151                 ret = samldb_objectclass_trigger(ac);
2152                 if (ret != LDB_SUCCESS) {
2153                         return ret;
2154                 }
2155
2156                 return samldb_fill_object(ac);
2157         }
2158
2159         if (samdb_find_attribute(ldb, ac->msg,
2160                                  "objectclass", "group") != NULL) {
2161                 ac->type = SAMLDB_TYPE_GROUP;
2162
2163                 ret = samldb_objectclass_trigger(ac);
2164                 if (ret != LDB_SUCCESS) {
2165                         return ret;
2166                 }
2167
2168                 return samldb_fill_object(ac);
2169         }
2170
2171         /* perhaps a foreignSecurityPrincipal? */
2172         if (samdb_find_attribute(ldb, ac->msg,
2173                                  "objectclass",
2174                                  "foreignSecurityPrincipal") != NULL) {
2175                 return samldb_fill_foreignSecurityPrincipal_object(ac);
2176         }
2177
2178         if (samdb_find_attribute(ldb, ac->msg,
2179                                  "objectclass", "classSchema") != NULL) {
2180                 ret = samldb_schema_info_update(ac);
2181                 if (ret != LDB_SUCCESS) {
2182                         talloc_free(ac);
2183                         return ret;
2184                 }
2185
2186                 ac->type = SAMLDB_TYPE_CLASS;
2187                 return samldb_fill_object(ac);
2188         }
2189
2190         if (samdb_find_attribute(ldb, ac->msg,
2191                                  "objectclass", "attributeSchema") != NULL) {
2192                 ret = samldb_schema_info_update(ac);
2193                 if (ret != LDB_SUCCESS) {
2194                         talloc_free(ac);
2195                         return ret;
2196                 }
2197
2198                 ac->type = SAMLDB_TYPE_ATTRIBUTE;
2199                 return samldb_fill_object(ac);
2200         }
2201
2202         talloc_free(ac);
2203
2204         /* nothing matched, go on */
2205         return ldb_next_request(module, req);
2206 }
2207
2208 /* modify */
2209 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
2210 {
2211         struct ldb_context *ldb;
2212         struct samldb_ctx *ac;
2213         struct ldb_message_element *el, *el2;
2214         bool modified = false;
2215         int ret;
2216
2217         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2218                 /* do not manipulate our control entries */
2219                 return ldb_next_request(module, req);
2220         }
2221
2222         ldb = ldb_module_get_ctx(module);
2223
2224         /* make sure that "objectSid" is not specified */
2225         el = ldb_msg_find_element(req->op.mod.message, "objectSid");
2226         if (el != NULL) {
2227                 if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
2228                         ldb_set_errstring(ldb,
2229                                           "samldb: objectSid must not be specified!");
2230                         return LDB_ERR_UNWILLING_TO_PERFORM;
2231                 }
2232         }
2233         /* make sure that "sAMAccountType" is not specified */
2234         el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
2235         if (el != NULL) {
2236                 ldb_set_errstring(ldb,
2237                                   "samldb: sAMAccountType must not be specified!");
2238                 return LDB_ERR_UNWILLING_TO_PERFORM;
2239         }
2240         /* make sure that "isCriticalSystemObject" is not specified */
2241         el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
2242         if (el != NULL) {
2243                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
2244                         ldb_set_errstring(ldb,
2245                                           "samldb: isCriticalSystemObject must not be specified!");
2246                         return LDB_ERR_UNWILLING_TO_PERFORM;
2247                 }
2248         }
2249
2250         /* msDS-IntId is not allowed to be modified
2251          * except when modification comes from replication */
2252         if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
2253                 if (!ldb_request_get_control(req,
2254                                              DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
2255                         return LDB_ERR_CONSTRAINT_VIOLATION;
2256                 }
2257         }
2258
2259         ac = samldb_ctx_init(module, req);
2260         if (ac == NULL) {
2261                 return ldb_operr(ldb);
2262         }
2263
2264         /* build the new msg */
2265         ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2266         if (ac->msg == NULL) {
2267                 talloc_free(ac);
2268                 ldb_debug(ldb, LDB_DEBUG_FATAL,
2269                           "samldb_modify: ldb_msg_copy_shallow failed!\n");
2270                 return ldb_operr(ldb);
2271         }
2272
2273         el = ldb_msg_find_element(ac->msg, "primaryGroupID");
2274         if (el != NULL) {
2275                 ret = samldb_prim_group_trigger(ac);
2276                 if (ret != LDB_SUCCESS) {
2277                         return ret;
2278                 }
2279         }
2280
2281         el = ldb_msg_find_element(ac->msg, "userAccountControl");
2282         if (el != NULL) {
2283                 modified = true;
2284                 ret = samldb_user_account_control_change(ac);
2285                 if (ret != LDB_SUCCESS) {
2286                         return ret;
2287                 }
2288         }
2289
2290         el = ldb_msg_find_element(ac->msg, "groupType");
2291         if (el != NULL) {
2292                 modified = true;
2293                 ret = samldb_group_type_change(ac);
2294                 if (ret != LDB_SUCCESS) {
2295                         return ret;
2296                 }
2297         }
2298
2299         el = ldb_msg_find_element(ac->msg, "sAMAccountName");
2300         if (el != NULL) {
2301                 ret = samldb_sam_accountname_check(ac);
2302                 if (ret != LDB_SUCCESS) {
2303                         return ret;
2304                 }
2305         }
2306
2307         el = ldb_msg_find_element(ac->msg, "member");
2308         if (el != NULL) {
2309                 ret = samldb_member_check(ac);
2310                 if (ret != LDB_SUCCESS) {
2311                         return ret;
2312                 }
2313         }
2314
2315         el = ldb_msg_find_element(ac->msg, "description");
2316         if (el != NULL) {
2317                 ret = samldb_description_check(ac, &modified);
2318                 if (ret != LDB_SUCCESS) {
2319                         return ret;
2320                 }
2321         }
2322
2323         el = ldb_msg_find_element(ac->msg, "dNSHostName");
2324         el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
2325         if ((el != NULL) || (el2 != NULL)) {
2326                 modified = true;
2327                 ret = samldb_service_principal_names_change(ac);
2328                 if (ret != LDB_SUCCESS) {
2329                         return ret;
2330                 }
2331         }
2332
2333         el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
2334         if (el != NULL) {
2335                 ret = samldb_fsmo_role_owner_check(ac);
2336                 if (ret != LDB_SUCCESS) {
2337                         return ret;
2338                 }
2339         }
2340
2341         if (modified) {
2342                 struct ldb_request *child_req;
2343
2344                 /* Now perform the real modifications as a child request */
2345                 ret = ldb_build_mod_req(&child_req, ldb, ac,
2346                                         ac->msg,
2347                                         req->controls,
2348                                         req, dsdb_next_callback,
2349                                         req);
2350                 LDB_REQ_SET_LOCATION(child_req);
2351                 if (ret != LDB_SUCCESS) {
2352                         return ret;
2353                 }
2354
2355                 return ldb_next_request(module, child_req);
2356         }
2357
2358         talloc_free(ac);
2359
2360         /* no change which interests us, go on */
2361         return ldb_next_request(module, req);
2362 }
2363
2364 /* delete */
2365
2366 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
2367 {
2368         struct ldb_context *ldb;
2369         struct dom_sid *sid;
2370         uint32_t rid;
2371         NTSTATUS status;
2372         int ret;
2373         struct ldb_result *res;
2374         const char * const attrs[] = { "objectSid", "isDeleted", NULL };
2375         const char * const noattrs[] = { NULL };
2376
2377         ldb = ldb_module_get_ctx(ac->module);
2378
2379         /* Finds out the SID/RID of the SAM object */
2380         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
2381                                         attrs,
2382                                         DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2383                                         ac->req);
2384         if (ret != LDB_SUCCESS) {
2385                 return ret;
2386         }
2387
2388         if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
2389                 return LDB_SUCCESS;
2390         }
2391
2392         sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
2393         if (sid == NULL) {
2394                 /* No SID - it might not be a SAM object - therefore ok */
2395                 return LDB_SUCCESS;
2396         }
2397         status = dom_sid_split_rid(ac, sid, NULL, &rid);
2398         if (!NT_STATUS_IS_OK(status)) {
2399                 return ldb_operr(ldb);
2400         }
2401         if (rid == 0) {
2402                 /* Special object (security principal?) */
2403                 return LDB_SUCCESS;
2404         }
2405
2406         /* Deny delete requests from groups which are primary ones */
2407         ret = dsdb_module_search(ac->module, ac, &res,
2408                                  ldb_get_default_basedn(ldb),
2409                                  LDB_SCOPE_SUBTREE, noattrs,
2410                                  DSDB_FLAG_NEXT_MODULE,
2411                                  ac->req,
2412                                  "(&(primaryGroupID=%u)(objectClass=user))", rid);
2413         if (ret != LDB_SUCCESS) {
2414                 return ret;
2415         }
2416         if (res->count > 0) {
2417                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
2418         }
2419
2420         return LDB_SUCCESS;
2421 }
2422
2423 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
2424 {
2425         struct samldb_ctx *ac;
2426         int ret;
2427
2428         if (ldb_dn_is_special(req->op.del.dn)) {
2429                 /* do not manipulate our control entries */
2430                 return ldb_next_request(module, req);
2431         }
2432
2433         ac = samldb_ctx_init(module, req);
2434         if (ac == NULL) {
2435                 return ldb_operr(ldb_module_get_ctx(module));
2436         }
2437
2438         ret = samldb_prim_group_users_check(ac);
2439         if (ret != LDB_SUCCESS) {
2440                 return ret;
2441         }
2442
2443         talloc_free(ac);
2444
2445         return ldb_next_request(module, req);
2446 }
2447
2448 /* extended */
2449
2450 static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
2451 {
2452         struct ldb_context *ldb = ldb_module_get_ctx(module);
2453         struct dsdb_fsmo_extended_op *exop;
2454         int ret;
2455
2456         exop = talloc_get_type(req->op.extended.data,
2457                                struct dsdb_fsmo_extended_op);
2458         if (!exop) {
2459                 ldb_set_errstring(ldb,
2460                                   "samldb_extended_allocate_rid_pool: invalid extended data");
2461                 return LDB_ERR_PROTOCOL_ERROR;
2462         }
2463
2464         ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
2465         if (ret != LDB_SUCCESS) {
2466                 return ret;
2467         }
2468
2469         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2470 }
2471
2472 static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
2473 {
2474         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
2475                 return samldb_extended_allocate_rid_pool(module, req);
2476         }
2477
2478         return ldb_next_request(module, req);
2479 }
2480
2481
2482 static const struct ldb_module_ops ldb_samldb_module_ops = {
2483         .name          = "samldb",
2484         .add           = samldb_add,
2485         .modify        = samldb_modify,
2486         .del           = samldb_delete,
2487         .extended      = samldb_extended
2488 };
2489
2490
2491 int ldb_samldb_module_init(const char *version)
2492 {
2493         LDB_MODULE_CHECK_VERSION(version);
2494         return ldb_register_module(&ldb_samldb_module_ops);
2495 }