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