dd15dddfb5054bffac88c9b2ba05060b7eb304f5
[samba.git] / source4 / dsdb / samdb / ldb_modules / acl.c
1 /*
2   ldb database library
3
4   Copyright (C) Simo Sorce 2006-2008
5   Copyright (C) Nadezhda Ivanova 2009
6   Copyright (C) Anatoliy Atanasov  2009
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 ACL module
26  *
27  *  Description: Module that performs authorisation access checks based on the
28  *               account's security context and the DACL of the object being polled.
29  *               Only DACL checks implemented at this point
30  *
31  *  Authors: Nadezhda Ivanova, Anatoliy Atanasov
32  */
33
34 #include "includes.h"
35 #include "ldb_module.h"
36 #include "auth/auth.h"
37 #include "libcli/security/security.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40 #include "param/param.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "lib/util/tsort.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
45
46 #undef strcasecmp
47 #undef strncasecmp
48
49 struct extended_access_check_attribute {
50         const char *oa_name;
51         const uint32_t requires_rights;
52 };
53
54 struct acl_private {
55         bool acl_search;
56         const char **password_attrs;
57         void *cached_schema_ptr;
58         uint64_t cached_schema_metadata_usn;
59         uint64_t cached_schema_loaded_usn;
60         const char **confidential_attrs;
61         bool userPassword_support;
62 };
63
64 struct acl_context {
65         struct ldb_module *module;
66         struct ldb_request *req;
67         bool am_system;
68         bool am_administrator;
69         bool modify_search;
70         bool constructed_attrs;
71         bool allowedAttributes;
72         bool allowedAttributesEffective;
73         bool allowedChildClasses;
74         bool allowedChildClassesEffective;
75         bool sDRightsEffective;
76         bool userPassword;
77         const char * const *attrs;
78         struct dsdb_schema *schema;
79 };
80
81 static int acl_module_init(struct ldb_module *module)
82 {
83         struct ldb_context *ldb;
84         struct acl_private *data;
85         int ret;
86         unsigned int i, n, j;
87         TALLOC_CTX *mem_ctx;
88         static const char * const attrs[] = { "passwordAttribute", NULL };
89         static const char * const secret_attrs[] = {
90                 DSDB_SECRET_ATTRIBUTES
91         };
92         struct ldb_result *res;
93         struct ldb_message *msg;
94         struct ldb_message_element *password_attributes;
95
96         ldb = ldb_module_get_ctx(module);
97
98         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
99         if (ret != LDB_SUCCESS) {
100                 ldb_debug(ldb, LDB_DEBUG_ERROR,
101                           "acl_module_init: Unable to register control with rootdse!\n");
102                 return ldb_operr(ldb);
103         }
104
105         data = talloc_zero(module, struct acl_private);
106         if (data == NULL) {
107                 return ldb_oom(ldb);
108         }
109
110         data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
111                                         NULL, "acl", "search", true);
112         ldb_module_set_private(module, data);
113
114         mem_ctx = talloc_new(module);
115         if (!mem_ctx) {
116                 return ldb_oom(ldb);
117         }
118
119         ret = dsdb_module_search_dn(module, mem_ctx, &res,
120                                     ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
121                                     attrs,
122                                     DSDB_FLAG_NEXT_MODULE |
123                                     DSDB_FLAG_AS_SYSTEM,
124                                     NULL);
125         if (ret != LDB_SUCCESS) {
126                 goto done;
127         }
128         if (res->count == 0) {
129                 goto done;
130         }
131
132         if (res->count > 1) {
133                 talloc_free(mem_ctx);
134                 return LDB_ERR_CONSTRAINT_VIOLATION;
135         }
136
137         msg = res->msgs[0];
138
139         password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
140         if (!password_attributes) {
141                 goto done;
142         }
143         data->password_attrs = talloc_array(data, const char *,
144                         password_attributes->num_values +
145                         ARRAY_SIZE(secret_attrs) + 1);
146         if (!data->password_attrs) {
147                 talloc_free(mem_ctx);
148                 return ldb_oom(ldb);
149         }
150
151         n = 0;
152         for (i=0; i < password_attributes->num_values; i++) {
153                 data->password_attrs[n] = (const char *)password_attributes->values[i].data;
154                 talloc_steal(data->password_attrs, password_attributes->values[i].data);
155                 n++;
156         }
157
158         for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
159                 bool found = false;
160
161                 for (j=0; j < n; j++) {
162                         if (strcasecmp(data->password_attrs[j], secret_attrs[i]) == 0) {
163                                 found = true;
164                                 break;
165                         }
166                 }
167
168                 if (found) {
169                         continue;
170                 }
171
172                 data->password_attrs[n] = talloc_strdup(data->password_attrs,
173                                                         secret_attrs[i]);
174                 if (data->password_attrs[n] == NULL) {
175                         talloc_free(mem_ctx);
176                         return ldb_oom(ldb);
177                 }
178                 n++;
179         }
180         data->password_attrs[n] = NULL;
181
182 done:
183         talloc_free(mem_ctx);
184         ret = ldb_next_init(module);
185
186         if (ret != LDB_SUCCESS) {
187                 return ret;
188         }
189
190         /*
191          * Check this after the modules have be initialised so we
192          * can actually read the backend DB.
193          */
194         data->userPassword_support
195                 = dsdb_user_password_support(module,
196                                              module,
197                                              NULL);
198         return ret;
199 }
200
201 static int acl_allowedAttributes(struct ldb_module *module,
202                                  const struct dsdb_schema *schema,
203                                  struct ldb_message *sd_msg,
204                                  struct ldb_message *msg,
205                                  struct acl_context *ac)
206 {
207         struct ldb_message_element *oc_el;
208         struct ldb_context *ldb = ldb_module_get_ctx(module);
209         TALLOC_CTX *mem_ctx;
210         const char **attr_list;
211         int i, ret;
212         const struct dsdb_class *objectclass;
213
214         /* If we don't have a schema yet, we can't do anything... */
215         if (schema == NULL) {
216                 ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
217                 return LDB_ERR_OPERATIONS_ERROR;
218         }
219
220         /* Must remove any existing attribute */
221         if (ac->allowedAttributes) {
222                 ldb_msg_remove_attr(msg, "allowedAttributes");
223         }
224
225         mem_ctx = talloc_new(msg);
226         if (!mem_ctx) {
227                 return ldb_oom(ldb);
228         }
229
230         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
231         attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
232         if (!attr_list) {
233                 ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
234                 talloc_free(mem_ctx);
235                 return LDB_ERR_OPERATIONS_ERROR;
236         }
237
238         /*
239          * Get the top-most structural object class for the ACL check
240          */
241         objectclass = dsdb_get_last_structural_class(ac->schema,
242                                                      oc_el);
243         if (objectclass == NULL) {
244                 ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
245                                        ldb_dn_get_linearized(sd_msg->dn));
246                 talloc_free(mem_ctx);
247                 return LDB_ERR_OPERATIONS_ERROR;
248         }
249
250         if (ac->allowedAttributes) {
251                 for (i=0; attr_list && attr_list[i]; i++) {
252                         ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
253                 }
254         }
255         if (ac->allowedAttributesEffective) {
256                 struct security_descriptor *sd;
257                 struct dom_sid *sid = NULL;
258                 struct ldb_control *as_system = ldb_request_get_control(ac->req,
259                                                                         LDB_CONTROL_AS_SYSTEM_OID);
260
261                 if (as_system != NULL) {
262                         as_system->critical = 0;
263                 }
264
265                 ldb_msg_remove_attr(msg, "allowedAttributesEffective");
266                 if (ac->am_system || as_system) {
267                         for (i=0; attr_list && attr_list[i]; i++) {
268                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
269                         }
270                         return LDB_SUCCESS;
271                 }
272
273                 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
274
275                 if (ret != LDB_SUCCESS) {
276                         return ret;
277                 }
278
279                 sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
280                 for (i=0; attr_list && attr_list[i]; i++) {
281                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
282                                                                                         attr_list[i]);
283                         if (!attr) {
284                                 return ldb_operr(ldb);
285                         }
286                         /* remove constructed attributes */
287                         if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
288                             || attr->systemOnly
289                             || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
290                                 continue;
291                         }
292                         ret = acl_check_access_on_attribute(module,
293                                                             msg,
294                                                             sd,
295                                                             sid,
296                                                             SEC_ADS_WRITE_PROP,
297                                                             attr,
298                                                             objectclass);
299                         if (ret == LDB_SUCCESS) {
300                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
301                         }
302                 }
303         }
304         return LDB_SUCCESS;
305 }
306
307 static int acl_childClasses(struct ldb_module *module,
308                             const struct dsdb_schema *schema,
309                             struct ldb_message *sd_msg,
310                             struct ldb_message *msg,
311                             const char *attrName)
312 {
313         struct ldb_message_element *oc_el;
314         struct ldb_message_element *allowedClasses;
315         const struct dsdb_class *sclass;
316         unsigned int i, j;
317         int ret;
318
319         /* If we don't have a schema yet, we can't do anything... */
320         if (schema == NULL) {
321                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add childClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
322                 return LDB_ERR_OPERATIONS_ERROR;
323         }
324
325         /* Must remove any existing attribute, or else confusion reins */
326         ldb_msg_remove_attr(msg, attrName);
327         ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
328         if (ret != LDB_SUCCESS) {
329                 return ret;
330         }
331
332         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
333
334         for (i=0; oc_el && i < oc_el->num_values; i++) {
335                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
336                 if (!sclass) {
337                         /* We don't know this class?  what is going on? */
338                         continue;
339                 }
340
341                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
342                         ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
343                 }
344         }
345         if (allowedClasses->num_values > 1) {
346                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
347                 for (i=1 ; i < allowedClasses->num_values; i++) {
348                         struct ldb_val *val1 = &allowedClasses->values[i-1];
349                         struct ldb_val *val2 = &allowedClasses->values[i];
350                         if (data_blob_cmp(val1, val2) == 0) {
351                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
352                                 allowedClasses->num_values--;
353                                 i--;
354                         }
355                 }
356         }
357
358         return LDB_SUCCESS;
359 }
360
361 static int acl_childClassesEffective(struct ldb_module *module,
362                                      const struct dsdb_schema *schema,
363                                      struct ldb_message *sd_msg,
364                                      struct ldb_message *msg,
365                                      struct acl_context *ac)
366 {
367         struct ldb_message_element *oc_el;
368         struct ldb_message_element *allowedClasses = NULL;
369         const struct dsdb_class *sclass;
370         struct security_descriptor *sd;
371         struct ldb_control *as_system = ldb_request_get_control(ac->req,
372                                                                 LDB_CONTROL_AS_SYSTEM_OID);
373         struct dom_sid *sid = NULL;
374         unsigned int i, j;
375         int ret;
376
377         if (as_system != NULL) {
378                 as_system->critical = 0;
379         }
380
381         if (ac->am_system || as_system) {
382                 return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
383         }
384
385         /* If we don't have a schema yet, we can't do anything... */
386         if (schema == NULL) {
387                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add allowedChildClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
388                 return LDB_ERR_OPERATIONS_ERROR;
389         }
390
391         /* Must remove any existing attribute, or else confusion reins */
392         ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
393
394         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
395         ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
396         if (ret != LDB_SUCCESS) {
397                 return ret;
398         }
399
400         sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
401         for (i=0; oc_el && i < oc_el->num_values; i++) {
402                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
403                 if (!sclass) {
404                         /* We don't know this class?  what is going on? */
405                         continue;
406                 }
407
408                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
409                         const struct dsdb_class *sc;
410
411                         sc = dsdb_class_by_lDAPDisplayName(schema,
412                                                            sclass->possibleInferiors[j]);
413                         if (!sc) {
414                                 /* We don't know this class?  what is going on? */
415                                 continue;
416                         }
417
418                         ret = acl_check_access_on_objectclass(module, ac,
419                                                               sd, sid,
420                                                               SEC_ADS_CREATE_CHILD,
421                                                               sc);
422                         if (ret == LDB_SUCCESS) {
423                                 ldb_msg_add_string(msg, "allowedChildClassesEffective",
424                                                    sclass->possibleInferiors[j]);
425                         }
426                 }
427         }
428         allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
429         if (!allowedClasses) {
430                 return LDB_SUCCESS;
431         }
432
433         if (allowedClasses->num_values > 1) {
434                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
435                 for (i=1 ; i < allowedClasses->num_values; i++) {
436                         struct ldb_val *val1 = &allowedClasses->values[i-1];
437                         struct ldb_val *val2 = &allowedClasses->values[i];
438                         if (data_blob_cmp(val1, val2) == 0) {
439                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
440                                 allowedClasses->num_values--;
441                                 i--;
442                         }
443                 }
444         }
445         return LDB_SUCCESS;
446 }
447
448 static int acl_sDRightsEffective(struct ldb_module *module,
449                                  struct ldb_message *sd_msg,
450                                  struct ldb_message *msg,
451                                  struct acl_context *ac)
452 {
453         struct ldb_context *ldb = ldb_module_get_ctx(module);
454         struct ldb_message_element *rightsEffective;
455         int ret;
456         struct security_descriptor *sd;
457         struct ldb_control *as_system = ldb_request_get_control(ac->req,
458                                                                 LDB_CONTROL_AS_SYSTEM_OID);
459         struct dom_sid *sid = NULL;
460         uint32_t flags = 0;
461
462         if (as_system != NULL) {
463                 as_system->critical = 0;
464         }
465
466         /* Must remove any existing attribute, or else confusion reins */
467         ldb_msg_remove_attr(msg, "sDRightsEffective");
468         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
469         if (ret != LDB_SUCCESS) {
470                 return ret;
471         }
472         if (ac->am_system || as_system) {
473                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
474         } else {
475                 const struct dsdb_class *objectclass;
476                 const struct dsdb_attribute *attr;
477
478                 objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
479                 if (objectclass == NULL) {
480                         return ldb_operr(ldb);
481                 }
482
483                 attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
484                                                          "nTSecurityDescriptor");
485                 if (attr == NULL) {
486                         return ldb_operr(ldb);
487                 }
488
489                 /* Get the security descriptor from the message */
490                 ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
491                 if (ret != LDB_SUCCESS) {
492                         return ret;
493                 }
494                 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
495                 ret = acl_check_access_on_attribute(module,
496                                                     msg,
497                                                     sd,
498                                                     sid,
499                                                     SEC_STD_WRITE_OWNER,
500                                                     attr,
501                                                     objectclass);
502                 if (ret == LDB_SUCCESS) {
503                         flags |= SECINFO_OWNER | SECINFO_GROUP;
504                 }
505
506                 /*
507                  * This call is made with
508                  * IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS
509                  * and without reference to the dSHeuristics via
510                  * dsdb_block_owner_implicit_rights().  This is
511                  * probably a Windows bug but for now we match
512                  * exactly.
513                  */
514                 ret = acl_check_access_on_attribute_implicit_owner(
515                         module,
516                         msg,
517                         sd,
518                         sid,
519                         SEC_STD_WRITE_DAC,
520                         attr,
521                         objectclass,
522                         IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
523                 if (ret == LDB_SUCCESS) {
524                         flags |= SECINFO_DACL;
525                 }
526                 ret = acl_check_access_on_attribute(module,
527                                                     msg,
528                                                     sd,
529                                                     sid,
530                                                     SEC_FLAG_SYSTEM_SECURITY,
531                                                     attr,
532                                                     objectclass);
533                 if (ret == LDB_SUCCESS) {
534                         flags |= SECINFO_SACL;
535                 }
536         }
537
538         if (flags != (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_SACL)) {
539                 const struct ldb_message_element *el = samdb_find_attribute(ldb,
540                                                                             sd_msg,
541                                                                             "objectclass",
542                                                                             "computer");
543                 if (el != NULL) {
544                         return LDB_SUCCESS;
545                 }
546         }
547
548         return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
549                                   "sDRightsEffective", flags);
550 }
551
552 static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
553                                   struct ldb_context *ldb,
554                                   const struct ldb_val *spn_value,
555                                   uint32_t userAccountControl,
556                                   const struct ldb_val *samAccountName,
557                                   const struct ldb_val *dnsHostName,
558                                   const char *netbios_name,
559                                   const char *ntds_guid)
560 {
561         int ret, princ_size;
562         krb5_context krb_ctx;
563         krb5_error_code kerr;
564         krb5_principal principal;
565         char *instanceName;
566         char *serviceType;
567         char *serviceName;
568         const char *spn_value_str = NULL;
569         size_t account_name_len;
570         const char *forest_name = samdb_forest_name(ldb, mem_ctx);
571         const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
572         struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
573                                                           struct loadparm_context);
574         bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
575                 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
576
577         spn_value_str = talloc_strndup(mem_ctx,
578                                        (const char *)spn_value->data,
579                                        spn_value->length);
580         if (spn_value_str == NULL) {
581                 return ldb_oom(ldb);
582         }
583
584         if (spn_value->length == samAccountName->length &&
585             strncasecmp((const char *)spn_value->data,
586                         (const char *)samAccountName->data,
587                         spn_value->length) == 0)
588         {
589                 /* MacOS X sets this value, and setting an SPN of your
590                  * own samAccountName is both pointless and safe */
591                 return LDB_SUCCESS;
592         }
593
594         kerr = smb_krb5_init_context_basic(mem_ctx,
595                                            lp_ctx,
596                                            &krb_ctx);
597         if (kerr != 0) {
598                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
599                                  "Could not initialize kerberos context.");
600         }
601
602         ret = krb5_parse_name(krb_ctx, spn_value_str, &principal);
603         if (ret) {
604                 krb5_free_context(krb_ctx);
605                 return LDB_ERR_CONSTRAINT_VIOLATION;
606         }
607
608         princ_size = krb5_princ_size(krb_ctx, principal);
609         if (princ_size < 2) {
610                 DBG_WARNING("princ_size=%d\n", princ_size);
611                 goto fail;
612         }
613
614         instanceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
615                                                           principal, 1);
616         serviceType = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
617                                                          principal, 0);
618         if (krb5_princ_size(krb_ctx, principal) == 3) {
619                 serviceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
620                                                                  principal, 2);
621         } else {
622                 serviceName = NULL;
623         }
624
625         if (serviceName) {
626                 if (!is_dc) {
627                         DBG_WARNING("is_dc=false, serviceName=%s,"
628                                     "serviceType=%s\n", serviceName,
629                                   serviceType);
630                         goto fail;
631                 }
632                 if (strcasecmp(serviceType, "ldap") == 0) {
633                         if (strcasecmp(serviceName, netbios_name) != 0 &&
634                             strcasecmp(serviceName, forest_name) != 0) {
635                                 DBG_WARNING("serviceName=%s\n", serviceName);
636                                 goto fail;
637                         }
638
639                 } else if (strcasecmp(serviceType, "gc") == 0) {
640                         if (strcasecmp(serviceName, forest_name) != 0) {
641                                 DBG_WARNING("serviceName=%s\n", serviceName);
642                                 goto fail;
643                         }
644                 } else {
645                         if (strcasecmp(serviceName, base_domain) != 0 &&
646                             strcasecmp(serviceName, netbios_name) != 0) {
647                                 DBG_WARNING("serviceType=%s, "
648                                             "serviceName=%s\n",
649                                             serviceType, serviceName);
650                                 goto fail;
651                         }
652                 }
653         }
654
655         account_name_len = samAccountName->length;
656         if (account_name_len &&
657             samAccountName->data[account_name_len - 1] == '$')
658         {
659                 /* Account for the '$' character. */
660                 --account_name_len;
661         }
662
663         /* instanceName can be samAccountName without $ or dnsHostName
664          * or "ntds_guid._msdcs.forest_domain for DC objects */
665         if (strlen(instanceName) == account_name_len
666             && strncasecmp(instanceName,
667                            (const char *)samAccountName->data,
668                            account_name_len) == 0)
669         {
670                 goto success;
671         }
672         if ((dnsHostName != NULL) &&
673             strlen(instanceName) == dnsHostName->length &&
674             (strncasecmp(instanceName,
675                          (const char *)dnsHostName->data,
676                          dnsHostName->length) == 0))
677         {
678                 goto success;
679         }
680         if (is_dc) {
681                 const char *guid_str;
682                 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
683                                            ntds_guid,
684                                            forest_name);
685                 if (strcasecmp(instanceName, guid_str) == 0) {
686                         goto success;
687                 }
688         }
689
690 fail:
691         krb5_free_principal(krb_ctx, principal);
692         krb5_free_context(krb_ctx);
693         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
694                       "acl: spn validation failed for "
695                       "spn[%.*s] uac[0x%x] account[%.*s] hostname[%.*s] "
696                       "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
697                       (int)spn_value->length, spn_value->data,
698                       (unsigned)userAccountControl,
699                       (int)samAccountName->length, samAccountName->data,
700                       dnsHostName != NULL ? (int)dnsHostName->length : 0,
701                       dnsHostName != NULL ? (const char *)dnsHostName->data : "",
702                       netbios_name, ntds_guid,
703                       forest_name, base_domain);
704         return LDB_ERR_CONSTRAINT_VIOLATION;
705
706 success:
707         krb5_free_principal(krb_ctx, principal);
708         krb5_free_context(krb_ctx);
709         return LDB_SUCCESS;
710 }
711
712 /*
713  * Passing in 'el' is critical, we want to check all the values.
714  *
715  */
716 static int acl_check_spn(TALLOC_CTX *mem_ctx,
717                          struct ldb_module *module,
718                          struct ldb_request *req,
719                          const struct ldb_message_element *el,
720                          struct security_descriptor *sd,
721                          struct dom_sid *sid,
722                          const struct dsdb_attribute *attr,
723                          const struct dsdb_class *objectclass,
724                          const struct ldb_control *implicit_validated_write_control)
725 {
726         int ret;
727         unsigned int i;
728         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
729         struct ldb_context *ldb = ldb_module_get_ctx(module);
730         struct ldb_result *acl_res;
731         struct ldb_result *netbios_res;
732         struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
733         uint32_t userAccountControl;
734         const char *netbios_name;
735         const struct ldb_val *dns_host_name_val = NULL;
736         const struct ldb_val *sam_account_name_val = NULL;
737         struct GUID ntds;
738         char *ntds_guid = NULL;
739         const struct ldb_message *msg = NULL;
740         const struct ldb_message *search_res = NULL;
741
742         static const char *acl_attrs[] = {
743                 "samAccountName",
744                 "dnsHostName",
745                 "userAccountControl",
746                 NULL
747         };
748         static const char *netbios_attrs[] = {
749                 "nETBIOSName",
750                 NULL
751         };
752
753         if (req->operation == LDB_MODIFY) {
754                 msg = req->op.mod.message;
755         } else if (req->operation == LDB_ADD) {
756                 msg = req->op.add.message;
757         }
758
759         if (implicit_validated_write_control != NULL) {
760                 /*
761                  * The validated write control dispenses with ACL
762                  * checks. We act as if we have an implicit Self Write
763                  * privilege, but, assuming we don't have Write
764                  * Property, still proceed with further validation
765                  * checks.
766                  */
767         } else {
768                 /* if we have wp, we can do whatever we like */
769                 if (acl_check_access_on_attribute(module,
770                                                   tmp_ctx,
771                                                   sd,
772                                                   sid,
773                                                   SEC_ADS_WRITE_PROP,
774                                                   attr, objectclass) == LDB_SUCCESS) {
775                         talloc_free(tmp_ctx);
776                         return LDB_SUCCESS;
777                 }
778
779                 ret = acl_check_extended_right(tmp_ctx,
780                                                module,
781                                                req,
782                                                objectclass,
783                                                sd,
784                                                acl_user_token(module),
785                                                GUID_DRS_VALIDATE_SPN,
786                                                SEC_ADS_SELF_WRITE,
787                                                sid);
788
789                 if (ret != LDB_SUCCESS) {
790                         dsdb_acl_debug(sd, acl_user_token(module),
791                                        msg->dn,
792                                        true,
793                                        10);
794                         talloc_free(tmp_ctx);
795                         return ret;
796                 }
797         }
798
799         /*
800          * If we have "validated write spn", allow delete of any
801          * existing value (this keeps constrained delete to the same
802          * rules as unconstrained)
803          */
804         if (req->operation == LDB_MODIFY) {
805                 /*
806                  * If not add or replace (eg delete),
807                  * return success
808                  */
809                 if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
810                     LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
811                 {
812                         talloc_free(tmp_ctx);
813                         return LDB_SUCCESS;
814                 }
815
816                 ret = dsdb_module_search_dn(module, tmp_ctx,
817                                             &acl_res, msg->dn,
818                                             acl_attrs,
819                                             DSDB_FLAG_NEXT_MODULE |
820                                             DSDB_FLAG_AS_SYSTEM |
821                                             DSDB_SEARCH_SHOW_RECYCLED,
822                                             req);
823                 if (ret != LDB_SUCCESS) {
824                         talloc_free(tmp_ctx);
825                         return ret;
826                 }
827
828                 search_res = acl_res->msgs[0];
829         } else if (req->operation == LDB_ADD) {
830                 search_res = msg;
831         } else {
832                 talloc_free(tmp_ctx);
833                 return LDB_ERR_OPERATIONS_ERROR;
834         }
835
836         if (req->operation == LDB_MODIFY) {
837                 dns_host_name_val = ldb_msg_find_ldb_val(search_res, "dNSHostName");
838         }
839
840         ret = dsdb_msg_get_single_value(msg,
841                                         "dNSHostName",
842                                         dns_host_name_val,
843                                         &dns_host_name_val,
844                                         req->operation);
845         if (ret != LDB_SUCCESS) {
846                 talloc_free(tmp_ctx);
847                 return ret;
848         }
849
850         userAccountControl = ldb_msg_find_attr_as_uint(search_res, "userAccountControl", 0);
851
852         if (req->operation == LDB_MODIFY) {
853                 sam_account_name_val = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
854         }
855
856         ret = dsdb_msg_get_single_value(msg,
857                                         "sAMAccountName",
858                                         sam_account_name_val,
859                                         &sam_account_name_val,
860                                         req->operation);
861         if (ret != LDB_SUCCESS) {
862                 talloc_free(tmp_ctx);
863                 return ret;
864         }
865
866         ret = dsdb_module_search(module, tmp_ctx,
867                                  &netbios_res, partitions_dn,
868                                  LDB_SCOPE_ONELEVEL,
869                                  netbios_attrs,
870                                  DSDB_FLAG_NEXT_MODULE |
871                                  DSDB_FLAG_AS_SYSTEM,
872                                  req,
873                                  "(ncName=%s)",
874                                  ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
875
876         netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
877
878         /*
879          * NTDSDSA objectGuid of object we are checking SPN for
880          *
881          * Note - do we have the necessary attributes for this during an add operation?
882          * How should we test this?
883          */
884         if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
885                 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
886                                                              msg->dn, &ntds, req);
887                 if (ret != LDB_SUCCESS) {
888                         ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
889                                                ldb_dn_get_linearized(msg->dn),
890                                                ldb_strerror(ret));
891                         talloc_free(tmp_ctx);
892                         return LDB_ERR_OPERATIONS_ERROR;
893                 }
894                 ntds_guid = GUID_string(tmp_ctx, &ntds);
895         }
896
897         for (i=0; i < el->num_values; i++) {
898                 ret = acl_validate_spn_value(tmp_ctx,
899                                              ldb,
900                                              &el->values[i],
901                                              userAccountControl,
902                                              sam_account_name_val,
903                                              dns_host_name_val,
904                                              netbios_name,
905                                              ntds_guid);
906                 if (ret != LDB_SUCCESS) {
907                         talloc_free(tmp_ctx);
908                         return ret;
909                 }
910         }
911         talloc_free(tmp_ctx);
912         return LDB_SUCCESS;
913 }
914
915 static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
916                                    struct ldb_module *module,
917                                    struct ldb_request *req,
918                                    const struct ldb_message_element *el,
919                                    struct security_descriptor *sd,
920                                    struct dom_sid *sid,
921                                    const struct dsdb_attribute *attr,
922                                    const struct dsdb_class *objectclass,
923                                    const struct ldb_control *implicit_validated_write_control)
924 {
925         int ret;
926         unsigned i;
927         TALLOC_CTX *tmp_ctx = NULL;
928         struct ldb_context *ldb = ldb_module_get_ctx(module);
929         const struct dsdb_schema *schema = NULL;
930         const struct ldb_message_element *allowed_suffixes = NULL;
931         struct ldb_result *nc_res = NULL;
932         struct ldb_dn *nc_root = NULL;
933         const char *nc_dns_name = NULL;
934         const char *dnsHostName_str = NULL;
935         size_t dns_host_name_len;
936         size_t account_name_len;
937         const struct ldb_message *msg = NULL;
938         const struct ldb_message *search_res = NULL;
939         const struct ldb_val *samAccountName = NULL;
940         const struct ldb_val *dnsHostName = NULL;
941         const struct dsdb_class *computer_objectclass = NULL;
942         bool is_subclass;
943
944         static const char *nc_attrs[] = {
945                 "msDS-AllowedDNSSuffixes",
946                 NULL
947         };
948
949         if (el->num_values == 0) {
950                 return LDB_SUCCESS;
951         }
952         dnsHostName = &el->values[0];
953
954         tmp_ctx = talloc_new(mem_ctx);
955         if (tmp_ctx == NULL) {
956                 return ldb_oom(ldb);
957         }
958
959         if (req->operation == LDB_MODIFY) {
960                 msg = req->op.mod.message;
961         } else if (req->operation == LDB_ADD) {
962                 msg = req->op.add.message;
963         }
964
965         if (implicit_validated_write_control != NULL) {
966                 /*
967                  * The validated write control dispenses with ACL
968                  * checks. We act as if we have an implicit Self Write
969                  * privilege, but, assuming we don't have Write
970                  * Property, still proceed with further validation
971                  * checks.
972                  */
973         } else {
974                 /* if we have wp, we can do whatever we like */
975                 ret = acl_check_access_on_attribute(module,
976                                                     tmp_ctx,
977                                                     sd,
978                                                     sid,
979                                                     SEC_ADS_WRITE_PROP,
980                                                     attr, objectclass);
981                 if (ret == LDB_SUCCESS) {
982                         talloc_free(tmp_ctx);
983                         return LDB_SUCCESS;
984                 }
985
986                 ret = acl_check_extended_right(tmp_ctx,
987                                                module,
988                                                req,
989                                                objectclass,
990                                                sd,
991                                                acl_user_token(module),
992                                                GUID_DRS_DNS_HOST_NAME,
993                                                SEC_ADS_SELF_WRITE,
994                                                sid);
995
996                 if (ret != LDB_SUCCESS) {
997                         dsdb_acl_debug(sd, acl_user_token(module),
998                                        msg->dn,
999                                        true,
1000                                        10);
1001                         talloc_free(tmp_ctx);
1002                         return ret;
1003                 }
1004         }
1005
1006         /*
1007          * If we have "validated write dnshostname", allow delete of
1008          * any existing value (this keeps constrained delete to the
1009          * same rules as unconstrained)
1010          */
1011         if (req->operation == LDB_MODIFY) {
1012                 struct ldb_result *acl_res = NULL;
1013
1014                 static const char *acl_attrs[] = {
1015                         "sAMAccountName",
1016                         NULL
1017                 };
1018
1019                 /*
1020                  * If not add or replace (eg delete),
1021                  * return success
1022                  */
1023                 if ((el->flags
1024                      & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0)
1025                 {
1026                         talloc_free(tmp_ctx);
1027                         return LDB_SUCCESS;
1028                 }
1029
1030                 ret = dsdb_module_search_dn(module, tmp_ctx,
1031                                             &acl_res, msg->dn,
1032                                             acl_attrs,
1033                                             DSDB_FLAG_NEXT_MODULE |
1034                                             DSDB_FLAG_AS_SYSTEM |
1035                                             DSDB_SEARCH_SHOW_RECYCLED,
1036                                             req);
1037                 if (ret != LDB_SUCCESS) {
1038                         talloc_free(tmp_ctx);
1039                         return ret;
1040                 }
1041
1042                 search_res = acl_res->msgs[0];
1043         } else if (req->operation == LDB_ADD) {
1044                 search_res = msg;
1045         } else {
1046                 talloc_free(tmp_ctx);
1047                 return LDB_ERR_OPERATIONS_ERROR;
1048         }
1049
1050         /* Check if the account has objectclass 'computer' or 'server'. */
1051
1052         schema = dsdb_get_schema(ldb, req);
1053         if (schema == NULL) {
1054                 talloc_free(tmp_ctx);
1055                 return ldb_operr(ldb);
1056         }
1057
1058         computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
1059         if (computer_objectclass == NULL) {
1060                 talloc_free(tmp_ctx);
1061                 return ldb_operr(ldb);
1062         }
1063
1064         is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
1065         if (!is_subclass) {
1066                 /* The account is not a computer -- check if it's a server. */
1067
1068                 const struct dsdb_class *server_objectclass = NULL;
1069
1070                 server_objectclass = dsdb_class_by_lDAPDisplayName(schema, "server");
1071                 if (server_objectclass == NULL) {
1072                         talloc_free(tmp_ctx);
1073                         return ldb_operr(ldb);
1074                 }
1075
1076                 is_subclass = dsdb_is_subclass_of(schema, objectclass, server_objectclass);
1077                 if (!is_subclass) {
1078                         /* Not a computer or server, so no need to validate. */
1079                         talloc_free(tmp_ctx);
1080                         return LDB_SUCCESS;
1081                 }
1082         }
1083
1084         if (req->operation == LDB_MODIFY) {
1085                 samAccountName = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
1086         }
1087
1088         ret = dsdb_msg_get_single_value(msg,
1089                                         "sAMAccountName",
1090                                         samAccountName,
1091                                         &samAccountName,
1092                                         req->operation);
1093         if (ret != LDB_SUCCESS) {
1094                 talloc_free(tmp_ctx);
1095                 return ret;
1096         }
1097
1098         account_name_len = samAccountName->length;
1099         if (account_name_len && samAccountName->data[account_name_len - 1] == '$') {
1100                 /* Account for the '$' character. */
1101                 --account_name_len;
1102         }
1103
1104         dnsHostName_str = (const char *)dnsHostName->data;
1105         dns_host_name_len = dnsHostName->length;
1106
1107         /* Check that sAMAccountName matches the new dNSHostName. */
1108
1109         if (dns_host_name_len < account_name_len) {
1110                 goto fail;
1111         }
1112         if (strncasecmp(dnsHostName_str,
1113                         (const char *)samAccountName->data,
1114                         account_name_len) != 0)
1115         {
1116                 goto fail;
1117         }
1118
1119         dnsHostName_str += account_name_len;
1120         dns_host_name_len -= account_name_len;
1121
1122         /* Check the '.' character */
1123
1124         if (dns_host_name_len == 0 || *dnsHostName_str != '.') {
1125                 goto fail;
1126         }
1127
1128         ++dnsHostName_str;
1129         --dns_host_name_len;
1130
1131         /* Now we check the suffix. */
1132
1133         ret = dsdb_find_nc_root(ldb,
1134                                 tmp_ctx,
1135                                 search_res->dn,
1136                                 &nc_root);
1137         if (ret != LDB_SUCCESS) {
1138                 talloc_free(tmp_ctx);
1139                 return ret;
1140         }
1141
1142         nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root);
1143         if (nc_dns_name == NULL) {
1144                 talloc_free(tmp_ctx);
1145                 return ldb_operr(ldb);
1146         }
1147
1148         if (strlen(nc_dns_name) == dns_host_name_len &&
1149             strncasecmp(dnsHostName_str,
1150                         nc_dns_name,
1151                         dns_host_name_len) == 0)
1152         {
1153                 /* It matches -- success. */
1154                 talloc_free(tmp_ctx);
1155                 return LDB_SUCCESS;
1156         }
1157
1158         /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */
1159
1160         ret = dsdb_module_search_dn(module, tmp_ctx,
1161                                     &nc_res, nc_root,
1162                                     nc_attrs,
1163                                     DSDB_FLAG_NEXT_MODULE |
1164                                     DSDB_FLAG_AS_SYSTEM |
1165                                     DSDB_SEARCH_SHOW_RECYCLED,
1166                                     req);
1167         if (ret != LDB_SUCCESS) {
1168                 talloc_free(tmp_ctx);
1169                 return ret;
1170         }
1171
1172         allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0],
1173                                                 "msDS-AllowedDNSSuffixes");
1174         if (allowed_suffixes == NULL) {
1175                 goto fail;
1176         }
1177
1178         for (i = 0; i < allowed_suffixes->num_values; ++i) {
1179                 const struct ldb_val *suffix = &allowed_suffixes->values[i];
1180
1181                 if (suffix->length == dns_host_name_len &&
1182                     strncasecmp(dnsHostName_str,
1183                                 (const char *)suffix->data,
1184                                 dns_host_name_len) == 0)
1185                 {
1186                         /* It matches -- success. */
1187                         talloc_free(tmp_ctx);
1188                         return LDB_SUCCESS;
1189                 }
1190         }
1191
1192 fail:
1193         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
1194                       "acl: hostname validation failed for "
1195                       "hostname[%.*s] account[%.*s]\n",
1196                       (int)dnsHostName->length, dnsHostName->data,
1197                       (int)samAccountName->length, samAccountName->data);
1198         talloc_free(tmp_ctx);
1199         return LDB_ERR_CONSTRAINT_VIOLATION;
1200 }
1201
1202 /* checks if modifications are allowed on "Member" attribute */
1203 static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
1204                                      struct ldb_module *module,
1205                                      struct ldb_request *req,
1206                                      struct security_descriptor *sd,
1207                                      struct dom_sid *sid,
1208                                      const struct dsdb_attribute *attr,
1209                                      const struct dsdb_class *objectclass)
1210 {
1211         int ret;
1212         unsigned int i;
1213         struct ldb_context *ldb = ldb_module_get_ctx(module);
1214         struct ldb_dn *user_dn;
1215         struct ldb_message_element *member_el;
1216         const struct ldb_message *msg = NULL;
1217
1218         if (req->operation == LDB_MODIFY) {
1219                 msg = req->op.mod.message;
1220         } else if (req->operation == LDB_ADD) {
1221                 msg = req->op.add.message;
1222         } else {
1223                 return LDB_ERR_OPERATIONS_ERROR;
1224         }
1225
1226         /* if we have wp, we can do whatever we like */
1227         if (acl_check_access_on_attribute(module,
1228                                           mem_ctx,
1229                                           sd,
1230                                           sid,
1231                                           SEC_ADS_WRITE_PROP,
1232                                           attr, objectclass) == LDB_SUCCESS) {
1233                 return LDB_SUCCESS;
1234         }
1235         /* if we are adding/deleting ourselves, check for self membership */
1236         ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
1237                                   &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
1238                                   &user_dn);
1239         if (ret != LDB_SUCCESS) {
1240                 return ret;
1241         }
1242         member_el = ldb_msg_find_element(msg, "member");
1243         if (!member_el) {
1244                 return ldb_operr(ldb);
1245         }
1246         /* user can only remove oneself */
1247         if (member_el->num_values == 0) {
1248                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1249         }
1250         for (i = 0; i < member_el->num_values; i++) {
1251                 if (strcasecmp((const char *)member_el->values[i].data,
1252                                ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
1253                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1254                 }
1255         }
1256         ret = acl_check_extended_right(mem_ctx,
1257                                        module,
1258                                        req,
1259                                        objectclass,
1260                                        sd,
1261                                        acl_user_token(module),
1262                                        GUID_DRS_SELF_MEMBERSHIP,
1263                                        SEC_ADS_SELF_WRITE,
1264                                        sid);
1265         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1266                 dsdb_acl_debug(sd, acl_user_token(module),
1267                                msg->dn,
1268                                true,
1269                                10);
1270         }
1271         return ret;
1272 }
1273
1274 static int acl_add(struct ldb_module *module, struct ldb_request *req)
1275 {
1276         int ret;
1277         struct ldb_dn *parent;
1278         struct ldb_context *ldb;
1279         const struct dsdb_schema *schema;
1280         const struct dsdb_class *objectclass;
1281         const struct dsdb_class *computer_objectclass = NULL;
1282         const struct ldb_message_element *oc_el = NULL;
1283         struct ldb_message_element sorted_oc_el;
1284         struct ldb_control *as_system;
1285         struct ldb_control *sd_ctrl = NULL;
1286         struct ldb_message_element *el;
1287         unsigned int instanceType = 0;
1288         struct dsdb_control_calculated_default_sd *control_sd = NULL;
1289         const struct dsdb_attribute *attr = NULL;
1290         const char **must_contain = NULL;
1291         const struct ldb_message *msg = req->op.add.message;
1292         const struct dom_sid *domain_sid = NULL;
1293         int i = 0;
1294         bool attribute_authorization;
1295         bool is_subclass;
1296
1297         if (ldb_dn_is_special(msg->dn)) {
1298                 return ldb_next_request(module, req);
1299         }
1300
1301         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1302         if (as_system != NULL) {
1303                 as_system->critical = 0;
1304         }
1305
1306         if (dsdb_module_am_system(module) || as_system) {
1307                 return ldb_next_request(module, req);
1308         }
1309
1310         ldb = ldb_module_get_ctx(module);
1311         domain_sid = samdb_domain_sid(ldb);
1312
1313         parent = ldb_dn_get_parent(req, msg->dn);
1314         if (parent == NULL) {
1315                 return ldb_oom(ldb);
1316         }
1317
1318         schema = dsdb_get_schema(ldb, req);
1319         if (!schema) {
1320                 return ldb_operr(ldb);
1321         }
1322
1323         /* Find the objectclass of the new account. */
1324
1325         oc_el = ldb_msg_find_element(msg, "objectclass");
1326         if (oc_el == NULL) {
1327                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1328                                        "acl: unable to find or validate structural objectClass on %s\n",
1329                                        ldb_dn_get_linearized(msg->dn));
1330                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
1331         }
1332
1333         schema = dsdb_get_schema(ldb, req);
1334         if (schema == NULL) {
1335                 return ldb_operr(ldb);
1336         }
1337
1338         ret = dsdb_sort_objectClass_attr(ldb, schema, oc_el, req, &sorted_oc_el);
1339         if (ret != LDB_SUCCESS) {
1340                 return ret;
1341         }
1342
1343         objectclass = dsdb_get_last_structural_class(schema, &sorted_oc_el);
1344         if (objectclass == NULL) {
1345                 return ldb_operr(ldb);
1346         }
1347
1348         el = ldb_msg_find_element(msg, "instanceType");
1349         if ((el != NULL) && (el->num_values != 1)) {
1350                 ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
1351                 return LDB_ERR_UNWILLING_TO_PERFORM;
1352         }
1353
1354         instanceType = ldb_msg_find_attr_as_uint(msg,
1355                                                  "instanceType", 0);
1356         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
1357                 static const char *no_attrs[] = { NULL };
1358                 struct ldb_result *partition_res;
1359                 struct ldb_dn *partitions_dn;
1360
1361                 partitions_dn = samdb_partitions_dn(ldb, req);
1362                 if (!partitions_dn) {
1363                         ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
1364                         return LDB_ERR_UNWILLING_TO_PERFORM;
1365                 }
1366
1367                 ret = dsdb_module_search(module, req, &partition_res,
1368                                          partitions_dn, LDB_SCOPE_ONELEVEL,
1369                                          no_attrs,
1370                                          DSDB_FLAG_NEXT_MODULE |
1371                                          DSDB_FLAG_AS_SYSTEM |
1372                                          DSDB_SEARCH_ONE_ONLY |
1373                                          DSDB_SEARCH_SHOW_RECYCLED,
1374                                          req,
1375                                          "(&(nCName=%s)(objectClass=crossRef))",
1376                                          ldb_dn_get_linearized(msg->dn));
1377
1378                 if (ret == LDB_SUCCESS) {
1379                         /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1380                         ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
1381                                                              SEC_ADS_WRITE_PROP,
1382                                                              &objectclass->schemaIDGUID, req);
1383                         if (ret != LDB_SUCCESS) {
1384                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1385                                                        "acl: ACL check failed on crossRef object %s: %s\n",
1386                                                        ldb_dn_get_linearized(partition_res->msgs[0]->dn),
1387                                                        ldb_errstring(ldb));
1388                                 return ret;
1389                         }
1390
1391                         /*
1392                          * TODO: Remaining checks, like if we are
1393                          * the naming master etc need to be handled
1394                          * in the instanceType module
1395                          */
1396                         /* Note - do we need per-attribute checks? */
1397                         return ldb_next_request(module, req);
1398                 }
1399
1400                 /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1401                 ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
1402                                                      SEC_ADS_CREATE_CHILD,
1403                                                      &objectclass->schemaIDGUID, req);
1404                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1405                     ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
1406                 {
1407                         /* Allow provision bootstrap */
1408                         ret = LDB_SUCCESS;
1409                 }
1410                 if (ret != LDB_SUCCESS) {
1411                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
1412                                                "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
1413                                                ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
1414                         return ret;
1415                 }
1416
1417                 /*
1418                  * TODO: Remaining checks, like if we are the naming
1419                  * master and adding the crossRef object need to be
1420                  * handled in the instanceType module
1421                  */
1422         } else {
1423                 ret = dsdb_module_check_access_on_dn(module, req, parent,
1424                                                      SEC_ADS_CREATE_CHILD,
1425                                                      &objectclass->schemaIDGUID, req);
1426                 if (ret != LDB_SUCCESS) {
1427                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
1428                                                "acl: unable to get access to %s\n",
1429                                                ldb_dn_get_linearized(msg->dn));
1430                         return ret;
1431                 }
1432         }
1433
1434         attribute_authorization = dsdb_attribute_authz_on_ldap_add(module,
1435                                                                    req,
1436                                                                    req);
1437         if (!attribute_authorization) {
1438                 /* Skip the remaining checks */
1439                 goto success;
1440         }
1441
1442         /* Check if we have computer objectclass. */
1443         computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
1444         if (computer_objectclass == NULL) {
1445                 return ldb_operr(ldb);
1446         }
1447
1448         is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
1449         if (!is_subclass) {
1450                 /*
1451                  * This object is not a computer (or derived from computer), so
1452                  * skip the remaining checks.
1453                  */
1454                 goto success;
1455         }
1456
1457         /*
1458          * we have established we have CC right, now check per-attribute
1459          * access based on the default SD
1460          */
1461
1462         sd_ctrl = ldb_request_get_control(req,
1463                                           DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID);
1464         if (sd_ctrl == NULL) {
1465                 goto success;
1466         }
1467
1468         {
1469                 TALLOC_CTX *tmp_ctx = talloc_new(req);
1470                 control_sd = (struct dsdb_control_calculated_default_sd *) sd_ctrl->data;
1471                 DBG_DEBUG("Received cookie descriptor %s\n\n",
1472                           sddl_encode(tmp_ctx, control_sd->default_sd, domain_sid));
1473                 TALLOC_FREE(tmp_ctx);
1474                 /* Mark the "change" control as uncritical (done) */
1475                 sd_ctrl->critical = false;
1476         }
1477
1478         /*
1479          * At this point we do not yet have the object's SID, so we
1480          * leave it empty. It is irrelevant, as it is used to expand
1481          * Principal-Self, and rights granted to PS will have no effect
1482          * in this case
1483          */
1484         /* check if we have WD, no need to perform other attribute checks if we do */
1485         attr = dsdb_attribute_by_lDAPDisplayName(schema, "nTSecurityDescriptor");
1486         if (attr == NULL) {
1487                 return ldb_operr(ldb);
1488         }
1489
1490         if (control_sd->specified_sacl) {
1491                 const struct security_token *token = acl_user_token(module);
1492                 bool has_priv = security_token_has_privilege(token, SEC_PRIV_SECURITY);
1493                 if (!has_priv) {
1494                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1495                 }
1496         }
1497
1498         ret = acl_check_access_on_attribute(module,
1499                                             req,
1500                                             control_sd->default_sd,
1501                                             NULL,
1502                                             SEC_STD_WRITE_DAC,
1503                                             attr,
1504                                             objectclass);
1505         if (ret == LDB_SUCCESS) {
1506                 goto success;
1507         }
1508
1509         if (control_sd->specified_sd) {
1510                 bool block_owner_rights = dsdb_block_owner_implicit_rights(module,
1511                                                                            req,
1512                                                                            req);
1513                 if (block_owner_rights) {
1514                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
1515                                                "Object %s has no SD modification rights",
1516                                                ldb_dn_get_linearized(msg->dn));
1517                         dsdb_acl_debug(control_sd->default_sd,
1518                                        acl_user_token(module),
1519                                        msg->dn,
1520                                        true,
1521                                        10);
1522                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1523                         return ret;
1524                 }
1525         }
1526
1527         must_contain = dsdb_full_attribute_list(req, schema, &sorted_oc_el,
1528                                                 DSDB_SCHEMA_ALL_MUST);
1529         for (i=0; i < msg->num_elements; i++) {
1530                 el = &msg->elements[i];
1531
1532                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1533                 if (attr == NULL && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1534                         ldb_asprintf_errstring(ldb, "acl_add: attribute '%s' "
1535                                                "on entry '%s' was not found in the schema!",
1536                                                el->name,
1537                                        ldb_dn_get_linearized(msg->dn));
1538                         ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1539                         return ret;
1540                 }
1541
1542                 if (attr != NULL) {
1543                         bool found = str_list_check(must_contain, attr->lDAPDisplayName);
1544                         /* do not check the mandatory attributes */
1545                         if (found) {
1546                                 continue;
1547                         }
1548                 }
1549
1550                 if (ldb_attr_cmp("dBCSPwd", el->name) == 0 ||
1551                            ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1552                            ldb_attr_cmp("userPassword", el->name) == 0 ||
1553                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1554                         continue;
1555                 } else if (ldb_attr_cmp("member", el->name) == 0) {
1556                         ret = acl_check_self_membership(req,
1557                                                         module,
1558                                                         req,
1559                                                         control_sd->default_sd,
1560                                                         NULL,
1561                                                         attr,
1562                                                         objectclass);
1563                         if (ret != LDB_SUCCESS) {
1564                                 return ret;
1565                         }
1566                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1567                         ret = acl_check_spn(req,
1568                                             module,
1569                                             req,
1570                                             el,
1571                                             control_sd->default_sd,
1572                                             NULL,
1573                                             attr,
1574                                             objectclass,
1575                                             NULL);
1576                         if (ret != LDB_SUCCESS) {
1577                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1578                                                        "Object %s cannot be created with spn",
1579                                                        ldb_dn_get_linearized(msg->dn));
1580                                 dsdb_acl_debug(control_sd->default_sd,
1581                                                acl_user_token(module),
1582                                                msg->dn,
1583                                                true,
1584                                                10);
1585                                 return ret;
1586                         }
1587                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
1588                         ret = acl_check_dns_host_name(req,
1589                                                       module,
1590                                                       req,
1591                                                       el,
1592                                                       control_sd->default_sd,
1593                                                       NULL,
1594                                                       attr,
1595                                                       objectclass,
1596                                                       NULL);
1597                         if (ret != LDB_SUCCESS) {
1598                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1599                                                        "Object %s cannot be created with dnsHostName",
1600                                                        ldb_dn_get_linearized(msg->dn));
1601                                 dsdb_acl_debug(control_sd->default_sd,
1602                                                acl_user_token(module),
1603                                                msg->dn,
1604                                                true,
1605                                                10);
1606                                 return ret;
1607                         }
1608                 } else {
1609                         ret = acl_check_access_on_attribute(module,
1610                                                             req,
1611                                                             control_sd->default_sd,
1612                                                             NULL,
1613                                                             SEC_ADS_WRITE_PROP,
1614                                                             attr,
1615                                                             objectclass);
1616                         if (ret != LDB_SUCCESS) {
1617                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1618                                                        "Object %s has no write property access",
1619                                                        ldb_dn_get_linearized(msg->dn));
1620                                 dsdb_acl_debug(control_sd->default_sd,
1621                                                acl_user_token(module),
1622                                                msg->dn,
1623                                                true,
1624                                                10);
1625                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1626                                 return ret;
1627                         }
1628                 }
1629         }
1630 success:
1631         return ldb_next_request(module, req);
1632 }
1633
1634 static int acl_check_password_rights(
1635         TALLOC_CTX *mem_ctx,
1636         struct ldb_module *module,
1637         struct ldb_request *req,
1638         struct security_descriptor *sd,
1639         struct dom_sid *sid,
1640         const struct dsdb_class *objectclass,
1641         bool userPassword,
1642         struct  dsdb_control_password_acl_validation **control_for_response)
1643 {
1644         int ret = LDB_SUCCESS;
1645         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
1646         unsigned int del_val_cnt = 0, add_val_cnt = 0, rep_val_cnt = 0;
1647         struct ldb_message_element *el;
1648         struct ldb_message *msg;
1649         struct ldb_control *c = NULL;
1650         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
1651                                         "unicodePwd", NULL }, **l;
1652         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1653         struct dsdb_control_password_acl_validation *pav = NULL;
1654
1655         if (tmp_ctx == NULL) {
1656                 return LDB_ERR_OPERATIONS_ERROR;
1657         }
1658
1659         pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
1660         if (pav == NULL) {
1661                 talloc_free(tmp_ctx);
1662                 return LDB_ERR_OPERATIONS_ERROR;
1663         }
1664         /*
1665          * Set control_for_response to pav so it can be added to the response
1666          * and be passed up to the audit_log module which uses it to identify
1667          * password reset attempts.
1668          */
1669         *control_for_response = pav;
1670
1671         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1672         if (c != NULL) {
1673                 pav->pwd_reset = false;
1674
1675                 /*
1676                  * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1677                  * have a user password change and not a set as the message
1678                  * looks like. In it's value blob it contains the NT and/or LM
1679                  * hash of the old password specified by the user.  This control
1680                  * is used by the SAMR and "kpasswd" password change mechanisms.
1681                  *
1682                  * This control can't be used by real LDAP clients,
1683                  * the only caller is samdb_set_password_internal(),
1684                  * so we don't have to strict verification of the input.
1685                  */
1686                 ret = acl_check_extended_right(tmp_ctx,
1687                                                module,
1688                                                req,
1689                                                objectclass,
1690                                                sd,
1691                                                acl_user_token(module),
1692                                                GUID_DRS_USER_CHANGE_PASSWORD,
1693                                                SEC_ADS_CONTROL_ACCESS,
1694                                                sid);
1695                 goto checked;
1696         }
1697
1698         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1699         if (c != NULL) {
1700                 pav->pwd_reset = true;
1701
1702                 /*
1703                  * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1704                  * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1705                  * have a force password set.
1706                  * This control is used by the SAMR/NETLOGON/LSA password
1707                  * reset mechanisms.
1708                  *
1709                  * This control can't be used by real LDAP clients,
1710                  * the only caller is samdb_set_password_internal(),
1711                  * so we don't have to strict verification of the input.
1712                  */
1713                 ret = acl_check_extended_right(tmp_ctx,
1714                                                module,
1715                                                req,
1716                                                objectclass,
1717                                                sd,
1718                                                acl_user_token(module),
1719                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1720                                                SEC_ADS_CONTROL_ACCESS,
1721                                                sid);
1722                 goto checked;
1723         }
1724
1725         el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1726         if (el != NULL) {
1727                 /*
1728                  * dBCSPwd is only allowed with a control.
1729                  */
1730                 talloc_free(tmp_ctx);
1731                 return LDB_ERR_UNWILLING_TO_PERFORM;
1732         }
1733
1734         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1735         if (msg == NULL) {
1736                 return ldb_module_oom(module);
1737         }
1738         for (l = passwordAttrs; *l != NULL; l++) {
1739                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1740                         continue;
1741                 }
1742
1743                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1744                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1745                                 ++del_attr_cnt;
1746                                 del_val_cnt += el->num_values;
1747                         }
1748                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1749                                 ++add_attr_cnt;
1750                                 add_val_cnt += el->num_values;
1751                         }
1752                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1753                                 ++rep_attr_cnt;
1754                                 rep_val_cnt += el->num_values;
1755                         }
1756                         ldb_msg_remove_element(msg, el);
1757                 }
1758         }
1759
1760         /* single deletes will be handled by the "password_hash" LDB module
1761          * later in the stack, so we let it though here */
1762         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1763                 talloc_free(tmp_ctx);
1764                 return LDB_SUCCESS;
1765         }
1766
1767
1768         if (rep_attr_cnt > 0) {
1769                 pav->pwd_reset = true;
1770
1771                 ret = acl_check_extended_right(tmp_ctx,
1772                                                module,
1773                                                req,
1774                                                objectclass,
1775                                                sd,
1776                                                acl_user_token(module),
1777                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1778                                                SEC_ADS_CONTROL_ACCESS,
1779                                                sid);
1780                 goto checked;
1781         }
1782
1783         if (add_attr_cnt != del_attr_cnt) {
1784                 pav->pwd_reset = true;
1785
1786                 ret = acl_check_extended_right(tmp_ctx,
1787                                                module,
1788                                                req,
1789                                                objectclass,
1790                                                sd,
1791                                                acl_user_token(module),
1792                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1793                                                SEC_ADS_CONTROL_ACCESS,
1794                                                sid);
1795                 goto checked;
1796         }
1797
1798         if (add_val_cnt == 1 && del_val_cnt == 1) {
1799                 pav->pwd_reset = false;
1800
1801                 ret = acl_check_extended_right(tmp_ctx,
1802                                                module,
1803                                                req,
1804                                                objectclass,
1805                                                sd,
1806                                                acl_user_token(module),
1807                                                GUID_DRS_USER_CHANGE_PASSWORD,
1808                                                SEC_ADS_CONTROL_ACCESS,
1809                                                sid);
1810                 /* Very strange, but we get constraint violation in this case */
1811                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1812                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1813                 }
1814                 goto checked;
1815         }
1816
1817         if (add_val_cnt == 1 && del_val_cnt == 0) {
1818                 pav->pwd_reset = true;
1819
1820                 ret = acl_check_extended_right(tmp_ctx,
1821                                                module,
1822                                                req,
1823                                                objectclass,
1824                                                sd,
1825                                                acl_user_token(module),
1826                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1827                                                SEC_ADS_CONTROL_ACCESS,
1828                                                sid);
1829                 /* Very strange, but we get constraint violation in this case */
1830                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1831                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1832                 }
1833                 goto checked;
1834         }
1835
1836         /*
1837          * Everything else is handled by the password_hash module where it will
1838          * fail, but with the correct error code when the module is again
1839          * checking the attributes. As the change request will lack the
1840          * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1841          * any modification attempt that went this way will be rejected.
1842          */
1843
1844         talloc_free(tmp_ctx);
1845         return LDB_SUCCESS;
1846
1847 checked:
1848         if (ret != LDB_SUCCESS) {
1849                 dsdb_acl_debug(sd, acl_user_token(module),
1850                                req->op.mod.message->dn,
1851                                true,
1852                                10);
1853                 talloc_free(tmp_ctx);
1854                 return ret;
1855         }
1856
1857         ret = ldb_request_add_control(req,
1858                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1859         if (ret != LDB_SUCCESS) {
1860                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1861                           "Unable to register ACL validation control!\n");
1862                 return ret;
1863         }
1864         return LDB_SUCCESS;
1865 }
1866
1867 /*
1868  * Context needed by acl_callback
1869  */
1870 struct acl_callback_context {
1871         struct ldb_request *request;
1872         struct ldb_module *module;
1873 };
1874
1875 /*
1876  * @brief Copy the password validation control to the reply.
1877  *
1878  * Copy the dsdb_control_password_acl_validation control from the request,
1879  * to the reply.  The control is used by the audit_log module to identify
1880  * password rests.
1881  *
1882  * @param req the ldb request.
1883  * @param ares the result, updated with the control.
1884  */
1885 static void copy_password_acl_validation_control(
1886         struct ldb_request *req,
1887         struct ldb_reply *ares)
1888 {
1889         struct ldb_control *pav_ctrl = NULL;
1890         struct dsdb_control_password_acl_validation *pav = NULL;
1891
1892         pav_ctrl = ldb_request_get_control(
1893                 discard_const(req),
1894                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1895         if (pav_ctrl == NULL) {
1896                 return;
1897         }
1898
1899         pav = talloc_get_type_abort(
1900                 pav_ctrl->data,
1901                 struct dsdb_control_password_acl_validation);
1902         if (pav == NULL) {
1903                 return;
1904         }
1905         ldb_reply_add_control(
1906                 ares,
1907                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1908                 false,
1909                 pav);
1910 }
1911 /*
1912  * @brief call back function for acl_modify.
1913  *
1914  * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1915  * the request to the reply.
1916  *
1917  * @param req the ldb_request.
1918  * @param ares the operation result.
1919  *
1920  * @return the LDB_STATUS
1921  */
1922 static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1923 {
1924         struct acl_callback_context *ac = NULL;
1925
1926         ac = talloc_get_type(req->context, struct acl_callback_context);
1927
1928         if (!ares) {
1929                 return ldb_module_done(
1930                         ac->request,
1931                         NULL,
1932                         NULL,
1933                         LDB_ERR_OPERATIONS_ERROR);
1934         }
1935
1936         /* pass on to the callback */
1937         switch (ares->type) {
1938         case LDB_REPLY_ENTRY:
1939                 return ldb_module_send_entry(
1940                         ac->request,
1941                         ares->message,
1942                         ares->controls);
1943
1944         case LDB_REPLY_REFERRAL:
1945                 return ldb_module_send_referral(
1946                         ac->request,
1947                         ares->referral);
1948
1949         case LDB_REPLY_DONE:
1950                 /*
1951                  * Copy the ACL control from the request to the response
1952                  */
1953                 copy_password_acl_validation_control(req, ares);
1954                 return ldb_module_done(
1955                         ac->request,
1956                         ares->controls,
1957                         ares->response,
1958                         ares->error);
1959
1960         default:
1961                 /* Can't happen */
1962                 return LDB_ERR_OPERATIONS_ERROR;
1963         }
1964 }
1965
1966 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1967 {
1968         int ret;
1969         struct ldb_context *ldb = ldb_module_get_ctx(module);
1970         const struct dsdb_schema *schema;
1971         unsigned int i;
1972         const struct dsdb_class *objectclass;
1973         struct ldb_result *acl_res;
1974         struct security_descriptor *sd;
1975         struct dom_sid *sid = NULL;
1976         struct ldb_control *as_system;
1977         struct ldb_control *is_undelete;
1978         struct ldb_control *implicit_validated_write_control = NULL;
1979         bool userPassword;
1980         bool password_rights_checked = false;
1981         TALLOC_CTX *tmp_ctx;
1982         const struct ldb_message *msg = req->op.mod.message;
1983         static const char *acl_attrs[] = {
1984                 "nTSecurityDescriptor",
1985                 "objectClass",
1986                 "objectSid",
1987                 NULL
1988         };
1989         struct acl_callback_context *context = NULL;
1990         struct ldb_request *new_req = NULL;
1991         struct  dsdb_control_password_acl_validation *pav = NULL;
1992         struct ldb_control **controls = NULL;
1993
1994         if (ldb_dn_is_special(msg->dn)) {
1995                 return ldb_next_request(module, req);
1996         }
1997
1998         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1999         if (as_system != NULL) {
2000                 as_system->critical = 0;
2001         }
2002
2003         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
2004
2005         implicit_validated_write_control = ldb_request_get_control(
2006                 req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
2007         if (implicit_validated_write_control != NULL) {
2008                 implicit_validated_write_control->critical = 0;
2009         }
2010
2011         /* Don't print this debug statement if elements[0].name is going to be NULL */
2012         if (msg->num_elements > 0) {
2013                 DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
2014         }
2015         if (dsdb_module_am_system(module) || as_system) {
2016                 return ldb_next_request(module, req);
2017         }
2018
2019         tmp_ctx = talloc_new(req);
2020         if (tmp_ctx == NULL) {
2021                 return ldb_oom(ldb);
2022         }
2023
2024         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
2025                                     acl_attrs,
2026                                     DSDB_FLAG_NEXT_MODULE |
2027                                     DSDB_FLAG_AS_SYSTEM |
2028                                     DSDB_SEARCH_SHOW_RECYCLED,
2029                                     req);
2030
2031         if (ret != LDB_SUCCESS) {
2032                 goto fail;
2033         }
2034
2035         userPassword = dsdb_user_password_support(module, req, req);
2036
2037         schema = dsdb_get_schema(ldb, tmp_ctx);
2038         if (!schema) {
2039                 talloc_free(tmp_ctx);
2040                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2041                                  "acl_modify: Error obtaining schema.");
2042         }
2043
2044         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
2045         if (ret != LDB_SUCCESS) {
2046                 talloc_free(tmp_ctx);
2047                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2048                                  "acl_modify: Error retrieving security descriptor.");
2049         }
2050         /* Theoretically we pass the check if the object has no sd */
2051         if (!sd) {
2052                 goto success;
2053         }
2054
2055         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2056         if (!objectclass) {
2057                 talloc_free(tmp_ctx);
2058                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2059                                  "acl_modify: Error retrieving object class for GUID.");
2060         }
2061         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2062         for (i=0; i < msg->num_elements; i++) {
2063                 const struct ldb_message_element *el = &msg->elements[i];
2064                 const struct dsdb_attribute *attr;
2065
2066                 /*
2067                  * This basic attribute existence check with the right errorcode
2068                  * is needed since this module is the first one which requests
2069                  * schema attribute information.
2070                  * The complete attribute checking is done in the
2071                  * "objectclass_attrs" module behind this one.
2072                  *
2073                  * NOTE: "clearTextPassword" is not defined in the schema.
2074                  */
2075                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2076                 if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
2077                         ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
2078                                                "on entry '%s' was not found in the schema!",
2079                                                req->op.mod.message->elements[i].name,
2080                                        ldb_dn_get_linearized(req->op.mod.message->dn));
2081                         ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
2082                         goto fail;
2083                 }
2084
2085                 if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
2086                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
2087                         uint32_t access_mask = 0;
2088
2089                         bool block_owner_rights;
2090                         enum implicit_owner_rights implicit_owner_rights;
2091
2092                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
2093                                 access_mask |= SEC_STD_WRITE_OWNER;
2094                         }
2095                         if (sd_flags & SECINFO_DACL) {
2096                                 access_mask |= SEC_STD_WRITE_DAC;
2097                         }
2098                         if (sd_flags & SECINFO_SACL) {
2099                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
2100                         }
2101
2102                         block_owner_rights = !dsdb_module_am_administrator(module);
2103
2104                         if (block_owner_rights) {
2105                                 block_owner_rights = dsdb_block_owner_implicit_rights(module,
2106                                                                                       req,
2107                                                                                       req);
2108                         }
2109                         if (block_owner_rights) {
2110                                 block_owner_rights = samdb_find_attribute(ldb,
2111                                                                           acl_res->msgs[0],
2112                                                                           "objectclass",
2113                                                                           "computer");
2114                         }
2115
2116                         implicit_owner_rights = block_owner_rights ?
2117                                 IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
2118                                 IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
2119
2120                         ret = acl_check_access_on_attribute_implicit_owner(module,
2121                                                                            tmp_ctx,
2122                                                                            sd,
2123                                                                            sid,
2124                                                                            access_mask,
2125                                                                            attr,
2126                                                                            objectclass,
2127                                                                            implicit_owner_rights);
2128                         if (ret != LDB_SUCCESS) {
2129                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2130                                                        "Object %s has no write dacl access\n",
2131                                                        ldb_dn_get_linearized(msg->dn));
2132                                 dsdb_acl_debug(sd,
2133                                                acl_user_token(module),
2134                                                msg->dn,
2135                                                true,
2136                                                10);
2137                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2138                                 goto fail;
2139                         }
2140                 } else if (ldb_attr_cmp("member", el->name) == 0) {
2141                         ret = acl_check_self_membership(tmp_ctx,
2142                                                         module,
2143                                                         req,
2144                                                         sd,
2145                                                         sid,
2146                                                         attr,
2147                                                         objectclass);
2148                         if (ret != LDB_SUCCESS) {
2149                                 goto fail;
2150                         }
2151                 } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
2152                         /* this one is not affected by any rights, we should let it through
2153                            so that passwords_hash returns the correct error */
2154                         continue;
2155                 } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
2156                            (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
2157                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
2158                         /*
2159                          * Ideally we would do the acl_check_password_rights
2160                          * before we checked the other attributes, i.e. in a
2161                          * loop before the current one.
2162                          * Have not done this as yet in order to limit the size
2163                          * of the change. To limit the possibility of breaking
2164                          * the ACL logic.
2165                          */
2166                         if (password_rights_checked) {
2167                                 continue;
2168                         }
2169                         ret = acl_check_password_rights(tmp_ctx,
2170                                                         module,
2171                                                         req,
2172                                                         sd,
2173                                                         sid,
2174                                                         objectclass,
2175                                                         userPassword,
2176                                                         &pav);
2177                         if (ret != LDB_SUCCESS) {
2178                                 goto fail;
2179                         }
2180                         password_rights_checked = true;
2181                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
2182                         ret = acl_check_spn(tmp_ctx,
2183                                             module,
2184                                             req,
2185                                             el,
2186                                             sd,
2187                                             sid,
2188                                             attr,
2189                                             objectclass,
2190                                             implicit_validated_write_control);
2191                         if (ret != LDB_SUCCESS) {
2192                                 goto fail;
2193                         }
2194                 } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
2195                         ret = acl_check_dns_host_name(tmp_ctx,
2196                                                       module,
2197                                                       req,
2198                                                       el,
2199                                                       sd,
2200                                                       sid,
2201                                                       attr,
2202                                                       objectclass,
2203                                                       implicit_validated_write_control);
2204                         if (ret != LDB_SUCCESS) {
2205                                 goto fail;
2206                         }
2207                 } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
2208                         /*
2209                          * in case of undelete op permissions on
2210                          * isDeleted are irrelevant and
2211                          * distinguishedName is removed by the
2212                          * tombstone_reanimate module
2213                          */
2214                         continue;
2215                 } else if (implicit_validated_write_control != NULL) {
2216                         /* Allow the update. */
2217                         continue;
2218                 } else {
2219                         ret = acl_check_access_on_attribute(module,
2220                                                             tmp_ctx,
2221                                                             sd,
2222                                                             sid,
2223                                                             SEC_ADS_WRITE_PROP,
2224                                                             attr,
2225                                                             objectclass);
2226                         if (ret != LDB_SUCCESS) {
2227                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2228                                                        "Object %s has no write property access\n",
2229                                                        ldb_dn_get_linearized(msg->dn));
2230                                 dsdb_acl_debug(sd,
2231                                                acl_user_token(module),
2232                                                msg->dn,
2233                                                true,
2234                                                10);
2235                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2236                                 goto fail;
2237                         }
2238                 }
2239         }
2240
2241 success:
2242         talloc_free(tmp_ctx);
2243         context = talloc_zero(req, struct acl_callback_context);
2244
2245         if (context == NULL) {
2246                 return ldb_oom(ldb);
2247         }
2248         context->request = req;
2249         context->module  = module;
2250         ret = ldb_build_mod_req(
2251                 &new_req,
2252                 ldb,
2253                 req,
2254                 req->op.mod.message,
2255                 req->controls,
2256                 context,
2257                 acl_callback,
2258                 req);
2259         if (ret != LDB_SUCCESS) {
2260                 return ret;
2261         }
2262         return ldb_next_request(module, new_req);
2263 fail:
2264         talloc_free(tmp_ctx);
2265         /*
2266          * We copy the pav into the result, so that the password reset
2267          * logging code in audit_log can log failed password reset attempts.
2268          */
2269         if (pav) {
2270                 struct ldb_control *control = NULL;
2271
2272                 controls = talloc_zero_array(req, struct ldb_control *, 2);
2273                 if (controls == NULL) {
2274                         return ldb_oom(ldb);
2275                 }
2276
2277                 control = talloc(controls, struct ldb_control);
2278
2279                 if (control == NULL) {
2280                         return ldb_oom(ldb);
2281                 }
2282
2283                 control->oid= talloc_strdup(
2284                         control,
2285                         DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
2286                 if (control->oid == NULL) {
2287                         return ldb_oom(ldb);
2288                 }
2289                 control->critical       = false;
2290                 control->data   = pav;
2291                 *controls = control;
2292         }
2293         return ldb_module_done(req, controls, NULL, ret);
2294 }
2295
2296 /* similar to the modify for the time being.
2297  * We need to consider the special delete tree case, though - TODO */
2298 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
2299 {
2300         int ret;
2301         struct ldb_dn *parent;
2302         struct ldb_context *ldb;
2303         struct ldb_dn *nc_root;
2304         struct ldb_control *as_system;
2305         const struct dsdb_schema *schema;
2306         const struct dsdb_class *objectclass;
2307         struct security_descriptor *sd = NULL;
2308         struct dom_sid *sid = NULL;
2309         struct ldb_result *acl_res;
2310         static const char *acl_attrs[] = {
2311                 "nTSecurityDescriptor",
2312                 "objectClass",
2313                 "objectSid",
2314                 NULL
2315         };
2316
2317         if (ldb_dn_is_special(req->op.del.dn)) {
2318                 return ldb_next_request(module, req);
2319         }
2320
2321         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2322         if (as_system != NULL) {
2323                 as_system->critical = 0;
2324         }
2325
2326         if (dsdb_module_am_system(module) || as_system) {
2327                 return ldb_next_request(module, req);
2328         }
2329
2330         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
2331
2332         ldb = ldb_module_get_ctx(module);
2333
2334         parent = ldb_dn_get_parent(req, req->op.del.dn);
2335         if (parent == NULL) {
2336                 return ldb_oom(ldb);
2337         }
2338
2339         /* Make sure we aren't deleting a NC */
2340
2341         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
2342         if (ret != LDB_SUCCESS) {
2343                 return ret;
2344         }
2345         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
2346                 talloc_free(nc_root);
2347                 DEBUG(10,("acl:deleting a NC\n"));
2348                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2349                 return ldb_module_done(req, NULL, NULL,
2350                                        LDB_ERR_UNWILLING_TO_PERFORM);
2351         }
2352         talloc_free(nc_root);
2353
2354         ret = dsdb_module_search_dn(module, req, &acl_res,
2355                                     req->op.del.dn, acl_attrs,
2356                                     DSDB_FLAG_NEXT_MODULE |
2357                                     DSDB_FLAG_AS_SYSTEM |
2358                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2359         /* we sould be able to find the parent */
2360         if (ret != LDB_SUCCESS) {
2361                 DEBUG(10,("acl: failed to find object %s\n",
2362                           ldb_dn_get_linearized(req->op.rename.olddn)));
2363                 return ret;
2364         }
2365
2366         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2367         if (ret != LDB_SUCCESS) {
2368                 return ldb_operr(ldb);
2369         }
2370         if (!sd) {
2371                 return ldb_operr(ldb);
2372         }
2373
2374         schema = dsdb_get_schema(ldb, req);
2375         if (!schema) {
2376                 return ldb_operr(ldb);
2377         }
2378
2379         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2380
2381         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2382         if (!objectclass) {
2383                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2384                                  "acl_modify: Error retrieving object class for GUID.");
2385         }
2386
2387         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
2388                 ret = acl_check_access_on_objectclass(module, req, sd, sid,
2389                                                       SEC_ADS_DELETE_TREE,
2390                                                       objectclass);
2391                 if (ret != LDB_SUCCESS) {
2392                         return ret;
2393                 }
2394
2395                 return ldb_next_request(module, req);
2396         }
2397
2398         /* First check if we have delete object right */
2399         ret = acl_check_access_on_objectclass(module, req, sd, sid,
2400                                               SEC_STD_DELETE,
2401                                               objectclass);
2402         if (ret == LDB_SUCCESS) {
2403                 return ldb_next_request(module, req);
2404         }
2405
2406         /* Nope, we don't have delete object. Lets check if we have delete
2407          * child on the parent */
2408         ret = dsdb_module_check_access_on_dn(module, req, parent,
2409                                              SEC_ADS_DELETE_CHILD,
2410                                              &objectclass->schemaIDGUID,
2411                                              req);
2412         if (ret != LDB_SUCCESS) {
2413                 return ret;
2414         }
2415
2416         return ldb_next_request(module, req);
2417 }
2418 static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
2419                                          struct ldb_module *module,
2420                                          struct ldb_request *req,
2421                                          struct ldb_dn *nc_root)
2422 {
2423         int ret;
2424         struct ldb_result *acl_res;
2425         struct security_descriptor *sd = NULL;
2426         struct dom_sid *sid = NULL;
2427         const struct dsdb_schema *schema = NULL;
2428         const struct dsdb_class *objectclass = NULL;
2429         struct ldb_context *ldb = ldb_module_get_ctx(module);
2430         static const char *acl_attrs[] = {
2431                 "nTSecurityDescriptor",
2432                 "objectClass",
2433                 "objectSid",
2434                 NULL
2435         };
2436
2437         ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
2438                                     nc_root, acl_attrs,
2439                                     DSDB_FLAG_NEXT_MODULE |
2440                                     DSDB_FLAG_AS_SYSTEM |
2441                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2442         if (ret != LDB_SUCCESS) {
2443                 DEBUG(10,("acl: failed to find object %s\n",
2444                           ldb_dn_get_linearized(nc_root)));
2445                 return ret;
2446         }
2447
2448         ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
2449         sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
2450         schema = dsdb_get_schema(ldb, req);
2451         if (!schema) {
2452                 return LDB_ERR_OPERATIONS_ERROR;
2453         }
2454         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2455         if (ret != LDB_SUCCESS || !sd) {
2456                 return ldb_operr(ldb_module_get_ctx(module));
2457         }
2458         return acl_check_extended_right(mem_ctx,
2459                                         module,
2460                                         req,
2461                                         objectclass,
2462                                         sd,
2463                                         acl_user_token(module),
2464                                         GUID_DRS_REANIMATE_TOMBSTONE,
2465                                         SEC_ADS_CONTROL_ACCESS, sid);
2466 }
2467
2468 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
2469 {
2470         int ret;
2471         struct ldb_dn *oldparent;
2472         struct ldb_dn *newparent;
2473         const struct dsdb_schema *schema;
2474         const struct dsdb_class *objectclass;
2475         const struct dsdb_attribute *attr = NULL;
2476         struct ldb_context *ldb;
2477         struct security_descriptor *sd = NULL;
2478         struct dom_sid *sid = NULL;
2479         struct ldb_result *acl_res;
2480         struct ldb_dn *nc_root;
2481         struct ldb_control *as_system;
2482         struct ldb_control *is_undelete;
2483         TALLOC_CTX *tmp_ctx;
2484         const char *rdn_name;
2485         static const char *acl_attrs[] = {
2486                 "nTSecurityDescriptor",
2487                 "objectClass",
2488                 "objectSid",
2489                 NULL
2490         };
2491
2492         if (ldb_dn_is_special(req->op.rename.olddn)) {
2493                 return ldb_next_request(module, req);
2494         }
2495
2496         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2497         if (as_system != NULL) {
2498                 as_system->critical = 0;
2499         }
2500
2501         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
2502         if (dsdb_module_am_system(module) || as_system) {
2503                 return ldb_next_request(module, req);
2504         }
2505
2506         ldb = ldb_module_get_ctx(module);
2507
2508         tmp_ctx = talloc_new(req);
2509         if (tmp_ctx == NULL) {
2510                 return ldb_oom(ldb);
2511         }
2512
2513         oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
2514         if (oldparent == NULL) {
2515                 return ldb_oom(ldb);
2516         }
2517         newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
2518         if (newparent == NULL) {
2519                 return ldb_oom(ldb);
2520         }
2521
2522         /* Make sure we aren't renaming/moving a NC */
2523
2524         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
2525         if (ret != LDB_SUCCESS) {
2526                 return ret;
2527         }
2528         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
2529                 talloc_free(nc_root);
2530                 DEBUG(10,("acl:renaming/moving a NC\n"));
2531                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2532                 return ldb_module_done(req, NULL, NULL,
2533                                        LDB_ERR_UNWILLING_TO_PERFORM);
2534         }
2535
2536         /* special check for undelete operation */
2537         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
2538         if (is_undelete != NULL) {
2539                 is_undelete->critical = 0;
2540                 ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
2541                 if (ret != LDB_SUCCESS) {
2542                         talloc_free(tmp_ctx);
2543                         return ret;
2544                 }
2545         }
2546         talloc_free(nc_root);
2547
2548         /* Look for the parent */
2549
2550         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
2551                                     req->op.rename.olddn, acl_attrs,
2552                                     DSDB_FLAG_NEXT_MODULE |
2553                                     DSDB_FLAG_AS_SYSTEM |
2554                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2555         /* we sould be able to find the parent */
2556         if (ret != LDB_SUCCESS) {
2557                 DEBUG(10,("acl: failed to find object %s\n",
2558                           ldb_dn_get_linearized(req->op.rename.olddn)));
2559                 talloc_free(tmp_ctx);
2560                 return ret;
2561         }
2562
2563         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2564         if (ret != LDB_SUCCESS) {
2565                 talloc_free(tmp_ctx);
2566                 return ldb_operr(ldb);
2567         }
2568         if (!sd) {
2569                 talloc_free(tmp_ctx);
2570                 return ldb_operr(ldb);
2571         }
2572
2573         schema = dsdb_get_schema(ldb, acl_res);
2574         if (!schema) {
2575                 talloc_free(tmp_ctx);
2576                 return ldb_operr(ldb);
2577         }
2578
2579         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2580
2581         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2582         if (!objectclass) {
2583                 talloc_free(tmp_ctx);
2584                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2585                                  "acl_modify: Error retrieving object class for GUID.");
2586         }
2587
2588         attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
2589         if (attr == NULL) {
2590                 talloc_free(tmp_ctx);
2591                 return ldb_operr(ldb);
2592         }
2593
2594         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2595                                             SEC_ADS_WRITE_PROP,
2596                                             attr, objectclass);
2597         if (ret != LDB_SUCCESS) {
2598                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2599                                        "Object %s has no wp on %s\n",
2600                                        ldb_dn_get_linearized(req->op.rename.olddn),
2601                                        attr->lDAPDisplayName);
2602                 dsdb_acl_debug(sd,
2603                           acl_user_token(module),
2604                           req->op.rename.olddn,
2605                           true,
2606                           10);
2607                 talloc_free(tmp_ctx);
2608                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2609         }
2610
2611         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
2612         if (rdn_name == NULL) {
2613                 talloc_free(tmp_ctx);
2614                 return ldb_operr(ldb);
2615         }
2616
2617         attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2618         if (attr == NULL) {
2619                 talloc_free(tmp_ctx);
2620                 return ldb_operr(ldb);
2621         }
2622
2623         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2624                                             SEC_ADS_WRITE_PROP,
2625                                             attr, objectclass);
2626         if (ret != LDB_SUCCESS) {
2627                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2628                                        "Object %s has no wp on %s\n",
2629                                        ldb_dn_get_linearized(req->op.rename.olddn),
2630                                        attr->lDAPDisplayName);
2631                 dsdb_acl_debug(sd,
2632                           acl_user_token(module),
2633                           req->op.rename.olddn,
2634                           true,
2635                           10);
2636                 talloc_free(tmp_ctx);
2637                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2638         }
2639
2640         if (ldb_dn_compare(oldparent, newparent) == 0) {
2641                 /* regular rename, not move, nothing more to do */
2642                 talloc_free(tmp_ctx);
2643                 return ldb_next_request(module, req);
2644         }
2645
2646         /* new parent should have create child */
2647         ret = dsdb_module_check_access_on_dn(module, req, newparent,
2648                                              SEC_ADS_CREATE_CHILD,
2649                                              &objectclass->schemaIDGUID, req);
2650         if (ret != LDB_SUCCESS) {
2651                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
2652                                        "acl:access_denied renaming %s",
2653                                        ldb_dn_get_linearized(req->op.rename.olddn));
2654                 talloc_free(tmp_ctx);
2655                 return ret;
2656         }
2657
2658         /* do we have delete object on the object? */
2659         /* this access is not necessary for undelete ops */
2660         if (is_undelete == NULL) {
2661                 ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
2662                                                       SEC_STD_DELETE,
2663                                                       objectclass);
2664                 if (ret == LDB_SUCCESS) {
2665                         talloc_free(tmp_ctx);
2666                         return ldb_next_request(module, req);
2667                 }
2668                 /* what about delete child on the current parent */
2669                 ret = dsdb_module_check_access_on_dn(module, req, oldparent,
2670                                                      SEC_ADS_DELETE_CHILD,
2671                                                      &objectclass->schemaIDGUID,
2672                                                      req);
2673                 if (ret != LDB_SUCCESS) {
2674                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
2675                                                "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
2676                         talloc_free(tmp_ctx);
2677                         return ldb_module_done(req, NULL, NULL, ret);
2678                 }
2679         }
2680         talloc_free(tmp_ctx);
2681
2682         return ldb_next_request(module, req);
2683 }
2684
2685 static int acl_search_update_confidential_attrs(struct acl_context *ac,
2686                                                 struct acl_private *data)
2687 {
2688         struct dsdb_attribute *a;
2689         uint32_t n = 0;
2690
2691         if (data->acl_search) {
2692                 /*
2693                  * If acl:search is activated, the acl_read module
2694                  * protects confidential attributes.
2695                  */
2696                 return LDB_SUCCESS;
2697         }
2698
2699         if ((ac->schema == data->cached_schema_ptr) &&
2700             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
2701         {
2702                 return LDB_SUCCESS;
2703         }
2704
2705         data->cached_schema_ptr = NULL;
2706         data->cached_schema_loaded_usn = 0;
2707         data->cached_schema_metadata_usn = 0;
2708         TALLOC_FREE(data->confidential_attrs);
2709
2710         if (ac->schema == NULL) {
2711                 return LDB_SUCCESS;
2712         }
2713
2714         for (a = ac->schema->attributes; a; a = a->next) {
2715                 const char **attrs = data->confidential_attrs;
2716
2717                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
2718                         continue;
2719                 }
2720
2721                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
2722                 if (attrs == NULL) {
2723                         TALLOC_FREE(data->confidential_attrs);
2724                         return ldb_module_oom(ac->module);
2725                 }
2726
2727                 attrs[n] = a->lDAPDisplayName;
2728                 attrs[n+1] = NULL;
2729                 n++;
2730
2731                 data->confidential_attrs = attrs;
2732         }
2733
2734         data->cached_schema_ptr = ac->schema;
2735         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
2736
2737         return LDB_SUCCESS;
2738 }
2739
2740 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2741 {
2742         struct acl_context *ac;
2743         struct acl_private *data;
2744         struct ldb_result *acl_res;
2745         static const char *acl_attrs[] = {
2746                 "objectClass",
2747                 "nTSecurityDescriptor",
2748                 "objectSid",
2749                 NULL
2750         };
2751         int ret;
2752         unsigned int i;
2753
2754         ac = talloc_get_type(req->context, struct acl_context);
2755         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2756         if (!ares) {
2757                 return ldb_module_done(ac->req, NULL, NULL,
2758                                        LDB_ERR_OPERATIONS_ERROR);
2759         }
2760         if (ares->error != LDB_SUCCESS) {
2761                 return ldb_module_done(ac->req, ares->controls,
2762                                        ares->response, ares->error);
2763         }
2764
2765         switch (ares->type) {
2766         case LDB_REPLY_ENTRY:
2767                 if (ac->constructed_attrs) {
2768                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn, 
2769                                                     acl_attrs,
2770                                                     DSDB_FLAG_NEXT_MODULE |
2771                                                     DSDB_FLAG_AS_SYSTEM |
2772                                                     DSDB_SEARCH_SHOW_RECYCLED,
2773                                                     req);
2774                         if (ret != LDB_SUCCESS) {
2775                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2776                         }
2777                 }
2778
2779                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2780                         ret = acl_allowedAttributes(ac->module, ac->schema,
2781                                                     acl_res->msgs[0],
2782                                                     ares->message, ac);
2783                         if (ret != LDB_SUCCESS) {
2784                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2785                         }
2786                 }
2787
2788                 if (ac->allowedChildClasses) {
2789                         ret = acl_childClasses(ac->module, ac->schema,
2790                                                acl_res->msgs[0],
2791                                                ares->message,
2792                                                "allowedChildClasses");
2793                         if (ret != LDB_SUCCESS) {
2794                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2795                         }
2796                 }
2797
2798                 if (ac->allowedChildClassesEffective) {
2799                         ret = acl_childClassesEffective(ac->module, ac->schema,
2800                                                         acl_res->msgs[0],
2801                                                         ares->message, ac);
2802                         if (ret != LDB_SUCCESS) {
2803                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2804                         }
2805                 }
2806
2807                 if (ac->sDRightsEffective) {
2808                         ret = acl_sDRightsEffective(ac->module,
2809                                                     acl_res->msgs[0],
2810                                                     ares->message, ac);
2811                         if (ret != LDB_SUCCESS) {
2812                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2813                         }
2814                 }
2815
2816                 if (data == NULL) {
2817                         return ldb_module_send_entry(ac->req, ares->message,
2818                                                      ares->controls);
2819                 }
2820
2821                 if (ac->am_system) {
2822                         return ldb_module_send_entry(ac->req, ares->message,
2823                                                      ares->controls);
2824                 }
2825
2826                 if (data->password_attrs != NULL) {
2827                         for (i = 0; data->password_attrs[i]; i++) {
2828                                 if ((!ac->userPassword) &&
2829                                     (ldb_attr_cmp(data->password_attrs[i],
2830                                                   "userPassword") == 0))
2831                                 {
2832                                                 continue;
2833                                 }
2834
2835                                 ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
2836                         }
2837                 }
2838
2839                 if (ac->am_administrator) {
2840                         return ldb_module_send_entry(ac->req, ares->message,
2841                                                      ares->controls);
2842                 }
2843
2844                 ret = acl_search_update_confidential_attrs(ac, data);
2845                 if (ret != LDB_SUCCESS) {
2846                         return ret;
2847                 }
2848
2849                 if (data->confidential_attrs != NULL) {
2850                         for (i = 0; data->confidential_attrs[i]; i++) {
2851                                 ldb_msg_remove_attr(ares->message,
2852                                                     data->confidential_attrs[i]);
2853                         }
2854                 }
2855
2856                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2857
2858         case LDB_REPLY_REFERRAL:
2859                 return ldb_module_send_referral(ac->req, ares->referral);
2860
2861         case LDB_REPLY_DONE:
2862                 return ldb_module_done(ac->req, ares->controls,
2863                                        ares->response, LDB_SUCCESS);
2864
2865         }
2866         return LDB_SUCCESS;
2867 }
2868
2869 static int acl_search(struct ldb_module *module, struct ldb_request *req)
2870 {
2871         struct ldb_context *ldb;
2872         struct acl_context *ac;
2873         struct ldb_parse_tree *down_tree;
2874         struct ldb_request *down_req;
2875         struct acl_private *data;
2876         int ret;
2877         unsigned int i;
2878
2879         if (ldb_dn_is_special(req->op.search.base)) {
2880                 return ldb_next_request(module, req);
2881         }
2882
2883         ldb = ldb_module_get_ctx(module);
2884
2885         ac = talloc_zero(req, struct acl_context);
2886         if (ac == NULL) {
2887                 return ldb_oom(ldb);
2888         }
2889         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2890
2891         ac->module = module;
2892         ac->req = req;
2893         ac->am_system = dsdb_module_am_system(module);
2894         ac->am_administrator = dsdb_module_am_administrator(module);
2895         ac->constructed_attrs = false;
2896         ac->modify_search = true;
2897         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2898         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2899         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2900         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2901         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2902         ac->userPassword = true;
2903         ac->schema = dsdb_get_schema(ldb, ac);
2904
2905         ac->constructed_attrs |= ac->allowedAttributes;
2906         ac->constructed_attrs |= ac->allowedChildClasses;
2907         ac->constructed_attrs |= ac->allowedChildClassesEffective;
2908         ac->constructed_attrs |= ac->allowedAttributesEffective;
2909         ac->constructed_attrs |= ac->sDRightsEffective;
2910
2911         if (data == NULL) {
2912                 ac->modify_search = false;
2913         }
2914         if (ac->am_system) {
2915                 ac->modify_search = false;
2916         }
2917
2918         if (!ac->constructed_attrs && !ac->modify_search) {
2919                 talloc_free(ac);
2920                 return ldb_next_request(module, req);
2921         }
2922
2923         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2924         if (data == NULL) {
2925                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2926                                  "acl_private data is missing");
2927         }
2928         ac->userPassword = data->userPassword_support;
2929
2930         ret = acl_search_update_confidential_attrs(ac, data);
2931         if (ret != LDB_SUCCESS) {
2932                 return ret;
2933         }
2934
2935         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2936         if (down_tree == NULL) {
2937                 return ldb_oom(ldb);
2938         }
2939
2940         if (!ac->am_system && data->password_attrs) {
2941                 for (i = 0; data->password_attrs[i]; i++) {
2942                         if ((!ac->userPassword) &&
2943                             (ldb_attr_cmp(data->password_attrs[i],
2944                                           "userPassword") == 0))
2945                         {
2946                                 continue;
2947                         }
2948
2949                         ldb_parse_tree_attr_replace(down_tree,
2950                                                     data->password_attrs[i],
2951                                                     "kludgeACLredactedattribute");
2952                 }
2953         }
2954
2955         if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) {
2956                 for (i = 0; data->confidential_attrs[i]; i++) {
2957                         ldb_parse_tree_attr_replace(down_tree,
2958                                                     data->confidential_attrs[i],
2959                                                     "kludgeACLredactedattribute");
2960                 }
2961         }
2962
2963         ret = ldb_build_search_req_ex(&down_req,
2964                                       ldb, ac,
2965                                       req->op.search.base,
2966                                       req->op.search.scope,
2967                                       down_tree,
2968                                       req->op.search.attrs,
2969                                       req->controls,
2970                                       ac, acl_search_callback,
2971                                       req);
2972         LDB_REQ_SET_LOCATION(down_req);
2973         if (ret != LDB_SUCCESS) {
2974                 return ret;
2975         }
2976         /* perform the search */
2977         return ldb_next_request(module, down_req);
2978 }
2979
2980 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2981 {
2982         struct ldb_context *ldb = ldb_module_get_ctx(module);
2983         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2984
2985         /* allow everybody to read the sequence number */
2986         if (strcmp(req->op.extended.oid,
2987                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2988                 return ldb_next_request(module, req);
2989         }
2990
2991         if (dsdb_module_am_system(module) ||
2992             dsdb_module_am_administrator(module) || as_system) {
2993                 return ldb_next_request(module, req);
2994         } else {
2995                 ldb_asprintf_errstring(ldb,
2996                                        "acl_extended: "
2997                                        "attempted database modify not permitted. "
2998                                        "User %s is not SYSTEM or an administrator",
2999                                        acl_user_name(req, module));
3000                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3001         }
3002 }
3003
3004 static const struct ldb_module_ops ldb_acl_module_ops = {
3005         .name              = "acl",
3006         .search            = acl_search,
3007         .add               = acl_add,
3008         .modify            = acl_modify,
3009         .del               = acl_delete,
3010         .rename            = acl_rename,
3011         .extended          = acl_extended,
3012         .init_context      = acl_module_init
3013 };
3014
3015 int ldb_acl_module_init(const char *version)
3016 {
3017         LDB_MODULE_CHECK_VERSION(version);
3018         return ldb_register_module(&ldb_acl_module_ops);
3019 }