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