9bf261225ec67946bfa55f8cb14012ece4386c61
[kai/samba.git] / source4 / dsdb / samdb / ldb_modules / acl.c
1 /*
2   ldb database library
3
4   Copyright (C) Simo Sorce 2006-2008
5   Copyright (C) Nadezhda Ivanova 2009
6   Copyright (C) Anatoliy Atanasov  2009
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: ldb ACL module
26  *
27  *  Description: Module that performs authorisation access checks based on the
28  *               account's security context and the DACL of the object being polled.
29  *               Only DACL checks implemented at this point
30  *
31  *  Authors: Nadezhda Ivanova, Anatoliy Atanasov
32  */
33
34 #include "includes.h"
35 #include "ldb_module.h"
36 #include "auth/auth.h"
37 #include "libcli/security/security.h"
38 #include "dsdb/samdb/samdb.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40 #include "param/param.h"
41 #include "dsdb/samdb/ldb_modules/util.h"
42 #include "lib/util/tsort.h"
43 #include "system/kerberos.h"
44 #include "auth/kerberos/kerberos.h"
45
46 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 };
59
60 struct acl_context {
61         struct ldb_module *module;
62         struct ldb_request *req;
63         bool am_system;
64         bool am_administrator;
65         bool modify_search;
66         bool constructed_attrs;
67         bool allowedAttributes;
68         bool allowedAttributesEffective;
69         bool allowedChildClasses;
70         bool allowedChildClassesEffective;
71         bool sDRightsEffective;
72         bool userPassword;
73         const char * const *attrs;
74         struct dsdb_schema *schema;
75 };
76
77 static int acl_module_init(struct ldb_module *module)
78 {
79         struct ldb_context *ldb;
80         struct acl_private *data;
81         int ret;
82         unsigned int i, n, j;
83         TALLOC_CTX *mem_ctx;
84         static const char * const attrs[] = { "passwordAttribute", NULL };
85         static const char * const secret_attrs[] = {
86                 DSDB_SECRET_ATTRIBUTES
87         };
88         struct ldb_result *res;
89         struct ldb_message *msg;
90         struct ldb_message_element *password_attributes;
91
92         ldb = ldb_module_get_ctx(module);
93
94         ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
95         if (ret != LDB_SUCCESS) {
96                 ldb_debug(ldb, LDB_DEBUG_ERROR,
97                           "acl_module_init: Unable to register control with rootdse!\n");
98                 return ldb_operr(ldb);
99         }
100
101         data = talloc_zero(module, struct acl_private);
102         if (data == NULL) {
103                 return ldb_oom(ldb);
104         }
105
106         data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
107                                         NULL, "acl", "search", true);
108         ldb_module_set_private(module, data);
109
110         mem_ctx = talloc_new(module);
111         if (!mem_ctx) {
112                 return ldb_oom(ldb);
113         }
114
115         ret = dsdb_module_search_dn(module, mem_ctx, &res,
116                                     ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
117                                     attrs,
118                                     DSDB_FLAG_NEXT_MODULE |
119                                     DSDB_FLAG_AS_SYSTEM,
120                                     NULL);
121         if (ret != LDB_SUCCESS) {
122                 goto done;
123         }
124         if (res->count == 0) {
125                 goto done;
126         }
127
128         if (res->count > 1) {
129                 talloc_free(mem_ctx);
130                 return LDB_ERR_CONSTRAINT_VIOLATION;
131         }
132
133         msg = res->msgs[0];
134
135         password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
136         if (!password_attributes) {
137                 goto done;
138         }
139         data->password_attrs = talloc_array(data, const char *,
140                         password_attributes->num_values +
141                         ARRAY_SIZE(secret_attrs) + 1);
142         if (!data->password_attrs) {
143                 talloc_free(mem_ctx);
144                 return ldb_oom(ldb);
145         }
146
147         n = 0;
148         for (i=0; i < password_attributes->num_values; i++) {
149                 data->password_attrs[n] = (const char *)password_attributes->values[i].data;
150                 talloc_steal(data->password_attrs, password_attributes->values[i].data);
151                 n++;
152         }
153
154         for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
155                 bool found = false;
156
157                 for (j=0; j < n; j++) {
158                         if (strcasecmp(data->password_attrs[j], secret_attrs[i]) == 0) {
159                                 found = true;
160                                 break;
161                         }
162                 }
163
164                 if (found) {
165                         continue;
166                 }
167
168                 data->password_attrs[n] = talloc_strdup(data->password_attrs,
169                                                         secret_attrs[i]);
170                 if (data->password_attrs[n] == NULL) {
171                         talloc_free(mem_ctx);
172                         return ldb_oom(ldb);
173                 }
174                 n++;
175         }
176         data->password_attrs[n] = NULL;
177
178 done:
179         talloc_free(mem_ctx);
180         return ldb_next_init(module);
181 }
182
183 static int acl_allowedAttributes(struct ldb_module *module,
184                                  const struct dsdb_schema *schema,
185                                  struct ldb_message *sd_msg,
186                                  struct ldb_message *msg,
187                                  struct acl_context *ac)
188 {
189         struct ldb_message_element *oc_el;
190         struct ldb_context *ldb = ldb_module_get_ctx(module);
191         TALLOC_CTX *mem_ctx;
192         const char **attr_list;
193         int i, ret;
194
195         /* If we don't have a schema yet, we can't do anything... */
196         if (schema == NULL) {
197                 ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
198                 return LDB_ERR_OPERATIONS_ERROR;
199         }
200
201         /* Must remove any existing attribute */
202         if (ac->allowedAttributes) {
203                 ldb_msg_remove_attr(msg, "allowedAttributes");
204         }
205
206         mem_ctx = talloc_new(msg);
207         if (!mem_ctx) {
208                 return ldb_oom(ldb);
209         }
210
211         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
212         attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
213         if (!attr_list) {
214                 ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
215                 talloc_free(mem_ctx);
216                 return LDB_ERR_OPERATIONS_ERROR;
217         }
218         if (ac->allowedAttributes) {
219                 for (i=0; attr_list && attr_list[i]; i++) {
220                         ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
221                 }
222         }
223         if (ac->allowedAttributesEffective) {
224                 struct security_descriptor *sd;
225                 struct dom_sid *sid = NULL;
226                 struct ldb_control *as_system = ldb_request_get_control(ac->req,
227                                                                         LDB_CONTROL_AS_SYSTEM_OID);
228
229                 if (as_system != NULL) {
230                         as_system->critical = 0;
231                 }
232
233                 ldb_msg_remove_attr(msg, "allowedAttributesEffective");
234                 if (ac->am_system || as_system) {
235                         for (i=0; attr_list && attr_list[i]; i++) {
236                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
237                         }
238                         return LDB_SUCCESS;
239                 }
240
241                 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
242
243                 if (ret != LDB_SUCCESS) {
244                         return ret;
245                 }
246
247                 sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
248                 for (i=0; attr_list && attr_list[i]; i++) {
249                         const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
250                                                                                         attr_list[i]);
251                         if (!attr) {
252                                 return ldb_operr(ldb);
253                         }
254                         /* remove constructed attributes */
255                         if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
256                             || attr->systemOnly
257                             || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
258                                 continue;
259                         }
260                         ret = acl_check_access_on_attribute(module,
261                                                             msg,
262                                                             sd,
263                                                             sid,
264                                                             SEC_ADS_WRITE_PROP,
265                                                             attr);
266                         if (ret == LDB_SUCCESS) {
267                                 ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
268                         }
269                 }
270         }
271         return LDB_SUCCESS;
272 }
273
274 static int acl_childClasses(struct ldb_module *module,
275                             const struct dsdb_schema *schema,
276                             struct ldb_message *sd_msg,
277                             struct ldb_message *msg,
278                             const char *attrName)
279 {
280         struct ldb_message_element *oc_el;
281         struct ldb_message_element *allowedClasses;
282         const struct dsdb_class *sclass;
283         unsigned int i, j;
284         int ret;
285
286         /* If we don't have a schema yet, we can't do anything... */
287         if (schema == NULL) {
288                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add childClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
289                 return LDB_ERR_OPERATIONS_ERROR;
290         }
291
292         /* Must remove any existing attribute, or else confusion reins */
293         ldb_msg_remove_attr(msg, attrName);
294         ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
295         if (ret != LDB_SUCCESS) {
296                 return ret;
297         }
298
299         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
300
301         for (i=0; oc_el && i < oc_el->num_values; i++) {
302                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
303                 if (!sclass) {
304                         /* We don't know this class?  what is going on? */
305                         continue;
306                 }
307
308                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
309                         ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
310                 }
311         }
312         if (allowedClasses->num_values > 1) {
313                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
314                 for (i=1 ; i < allowedClasses->num_values; i++) {
315                         struct ldb_val *val1 = &allowedClasses->values[i-1];
316                         struct ldb_val *val2 = &allowedClasses->values[i];
317                         if (data_blob_cmp(val1, val2) == 0) {
318                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
319                                 allowedClasses->num_values--;
320                                 i--;
321                         }
322                 }
323         }
324
325         return LDB_SUCCESS;
326 }
327
328 static int acl_check_access_on_class(struct ldb_module *module,
329                                      const struct dsdb_schema *schema,
330                                      TALLOC_CTX *mem_ctx,
331                                      struct security_descriptor *sd,
332                                      struct security_token *token,
333                                      struct dom_sid *rp_sid,
334                                      uint32_t access_mask,
335                                      const char *class_name)
336 {
337         int ret;
338         NTSTATUS status;
339         uint32_t access_granted;
340         struct object_tree *root = NULL;
341         struct object_tree *new_node = NULL;
342         const struct GUID *guid;
343
344         if (class_name != NULL) {
345                 guid = class_schemaid_guid_by_lDAPDisplayName(schema, class_name);
346                 if (!guid) {
347                         DEBUG(10, ("acl_search: cannot find class %s\n",
348                                    class_name));
349                         goto fail;
350                 }
351                 if (!insert_in_object_tree(mem_ctx,
352                                            guid, access_mask,
353                                            &root, &new_node)) {
354                         DEBUG(10, ("acl_search: cannot add to object tree guid\n"));
355                         goto fail;
356                 }
357         }
358
359         status = sec_access_check_ds(sd, token,
360                                      access_mask,
361                                      &access_granted,
362                                      root,
363                                      rp_sid);
364         if (!NT_STATUS_IS_OK(status)) {
365                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
366         } else {
367                 ret = LDB_SUCCESS;
368         }
369         return ret;
370 fail:
371         return ldb_operr(ldb_module_get_ctx(module));
372 }
373
374 static int acl_childClassesEffective(struct ldb_module *module,
375                                      const struct dsdb_schema *schema,
376                                      struct ldb_message *sd_msg,
377                                      struct ldb_message *msg,
378                                      struct acl_context *ac)
379 {
380         struct ldb_message_element *oc_el;
381         struct ldb_message_element *allowedClasses = NULL;
382         const struct dsdb_class *sclass;
383         struct security_descriptor *sd;
384         struct ldb_control *as_system = ldb_request_get_control(ac->req,
385                                                                 LDB_CONTROL_AS_SYSTEM_OID);
386         struct dom_sid *sid = NULL;
387         unsigned int i, j;
388         int ret;
389
390         if (as_system != NULL) {
391                 as_system->critical = 0;
392         }
393
394         if (ac->am_system || as_system) {
395                 return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
396         }
397
398         /* If we don't have a schema yet, we can't do anything... */
399         if (schema == NULL) {
400                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add allowedChildClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
401                 return LDB_ERR_OPERATIONS_ERROR;
402         }
403
404         /* Must remove any existing attribute, or else confusion reins */
405         ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
406
407         oc_el = ldb_msg_find_element(sd_msg, "objectClass");
408         ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
409         if (ret != LDB_SUCCESS) {
410                 return ret;
411         }
412
413         sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
414         for (i=0; oc_el && i < oc_el->num_values; i++) {
415                 sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
416                 if (!sclass) {
417                         /* We don't know this class?  what is going on? */
418                         continue;
419                 }
420
421                 for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
422                         ret = acl_check_access_on_class(module,
423                                                         schema,
424                                                         msg,
425                                                         sd,
426                                                         acl_user_token(module),
427                                                         sid,
428                                                         SEC_ADS_CREATE_CHILD,
429                                                         sclass->possibleInferiors[j]);
430                         if (ret == LDB_SUCCESS) {
431                                 ldb_msg_add_string(msg, "allowedChildClassesEffective",
432                                                    sclass->possibleInferiors[j]);
433                         }
434                 }
435         }
436         allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
437         if (!allowedClasses) {
438                 return LDB_SUCCESS;
439         }
440
441         if (allowedClasses->num_values > 1) {
442                 TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
443                 for (i=1 ; i < allowedClasses->num_values; i++) {
444                         struct ldb_val *val1 = &allowedClasses->values[i-1];
445                         struct ldb_val *val2 = &allowedClasses->values[i];
446                         if (data_blob_cmp(val1, val2) == 0) {
447                                 memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
448                                 allowedClasses->num_values--;
449                                 i--;
450                         }
451                 }
452         }
453         return LDB_SUCCESS;
454 }
455
456 static int acl_sDRightsEffective(struct ldb_module *module,
457                                  struct ldb_message *sd_msg,
458                                  struct ldb_message *msg,
459                                  struct acl_context *ac)
460 {
461         struct ldb_message_element *rightsEffective;
462         int ret;
463         struct security_descriptor *sd;
464         struct ldb_control *as_system = ldb_request_get_control(ac->req,
465                                                                 LDB_CONTROL_AS_SYSTEM_OID);
466         struct dom_sid *sid = NULL;
467         uint32_t flags = 0;
468
469         if (as_system != NULL) {
470                 as_system->critical = 0;
471         }
472
473         /* Must remove any existing attribute, or else confusion reins */
474         ldb_msg_remove_attr(msg, "sDRightsEffective");
475         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
476         if (ret != LDB_SUCCESS) {
477                 return ret;
478         }
479         if (ac->am_system || as_system) {
480                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
481         }
482         else {
483                 /* Get the security descriptor from the message */
484                 ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
485                 if (ret != LDB_SUCCESS) {
486                         return ret;
487                 }
488                 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
489                 ret = acl_check_access_on_attribute(module,
490                                                     msg,
491                                                     sd,
492                                                     sid,
493                                                     SEC_STD_WRITE_OWNER,
494                                                     NULL);
495                 if (ret == LDB_SUCCESS) {
496                         flags |= SECINFO_OWNER | SECINFO_GROUP;
497                 }
498                 ret = acl_check_access_on_attribute(module,
499                                                     msg,
500                                                     sd,
501                                                     sid,
502                                                     SEC_STD_WRITE_DAC,
503                                                     NULL);
504                 if (ret == LDB_SUCCESS) {
505                         flags |= SECINFO_DACL;
506                 }
507                 ret = acl_check_access_on_attribute(module,
508                                                     msg,
509                                                     sd,
510                                                     sid,
511                                                     SEC_FLAG_SYSTEM_SECURITY,
512                                                     NULL);
513                 if (ret == LDB_SUCCESS) {
514                         flags |= SECINFO_SACL;
515                 }
516         }
517         return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
518                                   "sDRightsEffective", flags);
519 }
520
521 static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
522                                   struct ldb_context *ldb,
523                                   const char *spn_value,
524                                   uint32_t userAccountControl,
525                                   const char *samAccountName,
526                                   const char *dnsHostName,
527                                   const char *netbios_name,
528                                   const char *ntds_guid)
529 {
530         int ret;
531         krb5_context krb_ctx;
532         krb5_error_code kerr;
533         krb5_principal principal;
534         char *instanceName;
535         char *serviceType;
536         char *serviceName;
537         const char *forest_name = samdb_forest_name(ldb, mem_ctx);
538         const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
539         struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
540                                                           struct loadparm_context);
541         bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
542                 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
543
544         if (strcasecmp_m(spn_value, samAccountName) == 0) {
545                 /* MacOS X sets this value, and setting an SPN of your
546                  * own samAccountName is both pointless and safe */
547                 return LDB_SUCCESS;
548         }
549
550         kerr = smb_krb5_init_context_basic(mem_ctx,
551                                            lp_ctx,
552                                            &krb_ctx);
553         if (kerr != 0) {
554                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
555                                  "Could not initialize kerberos context.");
556         }
557
558         ret = krb5_parse_name(krb_ctx, spn_value, &principal);
559         if (ret) {
560                 krb5_free_context(krb_ctx);
561                 return LDB_ERR_CONSTRAINT_VIOLATION;
562         }
563
564         if (principal->name.name_string.len < 2) {
565                 goto fail;
566         }
567
568         instanceName = principal->name.name_string.val[1];
569         serviceType = principal->name.name_string.val[0];
570         if (principal->name.name_string.len == 3) {
571                 serviceName = principal->name.name_string.val[2];
572         } else {
573                 serviceName = NULL;
574         }
575
576         if (serviceName) {
577                 if (!is_dc) {
578                         goto fail;
579                 }
580                 if (strcasecmp(serviceType, "ldap") == 0) {
581                         if (strcasecmp(serviceName, netbios_name) != 0 &&
582                             strcasecmp(serviceName, forest_name) != 0) {
583                                 goto fail;
584                         }
585
586                 } else if (strcasecmp(serviceType, "gc") == 0) {
587                         if (strcasecmp(serviceName, forest_name) != 0) {
588                                 goto fail;
589                         }
590                 } else {
591                         if (strcasecmp(serviceName, base_domain) != 0 &&
592                             strcasecmp(serviceName, netbios_name) != 0) {
593                                 goto fail;
594                         }
595                 }
596         }
597         /* instanceName can be samAccountName without $ or dnsHostName
598          * or "ntds_guid._msdcs.forest_domain for DC objects */
599         if (strlen(instanceName) == (strlen(samAccountName) - 1)
600             && strncasecmp(instanceName, samAccountName, strlen(samAccountName) - 1) == 0) {
601                 goto success;
602         } else if (dnsHostName != NULL && strcasecmp(instanceName, dnsHostName) == 0) {
603                 goto success;
604         } else if (is_dc) {
605                 const char *guid_str;
606                 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
607                                            ntds_guid,
608                                            forest_name);
609                 if (strcasecmp(instanceName, guid_str) == 0) {
610                         goto success;
611                 }
612         }
613
614 fail:
615         krb5_free_principal(krb_ctx, principal);
616         krb5_free_context(krb_ctx);
617         return LDB_ERR_CONSTRAINT_VIOLATION;
618
619 success:
620         krb5_free_principal(krb_ctx, principal);
621         krb5_free_context(krb_ctx);
622         return LDB_SUCCESS;
623 }
624
625 static int acl_check_spn(TALLOC_CTX *mem_ctx,
626                          struct ldb_module *module,
627                          struct ldb_request *req,
628                          struct security_descriptor *sd,
629                          struct dom_sid *sid,
630                          const struct GUID *oc_guid,
631                          const struct dsdb_attribute *attr)
632 {
633         int ret;
634         unsigned int i;
635         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
636         struct ldb_context *ldb = ldb_module_get_ctx(module);
637         struct ldb_result *acl_res;
638         struct ldb_result *netbios_res;
639         struct ldb_message_element *el;
640         struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
641         uint32_t userAccountControl;
642         const char *samAccountName;
643         const char *dnsHostName;
644         const char *netbios_name;
645         struct GUID ntds;
646         char *ntds_guid = NULL;
647
648         static const char *acl_attrs[] = {
649                 "samAccountName",
650                 "dnsHostName",
651                 "userAccountControl",
652                 NULL
653         };
654         static const char *netbios_attrs[] = {
655                 "nETBIOSName",
656                 NULL
657         };
658
659         /* if we have wp, we can do whatever we like */
660         if (acl_check_access_on_attribute(module,
661                                           tmp_ctx,
662                                           sd,
663                                           sid,
664                                           SEC_ADS_WRITE_PROP,
665                                           attr) == LDB_SUCCESS) {
666                 talloc_free(tmp_ctx);
667                 return LDB_SUCCESS;
668         }
669
670         ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
671                                        GUID_DRS_VALIDATE_SPN,
672                                        SEC_ADS_SELF_WRITE,
673                                        sid);
674
675         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
676                 dsdb_acl_debug(sd, acl_user_token(module),
677                                req->op.mod.message->dn,
678                                true,
679                                10);
680                 talloc_free(tmp_ctx);
681                 return ret;
682         }
683
684         ret = dsdb_module_search_dn(module, tmp_ctx,
685                                     &acl_res, req->op.mod.message->dn,
686                                     acl_attrs,
687                                     DSDB_FLAG_NEXT_MODULE |
688                                     DSDB_FLAG_AS_SYSTEM |
689                                     DSDB_SEARCH_SHOW_RECYCLED,
690                                     req);
691         if (ret != LDB_SUCCESS) {
692                 talloc_free(tmp_ctx);
693                 return ret;
694         }
695
696         userAccountControl = ldb_msg_find_attr_as_uint(acl_res->msgs[0], "userAccountControl", 0);
697         dnsHostName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "dnsHostName", NULL);
698         samAccountName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "samAccountName", NULL);
699
700         ret = dsdb_module_search(module, tmp_ctx,
701                                  &netbios_res, partitions_dn,
702                                  LDB_SCOPE_ONELEVEL,
703                                  netbios_attrs,
704                                  DSDB_FLAG_NEXT_MODULE |
705                                  DSDB_FLAG_AS_SYSTEM,
706                                  req,
707                                  "(ncName=%s)",
708                                  ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
709
710         netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
711
712         el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName");
713         if (!el) {
714                 talloc_free(tmp_ctx);
715                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
716                                          "Error finding element for servicePrincipalName.");
717         }
718
719         /* NTDSDSA objectGuid of object we are checking SPN for */
720         if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
721                 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
722                                                              req->op.mod.message->dn, &ntds, req);
723                 if (ret != LDB_SUCCESS) {
724                         ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
725                                                ldb_dn_get_linearized(req->op.mod.message->dn),
726                                                ldb_strerror(ret));
727                         talloc_free(tmp_ctx);
728                         return LDB_ERR_OPERATIONS_ERROR;
729                 }
730                 ntds_guid = GUID_string(tmp_ctx, &ntds);
731         }
732
733         for (i=0; i < el->num_values; i++) {
734                 ret = acl_validate_spn_value(tmp_ctx,
735                                              ldb,
736                                              (char *)el->values[i].data,
737                                              userAccountControl,
738                                              samAccountName,
739                                              dnsHostName,
740                                              netbios_name,
741                                              ntds_guid);
742                 if (ret != LDB_SUCCESS) {
743                         talloc_free(tmp_ctx);
744                         return ret;
745                 }
746         }
747         talloc_free(tmp_ctx);
748         return LDB_SUCCESS;
749 }
750
751 static int acl_add(struct ldb_module *module, struct ldb_request *req)
752 {
753         int ret;
754         struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.add.message->dn);
755         struct ldb_context *ldb;
756         const struct dsdb_schema *schema;
757         struct ldb_message_element *oc_el;
758         const struct GUID *guid;
759         struct ldb_dn *nc_root;
760         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
761
762         if (as_system != NULL) {
763                 as_system->critical = 0;
764         }
765
766         if (dsdb_module_am_system(module) || as_system) {
767                 return ldb_next_request(module, req);
768         }
769         if (ldb_dn_is_special(req->op.add.message->dn)) {
770                 return ldb_next_request(module, req);
771         }
772
773         ldb = ldb_module_get_ctx(module);
774
775         /* Creating an NC. There is probably something we should do here,
776          * but we will establish that later */
777
778         ret = dsdb_find_nc_root(ldb, req, req->op.add.message->dn, &nc_root);
779         if (ret != LDB_SUCCESS) {
780                 return ret;
781         }
782         if (ldb_dn_compare(nc_root, req->op.add.message->dn) == 0) {
783                 talloc_free(nc_root);
784                 return ldb_next_request(module, req);
785         }
786         talloc_free(nc_root);
787
788         schema = dsdb_get_schema(ldb, req);
789         if (!schema) {
790                 return ldb_operr(ldb);
791         }
792
793         oc_el = ldb_msg_find_element(req->op.add.message, "objectClass");
794         if (!oc_el || oc_el->num_values == 0) {
795                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
796                                        "acl: unable to find objectClass on %s\n",
797                                        ldb_dn_get_linearized(req->op.add.message->dn));
798                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
799         }
800
801         guid = class_schemaid_guid_by_lDAPDisplayName(schema,
802                                                       (char *)oc_el->values[oc_el->num_values-1].data);
803         ret = dsdb_module_check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, guid, req);
804         if (ret != LDB_SUCCESS) {
805                 return ret;
806         }
807         return ldb_next_request(module, req);
808 }
809
810 /* ckecks if modifications are allowed on "Member" attribute */
811 static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
812                                      struct ldb_module *module,
813                                      struct ldb_request *req,
814                                      struct security_descriptor *sd,
815                                      struct dom_sid *sid,
816                                      const struct GUID *oc_guid,
817                                      const struct dsdb_attribute *attr)
818 {
819         int ret;
820         unsigned int i;
821         struct ldb_context *ldb = ldb_module_get_ctx(module);
822         struct ldb_dn *user_dn;
823         struct ldb_message_element *member_el;
824         /* if we have wp, we can do whatever we like */
825         if (acl_check_access_on_attribute(module,
826                                           mem_ctx,
827                                           sd,
828                                           sid,
829                                           SEC_ADS_WRITE_PROP,
830                                           attr) == LDB_SUCCESS) {
831                 return LDB_SUCCESS;
832         }
833         /* if we are adding/deleting ourselves, check for self membership */
834         ret = dsdb_find_dn_by_sid(ldb, mem_ctx, 
835                                   &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], 
836                                   &user_dn);
837         if (ret != LDB_SUCCESS) {
838                 return ret;
839         }
840         member_el = ldb_msg_find_element(req->op.mod.message, "member");
841         if (!member_el) {
842                 return ldb_operr(ldb);
843         }
844         /* user can only remove oneself */
845         if (member_el->num_values == 0) {
846                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
847         }
848         for (i = 0; i < member_el->num_values; i++) {
849                 if (strcasecmp((const char *)member_el->values[i].data,
850                                ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
851                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
852                 }
853         }
854         ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
855                                        GUID_DRS_SELF_MEMBERSHIP,
856                                        SEC_ADS_SELF_WRITE,
857                                        sid);
858         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
859                 dsdb_acl_debug(sd, acl_user_token(module),
860                                req->op.mod.message->dn,
861                                true,
862                                10);
863         }
864         return ret;
865 }
866
867 static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
868                                      struct ldb_module *module,
869                                      struct ldb_request *req,
870                                      struct security_descriptor *sd,
871                                      struct dom_sid *sid,
872                                      const struct GUID *oc_guid,
873                                      bool userPassword)
874 {
875         int ret = LDB_SUCCESS;
876         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
877         struct ldb_message_element *el;
878         struct ldb_message *msg;
879         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
880                                         "unicodePwd", "dBCSPwd", NULL }, **l;
881         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
882
883         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
884         if (msg == NULL) {
885                 return ldb_module_oom(module);
886         }
887         for (l = passwordAttrs; *l != NULL; l++) {
888                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
889                         continue;
890                 }
891
892                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
893                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
894                                 ++del_attr_cnt;
895                         }
896                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
897                                 ++add_attr_cnt;
898                         }
899                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
900                                 ++rep_attr_cnt;
901                         }
902                         ldb_msg_remove_element(msg, el);
903                 }
904         }
905
906         /* single deletes will be handled by the "password_hash" LDB module
907          * later in the stack, so we let it though here */
908         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
909                 talloc_free(tmp_ctx);
910                 return LDB_SUCCESS;
911         }
912
913         if (ldb_request_get_control(req,
914                                     DSDB_CONTROL_PASSWORD_CHANGE_OID) != NULL) {
915                 /* The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
916                  * have a user password change and not a set as the message
917                  * looks like. In it's value blob it contains the NT and/or LM
918                  * hash of the old password specified by the user.
919                  * This control is used by the SAMR and "kpasswd" password
920                  * change mechanisms. */
921                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
922                                                GUID_DRS_USER_CHANGE_PASSWORD,
923                                                SEC_ADS_CONTROL_ACCESS,
924                                                sid);
925         }
926         else if (rep_attr_cnt > 0 || (add_attr_cnt != del_attr_cnt)) {
927                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
928                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
929                                                SEC_ADS_CONTROL_ACCESS,
930                                                sid);
931         }
932         else if (add_attr_cnt == 1 && del_attr_cnt == 1) {
933                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
934                                                GUID_DRS_USER_CHANGE_PASSWORD,
935                                                SEC_ADS_CONTROL_ACCESS,
936                                                sid);
937                 /* Very strange, but we get constraint violation in this case */
938                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
939                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
940                 }
941         }
942         if (ret != LDB_SUCCESS) {
943                 dsdb_acl_debug(sd, acl_user_token(module),
944                                req->op.mod.message->dn,
945                                true,
946                                10);
947         }
948         talloc_free(tmp_ctx);
949         return ret;
950 }
951
952 static const struct GUID *get_oc_guid_from_message(const struct dsdb_schema *schema,
953                                                    struct ldb_message *msg)
954 {
955         struct ldb_message_element *oc_el;
956         const struct dsdb_class *object_class;
957
958         oc_el = ldb_msg_find_element(msg, "objectClass");
959         if (!oc_el) {
960                 return NULL;
961         }
962
963         object_class = dsdb_get_last_structural_class(schema, oc_el);
964         if (object_class == NULL) {
965                 return NULL;
966         }
967
968         return &object_class->schemaIDGUID;
969 }
970
971
972 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
973 {
974         int ret;
975         struct ldb_context *ldb = ldb_module_get_ctx(module);
976         const struct dsdb_schema *schema;
977         unsigned int i;
978         const struct GUID *guid;
979         uint32_t access_granted;
980         struct object_tree *root = NULL;
981         struct object_tree *new_node = NULL;
982         NTSTATUS status;
983         struct ldb_result *acl_res;
984         struct security_descriptor *sd;
985         struct dom_sid *sid = NULL;
986         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
987         bool userPassword = dsdb_user_password_support(module, req, req);
988         TALLOC_CTX *tmp_ctx = talloc_new(req);
989         static const char *acl_attrs[] = {
990                 "nTSecurityDescriptor",
991                 "objectClass",
992                 "objectSid",
993                 NULL
994         };
995
996         if (as_system != NULL) {
997                 as_system->critical = 0;
998         }
999
1000         /* Don't print this debug statement if elements[0].name is going to be NULL */
1001         if(req->op.mod.message->num_elements > 0)
1002         {
1003                 DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name));
1004         }
1005         if (dsdb_module_am_system(module) || as_system) {
1006                 return ldb_next_request(module, req);
1007         }
1008         if (ldb_dn_is_special(req->op.mod.message->dn)) {
1009                 return ldb_next_request(module, req);
1010         }
1011         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, req->op.mod.message->dn,
1012                                     acl_attrs,
1013                                     DSDB_FLAG_NEXT_MODULE |
1014                                     DSDB_FLAG_AS_SYSTEM |
1015                                     DSDB_SEARCH_SHOW_RECYCLED,
1016                                     req);
1017
1018         if (ret != LDB_SUCCESS) {
1019                 goto fail;
1020         }
1021
1022         schema = dsdb_get_schema(ldb, tmp_ctx);
1023         if (!schema) {
1024                 ret = LDB_ERR_OPERATIONS_ERROR;
1025                 goto fail;
1026         }
1027
1028         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1029         if (ret != LDB_SUCCESS) {
1030                 talloc_free(tmp_ctx);
1031                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1032                                  "acl_modify: Error retrieving security descriptor.");
1033         }
1034         /* Theoretically we pass the check if the object has no sd */
1035         if (!sd) {
1036                 goto success;
1037         }
1038
1039         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1040         if (!guid) {
1041                 talloc_free(tmp_ctx);
1042                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1043                                  "acl_modify: Error retrieving object class GUID.");
1044         }
1045         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1046         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1047                                    &root, &new_node)) {
1048                 talloc_free(tmp_ctx);
1049                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1050                                  "acl_modify: Error adding new node in object tree.");
1051         }
1052         for (i=0; i < req->op.mod.message->num_elements; i++){
1053                 const struct dsdb_attribute *attr;
1054                 attr = dsdb_attribute_by_lDAPDisplayName(schema,
1055                                                          req->op.mod.message->elements[i].name);
1056
1057                 if (ldb_attr_cmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) {
1058                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1059                         uint32_t access_mask = 0;
1060
1061                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1062                                 access_mask |= SEC_STD_WRITE_OWNER;
1063                         }
1064                         if (sd_flags & SECINFO_DACL) {
1065                                 access_mask |= SEC_STD_WRITE_DAC;
1066                         }
1067                         if (sd_flags & SECINFO_SACL) {
1068                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1069                         }
1070
1071                         status = sec_access_check_ds(sd, acl_user_token(module),
1072                                              access_mask,
1073                                              &access_granted,
1074                                              NULL,
1075                                              sid);
1076
1077                         if (!NT_STATUS_IS_OK(status)) {
1078                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1079                                                        "Object %s has no write dacl access\n",
1080                                                        ldb_dn_get_linearized(req->op.mod.message->dn));
1081                                 dsdb_acl_debug(sd,
1082                                                acl_user_token(module),
1083                                                req->op.mod.message->dn,
1084                                                true,
1085                                                10);
1086                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1087                                 goto fail;
1088                         }
1089                 }
1090                 else if (ldb_attr_cmp("member", req->op.mod.message->elements[i].name) == 0) {
1091                         ret = acl_check_self_membership(tmp_ctx,
1092                                                         module,
1093                                                         req,
1094                                                         sd,
1095                                                         sid,
1096                                                         guid,
1097                                                         attr);
1098                         if (ret != LDB_SUCCESS) {
1099                                 goto fail;
1100                         }
1101                 }
1102                 else if (ldb_attr_cmp("dBCSPwd", req->op.mod.message->elements[i].name) == 0) {
1103                         /* this one is not affected by any rights, we should let it through
1104                            so that passwords_hash returns the correct error */
1105                         continue;
1106                 }
1107                 else if (ldb_attr_cmp("unicodePwd", req->op.mod.message->elements[i].name) == 0 ||
1108                          (userPassword && ldb_attr_cmp("userPassword", req->op.mod.message->elements[i].name) == 0) ||
1109                          ldb_attr_cmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) {
1110                         ret = acl_check_password_rights(tmp_ctx,
1111                                                         module,
1112                                                         req,
1113                                                         sd,
1114                                                         sid,
1115                                                         guid,
1116                                                         userPassword);
1117                         if (ret != LDB_SUCCESS) {
1118                                 goto fail;
1119                         }
1120                 } else if (ldb_attr_cmp("servicePrincipalName", req->op.mod.message->elements[i].name) == 0) {
1121                         ret = acl_check_spn(tmp_ctx,
1122                                             module,
1123                                             req,
1124                                             sd,
1125                                             sid,
1126                                             guid,
1127                                             attr);
1128                         if (ret != LDB_SUCCESS) {
1129                                 goto fail;
1130                         }
1131                 } else {
1132
1133                 /* This basic attribute existence check with the right errorcode
1134                  * is needed since this module is the first one which requests
1135                  * schema attribute information.
1136                  * The complete attribute checking is done in the
1137                  * "objectclass_attrs" module behind this one.
1138                  */
1139                         if (!attr) {
1140                                 ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' on entry '%s' was not found in the schema!",
1141                                                        req->op.mod.message->elements[i].name,
1142                                                ldb_dn_get_linearized(req->op.mod.message->dn));
1143                                 ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
1144                                 goto fail;
1145                         }
1146                         if (!insert_in_object_tree(tmp_ctx,
1147                                                    &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
1148                                                    &new_node, &new_node)) {
1149                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1150                                                        "acl_modify: cannot add to object tree securityGUID\n");
1151                                 ret = LDB_ERR_OPERATIONS_ERROR;
1152                                 goto fail;
1153                         }
1154
1155                         if (!insert_in_object_tree(tmp_ctx,
1156                                                    &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) {
1157                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1158                                                        "acl_modify: cannot add to object tree attributeGUID\n");
1159                                 ret = LDB_ERR_OPERATIONS_ERROR;
1160                                 goto fail;
1161                         }
1162                 }
1163         }
1164
1165         if (root->num_of_children > 0) {
1166                 status = sec_access_check_ds(sd, acl_user_token(module),
1167                                              SEC_ADS_WRITE_PROP,
1168                                              &access_granted,
1169                                              root,
1170                                              sid);
1171
1172                 if (!NT_STATUS_IS_OK(status)) {
1173                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
1174                                                "Object %s has no write property access\n",
1175                                                ldb_dn_get_linearized(req->op.mod.message->dn));
1176                         dsdb_acl_debug(sd,
1177                                        acl_user_token(module),
1178                                        req->op.mod.message->dn,
1179                                        true,
1180                                        10);
1181                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1182                         goto fail;
1183                 }
1184         }
1185
1186 success:
1187         talloc_free(tmp_ctx);
1188         return ldb_next_request(module, req);
1189 fail:
1190         talloc_free(tmp_ctx);
1191         return ret;
1192 }
1193
1194 /* similar to the modify for the time being.
1195  * We need to consider the special delete tree case, though - TODO */
1196 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
1197 {
1198         int ret;
1199         struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn);
1200         struct ldb_context *ldb;
1201         struct ldb_dn *nc_root;
1202         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1203
1204         if (as_system != NULL) {
1205                 as_system->critical = 0;
1206         }
1207
1208         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
1209         if (dsdb_module_am_system(module) || as_system) {
1210                 return ldb_next_request(module, req);
1211         }
1212         if (ldb_dn_is_special(req->op.del.dn)) {
1213                 return ldb_next_request(module, req);
1214         }
1215
1216         ldb = ldb_module_get_ctx(module);
1217
1218         /* Make sure we aren't deleting a NC */
1219
1220         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
1221         if (ret != LDB_SUCCESS) {
1222                 return ret;
1223         }
1224         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
1225                 talloc_free(nc_root);
1226                 DEBUG(10,("acl:deleting a NC\n"));
1227                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1228                 return ldb_module_done(req, NULL, NULL,
1229                                        LDB_ERR_UNWILLING_TO_PERFORM);
1230         }
1231         talloc_free(nc_root);
1232
1233         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
1234                 ret = dsdb_module_check_access_on_dn(module, req,
1235                                                      req->op.del.dn,
1236                                                      SEC_ADS_DELETE_TREE, NULL,
1237                                                      req);
1238                 if (ret != LDB_SUCCESS) {
1239                         return ret;
1240                 }
1241
1242                 return ldb_next_request(module, req);
1243         }
1244
1245         /* First check if we have delete object right */
1246         ret = dsdb_module_check_access_on_dn(module, req, req->op.del.dn,
1247                                              SEC_STD_DELETE, NULL, req);
1248         if (ret == LDB_SUCCESS) {
1249                 return ldb_next_request(module, req);
1250         }
1251
1252         /* Nope, we don't have delete object. Lets check if we have delete
1253          * child on the parent */
1254         ret = dsdb_module_check_access_on_dn(module, req, parent,
1255                                              SEC_ADS_DELETE_CHILD, NULL, req);
1256         if (ret != LDB_SUCCESS) {
1257                 return ret;
1258         }
1259
1260         return ldb_next_request(module, req);
1261 }
1262
1263 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
1264 {
1265         int ret;
1266         struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn);
1267         struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn);
1268         const struct dsdb_schema *schema;
1269         struct ldb_context *ldb;
1270         struct security_descriptor *sd = NULL;
1271         struct dom_sid *sid = NULL;
1272         struct ldb_result *acl_res;
1273         const struct GUID *guid;
1274         struct ldb_dn *nc_root;
1275         struct object_tree *root = NULL;
1276         struct object_tree *new_node = NULL;
1277         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1278         TALLOC_CTX *tmp_ctx = talloc_new(req);
1279         NTSTATUS status;
1280         uint32_t access_granted;
1281         const char *rdn_name;
1282         static const char *acl_attrs[] = {
1283                 "nTSecurityDescriptor",
1284                 "objectClass",
1285                 "objectSid",
1286                 NULL
1287         };
1288
1289         if (as_system != NULL) {
1290                 as_system->critical = 0;
1291         }
1292
1293         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
1294         if (dsdb_module_am_system(module) || as_system) {
1295                 return ldb_next_request(module, req);
1296         }
1297         if (ldb_dn_is_special(req->op.rename.olddn)) {
1298                 return ldb_next_request(module, req);
1299         }
1300
1301         ldb = ldb_module_get_ctx(module);
1302
1303         /* Make sure we aren't renaming/moving a NC */
1304
1305         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
1306         if (ret != LDB_SUCCESS) {
1307                 return ret;
1308         }
1309         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
1310                 talloc_free(nc_root);
1311                 DEBUG(10,("acl:renaming/moving a NC\n"));
1312                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1313                 return ldb_module_done(req, NULL, NULL,
1314                                        LDB_ERR_UNWILLING_TO_PERFORM);
1315         }
1316         talloc_free(nc_root);
1317
1318         /* Look for the parent */
1319
1320         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
1321                                     req->op.rename.olddn, acl_attrs,
1322                                     DSDB_FLAG_NEXT_MODULE |
1323                                     DSDB_FLAG_AS_SYSTEM |
1324                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1325         /* we sould be able to find the parent */
1326         if (ret != LDB_SUCCESS) {
1327                 DEBUG(10,("acl: failed to find object %s\n",
1328                           ldb_dn_get_linearized(req->op.rename.olddn)));
1329                 talloc_free(tmp_ctx);
1330                 return ret;
1331         }
1332
1333         schema = dsdb_get_schema(ldb, acl_res);
1334         if (!schema) {
1335                 talloc_free(tmp_ctx);
1336                 return ldb_operr(ldb);
1337         }
1338
1339         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1340         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1341                                    &root, &new_node)) {
1342                 talloc_free(tmp_ctx);
1343                 return ldb_operr(ldb);
1344         };
1345
1346         guid = attribute_schemaid_guid_by_lDAPDisplayName(schema,
1347                                                           "name");
1348         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1349                                    &new_node, &new_node)) {
1350                 talloc_free(tmp_ctx);
1351                 return ldb_operr(ldb);
1352         };
1353
1354         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
1355         if (rdn_name == NULL) {
1356                 talloc_free(tmp_ctx);
1357                 return ldb_operr(ldb);
1358         }
1359         guid = attribute_schemaid_guid_by_lDAPDisplayName(schema,
1360                                                           rdn_name);
1361         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1362                                    &new_node, &new_node)) {
1363                 talloc_free(tmp_ctx);
1364                 return ldb_operr(ldb);
1365         };
1366
1367         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1368
1369         if (ret != LDB_SUCCESS) {
1370                 talloc_free(tmp_ctx);
1371                 return ldb_operr(ldb);
1372         }
1373         /* Theoretically we pass the check if the object has no sd */
1374         if (!sd) {
1375                 talloc_free(tmp_ctx);
1376                 return LDB_SUCCESS;
1377         }
1378         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1379         status = sec_access_check_ds(sd, acl_user_token(module),
1380                                      SEC_ADS_WRITE_PROP,
1381                                      &access_granted,
1382                                      root,
1383                                      sid);
1384
1385         if (!NT_STATUS_IS_OK(status)) {
1386                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1387                                        "Object %s has no wp on name\n",
1388                                        ldb_dn_get_linearized(req->op.rename.olddn));
1389                 dsdb_acl_debug(sd,
1390                           acl_user_token(module),
1391                           req->op.rename.olddn,
1392                           true,
1393                           10);
1394                 talloc_free(tmp_ctx);
1395                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1396         }
1397
1398         if (ldb_dn_compare(oldparent, newparent) == 0) {
1399                 /* regular rename, not move, nothing more to do */
1400                 talloc_free(tmp_ctx);
1401                 return ldb_next_request(module, req);
1402         }
1403
1404         /* new parent should have create child */
1405         root = NULL;
1406         new_node = NULL;
1407         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1408         if (!guid) {
1409                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1410                                        "acl:renamed object has no object class\n");
1411                 talloc_free(tmp_ctx);
1412                 return ldb_module_done(req, NULL, NULL,  LDB_ERR_OPERATIONS_ERROR);
1413         }
1414
1415         ret = dsdb_module_check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, guid, req);
1416         if (ret != LDB_SUCCESS) {
1417                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1418                                        "acl:access_denied renaming %s",
1419                                        ldb_dn_get_linearized(req->op.rename.olddn));
1420                 talloc_free(tmp_ctx);
1421                 return ret;
1422         }
1423         /* do we have delete object on the object? */
1424
1425         status = sec_access_check_ds(sd, acl_user_token(module),
1426                                      SEC_STD_DELETE,
1427                                      &access_granted,
1428                                      NULL,
1429                                      sid);
1430
1431         if (NT_STATUS_IS_OK(status)) {
1432                 talloc_free(tmp_ctx);
1433                 return ldb_next_request(module, req);
1434         }
1435         /* what about delete child on the current parent */
1436         ret = dsdb_module_check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL, req);
1437         if (ret != LDB_SUCCESS) {
1438                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1439                                        "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
1440                 talloc_free(tmp_ctx);
1441                 return ldb_module_done(req, NULL, NULL, ret);
1442         }
1443
1444         talloc_free(tmp_ctx);
1445
1446         return ldb_next_request(module, req);
1447 }
1448
1449 static int acl_search_update_confidential_attrs(struct acl_context *ac,
1450                                                 struct acl_private *data)
1451 {
1452         struct dsdb_attribute *a;
1453         uint32_t n = 0;
1454
1455         if (data->acl_search) {
1456                 /*
1457                  * If acl:search is activated, the acl_read module
1458                  * protects confidential attributes.
1459                  */
1460                 return LDB_SUCCESS;
1461         }
1462
1463         if ((ac->schema == data->cached_schema_ptr) &&
1464             (ac->schema->loaded_usn == data->cached_schema_loaded_usn) &&
1465             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
1466         {
1467                 return LDB_SUCCESS;
1468         }
1469
1470         data->cached_schema_ptr = NULL;
1471         data->cached_schema_loaded_usn = 0;
1472         data->cached_schema_metadata_usn = 0;
1473         TALLOC_FREE(data->confidential_attrs);
1474
1475         if (ac->schema == NULL) {
1476                 return LDB_SUCCESS;
1477         }
1478
1479         for (a = ac->schema->attributes; a; a = a->next) {
1480                 const char **attrs = data->confidential_attrs;
1481
1482                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
1483                         continue;
1484                 }
1485
1486                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
1487                 if (attrs == NULL) {
1488                         TALLOC_FREE(data->confidential_attrs);
1489                         return ldb_module_oom(ac->module);
1490                 }
1491
1492                 attrs[n] = a->lDAPDisplayName;
1493                 attrs[n+1] = NULL;
1494                 n++;
1495
1496                 data->confidential_attrs = attrs;
1497         }
1498
1499         data->cached_schema_ptr = ac->schema;
1500         data->cached_schema_loaded_usn = ac->schema->loaded_usn;
1501         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
1502
1503         return LDB_SUCCESS;
1504 }
1505
1506 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1507 {
1508         struct acl_context *ac;
1509         struct acl_private *data;
1510         struct ldb_result *acl_res;
1511         static const char *acl_attrs[] = {
1512                 "objectClass",
1513                 "nTSecurityDescriptor",
1514                 "objectSid",
1515                 NULL
1516         };
1517         int ret;
1518         unsigned int i;
1519
1520         ac = talloc_get_type(req->context, struct acl_context);
1521         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
1522         if (!ares) {
1523                 return ldb_module_done(ac->req, NULL, NULL,
1524                                        LDB_ERR_OPERATIONS_ERROR);
1525         }
1526         if (ares->error != LDB_SUCCESS) {
1527                 return ldb_module_done(ac->req, ares->controls,
1528                                        ares->response, ares->error);
1529         }
1530
1531         switch (ares->type) {
1532         case LDB_REPLY_ENTRY:
1533                 if (ac->constructed_attrs) {
1534                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn, 
1535                                                     acl_attrs,
1536                                                     DSDB_FLAG_NEXT_MODULE |
1537                                                     DSDB_FLAG_AS_SYSTEM |
1538                                                     DSDB_SEARCH_SHOW_RECYCLED,
1539                                                     req);
1540                         if (ret != LDB_SUCCESS) {
1541                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1542                         }
1543                 }
1544
1545                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
1546                         ret = acl_allowedAttributes(ac->module, ac->schema,
1547                                                     acl_res->msgs[0],
1548                                                     ares->message, ac);
1549                         if (ret != LDB_SUCCESS) {
1550                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1551                         }
1552                 }
1553
1554                 if (ac->allowedChildClasses) {
1555                         ret = acl_childClasses(ac->module, ac->schema,
1556                                                acl_res->msgs[0],
1557                                                ares->message,
1558                                                "allowedChildClasses");
1559                         if (ret != LDB_SUCCESS) {
1560                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1561                         }
1562                 }
1563
1564                 if (ac->allowedChildClassesEffective) {
1565                         ret = acl_childClassesEffective(ac->module, ac->schema,
1566                                                         acl_res->msgs[0],
1567                                                         ares->message, ac);
1568                         if (ret != LDB_SUCCESS) {
1569                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1570                         }
1571                 }
1572
1573                 if (ac->sDRightsEffective) {
1574                         ret = acl_sDRightsEffective(ac->module,
1575                                                     acl_res->msgs[0],
1576                                                     ares->message, ac);
1577                         if (ret != LDB_SUCCESS) {
1578                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1579                         }
1580                 }
1581
1582                 if (data == NULL) {
1583                         return ldb_module_send_entry(ac->req, ares->message,
1584                                                      ares->controls);
1585                 }
1586
1587                 if (ac->am_system) {
1588                         return ldb_module_send_entry(ac->req, ares->message,
1589                                                      ares->controls);
1590                 }
1591
1592                 if (data->password_attrs != NULL) {
1593                         for (i = 0; data->password_attrs[i]; i++) {
1594                                 if ((!ac->userPassword) &&
1595                                     (ldb_attr_cmp(data->password_attrs[i],
1596                                                   "userPassword") == 0))
1597                                 {
1598                                                 continue;
1599                                 }
1600
1601                                 ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
1602                         }
1603                 }
1604
1605                 if (ac->am_administrator) {
1606                         return ldb_module_send_entry(ac->req, ares->message,
1607                                                      ares->controls);
1608                 }
1609
1610                 ret = acl_search_update_confidential_attrs(ac, data);
1611                 if (ret != LDB_SUCCESS) {
1612                         return ret;
1613                 }
1614
1615                 if (data->confidential_attrs != NULL) {
1616                         for (i = 0; data->confidential_attrs[i]; i++) {
1617                                 ldb_msg_remove_attr(ares->message,
1618                                                     data->confidential_attrs[i]);
1619                         }
1620                 }
1621
1622                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1623
1624         case LDB_REPLY_REFERRAL:
1625                 return ldb_module_send_referral(ac->req, ares->referral);
1626
1627         case LDB_REPLY_DONE:
1628                 return ldb_module_done(ac->req, ares->controls,
1629                                        ares->response, LDB_SUCCESS);
1630
1631         }
1632         return LDB_SUCCESS;
1633 }
1634
1635 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1636 {
1637         struct ldb_context *ldb;
1638         struct acl_context *ac;
1639         struct ldb_parse_tree *down_tree;
1640         struct ldb_request *down_req;
1641         struct acl_private *data;
1642         int ret;
1643         unsigned int i;
1644
1645         ldb = ldb_module_get_ctx(module);
1646
1647         ac = talloc_zero(req, struct acl_context);
1648         if (ac == NULL) {
1649                 return ldb_oom(ldb);
1650         }
1651         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1652
1653         ac->module = module;
1654         ac->req = req;
1655         ac->am_system = dsdb_module_am_system(module);
1656         ac->am_administrator = dsdb_module_am_administrator(module);
1657         ac->constructed_attrs = false;
1658         ac->modify_search = true;
1659         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
1660         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
1661         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
1662         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
1663         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
1664         ac->userPassword = dsdb_user_password_support(module, ac, req);
1665         ac->schema = dsdb_get_schema(ldb, ac);
1666
1667         ac->constructed_attrs |= ac->allowedAttributes;
1668         ac->constructed_attrs |= ac->allowedChildClasses;
1669         ac->constructed_attrs |= ac->allowedChildClassesEffective;
1670         ac->constructed_attrs |= ac->allowedAttributesEffective;
1671         ac->constructed_attrs |= ac->sDRightsEffective;
1672
1673         if (data == NULL) {
1674                 ac->modify_search = false;
1675         }
1676         if (ac->am_system) {
1677                 ac->modify_search = false;
1678         }
1679
1680         if (!ac->constructed_attrs && !ac->modify_search) {
1681                 return ldb_next_request(module, req);
1682         }
1683
1684         ret = acl_search_update_confidential_attrs(ac, data);
1685         if (ret != LDB_SUCCESS) {
1686                 return ret;
1687         }
1688
1689         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
1690         if (down_tree == NULL) {
1691                 return ldb_oom(ldb);
1692         }
1693
1694         if (!ac->am_system && data->password_attrs) {
1695                 for (i = 0; data->password_attrs[i]; i++) {
1696                         if ((!ac->userPassword) &&
1697                             (ldb_attr_cmp(data->password_attrs[i],
1698                                           "userPassword") == 0))
1699                         {
1700                                 continue;
1701                         }
1702
1703                         ldb_parse_tree_attr_replace(down_tree,
1704                                                     data->password_attrs[i],
1705                                                     "kludgeACLredactedattribute");
1706                 }
1707         }
1708
1709         if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) {
1710                 for (i = 0; data->confidential_attrs[i]; i++) {
1711                         ldb_parse_tree_attr_replace(down_tree,
1712                                                     data->confidential_attrs[i],
1713                                                     "kludgeACLredactedattribute");
1714                 }
1715         }
1716
1717         ret = ldb_build_search_req_ex(&down_req,
1718                                       ldb, ac,
1719                                       req->op.search.base,
1720                                       req->op.search.scope,
1721                                       down_tree,
1722                                       req->op.search.attrs,
1723                                       req->controls,
1724                                       ac, acl_search_callback,
1725                                       req);
1726         LDB_REQ_SET_LOCATION(down_req);
1727         if (ret != LDB_SUCCESS) {
1728                 return ret;
1729         }
1730         /* perform the search */
1731         return ldb_next_request(module, down_req);
1732 }
1733
1734 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
1735 {
1736         struct ldb_context *ldb = ldb_module_get_ctx(module);
1737         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1738
1739         /* allow everybody to read the sequence number */
1740         if (strcmp(req->op.extended.oid,
1741                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1742                 return ldb_next_request(module, req);
1743         }
1744
1745         if (dsdb_module_am_system(module) ||
1746             dsdb_module_am_administrator(module) || as_system) {
1747                 return ldb_next_request(module, req);
1748         } else {
1749                 ldb_asprintf_errstring(ldb,
1750                                        "acl_extended: "
1751                                        "attempted database modify not permitted. "
1752                                        "User %s is not SYSTEM or an administrator",
1753                                        acl_user_name(req, module));
1754                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1755         }
1756 }
1757
1758 static const struct ldb_module_ops ldb_acl_module_ops = {
1759         .name              = "acl",
1760         .search            = acl_search,
1761         .add               = acl_add,
1762         .modify            = acl_modify,
1763         .del               = acl_delete,
1764         .rename            = acl_rename,
1765         .extended          = acl_extended,
1766         .init_context      = acl_module_init
1767 };
1768
1769 int ldb_acl_module_init(const char *version)
1770 {
1771         LDB_MODULE_CHECK_VERSION(version);
1772         return ldb_register_module(&ldb_acl_module_ops);
1773 }