e5597710e822db8b8c587c787435515036273ff4
[mat/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         NTSTATUS status;
981         struct ldb_result *acl_res;
982         struct security_descriptor *sd;
983         struct dom_sid *sid = NULL;
984         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
985         bool userPassword;
986         TALLOC_CTX *tmp_ctx = talloc_new(req);
987         static const char *acl_attrs[] = {
988                 "nTSecurityDescriptor",
989                 "objectClass",
990                 "objectSid",
991                 NULL
992         };
993
994         if (as_system != NULL) {
995                 as_system->critical = 0;
996         }
997
998         /* Don't print this debug statement if elements[0].name is going to be NULL */
999         if(req->op.mod.message->num_elements > 0)
1000         {
1001                 DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name));
1002         }
1003         if (dsdb_module_am_system(module) || as_system) {
1004                 return ldb_next_request(module, req);
1005         }
1006         if (ldb_dn_is_special(req->op.mod.message->dn)) {
1007                 return ldb_next_request(module, req);
1008         }
1009         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, req->op.mod.message->dn,
1010                                     acl_attrs,
1011                                     DSDB_FLAG_NEXT_MODULE |
1012                                     DSDB_FLAG_AS_SYSTEM |
1013                                     DSDB_SEARCH_SHOW_RECYCLED,
1014                                     req);
1015
1016         if (ret != LDB_SUCCESS) {
1017                 goto fail;
1018         }
1019
1020         userPassword = dsdb_user_password_support(module, req, req);
1021
1022         schema = dsdb_get_schema(ldb, tmp_ctx);
1023         if (!schema) {
1024                 talloc_free(tmp_ctx);
1025                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1026                                  "acl_modify: Error obtaining schema.");
1027         }
1028
1029         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1030         if (ret != LDB_SUCCESS) {
1031                 talloc_free(tmp_ctx);
1032                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1033                                  "acl_modify: Error retrieving security descriptor.");
1034         }
1035         /* Theoretically we pass the check if the object has no sd */
1036         if (!sd) {
1037                 goto success;
1038         }
1039
1040         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1041         if (!guid) {
1042                 talloc_free(tmp_ctx);
1043                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1044                                  "acl_modify: Error retrieving object class GUID.");
1045         }
1046         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1047         for (i=0; i < req->op.mod.message->num_elements; i++){
1048                 const struct dsdb_attribute *attr;
1049                 attr = dsdb_attribute_by_lDAPDisplayName(schema,
1050                                                          req->op.mod.message->elements[i].name);
1051
1052                 if (ldb_attr_cmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) {
1053                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1054                         uint32_t access_mask = 0;
1055
1056                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1057                                 access_mask |= SEC_STD_WRITE_OWNER;
1058                         }
1059                         if (sd_flags & SECINFO_DACL) {
1060                                 access_mask |= SEC_STD_WRITE_DAC;
1061                         }
1062                         if (sd_flags & SECINFO_SACL) {
1063                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1064                         }
1065
1066                         status = sec_access_check_ds(sd, acl_user_token(module),
1067                                              access_mask,
1068                                              &access_granted,
1069                                              NULL,
1070                                              sid);
1071
1072                         if (!NT_STATUS_IS_OK(status)) {
1073                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1074                                                        "Object %s has no write dacl access\n",
1075                                                        ldb_dn_get_linearized(req->op.mod.message->dn));
1076                                 dsdb_acl_debug(sd,
1077                                                acl_user_token(module),
1078                                                req->op.mod.message->dn,
1079                                                true,
1080                                                10);
1081                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1082                                 goto fail;
1083                         }
1084                 }
1085                 else if (ldb_attr_cmp("member", req->op.mod.message->elements[i].name) == 0) {
1086                         ret = acl_check_self_membership(tmp_ctx,
1087                                                         module,
1088                                                         req,
1089                                                         sd,
1090                                                         sid,
1091                                                         guid,
1092                                                         attr);
1093                         if (ret != LDB_SUCCESS) {
1094                                 goto fail;
1095                         }
1096                 }
1097                 else if (ldb_attr_cmp("dBCSPwd", req->op.mod.message->elements[i].name) == 0) {
1098                         /* this one is not affected by any rights, we should let it through
1099                            so that passwords_hash returns the correct error */
1100                         continue;
1101                 }
1102                 else if (ldb_attr_cmp("unicodePwd", req->op.mod.message->elements[i].name) == 0 ||
1103                          (userPassword && ldb_attr_cmp("userPassword", req->op.mod.message->elements[i].name) == 0) ||
1104                          ldb_attr_cmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) {
1105                         ret = acl_check_password_rights(tmp_ctx,
1106                                                         module,
1107                                                         req,
1108                                                         sd,
1109                                                         sid,
1110                                                         guid,
1111                                                         userPassword);
1112                         if (ret != LDB_SUCCESS) {
1113                                 goto fail;
1114                         }
1115                 } else if (ldb_attr_cmp("servicePrincipalName", req->op.mod.message->elements[i].name) == 0) {
1116                         ret = acl_check_spn(tmp_ctx,
1117                                             module,
1118                                             req,
1119                                             sd,
1120                                             sid,
1121                                             guid,
1122                                             attr);
1123                         if (ret != LDB_SUCCESS) {
1124                                 goto fail;
1125                         }
1126                 } else {
1127                         struct object_tree *root = NULL;
1128                         struct object_tree *new_node = NULL;
1129
1130                 /* This basic attribute existence check with the right errorcode
1131                  * is needed since this module is the first one which requests
1132                  * schema attribute information.
1133                  * The complete attribute checking is done in the
1134                  * "objectclass_attrs" module behind this one.
1135                  */
1136                         if (!attr) {
1137                                 ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' on entry '%s' was not found in the schema!",
1138                                                        req->op.mod.message->elements[i].name,
1139                                                ldb_dn_get_linearized(req->op.mod.message->dn));
1140                                 ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
1141                                 goto fail;
1142                         }
1143
1144                         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1145                                                    &root, &new_node)) {
1146                                 talloc_free(tmp_ctx);
1147                                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1148                                                  "acl_modify: Error adding new node in object tree.");
1149                         }
1150
1151                         if (!insert_in_object_tree(tmp_ctx,
1152                                                    &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
1153                                                    &new_node, &new_node)) {
1154                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1155                                                        "acl_modify: cannot add to object tree securityGUID\n");
1156                                 ret = LDB_ERR_OPERATIONS_ERROR;
1157                                 goto fail;
1158                         }
1159
1160                         if (!insert_in_object_tree(tmp_ctx,
1161                                                    &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) {
1162                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1163                                                        "acl_modify: cannot add to object tree attributeGUID\n");
1164                                 ret = LDB_ERR_OPERATIONS_ERROR;
1165                                 goto fail;
1166                         }
1167
1168                         status = sec_access_check_ds(sd, acl_user_token(module),
1169                                                      SEC_ADS_WRITE_PROP,
1170                                                      &access_granted,
1171                                                      root,
1172                                                      sid);
1173                         if (!NT_STATUS_IS_OK(status)) {
1174                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1175                                                        "Object %s has no write property access\n",
1176                                                        ldb_dn_get_linearized(req->op.mod.message->dn));
1177                                 dsdb_acl_debug(sd,
1178                                                acl_user_token(module),
1179                                                req->op.mod.message->dn,
1180                                                true,
1181                                                10);
1182                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1183                                 goto fail;
1184                         }
1185                 }
1186         }
1187
1188 success:
1189         talloc_free(tmp_ctx);
1190         return ldb_next_request(module, req);
1191 fail:
1192         talloc_free(tmp_ctx);
1193         return ret;
1194 }
1195
1196 /* similar to the modify for the time being.
1197  * We need to consider the special delete tree case, though - TODO */
1198 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
1199 {
1200         int ret;
1201         struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn);
1202         struct ldb_context *ldb;
1203         struct ldb_dn *nc_root;
1204         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1205
1206         if (as_system != NULL) {
1207                 as_system->critical = 0;
1208         }
1209
1210         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
1211         if (dsdb_module_am_system(module) || as_system) {
1212                 return ldb_next_request(module, req);
1213         }
1214         if (ldb_dn_is_special(req->op.del.dn)) {
1215                 return ldb_next_request(module, req);
1216         }
1217
1218         ldb = ldb_module_get_ctx(module);
1219
1220         /* Make sure we aren't deleting a NC */
1221
1222         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
1223         if (ret != LDB_SUCCESS) {
1224                 return ret;
1225         }
1226         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
1227                 talloc_free(nc_root);
1228                 DEBUG(10,("acl:deleting a NC\n"));
1229                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1230                 return ldb_module_done(req, NULL, NULL,
1231                                        LDB_ERR_UNWILLING_TO_PERFORM);
1232         }
1233         talloc_free(nc_root);
1234
1235         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
1236                 ret = dsdb_module_check_access_on_dn(module, req,
1237                                                      req->op.del.dn,
1238                                                      SEC_ADS_DELETE_TREE, NULL,
1239                                                      req);
1240                 if (ret != LDB_SUCCESS) {
1241                         return ret;
1242                 }
1243
1244                 return ldb_next_request(module, req);
1245         }
1246
1247         /* First check if we have delete object right */
1248         ret = dsdb_module_check_access_on_dn(module, req, req->op.del.dn,
1249                                              SEC_STD_DELETE, NULL, req);
1250         if (ret == LDB_SUCCESS) {
1251                 return ldb_next_request(module, req);
1252         }
1253
1254         /* Nope, we don't have delete object. Lets check if we have delete
1255          * child on the parent */
1256         ret = dsdb_module_check_access_on_dn(module, req, parent,
1257                                              SEC_ADS_DELETE_CHILD, NULL, req);
1258         if (ret != LDB_SUCCESS) {
1259                 return ret;
1260         }
1261
1262         return ldb_next_request(module, req);
1263 }
1264
1265 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
1266 {
1267         int ret;
1268         struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn);
1269         struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn);
1270         const struct dsdb_schema *schema;
1271         struct ldb_context *ldb;
1272         struct security_descriptor *sd = NULL;
1273         struct dom_sid *sid = NULL;
1274         struct ldb_result *acl_res;
1275         const struct GUID *guid;
1276         struct ldb_dn *nc_root;
1277         struct object_tree *root = NULL;
1278         struct object_tree *new_node = NULL;
1279         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1280         TALLOC_CTX *tmp_ctx = talloc_new(req);
1281         NTSTATUS status;
1282         uint32_t access_granted;
1283         const char *rdn_name;
1284         static const char *acl_attrs[] = {
1285                 "nTSecurityDescriptor",
1286                 "objectClass",
1287                 "objectSid",
1288                 NULL
1289         };
1290
1291         if (as_system != NULL) {
1292                 as_system->critical = 0;
1293         }
1294
1295         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
1296         if (dsdb_module_am_system(module) || as_system) {
1297                 return ldb_next_request(module, req);
1298         }
1299         if (ldb_dn_is_special(req->op.rename.olddn)) {
1300                 return ldb_next_request(module, req);
1301         }
1302
1303         ldb = ldb_module_get_ctx(module);
1304
1305         /* Make sure we aren't renaming/moving a NC */
1306
1307         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
1308         if (ret != LDB_SUCCESS) {
1309                 return ret;
1310         }
1311         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
1312                 talloc_free(nc_root);
1313                 DEBUG(10,("acl:renaming/moving a NC\n"));
1314                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1315                 return ldb_module_done(req, NULL, NULL,
1316                                        LDB_ERR_UNWILLING_TO_PERFORM);
1317         }
1318         talloc_free(nc_root);
1319
1320         /* Look for the parent */
1321
1322         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
1323                                     req->op.rename.olddn, acl_attrs,
1324                                     DSDB_FLAG_NEXT_MODULE |
1325                                     DSDB_FLAG_AS_SYSTEM |
1326                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1327         /* we sould be able to find the parent */
1328         if (ret != LDB_SUCCESS) {
1329                 DEBUG(10,("acl: failed to find object %s\n",
1330                           ldb_dn_get_linearized(req->op.rename.olddn)));
1331                 talloc_free(tmp_ctx);
1332                 return ret;
1333         }
1334
1335         schema = dsdb_get_schema(ldb, acl_res);
1336         if (!schema) {
1337                 talloc_free(tmp_ctx);
1338                 return ldb_operr(ldb);
1339         }
1340
1341         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1342         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1343                                    &root, &new_node)) {
1344                 talloc_free(tmp_ctx);
1345                 return ldb_operr(ldb);
1346         };
1347
1348         guid = attribute_schemaid_guid_by_lDAPDisplayName(schema,
1349                                                           "name");
1350         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1351                                    &new_node, &new_node)) {
1352                 talloc_free(tmp_ctx);
1353                 return ldb_operr(ldb);
1354         };
1355
1356         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
1357         if (rdn_name == NULL) {
1358                 talloc_free(tmp_ctx);
1359                 return ldb_operr(ldb);
1360         }
1361         guid = attribute_schemaid_guid_by_lDAPDisplayName(schema,
1362                                                           rdn_name);
1363         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1364                                    &new_node, &new_node)) {
1365                 talloc_free(tmp_ctx);
1366                 return ldb_operr(ldb);
1367         };
1368
1369         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1370
1371         if (ret != LDB_SUCCESS) {
1372                 talloc_free(tmp_ctx);
1373                 return ldb_operr(ldb);
1374         }
1375         /* Theoretically we pass the check if the object has no sd */
1376         if (!sd) {
1377                 talloc_free(tmp_ctx);
1378                 return LDB_SUCCESS;
1379         }
1380         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1381         status = sec_access_check_ds(sd, acl_user_token(module),
1382                                      SEC_ADS_WRITE_PROP,
1383                                      &access_granted,
1384                                      root,
1385                                      sid);
1386
1387         if (!NT_STATUS_IS_OK(status)) {
1388                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1389                                        "Object %s has no wp on name\n",
1390                                        ldb_dn_get_linearized(req->op.rename.olddn));
1391                 dsdb_acl_debug(sd,
1392                           acl_user_token(module),
1393                           req->op.rename.olddn,
1394                           true,
1395                           10);
1396                 talloc_free(tmp_ctx);
1397                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1398         }
1399
1400         if (ldb_dn_compare(oldparent, newparent) == 0) {
1401                 /* regular rename, not move, nothing more to do */
1402                 talloc_free(tmp_ctx);
1403                 return ldb_next_request(module, req);
1404         }
1405
1406         /* new parent should have create child */
1407         root = NULL;
1408         new_node = NULL;
1409         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1410         if (!guid) {
1411                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1412                                        "acl:renamed object has no object class\n");
1413                 talloc_free(tmp_ctx);
1414                 return ldb_module_done(req, NULL, NULL,  LDB_ERR_OPERATIONS_ERROR);
1415         }
1416
1417         ret = dsdb_module_check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, guid, req);
1418         if (ret != LDB_SUCCESS) {
1419                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1420                                        "acl:access_denied renaming %s",
1421                                        ldb_dn_get_linearized(req->op.rename.olddn));
1422                 talloc_free(tmp_ctx);
1423                 return ret;
1424         }
1425         /* do we have delete object on the object? */
1426
1427         status = sec_access_check_ds(sd, acl_user_token(module),
1428                                      SEC_STD_DELETE,
1429                                      &access_granted,
1430                                      NULL,
1431                                      sid);
1432
1433         if (NT_STATUS_IS_OK(status)) {
1434                 talloc_free(tmp_ctx);
1435                 return ldb_next_request(module, req);
1436         }
1437         /* what about delete child on the current parent */
1438         ret = dsdb_module_check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL, req);
1439         if (ret != LDB_SUCCESS) {
1440                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1441                                        "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
1442                 talloc_free(tmp_ctx);
1443                 return ldb_module_done(req, NULL, NULL, ret);
1444         }
1445
1446         talloc_free(tmp_ctx);
1447
1448         return ldb_next_request(module, req);
1449 }
1450
1451 static int acl_search_update_confidential_attrs(struct acl_context *ac,
1452                                                 struct acl_private *data)
1453 {
1454         struct dsdb_attribute *a;
1455         uint32_t n = 0;
1456
1457         if (data->acl_search) {
1458                 /*
1459                  * If acl:search is activated, the acl_read module
1460                  * protects confidential attributes.
1461                  */
1462                 return LDB_SUCCESS;
1463         }
1464
1465         if ((ac->schema == data->cached_schema_ptr) &&
1466             (ac->schema->loaded_usn == data->cached_schema_loaded_usn) &&
1467             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
1468         {
1469                 return LDB_SUCCESS;
1470         }
1471
1472         data->cached_schema_ptr = NULL;
1473         data->cached_schema_loaded_usn = 0;
1474         data->cached_schema_metadata_usn = 0;
1475         TALLOC_FREE(data->confidential_attrs);
1476
1477         if (ac->schema == NULL) {
1478                 return LDB_SUCCESS;
1479         }
1480
1481         for (a = ac->schema->attributes; a; a = a->next) {
1482                 const char **attrs = data->confidential_attrs;
1483
1484                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
1485                         continue;
1486                 }
1487
1488                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
1489                 if (attrs == NULL) {
1490                         TALLOC_FREE(data->confidential_attrs);
1491                         return ldb_module_oom(ac->module);
1492                 }
1493
1494                 attrs[n] = a->lDAPDisplayName;
1495                 attrs[n+1] = NULL;
1496                 n++;
1497
1498                 data->confidential_attrs = attrs;
1499         }
1500
1501         data->cached_schema_ptr = ac->schema;
1502         data->cached_schema_loaded_usn = ac->schema->loaded_usn;
1503         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
1504
1505         return LDB_SUCCESS;
1506 }
1507
1508 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1509 {
1510         struct acl_context *ac;
1511         struct acl_private *data;
1512         struct ldb_result *acl_res;
1513         static const char *acl_attrs[] = {
1514                 "objectClass",
1515                 "nTSecurityDescriptor",
1516                 "objectSid",
1517                 NULL
1518         };
1519         int ret;
1520         unsigned int i;
1521
1522         ac = talloc_get_type(req->context, struct acl_context);
1523         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
1524         if (!ares) {
1525                 return ldb_module_done(ac->req, NULL, NULL,
1526                                        LDB_ERR_OPERATIONS_ERROR);
1527         }
1528         if (ares->error != LDB_SUCCESS) {
1529                 return ldb_module_done(ac->req, ares->controls,
1530                                        ares->response, ares->error);
1531         }
1532
1533         switch (ares->type) {
1534         case LDB_REPLY_ENTRY:
1535                 if (ac->constructed_attrs) {
1536                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn, 
1537                                                     acl_attrs,
1538                                                     DSDB_FLAG_NEXT_MODULE |
1539                                                     DSDB_FLAG_AS_SYSTEM |
1540                                                     DSDB_SEARCH_SHOW_RECYCLED,
1541                                                     req);
1542                         if (ret != LDB_SUCCESS) {
1543                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1544                         }
1545                 }
1546
1547                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
1548                         ret = acl_allowedAttributes(ac->module, ac->schema,
1549                                                     acl_res->msgs[0],
1550                                                     ares->message, ac);
1551                         if (ret != LDB_SUCCESS) {
1552                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1553                         }
1554                 }
1555
1556                 if (ac->allowedChildClasses) {
1557                         ret = acl_childClasses(ac->module, ac->schema,
1558                                                acl_res->msgs[0],
1559                                                ares->message,
1560                                                "allowedChildClasses");
1561                         if (ret != LDB_SUCCESS) {
1562                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1563                         }
1564                 }
1565
1566                 if (ac->allowedChildClassesEffective) {
1567                         ret = acl_childClassesEffective(ac->module, ac->schema,
1568                                                         acl_res->msgs[0],
1569                                                         ares->message, ac);
1570                         if (ret != LDB_SUCCESS) {
1571                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1572                         }
1573                 }
1574
1575                 if (ac->sDRightsEffective) {
1576                         ret = acl_sDRightsEffective(ac->module,
1577                                                     acl_res->msgs[0],
1578                                                     ares->message, ac);
1579                         if (ret != LDB_SUCCESS) {
1580                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1581                         }
1582                 }
1583
1584                 if (data == NULL) {
1585                         return ldb_module_send_entry(ac->req, ares->message,
1586                                                      ares->controls);
1587                 }
1588
1589                 if (ac->am_system) {
1590                         return ldb_module_send_entry(ac->req, ares->message,
1591                                                      ares->controls);
1592                 }
1593
1594                 if (data->password_attrs != NULL) {
1595                         for (i = 0; data->password_attrs[i]; i++) {
1596                                 if ((!ac->userPassword) &&
1597                                     (ldb_attr_cmp(data->password_attrs[i],
1598                                                   "userPassword") == 0))
1599                                 {
1600                                                 continue;
1601                                 }
1602
1603                                 ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
1604                         }
1605                 }
1606
1607                 if (ac->am_administrator) {
1608                         return ldb_module_send_entry(ac->req, ares->message,
1609                                                      ares->controls);
1610                 }
1611
1612                 ret = acl_search_update_confidential_attrs(ac, data);
1613                 if (ret != LDB_SUCCESS) {
1614                         return ret;
1615                 }
1616
1617                 if (data->confidential_attrs != NULL) {
1618                         for (i = 0; data->confidential_attrs[i]; i++) {
1619                                 ldb_msg_remove_attr(ares->message,
1620                                                     data->confidential_attrs[i]);
1621                         }
1622                 }
1623
1624                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1625
1626         case LDB_REPLY_REFERRAL:
1627                 return ldb_module_send_referral(ac->req, ares->referral);
1628
1629         case LDB_REPLY_DONE:
1630                 return ldb_module_done(ac->req, ares->controls,
1631                                        ares->response, LDB_SUCCESS);
1632
1633         }
1634         return LDB_SUCCESS;
1635 }
1636
1637 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1638 {
1639         struct ldb_context *ldb;
1640         struct acl_context *ac;
1641         struct ldb_parse_tree *down_tree;
1642         struct ldb_request *down_req;
1643         struct acl_private *data;
1644         int ret;
1645         unsigned int i;
1646
1647         ldb = ldb_module_get_ctx(module);
1648
1649         ac = talloc_zero(req, struct acl_context);
1650         if (ac == NULL) {
1651                 return ldb_oom(ldb);
1652         }
1653         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1654
1655         ac->module = module;
1656         ac->req = req;
1657         ac->am_system = dsdb_module_am_system(module);
1658         ac->am_administrator = dsdb_module_am_administrator(module);
1659         ac->constructed_attrs = false;
1660         ac->modify_search = true;
1661         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
1662         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
1663         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
1664         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
1665         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
1666         ac->userPassword = true;
1667         ac->schema = dsdb_get_schema(ldb, ac);
1668
1669         ac->constructed_attrs |= ac->allowedAttributes;
1670         ac->constructed_attrs |= ac->allowedChildClasses;
1671         ac->constructed_attrs |= ac->allowedChildClassesEffective;
1672         ac->constructed_attrs |= ac->allowedAttributesEffective;
1673         ac->constructed_attrs |= ac->sDRightsEffective;
1674
1675         if (data == NULL) {
1676                 ac->modify_search = false;
1677         }
1678         if (ac->am_system) {
1679                 ac->modify_search = false;
1680         }
1681
1682         if (!ac->constructed_attrs && !ac->modify_search) {
1683                 talloc_free(ac);
1684                 return ldb_next_request(module, req);
1685         }
1686
1687         if (!ac->am_system) {
1688                 ac->userPassword = dsdb_user_password_support(module, ac, req);
1689         }
1690
1691         ret = acl_search_update_confidential_attrs(ac, data);
1692         if (ret != LDB_SUCCESS) {
1693                 return ret;
1694         }
1695
1696         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
1697         if (down_tree == NULL) {
1698                 return ldb_oom(ldb);
1699         }
1700
1701         if (!ac->am_system && data->password_attrs) {
1702                 for (i = 0; data->password_attrs[i]; i++) {
1703                         if ((!ac->userPassword) &&
1704                             (ldb_attr_cmp(data->password_attrs[i],
1705                                           "userPassword") == 0))
1706                         {
1707                                 continue;
1708                         }
1709
1710                         ldb_parse_tree_attr_replace(down_tree,
1711                                                     data->password_attrs[i],
1712                                                     "kludgeACLredactedattribute");
1713                 }
1714         }
1715
1716         if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) {
1717                 for (i = 0; data->confidential_attrs[i]; i++) {
1718                         ldb_parse_tree_attr_replace(down_tree,
1719                                                     data->confidential_attrs[i],
1720                                                     "kludgeACLredactedattribute");
1721                 }
1722         }
1723
1724         ret = ldb_build_search_req_ex(&down_req,
1725                                       ldb, ac,
1726                                       req->op.search.base,
1727                                       req->op.search.scope,
1728                                       down_tree,
1729                                       req->op.search.attrs,
1730                                       req->controls,
1731                                       ac, acl_search_callback,
1732                                       req);
1733         LDB_REQ_SET_LOCATION(down_req);
1734         if (ret != LDB_SUCCESS) {
1735                 return ret;
1736         }
1737         /* perform the search */
1738         return ldb_next_request(module, down_req);
1739 }
1740
1741 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
1742 {
1743         struct ldb_context *ldb = ldb_module_get_ctx(module);
1744         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1745
1746         /* allow everybody to read the sequence number */
1747         if (strcmp(req->op.extended.oid,
1748                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1749                 return ldb_next_request(module, req);
1750         }
1751
1752         if (dsdb_module_am_system(module) ||
1753             dsdb_module_am_administrator(module) || as_system) {
1754                 return ldb_next_request(module, req);
1755         } else {
1756                 ldb_asprintf_errstring(ldb,
1757                                        "acl_extended: "
1758                                        "attempted database modify not permitted. "
1759                                        "User %s is not SYSTEM or an administrator",
1760                                        acl_user_name(req, module));
1761                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1762         }
1763 }
1764
1765 static const struct ldb_module_ops ldb_acl_module_ops = {
1766         .name              = "acl",
1767         .search            = acl_search,
1768         .add               = acl_add,
1769         .modify            = acl_modify,
1770         .del               = acl_delete,
1771         .rename            = acl_rename,
1772         .extended          = acl_extended,
1773         .init_context      = acl_module_init
1774 };
1775
1776 int ldb_acl_module_init(const char *version)
1777 {
1778         LDB_MODULE_CHECK_VERSION(version);
1779         return ldb_register_module(&ldb_acl_module_ops);
1780 }