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