24b65078030cb471fee8366d3ff14ef989561d73
[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_context *ldb = ldb_module_get_ctx(module);
462         struct ldb_message_element *rightsEffective;
463         int ret;
464         struct security_descriptor *sd;
465         struct ldb_control *as_system = ldb_request_get_control(ac->req,
466                                                                 LDB_CONTROL_AS_SYSTEM_OID);
467         struct dom_sid *sid = NULL;
468         uint32_t flags = 0;
469
470         if (as_system != NULL) {
471                 as_system->critical = 0;
472         }
473
474         /* Must remove any existing attribute, or else confusion reins */
475         ldb_msg_remove_attr(msg, "sDRightsEffective");
476         ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
477         if (ret != LDB_SUCCESS) {
478                 return ret;
479         }
480         if (ac->am_system || as_system) {
481                 flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
482         }
483         else {
484                 /* Get the security descriptor from the message */
485                 ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
486                 if (ret != LDB_SUCCESS) {
487                         return ret;
488                 }
489                 sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
490                 ret = acl_check_access_on_attribute(module,
491                                                     msg,
492                                                     sd,
493                                                     sid,
494                                                     SEC_STD_WRITE_OWNER,
495                                                     NULL);
496                 if (ret == LDB_SUCCESS) {
497                         flags |= SECINFO_OWNER | SECINFO_GROUP;
498                 }
499                 ret = acl_check_access_on_attribute(module,
500                                                     msg,
501                                                     sd,
502                                                     sid,
503                                                     SEC_STD_WRITE_DAC,
504                                                     NULL);
505                 if (ret == LDB_SUCCESS) {
506                         flags |= SECINFO_DACL;
507                 }
508                 ret = acl_check_access_on_attribute(module,
509                                                     msg,
510                                                     sd,
511                                                     sid,
512                                                     SEC_FLAG_SYSTEM_SECURITY,
513                                                     NULL);
514                 if (ret == LDB_SUCCESS) {
515                         flags |= SECINFO_SACL;
516                 }
517         }
518         return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
519                                   "sDRightsEffective", flags);
520 }
521
522 static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
523                                   struct ldb_context *ldb,
524                                   const char *spn_value,
525                                   uint32_t userAccountControl,
526                                   const char *samAccountName,
527                                   const char *dnsHostName,
528                                   const char *netbios_name,
529                                   const char *ntds_guid)
530 {
531         int ret;
532         krb5_context krb_ctx;
533         krb5_error_code kerr;
534         krb5_principal principal;
535         char *instanceName;
536         char *serviceType;
537         char *serviceName;
538         const char *forest_name = samdb_forest_name(ldb, mem_ctx);
539         const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
540         struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
541                                                           struct loadparm_context);
542         bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
543                 (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
544
545         if (strcasecmp_m(spn_value, samAccountName) == 0) {
546                 /* MacOS X sets this value, and setting an SPN of your
547                  * own samAccountName is both pointless and safe */
548                 return LDB_SUCCESS;
549         }
550
551         kerr = smb_krb5_init_context_basic(mem_ctx,
552                                            lp_ctx,
553                                            &krb_ctx);
554         if (kerr != 0) {
555                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
556                                  "Could not initialize kerberos context.");
557         }
558
559         ret = krb5_parse_name(krb_ctx, spn_value, &principal);
560         if (ret) {
561                 krb5_free_context(krb_ctx);
562                 return LDB_ERR_CONSTRAINT_VIOLATION;
563         }
564
565         if (principal->name.name_string.len < 2) {
566                 goto fail;
567         }
568
569         instanceName = principal->name.name_string.val[1];
570         serviceType = principal->name.name_string.val[0];
571         if (principal->name.name_string.len == 3) {
572                 serviceName = principal->name.name_string.val[2];
573         } else {
574                 serviceName = NULL;
575         }
576
577         if (serviceName) {
578                 if (!is_dc) {
579                         goto fail;
580                 }
581                 if (strcasecmp(serviceType, "ldap") == 0) {
582                         if (strcasecmp(serviceName, netbios_name) != 0 &&
583                             strcasecmp(serviceName, forest_name) != 0) {
584                                 goto fail;
585                         }
586
587                 } else if (strcasecmp(serviceType, "gc") == 0) {
588                         if (strcasecmp(serviceName, forest_name) != 0) {
589                                 goto fail;
590                         }
591                 } else {
592                         if (strcasecmp(serviceName, base_domain) != 0 &&
593                             strcasecmp(serviceName, netbios_name) != 0) {
594                                 goto fail;
595                         }
596                 }
597         }
598         /* instanceName can be samAccountName without $ or dnsHostName
599          * or "ntds_guid._msdcs.forest_domain for DC objects */
600         if (strlen(instanceName) == (strlen(samAccountName) - 1)
601             && strncasecmp(instanceName, samAccountName, strlen(samAccountName) - 1) == 0) {
602                 goto success;
603         } else if (dnsHostName != NULL && strcasecmp(instanceName, dnsHostName) == 0) {
604                 goto success;
605         } else if (is_dc) {
606                 const char *guid_str;
607                 guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
608                                            ntds_guid,
609                                            forest_name);
610                 if (strcasecmp(instanceName, guid_str) == 0) {
611                         goto success;
612                 }
613         }
614
615 fail:
616         krb5_free_principal(krb_ctx, principal);
617         krb5_free_context(krb_ctx);
618         return LDB_ERR_CONSTRAINT_VIOLATION;
619
620 success:
621         krb5_free_principal(krb_ctx, principal);
622         krb5_free_context(krb_ctx);
623         return LDB_SUCCESS;
624 }
625
626 static int acl_check_spn(TALLOC_CTX *mem_ctx,
627                          struct ldb_module *module,
628                          struct ldb_request *req,
629                          struct security_descriptor *sd,
630                          struct dom_sid *sid,
631                          const struct GUID *oc_guid,
632                          const struct dsdb_attribute *attr)
633 {
634         int ret;
635         unsigned int i;
636         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
637         struct ldb_context *ldb = ldb_module_get_ctx(module);
638         struct ldb_result *acl_res;
639         struct ldb_result *netbios_res;
640         struct ldb_message_element *el;
641         struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
642         uint32_t userAccountControl;
643         const char *samAccountName;
644         const char *dnsHostName;
645         const char *netbios_name;
646         struct GUID ntds;
647         char *ntds_guid = NULL;
648
649         static const char *acl_attrs[] = {
650                 "samAccountName",
651                 "dnsHostName",
652                 "userAccountControl",
653                 NULL
654         };
655         static const char *netbios_attrs[] = {
656                 "nETBIOSName",
657                 NULL
658         };
659
660         /* if we have wp, we can do whatever we like */
661         if (acl_check_access_on_attribute(module,
662                                           tmp_ctx,
663                                           sd,
664                                           sid,
665                                           SEC_ADS_WRITE_PROP,
666                                           attr) == LDB_SUCCESS) {
667                 talloc_free(tmp_ctx);
668                 return LDB_SUCCESS;
669         }
670
671         ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
672                                        GUID_DRS_VALIDATE_SPN,
673                                        SEC_ADS_SELF_WRITE,
674                                        sid);
675
676         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
677                 dsdb_acl_debug(sd, acl_user_token(module),
678                                req->op.mod.message->dn,
679                                true,
680                                10);
681                 talloc_free(tmp_ctx);
682                 return ret;
683         }
684
685         ret = dsdb_module_search_dn(module, tmp_ctx,
686                                     &acl_res, req->op.mod.message->dn,
687                                     acl_attrs,
688                                     DSDB_FLAG_NEXT_MODULE |
689                                     DSDB_FLAG_AS_SYSTEM |
690                                     DSDB_SEARCH_SHOW_RECYCLED,
691                                     req);
692         if (ret != LDB_SUCCESS) {
693                 talloc_free(tmp_ctx);
694                 return ret;
695         }
696
697         userAccountControl = ldb_msg_find_attr_as_uint(acl_res->msgs[0], "userAccountControl", 0);
698         dnsHostName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "dnsHostName", NULL);
699         samAccountName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "samAccountName", NULL);
700
701         ret = dsdb_module_search(module, tmp_ctx,
702                                  &netbios_res, partitions_dn,
703                                  LDB_SCOPE_ONELEVEL,
704                                  netbios_attrs,
705                                  DSDB_FLAG_NEXT_MODULE |
706                                  DSDB_FLAG_AS_SYSTEM,
707                                  req,
708                                  "(ncName=%s)",
709                                  ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
710
711         netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
712
713         el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName");
714         if (!el) {
715                 talloc_free(tmp_ctx);
716                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
717                                          "Error finding element for servicePrincipalName.");
718         }
719
720         /* NTDSDSA objectGuid of object we are checking SPN for */
721         if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
722                 ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
723                                                              req->op.mod.message->dn, &ntds, req);
724                 if (ret != LDB_SUCCESS) {
725                         ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
726                                                ldb_dn_get_linearized(req->op.mod.message->dn),
727                                                ldb_strerror(ret));
728                         talloc_free(tmp_ctx);
729                         return LDB_ERR_OPERATIONS_ERROR;
730                 }
731                 ntds_guid = GUID_string(tmp_ctx, &ntds);
732         }
733
734         for (i=0; i < el->num_values; i++) {
735                 ret = acl_validate_spn_value(tmp_ctx,
736                                              ldb,
737                                              (char *)el->values[i].data,
738                                              userAccountControl,
739                                              samAccountName,
740                                              dnsHostName,
741                                              netbios_name,
742                                              ntds_guid);
743                 if (ret != LDB_SUCCESS) {
744                         talloc_free(tmp_ctx);
745                         return ret;
746                 }
747         }
748         talloc_free(tmp_ctx);
749         return LDB_SUCCESS;
750 }
751
752 static int acl_add(struct ldb_module *module, struct ldb_request *req)
753 {
754         int ret;
755         struct ldb_dn *parent;
756         struct ldb_context *ldb;
757         const struct dsdb_schema *schema;
758         struct ldb_message_element *oc_el;
759         const struct GUID *guid;
760         struct ldb_dn *nc_root;
761         struct ldb_control *as_system;
762
763         if (ldb_dn_is_special(req->op.add.message->dn)) {
764                 return ldb_next_request(module, req);
765         }
766
767         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
768         if (as_system != NULL) {
769                 as_system->critical = 0;
770         }
771
772         if (dsdb_module_am_system(module) || as_system) {
773                 return ldb_next_request(module, req);
774         }
775
776         ldb = ldb_module_get_ctx(module);
777
778         parent = ldb_dn_get_parent(req, req->op.add.message->dn);
779         if (parent == NULL) {
780                 return ldb_oom(ldb);
781         }
782
783         /* Creating an NC. There is probably something we should do here,
784          * but we will establish that later */
785
786         ret = dsdb_find_nc_root(ldb, req, req->op.add.message->dn, &nc_root);
787         if (ret != LDB_SUCCESS) {
788                 return ret;
789         }
790         if (ldb_dn_compare(nc_root, req->op.add.message->dn) == 0) {
791                 talloc_free(nc_root);
792                 return ldb_next_request(module, req);
793         }
794         talloc_free(nc_root);
795
796         schema = dsdb_get_schema(ldb, req);
797         if (!schema) {
798                 return ldb_operr(ldb);
799         }
800
801         oc_el = ldb_msg_find_element(req->op.add.message, "objectClass");
802         if (!oc_el || oc_el->num_values == 0) {
803                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
804                                        "acl: unable to find objectClass on %s\n",
805                                        ldb_dn_get_linearized(req->op.add.message->dn));
806                 return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
807         }
808
809         guid = class_schemaid_guid_by_lDAPDisplayName(schema,
810                                                       (char *)oc_el->values[oc_el->num_values-1].data);
811         ret = dsdb_module_check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, guid, req);
812         if (ret != LDB_SUCCESS) {
813                 return ret;
814         }
815         return ldb_next_request(module, req);
816 }
817
818 /* ckecks if modifications are allowed on "Member" attribute */
819 static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
820                                      struct ldb_module *module,
821                                      struct ldb_request *req,
822                                      struct security_descriptor *sd,
823                                      struct dom_sid *sid,
824                                      const struct GUID *oc_guid,
825                                      const struct dsdb_attribute *attr)
826 {
827         int ret;
828         unsigned int i;
829         struct ldb_context *ldb = ldb_module_get_ctx(module);
830         struct ldb_dn *user_dn;
831         struct ldb_message_element *member_el;
832         /* if we have wp, we can do whatever we like */
833         if (acl_check_access_on_attribute(module,
834                                           mem_ctx,
835                                           sd,
836                                           sid,
837                                           SEC_ADS_WRITE_PROP,
838                                           attr) == LDB_SUCCESS) {
839                 return LDB_SUCCESS;
840         }
841         /* if we are adding/deleting ourselves, check for self membership */
842         ret = dsdb_find_dn_by_sid(ldb, mem_ctx, 
843                                   &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], 
844                                   &user_dn);
845         if (ret != LDB_SUCCESS) {
846                 return ret;
847         }
848         member_el = ldb_msg_find_element(req->op.mod.message, "member");
849         if (!member_el) {
850                 return ldb_operr(ldb);
851         }
852         /* user can only remove oneself */
853         if (member_el->num_values == 0) {
854                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
855         }
856         for (i = 0; i < member_el->num_values; i++) {
857                 if (strcasecmp((const char *)member_el->values[i].data,
858                                ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
859                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
860                 }
861         }
862         ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
863                                        GUID_DRS_SELF_MEMBERSHIP,
864                                        SEC_ADS_SELF_WRITE,
865                                        sid);
866         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
867                 dsdb_acl_debug(sd, acl_user_token(module),
868                                req->op.mod.message->dn,
869                                true,
870                                10);
871         }
872         return ret;
873 }
874
875 static int acl_check_password_rights(TALLOC_CTX *mem_ctx,
876                                      struct ldb_module *module,
877                                      struct ldb_request *req,
878                                      struct security_descriptor *sd,
879                                      struct dom_sid *sid,
880                                      const struct GUID *oc_guid,
881                                      bool userPassword)
882 {
883         int ret = LDB_SUCCESS;
884         unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
885         struct ldb_message_element *el;
886         struct ldb_message *msg;
887         const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
888                                         "unicodePwd", "dBCSPwd", NULL }, **l;
889         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
890
891         msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
892         if (msg == NULL) {
893                 return ldb_module_oom(module);
894         }
895         for (l = passwordAttrs; *l != NULL; l++) {
896                 if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
897                         continue;
898                 }
899
900                 while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
901                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
902                                 ++del_attr_cnt;
903                         }
904                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
905                                 ++add_attr_cnt;
906                         }
907                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
908                                 ++rep_attr_cnt;
909                         }
910                         ldb_msg_remove_element(msg, el);
911                 }
912         }
913
914         /* single deletes will be handled by the "password_hash" LDB module
915          * later in the stack, so we let it though here */
916         if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
917                 talloc_free(tmp_ctx);
918                 return LDB_SUCCESS;
919         }
920
921         if (ldb_request_get_control(req,
922                                     DSDB_CONTROL_PASSWORD_CHANGE_OID) != NULL) {
923                 /* The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
924                  * have a user password change and not a set as the message
925                  * looks like. In it's value blob it contains the NT and/or LM
926                  * hash of the old password specified by the user.
927                  * This control is used by the SAMR and "kpasswd" password
928                  * change mechanisms. */
929                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
930                                                GUID_DRS_USER_CHANGE_PASSWORD,
931                                                SEC_ADS_CONTROL_ACCESS,
932                                                sid);
933         }
934         else if (rep_attr_cnt > 0 || (add_attr_cnt != del_attr_cnt)) {
935                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
936                                                GUID_DRS_FORCE_CHANGE_PASSWORD,
937                                                SEC_ADS_CONTROL_ACCESS,
938                                                sid);
939         }
940         else if (add_attr_cnt == 1 && del_attr_cnt == 1) {
941                 ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
942                                                GUID_DRS_USER_CHANGE_PASSWORD,
943                                                SEC_ADS_CONTROL_ACCESS,
944                                                sid);
945                 /* Very strange, but we get constraint violation in this case */
946                 if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
947                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
948                 }
949         }
950         if (ret != LDB_SUCCESS) {
951                 dsdb_acl_debug(sd, acl_user_token(module),
952                                req->op.mod.message->dn,
953                                true,
954                                10);
955         }
956         talloc_free(tmp_ctx);
957         return ret;
958 }
959
960 static const struct GUID *get_oc_guid_from_message(const struct dsdb_schema *schema,
961                                                    struct ldb_message *msg)
962 {
963         struct ldb_message_element *oc_el;
964         const struct dsdb_class *object_class;
965
966         oc_el = ldb_msg_find_element(msg, "objectClass");
967         if (!oc_el) {
968                 return NULL;
969         }
970
971         object_class = dsdb_get_last_structural_class(schema, oc_el);
972         if (object_class == NULL) {
973                 return NULL;
974         }
975
976         return &object_class->schemaIDGUID;
977 }
978
979
980 static int acl_modify(struct ldb_module *module, struct ldb_request *req)
981 {
982         int ret;
983         struct ldb_context *ldb = ldb_module_get_ctx(module);
984         const struct dsdb_schema *schema;
985         unsigned int i;
986         const struct GUID *guid;
987         uint32_t access_granted;
988         NTSTATUS status;
989         struct ldb_result *acl_res;
990         struct security_descriptor *sd;
991         struct dom_sid *sid = NULL;
992         struct ldb_control *as_system;
993         bool userPassword;
994         TALLOC_CTX *tmp_ctx;
995         static const char *acl_attrs[] = {
996                 "nTSecurityDescriptor",
997                 "objectClass",
998                 "objectSid",
999                 NULL
1000         };
1001
1002         if (ldb_dn_is_special(req->op.mod.message->dn)) {
1003                 return ldb_next_request(module, req);
1004         }
1005
1006         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1007         if (as_system != NULL) {
1008                 as_system->critical = 0;
1009         }
1010
1011         /* Don't print this debug statement if elements[0].name is going to be NULL */
1012         if(req->op.mod.message->num_elements > 0)
1013         {
1014                 DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name));
1015         }
1016         if (dsdb_module_am_system(module) || as_system) {
1017                 return ldb_next_request(module, req);
1018         }
1019
1020         tmp_ctx = talloc_new(req);
1021         if (tmp_ctx == NULL) {
1022                 return ldb_oom(ldb);
1023         }
1024
1025         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, req->op.mod.message->dn,
1026                                     acl_attrs,
1027                                     DSDB_FLAG_NEXT_MODULE |
1028                                     DSDB_FLAG_AS_SYSTEM |
1029                                     DSDB_SEARCH_SHOW_RECYCLED,
1030                                     req);
1031
1032         if (ret != LDB_SUCCESS) {
1033                 goto fail;
1034         }
1035
1036         userPassword = dsdb_user_password_support(module, req, req);
1037
1038         schema = dsdb_get_schema(ldb, tmp_ctx);
1039         if (!schema) {
1040                 talloc_free(tmp_ctx);
1041                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1042                                  "acl_modify: Error obtaining schema.");
1043         }
1044
1045         ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1046         if (ret != LDB_SUCCESS) {
1047                 talloc_free(tmp_ctx);
1048                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1049                                  "acl_modify: Error retrieving security descriptor.");
1050         }
1051         /* Theoretically we pass the check if the object has no sd */
1052         if (!sd) {
1053                 goto success;
1054         }
1055
1056         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1057         if (!guid) {
1058                 talloc_free(tmp_ctx);
1059                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1060                                  "acl_modify: Error retrieving object class GUID.");
1061         }
1062         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1063         for (i=0; i < req->op.mod.message->num_elements; i++){
1064                 const struct dsdb_attribute *attr;
1065                 attr = dsdb_attribute_by_lDAPDisplayName(schema,
1066                                                          req->op.mod.message->elements[i].name);
1067
1068                 if (ldb_attr_cmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) {
1069                         uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1070                         uint32_t access_mask = 0;
1071
1072                         if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1073                                 access_mask |= SEC_STD_WRITE_OWNER;
1074                         }
1075                         if (sd_flags & SECINFO_DACL) {
1076                                 access_mask |= SEC_STD_WRITE_DAC;
1077                         }
1078                         if (sd_flags & SECINFO_SACL) {
1079                                 access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1080                         }
1081
1082                         status = sec_access_check_ds(sd, acl_user_token(module),
1083                                              access_mask,
1084                                              &access_granted,
1085                                              NULL,
1086                                              sid);
1087
1088                         if (!NT_STATUS_IS_OK(status)) {
1089                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1090                                                        "Object %s has no write dacl access\n",
1091                                                        ldb_dn_get_linearized(req->op.mod.message->dn));
1092                                 dsdb_acl_debug(sd,
1093                                                acl_user_token(module),
1094                                                req->op.mod.message->dn,
1095                                                true,
1096                                                10);
1097                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1098                                 goto fail;
1099                         }
1100                 }
1101                 else if (ldb_attr_cmp("member", req->op.mod.message->elements[i].name) == 0) {
1102                         ret = acl_check_self_membership(tmp_ctx,
1103                                                         module,
1104                                                         req,
1105                                                         sd,
1106                                                         sid,
1107                                                         guid,
1108                                                         attr);
1109                         if (ret != LDB_SUCCESS) {
1110                                 goto fail;
1111                         }
1112                 }
1113                 else if (ldb_attr_cmp("dBCSPwd", req->op.mod.message->elements[i].name) == 0) {
1114                         /* this one is not affected by any rights, we should let it through
1115                            so that passwords_hash returns the correct error */
1116                         continue;
1117                 }
1118                 else if (ldb_attr_cmp("unicodePwd", req->op.mod.message->elements[i].name) == 0 ||
1119                          (userPassword && ldb_attr_cmp("userPassword", req->op.mod.message->elements[i].name) == 0) ||
1120                          ldb_attr_cmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) {
1121                         ret = acl_check_password_rights(tmp_ctx,
1122                                                         module,
1123                                                         req,
1124                                                         sd,
1125                                                         sid,
1126                                                         guid,
1127                                                         userPassword);
1128                         if (ret != LDB_SUCCESS) {
1129                                 goto fail;
1130                         }
1131                 } else if (ldb_attr_cmp("servicePrincipalName", req->op.mod.message->elements[i].name) == 0) {
1132                         ret = acl_check_spn(tmp_ctx,
1133                                             module,
1134                                             req,
1135                                             sd,
1136                                             sid,
1137                                             guid,
1138                                             attr);
1139                         if (ret != LDB_SUCCESS) {
1140                                 goto fail;
1141                         }
1142                 } else {
1143                         struct object_tree *root = NULL;
1144                         struct object_tree *new_node = NULL;
1145
1146                 /* This basic attribute existence check with the right errorcode
1147                  * is needed since this module is the first one which requests
1148                  * schema attribute information.
1149                  * The complete attribute checking is done in the
1150                  * "objectclass_attrs" module behind this one.
1151                  */
1152                         if (!attr) {
1153                                 ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' on entry '%s' was not found in the schema!",
1154                                                        req->op.mod.message->elements[i].name,
1155                                                ldb_dn_get_linearized(req->op.mod.message->dn));
1156                                 ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
1157                                 goto fail;
1158                         }
1159
1160                         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1161                                                    &root, &new_node)) {
1162                                 talloc_free(tmp_ctx);
1163                                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1164                                                  "acl_modify: Error adding new node in object tree.");
1165                         }
1166
1167                         if (!insert_in_object_tree(tmp_ctx,
1168                                                    &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
1169                                                    &new_node, &new_node)) {
1170                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1171                                                        "acl_modify: cannot add to object tree securityGUID\n");
1172                                 ret = LDB_ERR_OPERATIONS_ERROR;
1173                                 goto fail;
1174                         }
1175
1176                         if (!insert_in_object_tree(tmp_ctx,
1177                                                    &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) {
1178                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1179                                                        "acl_modify: cannot add to object tree attributeGUID\n");
1180                                 ret = LDB_ERR_OPERATIONS_ERROR;
1181                                 goto fail;
1182                         }
1183
1184                         status = sec_access_check_ds(sd, acl_user_token(module),
1185                                                      SEC_ADS_WRITE_PROP,
1186                                                      &access_granted,
1187                                                      root,
1188                                                      sid);
1189                         if (!NT_STATUS_IS_OK(status)) {
1190                                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1191                                                        "Object %s has no write property access\n",
1192                                                        ldb_dn_get_linearized(req->op.mod.message->dn));
1193                                 dsdb_acl_debug(sd,
1194                                                acl_user_token(module),
1195                                                req->op.mod.message->dn,
1196                                                true,
1197                                                10);
1198                                 ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1199                                 goto fail;
1200                         }
1201                 }
1202         }
1203
1204 success:
1205         talloc_free(tmp_ctx);
1206         return ldb_next_request(module, req);
1207 fail:
1208         talloc_free(tmp_ctx);
1209         return ret;
1210 }
1211
1212 /* similar to the modify for the time being.
1213  * We need to consider the special delete tree case, though - TODO */
1214 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
1215 {
1216         int ret;
1217         struct ldb_dn *parent;
1218         struct ldb_context *ldb;
1219         struct ldb_dn *nc_root;
1220         struct ldb_control *as_system;
1221
1222         if (ldb_dn_is_special(req->op.del.dn)) {
1223                 return ldb_next_request(module, req);
1224         }
1225
1226         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1227         if (as_system != NULL) {
1228                 as_system->critical = 0;
1229         }
1230
1231         if (dsdb_module_am_system(module) || as_system) {
1232                 return ldb_next_request(module, req);
1233         }
1234
1235         DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
1236
1237         ldb = ldb_module_get_ctx(module);
1238
1239         parent = ldb_dn_get_parent(req, req->op.del.dn);
1240         if (parent == NULL) {
1241                 return ldb_oom(ldb);
1242         }
1243
1244         /* Make sure we aren't deleting a NC */
1245
1246         ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
1247         if (ret != LDB_SUCCESS) {
1248                 return ret;
1249         }
1250         if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
1251                 talloc_free(nc_root);
1252                 DEBUG(10,("acl:deleting a NC\n"));
1253                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1254                 return ldb_module_done(req, NULL, NULL,
1255                                        LDB_ERR_UNWILLING_TO_PERFORM);
1256         }
1257         talloc_free(nc_root);
1258
1259         if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
1260                 ret = dsdb_module_check_access_on_dn(module, req,
1261                                                      req->op.del.dn,
1262                                                      SEC_ADS_DELETE_TREE, NULL,
1263                                                      req);
1264                 if (ret != LDB_SUCCESS) {
1265                         return ret;
1266                 }
1267
1268                 return ldb_next_request(module, req);
1269         }
1270
1271         /* First check if we have delete object right */
1272         ret = dsdb_module_check_access_on_dn(module, req, req->op.del.dn,
1273                                              SEC_STD_DELETE, NULL, req);
1274         if (ret == LDB_SUCCESS) {
1275                 return ldb_next_request(module, req);
1276         }
1277
1278         /* Nope, we don't have delete object. Lets check if we have delete
1279          * child on the parent */
1280         ret = dsdb_module_check_access_on_dn(module, req, parent,
1281                                              SEC_ADS_DELETE_CHILD, NULL, req);
1282         if (ret != LDB_SUCCESS) {
1283                 return ret;
1284         }
1285
1286         return ldb_next_request(module, req);
1287 }
1288
1289 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
1290 {
1291         int ret;
1292         struct ldb_dn *oldparent;
1293         struct ldb_dn *newparent;
1294         const struct dsdb_schema *schema;
1295         struct ldb_context *ldb;
1296         struct security_descriptor *sd = NULL;
1297         struct dom_sid *sid = NULL;
1298         struct ldb_result *acl_res;
1299         const struct GUID *guid;
1300         struct ldb_dn *nc_root;
1301         struct object_tree *root = NULL;
1302         struct object_tree *new_node = NULL;
1303         struct ldb_control *as_system;
1304         TALLOC_CTX *tmp_ctx;
1305         NTSTATUS status;
1306         uint32_t access_granted;
1307         const char *rdn_name;
1308         static const char *acl_attrs[] = {
1309                 "nTSecurityDescriptor",
1310                 "objectClass",
1311                 "objectSid",
1312                 NULL
1313         };
1314
1315         if (ldb_dn_is_special(req->op.rename.olddn)) {
1316                 return ldb_next_request(module, req);
1317         }
1318
1319         as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1320         if (as_system != NULL) {
1321                 as_system->critical = 0;
1322         }
1323
1324         DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
1325         if (dsdb_module_am_system(module) || as_system) {
1326                 return ldb_next_request(module, req);
1327         }
1328
1329         ldb = ldb_module_get_ctx(module);
1330
1331         tmp_ctx = talloc_new(req);
1332         if (tmp_ctx == NULL) {
1333                 return ldb_oom(ldb);
1334         }
1335
1336         oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
1337         if (oldparent == NULL) {
1338                 return ldb_oom(ldb);
1339         }
1340         newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
1341         if (newparent == NULL) {
1342                 return ldb_oom(ldb);
1343         }
1344
1345         /* Make sure we aren't renaming/moving a NC */
1346
1347         ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
1348         if (ret != LDB_SUCCESS) {
1349                 return ret;
1350         }
1351         if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
1352                 talloc_free(nc_root);
1353                 DEBUG(10,("acl:renaming/moving a NC\n"));
1354                 /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1355                 return ldb_module_done(req, NULL, NULL,
1356                                        LDB_ERR_UNWILLING_TO_PERFORM);
1357         }
1358         talloc_free(nc_root);
1359
1360         /* Look for the parent */
1361
1362         ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
1363                                     req->op.rename.olddn, acl_attrs,
1364                                     DSDB_FLAG_NEXT_MODULE |
1365                                     DSDB_FLAG_AS_SYSTEM |
1366                                     DSDB_SEARCH_SHOW_RECYCLED, req);
1367         /* we sould be able to find the parent */
1368         if (ret != LDB_SUCCESS) {
1369                 DEBUG(10,("acl: failed to find object %s\n",
1370                           ldb_dn_get_linearized(req->op.rename.olddn)));
1371                 talloc_free(tmp_ctx);
1372                 return ret;
1373         }
1374
1375         schema = dsdb_get_schema(ldb, acl_res);
1376         if (!schema) {
1377                 talloc_free(tmp_ctx);
1378                 return ldb_operr(ldb);
1379         }
1380
1381         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1382         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1383                                    &root, &new_node)) {
1384                 talloc_free(tmp_ctx);
1385                 return ldb_operr(ldb);
1386         };
1387
1388         guid = attribute_schemaid_guid_by_lDAPDisplayName(schema,
1389                                                           "name");
1390         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1391                                    &new_node, &new_node)) {
1392                 talloc_free(tmp_ctx);
1393                 return ldb_operr(ldb);
1394         };
1395
1396         rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
1397         if (rdn_name == NULL) {
1398                 talloc_free(tmp_ctx);
1399                 return ldb_operr(ldb);
1400         }
1401         guid = attribute_schemaid_guid_by_lDAPDisplayName(schema,
1402                                                           rdn_name);
1403         if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
1404                                    &new_node, &new_node)) {
1405                 talloc_free(tmp_ctx);
1406                 return ldb_operr(ldb);
1407         };
1408
1409         ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1410
1411         if (ret != LDB_SUCCESS) {
1412                 talloc_free(tmp_ctx);
1413                 return ldb_operr(ldb);
1414         }
1415         /* Theoretically we pass the check if the object has no sd */
1416         if (!sd) {
1417                 talloc_free(tmp_ctx);
1418                 return LDB_SUCCESS;
1419         }
1420         sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1421         status = sec_access_check_ds(sd, acl_user_token(module),
1422                                      SEC_ADS_WRITE_PROP,
1423                                      &access_granted,
1424                                      root,
1425                                      sid);
1426
1427         if (!NT_STATUS_IS_OK(status)) {
1428                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1429                                        "Object %s has no wp on name\n",
1430                                        ldb_dn_get_linearized(req->op.rename.olddn));
1431                 dsdb_acl_debug(sd,
1432                           acl_user_token(module),
1433                           req->op.rename.olddn,
1434                           true,
1435                           10);
1436                 talloc_free(tmp_ctx);
1437                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1438         }
1439
1440         if (ldb_dn_compare(oldparent, newparent) == 0) {
1441                 /* regular rename, not move, nothing more to do */
1442                 talloc_free(tmp_ctx);
1443                 return ldb_next_request(module, req);
1444         }
1445
1446         /* new parent should have create child */
1447         root = NULL;
1448         new_node = NULL;
1449         guid = get_oc_guid_from_message(schema, acl_res->msgs[0]);
1450         if (!guid) {
1451                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1452                                        "acl:renamed object has no object class\n");
1453                 talloc_free(tmp_ctx);
1454                 return ldb_module_done(req, NULL, NULL,  LDB_ERR_OPERATIONS_ERROR);
1455         }
1456
1457         ret = dsdb_module_check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, guid, req);
1458         if (ret != LDB_SUCCESS) {
1459                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1460                                        "acl:access_denied renaming %s",
1461                                        ldb_dn_get_linearized(req->op.rename.olddn));
1462                 talloc_free(tmp_ctx);
1463                 return ret;
1464         }
1465         /* do we have delete object on the object? */
1466
1467         status = sec_access_check_ds(sd, acl_user_token(module),
1468                                      SEC_STD_DELETE,
1469                                      &access_granted,
1470                                      NULL,
1471                                      sid);
1472
1473         if (NT_STATUS_IS_OK(status)) {
1474                 talloc_free(tmp_ctx);
1475                 return ldb_next_request(module, req);
1476         }
1477         /* what about delete child on the current parent */
1478         ret = dsdb_module_check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL, req);
1479         if (ret != LDB_SUCCESS) {
1480                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1481                                        "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
1482                 talloc_free(tmp_ctx);
1483                 return ldb_module_done(req, NULL, NULL, ret);
1484         }
1485
1486         talloc_free(tmp_ctx);
1487
1488         return ldb_next_request(module, req);
1489 }
1490
1491 static int acl_search_update_confidential_attrs(struct acl_context *ac,
1492                                                 struct acl_private *data)
1493 {
1494         struct dsdb_attribute *a;
1495         uint32_t n = 0;
1496
1497         if (data->acl_search) {
1498                 /*
1499                  * If acl:search is activated, the acl_read module
1500                  * protects confidential attributes.
1501                  */
1502                 return LDB_SUCCESS;
1503         }
1504
1505         if ((ac->schema == data->cached_schema_ptr) &&
1506             (ac->schema->loaded_usn == data->cached_schema_loaded_usn) &&
1507             (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
1508         {
1509                 return LDB_SUCCESS;
1510         }
1511
1512         data->cached_schema_ptr = NULL;
1513         data->cached_schema_loaded_usn = 0;
1514         data->cached_schema_metadata_usn = 0;
1515         TALLOC_FREE(data->confidential_attrs);
1516
1517         if (ac->schema == NULL) {
1518                 return LDB_SUCCESS;
1519         }
1520
1521         for (a = ac->schema->attributes; a; a = a->next) {
1522                 const char **attrs = data->confidential_attrs;
1523
1524                 if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
1525                         continue;
1526                 }
1527
1528                 attrs = talloc_realloc(data, attrs, const char *, n + 2);
1529                 if (attrs == NULL) {
1530                         TALLOC_FREE(data->confidential_attrs);
1531                         return ldb_module_oom(ac->module);
1532                 }
1533
1534                 attrs[n] = a->lDAPDisplayName;
1535                 attrs[n+1] = NULL;
1536                 n++;
1537
1538                 data->confidential_attrs = attrs;
1539         }
1540
1541         data->cached_schema_ptr = ac->schema;
1542         data->cached_schema_loaded_usn = ac->schema->loaded_usn;
1543         data->cached_schema_metadata_usn = ac->schema->metadata_usn;
1544
1545         return LDB_SUCCESS;
1546 }
1547
1548 static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1549 {
1550         struct acl_context *ac;
1551         struct acl_private *data;
1552         struct ldb_result *acl_res;
1553         static const char *acl_attrs[] = {
1554                 "objectClass",
1555                 "nTSecurityDescriptor",
1556                 "objectSid",
1557                 NULL
1558         };
1559         int ret;
1560         unsigned int i;
1561
1562         ac = talloc_get_type(req->context, struct acl_context);
1563         data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
1564         if (!ares) {
1565                 return ldb_module_done(ac->req, NULL, NULL,
1566                                        LDB_ERR_OPERATIONS_ERROR);
1567         }
1568         if (ares->error != LDB_SUCCESS) {
1569                 return ldb_module_done(ac->req, ares->controls,
1570                                        ares->response, ares->error);
1571         }
1572
1573         switch (ares->type) {
1574         case LDB_REPLY_ENTRY:
1575                 if (ac->constructed_attrs) {
1576                         ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn, 
1577                                                     acl_attrs,
1578                                                     DSDB_FLAG_NEXT_MODULE |
1579                                                     DSDB_FLAG_AS_SYSTEM |
1580                                                     DSDB_SEARCH_SHOW_RECYCLED,
1581                                                     req);
1582                         if (ret != LDB_SUCCESS) {
1583                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1584                         }
1585                 }
1586
1587                 if (ac->allowedAttributes || ac->allowedAttributesEffective) {
1588                         ret = acl_allowedAttributes(ac->module, ac->schema,
1589                                                     acl_res->msgs[0],
1590                                                     ares->message, ac);
1591                         if (ret != LDB_SUCCESS) {
1592                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1593                         }
1594                 }
1595
1596                 if (ac->allowedChildClasses) {
1597                         ret = acl_childClasses(ac->module, ac->schema,
1598                                                acl_res->msgs[0],
1599                                                ares->message,
1600                                                "allowedChildClasses");
1601                         if (ret != LDB_SUCCESS) {
1602                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1603                         }
1604                 }
1605
1606                 if (ac->allowedChildClassesEffective) {
1607                         ret = acl_childClassesEffective(ac->module, ac->schema,
1608                                                         acl_res->msgs[0],
1609                                                         ares->message, ac);
1610                         if (ret != LDB_SUCCESS) {
1611                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1612                         }
1613                 }
1614
1615                 if (ac->sDRightsEffective) {
1616                         ret = acl_sDRightsEffective(ac->module,
1617                                                     acl_res->msgs[0],
1618                                                     ares->message, ac);
1619                         if (ret != LDB_SUCCESS) {
1620                                 return ldb_module_done(ac->req, NULL, NULL, ret);
1621                         }
1622                 }
1623
1624                 if (data == NULL) {
1625                         return ldb_module_send_entry(ac->req, ares->message,
1626                                                      ares->controls);
1627                 }
1628
1629                 if (ac->am_system) {
1630                         return ldb_module_send_entry(ac->req, ares->message,
1631                                                      ares->controls);
1632                 }
1633
1634                 if (data->password_attrs != NULL) {
1635                         for (i = 0; data->password_attrs[i]; i++) {
1636                                 if ((!ac->userPassword) &&
1637                                     (ldb_attr_cmp(data->password_attrs[i],
1638                                                   "userPassword") == 0))
1639                                 {
1640                                                 continue;
1641                                 }
1642
1643                                 ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
1644                         }
1645                 }
1646
1647                 if (ac->am_administrator) {
1648                         return ldb_module_send_entry(ac->req, ares->message,
1649                                                      ares->controls);
1650                 }
1651
1652                 ret = acl_search_update_confidential_attrs(ac, data);
1653                 if (ret != LDB_SUCCESS) {
1654                         return ret;
1655                 }
1656
1657                 if (data->confidential_attrs != NULL) {
1658                         for (i = 0; data->confidential_attrs[i]; i++) {
1659                                 ldb_msg_remove_attr(ares->message,
1660                                                     data->confidential_attrs[i]);
1661                         }
1662                 }
1663
1664                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
1665
1666         case LDB_REPLY_REFERRAL:
1667                 return ldb_module_send_referral(ac->req, ares->referral);
1668
1669         case LDB_REPLY_DONE:
1670                 return ldb_module_done(ac->req, ares->controls,
1671                                        ares->response, LDB_SUCCESS);
1672
1673         }
1674         return LDB_SUCCESS;
1675 }
1676
1677 static int acl_search(struct ldb_module *module, struct ldb_request *req)
1678 {
1679         struct ldb_context *ldb;
1680         struct acl_context *ac;
1681         struct ldb_parse_tree *down_tree;
1682         struct ldb_request *down_req;
1683         struct acl_private *data;
1684         int ret;
1685         unsigned int i;
1686
1687         if (ldb_dn_is_special(req->op.search.base)) {
1688                 return ldb_next_request(module, req);
1689         }
1690
1691         ldb = ldb_module_get_ctx(module);
1692
1693         ac = talloc_zero(req, struct acl_context);
1694         if (ac == NULL) {
1695                 return ldb_oom(ldb);
1696         }
1697         data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
1698
1699         ac->module = module;
1700         ac->req = req;
1701         ac->am_system = dsdb_module_am_system(module);
1702         ac->am_administrator = dsdb_module_am_administrator(module);
1703         ac->constructed_attrs = false;
1704         ac->modify_search = true;
1705         ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
1706         ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
1707         ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
1708         ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
1709         ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
1710         ac->userPassword = true;
1711         ac->schema = dsdb_get_schema(ldb, ac);
1712
1713         ac->constructed_attrs |= ac->allowedAttributes;
1714         ac->constructed_attrs |= ac->allowedChildClasses;
1715         ac->constructed_attrs |= ac->allowedChildClassesEffective;
1716         ac->constructed_attrs |= ac->allowedAttributesEffective;
1717         ac->constructed_attrs |= ac->sDRightsEffective;
1718
1719         if (data == NULL) {
1720                 ac->modify_search = false;
1721         }
1722         if (ac->am_system) {
1723                 ac->modify_search = false;
1724         }
1725
1726         if (!ac->constructed_attrs && !ac->modify_search) {
1727                 talloc_free(ac);
1728                 return ldb_next_request(module, req);
1729         }
1730
1731         if (!ac->am_system) {
1732                 ac->userPassword = dsdb_user_password_support(module, ac, req);
1733         }
1734
1735         ret = acl_search_update_confidential_attrs(ac, data);
1736         if (ret != LDB_SUCCESS) {
1737                 return ret;
1738         }
1739
1740         down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
1741         if (down_tree == NULL) {
1742                 return ldb_oom(ldb);
1743         }
1744
1745         if (!ac->am_system && data->password_attrs) {
1746                 for (i = 0; data->password_attrs[i]; i++) {
1747                         if ((!ac->userPassword) &&
1748                             (ldb_attr_cmp(data->password_attrs[i],
1749                                           "userPassword") == 0))
1750                         {
1751                                 continue;
1752                         }
1753
1754                         ldb_parse_tree_attr_replace(down_tree,
1755                                                     data->password_attrs[i],
1756                                                     "kludgeACLredactedattribute");
1757                 }
1758         }
1759
1760         if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) {
1761                 for (i = 0; data->confidential_attrs[i]; i++) {
1762                         ldb_parse_tree_attr_replace(down_tree,
1763                                                     data->confidential_attrs[i],
1764                                                     "kludgeACLredactedattribute");
1765                 }
1766         }
1767
1768         ret = ldb_build_search_req_ex(&down_req,
1769                                       ldb, ac,
1770                                       req->op.search.base,
1771                                       req->op.search.scope,
1772                                       down_tree,
1773                                       req->op.search.attrs,
1774                                       req->controls,
1775                                       ac, acl_search_callback,
1776                                       req);
1777         LDB_REQ_SET_LOCATION(down_req);
1778         if (ret != LDB_SUCCESS) {
1779                 return ret;
1780         }
1781         /* perform the search */
1782         return ldb_next_request(module, down_req);
1783 }
1784
1785 static int acl_extended(struct ldb_module *module, struct ldb_request *req)
1786 {
1787         struct ldb_context *ldb = ldb_module_get_ctx(module);
1788         struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1789
1790         /* allow everybody to read the sequence number */
1791         if (strcmp(req->op.extended.oid,
1792                    LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1793                 return ldb_next_request(module, req);
1794         }
1795
1796         if (dsdb_module_am_system(module) ||
1797             dsdb_module_am_administrator(module) || as_system) {
1798                 return ldb_next_request(module, req);
1799         } else {
1800                 ldb_asprintf_errstring(ldb,
1801                                        "acl_extended: "
1802                                        "attempted database modify not permitted. "
1803                                        "User %s is not SYSTEM or an administrator",
1804                                        acl_user_name(req, module));
1805                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1806         }
1807 }
1808
1809 static const struct ldb_module_ops ldb_acl_module_ops = {
1810         .name              = "acl",
1811         .search            = acl_search,
1812         .add               = acl_add,
1813         .modify            = acl_modify,
1814         .del               = acl_delete,
1815         .rename            = acl_rename,
1816         .extended          = acl_extended,
1817         .init_context      = acl_module_init
1818 };
1819
1820 int ldb_acl_module_init(const char *version)
1821 {
1822         LDB_MODULE_CHECK_VERSION(version);
1823         return ldb_register_module(&ldb_acl_module_ops);
1824 }