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 182004 : static int acl_module_init(struct ldb_module *module)
73 : {
74 6016 : struct ldb_context *ldb;
75 6016 : struct acl_private *data;
76 6016 : int ret;
77 :
78 182004 : ldb = ldb_module_get_ctx(module);
79 :
80 182004 : data = talloc_zero(module, struct acl_private);
81 182004 : if (data == NULL) {
82 0 : return ldb_oom(ldb);
83 : }
84 :
85 182004 : data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
86 : NULL, "acl", "search", true);
87 182004 : ldb_module_set_private(module, data);
88 :
89 182004 : ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
90 182004 : 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 182004 : 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 953 : 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 953 : TALLOC_CTX *tmp_ctx = NULL;
833 953 : struct ldb_context *ldb = ldb_module_get_ctx(module);
834 953 : const struct dsdb_schema *schema = NULL;
835 953 : const struct ldb_message_element *allowed_suffixes = NULL;
836 953 : struct ldb_result *nc_res = NULL;
837 953 : struct ldb_dn *nc_root = NULL;
838 953 : const char *nc_dns_name = NULL;
839 953 : const char *dnsHostName_str = NULL;
840 75 : size_t dns_host_name_len;
841 75 : size_t account_name_len;
842 953 : const struct ldb_message *msg = NULL;
843 953 : const struct ldb_message *search_res = NULL;
844 953 : const struct ldb_val *samAccountName = NULL;
845 953 : const struct ldb_val *dnsHostName = NULL;
846 953 : 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 953 : tmp_ctx = talloc_new(mem_ctx);
855 953 : if (tmp_ctx == NULL) {
856 0 : return ldb_oom(ldb);
857 : }
858 :
859 953 : if (req->operation == LDB_MODIFY) {
860 953 : msg = req->op.mod.message;
861 0 : } else if (req->operation == LDB_ADD) {
862 0 : msg = req->op.add.message;
863 : }
864 :
865 953 : 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 917 : ret = acl_check_access_on_attribute(module,
876 : tmp_ctx,
877 : sd,
878 : sid,
879 : SEC_ADS_WRITE_PROP,
880 : attr, objectclass);
881 917 : if (ret == LDB_SUCCESS) {
882 713 : talloc_free(tmp_ctx);
883 713 : 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 8016 : 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 8016 : 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 8016 : const struct ldb_message *msg = NULL;
1124 :
1125 8016 : if (req->operation == LDB_MODIFY) {
1126 8016 : 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 8016 : 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 7956 : 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 543727 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
1182 : {
1183 83679 : int ret;
1184 83679 : struct ldb_dn *parent;
1185 83679 : struct ldb_context *ldb;
1186 83679 : const struct dsdb_schema *schema;
1187 83679 : const struct dsdb_class *objectclass;
1188 543727 : const struct dsdb_class *computer_objectclass = NULL;
1189 543727 : const struct ldb_message_element *oc_el = NULL;
1190 83679 : struct ldb_message_element sorted_oc_el;
1191 543727 : struct ldb_control *sd_ctrl = NULL;
1192 83679 : struct ldb_message_element *el;
1193 543727 : unsigned int instanceType = 0;
1194 543727 : struct dsdb_control_calculated_default_sd *control_sd = NULL;
1195 543727 : const struct dsdb_attribute *attr = NULL;
1196 543727 : const char **must_contain = NULL;
1197 543727 : const struct ldb_message *msg = req->op.add.message;
1198 543727 : const struct dom_sid *domain_sid = NULL;
1199 543727 : int i = 0;
1200 83679 : bool attribute_authorization;
1201 83679 : bool is_subclass;
1202 :
1203 543727 : if (ldb_dn_is_special(msg->dn)) {
1204 538 : return ldb_next_request(module, req);
1205 : }
1206 :
1207 543189 : if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
1208 : {
1209 4540 : return ldb_next_request(module, req);
1210 : }
1211 :
1212 538649 : ldb = ldb_module_get_ctx(module);
1213 538649 : domain_sid = samdb_domain_sid(ldb);
1214 :
1215 538649 : parent = ldb_dn_get_parent(req, msg->dn);
1216 538649 : if (parent == NULL) {
1217 0 : return ldb_oom(ldb);
1218 : }
1219 :
1220 538649 : schema = dsdb_get_schema(ldb, req);
1221 538649 : if (!schema) {
1222 0 : return ldb_operr(ldb);
1223 : }
1224 :
1225 : /* Find the objectclass of the new account. */
1226 :
1227 538649 : oc_el = ldb_msg_find_element(msg, "objectclass");
1228 538649 : if (oc_el == NULL) {
1229 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1230 : "acl: unable to find or validate structural objectClass on %s\n",
1231 0 : ldb_dn_get_linearized(msg->dn));
1232 0 : return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
1233 : }
1234 :
1235 538649 : schema = dsdb_get_schema(ldb, req);
1236 538649 : if (schema == NULL) {
1237 0 : return ldb_operr(ldb);
1238 : }
1239 :
1240 538649 : ret = dsdb_sort_objectClass_attr(ldb, schema, oc_el, req, &sorted_oc_el);
1241 538649 : if (ret != LDB_SUCCESS) {
1242 0 : return ret;
1243 : }
1244 :
1245 538649 : objectclass = dsdb_get_last_structural_class(schema, &sorted_oc_el);
1246 538649 : if (objectclass == NULL) {
1247 0 : return ldb_operr(ldb);
1248 : }
1249 :
1250 538649 : el = ldb_msg_find_element(msg, "instanceType");
1251 538649 : if ((el != NULL) && (el->num_values != 1)) {
1252 1 : ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
1253 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
1254 : }
1255 :
1256 538648 : instanceType = ldb_msg_find_attr_as_uint(msg,
1257 : "instanceType", 0);
1258 538648 : if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
1259 108 : static const char *no_attrs[] = { NULL };
1260 108 : struct ldb_result *partition_res;
1261 108 : struct ldb_dn *partitions_dn;
1262 :
1263 609 : partitions_dn = samdb_partitions_dn(ldb, req);
1264 609 : if (!partitions_dn) {
1265 0 : ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
1266 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1267 : }
1268 :
1269 609 : ret = dsdb_module_search(module, req, &partition_res,
1270 : partitions_dn, LDB_SCOPE_ONELEVEL,
1271 : no_attrs,
1272 : DSDB_FLAG_NEXT_MODULE |
1273 : DSDB_FLAG_AS_SYSTEM |
1274 : DSDB_SEARCH_ONE_ONLY |
1275 : DSDB_SEARCH_SHOW_RECYCLED,
1276 : req,
1277 : "(&(nCName=%s)(objectClass=crossRef))",
1278 609 : ldb_dn_get_linearized(msg->dn));
1279 :
1280 609 : if (ret == LDB_SUCCESS) {
1281 : /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1282 0 : ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
1283 : SEC_ADS_WRITE_PROP,
1284 : &objectclass->schemaIDGUID, req);
1285 0 : if (ret != LDB_SUCCESS) {
1286 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1287 : "acl: ACL check failed on crossRef object %s: %s\n",
1288 0 : ldb_dn_get_linearized(partition_res->msgs[0]->dn),
1289 : ldb_errstring(ldb));
1290 0 : return ret;
1291 : }
1292 :
1293 : /*
1294 : * TODO: Remaining checks, like if we are
1295 : * the naming master etc need to be handled
1296 : * in the instanceType module
1297 : */
1298 : /* Note - do we need per-attribute checks? */
1299 0 : return ldb_next_request(module, req);
1300 : }
1301 :
1302 : /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1303 609 : ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
1304 : SEC_ADS_CREATE_CHILD,
1305 : &objectclass->schemaIDGUID, req);
1306 990 : if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1307 381 : ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
1308 : {
1309 : /* Allow provision bootstrap */
1310 315 : ret = LDB_SUCCESS;
1311 : }
1312 543 : if (ret != LDB_SUCCESS) {
1313 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1314 : "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
1315 : ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
1316 0 : return ret;
1317 : }
1318 :
1319 : /*
1320 : * TODO: Remaining checks, like if we are the naming
1321 : * master and adding the crossRef object need to be
1322 : * handled in the instanceType module
1323 : */
1324 : } else {
1325 538039 : ret = dsdb_module_check_access_on_dn(module, req, parent,
1326 : SEC_ADS_CREATE_CHILD,
1327 : &objectclass->schemaIDGUID, req);
1328 538039 : if (ret != LDB_SUCCESS) {
1329 24 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1330 : "acl: unable to get access to %s\n",
1331 24 : ldb_dn_get_linearized(msg->dn));
1332 24 : return ret;
1333 : }
1334 : }
1335 :
1336 538624 : attribute_authorization = dsdb_attribute_authz_on_ldap_add(module,
1337 : req,
1338 : req);
1339 538624 : if (!attribute_authorization) {
1340 : /* Skip the remaining checks */
1341 522892 : goto success;
1342 : }
1343 :
1344 : /* Check if we have computer objectclass. */
1345 15732 : computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
1346 15732 : if (computer_objectclass == NULL) {
1347 0 : return ldb_operr(ldb);
1348 : }
1349 :
1350 15732 : is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
1351 15732 : if (!is_subclass) {
1352 : /*
1353 : * This object is not a computer (or derived from computer), so
1354 : * skip the remaining checks.
1355 : */
1356 14958 : goto success;
1357 : }
1358 :
1359 : /*
1360 : * we have established we have CC right, now check per-attribute
1361 : * access based on the default SD
1362 : */
1363 :
1364 774 : sd_ctrl = ldb_request_get_control(req,
1365 : DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID);
1366 774 : if (sd_ctrl == NULL) {
1367 0 : goto success;
1368 : }
1369 :
1370 : {
1371 774 : TALLOC_CTX *tmp_ctx = talloc_new(req);
1372 774 : control_sd = (struct dsdb_control_calculated_default_sd *) sd_ctrl->data;
1373 774 : DBG_DEBUG("Received cookie descriptor %s\n\n",
1374 : sddl_encode(tmp_ctx, control_sd->default_sd, domain_sid));
1375 774 : TALLOC_FREE(tmp_ctx);
1376 : /* Mark the "change" control as uncritical (done) */
1377 774 : sd_ctrl->critical = false;
1378 : }
1379 :
1380 : /*
1381 : * At this point we do not yet have the object's SID, so we
1382 : * leave it empty. It is irrelevant, as it is used to expand
1383 : * Principal-Self, and rights granted to PS will have no effect
1384 : * in this case
1385 : */
1386 : /* check if we have WD, no need to perform other attribute checks if we do */
1387 774 : attr = dsdb_attribute_by_lDAPDisplayName(schema, "nTSecurityDescriptor");
1388 774 : if (attr == NULL) {
1389 0 : return ldb_operr(ldb);
1390 : }
1391 :
1392 774 : if (control_sd->specified_sacl) {
1393 18 : const struct security_token *token = acl_user_token(module);
1394 18 : bool has_priv = security_token_has_privilege(token, SEC_PRIV_SECURITY);
1395 18 : if (!has_priv) {
1396 18 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1397 : }
1398 : }
1399 :
1400 756 : ret = acl_check_access_on_attribute(module,
1401 : req,
1402 : control_sd->default_sd,
1403 : NULL,
1404 : SEC_STD_WRITE_DAC,
1405 : attr,
1406 : objectclass);
1407 756 : if (ret == LDB_SUCCESS) {
1408 486 : goto success;
1409 : }
1410 :
1411 270 : if (control_sd->specified_sd) {
1412 126 : bool block_owner_rights = dsdb_block_owner_implicit_rights(module,
1413 : req,
1414 : req);
1415 126 : if (block_owner_rights) {
1416 108 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1417 : "Object %s has no SD modification rights",
1418 108 : ldb_dn_get_linearized(msg->dn));
1419 108 : dsdb_acl_debug(control_sd->default_sd,
1420 : acl_user_token(module),
1421 108 : msg->dn,
1422 : true,
1423 : 10);
1424 108 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1425 108 : return ret;
1426 : }
1427 : }
1428 :
1429 162 : must_contain = dsdb_full_attribute_list(req, schema, &sorted_oc_el,
1430 : DSDB_SCHEMA_ALL_MUST);
1431 702 : for (i=0; i < msg->num_elements; i++) {
1432 603 : el = &msg->elements[i];
1433 :
1434 603 : attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1435 603 : if (attr == NULL && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1436 0 : ldb_asprintf_errstring(ldb, "acl_add: attribute '%s' "
1437 : "on entry '%s' was not found in the schema!",
1438 : el->name,
1439 0 : ldb_dn_get_linearized(msg->dn));
1440 0 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1441 0 : return ret;
1442 : }
1443 :
1444 603 : if (attr != NULL) {
1445 594 : bool found = str_list_check(must_contain, attr->lDAPDisplayName);
1446 : /* do not check the mandatory attributes */
1447 594 : if (found) {
1448 450 : continue;
1449 : }
1450 : }
1451 :
1452 153 : if (ldb_attr_cmp("dBCSPwd", el->name) == 0 ||
1453 153 : ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1454 144 : ldb_attr_cmp("userPassword", el->name) == 0 ||
1455 126 : ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1456 36 : continue;
1457 117 : } else if (ldb_attr_cmp("member", el->name) == 0) {
1458 0 : ret = acl_check_self_membership(req,
1459 : module,
1460 : req,
1461 : control_sd->default_sd,
1462 : NULL,
1463 : attr,
1464 : objectclass);
1465 0 : if (ret != LDB_SUCCESS) {
1466 0 : return ret;
1467 : }
1468 117 : } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1469 36 : ret = acl_check_spn(req,
1470 : module,
1471 : req,
1472 : el,
1473 : control_sd->default_sd,
1474 : NULL,
1475 : attr,
1476 : objectclass,
1477 : NULL);
1478 36 : if (ret != LDB_SUCCESS) {
1479 18 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1480 : "Object %s cannot be created with spn",
1481 18 : ldb_dn_get_linearized(msg->dn));
1482 18 : dsdb_acl_debug(control_sd->default_sd,
1483 : acl_user_token(module),
1484 18 : msg->dn,
1485 : true,
1486 : 10);
1487 18 : return ret;
1488 : }
1489 81 : } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
1490 0 : ret = acl_check_dns_host_name(req,
1491 : module,
1492 : req,
1493 : el,
1494 : control_sd->default_sd,
1495 : NULL,
1496 : attr,
1497 : objectclass,
1498 : NULL);
1499 0 : if (ret != LDB_SUCCESS) {
1500 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1501 : "Object %s cannot be created with dnsHostName",
1502 0 : ldb_dn_get_linearized(msg->dn));
1503 0 : dsdb_acl_debug(control_sd->default_sd,
1504 : acl_user_token(module),
1505 0 : msg->dn,
1506 : true,
1507 : 10);
1508 0 : return ret;
1509 : }
1510 : } else {
1511 81 : ret = acl_check_access_on_attribute(module,
1512 : req,
1513 : control_sd->default_sd,
1514 : NULL,
1515 : SEC_ADS_WRITE_PROP,
1516 : attr,
1517 : objectclass);
1518 81 : if (ret != LDB_SUCCESS) {
1519 45 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1520 : "Object %s has no write property access",
1521 45 : ldb_dn_get_linearized(msg->dn));
1522 45 : dsdb_acl_debug(control_sd->default_sd,
1523 : acl_user_token(module),
1524 45 : msg->dn,
1525 : true,
1526 : 10);
1527 45 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1528 45 : return ret;
1529 : }
1530 : }
1531 : }
1532 99 : success:
1533 538435 : return ldb_next_request(module, req);
1534 : }
1535 :
1536 17072 : static int acl_check_password_rights(
1537 : TALLOC_CTX *mem_ctx,
1538 : struct ldb_module *module,
1539 : struct ldb_request *req,
1540 : struct security_descriptor *sd,
1541 : struct dom_sid *sid,
1542 : const struct dsdb_class *objectclass,
1543 : bool userPassword,
1544 : struct dsdb_control_password_acl_validation **control_for_response)
1545 : {
1546 17072 : int ret = LDB_SUCCESS;
1547 17072 : unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
1548 17072 : unsigned int del_val_cnt = 0, add_val_cnt = 0;
1549 72 : struct ldb_message_element *el;
1550 72 : struct ldb_message *msg;
1551 17072 : struct ldb_control *c = NULL;
1552 17072 : const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
1553 : "unicodePwd", NULL }, **l;
1554 17072 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1555 17072 : struct dsdb_control_password_acl_validation *pav = NULL;
1556 :
1557 17072 : if (tmp_ctx == NULL) {
1558 0 : return LDB_ERR_OPERATIONS_ERROR;
1559 : }
1560 :
1561 17072 : pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
1562 17072 : if (pav == NULL) {
1563 0 : talloc_free(tmp_ctx);
1564 0 : return LDB_ERR_OPERATIONS_ERROR;
1565 : }
1566 : /*
1567 : * Set control_for_response to pav so it can be added to the response
1568 : * and be passed up to the audit_log module which uses it to identify
1569 : * password reset attempts.
1570 : */
1571 17072 : *control_for_response = pav;
1572 :
1573 17072 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1574 17072 : if (c != NULL) {
1575 522 : pav->pwd_reset = false;
1576 :
1577 : /*
1578 : * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1579 : * have a user password change and not a set as the message
1580 : * looks like. In it's value blob it contains the NT and/or LM
1581 : * hash of the old password specified by the user. This control
1582 : * is used by the SAMR and "kpasswd" password change mechanisms.
1583 : *
1584 : * This control can't be used by real LDAP clients,
1585 : * the only caller is samdb_set_password_internal(),
1586 : * so we don't have to strict verification of the input.
1587 : */
1588 522 : ret = acl_check_extended_right(tmp_ctx,
1589 : module,
1590 : req,
1591 : objectclass,
1592 : sd,
1593 : acl_user_token(module),
1594 : GUID_DRS_USER_CHANGE_PASSWORD,
1595 : SEC_ADS_CONTROL_ACCESS,
1596 : sid);
1597 522 : goto checked;
1598 : }
1599 :
1600 16550 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1601 16550 : if (c != NULL) {
1602 310 : pav->pwd_reset = true;
1603 :
1604 : /*
1605 : * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1606 : * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1607 : * have a force password set.
1608 : * This control is used by the SAMR/NETLOGON/LSA password
1609 : * reset mechanisms.
1610 : *
1611 : * This control can't be used by real LDAP clients,
1612 : * the only caller is samdb_set_password_internal(),
1613 : * so we don't have to strict verification of the input.
1614 : */
1615 310 : ret = acl_check_extended_right(tmp_ctx,
1616 : module,
1617 : req,
1618 : objectclass,
1619 : sd,
1620 : acl_user_token(module),
1621 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1622 : SEC_ADS_CONTROL_ACCESS,
1623 : sid);
1624 310 : goto checked;
1625 : }
1626 :
1627 16240 : el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1628 16240 : if (el != NULL) {
1629 : /*
1630 : * dBCSPwd is only allowed with a control.
1631 : */
1632 0 : talloc_free(tmp_ctx);
1633 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1634 : }
1635 :
1636 16240 : msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1637 16240 : if (msg == NULL) {
1638 0 : return ldb_module_oom(module);
1639 : }
1640 64960 : for (l = passwordAttrs; *l != NULL; l++) {
1641 48720 : if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1642 13457 : continue;
1643 : }
1644 :
1645 53578 : while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1646 18315 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1647 2084 : ++del_attr_cnt;
1648 2084 : del_val_cnt += el->num_values;
1649 : }
1650 18315 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1651 2048 : ++add_attr_cnt;
1652 2048 : add_val_cnt += el->num_values;
1653 : }
1654 18315 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1655 14183 : ++rep_attr_cnt;
1656 : }
1657 18315 : ldb_msg_remove_element(msg, el);
1658 : }
1659 : }
1660 :
1661 : /* single deletes will be handled by the "password_hash" LDB module
1662 : * later in the stack, so we let it though here */
1663 16240 : if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1664 63 : talloc_free(tmp_ctx);
1665 63 : return LDB_SUCCESS;
1666 : }
1667 :
1668 :
1669 16177 : if (rep_attr_cnt > 0) {
1670 14165 : pav->pwd_reset = true;
1671 :
1672 14165 : ret = acl_check_extended_right(tmp_ctx,
1673 : module,
1674 : req,
1675 : objectclass,
1676 : sd,
1677 : acl_user_token(module),
1678 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1679 : SEC_ADS_CONTROL_ACCESS,
1680 : sid);
1681 14165 : goto checked;
1682 : }
1683 :
1684 2012 : if (add_attr_cnt != del_attr_cnt) {
1685 99 : pav->pwd_reset = true;
1686 :
1687 99 : ret = acl_check_extended_right(tmp_ctx,
1688 : module,
1689 : req,
1690 : objectclass,
1691 : sd,
1692 : acl_user_token(module),
1693 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1694 : SEC_ADS_CONTROL_ACCESS,
1695 : sid);
1696 99 : goto checked;
1697 : }
1698 :
1699 1913 : if (add_val_cnt == 1 && del_val_cnt == 1) {
1700 1114 : pav->pwd_reset = false;
1701 :
1702 1114 : ret = acl_check_extended_right(tmp_ctx,
1703 : module,
1704 : req,
1705 : objectclass,
1706 : sd,
1707 : acl_user_token(module),
1708 : GUID_DRS_USER_CHANGE_PASSWORD,
1709 : SEC_ADS_CONTROL_ACCESS,
1710 : sid);
1711 : /* Very strange, but we get constraint violation in this case */
1712 1114 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1713 18 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1714 : }
1715 1114 : goto checked;
1716 : }
1717 :
1718 799 : if (add_val_cnt == 1 && del_val_cnt == 0) {
1719 529 : pav->pwd_reset = true;
1720 :
1721 529 : ret = acl_check_extended_right(tmp_ctx,
1722 : module,
1723 : req,
1724 : objectclass,
1725 : sd,
1726 : acl_user_token(module),
1727 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1728 : SEC_ADS_CONTROL_ACCESS,
1729 : sid);
1730 : /* Very strange, but we get constraint violation in this case */
1731 529 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1732 27 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1733 : }
1734 529 : goto checked;
1735 : }
1736 :
1737 : /*
1738 : * Everything else is handled by the password_hash module where it will
1739 : * fail, but with the correct error code when the module is again
1740 : * checking the attributes. As the change request will lack the
1741 : * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1742 : * any modification attempt that went this way will be rejected.
1743 : */
1744 :
1745 270 : talloc_free(tmp_ctx);
1746 270 : return LDB_SUCCESS;
1747 :
1748 16739 : checked:
1749 16739 : if (ret != LDB_SUCCESS) {
1750 142 : dsdb_acl_debug(sd, acl_user_token(module),
1751 142 : req->op.mod.message->dn,
1752 : true,
1753 : 10);
1754 142 : talloc_free(tmp_ctx);
1755 142 : return ret;
1756 : }
1757 :
1758 16597 : ret = ldb_request_add_control(req,
1759 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1760 16597 : if (ret != LDB_SUCCESS) {
1761 0 : ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1762 : "Unable to register ACL validation control!\n");
1763 0 : return ret;
1764 : }
1765 16525 : return LDB_SUCCESS;
1766 : }
1767 :
1768 : /*
1769 : * Context needed by acl_callback
1770 : */
1771 : struct acl_callback_context {
1772 : struct ldb_request *request;
1773 : struct ldb_module *module;
1774 : };
1775 :
1776 : /*
1777 : * @brief Copy the password validation control to the reply.
1778 : *
1779 : * Copy the dsdb_control_password_acl_validation control from the request,
1780 : * to the reply. The control is used by the audit_log module to identify
1781 : * password rests.
1782 : *
1783 : * @param req the ldb request.
1784 : * @param ares the result, updated with the control.
1785 : */
1786 118178 : static void copy_password_acl_validation_control(
1787 : struct ldb_request *req,
1788 : struct ldb_reply *ares)
1789 : {
1790 118178 : struct ldb_control *pav_ctrl = NULL;
1791 118178 : struct dsdb_control_password_acl_validation *pav = NULL;
1792 :
1793 118178 : pav_ctrl = ldb_request_get_control(
1794 : discard_const(req),
1795 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1796 118178 : if (pav_ctrl == NULL) {
1797 98466 : return;
1798 : }
1799 :
1800 16597 : pav = talloc_get_type_abort(
1801 : pav_ctrl->data,
1802 : struct dsdb_control_password_acl_validation);
1803 16597 : if (pav == NULL) {
1804 0 : return;
1805 : }
1806 16597 : ldb_reply_add_control(
1807 : ares,
1808 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1809 : false,
1810 : pav);
1811 : }
1812 : /*
1813 : * @brief call back function for acl_modify.
1814 : *
1815 : * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1816 : * the request to the reply.
1817 : *
1818 : * @param req the ldb_request.
1819 : * @param ares the operation result.
1820 : *
1821 : * @return the LDB_STATUS
1822 : */
1823 118188 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1824 : {
1825 118188 : struct acl_callback_context *ac = NULL;
1826 :
1827 118188 : ac = talloc_get_type(req->context, struct acl_callback_context);
1828 :
1829 118188 : if (!ares) {
1830 0 : return ldb_module_done(
1831 : ac->request,
1832 : NULL,
1833 : NULL,
1834 : LDB_ERR_OPERATIONS_ERROR);
1835 : }
1836 :
1837 : /* pass on to the callback */
1838 118188 : switch (ares->type) {
1839 0 : case LDB_REPLY_ENTRY:
1840 0 : return ldb_module_send_entry(
1841 : ac->request,
1842 : ares->message,
1843 : ares->controls);
1844 :
1845 10 : case LDB_REPLY_REFERRAL:
1846 10 : return ldb_module_send_referral(
1847 : ac->request,
1848 : ares->referral);
1849 :
1850 118178 : case LDB_REPLY_DONE:
1851 : /*
1852 : * Copy the ACL control from the request to the response
1853 : */
1854 118178 : copy_password_acl_validation_control(req, ares);
1855 118178 : return ldb_module_done(
1856 : ac->request,
1857 : ares->controls,
1858 : ares->response,
1859 : ares->error);
1860 :
1861 0 : default:
1862 : /* Can't happen */
1863 0 : return LDB_ERR_OPERATIONS_ERROR;
1864 : }
1865 : }
1866 :
1867 575661 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1868 : {
1869 21578 : int ret;
1870 575661 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1871 21578 : const struct dsdb_schema *schema;
1872 21578 : unsigned int i;
1873 21578 : const struct dsdb_class *objectclass;
1874 21578 : struct ldb_result *acl_res;
1875 21578 : struct security_descriptor *sd;
1876 575661 : struct dom_sid *sid = NULL;
1877 21578 : struct ldb_control *is_undelete;
1878 575661 : struct ldb_control *implicit_validated_write_control = NULL;
1879 21578 : bool userPassword;
1880 575661 : bool password_rights_checked = false;
1881 21578 : TALLOC_CTX *tmp_ctx;
1882 575661 : const struct ldb_message *msg = req->op.mod.message;
1883 21578 : static const char *acl_attrs[] = {
1884 : "nTSecurityDescriptor",
1885 : "objectClass",
1886 : "objectSid",
1887 : NULL
1888 : };
1889 575661 : struct acl_callback_context *context = NULL;
1890 575661 : struct ldb_request *new_req = NULL;
1891 575661 : struct dsdb_control_password_acl_validation *pav = NULL;
1892 575661 : struct ldb_control **controls = NULL;
1893 :
1894 575661 : if (ldb_dn_is_special(msg->dn)) {
1895 715 : return ldb_next_request(module, req);
1896 : }
1897 :
1898 574946 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1899 :
1900 574946 : implicit_validated_write_control = ldb_request_get_control(
1901 : req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
1902 574946 : if (implicit_validated_write_control != NULL) {
1903 147 : implicit_validated_write_control->critical = 0;
1904 : }
1905 :
1906 : /* Don't print this debug statement if elements[0].name is going to be NULL */
1907 574946 : if (msg->num_elements > 0) {
1908 574665 : DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
1909 : }
1910 574946 : if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
1911 : {
1912 455011 : return ldb_next_request(module, req);
1913 : }
1914 :
1915 119935 : tmp_ctx = talloc_new(req);
1916 119935 : if (tmp_ctx == NULL) {
1917 0 : return ldb_oom(ldb);
1918 : }
1919 :
1920 119935 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
1921 : acl_attrs,
1922 : DSDB_FLAG_NEXT_MODULE |
1923 : DSDB_FLAG_AS_SYSTEM |
1924 : DSDB_SEARCH_SHOW_RECYCLED,
1925 : req);
1926 :
1927 119935 : if (ret != LDB_SUCCESS) {
1928 122 : goto fail;
1929 : }
1930 :
1931 119813 : userPassword = dsdb_user_password_support(module, req, req);
1932 :
1933 119813 : schema = dsdb_get_schema(ldb, tmp_ctx);
1934 119813 : if (!schema) {
1935 0 : talloc_free(tmp_ctx);
1936 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1937 : "acl_modify: Error obtaining schema.");
1938 : }
1939 :
1940 119813 : ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1941 119813 : if (ret != LDB_SUCCESS) {
1942 0 : talloc_free(tmp_ctx);
1943 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1944 : "acl_modify: Error retrieving security descriptor.");
1945 : }
1946 : /* Theoretically we pass the check if the object has no sd */
1947 119813 : if (!sd) {
1948 0 : goto success;
1949 : }
1950 :
1951 119813 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1952 119813 : if (!objectclass) {
1953 0 : talloc_free(tmp_ctx);
1954 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1955 : "acl_modify: Error retrieving object class for GUID.");
1956 : }
1957 119813 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1958 278553 : for (i=0; i < msg->num_elements; i++) {
1959 157183 : const struct ldb_message_element *el = &msg->elements[i];
1960 4863 : const struct dsdb_attribute *attr;
1961 :
1962 : /*
1963 : * This basic attribute existence check with the right errorcode
1964 : * is needed since this module is the first one which requests
1965 : * schema attribute information.
1966 : * The complete attribute checking is done in the
1967 : * "objectclass_attrs" module behind this one.
1968 : *
1969 : * NOTE: "clearTextPassword" is not defined in the schema.
1970 : */
1971 157183 : attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1972 157183 : if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1973 4 : ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
1974 : "on entry '%s' was not found in the schema!",
1975 2 : req->op.mod.message->elements[i].name,
1976 2 : ldb_dn_get_linearized(req->op.mod.message->dn));
1977 2 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1978 2 : goto fail;
1979 : }
1980 :
1981 157181 : if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
1982 27367 : uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1983 27367 : uint32_t access_mask = 0;
1984 :
1985 88 : bool block_owner_rights;
1986 88 : enum implicit_owner_rights implicit_owner_rights;
1987 :
1988 27367 : if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1989 12961 : access_mask |= SEC_STD_WRITE_OWNER;
1990 : }
1991 27367 : if (sd_flags & SECINFO_DACL) {
1992 27133 : access_mask |= SEC_STD_WRITE_DAC;
1993 : }
1994 27367 : if (sd_flags & SECINFO_SACL) {
1995 12709 : access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1996 : }
1997 :
1998 27367 : block_owner_rights = !dsdb_module_am_administrator(module);
1999 :
2000 27367 : if (block_owner_rights) {
2001 180 : block_owner_rights = dsdb_block_owner_implicit_rights(module,
2002 : req,
2003 : req);
2004 : }
2005 27367 : if (block_owner_rights) {
2006 162 : block_owner_rights = samdb_find_attribute(ldb,
2007 162 : acl_res->msgs[0],
2008 : "objectclass",
2009 : "computer");
2010 : }
2011 :
2012 27367 : implicit_owner_rights = block_owner_rights ?
2013 27367 : IMPLICIT_OWNER_READ_CONTROL_RIGHTS :
2014 : IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS;
2015 :
2016 27367 : ret = acl_check_access_on_attribute_implicit_owner(module,
2017 : tmp_ctx,
2018 : sd,
2019 : sid,
2020 : access_mask,
2021 : attr,
2022 : objectclass,
2023 : implicit_owner_rights);
2024 27367 : if (ret != LDB_SUCCESS) {
2025 108 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2026 : "Object %s has no write dacl access\n",
2027 108 : ldb_dn_get_linearized(msg->dn));
2028 108 : dsdb_acl_debug(sd,
2029 : acl_user_token(module),
2030 108 : msg->dn,
2031 : true,
2032 : 10);
2033 108 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2034 108 : goto fail;
2035 : }
2036 129814 : } else if (ldb_attr_cmp("member", el->name) == 0) {
2037 8016 : ret = acl_check_self_membership(tmp_ctx,
2038 : module,
2039 : req,
2040 : sd,
2041 : sid,
2042 : attr,
2043 : objectclass);
2044 8016 : if (ret != LDB_SUCCESS) {
2045 51 : goto fail;
2046 : }
2047 121798 : } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
2048 : /* this one is not affected by any rights, we should let it through
2049 : so that passwords_hash returns the correct error */
2050 72 : continue;
2051 121726 : } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
2052 8300 : (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
2053 104217 : ldb_attr_cmp("clearTextPassword", el->name) == 0) {
2054 : /*
2055 : * Ideally we would do the acl_check_password_rights
2056 : * before we checked the other attributes, i.e. in a
2057 : * loop before the current one.
2058 : * Have not done this as yet in order to limit the size
2059 : * of the change. To limit the possibility of breaking
2060 : * the ACL logic.
2061 : */
2062 19030 : if (password_rights_checked) {
2063 1958 : continue;
2064 : }
2065 17072 : ret = acl_check_password_rights(tmp_ctx,
2066 : module,
2067 : req,
2068 : sd,
2069 : sid,
2070 : objectclass,
2071 : userPassword,
2072 : &pav);
2073 17072 : if (ret != LDB_SUCCESS) {
2074 142 : goto fail;
2075 : }
2076 16858 : password_rights_checked = true;
2077 102696 : } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
2078 2167 : ret = acl_check_spn(tmp_ctx,
2079 : module,
2080 : req,
2081 : el,
2082 : sd,
2083 : sid,
2084 : attr,
2085 : objectclass,
2086 : implicit_validated_write_control);
2087 2167 : if (ret != LDB_SUCCESS) {
2088 274 : goto fail;
2089 : }
2090 100529 : } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
2091 953 : ret = acl_check_dns_host_name(tmp_ctx,
2092 : module,
2093 : req,
2094 : el,
2095 : sd,
2096 : sid,
2097 : attr,
2098 : objectclass,
2099 : implicit_validated_write_control);
2100 953 : if (ret != LDB_SUCCESS) {
2101 180 : goto fail;
2102 : }
2103 99576 : } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
2104 : /*
2105 : * in case of undelete op permissions on
2106 : * isDeleted are irrelevant and
2107 : * distinguishedName is removed by the
2108 : * tombstone_reanimate module
2109 : */
2110 274 : continue;
2111 99302 : } else if (implicit_validated_write_control != NULL) {
2112 : /* Allow the update. */
2113 441 : continue;
2114 : } else {
2115 98861 : ret = acl_check_access_on_attribute(module,
2116 : tmp_ctx,
2117 : sd,
2118 : sid,
2119 : SEC_ADS_WRITE_PROP,
2120 : attr,
2121 : objectclass);
2122 98861 : if (ret != LDB_SUCCESS) {
2123 876 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2124 : "Object %s has no write property access\n",
2125 876 : ldb_dn_get_linearized(msg->dn));
2126 876 : dsdb_acl_debug(sd,
2127 : acl_user_token(module),
2128 876 : msg->dn,
2129 : true,
2130 : 10);
2131 876 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2132 876 : goto fail;
2133 : }
2134 : }
2135 : }
2136 :
2137 118180 : success:
2138 118180 : talloc_free(tmp_ctx);
2139 118180 : context = talloc_zero(req, struct acl_callback_context);
2140 :
2141 118180 : if (context == NULL) {
2142 0 : return ldb_oom(ldb);
2143 : }
2144 118180 : context->request = req;
2145 118180 : context->module = module;
2146 118180 : ret = ldb_build_mod_req(
2147 : &new_req,
2148 : ldb,
2149 : req,
2150 : req->op.mod.message,
2151 : req->controls,
2152 : context,
2153 : acl_callback,
2154 : req);
2155 118180 : if (ret != LDB_SUCCESS) {
2156 0 : return ret;
2157 : }
2158 118180 : return ldb_next_request(module, new_req);
2159 1755 : fail:
2160 1755 : talloc_free(tmp_ctx);
2161 : /*
2162 : * We copy the pav into the result, so that the password reset
2163 : * logging code in audit_log can log failed password reset attempts.
2164 : */
2165 1755 : if (pav) {
2166 142 : struct ldb_control *control = NULL;
2167 :
2168 142 : controls = talloc_zero_array(req, struct ldb_control *, 2);
2169 142 : if (controls == NULL) {
2170 0 : return ldb_oom(ldb);
2171 : }
2172 :
2173 142 : control = talloc(controls, struct ldb_control);
2174 :
2175 142 : if (control == NULL) {
2176 0 : return ldb_oom(ldb);
2177 : }
2178 :
2179 142 : control->oid= talloc_strdup(
2180 : control,
2181 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
2182 142 : if (control->oid == NULL) {
2183 0 : return ldb_oom(ldb);
2184 : }
2185 142 : control->critical = false;
2186 142 : control->data = pav;
2187 142 : *controls = control;
2188 : }
2189 1755 : return ldb_module_done(req, controls, NULL, ret);
2190 : }
2191 :
2192 : /* similar to the modify for the time being.
2193 : * We need to consider the special delete tree case, though - TODO */
2194 72815 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
2195 : {
2196 148 : int ret;
2197 148 : struct ldb_dn *parent;
2198 148 : struct ldb_context *ldb;
2199 148 : struct ldb_dn *nc_root;
2200 148 : const struct dsdb_schema *schema;
2201 148 : const struct dsdb_class *objectclass;
2202 72815 : struct security_descriptor *sd = NULL;
2203 72815 : struct dom_sid *sid = NULL;
2204 148 : struct ldb_result *acl_res;
2205 148 : static const char *acl_attrs[] = {
2206 : "nTSecurityDescriptor",
2207 : "objectClass",
2208 : "objectSid",
2209 : NULL
2210 : };
2211 :
2212 72815 : if (ldb_dn_is_special(req->op.del.dn)) {
2213 1 : return ldb_next_request(module, req);
2214 : }
2215 :
2216 72814 : if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
2217 : {
2218 31764 : return ldb_next_request(module, req);
2219 : }
2220 :
2221 41050 : DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
2222 :
2223 41050 : ldb = ldb_module_get_ctx(module);
2224 :
2225 41050 : parent = ldb_dn_get_parent(req, req->op.del.dn);
2226 41050 : if (parent == NULL) {
2227 0 : return ldb_oom(ldb);
2228 : }
2229 :
2230 : /* Make sure we aren't deleting a NC */
2231 :
2232 41050 : ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
2233 41050 : if (ret != LDB_SUCCESS) {
2234 0 : return ret;
2235 : }
2236 41050 : if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
2237 0 : talloc_free(nc_root);
2238 0 : DEBUG(10,("acl:deleting a NC\n"));
2239 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2240 0 : return ldb_module_done(req, NULL, NULL,
2241 : LDB_ERR_UNWILLING_TO_PERFORM);
2242 : }
2243 41050 : talloc_free(nc_root);
2244 :
2245 41050 : ret = dsdb_module_search_dn(module, req, &acl_res,
2246 : req->op.del.dn, acl_attrs,
2247 : DSDB_FLAG_NEXT_MODULE |
2248 : DSDB_FLAG_AS_SYSTEM |
2249 : DSDB_SEARCH_SHOW_RECYCLED, req);
2250 : /* we should be able to find the parent */
2251 41050 : if (ret != LDB_SUCCESS) {
2252 0 : DEBUG(10,("acl: failed to find object %s\n",
2253 : ldb_dn_get_linearized(req->op.rename.olddn)));
2254 0 : return ret;
2255 : }
2256 :
2257 41050 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2258 41050 : if (ret != LDB_SUCCESS) {
2259 0 : return ldb_operr(ldb);
2260 : }
2261 41050 : if (!sd) {
2262 0 : return ldb_operr(ldb);
2263 : }
2264 :
2265 41050 : schema = dsdb_get_schema(ldb, req);
2266 41050 : if (!schema) {
2267 0 : return ldb_operr(ldb);
2268 : }
2269 :
2270 41050 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2271 :
2272 41050 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2273 41050 : if (!objectclass) {
2274 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2275 : "acl_modify: Error retrieving object class for GUID.");
2276 : }
2277 :
2278 41050 : if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
2279 2692 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
2280 : SEC_ADS_DELETE_TREE,
2281 : objectclass);
2282 2692 : if (ret != LDB_SUCCESS) {
2283 0 : return ret;
2284 : }
2285 :
2286 2692 : return ldb_next_request(module, req);
2287 : }
2288 :
2289 : /* First check if we have delete object right */
2290 38358 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
2291 : SEC_STD_DELETE,
2292 : objectclass);
2293 38358 : if (ret == LDB_SUCCESS) {
2294 38053 : return ldb_next_request(module, req);
2295 : }
2296 :
2297 : /* Nope, we don't have delete object. Lets check if we have delete
2298 : * child on the parent */
2299 305 : ret = dsdb_module_check_access_on_dn(module, req, parent,
2300 : SEC_ADS_DELETE_CHILD,
2301 : &objectclass->schemaIDGUID,
2302 : req);
2303 305 : if (ret != LDB_SUCCESS) {
2304 10 : return ret;
2305 : }
2306 :
2307 295 : return ldb_next_request(module, req);
2308 : }
2309 265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
2310 : struct ldb_module *module,
2311 : struct ldb_request *req,
2312 : struct ldb_dn *nc_root)
2313 : {
2314 0 : int ret;
2315 0 : struct ldb_result *acl_res;
2316 265 : struct security_descriptor *sd = NULL;
2317 265 : struct dom_sid *sid = NULL;
2318 265 : const struct dsdb_schema *schema = NULL;
2319 265 : const struct dsdb_class *objectclass = NULL;
2320 265 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2321 0 : static const char *acl_attrs[] = {
2322 : "nTSecurityDescriptor",
2323 : "objectClass",
2324 : "objectSid",
2325 : NULL
2326 : };
2327 :
2328 265 : ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
2329 : nc_root, acl_attrs,
2330 : DSDB_FLAG_NEXT_MODULE |
2331 : DSDB_FLAG_AS_SYSTEM |
2332 : DSDB_SEARCH_SHOW_RECYCLED, req);
2333 265 : if (ret != LDB_SUCCESS) {
2334 0 : DEBUG(10,("acl: failed to find object %s\n",
2335 : ldb_dn_get_linearized(nc_root)));
2336 0 : return ret;
2337 : }
2338 :
2339 265 : ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
2340 265 : sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
2341 265 : schema = dsdb_get_schema(ldb, req);
2342 265 : if (!schema) {
2343 0 : return LDB_ERR_OPERATIONS_ERROR;
2344 : }
2345 265 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2346 265 : if (ret != LDB_SUCCESS || !sd) {
2347 0 : return ldb_operr(ldb_module_get_ctx(module));
2348 : }
2349 265 : return acl_check_extended_right(mem_ctx,
2350 : module,
2351 : req,
2352 : objectclass,
2353 : sd,
2354 : acl_user_token(module),
2355 : GUID_DRS_REANIMATE_TOMBSTONE,
2356 : SEC_ADS_CONTROL_ACCESS, sid);
2357 : }
2358 :
2359 1533 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
2360 : {
2361 5 : int ret;
2362 5 : struct ldb_dn *oldparent;
2363 5 : struct ldb_dn *newparent;
2364 5 : const struct dsdb_schema *schema;
2365 5 : const struct dsdb_class *objectclass;
2366 1533 : const struct dsdb_attribute *attr = NULL;
2367 5 : struct ldb_context *ldb;
2368 1533 : struct security_descriptor *sd = NULL;
2369 1533 : struct dom_sid *sid = NULL;
2370 5 : struct ldb_result *acl_res;
2371 5 : struct ldb_dn *nc_root;
2372 5 : struct ldb_control *is_undelete;
2373 5 : TALLOC_CTX *tmp_ctx;
2374 5 : const char *rdn_name;
2375 5 : static const char *acl_attrs[] = {
2376 : "nTSecurityDescriptor",
2377 : "objectClass",
2378 : "objectSid",
2379 : NULL
2380 : };
2381 :
2382 1533 : if (ldb_dn_is_special(req->op.rename.olddn)) {
2383 0 : return ldb_next_request(module, req);
2384 : }
2385 :
2386 1533 : DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
2387 1533 : if (dsdb_have_system_access(module, req, SYSTEM_CONTROL_STRIP_CRITICAL))
2388 : {
2389 895 : return ldb_next_request(module, req);
2390 : }
2391 :
2392 638 : ldb = ldb_module_get_ctx(module);
2393 :
2394 638 : tmp_ctx = talloc_new(req);
2395 638 : if (tmp_ctx == NULL) {
2396 0 : return ldb_oom(ldb);
2397 : }
2398 :
2399 638 : oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
2400 638 : if (oldparent == NULL) {
2401 0 : return ldb_oom(ldb);
2402 : }
2403 638 : newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
2404 638 : if (newparent == NULL) {
2405 0 : return ldb_oom(ldb);
2406 : }
2407 :
2408 : /* Make sure we aren't renaming/moving a NC */
2409 :
2410 638 : ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
2411 638 : if (ret != LDB_SUCCESS) {
2412 0 : return ret;
2413 : }
2414 638 : if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
2415 0 : talloc_free(nc_root);
2416 0 : DEBUG(10,("acl:renaming/moving a NC\n"));
2417 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2418 0 : return ldb_module_done(req, NULL, NULL,
2419 : LDB_ERR_UNWILLING_TO_PERFORM);
2420 : }
2421 :
2422 : /* special check for undelete operation */
2423 638 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
2424 638 : if (is_undelete != NULL) {
2425 265 : is_undelete->critical = 0;
2426 265 : ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
2427 265 : if (ret != LDB_SUCCESS) {
2428 9 : talloc_free(tmp_ctx);
2429 9 : return ret;
2430 : }
2431 : }
2432 629 : talloc_free(nc_root);
2433 :
2434 : /* Look for the parent */
2435 :
2436 629 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
2437 : req->op.rename.olddn, acl_attrs,
2438 : DSDB_FLAG_NEXT_MODULE |
2439 : DSDB_FLAG_AS_SYSTEM |
2440 : DSDB_SEARCH_SHOW_RECYCLED, req);
2441 : /* we should be able to find the parent */
2442 629 : if (ret != LDB_SUCCESS) {
2443 0 : DEBUG(10,("acl: failed to find object %s\n",
2444 : ldb_dn_get_linearized(req->op.rename.olddn)));
2445 0 : talloc_free(tmp_ctx);
2446 0 : return ret;
2447 : }
2448 :
2449 629 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2450 629 : if (ret != LDB_SUCCESS) {
2451 0 : talloc_free(tmp_ctx);
2452 0 : return ldb_operr(ldb);
2453 : }
2454 629 : if (!sd) {
2455 0 : talloc_free(tmp_ctx);
2456 0 : return ldb_operr(ldb);
2457 : }
2458 :
2459 629 : schema = dsdb_get_schema(ldb, acl_res);
2460 629 : if (!schema) {
2461 0 : talloc_free(tmp_ctx);
2462 0 : return ldb_operr(ldb);
2463 : }
2464 :
2465 629 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2466 :
2467 629 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2468 629 : if (!objectclass) {
2469 0 : talloc_free(tmp_ctx);
2470 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2471 : "acl_modify: Error retrieving object class for GUID.");
2472 : }
2473 :
2474 629 : attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
2475 629 : if (attr == NULL) {
2476 0 : talloc_free(tmp_ctx);
2477 0 : return ldb_operr(ldb);
2478 : }
2479 :
2480 629 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2481 : SEC_ADS_WRITE_PROP,
2482 : attr, objectclass);
2483 629 : if (ret != LDB_SUCCESS) {
2484 19 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2485 : "Object %s has no wp on %s\n",
2486 : ldb_dn_get_linearized(req->op.rename.olddn),
2487 19 : attr->lDAPDisplayName);
2488 19 : dsdb_acl_debug(sd,
2489 : acl_user_token(module),
2490 : req->op.rename.olddn,
2491 : true,
2492 : 10);
2493 19 : talloc_free(tmp_ctx);
2494 19 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2495 : }
2496 :
2497 610 : rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
2498 610 : if (rdn_name == NULL) {
2499 0 : talloc_free(tmp_ctx);
2500 0 : return ldb_operr(ldb);
2501 : }
2502 :
2503 610 : attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2504 610 : if (attr == NULL) {
2505 0 : talloc_free(tmp_ctx);
2506 0 : return ldb_operr(ldb);
2507 : }
2508 :
2509 610 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2510 : SEC_ADS_WRITE_PROP,
2511 : attr, objectclass);
2512 610 : if (ret != LDB_SUCCESS) {
2513 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2514 : "Object %s has no wp on %s\n",
2515 : ldb_dn_get_linearized(req->op.rename.olddn),
2516 9 : attr->lDAPDisplayName);
2517 9 : dsdb_acl_debug(sd,
2518 : acl_user_token(module),
2519 : req->op.rename.olddn,
2520 : true,
2521 : 10);
2522 9 : talloc_free(tmp_ctx);
2523 9 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2524 : }
2525 :
2526 601 : if (ldb_dn_compare(oldparent, newparent) == 0) {
2527 : /* regular rename, not move, nothing more to do */
2528 232 : talloc_free(tmp_ctx);
2529 232 : return ldb_next_request(module, req);
2530 : }
2531 :
2532 : /* new parent should have create child */
2533 369 : ret = dsdb_module_check_access_on_dn(module, req, newparent,
2534 : SEC_ADS_CREATE_CHILD,
2535 : &objectclass->schemaIDGUID, req);
2536 369 : if (ret != LDB_SUCCESS) {
2537 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2538 : "acl:access_denied renaming %s",
2539 : ldb_dn_get_linearized(req->op.rename.olddn));
2540 9 : talloc_free(tmp_ctx);
2541 9 : return ret;
2542 : }
2543 :
2544 : /* do we have delete object on the object? */
2545 : /* this access is not necessary for undelete ops */
2546 360 : if (is_undelete == NULL) {
2547 126 : ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
2548 : SEC_STD_DELETE,
2549 : objectclass);
2550 126 : if (ret == LDB_SUCCESS) {
2551 99 : talloc_free(tmp_ctx);
2552 99 : return ldb_next_request(module, req);
2553 : }
2554 : /* what about delete child on the current parent */
2555 27 : ret = dsdb_module_check_access_on_dn(module, req, oldparent,
2556 : SEC_ADS_DELETE_CHILD,
2557 : &objectclass->schemaIDGUID,
2558 : req);
2559 27 : if (ret != LDB_SUCCESS) {
2560 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2561 : "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
2562 9 : talloc_free(tmp_ctx);
2563 9 : return ldb_module_done(req, NULL, NULL, ret);
2564 : }
2565 : }
2566 252 : talloc_free(tmp_ctx);
2567 :
2568 252 : return ldb_next_request(module, req);
2569 : }
2570 :
2571 830365 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
2572 : struct acl_private *data)
2573 : {
2574 17500 : struct dsdb_attribute *a;
2575 830365 : uint32_t n = 0;
2576 :
2577 830365 : if (data->acl_search) {
2578 : /*
2579 : * If acl:search is activated, the acl_read module
2580 : * protects confidential attributes.
2581 : */
2582 812865 : return LDB_SUCCESS;
2583 : }
2584 :
2585 0 : if ((ac->schema == data->cached_schema_ptr) &&
2586 0 : (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
2587 : {
2588 0 : return LDB_SUCCESS;
2589 : }
2590 :
2591 0 : data->cached_schema_ptr = NULL;
2592 0 : data->cached_schema_loaded_usn = 0;
2593 0 : data->cached_schema_metadata_usn = 0;
2594 0 : TALLOC_FREE(data->confidential_attrs);
2595 :
2596 0 : if (ac->schema == NULL) {
2597 0 : return LDB_SUCCESS;
2598 : }
2599 :
2600 0 : for (a = ac->schema->attributes; a; a = a->next) {
2601 0 : const char **attrs = data->confidential_attrs;
2602 :
2603 0 : if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
2604 0 : continue;
2605 : }
2606 :
2607 0 : attrs = talloc_realloc(data, attrs, const char *, n + 2);
2608 0 : if (attrs == NULL) {
2609 0 : TALLOC_FREE(data->confidential_attrs);
2610 0 : return ldb_module_oom(ac->module);
2611 : }
2612 :
2613 0 : attrs[n] = a->lDAPDisplayName;
2614 0 : attrs[n+1] = NULL;
2615 0 : n++;
2616 :
2617 0 : data->confidential_attrs = attrs;
2618 : }
2619 :
2620 0 : data->cached_schema_ptr = ac->schema;
2621 0 : data->cached_schema_metadata_usn = ac->schema->metadata_usn;
2622 :
2623 0 : return LDB_SUCCESS;
2624 : }
2625 :
2626 46577021 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2627 : {
2628 1498311 : struct acl_context *ac;
2629 1498311 : struct acl_private *data;
2630 1498311 : struct ldb_result *acl_res;
2631 1498311 : static const char *acl_attrs[] = {
2632 : "objectClass",
2633 : "nTSecurityDescriptor",
2634 : "objectSid",
2635 : NULL
2636 : };
2637 1498311 : int ret;
2638 1498311 : unsigned int i;
2639 :
2640 46577021 : ac = talloc_get_type(req->context, struct acl_context);
2641 46577021 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2642 46577021 : if (!ares) {
2643 0 : return ldb_module_done(ac->req, NULL, NULL,
2644 : LDB_ERR_OPERATIONS_ERROR);
2645 : }
2646 46577021 : if (ares->error != LDB_SUCCESS) {
2647 1668615 : return ldb_module_done(ac->req, ares->controls,
2648 : ares->response, ares->error);
2649 : }
2650 :
2651 44908406 : switch (ares->type) {
2652 35440794 : case LDB_REPLY_ENTRY:
2653 35440794 : if (ac->constructed_attrs) {
2654 346 : ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
2655 : acl_attrs,
2656 : DSDB_FLAG_NEXT_MODULE |
2657 : DSDB_FLAG_AS_SYSTEM |
2658 : DSDB_SEARCH_SHOW_RECYCLED,
2659 : req);
2660 346 : if (ret != LDB_SUCCESS) {
2661 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2662 : }
2663 : }
2664 :
2665 35440794 : if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2666 22 : ret = acl_allowedAttributes(ac->module, ac->schema,
2667 22 : acl_res->msgs[0],
2668 : ares->message, ac);
2669 22 : if (ret != LDB_SUCCESS) {
2670 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2671 : }
2672 : }
2673 :
2674 35440794 : if (ac->allowedChildClasses) {
2675 0 : ret = acl_childClasses(ac->module, ac->schema,
2676 0 : acl_res->msgs[0],
2677 : ares->message,
2678 : "allowedChildClasses");
2679 0 : if (ret != LDB_SUCCESS) {
2680 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2681 : }
2682 : }
2683 :
2684 35440794 : if (ac->allowedChildClassesEffective) {
2685 18 : ret = acl_childClassesEffective(ac->module, ac->schema,
2686 18 : acl_res->msgs[0],
2687 : ares->message, ac);
2688 18 : if (ret != LDB_SUCCESS) {
2689 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2690 : }
2691 : }
2692 :
2693 35440794 : if (ac->sDRightsEffective) {
2694 306 : ret = acl_sDRightsEffective(ac->module,
2695 306 : acl_res->msgs[0],
2696 : ares->message, ac);
2697 306 : if (ret != LDB_SUCCESS) {
2698 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2699 : }
2700 : }
2701 :
2702 35440794 : if (data == NULL) {
2703 0 : return ldb_module_send_entry(ac->req, ares->message,
2704 : ares->controls);
2705 : }
2706 :
2707 35440794 : if (ac->am_system) {
2708 0 : return ldb_module_send_entry(ac->req, ares->message,
2709 : ares->controls);
2710 : }
2711 :
2712 35440794 : if (ac->am_administrator) {
2713 13843550 : return ldb_module_send_entry(ac->req, ares->message,
2714 : ares->controls);
2715 : }
2716 :
2717 21597244 : if (data->confidential_attrs != NULL) {
2718 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2719 0 : ldb_msg_remove_attr(ares->message,
2720 0 : data->confidential_attrs[i]);
2721 : }
2722 : }
2723 :
2724 21597244 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2725 :
2726 798478 : case LDB_REPLY_REFERRAL:
2727 798478 : return ldb_module_send_referral(ac->req, ares->referral);
2728 :
2729 8669134 : case LDB_REPLY_DONE:
2730 8669134 : return ldb_module_done(ac->req, ares->controls,
2731 : ares->response, LDB_SUCCESS);
2732 :
2733 : }
2734 0 : return LDB_SUCCESS;
2735 : }
2736 :
2737 32994928 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
2738 : {
2739 1776648 : struct ldb_context *ldb;
2740 1776648 : struct acl_context *ac;
2741 32994928 : struct ldb_parse_tree *down_tree = req->op.search.tree;
2742 1776648 : struct ldb_request *down_req;
2743 1776648 : struct acl_private *data;
2744 1776648 : int ret;
2745 1776648 : unsigned int i;
2746 32994928 : bool modify_search = true;
2747 :
2748 32994928 : if (ldb_dn_is_special(req->op.search.base)) {
2749 1146975 : return ldb_next_request(module, req);
2750 : }
2751 :
2752 31847953 : ldb = ldb_module_get_ctx(module);
2753 :
2754 31847953 : ac = talloc_zero(req, struct acl_context);
2755 31847953 : if (ac == NULL) {
2756 0 : return ldb_oom(ldb);
2757 : }
2758 31847953 : data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2759 :
2760 31847953 : ac->module = module;
2761 31847953 : ac->req = req;
2762 31847953 : ac->am_system = dsdb_module_am_system(module);
2763 31847953 : ac->am_administrator = dsdb_module_am_administrator(module);
2764 31847953 : ac->constructed_attrs = false;
2765 31847953 : ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2766 31847953 : ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2767 31847953 : ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2768 31847953 : ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2769 31847953 : ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2770 31847953 : ac->schema = dsdb_get_schema(ldb, ac);
2771 :
2772 31847953 : ac->constructed_attrs |= ac->allowedAttributes;
2773 31847953 : ac->constructed_attrs |= ac->allowedChildClasses;
2774 31847953 : ac->constructed_attrs |= ac->allowedChildClassesEffective;
2775 31847953 : ac->constructed_attrs |= ac->allowedAttributesEffective;
2776 31847953 : ac->constructed_attrs |= ac->sDRightsEffective;
2777 :
2778 31847953 : if (data == NULL) {
2779 0 : modify_search = false;
2780 : }
2781 31847953 : if (ac->am_system) {
2782 21509636 : modify_search = false;
2783 : }
2784 :
2785 31847953 : if (!ac->constructed_attrs && !modify_search) {
2786 21509636 : talloc_free(ac);
2787 21509636 : return ldb_next_request(module, req);
2788 : }
2789 :
2790 10338317 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2791 10338317 : if (data == NULL) {
2792 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2793 : "acl_private data is missing");
2794 : }
2795 :
2796 10338317 : if (!ac->am_system && !ac->am_administrator) {
2797 830365 : ret = acl_search_update_confidential_attrs(ac, data);
2798 830365 : if (ret != LDB_SUCCESS) {
2799 0 : return ret;
2800 : }
2801 :
2802 830365 : if (data->confidential_attrs != NULL) {
2803 0 : down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2804 0 : if (down_tree == NULL) {
2805 0 : return ldb_oom(ldb);
2806 : }
2807 :
2808 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2809 0 : ldb_parse_tree_attr_replace(down_tree,
2810 0 : data->confidential_attrs[i],
2811 : "kludgeACLredactedattribute");
2812 : }
2813 : }
2814 : }
2815 :
2816 10338317 : ret = ldb_build_search_req_ex(&down_req,
2817 : ldb, ac,
2818 : req->op.search.base,
2819 : req->op.search.scope,
2820 : down_tree,
2821 : req->op.search.attrs,
2822 : req->controls,
2823 : ac, acl_search_callback,
2824 : req);
2825 10338317 : LDB_REQ_SET_LOCATION(down_req);
2826 10338317 : if (ret != LDB_SUCCESS) {
2827 0 : return ret;
2828 : }
2829 : /* perform the search */
2830 10338317 : return ldb_next_request(module, down_req);
2831 : }
2832 :
2833 1281622 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2834 : {
2835 1281622 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2836 :
2837 : /* allow everybody to read the sequence number */
2838 1281622 : if (strcmp(req->op.extended.oid,
2839 : LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2840 1276068 : return ldb_next_request(module, req);
2841 : }
2842 :
2843 5554 : if (dsdb_have_system_access(module,
2844 : req,
2845 518 : SYSTEM_CONTROL_KEEP_CRITICAL) ||
2846 518 : dsdb_module_am_administrator(module))
2847 : {
2848 5554 : return ldb_next_request(module, req);
2849 : } else {
2850 0 : ldb_asprintf_errstring(ldb,
2851 : "acl_extended: "
2852 : "attempted database modify not permitted. "
2853 : "User %s is not SYSTEM or an administrator",
2854 : acl_user_name(req, module));
2855 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2856 : }
2857 : }
2858 :
2859 : static const struct ldb_module_ops ldb_acl_module_ops = {
2860 : .name = "acl",
2861 : .search = acl_search,
2862 : .add = acl_add,
2863 : .modify = acl_modify,
2864 : .del = acl_delete,
2865 : .rename = acl_rename,
2866 : .extended = acl_extended,
2867 : .init_context = acl_module_init
2868 : };
2869 :
2870 6040 : int ldb_acl_module_init(const char *version)
2871 : {
2872 6040 : LDB_MODULE_CHECK_VERSION(version);
2873 6040 : return ldb_register_module(&ldb_acl_module_ops);
2874 : }
|