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