Fix spelling mistakes
[vlendec/samba-autobuild/.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 struct extended_access_check_attribute {
47         const char *oa_name;
48         const uint32_t requires_rights;
49 };
50
51 struct acl_private {
52         bool acl_search;
53         const char **password_attrs;
54         void *cached_schema_ptr;
55         uint64_t cached_schema_metadata_usn;
56         uint64_t cached_schema_loaded_usn;
57         const char **confidential_attrs;
58         bool userPassword_support;
59 };
60
61 struct acl_context {
62         struct ldb_module *module;
63         struct ldb_request *req;
64         bool am_system;
65         bool am_administrator;
66         bool modify_search;
67         bool constructed_attrs;
68         bool allowedAttributes;
69         bool allowedAttributesEffective;
70         bool allowedChildClasses;
71         bool allowedChildClassesEffective;
72         bool sDRightsEffective;
73         bool userPassword;
74         const char * const *attrs;
75         struct dsdb_schema *schema;
76 };
77
78 static int acl_module_init(struct ldb_module *module)
79 {
80         struct ldb_context *ldb;
81         struct acl_private *data;
82         int ret;
83         unsigned int i, n, j;
84         TALLOC_CTX *mem_ctx;
85         static const char * const attrs[] = { "passwordAttribute", NULL };
86         static const char * const secret_attrs[] = {
87                 DSDB_SECRET_ATTRIBUTES
88         };
89         struct ldb_result *res;
90         struct ldb_message *msg;
91         struct ldb_message_element *password_attributes;
92
93         ldb = ldb_module_get_ctx(module);
94
95         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
96         if (ret != LDB_SUCCESS) {
97                 ldb_debug(ldb, LDB_DEBUG_ERROR,
98                           "acl_module_init: Unable to register control with rootdse!\n");
99                 return ldb_operr(ldb);
100         }
101
102         data = talloc_zero(module, struct acl_private);
103         if (data == NULL) {
104                 return ldb_oom(ldb);
105         }
106
107         data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
108                                         NULL, "acl", "search", true);
109         ldb_module_set_private(module, data);
110
111         mem_ctx = talloc_new(module);
112         if (!mem_ctx) {
113                 return ldb_oom(ldb);
114         }
115
116         ret = dsdb_module_search_dn(module, mem_ctx, &res,
117                                     ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
118                                     attrs,
119                                     DSDB_FLAG_NEXT_MODULE |
120                                     DSDB_FLAG_AS_SYSTEM,
121                                     NULL);
122         if (ret != LDB_SUCCESS) {
123                 goto done;
124         }
125         if (res->count == 0) {
126                 goto done;
127         }
128
129         if (res->count > 1) {
130                 talloc_free(mem_ctx);
131                 return LDB_ERR_CONSTRAINT_VIOLATION;
132         }
133
134         msg = res->msgs[0];
135
136         password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
137         if (!password_attributes) {
138                 goto done;
139         }
140         data->password_attrs = talloc_array(data, const char *,
141                         password_attributes->num_values +
142                         ARRAY_SIZE(secret_attrs) + 1);
143         if (!data->password_attrs) {
144                 talloc_free(mem_ctx);
145                 return ldb_oom(ldb);
146         }
147
148         n = 0;
149         for (i=0; i < password_attributes->num_values; i++) {
150                 data->password_attrs[n] = (const char *)password_attributes->values[i].data;
151                 talloc_steal(data->password_attrs, password_attributes->values[i].data);
152                 n++;
153         }
154
155         for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
156                 bool found = false;
157
158                 for (j=0; j < n; j++) {
159                         if (strcasecmp(data->password_attrs[j], secret_attrs[i]) == 0) {
160                                 found = true;
161                                 break;
162                         }
163                 }
164
165                 if (found) {
166                         continue;
167                 }
168
169                 data->password_attrs[n] = talloc_strdup(data->password_attrs,
170                                                         secret_attrs[i]);
171                 if (data->password_attrs[n] == NULL) {
172                         talloc_free(mem_ctx);
173                         return ldb_oom(ldb);
174                 }
175                 n++;
176         }
177         data->password_attrs[n] = NULL;
178
179 done:
180         talloc_free(mem_ctx);
181         ret = ldb_next_init(module);
182
183         if (ret != LDB_SUCCESS) {
184                 return ret;
185         }
186
187         /*
188          * Check this after the modules have be initialised so we
189          * can actually read the backend DB.
190          */
191         data->userPassword_support
192                 = dsdb_user_password_support(module,
193                                              module,
194                                              NULL);
195         return ret;
196 }
197
198 static int acl_allowedAttributes(struct ldb_module *module,
199                                  const struct dsdb_schema *schema,
200                                  struct ldb_message *sd_msg,
201                                  struct ldb_message *msg,
202                                  struct acl_context *ac)
203 {
204         struct ldb_message_element *oc_el;
205         struct ldb_context *ldb = ldb_module_get_ctx(module);
206         TALLOC_CTX *mem_ctx;
207         const char **attr_list;
208         int i, ret;
209         const struct dsdb_class *objectclass;
210
211         /* If we don't have a schema yet, we can't do anything... */
212         if (schema == NULL) {
213                 ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
214                 return LDB_ERR_OPERATIONS_ERROR;
215         }
216
217         /* Must remove any existing attribute */
218         if (ac->allowedAttributes) {
219                 ldb_msg_remove_attr(msg, "allowedAttributes");
220         }
221
222         mem_ctx = talloc_new(msg);
223         if (!mem_ctx) {
224                 return ldb_oom(ldb);
225         }
226
227         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
228         attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
229         if (!attr_list) {
230                 ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
231                 talloc_free(mem_ctx);
232                 return LDB_ERR_OPERATIONS_ERROR;
233         }
234
235         /*
236          * Get the top-most structural object class for the ACL check
237          */
238         objectclass = dsdb_get_last_structural_class(ac->schema,
239                                                      oc_el);
240         if (objectclass == NULL) {
241                 ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
242                                        ldb_dn_get_linearized(sd_msg->dn));
243                 talloc_free(mem_ctx);
244                 return LDB_ERR_OPERATIONS_ERROR;
245         }
246
247         if (ac->allowedAttributes) {
248                 for (i=0; attr_list && attr_list[i]; i++) {
249                         ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
250                 }
251         }
252         if (ac->allowedAttributesEffective) {
253                 struct security_descriptor *sd;
254                 struct dom_sid *sid = NULL;
255                 struct ldb_control *as_system = ldb_request_get_control(ac->req,
256                                                                         LDB_CONTROL_AS_SYSTEM_OID);
257
258                 if (as_system != NULL) {
259                         as_system->critical = 0;
260                 }
261
262                 ldb_msg_remove_attr(msg, "allowedAttributesEffective");
263                 if (ac->am_system || as_system) {
264                         for (i=0; attr_list && attr_list[i]; i++) {
265                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
266                         }
267                         return LDB_SUCCESS;
268                 }
269
270                 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
271
272                 if (ret != LDB_SUCCESS) {
273                         return ret;
274                 }
275
276                 sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
277                 for (i=0; attr_list && attr_list[i]; i++) {
278                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
279                                                                                         attr_list[i]);
280                         if (!attr) {
281                                 return ldb_operr(ldb);
282                         }
283                         /* remove constructed attributes */
284                         if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
285                             || attr->systemOnly
286                             || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
287                                 continue;
288                         }
289                         ret = acl_check_access_on_attribute(module,
290                                                             msg,
291                                                             sd,
292                                                             sid,
293                                                             SEC_ADS_WRITE_PROP,
294                                                             attr,
295                                                             objectclass);
296                         if (ret == LDB_SUCCESS) {
297                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
298                         }
299                 }
300         }
301         return LDB_SUCCESS;
302 }
303
304 static int acl_childClasses(struct ldb_module *module,
305                             const struct dsdb_schema *schema,
306                             struct ldb_message *sd_msg,
307                             struct ldb_message *msg,
308                             const char *attrName)
309 {
310         struct ldb_message_element *oc_el;
311         struct ldb_message_element *allowedClasses;
312         const struct dsdb_class *sclass;
313         unsigned int i, j;
314         int ret;
315
316         /* If we don't have a schema yet, we can't do anything... */
317         if (schema == NULL) {
318                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add childClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
319                 return LDB_ERR_OPERATIONS_ERROR;
320         }
321
322         /* Must remove any existing attribute, or else confusion reins */
323         ldb_msg_remove_attr(msg, attrName);
324         ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
325         if (ret != LDB_SUCCESS) {
326                 return ret;
327         }
328
329         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
330
331         for (i=0; oc_el && i < oc_el->num_values; i++) {
332                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
333                 if (!sclass) {
334                         /* We don't know this class?  what is going on? */
335                         continue;
336                 }
337
338                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
339                         ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
340                 }
341         }
342         if (allowedClasses->num_values > 1) {
343                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
344                 for (i=1 ; i < allowedClasses->num_values; i++) {
345                         struct ldb_val *val1 = &allowedClasses->values[i-1];
346                         struct ldb_val *val2 = &allowedClasses->values[i];
347                         if (data_blob_cmp(val1, val2) == 0) {
348                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
349                                 allowedClasses->num_values--;
350                                 i--;
351                         }
352                 }
353         }
354
355         return LDB_SUCCESS;
356 }
357
358 static int acl_childClassesEffective(struct ldb_module *module,
359                                      const struct dsdb_schema *schema,
360                                      struct ldb_message *sd_msg,
361                                      struct ldb_message *msg,
362                                      struct acl_context *ac)
363 {
364         struct ldb_message_element *oc_el;
365         struct ldb_message_element *allowedClasses = NULL;
366         const struct dsdb_class *sclass;
367         struct security_descriptor *sd;
368         struct ldb_control *as_system = ldb_request_get_control(ac->req,
369                                                                 LDB_CONTROL_AS_SYSTEM_OID);
370         struct dom_sid *sid = NULL;
371         unsigned int i, j;
372         int ret;
373
374         if (as_system != NULL) {
375                 as_system->critical = 0;
376         }
377
378         if (ac->am_system || as_system) {
379                 return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
380         }
381
382         /* If we don't have a schema yet, we can't do anything... */
383         if (schema == NULL) {
384                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add allowedChildClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
385                 return LDB_ERR_OPERATIONS_ERROR;
386         }
387
388         /* Must remove any existing attribute, or else confusion reins */
389         ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
390
391         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
392         ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
393         if (ret != LDB_SUCCESS) {
394                 return ret;
395         }
396
397         sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
398         for (i=0; oc_el && i < oc_el->num_values; i++) {
399                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
400                 if (!sclass) {
401                         /* We don't know this class?  what is going on? */
402                         continue;
403                 }
404
405                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
406                         const struct dsdb_class *sc;
407
408                         sc = dsdb_class_by_lDAPDisplayName(schema,
409                                                            sclass->possibleInferiors[j]);
410                         if (!sc) {
411                                 /* We don't know this class?  what is going on? */
412                                 continue;
413                         }
414
415                         ret = acl_check_access_on_objectclass(module, ac,
416                                                               sd, sid,
417                                                               SEC_ADS_CREATE_CHILD,
418                                                               sc);
419                         if (ret == LDB_SUCCESS) {
420                                 ldb_msg_add_string(msg, "allowedChildClassesEffective",
421                                                    sclass->possibleInferiors[j]);
422                         }
423                 }
424         }
425         allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
426         if (!allowedClasses) {
427                 return LDB_SUCCESS;
428         }
429
430         if (allowedClasses->num_values > 1) {
431                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
432                 for (i=1 ; i < allowedClasses->num_values; i++) {
433                         struct ldb_val *val1 = &allowedClasses->values[i-1];
434                         struct ldb_val *val2 = &allowedClasses->values[i];
435                         if (data_blob_cmp(val1, val2) == 0) {
436                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
437                                 allowedClasses->num_values--;
438                                 i--;
439                         }
440                 }
441         }
442         return LDB_SUCCESS;
443 }
444
445 static int acl_sDRightsEffective(struct ldb_module *module,
446                                  struct ldb_message *sd_msg,
447                                  struct ldb_message *msg,
448                                  struct acl_context *ac)
449 {
450         struct ldb_context *ldb = ldb_module_get_ctx(module);
451         struct ldb_message_element *rightsEffective;
452         int ret;
453         struct security_descriptor *sd;
454         struct ldb_control *as_system = ldb_request_get_control(ac->req,
455                                                                 LDB_CONTROL_AS_SYSTEM_OID);
456         struct dom_sid *sid = NULL;
457         uint32_t flags = 0;
458
459         if (as_system != NULL) {
460                 as_system->critical = 0;
461         }
462
463         /* Must remove any existing attribute, or else confusion reins */
464         ldb_msg_remove_attr(msg, "sDRightsEffective");
465         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
466         if (ret != LDB_SUCCESS) {
467                 return ret;
468         }
469         if (ac->am_system || as_system) {
470                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
471         } else {
472                 const struct dsdb_class *objectclass;
473                 const struct dsdb_attribute *attr;
474
475                 objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
476                 if (objectclass == NULL) {
477                         return ldb_operr(ldb);
478                 }
479
480                 attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
481                                                          "nTSecurityDescriptor");
482                 if (attr == NULL) {
483                         return ldb_operr(ldb);
484                 }
485
486                 /* Get the security descriptor from the message */
487                 ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
488                 if (ret != LDB_SUCCESS) {
489                         return ret;
490                 }
491                 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
492                 ret = acl_check_access_on_attribute(module,
493                                                     msg,
494                                                     sd,
495                                                     sid,
496                                                     SEC_STD_WRITE_OWNER,
497                                                     attr,
498                                                     objectclass);
499                 if (ret == LDB_SUCCESS) {
500                         flags |= SECINFO_OWNER | SECINFO_GROUP;
501                 }
502                 ret = acl_check_access_on_attribute(module,
503                                                     msg,
504                                                     sd,
505                                                     sid,
506                                                     SEC_STD_WRITE_DAC,
507                                                     attr,
508                                                     objectclass);
509                 if (ret == LDB_SUCCESS) {
510                         flags |= SECINFO_DACL;
511                 }
512                 ret = acl_check_access_on_attribute(module,
513                                                     msg,
514                                                     sd,
515                                                     sid,
516                                                     SEC_FLAG_SYSTEM_SECURITY,
517                                                     attr,
518                                                     objectclass);
519                 if (ret == LDB_SUCCESS) {
520                         flags |= SECINFO_SACL;
521                 }
522         }
523         return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
524                                   "sDRightsEffective", flags);
525 }
526
527 static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
528                                   struct ldb_context *ldb,
529                                   const char *spn_value,
530                                   uint32_t userAccountControl,
531                                   const char *samAccountName,
532                                   const char *dnsHostName,
533                                   const char *netbios_name,
534                                   const char *ntds_guid)
535 {
536         int ret, princ_size;
537         krb5_context krb_ctx;
538         krb5_error_code kerr;
539         krb5_principal principal;
540         char *instanceName;
541         char *serviceType;
542         char *serviceName;
543         const char *forest_name = samdb_forest_name(ldb, mem_ctx);
544         const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
545         struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
546                                                           struct loadparm_context);
547         bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
548                 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
549
550         if (strcasecmp_m(spn_value, samAccountName) == 0) {
551                 /* MacOS X sets this value, and setting an SPN of your
552                  * own samAccountName is both pointless and safe */
553                 return LDB_SUCCESS;
554         }
555
556         kerr = smb_krb5_init_context_basic(mem_ctx,
557                                            lp_ctx,
558                                            &krb_ctx);
559         if (kerr != 0) {
560                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
561                                  "Could not initialize kerberos context.");
562         }
563
564         ret = krb5_parse_name(krb_ctx, spn_value, &principal);
565         if (ret) {
566                 krb5_free_context(krb_ctx);
567                 return LDB_ERR_CONSTRAINT_VIOLATION;
568         }
569
570         princ_size = krb5_princ_size(krb_ctx, principal);
571         if (princ_size < 2) {
572                 DBG_WARNING("princ_size=%d\n", princ_size);
573                 goto fail;
574         }
575
576         instanceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
577                                                           principal, 1);
578         serviceType = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
579                                                          principal, 0);
580         if (krb5_princ_size(krb_ctx, principal) == 3) {
581                 serviceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
582                                                                  principal, 2);
583         } else {
584                 serviceName = NULL;
585         }
586
587         if (serviceName) {
588                 if (!is_dc) {
589                         DBG_WARNING("is_dc=false, serviceName=%s,"
590                                     "serviceType=%s\n", serviceName,
591                                   serviceType);
592                         goto fail;
593                 }
594                 if (strcasecmp(serviceType, "ldap") == 0) {
595                         if (strcasecmp(serviceName, netbios_name) != 0 &&
596                             strcasecmp(serviceName, forest_name) != 0) {
597                                 DBG_WARNING("serviceName=%s\n", serviceName);
598                                 goto fail;
599                         }
600
601                 } else if (strcasecmp(serviceType, "gc") == 0) {
602                         if (strcasecmp(serviceName, forest_name) != 0) {
603                                 DBG_WARNING("serviceName=%s\n", serviceName);
604                                 goto fail;
605                         }
606                 } else {
607                         if (strcasecmp(serviceName, base_domain) != 0 &&
608                             strcasecmp(serviceName, netbios_name) != 0) {
609                                 DBG_WARNING("serviceType=%s, "
610                                             "serviceName=%s\n",
611                                             serviceType, serviceName);
612                                 goto fail;
613                         }
614                 }
615         }
616         /* instanceName can be samAccountName without $ or dnsHostName
617          * or "ntds_guid._msdcs.forest_domain for DC objects */
618         if (strlen(instanceName) == (strlen(samAccountName) - 1)
619             && strncasecmp(instanceName, samAccountName,
620                            strlen(samAccountName) - 1) == 0) {
621                 goto success;
622         }
623         if ((dnsHostName != NULL) &&
624             (strcasecmp(instanceName, dnsHostName) == 0)) {
625                 goto success;
626         }
627         if (is_dc) {
628                 const char *guid_str;
629                 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
630                                            ntds_guid,
631                                            forest_name);
632                 if (strcasecmp(instanceName, guid_str) == 0) {
633                         goto success;
634                 }
635         }
636
637 fail:
638         krb5_free_principal(krb_ctx, principal);
639         krb5_free_context(krb_ctx);
640         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
641                       "acl: spn validation failed for "
642                       "spn[%s] uac[0x%x] account[%s] hostname[%s] "
643                       "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
644                       spn_value, (unsigned)userAccountControl,
645                       samAccountName, dnsHostName,
646                       netbios_name, ntds_guid,
647                       forest_name, base_domain);
648         return LDB_ERR_CONSTRAINT_VIOLATION;
649
650 success:
651         krb5_free_principal(krb_ctx, principal);
652         krb5_free_context(krb_ctx);
653         return LDB_SUCCESS;
654 }
655
656 static int acl_check_spn(TALLOC_CTX *mem_ctx,
657                          struct ldb_module *module,
658                          struct ldb_request *req,
659                          struct security_descriptor *sd,
660                          struct dom_sid *sid,
661                          const struct dsdb_attribute *attr,
662                          const struct dsdb_class *objectclass)
663 {
664         int ret;
665         unsigned int i;
666         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
667         struct ldb_context *ldb = ldb_module_get_ctx(module);
668         struct ldb_result *acl_res;
669         struct ldb_result *netbios_res;
670         struct ldb_message_element *el;
671         struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
672         uint32_t userAccountControl;
673         const char *samAccountName;
674         const char *dnsHostName;
675         const char *netbios_name;
676         struct GUID ntds;
677         char *ntds_guid = NULL;
678
679         static const char *acl_attrs[] = {
680                 "samAccountName",
681                 "dnsHostName",
682                 "userAccountControl",
683                 NULL
684         };
685         static const char *netbios_attrs[] = {
686                 "nETBIOSName",
687                 NULL
688         };
689
690         /* if we have wp, we can do whatever we like */
691         if (acl_check_access_on_attribute(module,
692                                           tmp_ctx,
693                                           sd,
694                                           sid,
695                                           SEC_ADS_WRITE_PROP,
696                                           attr, objectclass) == LDB_SUCCESS) {
697                 talloc_free(tmp_ctx);
698                 return LDB_SUCCESS;
699         }
700
701         ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
702                                        GUID_DRS_VALIDATE_SPN,
703                                        SEC_ADS_SELF_WRITE,
704                                        sid);
705
706         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
707                 dsdb_acl_debug(sd, acl_user_token(module),
708                                req->op.mod.message->dn,
709                                true,
710                                10);
711                 talloc_free(tmp_ctx);
712                 return ret;
713         }
714
715         ret = dsdb_module_search_dn(module, tmp_ctx,
716                                     &acl_res, req->op.mod.message->dn,
717                                     acl_attrs,
718                                     DSDB_FLAG_NEXT_MODULE |
719                                     DSDB_FLAG_AS_SYSTEM |
720                                     DSDB_SEARCH_SHOW_RECYCLED,
721                                     req);
722         if (ret != LDB_SUCCESS) {
723                 talloc_free(tmp_ctx);
724                 return ret;
725         }
726
727         userAccountControl = ldb_msg_find_attr_as_uint(acl_res->msgs[0], "userAccountControl", 0);
728         dnsHostName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "dnsHostName", NULL);
729         samAccountName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "samAccountName", NULL);
730
731         ret = dsdb_module_search(module, tmp_ctx,
732                                  &netbios_res, partitions_dn,
733                                  LDB_SCOPE_ONELEVEL,
734                                  netbios_attrs,
735                                  DSDB_FLAG_NEXT_MODULE |
736                                  DSDB_FLAG_AS_SYSTEM,
737                                  req,
738                                  "(ncName=%s)",
739                                  ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
740
741         netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
742
743         el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName");
744         if (!el) {
745                 talloc_free(tmp_ctx);
746                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
747                                          "Error finding element for servicePrincipalName.");
748         }
749
750         /* NTDSDSA objectGuid of object we are checking SPN for */
751         if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
752                 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
753                                                              req->op.mod.message->dn, &ntds, req);
754                 if (ret != LDB_SUCCESS) {
755                         ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
756                                                ldb_dn_get_linearized(req->op.mod.message->dn),
757                                                ldb_strerror(ret));
758                         talloc_free(tmp_ctx);
759                         return LDB_ERR_OPERATIONS_ERROR;
760                 }
761                 ntds_guid = GUID_string(tmp_ctx, &ntds);
762         }
763
764         for (i=0; i < el->num_values; i++) {
765                 ret = acl_validate_spn_value(tmp_ctx,
766                                              ldb,
767                                              (char *)el->values[i].data,
768                                              userAccountControl,
769                                              samAccountName,
770                                              dnsHostName,
771                                              netbios_name,
772                                              ntds_guid);
773                 if (ret != LDB_SUCCESS) {
774                         talloc_free(tmp_ctx);
775                         return ret;
776                 }
777         }
778         talloc_free(tmp_ctx);
779         return LDB_SUCCESS;
780 }
781
782 static int acl_add(struct ldb_module *module, struct ldb_request *req)
783 {
784         int ret;
785         struct ldb_dn *parent;
786         struct ldb_context *ldb;
787         const struct dsdb_schema *schema;
788         const struct dsdb_class *objectclass;
789         struct ldb_control *as_system;
790         struct ldb_message_element *el;
791         unsigned int instanceType = 0;
792
793         if (ldb_dn_is_special(req->op.add.message->dn)) {
794                 return ldb_next_request(module, req);
795         }
796
797         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
798         if (as_system != NULL) {
799                 as_system->critical = 0;
800         }
801
802         if (dsdb_module_am_system(module) || as_system) {
803                 return ldb_next_request(module, req);
804         }
805
806         ldb = ldb_module_get_ctx(module);
807
808         parent = ldb_dn_get_parent(req, req->op.add.message->dn);
809         if (parent == NULL) {
810                 return ldb_oom(ldb);
811         }
812
813         schema = dsdb_get_schema(ldb, req);
814         if (!schema) {
815                 return ldb_operr(ldb);
816         }
817
818         objectclass = dsdb_get_structural_oc_from_msg(schema, req->op.add.message);
819         if (!objectclass) {
820                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
821                                        "acl: unable to find or validate structural objectClass on %s\n",
822                                        ldb_dn_get_linearized(req->op.add.message->dn));
823                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
824         }
825
826         el = ldb_msg_find_element(req->op.add.message, "instanceType");
827         if ((el != NULL) && (el->num_values != 1)) {
828                 ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
829                 return LDB_ERR_UNWILLING_TO_PERFORM;
830         }
831
832         instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
833                                                  "instanceType", 0);
834         if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
835                 static const char *no_attrs[] = { NULL };
836                 struct ldb_result *partition_res;
837                 struct ldb_dn *partitions_dn;
838
839                 partitions_dn = samdb_partitions_dn(ldb, req);
840                 if (!partitions_dn) {
841                         ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
842                         return LDB_ERR_UNWILLING_TO_PERFORM;
843                 }
844
845                 ret = dsdb_module_search(module, req, &partition_res,
846                                          partitions_dn, LDB_SCOPE_ONELEVEL,
847                                          no_attrs,
848                                          DSDB_FLAG_NEXT_MODULE |
849                                          DSDB_FLAG_AS_SYSTEM |
850                                          DSDB_SEARCH_ONE_ONLY |
851                                          DSDB_SEARCH_SHOW_RECYCLED,
852                                          req,
853                                          "(&(nCName=%s)(objectClass=crossRef))",
854                                          ldb_dn_get_linearized(req->op.add.message->dn));
855
856                 if (ret == LDB_SUCCESS) {
857                         /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
858                         ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
859                                                              SEC_ADS_WRITE_PROP,
860                                                              &objectclass->schemaIDGUID, req);
861                         if (ret != LDB_SUCCESS) {
862                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
863                                                        "acl: ACL check failed on crossRef object %s: %s\n",
864                                                        ldb_dn_get_linearized(partition_res->msgs[0]->dn),
865                                                        ldb_errstring(ldb));
866                                 return ret;
867                         }
868
869                         /*
870                          * TODO: Remaining checks, like if we are
871                          * the naming master etc need to be handled
872                          * in the instanceType module
873                          */
874                         return ldb_next_request(module, req);
875                 }
876
877                 /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
878                 ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
879                                                      SEC_ADS_CREATE_CHILD,
880                                                      &objectclass->schemaIDGUID, req);
881                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
882                     ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
883                 {
884                         /* Allow provision bootstrap */
885                         ret = LDB_SUCCESS;
886                 }
887                 if (ret != LDB_SUCCESS) {
888                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
889                                                "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
890                                                ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
891                         return ret;
892                 }
893
894                 /*
895                  * TODO: Remaining checks, like if we are the naming
896                  * master and adding the crossRef object need to be
897                  * handled in the instanceType module
898                  */
899                 return ldb_next_request(module, req);
900         }
901
902         ret = dsdb_module_check_access_on_dn(module, req, parent,
903                                              SEC_ADS_CREATE_CHILD,
904                                              &objectclass->schemaIDGUID, req);
905         if (ret != LDB_SUCCESS) {
906                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
907                                        "acl: unable to get access to %s\n",
908                                        ldb_dn_get_linearized(req->op.add.message->dn));
909                 return ret;
910         }
911         return ldb_next_request(module, req);
912 }
913
914 /* ckecks if modifications are allowed on "Member" attribute */
915 static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
916                                      struct ldb_module *module,
917                                      struct ldb_request *req,
918                                      struct security_descriptor *sd,
919                                      struct dom_sid *sid,
920                                      const struct dsdb_attribute *attr,
921                                      const struct dsdb_class *objectclass)
922 {
923         int ret;
924         unsigned int i;
925         struct ldb_context *ldb = ldb_module_get_ctx(module);
926         struct ldb_dn *user_dn;
927         struct ldb_message_element *member_el;
928         /* if we have wp, we can do whatever we like */
929         if (acl_check_access_on_attribute(module,
930                                           mem_ctx,
931                                           sd,
932                                           sid,
933                                           SEC_ADS_WRITE_PROP,
934                                           attr, objectclass) == LDB_SUCCESS) {
935                 return LDB_SUCCESS;
936         }
937         /* if we are adding/deleting ourselves, check for self membership */
938         ret = dsdb_find_dn_by_sid(ldb, mem_ctx, 
939                                   &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], 
940                                   &user_dn);
941         if (ret != LDB_SUCCESS) {
942                 return ret;
943         }
944         member_el = ldb_msg_find_element(req->op.mod.message, "member");
945         if (!member_el) {
946                 return ldb_operr(ldb);
947         }
948         /* user can only remove oneself */
949         if (member_el->num_values == 0) {
950                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
951         }
952         for (i = 0; i < member_el->num_values; i++) {
953                 if (strcasecmp((const char *)member_el->values[i].data,
954                                ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
955                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
956                 }
957         }
958         ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
959                                        GUID_DRS_SELF_MEMBERSHIP,
960                                        SEC_ADS_SELF_WRITE,
961                                        sid);
962         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
963                 dsdb_acl_debug(sd, acl_user_token(module),
964                                req->op.mod.message->dn,
965                                true,
966                                10);
967         }
968         return ret;
969 }
970
971 static int acl_check_password_rights(
972         TALLOC_CTX *mem_ctx,
973         struct ldb_module *module,
974         struct ldb_request *req,
975         struct security_descriptor *sd,
976         struct dom_sid *sid,
977         const struct dsdb_class *objectclass,
978         bool userPassword,
979         struct  dsdb_control_password_acl_validation **control_for_response)
980 {
981         int ret = LDB_SUCCESS;
982         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
983         unsigned int del_val_cnt = 0, add_val_cnt = 0, rep_val_cnt = 0;
984         struct ldb_message_element *el;
985         struct ldb_message *msg;
986         struct ldb_control *c = NULL;
987         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
988                                         "unicodePwd", NULL }, **l;
989         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
990         struct dsdb_control_password_acl_validation *pav = NULL;
991
992         if (tmp_ctx == NULL) {
993                 return LDB_ERR_OPERATIONS_ERROR;
994         }
995
996         pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
997         if (pav == NULL) {
998                 talloc_free(tmp_ctx);
999                 return LDB_ERR_OPERATIONS_ERROR;
1000         }
1001         /*
1002          * Set control_for_response to pav so it can be added to the response
1003          * and be passed up to the audit_log module which uses it to identify
1004          * password reset attempts.
1005          */
1006         *control_for_response = pav;
1007
1008         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OID);
1009         if (c != NULL) {
1010                 pav->pwd_reset = false;
1011
1012                 /*
1013                  * The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
1014                  * have a user password change and not a set as the message
1015                  * looks like. In it's value blob it contains the NT and/or LM
1016                  * hash of the old password specified by the user.  This control
1017                  * is used by the SAMR and "kpasswd" password change mechanisms.
1018                  *
1019                  * This control can't be used by real LDAP clients,
1020                  * the only caller is samdb_set_password_internal(),
1021                  * so we don't have to strict verification of the input.
1022                  */
1023                 ret = acl_check_extended_right(tmp_ctx,
1024                                                sd,
1025                                                acl_user_token(module),
1026                                                GUID_DRS_USER_CHANGE_PASSWORD,
1027                                                SEC_ADS_CONTROL_ACCESS,
1028                                                sid);
1029                 goto checked;
1030         }
1031
1032         c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1033         if (c != NULL) {
1034                 pav->pwd_reset = true;
1035
1036                 /*
1037                  * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1038                  * "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
1039                  * have a force password set.
1040                  * This control is used by the SAMR/NETLOGON/LSA password
1041                  * reset mechanisms.
1042                  *
1043                  * This control can't be used by real LDAP clients,
1044                  * the only caller is samdb_set_password_internal(),
1045                  * so we don't have to strict verification of the input.
1046                  */
1047                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1048                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1049                                                SEC_ADS_CONTROL_ACCESS,
1050                                                sid);
1051                 goto checked;
1052         }
1053
1054         el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1055         if (el != NULL) {
1056                 /*
1057                  * dBCSPwd is only allowed with a control.
1058                  */
1059                 talloc_free(tmp_ctx);
1060                 return LDB_ERR_UNWILLING_TO_PERFORM;
1061         }
1062
1063         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1064         if (msg == NULL) {
1065                 return ldb_module_oom(module);
1066         }
1067         for (l = passwordAttrs; *l != NULL; l++) {
1068                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1069                         continue;
1070                 }
1071
1072                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1073                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1074                                 ++del_attr_cnt;
1075                                 del_val_cnt += el->num_values;
1076                         }
1077                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1078                                 ++add_attr_cnt;
1079                                 add_val_cnt += el->num_values;
1080                         }
1081                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1082                                 ++rep_attr_cnt;
1083                                 rep_val_cnt += el->num_values;
1084                         }
1085                         ldb_msg_remove_element(msg, el);
1086                 }
1087         }
1088
1089         /* single deletes will be handled by the "password_hash" LDB module
1090          * later in the stack, so we let it though here */
1091         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1092                 talloc_free(tmp_ctx);
1093                 return LDB_SUCCESS;
1094         }
1095
1096
1097         if (rep_attr_cnt > 0) {
1098                 pav->pwd_reset = true;
1099
1100                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1101                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1102                                                SEC_ADS_CONTROL_ACCESS,
1103                                                sid);
1104                 goto checked;
1105         }
1106
1107         if (add_attr_cnt != del_attr_cnt) {
1108                 pav->pwd_reset = true;
1109
1110                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1111                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1112                                                SEC_ADS_CONTROL_ACCESS,
1113                                                sid);
1114                 goto checked;
1115         }
1116
1117         if (add_val_cnt == 1 && del_val_cnt == 1) {
1118                 pav->pwd_reset = false;
1119
1120                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1121                                                GUID_DRS_USER_CHANGE_PASSWORD,
1122                                                SEC_ADS_CONTROL_ACCESS,
1123                                                sid);
1124                 /* Very strange, but we get constraint violation in this case */
1125                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1126                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1127                 }
1128                 goto checked;
1129         }
1130
1131         if (add_val_cnt == 1 && del_val_cnt == 0) {
1132                 pav->pwd_reset = true;
1133
1134                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1135                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
1136                                                SEC_ADS_CONTROL_ACCESS,
1137                                                sid);
1138                 /* Very strange, but we get constraint violation in this case */
1139                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1140                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
1141                 }
1142                 goto checked;
1143         }
1144
1145         /*
1146          * Everything else is handled by the password_hash module where it will
1147          * fail, but with the correct error code when the module is again
1148          * checking the attributes. As the change request will lack the
1149          * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1150          * any modification attempt that went this way will be rejected.
1151          */
1152
1153         talloc_free(tmp_ctx);
1154         return LDB_SUCCESS;
1155
1156 checked:
1157         if (ret != LDB_SUCCESS) {
1158                 dsdb_acl_debug(sd, acl_user_token(module),
1159                                req->op.mod.message->dn,
1160                                true,
1161                                10);
1162                 talloc_free(tmp_ctx);
1163                 return ret;
1164         }
1165
1166         ret = ldb_request_add_control(req,
1167                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1168         if (ret != LDB_SUCCESS) {
1169                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1170                           "Unable to register ACL validation control!\n");
1171                 return ret;
1172         }
1173         return LDB_SUCCESS;
1174 }
1175
1176 /*
1177  * Context needed by acl_callback
1178  */
1179 struct acl_callback_context {
1180         struct ldb_request *request;
1181         struct ldb_module *module;
1182 };
1183
1184 /*
1185  * @brief Copy the password validation control to the reply.
1186  *
1187  * Copy the dsdb_control_password_acl_validation control from the request,
1188  * to the reply.  The control is used by the audit_log module to identify
1189  * password rests.
1190  *
1191  * @param req the ldb request.
1192  * @param ares the result, updated with the control.
1193  */
1194 static void copy_password_acl_validation_control(
1195         struct ldb_request *req,
1196         struct ldb_reply *ares)
1197 {
1198         struct ldb_control *pav_ctrl = NULL;
1199         struct dsdb_control_password_acl_validation *pav = NULL;
1200
1201         pav_ctrl = ldb_request_get_control(
1202                 discard_const(req),
1203                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1204         if (pav_ctrl == NULL) {
1205                 return;
1206         }
1207
1208         pav = talloc_get_type_abort(
1209                 pav_ctrl->data,
1210                 struct dsdb_control_password_acl_validation);
1211         if (pav == NULL) {
1212                 return;
1213         }
1214         ldb_reply_add_control(
1215                 ares,
1216                 DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1217                 false,
1218                 pav);
1219 }
1220 /*
1221  * @brief call back function for acl_modify.
1222  *
1223  * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1224  * the request to the reply.
1225  *
1226  * @param req the ldb_request.
1227  * @param ares the operation result.
1228  *
1229  * @return the LDB_STATUS
1230  */
1231 static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1232 {
1233         struct acl_callback_context *ac = NULL;
1234
1235         ac = talloc_get_type(req->context, struct acl_callback_context);
1236
1237         if (!ares) {
1238                 return ldb_module_done(
1239                         ac->request,
1240                         NULL,
1241                         NULL,
1242                         LDB_ERR_OPERATIONS_ERROR);
1243         }
1244
1245         /* pass on to the callback */
1246         switch (ares->type) {
1247         case LDB_REPLY_ENTRY:
1248                 return ldb_module_send_entry(
1249                         ac->request,
1250                         ares->message,
1251                         ares->controls);
1252
1253         case LDB_REPLY_REFERRAL:
1254                 return ldb_module_send_referral(
1255                         ac->request,
1256                         ares->referral);
1257
1258         case LDB_REPLY_DONE:
1259                 /*
1260                  * Copy the ACL control from the request to the response
1261                  */
1262                 copy_password_acl_validation_control(req, ares);
1263                 return ldb_module_done(
1264                         ac->request,
1265                         ares->controls,
1266                         ares->response,
1267                         ares->error);
1268
1269         default:
1270                 /* Can't happen */
1271                 return LDB_ERR_OPERATIONS_ERROR;
1272         }
1273 }
1274
1275 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1276 {
1277         int ret;
1278         struct ldb_context *ldb = ldb_module_get_ctx(module);
1279         const struct dsdb_schema *schema;
1280         unsigned int i;
1281         const struct dsdb_class *objectclass;
1282         struct ldb_result *acl_res;
1283         struct security_descriptor *sd;
1284         struct dom_sid *sid = NULL;
1285         struct ldb_control *as_system;
1286         struct ldb_control *is_undelete;
1287         bool userPassword;
1288         bool password_rights_checked = false;
1289         TALLOC_CTX *tmp_ctx;
1290         const struct ldb_message *msg = req->op.mod.message;
1291         static const char *acl_attrs[] = {
1292                 "nTSecurityDescriptor",
1293                 "objectClass",
1294                 "objectSid",
1295                 NULL
1296         };
1297         struct acl_callback_context *context = NULL;
1298         struct ldb_request *new_req = NULL;
1299         struct  dsdb_control_password_acl_validation *pav = NULL;
1300         struct ldb_control **controls = NULL;
1301
1302         if (ldb_dn_is_special(msg->dn)) {
1303                 return ldb_next_request(module, req);
1304         }
1305
1306         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1307         if (as_system != NULL) {
1308                 as_system->critical = 0;
1309         }
1310
1311         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1312
1313         /* Don't print this debug statement if elements[0].name is going to be NULL */
1314         if (msg->num_elements > 0) {
1315                 DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
1316         }
1317         if (dsdb_module_am_system(module) || as_system) {
1318                 return ldb_next_request(module, req);
1319         }
1320
1321         tmp_ctx = talloc_new(req);
1322         if (tmp_ctx == NULL) {
1323                 return ldb_oom(ldb);
1324         }
1325
1326         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
1327                                     acl_attrs,
1328                                     DSDB_FLAG_NEXT_MODULE |
1329                                     DSDB_FLAG_AS_SYSTEM |
1330                                     DSDB_SEARCH_SHOW_RECYCLED,
1331                                     req);
1332
1333         if (ret != LDB_SUCCESS) {
1334                 goto fail;
1335         }
1336
1337         userPassword = dsdb_user_password_support(module, req, req);
1338
1339         schema = dsdb_get_schema(ldb, tmp_ctx);
1340         if (!schema) {
1341                 talloc_free(tmp_ctx);
1342                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1343                                  "acl_modify: Error obtaining schema.");
1344         }
1345
1346         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1347         if (ret != LDB_SUCCESS) {
1348                 talloc_free(tmp_ctx);
1349                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1350                                  "acl_modify: Error retrieving security descriptor.");
1351         }
1352         /* Theoretically we pass the check if the object has no sd */
1353         if (!sd) {
1354                 goto success;
1355         }
1356
1357         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1358         if (!objectclass) {
1359                 talloc_free(tmp_ctx);
1360                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1361                                  "acl_modify: Error retrieving object class for GUID.");
1362         }
1363         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1364         for (i=0; i < msg->num_elements; i++) {
1365                 const struct ldb_message_element *el = &msg->elements[i];
1366                 const struct dsdb_attribute *attr;
1367
1368                 /*
1369                  * This basic attribute existence check with the right errorcode
1370                  * is needed since this module is the first one which requests
1371                  * schema attribute information.
1372                  * The complete attribute checking is done in the
1373                  * "objectclass_attrs" module behind this one.
1374                  *
1375                  * NOTE: "clearTextPassword" is not defined in the schema.
1376                  */
1377                 attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1378                 if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1379                         ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
1380                                                "on entry '%s' was not found in the schema!",
1381                                                req->op.mod.message->elements[i].name,
1382                                        ldb_dn_get_linearized(req->op.mod.message->dn));
1383                         ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
1384                         goto fail;
1385                 }
1386
1387                 if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
1388                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1389                         uint32_t access_mask = 0;
1390
1391                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1392                                 access_mask |= SEC_STD_WRITE_OWNER;
1393                         }
1394                         if (sd_flags & SECINFO_DACL) {
1395                                 access_mask |= SEC_STD_WRITE_DAC;
1396                         }
1397                         if (sd_flags & SECINFO_SACL) {
1398                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1399                         }
1400
1401                         ret = acl_check_access_on_attribute(module,
1402                                                             tmp_ctx,
1403                                                             sd,
1404                                                             sid,
1405                                                             access_mask,
1406                                                             attr,
1407                                                             objectclass);
1408                         if (ret != LDB_SUCCESS) {
1409                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1410                                                        "Object %s has no write dacl access\n",
1411                                                        ldb_dn_get_linearized(msg->dn));
1412                                 dsdb_acl_debug(sd,
1413                                                acl_user_token(module),
1414                                                msg->dn,
1415                                                true,
1416                                                10);
1417                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1418                                 goto fail;
1419                         }
1420                 } else if (ldb_attr_cmp("member", el->name) == 0) {
1421                         ret = acl_check_self_membership(tmp_ctx,
1422                                                         module,
1423                                                         req,
1424                                                         sd,
1425                                                         sid,
1426                                                         attr,
1427                                                         objectclass);
1428                         if (ret != LDB_SUCCESS) {
1429                                 goto fail;
1430                         }
1431                 } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
1432                         /* this one is not affected by any rights, we should let it through
1433                            so that passwords_hash returns the correct error */
1434                         continue;
1435                 } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1436                            (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
1437                            ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1438                         /*
1439                          * Ideally we would do the acl_check_password_rights
1440                          * before we checked the other attributes, i.e. in a
1441                          * loop before the current one.
1442                          * Have not done this as yet in order to limit the size
1443                          * of the change. To limit the possibility of breaking
1444                          * the ACL logic.
1445                          */
1446                         if (password_rights_checked) {
1447                                 continue;
1448                         }
1449                         ret = acl_check_password_rights(tmp_ctx,
1450                                                         module,
1451                                                         req,
1452                                                         sd,
1453                                                         sid,
1454                                                         objectclass,
1455                                                         userPassword,
1456                                                         &pav);
1457                         if (ret != LDB_SUCCESS) {
1458                                 goto fail;
1459                         }
1460                         password_rights_checked = true;
1461                 } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1462                         ret = acl_check_spn(tmp_ctx,
1463                                             module,
1464                                             req,
1465                                             sd,
1466                                             sid,
1467                                             attr,
1468                                             objectclass);
1469                         if (ret != LDB_SUCCESS) {
1470                                 goto fail;
1471                         }
1472                 } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
1473                         /*
1474                          * in case of undelete op permissions on
1475                          * isDeleted are irrelevant and
1476                          * distinguishedName is removed by the
1477                          * tombstone_reanimate module
1478                          */
1479                         continue;
1480                 } else {
1481                         ret = acl_check_access_on_attribute(module,
1482                                                             tmp_ctx,
1483                                                             sd,
1484                                                             sid,
1485                                                             SEC_ADS_WRITE_PROP,
1486                                                             attr,
1487                                                             objectclass);
1488                         if (ret != LDB_SUCCESS) {
1489                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1490                                                        "Object %s has no write property access\n",
1491                                                        ldb_dn_get_linearized(msg->dn));
1492                                 dsdb_acl_debug(sd,
1493                                                acl_user_token(module),
1494                                                msg->dn,
1495                                                true,
1496                                                10);
1497                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1498                                 goto fail;
1499                         }
1500                 }
1501         }
1502
1503 success:
1504         talloc_free(tmp_ctx);
1505         context = talloc_zero(req, struct acl_callback_context);
1506
1507         if (context == NULL) {
1508                 return ldb_oom(ldb);
1509         }
1510         context->request = req;
1511         context->module  = module;
1512         ret = ldb_build_mod_req(
1513                 &new_req,
1514                 ldb,
1515                 req,
1516                 req->op.mod.message,
1517                 req->controls,
1518                 context,
1519                 acl_callback,
1520                 req);
1521         if (ret != LDB_SUCCESS) {
1522                 return ret;
1523         }
1524         return ldb_next_request(module, new_req);
1525 fail:
1526         talloc_free(tmp_ctx);
1527         /*
1528          * We copy the pav into the result, so that the password reset
1529          * logging code in audit_log can log failed password reset attempts.
1530          */
1531         if (pav) {
1532                 struct ldb_control *control = NULL;
1533
1534                 controls = talloc_zero_array(req, struct ldb_control *, 2);
1535                 if (controls == NULL) {
1536                         return ldb_oom(ldb);
1537                 }
1538
1539                 control = talloc(controls, struct ldb_control);
1540
1541                 if (control == NULL) {
1542                         return ldb_oom(ldb);
1543                 }
1544
1545                 control->oid= talloc_strdup(
1546                         control,
1547                         DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1548                 if (control->oid == NULL) {
1549                         return ldb_oom(ldb);
1550                 }
1551                 control->critical       = false;
1552                 control->data   = pav;
1553                 *controls = control;
1554         }
1555         return ldb_module_done(req, controls, NULL, ret);
1556 }
1557
1558 /* similar to the modify for the time being.
1559  * We need to consider the special delete tree case, though - TODO */
1560 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
1561 {
1562         int ret;
1563         struct ldb_dn *parent;
1564         struct ldb_context *ldb;
1565         struct ldb_dn *nc_root;
1566         struct ldb_control *as_system;
1567         const struct dsdb_schema *schema;
1568         const struct dsdb_class *objectclass;
1569         struct security_descriptor *sd = NULL;
1570         struct dom_sid *sid = NULL;
1571         struct ldb_result *acl_res;
1572         static const char *acl_attrs[] = {
1573                 "nTSecurityDescriptor",
1574                 "objectClass",
1575                 "objectSid",
1576                 NULL
1577         };
1578
1579         if (ldb_dn_is_special(req->op.del.dn)) {
1580                 return ldb_next_request(module, req);
1581         }
1582
1583         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1584         if (as_system != NULL) {
1585                 as_system->critical = 0;
1586         }
1587
1588         if (dsdb_module_am_system(module) || as_system) {
1589                 return ldb_next_request(module, req);
1590         }
1591
1592         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
1593
1594         ldb = ldb_module_get_ctx(module);
1595
1596         parent = ldb_dn_get_parent(req, req->op.del.dn);
1597         if (parent == NULL) {
1598                 return ldb_oom(ldb);
1599         }
1600
1601         /* Make sure we aren't deleting a NC */
1602
1603         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
1604         if (ret != LDB_SUCCESS) {
1605                 return ret;
1606         }
1607         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
1608                 talloc_free(nc_root);
1609                 DEBUG(10,("acl:deleting a NC\n"));
1610                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1611                 return ldb_module_done(req, NULL, NULL,
1612                                        LDB_ERR_UNWILLING_TO_PERFORM);
1613         }
1614         talloc_free(nc_root);
1615
1616         ret = dsdb_module_search_dn(module, req, &acl_res,
1617                                     req->op.del.dn, acl_attrs,
1618                                     DSDB_FLAG_NEXT_MODULE |
1619                                     DSDB_FLAG_AS_SYSTEM |
1620                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1621         /* we sould be able to find the parent */
1622         if (ret != LDB_SUCCESS) {
1623                 DEBUG(10,("acl: failed to find object %s\n",
1624                           ldb_dn_get_linearized(req->op.rename.olddn)));
1625                 return ret;
1626         }
1627
1628         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1629         if (ret != LDB_SUCCESS) {
1630                 return ldb_operr(ldb);
1631         }
1632         if (!sd) {
1633                 return ldb_operr(ldb);
1634         }
1635
1636         schema = dsdb_get_schema(ldb, req);
1637         if (!schema) {
1638                 return ldb_operr(ldb);
1639         }
1640
1641         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1642
1643         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1644         if (!objectclass) {
1645                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1646                                  "acl_modify: Error retrieving object class for GUID.");
1647         }
1648
1649         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
1650                 ret = acl_check_access_on_objectclass(module, req, sd, sid,
1651                                                       SEC_ADS_DELETE_TREE,
1652                                                       objectclass);
1653                 if (ret != LDB_SUCCESS) {
1654                         return ret;
1655                 }
1656
1657                 return ldb_next_request(module, req);
1658         }
1659
1660         /* First check if we have delete object right */
1661         ret = acl_check_access_on_objectclass(module, req, sd, sid,
1662                                               SEC_STD_DELETE,
1663                                               objectclass);
1664         if (ret == LDB_SUCCESS) {
1665                 return ldb_next_request(module, req);
1666         }
1667
1668         /* Nope, we don't have delete object. Lets check if we have delete
1669          * child on the parent */
1670         ret = dsdb_module_check_access_on_dn(module, req, parent,
1671                                              SEC_ADS_DELETE_CHILD,
1672                                              &objectclass->schemaIDGUID,
1673                                              req);
1674         if (ret != LDB_SUCCESS) {
1675                 return ret;
1676         }
1677
1678         return ldb_next_request(module, req);
1679 }
1680 static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
1681                                          struct ldb_module *module,
1682                                          struct ldb_request *req,
1683                                          struct ldb_dn *nc_root)
1684 {
1685         int ret;
1686         struct ldb_result *acl_res;
1687         struct security_descriptor *sd = NULL;
1688         struct dom_sid *sid = NULL;
1689         static const char *acl_attrs[] = {
1690                 "nTSecurityDescriptor",
1691                 "objectClass",
1692                 "objectSid",
1693                 NULL
1694         };
1695
1696         ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
1697                                     nc_root, acl_attrs,
1698                                     DSDB_FLAG_NEXT_MODULE |
1699                                     DSDB_FLAG_AS_SYSTEM |
1700                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1701         if (ret != LDB_SUCCESS) {
1702                 DEBUG(10,("acl: failed to find object %s\n",
1703                           ldb_dn_get_linearized(nc_root)));
1704                 return ret;
1705         }
1706
1707         ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
1708         sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
1709         if (ret != LDB_SUCCESS || !sd) {
1710                 return ldb_operr(ldb_module_get_ctx(module));
1711         }
1712         return acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
1713                                         GUID_DRS_REANIMATE_TOMBSTONE,
1714                                         SEC_ADS_CONTROL_ACCESS, sid);
1715 }
1716
1717 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
1718 {
1719         int ret;
1720         struct ldb_dn *oldparent;
1721         struct ldb_dn *newparent;
1722         const struct dsdb_schema *schema;
1723         const struct dsdb_class *objectclass;
1724         const struct dsdb_attribute *attr = NULL;
1725         struct ldb_context *ldb;
1726         struct security_descriptor *sd = NULL;
1727         struct dom_sid *sid = NULL;
1728         struct ldb_result *acl_res;
1729         struct ldb_dn *nc_root;
1730         struct ldb_control *as_system;
1731         struct ldb_control *is_undelete;
1732         TALLOC_CTX *tmp_ctx;
1733         const char *rdn_name;
1734         static const char *acl_attrs[] = {
1735                 "nTSecurityDescriptor",
1736                 "objectClass",
1737                 "objectSid",
1738                 NULL
1739         };
1740
1741         if (ldb_dn_is_special(req->op.rename.olddn)) {
1742                 return ldb_next_request(module, req);
1743         }
1744
1745         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1746         if (as_system != NULL) {
1747                 as_system->critical = 0;
1748         }
1749
1750         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
1751         if (dsdb_module_am_system(module) || as_system) {
1752                 return ldb_next_request(module, req);
1753         }
1754
1755         ldb = ldb_module_get_ctx(module);
1756
1757         tmp_ctx = talloc_new(req);
1758         if (tmp_ctx == NULL) {
1759                 return ldb_oom(ldb);
1760         }
1761
1762         oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
1763         if (oldparent == NULL) {
1764                 return ldb_oom(ldb);
1765         }
1766         newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
1767         if (newparent == NULL) {
1768                 return ldb_oom(ldb);
1769         }
1770
1771         /* Make sure we aren't renaming/moving a NC */
1772
1773         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
1774         if (ret != LDB_SUCCESS) {
1775                 return ret;
1776         }
1777         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
1778                 talloc_free(nc_root);
1779                 DEBUG(10,("acl:renaming/moving a NC\n"));
1780                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1781                 return ldb_module_done(req, NULL, NULL,
1782                                        LDB_ERR_UNWILLING_TO_PERFORM);
1783         }
1784
1785         /* special check for undelete operation */
1786         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1787         if (is_undelete != NULL) {
1788                 is_undelete->critical = 0;
1789                 ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
1790                 if (ret != LDB_SUCCESS) {
1791                         talloc_free(tmp_ctx);
1792                         return ret;
1793                 }
1794         }
1795         talloc_free(nc_root);
1796
1797         /* Look for the parent */
1798
1799         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
1800                                     req->op.rename.olddn, acl_attrs,
1801                                     DSDB_FLAG_NEXT_MODULE |
1802                                     DSDB_FLAG_AS_SYSTEM |
1803                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1804         /* we sould be able to find the parent */
1805         if (ret != LDB_SUCCESS) {
1806                 DEBUG(10,("acl: failed to find object %s\n",
1807                           ldb_dn_get_linearized(req->op.rename.olddn)));
1808                 talloc_free(tmp_ctx);
1809                 return ret;
1810         }
1811
1812         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1813         if (ret != LDB_SUCCESS) {
1814                 talloc_free(tmp_ctx);
1815                 return ldb_operr(ldb);
1816         }
1817         if (!sd) {
1818                 talloc_free(tmp_ctx);
1819                 return ldb_operr(ldb);
1820         }
1821
1822         schema = dsdb_get_schema(ldb, acl_res);
1823         if (!schema) {
1824                 talloc_free(tmp_ctx);
1825                 return ldb_operr(ldb);
1826         }
1827
1828         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1829
1830         objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1831         if (!objectclass) {
1832                 talloc_free(tmp_ctx);
1833                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1834                                  "acl_modify: Error retrieving object class for GUID.");
1835         }
1836
1837         attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
1838         if (attr == NULL) {
1839                 talloc_free(tmp_ctx);
1840                 return ldb_operr(ldb);
1841         }
1842
1843         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
1844                                             SEC_ADS_WRITE_PROP,
1845                                             attr, objectclass);
1846         if (ret != LDB_SUCCESS) {
1847                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1848                                        "Object %s has no wp on %s\n",
1849                                        ldb_dn_get_linearized(req->op.rename.olddn),
1850                                        attr->lDAPDisplayName);
1851                 dsdb_acl_debug(sd,
1852                           acl_user_token(module),
1853                           req->op.rename.olddn,
1854                           true,
1855                           10);
1856                 talloc_free(tmp_ctx);
1857                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1858         }
1859
1860         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
1861         if (rdn_name == NULL) {
1862                 talloc_free(tmp_ctx);
1863                 return ldb_operr(ldb);
1864         }
1865
1866         attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
1867         if (attr == NULL) {
1868                 talloc_free(tmp_ctx);
1869                 return ldb_operr(ldb);
1870         }
1871
1872         ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
1873                                             SEC_ADS_WRITE_PROP,
1874                                             attr, objectclass);
1875         if (ret != LDB_SUCCESS) {
1876                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1877                                        "Object %s has no wp on %s\n",
1878                                        ldb_dn_get_linearized(req->op.rename.olddn),
1879                                        attr->lDAPDisplayName);
1880                 dsdb_acl_debug(sd,
1881                           acl_user_token(module),
1882                           req->op.rename.olddn,
1883                           true,
1884                           10);
1885                 talloc_free(tmp_ctx);
1886                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1887         }
1888
1889         if (ldb_dn_compare(oldparent, newparent) == 0) {
1890                 /* regular rename, not move, nothing more to do */
1891                 talloc_free(tmp_ctx);
1892                 return ldb_next_request(module, req);
1893         }
1894
1895         /* new parent should have create child */
1896         ret = dsdb_module_check_access_on_dn(module, req, newparent,
1897                                              SEC_ADS_CREATE_CHILD,
1898                                              &objectclass->schemaIDGUID, req);
1899         if (ret != LDB_SUCCESS) {
1900                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1901                                        "acl:access_denied renaming %s",
1902                                        ldb_dn_get_linearized(req->op.rename.olddn));
1903                 talloc_free(tmp_ctx);
1904                 return ret;
1905         }
1906
1907         /* do we have delete object on the object? */
1908         /* this access is not necessary for undelete ops */
1909         if (is_undelete == NULL) {
1910                 ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
1911                                                       SEC_STD_DELETE,
1912                                                       objectclass);
1913                 if (ret == LDB_SUCCESS) {
1914                         talloc_free(tmp_ctx);
1915                         return ldb_next_request(module, req);
1916                 }
1917                 /* what about delete child on the current parent */
1918                 ret = dsdb_module_check_access_on_dn(module, req, oldparent,
1919                                                      SEC_ADS_DELETE_CHILD,
1920                                                      &objectclass->schemaIDGUID,
1921                                                      req);
1922                 if (ret != LDB_SUCCESS) {
1923                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
1924                                                "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
1925                         talloc_free(tmp_ctx);
1926                         return ldb_module_done(req, NULL, NULL, ret);
1927                 }
1928         }
1929         talloc_free(tmp_ctx);
1930
1931         return ldb_next_request(module, req);
1932 }
1933
1934 static int acl_search_update_confidential_attrs(struct acl_context *ac,
1935                                                 struct acl_private *data)
1936 {
1937         struct dsdb_attribute *a;
1938         uint32_t n = 0;
1939
1940         if (data->acl_search) {
1941                 /*
1942                  * If acl:search is activated, the acl_read module
1943                  * protects confidential attributes.
1944                  */
1945                 return LDB_SUCCESS;
1946         }
1947
1948         if ((ac->schema == data->cached_schema_ptr) &&
1949             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
1950         {
1951                 return LDB_SUCCESS;
1952         }
1953
1954         data->cached_schema_ptr = NULL;
1955         data->cached_schema_loaded_usn = 0;
1956         data->cached_schema_metadata_usn = 0;
1957         TALLOC_FREE(data->confidential_attrs);
1958
1959         if (ac->schema == NULL) {
1960                 return LDB_SUCCESS;
1961         }
1962
1963         for (a = ac->schema->attributes; a; a = a->next) {
1964                 const char **attrs = data->confidential_attrs;
1965
1966                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
1967                         continue;
1968                 }
1969
1970                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
1971                 if (attrs == NULL) {
1972                         TALLOC_FREE(data->confidential_attrs);
1973                         return ldb_module_oom(ac->module);
1974                 }
1975
1976                 attrs[n] = a->lDAPDisplayName;
1977                 attrs[n+1] = NULL;
1978                 n++;
1979
1980                 data->confidential_attrs = attrs;
1981         }
1982
1983         data->cached_schema_ptr = ac->schema;
1984         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
1985
1986         return LDB_SUCCESS;
1987 }
1988
1989 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1990 {
1991         struct acl_context *ac;
1992         struct acl_private *data;
1993         struct ldb_result *acl_res;
1994         static const char *acl_attrs[] = {
1995                 "objectClass",
1996                 "nTSecurityDescriptor",
1997                 "objectSid",
1998                 NULL
1999         };
2000         int ret;
2001         unsigned int i;
2002
2003         ac = talloc_get_type(req->context, struct acl_context);
2004         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2005         if (!ares) {
2006                 return ldb_module_done(ac->req, NULL, NULL,
2007                                        LDB_ERR_OPERATIONS_ERROR);
2008         }
2009         if (ares->error != LDB_SUCCESS) {
2010                 return ldb_module_done(ac->req, ares->controls,
2011                                        ares->response, ares->error);
2012         }
2013
2014         switch (ares->type) {
2015         case LDB_REPLY_ENTRY:
2016                 if (ac->constructed_attrs) {
2017                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn, 
2018                                                     acl_attrs,
2019                                                     DSDB_FLAG_NEXT_MODULE |
2020                                                     DSDB_FLAG_AS_SYSTEM |
2021                                                     DSDB_SEARCH_SHOW_RECYCLED,
2022                                                     req);
2023                         if (ret != LDB_SUCCESS) {
2024                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2025                         }
2026                 }
2027
2028                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2029                         ret = acl_allowedAttributes(ac->module, ac->schema,
2030                                                     acl_res->msgs[0],
2031                                                     ares->message, ac);
2032                         if (ret != LDB_SUCCESS) {
2033                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2034                         }
2035                 }
2036
2037                 if (ac->allowedChildClasses) {
2038                         ret = acl_childClasses(ac->module, ac->schema,
2039                                                acl_res->msgs[0],
2040                                                ares->message,
2041                                                "allowedChildClasses");
2042                         if (ret != LDB_SUCCESS) {
2043                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2044                         }
2045                 }
2046
2047                 if (ac->allowedChildClassesEffective) {
2048                         ret = acl_childClassesEffective(ac->module, ac->schema,
2049                                                         acl_res->msgs[0],
2050                                                         ares->message, ac);
2051                         if (ret != LDB_SUCCESS) {
2052                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2053                         }
2054                 }
2055
2056                 if (ac->sDRightsEffective) {
2057                         ret = acl_sDRightsEffective(ac->module,
2058                                                     acl_res->msgs[0],
2059                                                     ares->message, ac);
2060                         if (ret != LDB_SUCCESS) {
2061                                 return ldb_module_done(ac->req, NULL, NULL, ret);
2062                         }
2063                 }
2064
2065                 if (data == NULL) {
2066                         return ldb_module_send_entry(ac->req, ares->message,
2067                                                      ares->controls);
2068                 }
2069
2070                 if (ac->am_system) {
2071                         return ldb_module_send_entry(ac->req, ares->message,
2072                                                      ares->controls);
2073                 }
2074
2075                 if (data->password_attrs != NULL) {
2076                         for (i = 0; data->password_attrs[i]; i++) {
2077                                 if ((!ac->userPassword) &&
2078                                     (ldb_attr_cmp(data->password_attrs[i],
2079                                                   "userPassword") == 0))
2080                                 {
2081                                                 continue;
2082                                 }
2083
2084                                 ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
2085                         }
2086                 }
2087
2088                 if (ac->am_administrator) {
2089                         return ldb_module_send_entry(ac->req, ares->message,
2090                                                      ares->controls);
2091                 }
2092
2093                 ret = acl_search_update_confidential_attrs(ac, data);
2094                 if (ret != LDB_SUCCESS) {
2095                         return ret;
2096                 }
2097
2098                 if (data->confidential_attrs != NULL) {
2099                         for (i = 0; data->confidential_attrs[i]; i++) {
2100                                 ldb_msg_remove_attr(ares->message,
2101                                                     data->confidential_attrs[i]);
2102                         }
2103                 }
2104
2105                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2106
2107         case LDB_REPLY_REFERRAL:
2108                 return ldb_module_send_referral(ac->req, ares->referral);
2109
2110         case LDB_REPLY_DONE:
2111                 return ldb_module_done(ac->req, ares->controls,
2112                                        ares->response, LDB_SUCCESS);
2113
2114         }
2115         return LDB_SUCCESS;
2116 }
2117
2118 static int acl_search(struct ldb_module *module, struct ldb_request *req)
2119 {
2120         struct ldb_context *ldb;
2121         struct acl_context *ac;
2122         struct ldb_parse_tree *down_tree;
2123         struct ldb_request *down_req;
2124         struct acl_private *data;
2125         int ret;
2126         unsigned int i;
2127
2128         if (ldb_dn_is_special(req->op.search.base)) {
2129                 return ldb_next_request(module, req);
2130         }
2131
2132         ldb = ldb_module_get_ctx(module);
2133
2134         ac = talloc_zero(req, struct acl_context);
2135         if (ac == NULL) {
2136                 return ldb_oom(ldb);
2137         }
2138         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2139
2140         ac->module = module;
2141         ac->req = req;
2142         ac->am_system = dsdb_module_am_system(module);
2143         ac->am_administrator = dsdb_module_am_administrator(module);
2144         ac->constructed_attrs = false;
2145         ac->modify_search = true;
2146         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2147         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2148         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2149         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2150         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2151         ac->userPassword = true;
2152         ac->schema = dsdb_get_schema(ldb, ac);
2153
2154         ac->constructed_attrs |= ac->allowedAttributes;
2155         ac->constructed_attrs |= ac->allowedChildClasses;
2156         ac->constructed_attrs |= ac->allowedChildClassesEffective;
2157         ac->constructed_attrs |= ac->allowedAttributesEffective;
2158         ac->constructed_attrs |= ac->sDRightsEffective;
2159
2160         if (data == NULL) {
2161                 ac->modify_search = false;
2162         }
2163         if (ac->am_system) {
2164                 ac->modify_search = false;
2165         }
2166
2167         if (!ac->constructed_attrs && !ac->modify_search) {
2168                 talloc_free(ac);
2169                 return ldb_next_request(module, req);
2170         }
2171
2172         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2173         if (data != NULL) {
2174                 ac->userPassword = data->userPassword_support;
2175         }
2176
2177         ret = acl_search_update_confidential_attrs(ac, data);
2178         if (ret != LDB_SUCCESS) {
2179                 return ret;
2180         }
2181
2182         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2183         if (down_tree == NULL) {
2184                 return ldb_oom(ldb);
2185         }
2186
2187         if (!ac->am_system && data->password_attrs) {
2188                 for (i = 0; data->password_attrs[i]; i++) {
2189                         if ((!ac->userPassword) &&
2190                             (ldb_attr_cmp(data->password_attrs[i],
2191                                           "userPassword") == 0))
2192                         {
2193                                 continue;
2194                         }
2195
2196                         ldb_parse_tree_attr_replace(down_tree,
2197                                                     data->password_attrs[i],
2198                                                     "kludgeACLredactedattribute");
2199                 }
2200         }
2201
2202         if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) {
2203                 for (i = 0; data->confidential_attrs[i]; i++) {
2204                         ldb_parse_tree_attr_replace(down_tree,
2205                                                     data->confidential_attrs[i],
2206                                                     "kludgeACLredactedattribute");
2207                 }
2208         }
2209
2210         ret = ldb_build_search_req_ex(&down_req,
2211                                       ldb, ac,
2212                                       req->op.search.base,
2213                                       req->op.search.scope,
2214                                       down_tree,
2215                                       req->op.search.attrs,
2216                                       req->controls,
2217                                       ac, acl_search_callback,
2218                                       req);
2219         LDB_REQ_SET_LOCATION(down_req);
2220         if (ret != LDB_SUCCESS) {
2221                 return ret;
2222         }
2223         /* perform the search */
2224         return ldb_next_request(module, down_req);
2225 }
2226
2227 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2228 {
2229         struct ldb_context *ldb = ldb_module_get_ctx(module);
2230         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2231
2232         /* allow everybody to read the sequence number */
2233         if (strcmp(req->op.extended.oid,
2234                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2235                 return ldb_next_request(module, req);
2236         }
2237
2238         if (dsdb_module_am_system(module) ||
2239             dsdb_module_am_administrator(module) || as_system) {
2240                 return ldb_next_request(module, req);
2241         } else {
2242                 ldb_asprintf_errstring(ldb,
2243                                        "acl_extended: "
2244                                        "attempted database modify not permitted. "
2245                                        "User %s is not SYSTEM or an administrator",
2246                                        acl_user_name(req, module));
2247                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2248         }
2249 }
2250
2251 static const struct ldb_module_ops ldb_acl_module_ops = {
2252         .name              = "acl",
2253         .search            = acl_search,
2254         .add               = acl_add,
2255         .modify            = acl_modify,
2256         .del               = acl_delete,
2257         .rename            = acl_rename,
2258         .extended          = acl_extended,
2259         .init_context      = acl_module_init
2260 };
2261
2262 int ldb_acl_module_init(const char *version)
2263 {
2264         LDB_MODULE_CHECK_VERSION(version);
2265         return ldb_register_module(&ldb_acl_module_ops);
2266 }