Line data Source code
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 : #undef strcasecmp
47 : #undef strncasecmp
48 :
49 : struct acl_private {
50 : bool acl_search;
51 : const char **password_attrs;
52 : void *cached_schema_ptr;
53 : uint64_t cached_schema_metadata_usn;
54 : uint64_t cached_schema_loaded_usn;
55 : const char **confidential_attrs;
56 : };
57 :
58 : struct acl_context {
59 : struct ldb_module *module;
60 : struct ldb_request *req;
61 : bool am_system;
62 : bool am_administrator;
63 : bool constructed_attrs;
64 : bool allowedAttributes;
65 : bool allowedAttributesEffective;
66 : bool allowedChildClasses;
67 : bool allowedChildClassesEffective;
68 : bool sDRightsEffective;
69 : struct dsdb_schema *schema;
70 : };
71 :
72 180956 : static int acl_module_init(struct ldb_module *module)
73 : {
74 6012 : struct ldb_context *ldb;
75 6012 : struct acl_private *data;
76 6012 : int ret;
77 :
78 180956 : ldb = ldb_module_get_ctx(module);
79 :
80 180956 : data = talloc_zero(module, struct acl_private);
81 180956 : if (data == NULL) {
82 0 : return ldb_oom(ldb);
83 : }
84 :
85 180956 : data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
86 : NULL, "acl", "search", true);
87 180956 : ldb_module_set_private(module, data);
88 :
89 180956 : ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
90 180956 : if (ret != LDB_SUCCESS) {
91 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
92 : "acl_module_init: Unable to register control with rootdse!\n");
93 0 : return ldb_operr(ldb);
94 : }
95 :
96 180956 : return ldb_next_init(module);
97 : }
98 :
99 22 : static int acl_allowedAttributes(struct ldb_module *module,
100 : const struct dsdb_schema *schema,
101 : struct ldb_message *sd_msg,
102 : struct ldb_message *msg,
103 : struct acl_context *ac)
104 : {
105 0 : struct ldb_message_element *oc_el;
106 22 : struct ldb_context *ldb = ldb_module_get_ctx(module);
107 0 : TALLOC_CTX *mem_ctx;
108 0 : const char **attr_list;
109 0 : int i, ret;
110 0 : const struct dsdb_class *objectclass;
111 :
112 : /* If we don't have a schema yet, we can't do anything... */
113 22 : if (schema == NULL) {
114 0 : ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
115 0 : return LDB_ERR_OPERATIONS_ERROR;
116 : }
117 :
118 : /* Must remove any existing attribute */
119 22 : if (ac->allowedAttributes) {
120 4 : ldb_msg_remove_attr(msg, "allowedAttributes");
121 : }
122 :
123 22 : mem_ctx = talloc_new(msg);
124 22 : if (!mem_ctx) {
125 0 : return ldb_oom(ldb);
126 : }
127 :
128 22 : oc_el = ldb_msg_find_element(sd_msg, "objectClass");
129 22 : attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
130 22 : if (!attr_list) {
131 0 : ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
132 0 : talloc_free(mem_ctx);
133 0 : return LDB_ERR_OPERATIONS_ERROR;
134 : }
135 :
136 : /*
137 : * Get the top-most structural object class for the ACL check
138 : */
139 22 : objectclass = dsdb_get_last_structural_class(ac->schema,
140 : oc_el);
141 22 : if (objectclass == NULL) {
142 0 : ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
143 : ldb_dn_get_linearized(sd_msg->dn));
144 0 : talloc_free(mem_ctx);
145 0 : return LDB_ERR_OPERATIONS_ERROR;
146 : }
147 :
148 22 : if (ac->allowedAttributes) {
149 972 : for (i=0; attr_list && attr_list[i]; i++) {
150 968 : ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
151 : }
152 : }
153 22 : if (ac->allowedAttributesEffective) {
154 0 : struct security_descriptor *sd;
155 22 : struct dom_sid *sid = NULL;
156 22 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
157 : LDB_CONTROL_AS_SYSTEM_OID);
158 :
159 22 : if (as_system != NULL) {
160 0 : as_system->critical = 0;
161 : }
162 :
163 22 : ldb_msg_remove_attr(msg, "allowedAttributesEffective");
164 22 : if (ac->am_system || as_system) {
165 0 : for (i=0; attr_list && attr_list[i]; i++) {
166 0 : ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
167 : }
168 0 : return LDB_SUCCESS;
169 : }
170 :
171 22 : ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
172 :
173 22 : if (ret != LDB_SUCCESS) {
174 0 : return ret;
175 : }
176 :
177 22 : sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
178 3608 : for (i=0; attr_list && attr_list[i]; i++) {
179 3586 : const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
180 3586 : attr_list[i]);
181 3586 : if (!attr) {
182 0 : return ldb_operr(ldb);
183 : }
184 : /* remove constructed attributes */
185 3586 : if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
186 3044 : || attr->systemOnly
187 1712 : || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
188 2002 : continue;
189 : }
190 1584 : ret = acl_check_access_on_attribute(module,
191 : msg,
192 : sd,
193 : sid,
194 : SEC_ADS_WRITE_PROP,
195 : attr,
196 : objectclass);
197 1584 : if (ret == LDB_SUCCESS) {
198 552 : ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
199 : }
200 : }
201 : }
202 22 : return LDB_SUCCESS;
203 : }
204 :
205 0 : static int acl_childClasses(struct ldb_module *module,
206 : const struct dsdb_schema *schema,
207 : struct ldb_message *sd_msg,
208 : struct ldb_message *msg,
209 : const char *attrName)
210 : {
211 0 : struct ldb_message_element *oc_el;
212 0 : struct ldb_message_element *allowedClasses;
213 0 : const struct dsdb_class *sclass;
214 0 : unsigned int i, j;
215 0 : int ret;
216 :
217 : /* If we don't have a schema yet, we can't do anything... */
218 0 : if (schema == NULL) {
219 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add childClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
220 0 : return LDB_ERR_OPERATIONS_ERROR;
221 : }
222 :
223 : /* Must remove any existing attribute, or else confusion reigns */
224 0 : ldb_msg_remove_attr(msg, attrName);
225 0 : ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
226 0 : if (ret != LDB_SUCCESS) {
227 0 : return ret;
228 : }
229 :
230 0 : oc_el = ldb_msg_find_element(sd_msg, "objectClass");
231 :
232 0 : for (i=0; oc_el && i < oc_el->num_values; i++) {
233 0 : sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
234 0 : if (!sclass) {
235 : /* We don't know this class? what is going on? */
236 0 : continue;
237 : }
238 :
239 0 : for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
240 0 : ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
241 : }
242 : }
243 0 : if (allowedClasses->num_values > 1) {
244 0 : TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
245 0 : for (i=1 ; i < allowedClasses->num_values; i++) {
246 0 : struct ldb_val *val1 = &allowedClasses->values[i-1];
247 0 : struct ldb_val *val2 = &allowedClasses->values[i];
248 0 : if (data_blob_cmp(val1, val2) == 0) {
249 0 : memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
250 0 : allowedClasses->num_values--;
251 0 : i--;
252 : }
253 : }
254 : }
255 :
256 0 : return LDB_SUCCESS;
257 : }
258 :
259 18 : static int acl_childClassesEffective(struct ldb_module *module,
260 : const struct dsdb_schema *schema,
261 : struct ldb_message *sd_msg,
262 : struct ldb_message *msg,
263 : struct acl_context *ac)
264 : {
265 0 : struct ldb_message_element *oc_el;
266 18 : struct ldb_message_element *allowedClasses = NULL;
267 0 : const struct dsdb_class *sclass;
268 0 : struct security_descriptor *sd;
269 18 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
270 : LDB_CONTROL_AS_SYSTEM_OID);
271 18 : struct dom_sid *sid = NULL;
272 0 : unsigned int i, j;
273 0 : int ret;
274 :
275 18 : if (as_system != NULL) {
276 0 : as_system->critical = 0;
277 : }
278 :
279 18 : if (ac->am_system || as_system) {
280 0 : return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
281 : }
282 :
283 : /* If we don't have a schema yet, we can't do anything... */
284 18 : if (schema == NULL) {
285 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module), "cannot add allowedChildClassesEffective to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
286 0 : return LDB_ERR_OPERATIONS_ERROR;
287 : }
288 :
289 : /* Must remove any existing attribute, or else confusion reigns */
290 18 : ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
291 :
292 18 : oc_el = ldb_msg_find_element(sd_msg, "objectClass");
293 18 : ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
294 18 : if (ret != LDB_SUCCESS) {
295 0 : return ret;
296 : }
297 :
298 18 : sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
299 54 : for (i=0; oc_el && i < oc_el->num_values; i++) {
300 36 : sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
301 36 : if (!sclass) {
302 : /* We don't know this class? what is going on? */
303 0 : continue;
304 : }
305 :
306 1700 : for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
307 0 : const struct dsdb_class *sc;
308 :
309 1664 : sc = dsdb_class_by_lDAPDisplayName(schema,
310 1664 : sclass->possibleInferiors[j]);
311 1664 : if (!sc) {
312 : /* We don't know this class? what is going on? */
313 0 : continue;
314 : }
315 :
316 1664 : ret = acl_check_access_on_objectclass(module, ac,
317 : sd, sid,
318 : SEC_ADS_CREATE_CHILD,
319 : sc);
320 1664 : if (ret == LDB_SUCCESS) {
321 9 : ldb_msg_add_string(msg, "allowedChildClassesEffective",
322 9 : sclass->possibleInferiors[j]);
323 : }
324 : }
325 : }
326 18 : allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
327 18 : if (!allowedClasses) {
328 9 : return LDB_SUCCESS;
329 : }
330 :
331 9 : if (allowedClasses->num_values > 1) {
332 0 : TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
333 0 : for (i=1 ; i < allowedClasses->num_values; i++) {
334 0 : struct ldb_val *val1 = &allowedClasses->values[i-1];
335 0 : struct ldb_val *val2 = &allowedClasses->values[i];
336 0 : if (data_blob_cmp(val1, val2) == 0) {
337 0 : memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
338 0 : allowedClasses->num_values--;
339 0 : i--;
340 : }
341 : }
342 : }
343 9 : return LDB_SUCCESS;
344 : }
345 :
346 306 : static int acl_sDRightsEffective(struct ldb_module *module,
347 : struct ldb_message *sd_msg,
348 : struct ldb_message *msg,
349 : struct acl_context *ac)
350 : {
351 306 : struct ldb_context *ldb = ldb_module_get_ctx(module);
352 0 : struct ldb_message_element *rightsEffective;
353 0 : int ret;
354 0 : struct security_descriptor *sd;
355 306 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
356 : LDB_CONTROL_AS_SYSTEM_OID);
357 306 : struct dom_sid *sid = NULL;
358 306 : uint32_t flags = 0;
359 :
360 306 : if (as_system != NULL) {
361 0 : as_system->critical = 0;
362 : }
363 :
364 : /* Must remove any existing attribute, or else confusion reigns */
365 306 : ldb_msg_remove_attr(msg, "sDRightsEffective");
366 306 : ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
367 306 : if (ret != LDB_SUCCESS) {
368 0 : return ret;
369 : }
370 306 : if (ac->am_system || as_system) {
371 0 : flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL;
372 : } else {
373 0 : const struct dsdb_class *objectclass;
374 0 : const struct dsdb_attribute *attr;
375 :
376 306 : objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
377 306 : if (objectclass == NULL) {
378 0 : return ldb_operr(ldb);
379 : }
380 :
381 306 : attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
382 : "nTSecurityDescriptor");
383 306 : if (attr == NULL) {
384 0 : return ldb_operr(ldb);
385 : }
386 :
387 : /* Get the security descriptor from the message */
388 306 : ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
389 306 : if (ret != LDB_SUCCESS) {
390 0 : return ret;
391 : }
392 306 : sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
393 306 : ret = acl_check_access_on_attribute(module,
394 : msg,
395 : sd,
396 : sid,
397 : SEC_STD_WRITE_OWNER,
398 : attr,
399 : objectclass);
400 306 : if (ret == LDB_SUCCESS) {
401 108 : flags |= SECINFO_OWNER | SECINFO_GROUP;
402 : }
403 :
404 : /*
405 : * This call is made with
406 : * IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS
407 : * and without reference to the dSHeuristics via
408 : * dsdb_block_owner_implicit_rights(). This is
409 : * probably a Windows bug but for now we match
410 : * exactly.
411 : */
412 306 : ret = acl_check_access_on_attribute_implicit_owner(
413 : module,
414 : msg,
415 : sd,
416 : sid,
417 : SEC_STD_WRITE_DAC,
418 : attr,
419 : objectclass,
420 : IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
421 306 : if (ret == LDB_SUCCESS) {
422 72 : flags |= SECINFO_DACL;
423 : }
424 306 : ret = acl_check_access_on_attribute(module,
425 : msg,
426 : sd,
427 : sid,
428 : SEC_FLAG_SYSTEM_SECURITY,
429 : attr,
430 : objectclass);
431 306 : if (ret == LDB_SUCCESS) {
432 9 : flags |= SECINFO_SACL;
433 : }
434 : }
435 :
436 306 : if (flags != (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_SACL)) {
437 297 : const struct ldb_message_element *el = samdb_find_attribute(ldb,
438 : sd_msg,
439 : "objectclass",
440 : "computer");
441 297 : if (el != NULL) {
442 144 : return LDB_SUCCESS;
443 : }
444 : }
445 :
446 162 : return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
447 : "sDRightsEffective", flags);
448 : }
449 :
450 577 : static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
451 : struct ldb_context *ldb,
452 : const struct ldb_val *spn_value,
453 : uint32_t userAccountControl,
454 : const struct ldb_val *samAccountName,
455 : const struct ldb_val *dnsHostName,
456 : const char *netbios_name,
457 : const char *ntds_guid)
458 : {
459 0 : krb5_error_code ret, princ_size;
460 0 : krb5_context krb_ctx;
461 0 : krb5_error_code kerr;
462 0 : krb5_principal principal;
463 577 : char *instanceName = NULL;
464 577 : char *serviceType = NULL;
465 577 : char *serviceName = NULL;
466 577 : const char *spn_value_str = NULL;
467 0 : size_t account_name_len;
468 577 : const char *forest_name = samdb_forest_name(ldb, mem_ctx);
469 577 : const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
470 577 : struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
471 : struct loadparm_context);
472 956 : bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
473 379 : (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
474 :
475 577 : spn_value_str = talloc_strndup(mem_ctx,
476 577 : (const char *)spn_value->data,
477 577 : spn_value->length);
478 577 : if (spn_value_str == NULL) {
479 0 : return ldb_oom(ldb);
480 : }
481 :
482 577 : if (spn_value->length == samAccountName->length &&
483 0 : strncasecmp((const char *)spn_value->data,
484 0 : (const char *)samAccountName->data,
485 0 : spn_value->length) == 0)
486 : {
487 : /* MacOS X sets this value, and setting an SPN of your
488 : * own samAccountName is both pointless and safe */
489 0 : return LDB_SUCCESS;
490 : }
491 :
492 577 : kerr = smb_krb5_init_context_basic(mem_ctx,
493 : lp_ctx,
494 : &krb_ctx);
495 577 : if (kerr != 0) {
496 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
497 : "Could not initialize kerberos context.");
498 : }
499 :
500 577 : ret = krb5_parse_name(krb_ctx, spn_value_str, &principal);
501 577 : if (ret) {
502 0 : krb5_free_context(krb_ctx);
503 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
504 : }
505 :
506 577 : princ_size = krb5_princ_size(krb_ctx, principal);
507 577 : if (princ_size < 2) {
508 0 : DBG_WARNING("princ_size=%d\n", princ_size);
509 0 : goto fail;
510 : }
511 :
512 577 : ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
513 : principal, 1, &instanceName);
514 577 : if (ret) {
515 0 : goto fail;
516 : }
517 577 : ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
518 : principal, 0, &serviceType);
519 577 : if (ret) {
520 0 : goto fail;
521 : }
522 577 : if (krb5_princ_size(krb_ctx, principal) == 3) {
523 427 : ret = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
524 : principal, 2, &serviceName);
525 427 : if (ret) {
526 0 : goto fail;
527 : }
528 : }
529 :
530 577 : if (serviceName) {
531 427 : if (!is_dc) {
532 99 : DBG_WARNING("is_dc=false, serviceName=%s,"
533 : "serviceType=%s\n", serviceName,
534 : serviceType);
535 99 : goto fail;
536 : }
537 328 : if (strcasecmp(serviceType, "ldap") == 0) {
538 110 : if (strcasecmp(serviceName, netbios_name) != 0 &&
539 73 : strcasecmp(serviceName, forest_name) != 0) {
540 36 : DBG_WARNING("serviceName=%s\n", serviceName);
541 36 : goto fail;
542 : }
543 :
544 218 : } else if (strcasecmp(serviceType, "gc") == 0) {
545 36 : if (strcasecmp(serviceName, forest_name) != 0) {
546 18 : DBG_WARNING("serviceName=%s\n", serviceName);
547 18 : goto fail;
548 : }
549 : } else {
550 182 : if (strcasecmp(serviceName, base_domain) != 0 &&
551 55 : strcasecmp(serviceName, netbios_name) != 0) {
552 18 : DBG_WARNING("serviceType=%s, "
553 : "serviceName=%s\n",
554 : serviceType, serviceName);
555 18 : goto fail;
556 : }
557 : }
558 : }
559 :
560 406 : account_name_len = samAccountName->length;
561 406 : if (account_name_len &&
562 406 : samAccountName->data[account_name_len - 1] == '$')
563 : {
564 : /* Account for the '$' character. */
565 406 : --account_name_len;
566 : }
567 :
568 : /* instanceName can be samAccountName without $ or dnsHostName
569 : * or "ntds_guid._msdcs.forest_domain for DC objects */
570 406 : if (strlen(instanceName) == account_name_len
571 214 : && strncasecmp(instanceName,
572 214 : (const char *)samAccountName->data,
573 : account_name_len) == 0)
574 : {
575 214 : goto success;
576 : }
577 192 : if ((dnsHostName != NULL) &&
578 192 : strlen(instanceName) == dnsHostName->length &&
579 146 : (strncasecmp(instanceName,
580 146 : (const char *)dnsHostName->data,
581 146 : dnsHostName->length) == 0))
582 : {
583 146 : goto success;
584 : }
585 46 : if (is_dc) {
586 37 : const char *guid_str = NULL;
587 37 : guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
588 : ntds_guid,
589 : forest_name);
590 37 : if (strcasecmp(instanceName, guid_str) == 0) {
591 19 : goto success;
592 : }
593 : }
594 :
595 27 : fail:
596 198 : krb5_free_principal(krb_ctx, principal);
597 198 : krb5_free_context(krb_ctx);
598 198 : ldb_debug_set(ldb, LDB_DEBUG_WARNING,
599 : "acl: spn validation failed for "
600 : "spn[%.*s] uac[0x%x] account[%.*s] hostname[%.*s] "
601 : "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
602 198 : (int)spn_value->length, spn_value->data,
603 : (unsigned)userAccountControl,
604 198 : (int)samAccountName->length, samAccountName->data,
605 180 : dnsHostName != NULL ? (int)dnsHostName->length : 0,
606 : dnsHostName != NULL ? (const char *)dnsHostName->data : "",
607 : netbios_name, ntds_guid,
608 : forest_name, base_domain);
609 198 : return LDB_ERR_CONSTRAINT_VIOLATION;
610 :
611 379 : success:
612 379 : krb5_free_principal(krb_ctx, principal);
613 379 : krb5_free_context(krb_ctx);
614 379 : return LDB_SUCCESS;
615 : }
616 :
617 : /*
618 : * Passing in 'el' is critical, we want to check all the values.
619 : *
620 : */
621 2203 : static int acl_check_spn(TALLOC_CTX *mem_ctx,
622 : struct ldb_module *module,
623 : struct ldb_request *req,
624 : const struct ldb_message_element *el,
625 : struct security_descriptor *sd,
626 : struct dom_sid *sid,
627 : const struct dsdb_attribute *attr,
628 : const struct dsdb_class *objectclass,
629 : const struct ldb_control *implicit_validated_write_control)
630 : {
631 74 : int ret;
632 74 : unsigned int i;
633 2203 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
634 2203 : struct ldb_context *ldb = ldb_module_get_ctx(module);
635 74 : struct ldb_result *acl_res;
636 74 : struct ldb_result *netbios_res;
637 2203 : struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
638 74 : uint32_t userAccountControl;
639 74 : const char *netbios_name;
640 2203 : const struct ldb_val *dns_host_name_val = NULL;
641 2203 : const struct ldb_val *sam_account_name_val = NULL;
642 74 : struct GUID ntds;
643 2203 : char *ntds_guid = NULL;
644 2203 : const struct ldb_message *msg = NULL;
645 2203 : const struct ldb_message *search_res = NULL;
646 :
647 74 : static const char *acl_attrs[] = {
648 : "samAccountName",
649 : "dnsHostName",
650 : "userAccountControl",
651 : NULL
652 : };
653 74 : static const char *netbios_attrs[] = {
654 : "nETBIOSName",
655 : NULL
656 : };
657 :
658 2203 : if (req->operation == LDB_MODIFY) {
659 2167 : msg = req->op.mod.message;
660 36 : } else if (req->operation == LDB_ADD) {
661 36 : msg = req->op.add.message;
662 : }
663 :
664 2203 : if (implicit_validated_write_control != NULL) {
665 : /*
666 : * The validated write control dispenses with ACL
667 : * checks. We act as if we have an implicit Self Write
668 : * privilege, but, assuming we don't have Write
669 : * Property, still proceed with further validation
670 : * checks.
671 : */
672 : } else {
673 : /* if we have wp, we can do whatever we like */
674 2197 : if (acl_check_access_on_attribute(module,
675 : tmp_ctx,
676 : sd,
677 : sid,
678 : SEC_ADS_WRITE_PROP,
679 : attr, objectclass) == LDB_SUCCESS) {
680 1526 : talloc_free(tmp_ctx);
681 1526 : return LDB_SUCCESS;
682 : }
683 :
684 671 : ret = acl_check_extended_right(tmp_ctx,
685 : module,
686 : req,
687 : objectclass,
688 : sd,
689 : acl_user_token(module),
690 : GUID_DRS_VALIDATE_SPN,
691 : SEC_ADS_SELF_WRITE,
692 : sid);
693 :
694 671 : if (ret != LDB_SUCCESS) {
695 94 : dsdb_acl_debug(sd, acl_user_token(module),
696 94 : msg->dn,
697 : true,
698 : 10);
699 94 : talloc_free(tmp_ctx);
700 94 : return ret;
701 : }
702 : }
703 :
704 : /*
705 : * If we have "validated write spn", allow delete of any
706 : * existing value (this keeps constrained delete to the same
707 : * rules as unconstrained)
708 : */
709 583 : if (req->operation == LDB_MODIFY) {
710 : /*
711 : * If not add or replace (eg delete),
712 : * return success
713 : */
714 565 : if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
715 501 : LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
716 : {
717 18 : talloc_free(tmp_ctx);
718 18 : return LDB_SUCCESS;
719 : }
720 :
721 547 : ret = dsdb_module_search_dn(module, tmp_ctx,
722 547 : &acl_res, msg->dn,
723 : acl_attrs,
724 : DSDB_FLAG_NEXT_MODULE |
725 : DSDB_FLAG_AS_SYSTEM |
726 : DSDB_SEARCH_SHOW_RECYCLED,
727 : req);
728 547 : if (ret != LDB_SUCCESS) {
729 0 : talloc_free(tmp_ctx);
730 0 : return ret;
731 : }
732 :
733 547 : search_res = acl_res->msgs[0];
734 18 : } else if (req->operation == LDB_ADD) {
735 18 : search_res = msg;
736 : } else {
737 0 : talloc_free(tmp_ctx);
738 0 : return LDB_ERR_OPERATIONS_ERROR;
739 : }
740 :
741 565 : if (req->operation == LDB_MODIFY) {
742 547 : dns_host_name_val = ldb_msg_find_ldb_val(search_res, "dNSHostName");
743 : }
744 :
745 565 : ret = dsdb_msg_get_single_value(msg,
746 : "dNSHostName",
747 : dns_host_name_val,
748 : &dns_host_name_val,
749 : req->operation);
750 565 : if (ret != LDB_SUCCESS) {
751 0 : talloc_free(tmp_ctx);
752 0 : return ret;
753 : }
754 :
755 565 : userAccountControl = ldb_msg_find_attr_as_uint(search_res, "userAccountControl", 0);
756 :
757 565 : if (req->operation == LDB_MODIFY) {
758 547 : sam_account_name_val = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
759 : }
760 :
761 565 : ret = dsdb_msg_get_single_value(msg,
762 : "sAMAccountName",
763 : sam_account_name_val,
764 : &sam_account_name_val,
765 : req->operation);
766 565 : if (ret != LDB_SUCCESS) {
767 0 : talloc_free(tmp_ctx);
768 0 : return ret;
769 : }
770 :
771 565 : ret = dsdb_module_search(module, tmp_ctx,
772 : &netbios_res, partitions_dn,
773 : LDB_SCOPE_ONELEVEL,
774 : netbios_attrs,
775 : DSDB_FLAG_NEXT_MODULE |
776 : DSDB_FLAG_AS_SYSTEM,
777 : req,
778 : "(ncName=%s)",
779 : ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
780 :
781 565 : netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
782 :
783 : /*
784 : * NTDSDSA objectGuid of object we are checking SPN for
785 : *
786 : * Note - do we have the necessary attributes for this during an add operation?
787 : * How should we test this?
788 : */
789 565 : if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
790 397 : ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
791 397 : msg->dn, &ntds, req);
792 397 : if (ret != LDB_SUCCESS) {
793 0 : ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
794 0 : ldb_dn_get_linearized(msg->dn),
795 : ldb_strerror(ret));
796 0 : talloc_free(tmp_ctx);
797 0 : return LDB_ERR_OPERATIONS_ERROR;
798 : }
799 397 : ntds_guid = GUID_string(tmp_ctx, &ntds);
800 : }
801 :
802 944 : for (i=0; i < el->num_values; i++) {
803 577 : ret = acl_validate_spn_value(tmp_ctx,
804 : ldb,
805 577 : &el->values[i],
806 : userAccountControl,
807 : sam_account_name_val,
808 : dns_host_name_val,
809 : netbios_name,
810 : ntds_guid);
811 577 : if (ret != LDB_SUCCESS) {
812 198 : talloc_free(tmp_ctx);
813 198 : return ret;
814 : }
815 : }
816 367 : talloc_free(tmp_ctx);
817 367 : return LDB_SUCCESS;
818 : }
819 :
820 952 : static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
821 : struct ldb_module *module,
822 : struct ldb_request *req,
823 : const struct ldb_message_element *el,
824 : struct security_descriptor *sd,
825 : struct dom_sid *sid,
826 : const struct dsdb_attribute *attr,
827 : const struct dsdb_class *objectclass,
828 : const struct ldb_control *implicit_validated_write_control)
829 : {
830 75 : int ret;
831 75 : unsigned i;
832 952 : TALLOC_CTX *tmp_ctx = NULL;
833 952 : struct ldb_context *ldb = ldb_module_get_ctx(module);
834 952 : const struct dsdb_schema *schema = NULL;
835 952 : const struct ldb_message_element *allowed_suffixes = NULL;
836 952 : struct ldb_result *nc_res = NULL;
837 952 : struct ldb_dn *nc_root = NULL;
838 952 : const char *nc_dns_name = NULL;
839 952 : const char *dnsHostName_str = NULL;
840 75 : size_t dns_host_name_len;
841 75 : size_t account_name_len;
842 952 : const struct ldb_message *msg = NULL;
843 952 : const struct ldb_message *search_res = NULL;
844 952 : const struct ldb_val *samAccountName = NULL;
845 952 : const struct ldb_val *dnsHostName = NULL;
846 952 : const struct dsdb_class *computer_objectclass = NULL;
847 75 : bool is_subclass;
848 :
849 75 : static const char *nc_attrs[] = {
850 : "msDS-AllowedDNSSuffixes",
851 : NULL
852 : };
853 :
854 952 : tmp_ctx = talloc_new(mem_ctx);
855 952 : if (tmp_ctx == NULL) {
856 0 : return ldb_oom(ldb);
857 : }
858 :
859 952 : if (req->operation == LDB_MODIFY) {
860 952 : msg = req->op.mod.message;
861 0 : } else if (req->operation == LDB_ADD) {
862 0 : msg = req->op.add.message;
863 : }
864 :
865 952 : if (implicit_validated_write_control != NULL) {
866 : /*
867 : * The validated write control dispenses with ACL
868 : * checks. We act as if we have an implicit Self Write
869 : * privilege, but, assuming we don't have Write
870 : * Property, still proceed with further validation
871 : * checks.
872 : */
873 : } else {
874 : /* if we have wp, we can do whatever we like */
875 916 : ret = acl_check_access_on_attribute(module,
876 : tmp_ctx,
877 : sd,
878 : sid,
879 : SEC_ADS_WRITE_PROP,
880 : attr, objectclass);
881 916 : if (ret == LDB_SUCCESS) {
882 712 : talloc_free(tmp_ctx);
883 712 : return LDB_SUCCESS;
884 : }
885 :
886 204 : ret = acl_check_extended_right(tmp_ctx,
887 : module,
888 : req,
889 : objectclass,
890 : sd,
891 : acl_user_token(module),
892 : GUID_DRS_DNS_HOST_NAME,
893 : SEC_ADS_SELF_WRITE,
894 : sid);
895 :
896 204 : if (ret != LDB_SUCCESS) {
897 78 : dsdb_acl_debug(sd, acl_user_token(module),
898 78 : msg->dn,
899 : true,
900 : 10);
901 78 : talloc_free(tmp_ctx);
902 78 : return ret;
903 : }
904 : }
905 :
906 : /*
907 : * If we have "validated write dnshostname", allow delete of
908 : * any existing value (this keeps constrained delete to the
909 : * same rules as unconstrained)
910 : */
911 162 : if (req->operation == LDB_MODIFY) {
912 162 : struct ldb_result *acl_res = NULL;
913 :
914 3 : static const char *acl_attrs[] = {
915 : "sAMAccountName",
916 : NULL
917 : };
918 :
919 : /*
920 : * If not add or replace (eg delete),
921 : * return success
922 : */
923 162 : if ((el->flags
924 162 : & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0)
925 : {
926 0 : talloc_free(tmp_ctx);
927 0 : return LDB_SUCCESS;
928 : }
929 :
930 165 : ret = dsdb_module_search_dn(module, tmp_ctx,
931 162 : &acl_res, msg->dn,
932 : acl_attrs,
933 : DSDB_FLAG_NEXT_MODULE |
934 : DSDB_FLAG_AS_SYSTEM |
935 : DSDB_SEARCH_SHOW_RECYCLED,
936 : req);
937 162 : if (ret != LDB_SUCCESS) {
938 0 : talloc_free(tmp_ctx);
939 0 : return ret;
940 : }
941 :
942 162 : search_res = acl_res->msgs[0];
943 0 : } else if (req->operation == LDB_ADD) {
944 0 : search_res = msg;
945 : } else {
946 0 : talloc_free(tmp_ctx);
947 0 : return LDB_ERR_OPERATIONS_ERROR;
948 : }
949 :
950 : /* Check if the account has objectclass 'computer' or 'server'. */
951 :
952 162 : schema = dsdb_get_schema(ldb, req);
953 162 : if (schema == NULL) {
954 0 : talloc_free(tmp_ctx);
955 0 : return ldb_operr(ldb);
956 : }
957 :
958 162 : computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
959 162 : if (computer_objectclass == NULL) {
960 0 : talloc_free(tmp_ctx);
961 0 : return ldb_operr(ldb);
962 : }
963 :
964 162 : is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
965 162 : if (!is_subclass) {
966 : /* The account is not a computer -- check if it's a server. */
967 :
968 0 : const struct dsdb_class *server_objectclass = NULL;
969 :
970 0 : server_objectclass = dsdb_class_by_lDAPDisplayName(schema, "server");
971 0 : if (server_objectclass == NULL) {
972 0 : talloc_free(tmp_ctx);
973 0 : return ldb_operr(ldb);
974 : }
975 :
976 0 : is_subclass = dsdb_is_subclass_of(schema, objectclass, server_objectclass);
977 0 : if (!is_subclass) {
978 : /* Not a computer or server, so no need to validate. */
979 0 : talloc_free(tmp_ctx);
980 0 : return LDB_SUCCESS;
981 : }
982 : }
983 :
984 162 : if (req->operation == LDB_MODIFY) {
985 162 : samAccountName = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
986 : }
987 :
988 162 : ret = dsdb_msg_get_single_value(msg,
989 : "sAMAccountName",
990 : samAccountName,
991 : &samAccountName,
992 : req->operation);
993 162 : if (ret != LDB_SUCCESS) {
994 0 : talloc_free(tmp_ctx);
995 0 : return ret;
996 : }
997 :
998 162 : account_name_len = samAccountName->length;
999 162 : if (account_name_len && samAccountName->data[account_name_len - 1] == '$') {
1000 : /* Account for the '$' character. */
1001 153 : --account_name_len;
1002 : }
1003 :
1004 : /* Check for add or replace requests with no value. */
1005 162 : if (el->num_values == 0) {
1006 9 : talloc_free(tmp_ctx);
1007 9 : return ldb_operr(ldb);
1008 : }
1009 153 : dnsHostName = &el->values[0];
1010 :
1011 153 : dnsHostName_str = (const char *)dnsHostName->data;
1012 153 : dns_host_name_len = dnsHostName->length;
1013 :
1014 : /* Check that sAMAccountName matches the new dNSHostName. */
1015 :
1016 153 : if (dns_host_name_len < account_name_len) {
1017 18 : goto fail;
1018 : }
1019 135 : if (strncasecmp(dnsHostName_str,
1020 135 : (const char *)samAccountName->data,
1021 : account_name_len) != 0)
1022 : {
1023 24 : goto fail;
1024 : }
1025 :
1026 111 : dnsHostName_str += account_name_len;
1027 111 : dns_host_name_len -= account_name_len;
1028 :
1029 : /* Check the '.' character */
1030 :
1031 111 : if (dns_host_name_len == 0 || *dnsHostName_str != '.') {
1032 39 : goto fail;
1033 : }
1034 :
1035 72 : ++dnsHostName_str;
1036 72 : --dns_host_name_len;
1037 :
1038 : /* Now we check the suffix. */
1039 :
1040 72 : ret = dsdb_find_nc_root(ldb,
1041 : tmp_ctx,
1042 72 : search_res->dn,
1043 : &nc_root);
1044 72 : if (ret != LDB_SUCCESS) {
1045 0 : talloc_free(tmp_ctx);
1046 0 : return ret;
1047 : }
1048 :
1049 72 : nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root);
1050 72 : if (nc_dns_name == NULL) {
1051 0 : talloc_free(tmp_ctx);
1052 0 : return ldb_operr(ldb);
1053 : }
1054 :
1055 72 : if (strlen(nc_dns_name) == dns_host_name_len &&
1056 51 : strncasecmp(dnsHostName_str,
1057 : nc_dns_name,
1058 : dns_host_name_len) == 0)
1059 : {
1060 : /* It matches -- success. */
1061 51 : talloc_free(tmp_ctx);
1062 51 : return LDB_SUCCESS;
1063 : }
1064 :
1065 : /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */
1066 :
1067 21 : ret = dsdb_module_search_dn(module, tmp_ctx,
1068 : &nc_res, nc_root,
1069 : nc_attrs,
1070 : DSDB_FLAG_NEXT_MODULE |
1071 : DSDB_FLAG_AS_SYSTEM |
1072 : DSDB_SEARCH_SHOW_RECYCLED,
1073 : req);
1074 21 : if (ret != LDB_SUCCESS) {
1075 0 : talloc_free(tmp_ctx);
1076 0 : return ret;
1077 : }
1078 :
1079 21 : allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0],
1080 : "msDS-AllowedDNSSuffixes");
1081 21 : if (allowed_suffixes == NULL) {
1082 12 : goto fail;
1083 : }
1084 :
1085 9 : for (i = 0; i < allowed_suffixes->num_values; ++i) {
1086 9 : const struct ldb_val *suffix = &allowed_suffixes->values[i];
1087 :
1088 9 : if (suffix->length == dns_host_name_len &&
1089 9 : strncasecmp(dnsHostName_str,
1090 9 : (const char *)suffix->data,
1091 : dns_host_name_len) == 0)
1092 : {
1093 : /* It matches -- success. */
1094 9 : talloc_free(tmp_ctx);
1095 9 : return LDB_SUCCESS;
1096 : }
1097 : }
1098 :
1099 0 : fail:
1100 93 : ldb_debug_set(ldb, LDB_DEBUG_WARNING,
1101 : "acl: hostname validation failed for "
1102 : "hostname[%.*s] account[%.*s]\n",
1103 93 : (int)dnsHostName->length, dnsHostName->data,
1104 93 : (int)samAccountName->length, samAccountName->data);
1105 93 : talloc_free(tmp_ctx);
1106 93 : return LDB_ERR_CONSTRAINT_VIOLATION;
1107 : }
1108 :
1109 : /* checks if modifications are allowed on "Member" attribute */
1110 8013 : static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
1111 : struct ldb_module *module,
1112 : struct ldb_request *req,
1113 : struct security_descriptor *sd,
1114 : struct dom_sid *sid,
1115 : const struct dsdb_attribute *attr,
1116 : const struct dsdb_class *objectclass)
1117 : {
1118 0 : int ret;
1119 0 : unsigned int i;
1120 8013 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1121 0 : struct ldb_dn *user_dn;
1122 0 : struct ldb_message_element *member_el;
1123 8013 : const struct ldb_message *msg = NULL;
1124 :
1125 8013 : if (req->operation == LDB_MODIFY) {
1126 8013 : msg = req->op.mod.message;
1127 0 : } else if (req->operation == LDB_ADD) {
1128 0 : msg = req->op.add.message;
1129 : } else {
1130 0 : return LDB_ERR_OPERATIONS_ERROR;
1131 : }
1132 :
1133 : /* if we have wp, we can do whatever we like */
1134 8013 : if (acl_check_access_on_attribute(module,
1135 : mem_ctx,
1136 : sd,
1137 : sid,
1138 : SEC_ADS_WRITE_PROP,
1139 : attr, objectclass) == LDB_SUCCESS) {
1140 7953 : return LDB_SUCCESS;
1141 : }
1142 : /* if we are adding/deleting ourselves, check for self membership */
1143 60 : ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
1144 60 : &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
1145 : &user_dn);
1146 60 : if (ret != LDB_SUCCESS) {
1147 0 : return ret;
1148 : }
1149 60 : member_el = ldb_msg_find_element(msg, "member");
1150 60 : if (!member_el) {
1151 0 : return ldb_operr(ldb);
1152 : }
1153 : /* user can only remove oneself */
1154 60 : if (member_el->num_values == 0) {
1155 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1156 : }
1157 87 : for (i = 0; i < member_el->num_values; i++) {
1158 69 : if (strcasecmp((const char *)member_el->values[i].data,
1159 69 : ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
1160 42 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1161 : }
1162 : }
1163 18 : ret = acl_check_extended_right(mem_ctx,
1164 : module,
1165 : req,
1166 : objectclass,
1167 : sd,
1168 : acl_user_token(module),
1169 : GUID_DRS_SELF_MEMBERSHIP,
1170 : SEC_ADS_SELF_WRITE,
1171 : sid);
1172 18 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1173 9 : dsdb_acl_debug(sd, acl_user_token(module),
1174 9 : msg->dn,
1175 : true,
1176 : 10);
1177 : }
1178 18 : return ret;
1179 : }
1180 :
1181 543299 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
1182 : {
1183 83657 : int ret;
1184 83657 : struct ldb_dn *parent;
1185 83657 : struct ldb_context *ldb;
1186 83657 : const struct dsdb_schema *schema;
1187 83657 : const struct dsdb_class *objectclass;
1188 543299 : const struct dsdb_class *computer_objectclass = NULL;
1189 543299 : const struct ldb_message_element *oc_el = NULL;
1190 83657 : struct ldb_message_element sorted_oc_el;
1191 83657 : struct ldb_control *as_system;
1192 543299 : struct ldb_control *sd_ctrl = NULL;
1193 83657 : struct ldb_message_element *el;
1194 543299 : unsigned int instanceType = 0;
1195 543299 : struct dsdb_control_calculated_default_sd *control_sd = NULL;
1196 543299 : const struct dsdb_attribute *attr = NULL;
1197 543299 : const char **must_contain = NULL;
1198 543299 : const struct ldb_message *msg = req->op.add.message;
1199 543299 : const struct dom_sid *domain_sid = NULL;
1200 543299 : int i = 0;
1201 83657 : bool attribute_authorization;
1202 83657 : bool is_subclass;
1203 :
1204 543299 : if (ldb_dn_is_special(msg->dn)) {
1205 538 : return ldb_next_request(module, req);
1206 : }
1207 :
1208 542761 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1209 542761 : if (as_system != NULL) {
1210 117 : as_system->critical = 0;
1211 : }
1212 :
1213 542761 : if (dsdb_module_am_system(module) || as_system) {
1214 4525 : return ldb_next_request(module, req);
1215 : }
1216 :
1217 538236 : ldb = ldb_module_get_ctx(module);
1218 538236 : domain_sid = samdb_domain_sid(ldb);
1219 :
1220 538236 : parent = ldb_dn_get_parent(req, msg->dn);
1221 538236 : if (parent == NULL) {
1222 0 : return ldb_oom(ldb);
1223 : }
1224 :
1225 538236 : schema = dsdb_get_schema(ldb, req);
1226 538236 : if (!schema) {
1227 0 : return ldb_operr(ldb);
1228 : }
1229 :
1230 : /* Find the objectclass of the new account. */
1231 :
1232 538236 : oc_el = ldb_msg_find_element(msg, "objectclass");
1233 538236 : if (oc_el == NULL) {
1234 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1235 : "acl: unable to find or validate structural objectClass on %s\n",
1236 0 : ldb_dn_get_linearized(msg->dn));
1237 0 : return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
1238 : }
1239 :
1240 538236 : schema = dsdb_get_schema(ldb, req);
1241 538236 : if (schema == NULL) {
1242 0 : return ldb_operr(ldb);
1243 : }
1244 :
1245 538236 : ret = dsdb_sort_objectClass_attr(ldb, schema, oc_el, req, &sorted_oc_el);
1246 538236 : if (ret != LDB_SUCCESS) {
1247 0 : return ret;
1248 : }
1249 :
1250 538236 : objectclass = dsdb_get_last_structural_class(schema, &sorted_oc_el);
1251 538236 : if (objectclass == NULL) {
1252 0 : return ldb_operr(ldb);
1253 : }
1254 :
1255 538236 : el = ldb_msg_find_element(msg, "instanceType");
1256 538236 : if ((el != NULL) && (el->num_values != 1)) {
1257 1 : ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
1258 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
1259 : }
1260 :
1261 538235 : instanceType = ldb_msg_find_attr_as_uint(msg,
1262 : "instanceType", 0);
1263 538235 : if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
1264 108 : static const char *no_attrs[] = { NULL };
1265 108 : struct ldb_result *partition_res;
1266 108 : struct ldb_dn *partitions_dn;
1267 :
1268 609 : partitions_dn = samdb_partitions_dn(ldb, req);
1269 609 : if (!partitions_dn) {
1270 0 : ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
1271 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1272 : }
1273 :
1274 609 : ret = dsdb_module_search(module, req, &partition_res,
1275 : partitions_dn, LDB_SCOPE_ONELEVEL,
1276 : no_attrs,
1277 : DSDB_FLAG_NEXT_MODULE |
1278 : DSDB_FLAG_AS_SYSTEM |
1279 : DSDB_SEARCH_ONE_ONLY |
1280 : DSDB_SEARCH_SHOW_RECYCLED,
1281 : req,
1282 : "(&(nCName=%s)(objectClass=crossRef))",
1283 609 : ldb_dn_get_linearized(msg->dn));
1284 :
1285 609 : if (ret == LDB_SUCCESS) {
1286 : /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1287 0 : ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
1288 : SEC_ADS_WRITE_PROP,
1289 : &objectclass->schemaIDGUID, req);
1290 0 : if (ret != LDB_SUCCESS) {
1291 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1292 : "acl: ACL check failed on crossRef object %s: %s\n",
1293 0 : ldb_dn_get_linearized(partition_res->msgs[0]->dn),
1294 : ldb_errstring(ldb));
1295 0 : return ret;
1296 : }
1297 :
1298 : /*
1299 : * TODO: Remaining checks, like if we are
1300 : * the naming master etc need to be handled
1301 : * in the instanceType module
1302 : */
1303 : /* Note - do we need per-attribute checks? */
1304 0 : return ldb_next_request(module, req);
1305 : }
1306 :
1307 : /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1308 609 : ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
1309 : SEC_ADS_CREATE_CHILD,
1310 : &objectclass->schemaIDGUID, req);
1311 990 : if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1312 381 : ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
1313 : {
1314 : /* Allow provision bootstrap */
1315 315 : ret = LDB_SUCCESS;
1316 : }
1317 543 : if (ret != LDB_SUCCESS) {
1318 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1319 : "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
1320 : ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
1321 0 : return ret;
1322 : }
1323 :
1324 : /*
1325 : * TODO: Remaining checks, like if we are the naming
1326 : * master and adding the crossRef object need to be
1327 : * handled in the instanceType module
1328 : */
1329 : } else {
1330 537626 : ret = dsdb_module_check_access_on_dn(module, req, parent,
1331 : SEC_ADS_CREATE_CHILD,
1332 : &objectclass->schemaIDGUID, req);
1333 537626 : if (ret != LDB_SUCCESS) {
1334 24 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1335 : "acl: unable to get access to %s\n",
1336 24 : ldb_dn_get_linearized(msg->dn));
1337 24 : return ret;
1338 : }
1339 : }
1340 :
1341 538211 : attribute_authorization = dsdb_attribute_authz_on_ldap_add(module,
1342 : req,
1343 : req);
1344 538211 : if (!attribute_authorization) {
1345 : /* Skip the remaining checks */
1346 522479 : goto success;
1347 : }
1348 :
1349 : /* Check if we have computer objectclass. */
1350 15732 : computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
1351 15732 : if (computer_objectclass == NULL) {
1352 0 : return ldb_operr(ldb);
1353 : }
1354 :
1355 15732 : is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
1356 15732 : if (!is_subclass) {
1357 : /*
1358 : * This object is not a computer (or derived from computer), so
1359 : * skip the remaining checks.
1360 : */
1361 14958 : goto success;
1362 : }
1363 :
1364 : /*
1365 : * we have established we have CC right, now check per-attribute
1366 : * access based on the default SD
1367 : */
1368 :
1369 774 : sd_ctrl = ldb_request_get_control(req,
1370 : DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID);
1371 774 : if (sd_ctrl == NULL) {
1372 0 : goto success;
1373 : }
1374 :
1375 : {
1376 774 : TALLOC_CTX *tmp_ctx = talloc_new(req);
1377 774 : control_sd = (struct dsdb_control_calculated_default_sd *) sd_ctrl->data;
1378 774 : DBG_DEBUG("Received cookie descriptor %s\n\n",
1379 : sddl_encode(tmp_ctx, control_sd->default_sd, domain_sid));
1380 774 : TALLOC_FREE(tmp_ctx);
1381 : /* Mark the "change" control as uncritical (done) */
1382 774 : sd_ctrl->critical = false;
1383 : }
1384 :
1385 : /*
1386 : * At this point we do not yet have the object's SID, so we
1387 : * leave it empty. It is irrelevant, as it is used to expand
1388 : * Principal-Self, and rights granted to PS will have no effect
1389 : * in this case
1390 : */
1391 : /* check if we have WD, no need to perform other attribute checks if we do */
1392 774 : attr = dsdb_attribute_by_lDAPDisplayName(schema, "nTSecurityDescriptor");
1393 774 : if (attr == NULL) {
1394 0 : return ldb_operr(ldb);
1395 : }
1396 :
1397 774 : if (control_sd->specified_sacl) {
1398 18 : const struct security_token *token = acl_user_token(module);
1399 18 : bool has_priv = security_token_has_privilege(token, SEC_PRIV_SECURITY);
1400 18 : if (!has_priv) {
1401 18 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1402 : }
1403 : }
1404 :
1405 756 : ret = acl_check_access_on_attribute(module,
1406 : req,
1407 : control_sd->default_sd,
1408 : NULL,
1409 : SEC_STD_WRITE_DAC,
1410 : attr,
1411 : objectclass);
1412 756 : if (ret == LDB_SUCCESS) {
1413 486 : goto success;
1414 : }
1415 :
1416 270 : if (control_sd->specified_sd) {
1417 126 : bool block_owner_rights = dsdb_block_owner_implicit_rights(module,
1418 : req,
1419 : req);
1420 126 : if (block_owner_rights) {
1421 108 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1422 : "Object %s has no SD modification rights",
1423 108 : ldb_dn_get_linearized(msg->dn));
1424 108 : dsdb_acl_debug(control_sd->default_sd,
1425 : acl_user_token(module),
1426 108 : msg->dn,
1427 : true,
1428 : 10);
1429 108 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1430 108 : return ret;
1431 : }
1432 : }
1433 :
1434 162 : must_contain = dsdb_full_attribute_list(req, schema, &sorted_oc_el,
1435 : DSDB_SCHEMA_ALL_MUST);
1436 702 : for (i=0; i < msg->num_elements; i++) {
1437 603 : el = &msg->elements[i];
1438 :
1439 603 : attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1440 603 : if (attr == NULL && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1441 0 : ldb_asprintf_errstring(ldb, "acl_add: attribute '%s' "
1442 : "on entry '%s' was not found in the schema!",
1443 : el->name,
1444 0 : ldb_dn_get_linearized(msg->dn));
1445 0 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1446 0 : return ret;
1447 : }
1448 :
1449 603 : if (attr != NULL) {
1450 594 : bool found = str_list_check(must_contain, attr->lDAPDisplayName);
1451 : /* do not check the mandatory attributes */
1452 594 : if (found) {
1453 450 : continue;
1454 : }
1455 : }
1456 :
1457 153 : if (ldb_attr_cmp("dBCSPwd", el->name) == 0 ||
1458 153 : ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1459 144 : ldb_attr_cmp("userPassword", el->name) == 0 ||
1460 126 : ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1461 36 : continue;
1462 117 : } else if (ldb_attr_cmp("member", el->name) == 0) {
1463 0 : ret = acl_check_self_membership(req,
1464 : module,
1465 : req,
1466 : control_sd->default_sd,
1467 : NULL,
1468 : attr,
1469 : objectclass);
1470 0 : if (ret != LDB_SUCCESS) {
1471 0 : return ret;
1472 : }
1473 117 : } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1474 36 : ret = acl_check_spn(req,
1475 : module,
1476 : req,
1477 : el,
1478 : control_sd->default_sd,
1479 : NULL,
1480 : attr,
1481 : objectclass,
1482 : NULL);
1483 36 : if (ret != LDB_SUCCESS) {
1484 18 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1485 : "Object %s cannot be created with spn",
1486 18 : ldb_dn_get_linearized(msg->dn));
1487 18 : dsdb_acl_debug(control_sd->default_sd,
1488 : acl_user_token(module),
1489 18 : msg->dn,
1490 : true,
1491 : 10);
1492 18 : return ret;
1493 : }
1494 81 : } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
1495 0 : ret = acl_check_dns_host_name(req,
1496 : module,
1497 : req,
1498 : el,
1499 : control_sd->default_sd,
1500 : NULL,
1501 : attr,
1502 : objectclass,
1503 : NULL);
1504 0 : if (ret != LDB_SUCCESS) {
1505 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1506 : "Object %s cannot be created with dnsHostName",
1507 0 : ldb_dn_get_linearized(msg->dn));
1508 0 : dsdb_acl_debug(control_sd->default_sd,
1509 : acl_user_token(module),
1510 0 : msg->dn,
1511 : true,
1512 : 10);
1513 0 : return ret;
1514 : }
1515 : } else {
1516 81 : ret = acl_check_access_on_attribute(module,
1517 : req,
1518 : control_sd->default_sd,
1519 : NULL,
1520 : SEC_ADS_WRITE_PROP,
1521 : attr,
1522 : objectclass);
1523 81 : if (ret != LDB_SUCCESS) {
1524 45 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1525 : "Object %s has no write property access",
1526 45 : ldb_dn_get_linearized(msg->dn));
1527 45 : dsdb_acl_debug(control_sd->default_sd,
1528 : acl_user_token(module),
1529 45 : msg->dn,
1530 : true,
1531 : 10);
1532 45 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1533 45 : return ret;
1534 : }
1535 : }
1536 : }
1537 99 : success:
1538 538022 : return ldb_next_request(module, req);
1539 : }
1540 :
1541 16982 : static int acl_check_password_rights(
1542 : TALLOC_CTX *mem_ctx,
1543 : struct ldb_module *module,
1544 : struct ldb_request *req,
1545 : struct security_descriptor *sd,
1546 : struct dom_sid *sid,
1547 : const struct dsdb_class *objectclass,
1548 : bool userPassword,
1549 : struct dsdb_control_password_acl_validation **control_for_response)
1550 : {
1551 16982 : int ret = LDB_SUCCESS;
1552 16982 : unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
1553 16982 : unsigned int del_val_cnt = 0, add_val_cnt = 0;
1554 72 : struct ldb_message_element *el;
1555 72 : struct ldb_message *msg;
1556 16982 : struct ldb_control *c = NULL;
1557 16982 : const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
1558 : "unicodePwd", NULL }, **l;
1559 16982 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1560 16982 : struct dsdb_control_password_acl_validation *pav = NULL;
1561 :
1562 16982 : if (tmp_ctx == NULL) {
1563 0 : return LDB_ERR_OPERATIONS_ERROR;
1564 : }
1565 :
1566 16982 : pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
1567 16982 : if (pav == NULL) {
1568 0 : talloc_free(tmp_ctx);
1569 0 : return LDB_ERR_OPERATIONS_ERROR;
1570 : }
1571 : /*
1572 : * Set control_for_response to pav so it can be added to the response
1573 : * and be passed up to the audit_log module which uses it to identify
1574 : * password reset attempts.
1575 : */
1576 16982 : *control_for_response = pav;
1577 :
1578 16982 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1579 16982 : if (c != NULL) {
1580 522 : pav->pwd_reset = false;
1581 :
1582 : /*
1583 : * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1584 : * have a user password change and not a set as the message
1585 : * looks like. In it's value blob it contains the NT and/or LM
1586 : * hash of the old password specified by the user. This control
1587 : * is used by the SAMR and "kpasswd" password change mechanisms.
1588 : *
1589 : * This control can't be used by real LDAP clients,
1590 : * the only caller is samdb_set_password_internal(),
1591 : * so we don't have to strict verification of the input.
1592 : */
1593 522 : ret = acl_check_extended_right(tmp_ctx,
1594 : module,
1595 : req,
1596 : objectclass,
1597 : sd,
1598 : acl_user_token(module),
1599 : GUID_DRS_USER_CHANGE_PASSWORD,
1600 : SEC_ADS_CONTROL_ACCESS,
1601 : sid);
1602 522 : goto checked;
1603 : }
1604 :
1605 16460 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1606 16460 : if (c != NULL) {
1607 310 : pav->pwd_reset = true;
1608 :
1609 : /*
1610 : * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1611 : * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1612 : * have a force password set.
1613 : * This control is used by the SAMR/NETLOGON/LSA password
1614 : * reset mechanisms.
1615 : *
1616 : * This control can't be used by real LDAP clients,
1617 : * the only caller is samdb_set_password_internal(),
1618 : * so we don't have to strict verification of the input.
1619 : */
1620 310 : ret = acl_check_extended_right(tmp_ctx,
1621 : module,
1622 : req,
1623 : objectclass,
1624 : sd,
1625 : acl_user_token(module),
1626 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1627 : SEC_ADS_CONTROL_ACCESS,
1628 : sid);
1629 310 : goto checked;
1630 : }
1631 :
1632 16150 : el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1633 16150 : if (el != NULL) {
1634 : /*
1635 : * dBCSPwd is only allowed with a control.
1636 : */
1637 0 : talloc_free(tmp_ctx);
1638 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1639 : }
1640 :
1641 16150 : msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1642 16150 : if (msg == NULL) {
1643 0 : return ldb_module_oom(module);
1644 : }
1645 64600 : for (l = passwordAttrs; *l != NULL; l++) {
1646 48450 : if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1647 13366 : continue;
1648 : }
1649 :
1650 53310 : while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1651 18226 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1652 2085 : ++del_attr_cnt;
1653 2085 : del_val_cnt += el->num_values;
1654 : }
1655 18226 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1656 2049 : ++add_attr_cnt;
1657 2049 : add_val_cnt += el->num_values;
1658 : }
1659 18226 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1660 14092 : ++rep_attr_cnt;
1661 : }
1662 18226 : ldb_msg_remove_element(msg, el);
1663 : }
1664 : }
1665 :
1666 : /* single deletes will be handled by the "password_hash" LDB module
1667 : * later in the stack, so we let it though here */
1668 16150 : if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1669 63 : talloc_free(tmp_ctx);
1670 63 : return LDB_SUCCESS;
1671 : }
1672 :
1673 :
1674 16087 : if (rep_attr_cnt > 0) {
1675 14074 : pav->pwd_reset = true;
1676 :
1677 14074 : ret = acl_check_extended_right(tmp_ctx,
1678 : module,
1679 : req,
1680 : objectclass,
1681 : sd,
1682 : acl_user_token(module),
1683 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1684 : SEC_ADS_CONTROL_ACCESS,
1685 : sid);
1686 14074 : goto checked;
1687 : }
1688 :
1689 2013 : if (add_attr_cnt != del_attr_cnt) {
1690 99 : pav->pwd_reset = true;
1691 :
1692 99 : ret = acl_check_extended_right(tmp_ctx,
1693 : module,
1694 : req,
1695 : objectclass,
1696 : sd,
1697 : acl_user_token(module),
1698 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1699 : SEC_ADS_CONTROL_ACCESS,
1700 : sid);
1701 99 : goto checked;
1702 : }
1703 :
1704 1914 : if (add_val_cnt == 1 && del_val_cnt == 1) {
1705 1115 : pav->pwd_reset = false;
1706 :
1707 1115 : ret = acl_check_extended_right(tmp_ctx,
1708 : module,
1709 : req,
1710 : objectclass,
1711 : sd,
1712 : acl_user_token(module),
1713 : GUID_DRS_USER_CHANGE_PASSWORD,
1714 : SEC_ADS_CONTROL_ACCESS,
1715 : sid);
1716 : /* Very strange, but we get constraint violation in this case */
1717 1115 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1718 18 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1719 : }
1720 1115 : goto checked;
1721 : }
1722 :
1723 799 : if (add_val_cnt == 1 && del_val_cnt == 0) {
1724 529 : pav->pwd_reset = true;
1725 :
1726 529 : ret = acl_check_extended_right(tmp_ctx,
1727 : module,
1728 : req,
1729 : objectclass,
1730 : sd,
1731 : acl_user_token(module),
1732 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1733 : SEC_ADS_CONTROL_ACCESS,
1734 : sid);
1735 : /* Very strange, but we get constraint violation in this case */
1736 529 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1737 27 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1738 : }
1739 529 : goto checked;
1740 : }
1741 :
1742 : /*
1743 : * Everything else is handled by the password_hash module where it will
1744 : * fail, but with the correct error code when the module is again
1745 : * checking the attributes. As the change request will lack the
1746 : * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1747 : * any modification attempt that went this way will be rejected.
1748 : */
1749 :
1750 270 : talloc_free(tmp_ctx);
1751 270 : return LDB_SUCCESS;
1752 :
1753 16649 : checked:
1754 16649 : if (ret != LDB_SUCCESS) {
1755 142 : dsdb_acl_debug(sd, acl_user_token(module),
1756 142 : req->op.mod.message->dn,
1757 : true,
1758 : 10);
1759 142 : talloc_free(tmp_ctx);
1760 142 : return ret;
1761 : }
1762 :
1763 16507 : ret = ldb_request_add_control(req,
1764 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1765 16507 : if (ret != LDB_SUCCESS) {
1766 0 : ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1767 : "Unable to register ACL validation control!\n");
1768 0 : return ret;
1769 : }
1770 16435 : return LDB_SUCCESS;
1771 : }
1772 :
1773 : /*
1774 : * Context needed by acl_callback
1775 : */
1776 : struct acl_callback_context {
1777 : struct ldb_request *request;
1778 : struct ldb_module *module;
1779 : };
1780 :
1781 : /*
1782 : * @brief Copy the password validation control to the reply.
1783 : *
1784 : * Copy the dsdb_control_password_acl_validation control from the request,
1785 : * to the reply. The control is used by the audit_log module to identify
1786 : * password rests.
1787 : *
1788 : * @param req the ldb request.
1789 : * @param ares the result, updated with the control.
1790 : */
1791 117959 : static void copy_password_acl_validation_control(
1792 : struct ldb_request *req,
1793 : struct ldb_reply *ares)
1794 : {
1795 117959 : struct ldb_control *pav_ctrl = NULL;
1796 117959 : struct dsdb_control_password_acl_validation *pav = NULL;
1797 :
1798 117959 : pav_ctrl = ldb_request_get_control(
1799 : discard_const(req),
1800 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1801 117959 : if (pav_ctrl == NULL) {
1802 98337 : return;
1803 : }
1804 :
1805 16507 : pav = talloc_get_type_abort(
1806 : pav_ctrl->data,
1807 : struct dsdb_control_password_acl_validation);
1808 16507 : if (pav == NULL) {
1809 0 : return;
1810 : }
1811 16507 : ldb_reply_add_control(
1812 : ares,
1813 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1814 : false,
1815 : pav);
1816 : }
1817 : /*
1818 : * @brief call back function for acl_modify.
1819 : *
1820 : * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1821 : * the request to the reply.
1822 : *
1823 : * @param req the ldb_request.
1824 : * @param ares the operation result.
1825 : *
1826 : * @return the LDB_STATUS
1827 : */
1828 117969 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1829 : {
1830 117969 : struct acl_callback_context *ac = NULL;
1831 :
1832 117969 : ac = talloc_get_type(req->context, struct acl_callback_context);
1833 :
1834 117969 : if (!ares) {
1835 0 : return ldb_module_done(
1836 : ac->request,
1837 : NULL,
1838 : NULL,
1839 : LDB_ERR_OPERATIONS_ERROR);
1840 : }
1841 :
1842 : /* pass on to the callback */
1843 117969 : switch (ares->type) {
1844 0 : case LDB_REPLY_ENTRY:
1845 0 : return ldb_module_send_entry(
1846 : ac->request,
1847 : ares->message,
1848 : ares->controls);
1849 :
1850 10 : case LDB_REPLY_REFERRAL:
1851 10 : return ldb_module_send_referral(
1852 : ac->request,
1853 : ares->referral);
1854 :
1855 117959 : case LDB_REPLY_DONE:
1856 : /*
1857 : * Copy the ACL control from the request to the response
1858 : */
1859 117959 : copy_password_acl_validation_control(req, ares);
1860 117959 : return ldb_module_done(
1861 : ac->request,
1862 : ares->controls,
1863 : ares->response,
1864 : ares->error);
1865 :
1866 0 : default:
1867 : /* Can't happen */
1868 0 : return LDB_ERR_OPERATIONS_ERROR;
1869 : }
1870 : }
1871 :
1872 591514 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1873 : {
1874 21578 : int ret;
1875 591514 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1876 21578 : const struct dsdb_schema *schema;
1877 21578 : unsigned int i;
1878 21578 : const struct dsdb_class *objectclass;
1879 21578 : struct ldb_result *acl_res;
1880 21578 : struct security_descriptor *sd;
1881 591514 : struct dom_sid *sid = NULL;
1882 21578 : struct ldb_control *as_system;
1883 21578 : struct ldb_control *is_undelete;
1884 591514 : struct ldb_control *implicit_validated_write_control = NULL;
1885 21578 : bool userPassword;
1886 591514 : bool password_rights_checked = false;
1887 21578 : TALLOC_CTX *tmp_ctx;
1888 591514 : const struct ldb_message *msg = req->op.mod.message;
1889 21578 : static const char *acl_attrs[] = {
1890 : "nTSecurityDescriptor",
1891 : "objectClass",
1892 : "objectSid",
1893 : NULL
1894 : };
1895 591514 : struct acl_callback_context *context = NULL;
1896 591514 : struct ldb_request *new_req = NULL;
1897 591514 : struct dsdb_control_password_acl_validation *pav = NULL;
1898 591514 : struct ldb_control **controls = NULL;
1899 :
1900 591514 : if (ldb_dn_is_special(msg->dn)) {
1901 715 : return ldb_next_request(module, req);
1902 : }
1903 :
1904 590799 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1905 590799 : if (as_system != NULL) {
1906 270819 : as_system->critical = 0;
1907 : }
1908 :
1909 590799 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1910 :
1911 590799 : implicit_validated_write_control = ldb_request_get_control(
1912 : req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
1913 590799 : if (implicit_validated_write_control != NULL) {
1914 147 : implicit_validated_write_control->critical = 0;
1915 : }
1916 :
1917 : /* Don't print this debug statement if elements[0].name is going to be NULL */
1918 590799 : if (msg->num_elements > 0) {
1919 590518 : DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
1920 : }
1921 590799 : if (dsdb_module_am_system(module) || as_system) {
1922 471083 : return ldb_next_request(module, req);
1923 : }
1924 :
1925 119716 : tmp_ctx = talloc_new(req);
1926 119716 : if (tmp_ctx == NULL) {
1927 0 : return ldb_oom(ldb);
1928 : }
1929 :
1930 119716 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
1931 : acl_attrs,
1932 : DSDB_FLAG_NEXT_MODULE |
1933 : DSDB_FLAG_AS_SYSTEM |
1934 : DSDB_SEARCH_SHOW_RECYCLED,
1935 : req);
1936 :
1937 119716 : if (ret != LDB_SUCCESS) {
1938 122 : goto fail;
1939 : }
1940 :
1941 119594 : userPassword = dsdb_user_password_support(module, req, req);
1942 :
1943 119594 : schema = dsdb_get_schema(ldb, tmp_ctx);
1944 119594 : if (!schema) {
1945 0 : talloc_free(tmp_ctx);
1946 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1947 : "acl_modify: Error obtaining schema.");
1948 : }
1949 :
1950 119594 : ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1951 119594 : if (ret != LDB_SUCCESS) {
1952 0 : talloc_free(tmp_ctx);
1953 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1954 : "acl_modify: Error retrieving security descriptor.");
1955 : }
1956 : /* Theoretically we pass the check if the object has no sd */
1957 119594 : if (!sd) {
1958 0 : goto success;
1959 : }
1960 :
1961 119594 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1962 119594 : if (!objectclass) {
1963 0 : talloc_free(tmp_ctx);
1964 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1965 : "acl_modify: Error retrieving object class for GUID.");
1966 : }
1967 119594 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1968 277855 : for (i=0; i < msg->num_elements; i++) {
1969 156704 : const struct ldb_message_element *el = &msg->elements[i];
1970 4863 : const struct dsdb_attribute *attr;
1971 :
1972 : /*
1973 : * This basic attribute existence check with the right errorcode
1974 : * is needed since this module is the first one which requests
1975 : * schema attribute information.
1976 : * The complete attribute checking is done in the
1977 : * "objectclass_attrs" module behind this one.
1978 : *
1979 : * NOTE: "clearTextPassword" is not defined in the schema.
1980 : */
1981 156704 : attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1982 156704 : if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1983 4 : ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
1984 : "on entry '%s' was not found in the schema!",
1985 2 : req->op.mod.message->elements[i].name,
1986 2 : ldb_dn_get_linearized(req->op.mod.message->dn));
1987 2 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1988 2 : goto fail;
1989 : }
1990 :
1991 156702 : if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
1992 27364 : uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1993 27364 : uint32_t access_mask = 0;
1994 :
1995 88 : bool block_owner_rights;
1996 88 : enum implicit_owner_rights implicit_owner_rights;
1997 :
1998 27364 : if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1999 12958 : access_mask |= SEC_STD_WRITE_OWNER;
2000 : }
2001 27364 : if (sd_flags & SECINFO_DACL) {
2002 27130 : access_mask |= SEC_STD_WRITE_DAC;
2003 : }
2004 27364 : if (sd_flags & SECINFO_SACL) {
2005 12706 : access_mask |= SEC_FLAG_SYSTEM_SECURITY;
2006 : }
2007 :
2008 27364 : block_owner_rights = !dsdb_module_am_administrator(module);
2009 :
2010 27364 : if (block_owner_rights) {
2011 180 : block_owner_rights = dsdb_block_owner_implicit_rights(module,
2012 : req,
2013 : req);
2014 : }
2015 27364 : if (block_owner_rights) {
2016 162 : block_owner_rights = samdb_find_attribute(ldb,
2017 162 : acl_res->msgs[0],
2018 : "objectclass",
2019 : "computer");
2020 : }
2021 :
2022 27364 : implicit_owner_rights = block_owner_rights ?
2023 27364 : IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
2024 : IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
2025 :
2026 27364 : ret = acl_check_access_on_attribute_implicit_owner(module,
2027 : tmp_ctx,
2028 : sd,
2029 : sid,
2030 : access_mask,
2031 : attr,
2032 : objectclass,
2033 : implicit_owner_rights);
2034 27364 : if (ret != LDB_SUCCESS) {
2035 108 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2036 : "Object %s has no write dacl access\n",
2037 108 : ldb_dn_get_linearized(msg->dn));
2038 108 : dsdb_acl_debug(sd,
2039 : acl_user_token(module),
2040 108 : msg->dn,
2041 : true,
2042 : 10);
2043 108 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2044 108 : goto fail;
2045 : }
2046 129338 : } else if (ldb_attr_cmp("member", el->name) == 0) {
2047 8013 : ret = acl_check_self_membership(tmp_ctx,
2048 : module,
2049 : req,
2050 : sd,
2051 : sid,
2052 : attr,
2053 : objectclass);
2054 8013 : if (ret != LDB_SUCCESS) {
2055 51 : goto fail;
2056 : }
2057 121325 : } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
2058 : /* this one is not affected by any rights, we should let it through
2059 : so that passwords_hash returns the correct error */
2060 72 : continue;
2061 121253 : } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
2062 8302 : (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
2063 103833 : ldb_attr_cmp("clearTextPassword", el->name) == 0) {
2064 : /*
2065 : * Ideally we would do the acl_check_password_rights
2066 : * before we checked the other attributes, i.e. in a
2067 : * loop before the current one.
2068 : * Have not done this as yet in order to limit the size
2069 : * of the change. To limit the possibility of breaking
2070 : * the ACL logic.
2071 : */
2072 18941 : if (password_rights_checked) {
2073 1959 : continue;
2074 : }
2075 16982 : ret = acl_check_password_rights(tmp_ctx,
2076 : module,
2077 : req,
2078 : sd,
2079 : sid,
2080 : objectclass,
2081 : userPassword,
2082 : &pav);
2083 16982 : if (ret != LDB_SUCCESS) {
2084 142 : goto fail;
2085 : }
2086 16768 : password_rights_checked = true;
2087 102312 : } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
2088 2167 : ret = acl_check_spn(tmp_ctx,
2089 : module,
2090 : req,
2091 : el,
2092 : sd,
2093 : sid,
2094 : attr,
2095 : objectclass,
2096 : implicit_validated_write_control);
2097 2167 : if (ret != LDB_SUCCESS) {
2098 274 : goto fail;
2099 : }
2100 100145 : } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
2101 952 : ret = acl_check_dns_host_name(tmp_ctx,
2102 : module,
2103 : req,
2104 : el,
2105 : sd,
2106 : sid,
2107 : attr,
2108 : objectclass,
2109 : implicit_validated_write_control);
2110 952 : if (ret != LDB_SUCCESS) {
2111 180 : goto fail;
2112 : }
2113 99193 : } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
2114 : /*
2115 : * in case of undelete op permissions on
2116 : * isDeleted are irrelevant and
2117 : * distinguishedName is removed by the
2118 : * tombstone_reanimate module
2119 : */
2120 274 : continue;
2121 98919 : } else if (implicit_validated_write_control != NULL) {
2122 : /* Allow the update. */
2123 441 : continue;
2124 : } else {
2125 98478 : ret = acl_check_access_on_attribute(module,
2126 : tmp_ctx,
2127 : sd,
2128 : sid,
2129 : SEC_ADS_WRITE_PROP,
2130 : attr,
2131 : objectclass);
2132 98478 : if (ret != LDB_SUCCESS) {
2133 876 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2134 : "Object %s has no write property access\n",
2135 876 : ldb_dn_get_linearized(msg->dn));
2136 876 : dsdb_acl_debug(sd,
2137 : acl_user_token(module),
2138 876 : msg->dn,
2139 : true,
2140 : 10);
2141 876 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2142 876 : goto fail;
2143 : }
2144 : }
2145 : }
2146 :
2147 117961 : success:
2148 117961 : talloc_free(tmp_ctx);
2149 117961 : context = talloc_zero(req, struct acl_callback_context);
2150 :
2151 117961 : if (context == NULL) {
2152 0 : return ldb_oom(ldb);
2153 : }
2154 117961 : context->request = req;
2155 117961 : context->module = module;
2156 117961 : ret = ldb_build_mod_req(
2157 : &new_req,
2158 : ldb,
2159 : req,
2160 : req->op.mod.message,
2161 : req->controls,
2162 : context,
2163 : acl_callback,
2164 : req);
2165 117961 : if (ret != LDB_SUCCESS) {
2166 0 : return ret;
2167 : }
2168 117961 : return ldb_next_request(module, new_req);
2169 1755 : fail:
2170 1755 : talloc_free(tmp_ctx);
2171 : /*
2172 : * We copy the pav into the result, so that the password reset
2173 : * logging code in audit_log can log failed password reset attempts.
2174 : */
2175 1755 : if (pav) {
2176 142 : struct ldb_control *control = NULL;
2177 :
2178 142 : controls = talloc_zero_array(req, struct ldb_control *, 2);
2179 142 : if (controls == NULL) {
2180 0 : return ldb_oom(ldb);
2181 : }
2182 :
2183 142 : control = talloc(controls, struct ldb_control);
2184 :
2185 142 : if (control == NULL) {
2186 0 : return ldb_oom(ldb);
2187 : }
2188 :
2189 142 : control->oid= talloc_strdup(
2190 : control,
2191 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
2192 142 : if (control->oid == NULL) {
2193 0 : return ldb_oom(ldb);
2194 : }
2195 142 : control->critical = false;
2196 142 : control->data = pav;
2197 142 : *controls = control;
2198 : }
2199 1755 : return ldb_module_done(req, controls, NULL, ret);
2200 : }
2201 :
2202 : /* similar to the modify for the time being.
2203 : * We need to consider the special delete tree case, though - TODO */
2204 72485 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
2205 : {
2206 148 : int ret;
2207 148 : struct ldb_dn *parent;
2208 148 : struct ldb_context *ldb;
2209 148 : struct ldb_dn *nc_root;
2210 148 : struct ldb_control *as_system;
2211 148 : const struct dsdb_schema *schema;
2212 148 : const struct dsdb_class *objectclass;
2213 72485 : struct security_descriptor *sd = NULL;
2214 72485 : struct dom_sid *sid = NULL;
2215 148 : struct ldb_result *acl_res;
2216 148 : static const char *acl_attrs[] = {
2217 : "nTSecurityDescriptor",
2218 : "objectClass",
2219 : "objectSid",
2220 : NULL
2221 : };
2222 :
2223 72485 : if (ldb_dn_is_special(req->op.del.dn)) {
2224 1 : return ldb_next_request(module, req);
2225 : }
2226 :
2227 72484 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2228 72484 : if (as_system != NULL) {
2229 29325 : as_system->critical = 0;
2230 : }
2231 :
2232 72484 : if (dsdb_module_am_system(module) || as_system) {
2233 31698 : return ldb_next_request(module, req);
2234 : }
2235 :
2236 40786 : DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
2237 :
2238 40786 : ldb = ldb_module_get_ctx(module);
2239 :
2240 40786 : parent = ldb_dn_get_parent(req, req->op.del.dn);
2241 40786 : if (parent == NULL) {
2242 0 : return ldb_oom(ldb);
2243 : }
2244 :
2245 : /* Make sure we aren't deleting a NC */
2246 :
2247 40786 : ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
2248 40786 : if (ret != LDB_SUCCESS) {
2249 0 : return ret;
2250 : }
2251 40786 : if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
2252 0 : talloc_free(nc_root);
2253 0 : DEBUG(10,("acl:deleting a NC\n"));
2254 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2255 0 : return ldb_module_done(req, NULL, NULL,
2256 : LDB_ERR_UNWILLING_TO_PERFORM);
2257 : }
2258 40786 : talloc_free(nc_root);
2259 :
2260 40786 : ret = dsdb_module_search_dn(module, req, &acl_res,
2261 : req->op.del.dn, acl_attrs,
2262 : DSDB_FLAG_NEXT_MODULE |
2263 : DSDB_FLAG_AS_SYSTEM |
2264 : DSDB_SEARCH_SHOW_RECYCLED, req);
2265 : /* we should be able to find the parent */
2266 40786 : if (ret != LDB_SUCCESS) {
2267 0 : DEBUG(10,("acl: failed to find object %s\n",
2268 : ldb_dn_get_linearized(req->op.rename.olddn)));
2269 0 : return ret;
2270 : }
2271 :
2272 40786 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2273 40786 : if (ret != LDB_SUCCESS) {
2274 0 : return ldb_operr(ldb);
2275 : }
2276 40786 : if (!sd) {
2277 0 : return ldb_operr(ldb);
2278 : }
2279 :
2280 40786 : schema = dsdb_get_schema(ldb, req);
2281 40786 : if (!schema) {
2282 0 : return ldb_operr(ldb);
2283 : }
2284 :
2285 40786 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2286 :
2287 40786 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2288 40786 : if (!objectclass) {
2289 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2290 : "acl_modify: Error retrieving object class for GUID.");
2291 : }
2292 :
2293 40786 : if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
2294 2692 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
2295 : SEC_ADS_DELETE_TREE,
2296 : objectclass);
2297 2692 : if (ret != LDB_SUCCESS) {
2298 0 : return ret;
2299 : }
2300 :
2301 2692 : return ldb_next_request(module, req);
2302 : }
2303 :
2304 : /* First check if we have delete object right */
2305 38094 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
2306 : SEC_STD_DELETE,
2307 : objectclass);
2308 38094 : if (ret == LDB_SUCCESS) {
2309 37789 : return ldb_next_request(module, req);
2310 : }
2311 :
2312 : /* Nope, we don't have delete object. Lets check if we have delete
2313 : * child on the parent */
2314 305 : ret = dsdb_module_check_access_on_dn(module, req, parent,
2315 : SEC_ADS_DELETE_CHILD,
2316 : &objectclass->schemaIDGUID,
2317 : req);
2318 305 : if (ret != LDB_SUCCESS) {
2319 10 : return ret;
2320 : }
2321 :
2322 295 : return ldb_next_request(module, req);
2323 : }
2324 265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
2325 : struct ldb_module *module,
2326 : struct ldb_request *req,
2327 : struct ldb_dn *nc_root)
2328 : {
2329 0 : int ret;
2330 0 : struct ldb_result *acl_res;
2331 265 : struct security_descriptor *sd = NULL;
2332 265 : struct dom_sid *sid = NULL;
2333 265 : const struct dsdb_schema *schema = NULL;
2334 265 : const struct dsdb_class *objectclass = NULL;
2335 265 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2336 0 : static const char *acl_attrs[] = {
2337 : "nTSecurityDescriptor",
2338 : "objectClass",
2339 : "objectSid",
2340 : NULL
2341 : };
2342 :
2343 265 : ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
2344 : nc_root, acl_attrs,
2345 : DSDB_FLAG_NEXT_MODULE |
2346 : DSDB_FLAG_AS_SYSTEM |
2347 : DSDB_SEARCH_SHOW_RECYCLED, req);
2348 265 : if (ret != LDB_SUCCESS) {
2349 0 : DEBUG(10,("acl: failed to find object %s\n",
2350 : ldb_dn_get_linearized(nc_root)));
2351 0 : return ret;
2352 : }
2353 :
2354 265 : ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
2355 265 : sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
2356 265 : schema = dsdb_get_schema(ldb, req);
2357 265 : if (!schema) {
2358 0 : return LDB_ERR_OPERATIONS_ERROR;
2359 : }
2360 265 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2361 265 : if (ret != LDB_SUCCESS || !sd) {
2362 0 : return ldb_operr(ldb_module_get_ctx(module));
2363 : }
2364 265 : return acl_check_extended_right(mem_ctx,
2365 : module,
2366 : req,
2367 : objectclass,
2368 : sd,
2369 : acl_user_token(module),
2370 : GUID_DRS_REANIMATE_TOMBSTONE,
2371 : SEC_ADS_CONTROL_ACCESS, sid);
2372 : }
2373 :
2374 1533 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
2375 : {
2376 5 : int ret;
2377 5 : struct ldb_dn *oldparent;
2378 5 : struct ldb_dn *newparent;
2379 5 : const struct dsdb_schema *schema;
2380 5 : const struct dsdb_class *objectclass;
2381 1533 : const struct dsdb_attribute *attr = NULL;
2382 5 : struct ldb_context *ldb;
2383 1533 : struct security_descriptor *sd = NULL;
2384 1533 : struct dom_sid *sid = NULL;
2385 5 : struct ldb_result *acl_res;
2386 5 : struct ldb_dn *nc_root;
2387 5 : struct ldb_control *as_system;
2388 5 : struct ldb_control *is_undelete;
2389 5 : TALLOC_CTX *tmp_ctx;
2390 5 : const char *rdn_name;
2391 5 : static const char *acl_attrs[] = {
2392 : "nTSecurityDescriptor",
2393 : "objectClass",
2394 : "objectSid",
2395 : NULL
2396 : };
2397 :
2398 1533 : if (ldb_dn_is_special(req->op.rename.olddn)) {
2399 0 : return ldb_next_request(module, req);
2400 : }
2401 :
2402 1533 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2403 1533 : if (as_system != NULL) {
2404 0 : as_system->critical = 0;
2405 : }
2406 :
2407 1533 : DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
2408 1533 : if (dsdb_module_am_system(module) || as_system) {
2409 895 : return ldb_next_request(module, req);
2410 : }
2411 :
2412 638 : ldb = ldb_module_get_ctx(module);
2413 :
2414 638 : tmp_ctx = talloc_new(req);
2415 638 : if (tmp_ctx == NULL) {
2416 0 : return ldb_oom(ldb);
2417 : }
2418 :
2419 638 : oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
2420 638 : if (oldparent == NULL) {
2421 0 : return ldb_oom(ldb);
2422 : }
2423 638 : newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
2424 638 : if (newparent == NULL) {
2425 0 : return ldb_oom(ldb);
2426 : }
2427 :
2428 : /* Make sure we aren't renaming/moving a NC */
2429 :
2430 638 : ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
2431 638 : if (ret != LDB_SUCCESS) {
2432 0 : return ret;
2433 : }
2434 638 : if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
2435 0 : talloc_free(nc_root);
2436 0 : DEBUG(10,("acl:renaming/moving a NC\n"));
2437 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2438 0 : return ldb_module_done(req, NULL, NULL,
2439 : LDB_ERR_UNWILLING_TO_PERFORM);
2440 : }
2441 :
2442 : /* special check for undelete operation */
2443 638 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
2444 638 : if (is_undelete != NULL) {
2445 265 : is_undelete->critical = 0;
2446 265 : ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
2447 265 : if (ret != LDB_SUCCESS) {
2448 9 : talloc_free(tmp_ctx);
2449 9 : return ret;
2450 : }
2451 : }
2452 629 : talloc_free(nc_root);
2453 :
2454 : /* Look for the parent */
2455 :
2456 629 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
2457 : req->op.rename.olddn, acl_attrs,
2458 : DSDB_FLAG_NEXT_MODULE |
2459 : DSDB_FLAG_AS_SYSTEM |
2460 : DSDB_SEARCH_SHOW_RECYCLED, req);
2461 : /* we should be able to find the parent */
2462 629 : if (ret != LDB_SUCCESS) {
2463 0 : DEBUG(10,("acl: failed to find object %s\n",
2464 : ldb_dn_get_linearized(req->op.rename.olddn)));
2465 0 : talloc_free(tmp_ctx);
2466 0 : return ret;
2467 : }
2468 :
2469 629 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2470 629 : if (ret != LDB_SUCCESS) {
2471 0 : talloc_free(tmp_ctx);
2472 0 : return ldb_operr(ldb);
2473 : }
2474 629 : if (!sd) {
2475 0 : talloc_free(tmp_ctx);
2476 0 : return ldb_operr(ldb);
2477 : }
2478 :
2479 629 : schema = dsdb_get_schema(ldb, acl_res);
2480 629 : if (!schema) {
2481 0 : talloc_free(tmp_ctx);
2482 0 : return ldb_operr(ldb);
2483 : }
2484 :
2485 629 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2486 :
2487 629 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2488 629 : if (!objectclass) {
2489 0 : talloc_free(tmp_ctx);
2490 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2491 : "acl_modify: Error retrieving object class for GUID.");
2492 : }
2493 :
2494 629 : attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
2495 629 : if (attr == NULL) {
2496 0 : talloc_free(tmp_ctx);
2497 0 : return ldb_operr(ldb);
2498 : }
2499 :
2500 629 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2501 : SEC_ADS_WRITE_PROP,
2502 : attr, objectclass);
2503 629 : if (ret != LDB_SUCCESS) {
2504 19 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2505 : "Object %s has no wp on %s\n",
2506 : ldb_dn_get_linearized(req->op.rename.olddn),
2507 19 : attr->lDAPDisplayName);
2508 19 : dsdb_acl_debug(sd,
2509 : acl_user_token(module),
2510 : req->op.rename.olddn,
2511 : true,
2512 : 10);
2513 19 : talloc_free(tmp_ctx);
2514 19 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2515 : }
2516 :
2517 610 : rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
2518 610 : if (rdn_name == NULL) {
2519 0 : talloc_free(tmp_ctx);
2520 0 : return ldb_operr(ldb);
2521 : }
2522 :
2523 610 : attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2524 610 : if (attr == NULL) {
2525 0 : talloc_free(tmp_ctx);
2526 0 : return ldb_operr(ldb);
2527 : }
2528 :
2529 610 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2530 : SEC_ADS_WRITE_PROP,
2531 : attr, objectclass);
2532 610 : if (ret != LDB_SUCCESS) {
2533 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2534 : "Object %s has no wp on %s\n",
2535 : ldb_dn_get_linearized(req->op.rename.olddn),
2536 9 : attr->lDAPDisplayName);
2537 9 : dsdb_acl_debug(sd,
2538 : acl_user_token(module),
2539 : req->op.rename.olddn,
2540 : true,
2541 : 10);
2542 9 : talloc_free(tmp_ctx);
2543 9 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2544 : }
2545 :
2546 601 : if (ldb_dn_compare(oldparent, newparent) == 0) {
2547 : /* regular rename, not move, nothing more to do */
2548 232 : talloc_free(tmp_ctx);
2549 232 : return ldb_next_request(module, req);
2550 : }
2551 :
2552 : /* new parent should have create child */
2553 369 : ret = dsdb_module_check_access_on_dn(module, req, newparent,
2554 : SEC_ADS_CREATE_CHILD,
2555 : &objectclass->schemaIDGUID, req);
2556 369 : if (ret != LDB_SUCCESS) {
2557 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2558 : "acl:access_denied renaming %s",
2559 : ldb_dn_get_linearized(req->op.rename.olddn));
2560 9 : talloc_free(tmp_ctx);
2561 9 : return ret;
2562 : }
2563 :
2564 : /* do we have delete object on the object? */
2565 : /* this access is not necessary for undelete ops */
2566 360 : if (is_undelete == NULL) {
2567 126 : ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
2568 : SEC_STD_DELETE,
2569 : objectclass);
2570 126 : if (ret == LDB_SUCCESS) {
2571 99 : talloc_free(tmp_ctx);
2572 99 : return ldb_next_request(module, req);
2573 : }
2574 : /* what about delete child on the current parent */
2575 27 : ret = dsdb_module_check_access_on_dn(module, req, oldparent,
2576 : SEC_ADS_DELETE_CHILD,
2577 : &objectclass->schemaIDGUID,
2578 : req);
2579 27 : if (ret != LDB_SUCCESS) {
2580 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2581 : "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
2582 9 : talloc_free(tmp_ctx);
2583 9 : return ldb_module_done(req, NULL, NULL, ret);
2584 : }
2585 : }
2586 252 : talloc_free(tmp_ctx);
2587 :
2588 252 : return ldb_next_request(module, req);
2589 : }
2590 :
2591 826249 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
2592 : struct acl_private *data)
2593 : {
2594 17500 : struct dsdb_attribute *a;
2595 826249 : uint32_t n = 0;
2596 :
2597 826249 : if (data->acl_search) {
2598 : /*
2599 : * If acl:search is activated, the acl_read module
2600 : * protects confidential attributes.
2601 : */
2602 808749 : return LDB_SUCCESS;
2603 : }
2604 :
2605 0 : if ((ac->schema == data->cached_schema_ptr) &&
2606 0 : (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
2607 : {
2608 0 : return LDB_SUCCESS;
2609 : }
2610 :
2611 0 : data->cached_schema_ptr = NULL;
2612 0 : data->cached_schema_loaded_usn = 0;
2613 0 : data->cached_schema_metadata_usn = 0;
2614 0 : TALLOC_FREE(data->confidential_attrs);
2615 :
2616 0 : if (ac->schema == NULL) {
2617 0 : return LDB_SUCCESS;
2618 : }
2619 :
2620 0 : for (a = ac->schema->attributes; a; a = a->next) {
2621 0 : const char **attrs = data->confidential_attrs;
2622 :
2623 0 : if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
2624 0 : continue;
2625 : }
2626 :
2627 0 : attrs = talloc_realloc(data, attrs, const char *, n + 2);
2628 0 : if (attrs == NULL) {
2629 0 : TALLOC_FREE(data->confidential_attrs);
2630 0 : return ldb_module_oom(ac->module);
2631 : }
2632 :
2633 0 : attrs[n] = a->lDAPDisplayName;
2634 0 : attrs[n+1] = NULL;
2635 0 : n++;
2636 :
2637 0 : data->confidential_attrs = attrs;
2638 : }
2639 :
2640 0 : data->cached_schema_ptr = ac->schema;
2641 0 : data->cached_schema_metadata_usn = ac->schema->metadata_usn;
2642 :
2643 0 : return LDB_SUCCESS;
2644 : }
2645 :
2646 46425692 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2647 : {
2648 1501619 : struct acl_context *ac;
2649 1501619 : struct acl_private *data;
2650 1501619 : struct ldb_result *acl_res;
2651 1501619 : static const char *acl_attrs[] = {
2652 : "objectClass",
2653 : "nTSecurityDescriptor",
2654 : "objectSid",
2655 : NULL
2656 : };
2657 1501619 : int ret;
2658 1501619 : unsigned int i;
2659 :
2660 46425692 : ac = talloc_get_type(req->context, struct acl_context);
2661 46425692 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2662 46425692 : if (!ares) {
2663 0 : return ldb_module_done(ac->req, NULL, NULL,
2664 : LDB_ERR_OPERATIONS_ERROR);
2665 : }
2666 46425692 : if (ares->error != LDB_SUCCESS) {
2667 1667248 : return ldb_module_done(ac->req, ares->controls,
2668 : ares->response, ares->error);
2669 : }
2670 :
2671 44758444 : switch (ares->type) {
2672 35353295 : case LDB_REPLY_ENTRY:
2673 35353295 : if (ac->constructed_attrs) {
2674 346 : ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
2675 : acl_attrs,
2676 : DSDB_FLAG_NEXT_MODULE |
2677 : DSDB_FLAG_AS_SYSTEM |
2678 : DSDB_SEARCH_SHOW_RECYCLED,
2679 : req);
2680 346 : if (ret != LDB_SUCCESS) {
2681 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2682 : }
2683 : }
2684 :
2685 35353295 : if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2686 22 : ret = acl_allowedAttributes(ac->module, ac->schema,
2687 22 : acl_res->msgs[0],
2688 : ares->message, ac);
2689 22 : if (ret != LDB_SUCCESS) {
2690 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2691 : }
2692 : }
2693 :
2694 35353295 : if (ac->allowedChildClasses) {
2695 0 : ret = acl_childClasses(ac->module, ac->schema,
2696 0 : acl_res->msgs[0],
2697 : ares->message,
2698 : "allowedChildClasses");
2699 0 : if (ret != LDB_SUCCESS) {
2700 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2701 : }
2702 : }
2703 :
2704 35353295 : if (ac->allowedChildClassesEffective) {
2705 18 : ret = acl_childClassesEffective(ac->module, ac->schema,
2706 18 : acl_res->msgs[0],
2707 : ares->message, ac);
2708 18 : if (ret != LDB_SUCCESS) {
2709 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2710 : }
2711 : }
2712 :
2713 35353295 : if (ac->sDRightsEffective) {
2714 306 : ret = acl_sDRightsEffective(ac->module,
2715 306 : acl_res->msgs[0],
2716 : ares->message, ac);
2717 306 : if (ret != LDB_SUCCESS) {
2718 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2719 : }
2720 : }
2721 :
2722 35353295 : if (data == NULL) {
2723 0 : return ldb_module_send_entry(ac->req, ares->message,
2724 : ares->controls);
2725 : }
2726 :
2727 35353295 : if (ac->am_system) {
2728 0 : return ldb_module_send_entry(ac->req, ares->message,
2729 : ares->controls);
2730 : }
2731 :
2732 35353295 : if (ac->am_administrator) {
2733 13786542 : return ldb_module_send_entry(ac->req, ares->message,
2734 : ares->controls);
2735 : }
2736 :
2737 21566753 : if (data->confidential_attrs != NULL) {
2738 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2739 0 : ldb_msg_remove_attr(ares->message,
2740 0 : data->confidential_attrs[i]);
2741 : }
2742 : }
2743 :
2744 21566753 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2745 :
2746 786452 : case LDB_REPLY_REFERRAL:
2747 786452 : return ldb_module_send_referral(ac->req, ares->referral);
2748 :
2749 8618697 : case LDB_REPLY_DONE:
2750 8618697 : return ldb_module_done(ac->req, ares->controls,
2751 : ares->response, LDB_SUCCESS);
2752 :
2753 : }
2754 0 : return LDB_SUCCESS;
2755 : }
2756 :
2757 32772584 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
2758 : {
2759 1774968 : struct ldb_context *ldb;
2760 1774968 : struct acl_context *ac;
2761 32772584 : struct ldb_parse_tree *down_tree = req->op.search.tree;
2762 1774968 : struct ldb_request *down_req;
2763 1774968 : struct acl_private *data;
2764 1774968 : int ret;
2765 1774968 : unsigned int i;
2766 32772584 : bool modify_search = true;
2767 :
2768 32772584 : if (ldb_dn_is_special(req->op.search.base)) {
2769 1137932 : return ldb_next_request(module, req);
2770 : }
2771 :
2772 31634652 : ldb = ldb_module_get_ctx(module);
2773 :
2774 31634652 : ac = talloc_zero(req, struct acl_context);
2775 31634652 : if (ac == NULL) {
2776 0 : return ldb_oom(ldb);
2777 : }
2778 31634652 : data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2779 :
2780 31634652 : ac->module = module;
2781 31634652 : ac->req = req;
2782 31634652 : ac->am_system = dsdb_module_am_system(module);
2783 31634652 : ac->am_administrator = dsdb_module_am_administrator(module);
2784 31634652 : ac->constructed_attrs = false;
2785 31634652 : ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2786 31634652 : ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2787 31634652 : ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2788 31634652 : ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2789 31634652 : ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2790 31634652 : ac->schema = dsdb_get_schema(ldb, ac);
2791 :
2792 31634652 : ac->constructed_attrs |= ac->allowedAttributes;
2793 31634652 : ac->constructed_attrs |= ac->allowedChildClasses;
2794 31634652 : ac->constructed_attrs |= ac->allowedChildClassesEffective;
2795 31634652 : ac->constructed_attrs |= ac->allowedAttributesEffective;
2796 31634652 : ac->constructed_attrs |= ac->sDRightsEffective;
2797 :
2798 31634652 : if (data == NULL) {
2799 0 : modify_search = false;
2800 : }
2801 31634652 : if (ac->am_system) {
2802 21348147 : modify_search = false;
2803 : }
2804 :
2805 31634652 : if (!ac->constructed_attrs && !modify_search) {
2806 21348147 : talloc_free(ac);
2807 21348147 : return ldb_next_request(module, req);
2808 : }
2809 :
2810 10286505 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2811 10286505 : if (data == NULL) {
2812 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2813 : "acl_private data is missing");
2814 : }
2815 :
2816 10286505 : if (!ac->am_system && !ac->am_administrator) {
2817 826249 : ret = acl_search_update_confidential_attrs(ac, data);
2818 826249 : if (ret != LDB_SUCCESS) {
2819 0 : return ret;
2820 : }
2821 :
2822 826249 : if (data->confidential_attrs != NULL) {
2823 0 : down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2824 0 : if (down_tree == NULL) {
2825 0 : return ldb_oom(ldb);
2826 : }
2827 :
2828 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2829 0 : ldb_parse_tree_attr_replace(down_tree,
2830 0 : data->confidential_attrs[i],
2831 : "kludgeACLredactedattribute");
2832 : }
2833 : }
2834 : }
2835 :
2836 10286505 : ret = ldb_build_search_req_ex(&down_req,
2837 : ldb, ac,
2838 : req->op.search.base,
2839 : req->op.search.scope,
2840 : down_tree,
2841 : req->op.search.attrs,
2842 : req->controls,
2843 : ac, acl_search_callback,
2844 : req);
2845 10286505 : LDB_REQ_SET_LOCATION(down_req);
2846 10286505 : if (ret != LDB_SUCCESS) {
2847 0 : return ret;
2848 : }
2849 : /* perform the search */
2850 10286505 : return ldb_next_request(module, down_req);
2851 : }
2852 :
2853 1280922 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2854 : {
2855 1280922 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2856 1280922 : struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2857 :
2858 : /* allow everybody to read the sequence number */
2859 1280922 : if (strcmp(req->op.extended.oid,
2860 : LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2861 1275306 : return ldb_next_request(module, req);
2862 : }
2863 :
2864 6134 : if (dsdb_module_am_system(module) ||
2865 518 : dsdb_module_am_administrator(module) || as_system) {
2866 5616 : return ldb_next_request(module, req);
2867 : } else {
2868 0 : ldb_asprintf_errstring(ldb,
2869 : "acl_extended: "
2870 : "attempted database modify not permitted. "
2871 : "User %s is not SYSTEM or an administrator",
2872 : acl_user_name(req, module));
2873 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2874 : }
2875 : }
2876 :
2877 : static const struct ldb_module_ops ldb_acl_module_ops = {
2878 : .name = "acl",
2879 : .search = acl_search,
2880 : .add = acl_add,
2881 : .modify = acl_modify,
2882 : .del = acl_delete,
2883 : .rename = acl_rename,
2884 : .extended = acl_extended,
2885 : .init_context = acl_module_init
2886 : };
2887 :
2888 5908 : int ldb_acl_module_init(const char *version)
2889 : {
2890 5908 : LDB_MODULE_CHECK_VERSION(version);
2891 5908 : return ldb_register_module(&ldb_acl_module_ops);
2892 : }
|