s4:samldb LDB module - "samldb_check_primaryGroupID" - support RID derivation from...
[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-2010
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: add embedded user/group creation functionality
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 "libcli/security/security.h"
38 #include "librpc/gen_ndr/ndr_security.h"
39 #include "../lib/util/util_ldb.h"
40 #include "ldb_wrap.h"
41 #include "param/param.h"
42
43 struct samldb_ctx;
44
45 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
46
47 struct samldb_step {
48         struct samldb_step *next;
49         samldb_step_fn_t fn;
50 };
51
52 struct samldb_ctx {
53         struct ldb_module *module;
54         struct ldb_request *req;
55
56         /* used for add operations */
57         const char *type;
58
59         /* the resulting message */
60         struct ldb_message *msg;
61
62         /* used in "samldb_find_for_defaultObjectCategory" */
63         struct ldb_dn *dn, *res_dn;
64
65         /* all the async steps necessary to complete the operation */
66         struct samldb_step *steps;
67         struct samldb_step *curstep;
68
69         /* If someone set an ares to forward controls and response back to the caller */
70         struct ldb_reply *ares;
71 };
72
73 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
74                                           struct ldb_request *req)
75 {
76         struct ldb_context *ldb;
77         struct samldb_ctx *ac;
78
79         ldb = ldb_module_get_ctx(module);
80
81         ac = talloc_zero(req, struct samldb_ctx);
82         if (ac == NULL) {
83                 ldb_oom(ldb);
84                 return NULL;
85         }
86
87         ac->module = module;
88         ac->req = req;
89
90         return ac;
91 }
92
93 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
94 {
95         struct samldb_step *step, *stepper;
96
97         step = talloc_zero(ac, struct samldb_step);
98         if (step == NULL) {
99                 return ldb_oom(ldb_module_get_ctx(ac->module));
100         }
101
102         step->fn = fn;
103
104         if (ac->steps == NULL) {
105                 ac->steps = step;
106                 ac->curstep = step;
107         } else {
108                 if (ac->curstep == NULL)
109                         return ldb_operr(ldb_module_get_ctx(ac->module));
110                 for (stepper = ac->curstep; stepper->next != NULL;
111                         stepper = stepper->next);
112                 stepper->next = step;
113         }
114
115         return LDB_SUCCESS;
116 }
117
118 static int samldb_first_step(struct samldb_ctx *ac)
119 {
120         if (ac->steps == NULL) {
121                 return ldb_operr(ldb_module_get_ctx(ac->module));
122         }
123
124         ac->curstep = ac->steps;
125         return ac->curstep->fn(ac);
126 }
127
128 static int samldb_next_step(struct samldb_ctx *ac)
129 {
130         if (ac->curstep->next) {
131                 ac->curstep = ac->curstep->next;
132                 return ac->curstep->fn(ac);
133         }
134
135         /* we exit the samldb module here */
136         /* If someone set an ares to forward controls and response back to the caller, use them */
137         if (ac->ares) {
138                 return ldb_module_done(ac->req, ac->ares->controls,
139                                        ac->ares->response, LDB_SUCCESS);
140         } else {
141                 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
142         }
143 }
144
145
146 /* sAMAccountName handling */
147
148 static int samldb_generate_sAMAccountName(struct ldb_context *ldb, struct ldb_message *msg)
149 {
150         char *name;
151
152         /* Format: $000000-000000000000 */
153
154         name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
155                                 (unsigned int)generate_random(),
156                                 (unsigned int)generate_random(),
157                                 (unsigned int)generate_random());
158         if (name == NULL) {
159                 return ldb_oom(ldb);
160         }
161         return ldb_msg_add_steal_string(msg, "sAMAccountName", name);
162 }
163
164 static int samldb_check_sAMAccountName(struct samldb_ctx *ac)
165 {
166         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
167         const char *name;
168         int ret;
169
170         if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
171                 ret = samldb_generate_sAMAccountName(ldb, ac->msg);
172                 if (ret != LDB_SUCCESS) {
173                         return ret;
174                 }
175         }
176
177         name = ldb_msg_find_attr_as_string(ac->msg, "sAMAccountName", NULL);
178         if (name == NULL) {
179                 return ldb_operr(ldb);
180         }
181
182         ret = samdb_search_count(ldb, NULL, "(sAMAccountName=%s)",
183                                  ldb_binary_encode_string(ac, name));
184         if ((ret < 0) || (ret > 1)) {
185                 return ldb_operr(ldb);
186         }
187         if (ret == 1) {
188                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
189         }
190
191         return samldb_next_step(ac);
192 }
193
194 /* sAMAccountType handling */
195
196 static int samldb_check_sAMAccountType(struct samldb_ctx *ac)
197 {
198         struct ldb_context *ldb;
199         unsigned int account_type;
200         unsigned int group_type;
201         unsigned int uac;
202         int ret;
203
204         ldb = ldb_module_get_ctx(ac->module);
205
206         /* make sure sAMAccountType is not specified */
207         if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
208                 ldb_asprintf_errstring(ldb,
209                         "sAMAccountType must not be specified!");
210                 return LDB_ERR_UNWILLING_TO_PERFORM;
211         }
212
213         if (strcmp("user", ac->type) == 0) {
214                 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
215                 if (uac == 0) {
216                         ldb_asprintf_errstring(ldb,
217                                 "userAccountControl invalid!");
218                         return LDB_ERR_UNWILLING_TO_PERFORM;
219                 } else {
220                         account_type = ds_uf2atype(uac);
221                         ret = samdb_msg_add_uint(ldb,
222                                                  ac->msg, ac->msg,
223                                                  "sAMAccountType",
224                                                  account_type);
225                         if (ret != LDB_SUCCESS) {
226                                 return ret;
227                         }
228                 }
229         } else if (strcmp("group", ac->type) == 0) {
230                 group_type = samdb_result_uint(ac->msg, "groupType", 0);
231                 if (group_type == 0) {
232                         ldb_asprintf_errstring(ldb,
233                                 "groupType invalid!\n");
234                         return LDB_ERR_UNWILLING_TO_PERFORM;
235                 } else {
236                         account_type = ds_gtype2atype(group_type);
237                         ret = samdb_msg_add_uint(ldb,
238                                                  ac->msg, ac->msg,
239                                                  "sAMAccountType",
240                                                  account_type);
241                         if (ret != LDB_SUCCESS) {
242                                 return ret;
243                         }
244                 }
245         }
246
247         return samldb_next_step(ac);
248 }
249
250 /* primaryGroupID handling */
251
252 static int samldb_check_primaryGroupID(struct samldb_ctx *ac)
253 {
254         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
255         struct ldb_dn *prim_group_dn;
256         uint32_t rid;
257         struct dom_sid *sid;
258         int ret;
259
260         rid = samdb_result_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
261         if (rid == (uint32_t) -1) {
262                 uint32_t uac = samdb_result_uint(ac->msg, "userAccountControl",
263                                                  0);
264
265                 rid = ds_uf2prim_group_rid(uac);
266
267                 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
268                                          "primaryGroupID", rid);
269                 if (ret != LDB_SUCCESS) {
270                         return ret;
271                 }
272         }
273
274         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
275         if (sid == NULL) {
276                 return ldb_operr(ldb);
277         }
278
279         prim_group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSID=%s)",
280                                         dom_sid_string(ac, sid));
281         if (prim_group_dn == NULL) {
282                 ldb_asprintf_errstring(ldb,
283                                        "Failed to find primary group with RID %u!",
284                                        rid);
285                 return LDB_ERR_UNWILLING_TO_PERFORM;
286         }
287
288         return samldb_next_step(ac);
289 }
290
291
292 static bool samldb_msg_add_sid(struct ldb_message *msg,
293                                 const char *name,
294                                 const struct dom_sid *sid)
295 {
296         struct ldb_val v;
297         enum ndr_err_code ndr_err;
298
299         ndr_err = ndr_push_struct_blob(&v, msg, sid,
300                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
301         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
302                 return false;
303         }
304         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
305 }
306
307
308 /* allocate a SID using our RID Set */
309 static int samldb_allocate_sid(struct samldb_ctx *ac)
310 {
311         uint32_t rid;
312         struct dom_sid *sid;
313         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
314         int ret;
315
316         ret = ridalloc_allocate_rid(ac->module, &rid);
317         if (ret != LDB_SUCCESS) {
318                 return ret;
319         }
320
321         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
322         if (sid == NULL) {
323                 return ldb_module_oom(ac->module);
324         }
325
326         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
327                 return ldb_operr(ldb);
328         }
329
330         return samldb_next_step(ac);
331 }
332
333 /*
334   see if a krbtgt_number is available
335  */
336 static bool samldb_krbtgtnumber_available(struct samldb_ctx *ac, unsigned krbtgt_number)
337 {
338         TALLOC_CTX *tmp_ctx = talloc_new(ac);
339         struct ldb_result *res;
340         const char *attrs[] = { NULL };
341         int ret;
342
343         ret = dsdb_module_search(ac->module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
344                                  attrs, DSDB_FLAG_NEXT_MODULE,
345                                  "msDC-SecondaryKrbTgtNumber=%u", krbtgt_number);
346         if (ret == LDB_SUCCESS && res->count == 0) {
347                 talloc_free(tmp_ctx);
348                 return true;
349         }
350         talloc_free(tmp_ctx);
351         return false;
352 }
353
354 /* special handling for add in RODC join */
355 static int samldb_rodc_add(struct samldb_ctx *ac)
356 {
357         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
358         unsigned krbtgt_number, i_start, i;
359         int ret;
360
361         /* find a unused msDC-SecondaryKrbTgtNumber */
362         i_start = generate_random() & 0xFFFF;
363         if (i_start == 0) {
364                 i_start = 1;
365         }
366
367         for (i=i_start; i<=0xFFFF; i++) {
368                 if (samldb_krbtgtnumber_available(ac, i)) {
369                         krbtgt_number = i;
370                         goto found;
371                 }
372         }
373         for (i=1; i<i_start; i++) {
374                 if (samldb_krbtgtnumber_available(ac, i)) {
375                         krbtgt_number = i;
376                         goto found;
377                 }
378         }
379
380         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
381                                "%08X: Unable to find available msDS-SecondaryKrbTgtNumber",
382                                W_ERROR_V(WERR_NO_SYSTEM_RESOURCES));
383         return LDB_ERR_OTHER;
384
385 found:
386         ret = ldb_msg_add_empty(ac->msg, "msDS-SecondaryKrbTgtNumber", LDB_FLAG_INTERNAL_DISABLE_VALIDATION, NULL);
387         if (ret != LDB_SUCCESS) {
388                 return ldb_operr(ldb);
389         }
390
391         ret = ldb_msg_add_fmt(ac->msg, "msDS-SecondaryKrbTgtNumber", "%u", krbtgt_number);
392         if (ret != LDB_SUCCESS) {
393                 return ldb_operr(ldb);
394         }
395
396         ret = ldb_msg_add_fmt(ac->msg, "sAMAccountName", "krbtgt_%u", krbtgt_number);
397         if (ret != LDB_SUCCESS) {
398                 return ldb_operr(ldb);
399         }
400
401         return samldb_next_step(ac);
402 }
403
404 static int samldb_find_for_defaultObjectCategory(struct samldb_ctx *ac)
405 {
406         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
407         struct ldb_result *res;
408         const char *no_attrs[] = { NULL };
409         int ret;
410
411         ac->res_dn = NULL;
412
413         ret = dsdb_module_search(ac->module, ac, &res,
414                                  ac->dn, LDB_SCOPE_BASE, no_attrs,
415                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | DSDB_FLAG_NEXT_MODULE,
416                                  "(objectClass=classSchema)");
417         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
418                 /* Don't be pricky when the DN doesn't exist if we have the */
419                 /* RELAX control specified */
420                 if (ldb_request_get_control(ac->req,
421                                             LDB_CONTROL_RELAX_OID) == NULL) {
422                         ldb_set_errstring(ldb,
423                                           "samldb_find_defaultObjectCategory: "
424                                           "Invalid DN for 'defaultObjectCategory'!");
425                         return LDB_ERR_CONSTRAINT_VIOLATION;
426                 }
427         }
428         if ((ret != LDB_ERR_NO_SUCH_OBJECT) && (ret != LDB_SUCCESS)) {
429                 return ret;
430         }
431
432         ac->res_dn = ac->dn;
433
434         return samldb_next_step(ac);
435 }
436
437 /**
438  * msDS-IntId attributeSchema attribute handling
439  * during LDB_ADD request processing
440  */
441 static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac)
442 {
443         int ret;
444         bool id_exists;
445         uint32_t msds_intid;
446         uint32_t system_flags;
447         struct ldb_context *ldb;
448         struct ldb_result *ldb_res;
449         struct ldb_dn *schema_dn;
450
451         ldb = ldb_module_get_ctx(ac->module);
452         schema_dn = ldb_get_schema_basedn(ldb);
453
454         /* replicated update should always go through */
455         if (ldb_request_get_control(ac->req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
456                 return LDB_SUCCESS;
457         }
458
459         /* msDS-IntId is handled by system and should never be
460          * passed by clients */
461         if (ldb_msg_find_element(ac->msg, "msDS-IntId")) {
462                 return LDB_ERR_UNWILLING_TO_PERFORM;
463         }
464
465         /* do not generate msDS-IntId if Relax control is passed */
466         if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
467                 return LDB_SUCCESS;
468         }
469
470         /* check Functional Level */
471         if (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003) {
472                 return LDB_SUCCESS;
473         }
474
475         /* check systemFlags for SCHEMA_BASE_OBJECT flag */
476         system_flags = ldb_msg_find_attr_as_uint(ac->msg, "systemFlags", 0);
477         if (system_flags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) {
478                 return LDB_SUCCESS;
479         }
480
481         /* Generate new value for msDs-IntId
482          * Value should be in 0x80000000..0xBFFFFFFF range */
483         msds_intid = generate_random() % 0X3FFFFFFF;
484         msds_intid += 0x80000000;
485
486         /* probe id values until unique one is found */
487         do {
488                 msds_intid++;
489                 if (msds_intid > 0xBFFFFFFF) {
490                         msds_intid = 0x80000001;
491                 }
492
493                 ret = dsdb_module_search(ac->module, ac,
494                                          &ldb_res,
495                                          schema_dn, LDB_SCOPE_ONELEVEL, NULL,
496                                          DSDB_FLAG_NEXT_MODULE,
497                                          "(msDS-IntId=%d)", msds_intid);
498                 if (ret != LDB_SUCCESS) {
499                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
500                                       __location__": Searching for msDS-IntId=%d failed - %s\n",
501                                       msds_intid,
502                                       ldb_errstring(ldb));
503                         return ldb_operr(ldb);
504                 }
505                 id_exists = (ldb_res->count > 0);
506
507                 talloc_free(ldb_res);
508         } while(id_exists);
509
510         return ldb_msg_add_fmt(ac->msg, "msDS-IntId", "%d", msds_intid);
511 }
512
513
514 /*
515  * samldb_add_entry (async)
516  */
517
518 static int samldb_add_entry_callback(struct ldb_request *req,
519                                         struct ldb_reply *ares)
520 {
521         struct ldb_context *ldb;
522         struct samldb_ctx *ac;
523         int ret;
524
525         ac = talloc_get_type(req->context, struct samldb_ctx);
526         ldb = ldb_module_get_ctx(ac->module);
527
528         if (!ares) {
529                 return ldb_module_done(ac->req, NULL, NULL,
530                                         LDB_ERR_OPERATIONS_ERROR);
531         }
532
533         if (ares->type == LDB_REPLY_REFERRAL) {
534                 return ldb_module_send_referral(ac->req, ares->referral);
535         }
536
537         if (ares->error != LDB_SUCCESS) {
538                 return ldb_module_done(ac->req, ares->controls,
539                                         ares->response, ares->error);
540         }
541         if (ares->type != LDB_REPLY_DONE) {
542                 ldb_set_errstring(ldb,
543                         "Invalid reply type!\n");
544                 return ldb_module_done(ac->req, NULL, NULL,
545                                         LDB_ERR_OPERATIONS_ERROR);
546         }
547
548         /* The caller may wish to get controls back from the add */
549         ac->ares = talloc_steal(ac, ares);
550
551         ret = samldb_next_step(ac);
552         if (ret != LDB_SUCCESS) {
553                 return ldb_module_done(ac->req, NULL, NULL, ret);
554         }
555         return ret;
556 }
557
558 static int samldb_add_entry(struct samldb_ctx *ac)
559 {
560         struct ldb_context *ldb;
561         struct ldb_request *req;
562         int ret;
563
564         ldb = ldb_module_get_ctx(ac->module);
565
566         ret = ldb_build_add_req(&req, ldb, ac,
567                                 ac->msg,
568                                 ac->req->controls,
569                                 ac, samldb_add_entry_callback,
570                                 ac->req);
571         if (ret != LDB_SUCCESS) {
572                 return ret;
573         }
574
575         return ldb_next_request(ac->module, req);
576 }
577
578 /*
579  * return true if msg carries an attributeSchema that is intended to be RODC
580  * filtered but is also a system-critical attribute.
581  */
582 static bool check_rodc_critical_attribute(struct ldb_message *msg)
583 {
584         uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
585
586         schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
587         searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
588         rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE | SEARCH_FLAG_CONFIDENTIAL);
589
590         if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
591                 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
592                 return true;
593         } else {
594                 return false;
595         }
596 }
597
598
599 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
600 {
601         struct ldb_context *ldb;
602         struct loadparm_context *lp_ctx;
603         enum sid_generator sid_generator;
604         int ret;
605         struct ldb_control *rodc_control;
606         struct dom_sid *sid;
607
608         ldb = ldb_module_get_ctx(ac->module);
609
610         /* Add informations for the different account types */
611         ac->type = type;
612         if (strcmp(ac->type, "user") == 0) {
613                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
614                         "userAccountControl", "546");
615                 if (ret != LDB_SUCCESS) return ret;
616                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
617                         "badPwdCount", "0");
618                 if (ret != LDB_SUCCESS) return ret;
619                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
620                         "codePage", "0");
621                 if (ret != LDB_SUCCESS) return ret;
622                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
623                         "countryCode", "0");
624                 if (ret != LDB_SUCCESS) return ret;
625                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
626                         "badPasswordTime", "0");
627                 if (ret != LDB_SUCCESS) return ret;
628                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
629                         "lastLogoff", "0");
630                 if (ret != LDB_SUCCESS) return ret;
631                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
632                         "lastLogon", "0");
633                 if (ret != LDB_SUCCESS) return ret;
634                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
635                         "pwdLastSet", "0");
636                 if (ret != LDB_SUCCESS) return ret;
637                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
638                         "accountExpires", "9223372036854775807");
639                 if (ret != LDB_SUCCESS) return ret;
640                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
641                         "logonCount", "0");
642                 if (ret != LDB_SUCCESS) return ret;
643         } else if (strcmp(ac->type, "group") == 0) {
644                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
645                         "groupType", "-2147483646");
646                 if (ret != LDB_SUCCESS) return ret;
647         } else if (strcmp(ac->type, "classSchema") == 0) {
648                 const struct ldb_val *rdn_value, *def_obj_cat_val;
649
650                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
651                                                   "rdnAttId", "cn");
652                 if (ret != LDB_SUCCESS) return ret;
653
654                 /* do not allow to mark an attributeSchema as RODC filtered if it
655                  * is system-critical */
656                 if (check_rodc_critical_attribute(ac->msg)) {
657                         ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
658                                                ldb_dn_get_linearized(ac->msg->dn));
659                         return LDB_ERR_UNWILLING_TO_PERFORM;
660                 }
661
662
663                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
664                 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
665                         /* the RDN has prefix "CN" */
666                         ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
667                                 samdb_cn_to_lDAPDisplayName(ac,
668                                         (const char *) rdn_value->data));
669                         if (ret != LDB_SUCCESS) {
670                                 ldb_oom(ldb);
671                                 return ret;
672                         }
673                 }
674
675                 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
676                         struct GUID guid;
677                         /* a new GUID */
678                         guid = GUID_random();
679                         ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
680                         if (ret != LDB_SUCCESS) {
681                                 ldb_oom(ldb);
682                                 return ret;
683                         }
684                 }
685
686                 def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
687                                                        "defaultObjectCategory");
688                 if (def_obj_cat_val != NULL) {
689                         /* "defaultObjectCategory" has been set by the caller.
690                          * Do some checks for consistency.
691                          * NOTE: The real constraint check (that
692                          * 'defaultObjectCategory' is the DN of the new
693                          * objectclass or any parent of it) is still incomplete.
694                          * For now we say that 'defaultObjectCategory' is valid
695                          * if it exists and it is of objectclass "classSchema".
696                          */
697                         ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
698                         if (ac->dn == NULL) {
699                                 ldb_set_errstring(ldb,
700                                                   "Invalid DN for 'defaultObjectCategory'!");
701                                 return LDB_ERR_CONSTRAINT_VIOLATION;
702                         }
703                 } else {
704                         /* "defaultObjectCategory" has not been set by the
705                          * caller. Use the entry DN for it. */
706                         ac->dn = ac->msg->dn;
707
708                         ret = samdb_msg_add_string(ldb, ac, ac->msg,
709                                                    "defaultObjectCategory",
710                                                    ldb_dn_get_linearized(ac->dn));
711                         if (ret != LDB_SUCCESS) {
712                                 ldb_oom(ldb);
713                                 return ret;
714                         }
715                 }
716
717                 ret = samldb_add_step(ac, samldb_add_entry);
718                 if (ret != LDB_SUCCESS) return ret;
719
720                 /* Now perform the checks for the 'defaultObjectCategory'. The
721                  * lookup DN was already saved in "ac->dn" */
722                 ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
723                 if (ret != LDB_SUCCESS) return ret;
724
725                 return samldb_first_step(ac);
726         } else if (strcmp(ac->type, "attributeSchema") == 0) {
727                 const struct ldb_val *rdn_value;
728                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
729                 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
730                         /* the RDN has prefix "CN" */
731                         ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
732                                 samdb_cn_to_lDAPDisplayName(ac,
733                                         (const char *) rdn_value->data));
734                         if (ret != LDB_SUCCESS) {
735                                 ldb_oom(ldb);
736                                 return ret;
737                         }
738                 }
739
740                 /* do not allow to mark an attributeSchema as RODC filtered if it
741                  * is system-critical */
742                 if (check_rodc_critical_attribute(ac->msg)) {
743                         ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical attribute with RODC filtering",
744                                                ldb_dn_get_linearized(ac->msg->dn));
745                         return LDB_ERR_UNWILLING_TO_PERFORM;
746                 }
747
748                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
749                                                   "isSingleValued", "FALSE");
750                 if (ret != LDB_SUCCESS) return ret;
751
752                 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
753                         struct GUID guid;
754                         /* a new GUID */
755                         guid = GUID_random();
756                         ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
757                         if (ret != LDB_SUCCESS) {
758                                 ldb_oom(ldb);
759                                 return ret;
760                         }
761                 }
762
763                 /* handle msDS-IntID attribute */
764                 ret = samldb_add_handle_msDS_IntId(ac);
765                 if (ret != LDB_SUCCESS) return ret;
766
767                 ret = samldb_add_step(ac, samldb_add_entry);
768                 if (ret != LDB_SUCCESS) return ret;
769
770                 return samldb_first_step(ac);
771         } else {
772                 ldb_asprintf_errstring(ldb,
773                         "Invalid entry type!");
774                 return LDB_ERR_OPERATIONS_ERROR;
775         }
776
777         rodc_control = ldb_request_get_control(ac->req, LDB_CONTROL_RODC_DCPROMO_OID);
778         if (rodc_control) {
779                 /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
780                 rodc_control->critical = false;
781                 ret = samldb_add_step(ac, samldb_rodc_add);
782                 if (ret != LDB_SUCCESS) return ret;
783         }
784
785         /* check if we have a valid sAMAccountName */
786         ret = samldb_add_step(ac, samldb_check_sAMAccountName);
787         if (ret != LDB_SUCCESS) return ret;
788
789         /* check account_type/group_type */
790         ret = samldb_add_step(ac, samldb_check_sAMAccountType);
791         if (ret != LDB_SUCCESS) return ret;
792
793         /* check if we have a valid primary group ID */
794         if (strcmp(ac->type, "user") == 0) {
795                 ret = samldb_add_step(ac, samldb_check_primaryGroupID);
796                 if (ret != LDB_SUCCESS) return ret;
797         }
798
799         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
800                  struct loadparm_context);
801
802         /* don't allow objectSID to be specified without the RELAX control */
803         sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
804         if (sid && !ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) &&
805             !dsdb_module_am_system(ac->module)) {
806                 ldb_asprintf_errstring(ldb, "No SID may be specified in user/group creation for %s",
807                                        ldb_dn_get_linearized(ac->msg->dn));
808                 return LDB_ERR_UNWILLING_TO_PERFORM;
809         }
810
811         if (sid == NULL) {
812                 sid_generator = lpcfg_sid_generator(lp_ctx);
813                 if (sid_generator == SID_GENERATOR_INTERNAL) {
814                         ret = samldb_add_step(ac, samldb_allocate_sid);
815                         if (ret != LDB_SUCCESS) return ret;
816                 }
817         }
818
819         /* finally proceed with adding the entry */
820         ret = samldb_add_step(ac, samldb_add_entry);
821         if (ret != LDB_SUCCESS) return ret;
822
823         return samldb_first_step(ac);
824 }
825
826 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
827 {
828         struct ldb_context *ldb;
829         struct dom_sid *sid;
830         int ret;
831
832         ldb = ldb_module_get_ctx(ac->module);
833
834         sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
835         if (sid == NULL) {
836                 sid = dom_sid_parse_talloc(ac->msg,
837                                            (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
838                 if (sid == NULL) {
839                         ldb_set_errstring(ldb,
840                                         "No valid SID found in "
841                                         "ForeignSecurityPrincipal CN!");
842                         return LDB_ERR_CONSTRAINT_VIOLATION;
843                 }
844                 if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
845                         return ldb_operr(ldb);
846                 }
847         }
848
849         /* finally proceed with adding the entry */
850         ret = samldb_add_step(ac, samldb_add_entry);
851         if (ret != LDB_SUCCESS) return ret;
852
853         return samldb_first_step(ac);
854 }
855
856 static int samldb_schema_info_update(struct samldb_ctx *ac)
857 {
858         WERROR werr;
859         struct ldb_context *ldb;
860         struct dsdb_schema *schema;
861
862         /* replicated update should always go through */
863         if (ldb_request_get_control(ac->req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
864                 return LDB_SUCCESS;
865         }
866
867         /* do not update schemaInfo during provisioning */
868         if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
869                 return LDB_SUCCESS;
870         }
871
872         ldb = ldb_module_get_ctx(ac->module);
873         schema = dsdb_get_schema(ldb, NULL);
874         if (!schema) {
875                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
876                               "samldb_schema_info_update: no dsdb_schema loaded");
877                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
878                 return ldb_operr(ldb);
879         }
880
881         werr = dsdb_module_schema_info_update(ac->module, schema, DSDB_FLAG_NEXT_MODULE);
882         if (!W_ERROR_IS_OK(werr)) {
883                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
884                               "samldb_schema_info_update: "
885                               "dsdb_module_schema_info_update failed with %s",
886                               win_errstr(werr));
887                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
888                 return ldb_operr(ldb);
889         }
890
891         return LDB_SUCCESS;
892 }
893
894
895 static int samldb_prim_group_change(struct samldb_ctx *ac)
896 {
897         struct ldb_context *ldb;
898         const char * attrs[] = { "primaryGroupID", "memberOf", NULL };
899         struct ldb_result *res;
900         struct ldb_message_element *el;
901         struct ldb_message *msg;
902         uint32_t rid;
903         struct dom_sid *sid;
904         struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
905         int ret;
906
907         ldb = ldb_module_get_ctx(ac->module);
908
909         /* Fetch informations from the existing object */
910
911         ret = ldb_search(ldb, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
912                          NULL);
913         if (ret != LDB_SUCCESS) {
914                 return ret;
915         }
916
917         /* Finds out the DN of the old primary group */
918
919         rid = samdb_result_uint(res->msgs[0], "primaryGroupID", (uint32_t) -1);
920         if (rid == (uint32_t) -1) {
921                 /* User objects do always have a mandatory "primaryGroupID"
922                  * attribute. If this doesn't exist then the object is of the
923                  * wrong type. This is the exact Windows error code */
924                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
925         }
926
927         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
928         if (sid == NULL) {
929                 return ldb_operr(ldb);
930         }
931
932         prev_prim_group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSID=%s)",
933                                              dom_sid_string(ac, sid));
934         if (prev_prim_group_dn == NULL) {
935                 return ldb_operr(ldb);
936         }
937
938         /* Finds out the DN of the new primary group */
939
940         rid = samdb_result_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
941         if (rid == (uint32_t) -1) {
942                 /* we aren't affected of any primary group change */
943                 return LDB_SUCCESS;
944         }
945
946         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
947         if (sid == NULL) {
948                 return ldb_operr(ldb);
949         }
950
951         new_prim_group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSID=%s)",
952                                             dom_sid_string(ac, sid));
953         if (new_prim_group_dn == NULL) {
954                 /* Here we know if the specified new primary group candidate is
955                  * valid or not. */
956                 return LDB_ERR_UNWILLING_TO_PERFORM;
957         }
958
959         /* Only update the "member" attributes when we really do have a change */
960         if (ldb_dn_compare(new_prim_group_dn, prev_prim_group_dn) != 0) {
961                 /* We need to be already a normal member of the new primary
962                  * group in order to be successful. */
963                 el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
964                                           ldb_dn_get_linearized(new_prim_group_dn));
965                 if (el == NULL) {
966                         return LDB_ERR_UNWILLING_TO_PERFORM;
967                 }
968
969                 /* Remove the "member" attribute on the new primary group */
970                 msg = talloc_zero(ac, struct ldb_message);
971                 msg->dn = new_prim_group_dn;
972
973                 ret = samdb_msg_add_delval(ldb, ac, msg, "member",
974                                            ldb_dn_get_linearized(ac->msg->dn));
975                 if (ret != LDB_SUCCESS) {
976                         return ret;
977                 }
978
979                 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE);
980                 if (ret != LDB_SUCCESS) {
981                         return ret;
982                 }
983
984                 /* Add a "member" attribute for the previous primary group */
985                 msg = talloc_zero(ac, struct ldb_message);
986                 msg->dn = prev_prim_group_dn;
987
988                 ret = samdb_msg_add_addval(ldb, ac, msg, "member",
989                                            ldb_dn_get_linearized(ac->msg->dn));
990                 if (ret != LDB_SUCCESS) {
991                         return ret;
992                 }
993
994                 ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE);
995                 if (ret != LDB_SUCCESS) {
996                         return ret;
997                 }
998         }
999
1000         return LDB_SUCCESS;
1001 }
1002
1003
1004 static int samldb_member_check(struct samldb_ctx *ac)
1005 {
1006         struct ldb_context *ldb;
1007         struct ldb_message_element *el;
1008         struct ldb_dn *member_dn, *group_dn;
1009         uint32_t prim_group_rid;
1010         struct dom_sid *sid;
1011         unsigned int i;
1012
1013         ldb = ldb_module_get_ctx(ac->module);
1014
1015         el = ldb_msg_find_element(ac->msg, "member");
1016         if (el == NULL) {
1017                 /* we aren't affected */
1018                 return LDB_SUCCESS;
1019         }
1020
1021         for (i = 0; i < el->num_values; i++) {
1022                 /* Denies to add "member"s to groups which are primary ones
1023                  * for them */
1024                 member_dn = ldb_dn_from_ldb_val(ac, ldb, &el->values[i]);
1025                 if (!ldb_dn_validate(member_dn)) {
1026                         return ldb_operr(ldb);
1027                 }
1028
1029                 prim_group_rid = samdb_search_uint(ldb, ac, (uint32_t) -1,
1030                                                    member_dn, "primaryGroupID",
1031                                                    NULL);
1032                 if (prim_group_rid == (uint32_t) -1) {
1033                         /* the member hasn't to be a user account -> therefore
1034                          * no check needed in this case. */
1035                         continue;
1036                 }
1037
1038                 sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
1039                                       prim_group_rid);
1040                 if (sid == NULL) {
1041                         return ldb_operr(ldb);
1042                 }
1043
1044                 group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSID=%s)",
1045                                            dom_sid_string(ac, sid));
1046                 if (group_dn == NULL) {
1047                         return ldb_operr(ldb);
1048                 }
1049
1050                 if (ldb_dn_compare(group_dn, ac->msg->dn) == 0) {
1051                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1052                 }
1053         }
1054
1055         return LDB_SUCCESS;
1056 }
1057
1058
1059 /* add */
1060 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1061 {
1062         struct ldb_context *ldb;
1063         struct samldb_ctx *ac;
1064         int ret;
1065
1066         ldb = ldb_module_get_ctx(module);
1067         ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
1068
1069         /* do not manipulate our control entries */
1070         if (ldb_dn_is_special(req->op.add.message->dn)) {
1071                 return ldb_next_request(module, req);
1072         }
1073
1074         ac = samldb_ctx_init(module, req);
1075         if (ac == NULL) {
1076                 return ldb_operr(ldb);
1077         }
1078
1079         /* build the new msg */
1080         req->op.add.message = ac->msg = ldb_msg_copy_shallow(req,
1081                                                              req->op.add.message);
1082         if (ac->msg == NULL) {
1083                 return ldb_operr(ldb);
1084         }
1085
1086         if (samdb_find_attribute(ldb, ac->msg,
1087                                  "objectclass", "user") != NULL) {
1088                 return samldb_fill_object(ac, "user");
1089         }
1090
1091         if (samdb_find_attribute(ldb, ac->msg,
1092                                  "objectclass", "group") != NULL) {
1093                 return samldb_fill_object(ac, "group");
1094         }
1095
1096         /* perhaps a foreignSecurityPrincipal? */
1097         if (samdb_find_attribute(ldb, ac->msg,
1098                                  "objectclass",
1099                                  "foreignSecurityPrincipal") != NULL) {
1100                 return samldb_fill_foreignSecurityPrincipal_object(ac);
1101         }
1102
1103         if (samdb_find_attribute(ldb, ac->msg,
1104                                  "objectclass", "classSchema") != NULL) {
1105                 ret = samldb_schema_info_update(ac);
1106                 if (ret != LDB_SUCCESS) {
1107                         talloc_free(ac);
1108                         return ret;
1109                 }
1110
1111                 return samldb_fill_object(ac, "classSchema");
1112         }
1113
1114         if (samdb_find_attribute(ldb, ac->msg,
1115                                  "objectclass", "attributeSchema") != NULL) {
1116                 ret = samldb_schema_info_update(ac);
1117                 if (ret != LDB_SUCCESS) {
1118                         talloc_free(ac);
1119                         return ret;
1120                 }
1121
1122                 return samldb_fill_object(ac, "attributeSchema");
1123         }
1124
1125         talloc_free(ac);
1126
1127         /* nothing matched, go on */
1128         return ldb_next_request(module, req);
1129 }
1130
1131 /* modify */
1132 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1133 {
1134         struct ldb_context *ldb;
1135         struct samldb_ctx *ac;
1136         struct ldb_message_element *el, *el2;
1137         int ret;
1138         uint32_t account_type;
1139
1140         if (ldb_dn_is_special(req->op.mod.message->dn)) {
1141                 /* do not manipulate our control entries */
1142                 return ldb_next_request(module, req);
1143         }
1144
1145         ldb = ldb_module_get_ctx(module);
1146
1147         if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1148                 ldb_asprintf_errstring(ldb,
1149                         "sAMAccountType must not be specified!");
1150                 return LDB_ERR_UNWILLING_TO_PERFORM;
1151         }
1152
1153         /* msDS-IntId is not allowed to be modified
1154          * except when modification comes from replication */
1155         if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
1156                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1157                         return LDB_ERR_CONSTRAINT_VIOLATION;
1158                 }
1159         }
1160
1161         ac = samldb_ctx_init(module, req);
1162         if (ac == NULL) {
1163                 return ldb_operr(ldb);
1164         }
1165
1166         /* build the new msg */
1167         req->op.mod.message = ac->msg = ldb_msg_copy_shallow(req,
1168                                                              req->op.mod.message);
1169         if (ac->msg == NULL) {
1170                 return ldb_operr(ldb);
1171         }
1172
1173         el = ldb_msg_find_element(ac->msg, "groupType");
1174         if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1175                 uint32_t group_type;
1176
1177                 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1178                 account_type =  ds_gtype2atype(group_type);
1179                 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1180                                          "sAMAccountType",
1181                                          account_type);
1182                 if (ret != LDB_SUCCESS) {
1183                         return ret;
1184                 }
1185                 el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1186                 el2->flags = LDB_FLAG_MOD_REPLACE;
1187         }
1188         if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
1189                 return LDB_ERR_UNWILLING_TO_PERFORM;
1190         }
1191
1192         el = ldb_msg_find_element(ac->msg, "primaryGroupID");
1193         if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1194                 ret = samldb_prim_group_change(ac);
1195                 if (ret != LDB_SUCCESS) {
1196                         return ret;
1197                 }
1198         }
1199         if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
1200                 return LDB_ERR_UNWILLING_TO_PERFORM;
1201         }
1202
1203         el = ldb_msg_find_element(ac->msg, "userAccountControl");
1204         if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1205                 uint32_t user_account_control;
1206
1207                 user_account_control = strtoul((const char *)el->values[0].data,
1208                         NULL, 0);
1209                 account_type = ds_uf2atype(user_account_control);
1210                 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1211                                          "sAMAccountType",
1212                                          account_type);
1213                 if (ret != LDB_SUCCESS) {
1214                         return ret;
1215                 }
1216                 el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1217                 el2->flags = LDB_FLAG_MOD_REPLACE;
1218
1219                 if (user_account_control & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1220                         ret = samdb_msg_add_string(ldb, ac->msg, ac->msg,
1221                                                    "isCriticalSystemObject",
1222                                                    "TRUE");
1223                         if (ret != LDB_SUCCESS) {
1224                                 return ret;
1225                         }
1226                         el2 = ldb_msg_find_element(ac->msg,
1227                                                    "isCriticalSystemObject");
1228                         el2->flags = LDB_FLAG_MOD_REPLACE;
1229
1230                         /* DCs have primaryGroupID of DOMAIN_RID_DCS */
1231                         if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1232                                 uint32_t rid;
1233                                 if (user_account_control & UF_SERVER_TRUST_ACCOUNT) {
1234                                         rid = DOMAIN_RID_DCS;
1235                                 } else {
1236                                         /* read-only DC */
1237                                         rid = DOMAIN_RID_READONLY_DCS;
1238                                 }
1239                                 ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1240                                                          "primaryGroupID", rid);
1241                                 if (ret != LDB_SUCCESS) {
1242                                         return ret;
1243                                 }
1244                                 el2 = ldb_msg_find_element(ac->msg,
1245                                                            "primaryGroupID");
1246                                 el2->flags = LDB_FLAG_MOD_REPLACE;
1247                         }
1248                 }
1249         }
1250         if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
1251                 return LDB_ERR_UNWILLING_TO_PERFORM;
1252         }
1253
1254         el = ldb_msg_find_element(ac->msg, "member");
1255         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1256                 ret = samldb_member_check(ac);
1257                 if (ret != LDB_SUCCESS) {
1258                         return ret;
1259                 }
1260         }
1261
1262         talloc_free(ac);
1263
1264         return ldb_next_request(module, req);
1265 }
1266
1267 /* delete */
1268
1269 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
1270 {
1271         struct ldb_context *ldb;
1272         struct dom_sid *sid;
1273         uint32_t rid;
1274         NTSTATUS status;
1275         int count;
1276
1277         ldb = ldb_module_get_ctx(ac->module);
1278
1279         /* Finds out the SID/RID of the SAM object */
1280         sid = samdb_search_dom_sid(ldb, ac, ac->req->op.del.dn, "objectSID",
1281                                    NULL);
1282         if (sid == NULL) {
1283                 /* No SID - it might not be a SAM object - therefore ok */
1284                 return LDB_SUCCESS;
1285         }
1286         status = dom_sid_split_rid(ac, sid, NULL, &rid);
1287         if (!NT_STATUS_IS_OK(status)) {
1288                 return ldb_operr(ldb);
1289         }
1290         if (rid == 0) {
1291                 /* Special object (security principal?) */
1292                 return LDB_SUCCESS;
1293         }
1294
1295         /* Deny delete requests from groups which are primary ones */
1296         count = samdb_search_count(ldb, NULL,
1297                                    "(&(primaryGroupID=%u)(objectClass=user))",
1298                                    rid);
1299         if (count < 0) {
1300                 return ldb_operr(ldb);
1301         }
1302         if (count > 0) {
1303                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
1304         }
1305
1306         return LDB_SUCCESS;
1307 }
1308
1309 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
1310 {
1311         struct samldb_ctx *ac;
1312         int ret;
1313
1314         if (ldb_dn_is_special(req->op.del.dn)) {
1315                 /* do not manipulate our control entries */
1316                 return ldb_next_request(module, req);
1317         }
1318
1319         ac = samldb_ctx_init(module, req);
1320         if (ac == NULL) {
1321                 return ldb_operr(ldb_module_get_ctx(module));
1322         }
1323
1324         ret = samldb_prim_group_users_check(ac);
1325         if (ret != LDB_SUCCESS) {
1326                 return ret;
1327         }
1328
1329         talloc_free(ac);
1330
1331         return ldb_next_request(module, req);
1332 }
1333
1334 /* extended */
1335
1336 static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
1337 {
1338         struct ldb_context *ldb = ldb_module_get_ctx(module);
1339         struct dsdb_fsmo_extended_op *exop;
1340         int ret;
1341
1342         exop = talloc_get_type(req->op.extended.data, struct dsdb_fsmo_extended_op);
1343         if (!exop) {
1344                 ldb_debug(ldb, LDB_DEBUG_FATAL, "samldb_extended_allocate_rid_pool: invalid extended data\n");
1345                 return LDB_ERR_PROTOCOL_ERROR;
1346         }
1347
1348         ret = ridalloc_allocate_rid_pool_fsmo(module, exop);
1349         if (ret != LDB_SUCCESS) {
1350                 return ret;
1351         }
1352
1353         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
1354 }
1355
1356 static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
1357 {
1358         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
1359                 return samldb_extended_allocate_rid_pool(module, req);
1360         }
1361
1362         return ldb_next_request(module, req);
1363 }
1364
1365
1366 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1367         .name          = "samldb",
1368         .add           = samldb_add,
1369         .modify        = samldb_modify,
1370         .del           = samldb_delete,
1371         .extended      = samldb_extended
1372 };
1373