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 108013 : 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 108013 : ldb = ldb_module_get_ctx(module);
79 :
80 108013 : data = talloc_zero(module, struct acl_private);
81 108013 : if (data == NULL) {
82 0 : return ldb_oom(ldb);
83 : }
84 :
85 108013 : data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
86 : NULL, "acl", "search", true);
87 108013 : ldb_module_set_private(module, data);
88 :
89 108013 : ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
90 108013 : 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 108013 : 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 36 : 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 36 : struct ldb_context *ldb = ldb_module_get_ctx(module);
352 : struct ldb_message_element *rightsEffective;
353 : int ret;
354 : struct security_descriptor *sd;
355 36 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
356 : LDB_CONTROL_AS_SYSTEM_OID);
357 36 : struct dom_sid *sid = NULL;
358 36 : uint32_t flags = 0;
359 :
360 36 : if (as_system != NULL) {
361 0 : as_system->critical = 0;
362 : }
363 :
364 : /* Must remove any existing attribute, or else confusion reins */
365 36 : ldb_msg_remove_attr(msg, "sDRightsEffective");
366 36 : ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
367 36 : if (ret != LDB_SUCCESS) {
368 0 : return ret;
369 : }
370 36 : 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 36 : objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
377 36 : if (objectclass == NULL) {
378 0 : return ldb_operr(ldb);
379 : }
380 :
381 36 : attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
382 : "nTSecurityDescriptor");
383 36 : if (attr == NULL) {
384 0 : return ldb_operr(ldb);
385 : }
386 :
387 : /* Get the security descriptor from the message */
388 36 : ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
389 36 : if (ret != LDB_SUCCESS) {
390 0 : return ret;
391 : }
392 36 : sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
393 36 : ret = acl_check_access_on_attribute(module,
394 : msg,
395 : sd,
396 : sid,
397 : SEC_STD_WRITE_OWNER,
398 : attr,
399 : objectclass);
400 36 : if (ret == LDB_SUCCESS) {
401 18 : flags |= SECINFO_OWNER | SECINFO_GROUP;
402 : }
403 36 : ret = acl_check_access_on_attribute(module,
404 : msg,
405 : sd,
406 : sid,
407 : SEC_STD_WRITE_DAC,
408 : attr,
409 : objectclass);
410 36 : if (ret == LDB_SUCCESS) {
411 27 : flags |= SECINFO_DACL;
412 : }
413 36 : ret = acl_check_access_on_attribute(module,
414 : msg,
415 : sd,
416 : sid,
417 : SEC_FLAG_SYSTEM_SECURITY,
418 : attr,
419 : objectclass);
420 36 : if (ret == LDB_SUCCESS) {
421 9 : flags |= SECINFO_SACL;
422 : }
423 : }
424 36 : return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
425 : "sDRightsEffective", flags);
426 : }
427 :
428 559 : static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
429 : struct ldb_context *ldb,
430 : const struct ldb_val *spn_value,
431 : uint32_t userAccountControl,
432 : const struct ldb_val *samAccountName,
433 : const struct ldb_val *dnsHostName,
434 : const char *netbios_name,
435 : const char *ntds_guid)
436 : {
437 : int ret, princ_size;
438 : krb5_context krb_ctx;
439 : krb5_error_code kerr;
440 : krb5_principal principal;
441 : char *instanceName;
442 : char *serviceType;
443 : char *serviceName;
444 559 : const char *spn_value_str = NULL;
445 : size_t account_name_len;
446 559 : const char *forest_name = samdb_forest_name(ldb, mem_ctx);
447 559 : const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
448 559 : struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
449 : struct loadparm_context);
450 920 : bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
451 361 : (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
452 :
453 878 : spn_value_str = talloc_strndup(mem_ctx,
454 559 : (const char *)spn_value->data,
455 240 : spn_value->length);
456 559 : if (spn_value_str == NULL) {
457 0 : return ldb_oom(ldb);
458 : }
459 :
460 559 : if (spn_value->length == samAccountName->length &&
461 0 : strncasecmp((const char *)spn_value->data,
462 0 : (const char *)samAccountName->data,
463 0 : spn_value->length) == 0)
464 : {
465 : /* MacOS X sets this value, and setting an SPN of your
466 : * own samAccountName is both pointless and safe */
467 0 : return LDB_SUCCESS;
468 : }
469 :
470 559 : kerr = smb_krb5_init_context_basic(mem_ctx,
471 : lp_ctx,
472 : &krb_ctx);
473 559 : if (kerr != 0) {
474 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
475 : "Could not initialize kerberos context.");
476 : }
477 :
478 559 : ret = krb5_parse_name(krb_ctx, spn_value_str, &principal);
479 559 : if (ret) {
480 0 : krb5_free_context(krb_ctx);
481 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
482 : }
483 :
484 559 : princ_size = krb5_princ_size(krb_ctx, principal);
485 559 : if (princ_size < 2) {
486 0 : DBG_WARNING("princ_size=%d\n", princ_size);
487 0 : goto fail;
488 : }
489 :
490 559 : instanceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
491 : principal, 1);
492 559 : serviceType = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
493 : principal, 0);
494 559 : if (krb5_princ_size(krb_ctx, principal) == 3) {
495 409 : serviceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
496 : principal, 2);
497 : } else {
498 150 : serviceName = NULL;
499 : }
500 :
501 559 : if (serviceName) {
502 409 : if (!is_dc) {
503 81 : DBG_WARNING("is_dc=false, serviceName=%s,"
504 : "serviceType=%s\n", serviceName,
505 : serviceType);
506 81 : goto fail;
507 : }
508 328 : if (strcasecmp(serviceType, "ldap") == 0) {
509 151 : if (strcasecmp(serviceName, netbios_name) != 0 &&
510 73 : strcasecmp(serviceName, forest_name) != 0) {
511 36 : DBG_WARNING("serviceName=%s\n", serviceName);
512 36 : goto fail;
513 : }
514 :
515 218 : } else if (strcasecmp(serviceType, "gc") == 0) {
516 36 : if (strcasecmp(serviceName, forest_name) != 0) {
517 18 : DBG_WARNING("serviceName=%s\n", serviceName);
518 18 : goto fail;
519 : }
520 : } else {
521 213 : if (strcasecmp(serviceName, base_domain) != 0 &&
522 55 : strcasecmp(serviceName, netbios_name) != 0) {
523 18 : DBG_WARNING("serviceType=%s, "
524 : "serviceName=%s\n",
525 : serviceType, serviceName);
526 18 : goto fail;
527 : }
528 : }
529 : }
530 :
531 406 : account_name_len = samAccountName->length;
532 640 : if (account_name_len &&
533 406 : samAccountName->data[account_name_len - 1] == '$')
534 : {
535 : /* Account for the '$' character. */
536 406 : --account_name_len;
537 : }
538 :
539 : /* instanceName can be samAccountName without $ or dnsHostName
540 : * or "ntds_guid._msdcs.forest_domain for DC objects */
541 406 : if (strlen(instanceName) == account_name_len
542 214 : && strncasecmp(instanceName,
543 214 : (const char *)samAccountName->data,
544 : account_name_len) == 0)
545 : {
546 214 : goto success;
547 : }
548 304 : if ((dnsHostName != NULL) &&
549 278 : strlen(instanceName) == dnsHostName->length &&
550 232 : (strncasecmp(instanceName,
551 146 : (const char *)dnsHostName->data,
552 60 : dnsHostName->length) == 0))
553 : {
554 146 : goto success;
555 : }
556 46 : if (is_dc) {
557 : const char *guid_str;
558 37 : guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
559 : ntds_guid,
560 : forest_name);
561 37 : if (strcasecmp(instanceName, guid_str) == 0) {
562 19 : goto success;
563 : }
564 : }
565 :
566 27 : fail:
567 180 : krb5_free_principal(krb_ctx, principal);
568 180 : krb5_free_context(krb_ctx);
569 480 : ldb_debug_set(ldb, LDB_DEBUG_WARNING,
570 : "acl: spn validation failed for "
571 : "spn[%.*s] uac[0x%x] account[%.*s] hostname[%.*s] "
572 : "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
573 180 : (int)spn_value->length, spn_value->data,
574 : (unsigned)userAccountControl,
575 180 : (int)samAccountName->length, samAccountName->data,
576 180 : dnsHostName != NULL ? (int)dnsHostName->length : 0,
577 : dnsHostName != NULL ? (const char *)dnsHostName->data : "",
578 : netbios_name, ntds_guid,
579 : forest_name, base_domain);
580 180 : return LDB_ERR_CONSTRAINT_VIOLATION;
581 :
582 379 : success:
583 379 : krb5_free_principal(krb_ctx, principal);
584 379 : krb5_free_context(krb_ctx);
585 379 : return LDB_SUCCESS;
586 : }
587 :
588 : /*
589 : * Passing in 'el' is critical, we want to check all the values.
590 : *
591 : */
592 1269 : static int acl_check_spn(TALLOC_CTX *mem_ctx,
593 : struct ldb_module *module,
594 : struct ldb_request *req,
595 : const struct ldb_message_element *el,
596 : struct security_descriptor *sd,
597 : struct dom_sid *sid,
598 : const struct dsdb_attribute *attr,
599 : const struct dsdb_class *objectclass,
600 : const struct ldb_control *implicit_validated_write_control)
601 : {
602 : int ret;
603 : unsigned int i;
604 1269 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
605 1269 : struct ldb_context *ldb = ldb_module_get_ctx(module);
606 : struct ldb_result *acl_res;
607 : struct ldb_result *netbios_res;
608 1269 : struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
609 : uint32_t userAccountControl;
610 : const char *netbios_name;
611 1269 : const struct ldb_val *dns_host_name_val = NULL;
612 1269 : const struct ldb_val *sam_account_name_val = NULL;
613 : struct GUID ntds;
614 1269 : char *ntds_guid = NULL;
615 :
616 : static const char *acl_attrs[] = {
617 : "samAccountName",
618 : "dnsHostName",
619 : "userAccountControl",
620 : NULL
621 : };
622 : static const char *netbios_attrs[] = {
623 : "nETBIOSName",
624 : NULL
625 : };
626 :
627 1269 : if (implicit_validated_write_control != NULL) {
628 : /*
629 : * The validated write control dispenses with ACL
630 : * checks. We act as if we have an implicit Self Write
631 : * privilege, but, assuming we don't have Write
632 : * Property, still proceed with further validation
633 : * checks.
634 : */
635 : } else {
636 : /* if we have wp, we can do whatever we like */
637 1263 : if (acl_check_access_on_attribute(module,
638 : tmp_ctx,
639 : sd,
640 : sid,
641 : SEC_ADS_WRITE_PROP,
642 : attr, objectclass) == LDB_SUCCESS) {
643 668 : talloc_free(tmp_ctx);
644 668 : return LDB_SUCCESS;
645 : }
646 :
647 595 : ret = acl_check_extended_right(tmp_ctx,
648 : module,
649 : req,
650 : objectclass,
651 : sd,
652 : acl_user_token(module),
653 : GUID_DRS_VALIDATE_SPN,
654 : SEC_ADS_SELF_WRITE,
655 : sid);
656 :
657 595 : if (ret != LDB_SUCCESS) {
658 36 : dsdb_acl_debug(sd, acl_user_token(module),
659 36 : req->op.mod.message->dn,
660 : true,
661 : 10);
662 36 : talloc_free(tmp_ctx);
663 36 : return ret;
664 : }
665 : }
666 :
667 : /*
668 : * If we have "validated write spn", allow delete of any
669 : * existing value (this keeps constrained delete to the same
670 : * rules as unconstrained)
671 : */
672 565 : if (req->operation == LDB_MODIFY) {
673 : /*
674 : * If not add or replace (eg delete),
675 : * return success
676 : */
677 846 : if (LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_ADD &&
678 501 : LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_REPLACE)
679 : {
680 18 : talloc_free(tmp_ctx);
681 18 : return LDB_SUCCESS;
682 : }
683 : }
684 :
685 547 : ret = dsdb_module_search_dn(module, tmp_ctx,
686 547 : &acl_res, req->op.mod.message->dn,
687 : acl_attrs,
688 : DSDB_FLAG_NEXT_MODULE |
689 : DSDB_FLAG_AS_SYSTEM |
690 : DSDB_SEARCH_SHOW_RECYCLED,
691 : req);
692 547 : if (ret != LDB_SUCCESS) {
693 0 : talloc_free(tmp_ctx);
694 0 : return ret;
695 : }
696 :
697 547 : dns_host_name_val = ldb_msg_find_ldb_val(acl_res->msgs[0], "dNSHostName");
698 :
699 547 : ret = dsdb_msg_get_single_value(req->op.mod.message,
700 : "dNSHostName",
701 : dns_host_name_val,
702 : &dns_host_name_val,
703 : req->operation);
704 547 : if (ret != LDB_SUCCESS) {
705 0 : talloc_free(tmp_ctx);
706 0 : return ret;
707 : }
708 :
709 547 : userAccountControl = ldb_msg_find_attr_as_uint(acl_res->msgs[0], "userAccountControl", 0);
710 :
711 547 : sam_account_name_val = ldb_msg_find_ldb_val(acl_res->msgs[0], "sAMAccountName");
712 :
713 547 : ret = dsdb_msg_get_single_value(req->op.mod.message,
714 : "sAMAccountName",
715 : sam_account_name_val,
716 : &sam_account_name_val,
717 : req->operation);
718 547 : if (ret != LDB_SUCCESS) {
719 0 : talloc_free(tmp_ctx);
720 0 : return ret;
721 : }
722 :
723 547 : ret = dsdb_module_search(module, tmp_ctx,
724 : &netbios_res, partitions_dn,
725 : LDB_SCOPE_ONELEVEL,
726 : netbios_attrs,
727 : DSDB_FLAG_NEXT_MODULE |
728 : DSDB_FLAG_AS_SYSTEM,
729 : req,
730 : "(ncName=%s)",
731 : ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
732 :
733 547 : netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
734 :
735 : /* NTDSDSA objectGuid of object we are checking SPN for */
736 547 : if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
737 397 : ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
738 397 : req->op.mod.message->dn, &ntds, req);
739 397 : if (ret != LDB_SUCCESS) {
740 0 : ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
741 0 : ldb_dn_get_linearized(req->op.mod.message->dn),
742 : ldb_strerror(ret));
743 0 : talloc_free(tmp_ctx);
744 0 : return LDB_ERR_OPERATIONS_ERROR;
745 : }
746 397 : ntds_guid = GUID_string(tmp_ctx, &ntds);
747 : }
748 :
749 926 : for (i=0; i < el->num_values; i++) {
750 878 : ret = acl_validate_spn_value(tmp_ctx,
751 : ldb,
752 559 : &el->values[i],
753 : userAccountControl,
754 : sam_account_name_val,
755 : dns_host_name_val,
756 : netbios_name,
757 : ntds_guid);
758 559 : if (ret != LDB_SUCCESS) {
759 180 : talloc_free(tmp_ctx);
760 180 : return ret;
761 : }
762 : }
763 367 : talloc_free(tmp_ctx);
764 367 : return LDB_SUCCESS;
765 : }
766 :
767 645 : static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx,
768 : struct ldb_module *module,
769 : struct ldb_request *req,
770 : const struct ldb_message_element *el,
771 : struct security_descriptor *sd,
772 : struct dom_sid *sid,
773 : const struct dsdb_attribute *attr,
774 : const struct dsdb_class *objectclass,
775 : const struct ldb_control *implicit_validated_write_control)
776 : {
777 : int ret;
778 : unsigned i;
779 645 : TALLOC_CTX *tmp_ctx = NULL;
780 645 : struct ldb_context *ldb = ldb_module_get_ctx(module);
781 645 : const struct dsdb_schema *schema = NULL;
782 645 : const struct ldb_message_element *allowed_suffixes = NULL;
783 645 : struct ldb_result *nc_res = NULL;
784 645 : struct ldb_dn *nc_root = NULL;
785 645 : const char *nc_dns_name = NULL;
786 645 : const char *dnsHostName_str = NULL;
787 : size_t dns_host_name_len;
788 : size_t account_name_len;
789 645 : const struct ldb_message *msg = NULL;
790 645 : const struct ldb_message *search_res = NULL;
791 645 : const struct ldb_val *samAccountName = NULL;
792 645 : const struct ldb_val *dnsHostName = NULL;
793 645 : const struct dsdb_class *computer_objectclass = NULL;
794 : bool is_subclass;
795 :
796 : static const char *nc_attrs[] = {
797 : "msDS-AllowedDNSSuffixes",
798 : NULL
799 : };
800 :
801 645 : tmp_ctx = talloc_new(mem_ctx);
802 645 : if (tmp_ctx == NULL) {
803 0 : return ldb_oom(ldb);
804 : }
805 :
806 645 : if (implicit_validated_write_control != NULL) {
807 : /*
808 : * The validated write control dispenses with ACL
809 : * checks. We act as if we have an implicit Self Write
810 : * privilege, but, assuming we don't have Write
811 : * Property, still proceed with further validation
812 : * checks.
813 : */
814 : } else {
815 : /* if we have wp, we can do whatever we like */
816 618 : ret = acl_check_access_on_attribute(module,
817 : tmp_ctx,
818 : sd,
819 : sid,
820 : SEC_ADS_WRITE_PROP,
821 : attr, objectclass);
822 618 : if (ret == LDB_SUCCESS) {
823 414 : talloc_free(tmp_ctx);
824 414 : return LDB_SUCCESS;
825 : }
826 :
827 204 : ret = acl_check_extended_right(tmp_ctx,
828 : module,
829 : req,
830 : objectclass,
831 : sd,
832 : acl_user_token(module),
833 : GUID_DRS_DNS_HOST_NAME,
834 : SEC_ADS_SELF_WRITE,
835 : sid);
836 :
837 204 : if (ret != LDB_SUCCESS) {
838 78 : dsdb_acl_debug(sd, acl_user_token(module),
839 78 : req->op.mod.message->dn,
840 : true,
841 : 10);
842 78 : talloc_free(tmp_ctx);
843 78 : return ret;
844 : }
845 : }
846 :
847 : /*
848 : * If we have "validated write dnshostname", allow delete of
849 : * any existing value (this keeps constrained delete to the
850 : * same rules as unconstrained)
851 : */
852 153 : if (req->operation == LDB_MODIFY) {
853 153 : struct ldb_result *acl_res = NULL;
854 :
855 : static const char *acl_attrs[] = {
856 : "sAMAccountName",
857 : NULL
858 : };
859 :
860 153 : msg = req->op.mod.message;
861 :
862 : /*
863 : * If not add or replace (eg delete),
864 : * return success
865 : */
866 250 : if ((el->flags
867 153 : & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0)
868 : {
869 0 : talloc_free(tmp_ctx);
870 0 : return LDB_SUCCESS;
871 : }
872 :
873 153 : ret = dsdb_module_search_dn(module, tmp_ctx,
874 56 : &acl_res, msg->dn,
875 : acl_attrs,
876 : DSDB_FLAG_NEXT_MODULE |
877 : DSDB_FLAG_AS_SYSTEM |
878 : DSDB_SEARCH_SHOW_RECYCLED,
879 : req);
880 153 : if (ret != LDB_SUCCESS) {
881 0 : talloc_free(tmp_ctx);
882 0 : return ret;
883 : }
884 :
885 153 : search_res = acl_res->msgs[0];
886 0 : } else if (req->operation == LDB_ADD) {
887 0 : msg = req->op.add.message;
888 0 : search_res = msg;
889 : } else {
890 0 : talloc_free(tmp_ctx);
891 0 : return LDB_ERR_OPERATIONS_ERROR;
892 : }
893 :
894 : /* Check if the account has objectclass 'computer' or 'server'. */
895 :
896 153 : schema = dsdb_get_schema(ldb, req);
897 153 : if (schema == NULL) {
898 0 : talloc_free(tmp_ctx);
899 0 : return ldb_operr(ldb);
900 : }
901 :
902 153 : computer_objectclass = dsdb_class_by_lDAPDisplayName(schema, "computer");
903 153 : if (computer_objectclass == NULL) {
904 0 : talloc_free(tmp_ctx);
905 0 : return ldb_operr(ldb);
906 : }
907 :
908 153 : is_subclass = dsdb_is_subclass_of(schema, objectclass, computer_objectclass);
909 153 : if (!is_subclass) {
910 : /* The account is not a computer -- check if it's a server. */
911 :
912 0 : const struct dsdb_class *server_objectclass = NULL;
913 :
914 0 : server_objectclass = dsdb_class_by_lDAPDisplayName(schema, "server");
915 0 : if (server_objectclass == NULL) {
916 0 : talloc_free(tmp_ctx);
917 0 : return ldb_operr(ldb);
918 : }
919 :
920 0 : is_subclass = dsdb_is_subclass_of(schema, objectclass, server_objectclass);
921 0 : if (!is_subclass) {
922 : /* Not a computer or server, so no need to validate. */
923 0 : talloc_free(tmp_ctx);
924 0 : return LDB_SUCCESS;
925 : }
926 : }
927 :
928 153 : samAccountName = ldb_msg_find_ldb_val(search_res, "sAMAccountName");
929 :
930 153 : ret = dsdb_msg_get_single_value(msg,
931 : "sAMAccountName",
932 : samAccountName,
933 : &samAccountName,
934 : req->operation);
935 153 : if (ret != LDB_SUCCESS) {
936 0 : talloc_free(tmp_ctx);
937 0 : return ret;
938 : }
939 :
940 153 : account_name_len = samAccountName->length;
941 153 : if (account_name_len && samAccountName->data[account_name_len - 1] == '$') {
942 : /* Account for the '$' character. */
943 144 : --account_name_len;
944 : }
945 :
946 : /* Check for add or replace requests with no value. */
947 153 : if (el->num_values == 0) {
948 9 : talloc_free(tmp_ctx);
949 9 : return ldb_operr(ldb);
950 : }
951 144 : dnsHostName = &el->values[0];
952 :
953 144 : dnsHostName_str = (const char *)dnsHostName->data;
954 144 : dns_host_name_len = dnsHostName->length;
955 :
956 : /* Check that sAMAccountName matches the new dNSHostName. */
957 :
958 144 : if (dns_host_name_len < account_name_len) {
959 18 : goto fail;
960 : }
961 126 : if (strncasecmp(dnsHostName_str,
962 126 : (const char *)samAccountName->data,
963 : account_name_len) != 0)
964 : {
965 24 : goto fail;
966 : }
967 :
968 102 : dnsHostName_str += account_name_len;
969 102 : dns_host_name_len -= account_name_len;
970 :
971 : /* Check the '.' character */
972 :
973 160 : if (dns_host_name_len == 0 || *dnsHostName_str != '.') {
974 8 : goto fail;
975 : }
976 :
977 72 : ++dnsHostName_str;
978 72 : --dns_host_name_len;
979 :
980 : /* Now we check the suffix. */
981 :
982 72 : ret = dsdb_find_nc_root(ldb,
983 : tmp_ctx,
984 28 : search_res->dn,
985 : &nc_root);
986 72 : if (ret != LDB_SUCCESS) {
987 0 : talloc_free(tmp_ctx);
988 0 : return ret;
989 : }
990 :
991 72 : nc_dns_name = samdb_dn_to_dns_domain(tmp_ctx, nc_root);
992 72 : if (nc_dns_name == NULL) {
993 0 : talloc_free(tmp_ctx);
994 0 : return ldb_operr(ldb);
995 : }
996 :
997 103 : if (strlen(nc_dns_name) == dns_host_name_len &&
998 51 : strncasecmp(dnsHostName_str,
999 : nc_dns_name,
1000 : dns_host_name_len) == 0)
1001 : {
1002 : /* It matches -- success. */
1003 51 : talloc_free(tmp_ctx);
1004 51 : return LDB_SUCCESS;
1005 : }
1006 :
1007 : /* We didn't get a match, so now try msDS-AllowedDNSSuffixes. */
1008 :
1009 21 : ret = dsdb_module_search_dn(module, tmp_ctx,
1010 : &nc_res, nc_root,
1011 : nc_attrs,
1012 : DSDB_FLAG_NEXT_MODULE |
1013 : DSDB_FLAG_AS_SYSTEM |
1014 : DSDB_SEARCH_SHOW_RECYCLED,
1015 : req);
1016 21 : if (ret != LDB_SUCCESS) {
1017 0 : talloc_free(tmp_ctx);
1018 0 : return ret;
1019 : }
1020 :
1021 21 : allowed_suffixes = ldb_msg_find_element(nc_res->msgs[0],
1022 : "msDS-AllowedDNSSuffixes");
1023 21 : if (allowed_suffixes == NULL) {
1024 12 : goto fail;
1025 : }
1026 :
1027 9 : for (i = 0; i < allowed_suffixes->num_values; ++i) {
1028 9 : const struct ldb_val *suffix = &allowed_suffixes->values[i];
1029 :
1030 14 : if (suffix->length == dns_host_name_len &&
1031 9 : strncasecmp(dnsHostName_str,
1032 9 : (const char *)suffix->data,
1033 : dns_host_name_len) == 0)
1034 : {
1035 : /* It matches -- success. */
1036 9 : talloc_free(tmp_ctx);
1037 9 : return LDB_SUCCESS;
1038 : }
1039 : }
1040 :
1041 22 : fail:
1042 196 : ldb_debug_set(ldb, LDB_DEBUG_WARNING,
1043 : "acl: hostname validation failed for "
1044 : "hostname[%.*s] account[%.*s]\n",
1045 84 : (int)dnsHostName->length, dnsHostName->data,
1046 140 : (int)samAccountName->length, samAccountName->data);
1047 84 : talloc_free(tmp_ctx);
1048 84 : return LDB_ERR_CONSTRAINT_VIOLATION;
1049 : }
1050 :
1051 320277 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
1052 : {
1053 : int ret;
1054 : struct ldb_dn *parent;
1055 : struct ldb_context *ldb;
1056 : const struct dsdb_schema *schema;
1057 : const struct dsdb_class *objectclass;
1058 : struct ldb_control *as_system;
1059 : struct ldb_message_element *el;
1060 320277 : unsigned int instanceType = 0;
1061 :
1062 320277 : if (ldb_dn_is_special(req->op.add.message->dn)) {
1063 371 : return ldb_next_request(module, req);
1064 : }
1065 :
1066 319906 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1067 319906 : if (as_system != NULL) {
1068 75 : as_system->critical = 0;
1069 : }
1070 :
1071 319906 : if (dsdb_module_am_system(module) || as_system) {
1072 3842 : return ldb_next_request(module, req);
1073 : }
1074 :
1075 316064 : ldb = ldb_module_get_ctx(module);
1076 :
1077 316064 : parent = ldb_dn_get_parent(req, req->op.add.message->dn);
1078 316064 : if (parent == NULL) {
1079 0 : return ldb_oom(ldb);
1080 : }
1081 :
1082 316064 : schema = dsdb_get_schema(ldb, req);
1083 316064 : if (!schema) {
1084 0 : return ldb_operr(ldb);
1085 : }
1086 :
1087 316064 : objectclass = dsdb_get_structural_oc_from_msg(schema, req->op.add.message);
1088 316064 : if (!objectclass) {
1089 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1090 : "acl: unable to find or validate structural objectClass on %s\n",
1091 0 : ldb_dn_get_linearized(req->op.add.message->dn));
1092 0 : return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
1093 : }
1094 :
1095 316064 : el = ldb_msg_find_element(req->op.add.message, "instanceType");
1096 316064 : if ((el != NULL) && (el->num_values != 1)) {
1097 1 : ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
1098 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
1099 : }
1100 :
1101 316063 : instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
1102 : "instanceType", 0);
1103 316063 : if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
1104 : static const char *no_attrs[] = { NULL };
1105 : struct ldb_result *partition_res;
1106 : struct ldb_dn *partitions_dn;
1107 :
1108 356 : partitions_dn = samdb_partitions_dn(ldb, req);
1109 356 : if (!partitions_dn) {
1110 0 : ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
1111 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1112 : }
1113 :
1114 356 : ret = dsdb_module_search(module, req, &partition_res,
1115 : partitions_dn, LDB_SCOPE_ONELEVEL,
1116 : no_attrs,
1117 : DSDB_FLAG_NEXT_MODULE |
1118 : DSDB_FLAG_AS_SYSTEM |
1119 : DSDB_SEARCH_ONE_ONLY |
1120 : DSDB_SEARCH_SHOW_RECYCLED,
1121 : req,
1122 : "(&(nCName=%s)(objectClass=crossRef))",
1123 356 : ldb_dn_get_linearized(req->op.add.message->dn));
1124 :
1125 356 : if (ret == LDB_SUCCESS) {
1126 : /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1127 0 : ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
1128 : SEC_ADS_WRITE_PROP,
1129 : &objectclass->schemaIDGUID, req);
1130 0 : if (ret != LDB_SUCCESS) {
1131 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1132 : "acl: ACL check failed on crossRef object %s: %s\n",
1133 0 : ldb_dn_get_linearized(partition_res->msgs[0]->dn),
1134 : ldb_errstring(ldb));
1135 0 : return ret;
1136 : }
1137 :
1138 : /*
1139 : * TODO: Remaining checks, like if we are
1140 : * the naming master etc need to be handled
1141 : * in the instanceType module
1142 : */
1143 0 : return ldb_next_request(module, req);
1144 : }
1145 :
1146 : /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
1147 356 : ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
1148 : SEC_ADS_CREATE_CHILD,
1149 : &objectclass->schemaIDGUID, req);
1150 584 : if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1151 228 : ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
1152 : {
1153 : /* Allow provision bootstrap */
1154 228 : ret = LDB_SUCCESS;
1155 : }
1156 356 : if (ret != LDB_SUCCESS) {
1157 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1158 : "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
1159 : ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
1160 0 : return ret;
1161 : }
1162 :
1163 : /*
1164 : * TODO: Remaining checks, like if we are the naming
1165 : * master and adding the crossRef object need to be
1166 : * handled in the instanceType module
1167 : */
1168 356 : return ldb_next_request(module, req);
1169 : }
1170 :
1171 315707 : ret = dsdb_module_check_access_on_dn(module, req, parent,
1172 : SEC_ADS_CREATE_CHILD,
1173 : &objectclass->schemaIDGUID, req);
1174 315707 : if (ret != LDB_SUCCESS) {
1175 24 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1176 : "acl: unable to get access to %s\n",
1177 24 : ldb_dn_get_linearized(req->op.add.message->dn));
1178 24 : return ret;
1179 : }
1180 315683 : return ldb_next_request(module, req);
1181 : }
1182 :
1183 : /* checks if modifications are allowed on "Member" attribute */
1184 6253 : static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
1185 : struct ldb_module *module,
1186 : struct ldb_request *req,
1187 : struct security_descriptor *sd,
1188 : struct dom_sid *sid,
1189 : const struct dsdb_attribute *attr,
1190 : const struct dsdb_class *objectclass)
1191 : {
1192 : int ret;
1193 : unsigned int i;
1194 6253 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1195 : struct ldb_dn *user_dn;
1196 : struct ldb_message_element *member_el;
1197 6253 : const struct ldb_message *msg = NULL;
1198 :
1199 6253 : if (req->operation == LDB_MODIFY) {
1200 6253 : msg = req->op.mod.message;
1201 0 : } else if (req->operation == LDB_ADD) {
1202 0 : msg = req->op.add.message;
1203 : } else {
1204 0 : return LDB_ERR_OPERATIONS_ERROR;
1205 : }
1206 :
1207 : /* if we have wp, we can do whatever we like */
1208 6253 : if (acl_check_access_on_attribute(module,
1209 : mem_ctx,
1210 : sd,
1211 : sid,
1212 : SEC_ADS_WRITE_PROP,
1213 : attr, objectclass) == LDB_SUCCESS) {
1214 6193 : return LDB_SUCCESS;
1215 : }
1216 : /* if we are adding/deleting ourselves, check for self membership */
1217 60 : ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
1218 60 : &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
1219 : &user_dn);
1220 60 : if (ret != LDB_SUCCESS) {
1221 0 : return ret;
1222 : }
1223 60 : member_el = ldb_msg_find_element(msg, "member");
1224 60 : if (!member_el) {
1225 0 : return ldb_operr(ldb);
1226 : }
1227 : /* user can only remove oneself */
1228 60 : if (member_el->num_values == 0) {
1229 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1230 : }
1231 87 : for (i = 0; i < member_el->num_values; i++) {
1232 118 : if (strcasecmp((const char *)member_el->values[i].data,
1233 69 : ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
1234 42 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1235 : }
1236 : }
1237 18 : ret = acl_check_extended_right(mem_ctx,
1238 : module,
1239 : req,
1240 : objectclass,
1241 : sd,
1242 : acl_user_token(module),
1243 : GUID_DRS_SELF_MEMBERSHIP,
1244 : SEC_ADS_SELF_WRITE,
1245 : sid);
1246 18 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1247 9 : dsdb_acl_debug(sd, acl_user_token(module),
1248 4 : msg->dn,
1249 : true,
1250 : 10);
1251 : }
1252 18 : return ret;
1253 : }
1254 :
1255 12757 : static int acl_check_password_rights(
1256 : TALLOC_CTX *mem_ctx,
1257 : struct ldb_module *module,
1258 : struct ldb_request *req,
1259 : struct security_descriptor *sd,
1260 : struct dom_sid *sid,
1261 : const struct dsdb_class *objectclass,
1262 : bool userPassword,
1263 : struct dsdb_control_password_acl_validation **control_for_response)
1264 : {
1265 12757 : int ret = LDB_SUCCESS;
1266 12757 : unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
1267 12757 : unsigned int del_val_cnt = 0, add_val_cnt = 0, rep_val_cnt = 0;
1268 : struct ldb_message_element *el;
1269 : struct ldb_message *msg;
1270 12757 : struct ldb_control *c = NULL;
1271 12757 : const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
1272 : "unicodePwd", NULL }, **l;
1273 12757 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1274 12757 : struct dsdb_control_password_acl_validation *pav = NULL;
1275 :
1276 12757 : if (tmp_ctx == NULL) {
1277 0 : return LDB_ERR_OPERATIONS_ERROR;
1278 : }
1279 :
1280 12757 : pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
1281 12757 : if (pav == NULL) {
1282 0 : talloc_free(tmp_ctx);
1283 0 : return LDB_ERR_OPERATIONS_ERROR;
1284 : }
1285 : /*
1286 : * Set control_for_response to pav so it can be added to the response
1287 : * and be passed up to the audit_log module which uses it to identify
1288 : * password reset attempts.
1289 : */
1290 12757 : *control_for_response = pav;
1291 :
1292 12757 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
1293 12757 : if (c != NULL) {
1294 424 : pav->pwd_reset = false;
1295 :
1296 : /*
1297 : * The "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1298 : * have a user password change and not a set as the message
1299 : * looks like. In it's value blob it contains the NT and/or LM
1300 : * hash of the old password specified by the user. This control
1301 : * is used by the SAMR and "kpasswd" password change mechanisms.
1302 : *
1303 : * This control can't be used by real LDAP clients,
1304 : * the only caller is samdb_set_password_internal(),
1305 : * so we don't have to strict verification of the input.
1306 : */
1307 424 : ret = acl_check_extended_right(tmp_ctx,
1308 : module,
1309 : req,
1310 : objectclass,
1311 : sd,
1312 : acl_user_token(module),
1313 : GUID_DRS_USER_CHANGE_PASSWORD,
1314 : SEC_ADS_CONTROL_ACCESS,
1315 : sid);
1316 424 : goto checked;
1317 : }
1318 :
1319 12333 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1320 12333 : if (c != NULL) {
1321 234 : pav->pwd_reset = true;
1322 :
1323 : /*
1324 : * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1325 : * "DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID" control means that we
1326 : * have a force password set.
1327 : * This control is used by the SAMR/NETLOGON/LSA password
1328 : * reset mechanisms.
1329 : *
1330 : * This control can't be used by real LDAP clients,
1331 : * the only caller is samdb_set_password_internal(),
1332 : * so we don't have to strict verification of the input.
1333 : */
1334 234 : ret = acl_check_extended_right(tmp_ctx,
1335 : module,
1336 : req,
1337 : objectclass,
1338 : sd,
1339 : acl_user_token(module),
1340 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1341 : SEC_ADS_CONTROL_ACCESS,
1342 : sid);
1343 234 : goto checked;
1344 : }
1345 :
1346 12099 : el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1347 12099 : if (el != NULL) {
1348 : /*
1349 : * dBCSPwd is only allowed with a control.
1350 : */
1351 0 : talloc_free(tmp_ctx);
1352 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1353 : }
1354 :
1355 12099 : msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1356 12099 : if (msg == NULL) {
1357 0 : return ldb_module_oom(module);
1358 : }
1359 48396 : for (l = passwordAttrs; *l != NULL; l++) {
1360 36297 : if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1361 9701 : continue;
1362 : }
1363 :
1364 58013 : while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1365 13821 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1366 1729 : ++del_attr_cnt;
1367 1729 : del_val_cnt += el->num_values;
1368 : }
1369 13821 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1370 1697 : ++add_attr_cnt;
1371 1697 : add_val_cnt += el->num_values;
1372 : }
1373 13821 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1374 10395 : ++rep_attr_cnt;
1375 10395 : rep_val_cnt += el->num_values;
1376 : }
1377 13821 : ldb_msg_remove_element(msg, el);
1378 : }
1379 : }
1380 :
1381 : /* single deletes will be handled by the "password_hash" LDB module
1382 : * later in the stack, so we let it though here */
1383 12099 : if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1384 49 : talloc_free(tmp_ctx);
1385 49 : return LDB_SUCCESS;
1386 : }
1387 :
1388 :
1389 12050 : if (rep_attr_cnt > 0) {
1390 10381 : pav->pwd_reset = true;
1391 :
1392 10381 : ret = acl_check_extended_right(tmp_ctx,
1393 : module,
1394 : req,
1395 : objectclass,
1396 : sd,
1397 : acl_user_token(module),
1398 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1399 : SEC_ADS_CONTROL_ACCESS,
1400 : sid);
1401 10381 : goto checked;
1402 : }
1403 :
1404 1669 : if (add_attr_cnt != del_attr_cnt) {
1405 81 : pav->pwd_reset = true;
1406 :
1407 81 : ret = acl_check_extended_right(tmp_ctx,
1408 : module,
1409 : req,
1410 : objectclass,
1411 : sd,
1412 : acl_user_token(module),
1413 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1414 : SEC_ADS_CONTROL_ACCESS,
1415 : sid);
1416 81 : goto checked;
1417 : }
1418 :
1419 1588 : if (add_val_cnt == 1 && del_val_cnt == 1) {
1420 925 : pav->pwd_reset = false;
1421 :
1422 925 : ret = acl_check_extended_right(tmp_ctx,
1423 : module,
1424 : req,
1425 : objectclass,
1426 : sd,
1427 : acl_user_token(module),
1428 : GUID_DRS_USER_CHANGE_PASSWORD,
1429 : SEC_ADS_CONTROL_ACCESS,
1430 : sid);
1431 : /* Very strange, but we get constraint violation in this case */
1432 925 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1433 18 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1434 : }
1435 925 : goto checked;
1436 : }
1437 :
1438 663 : if (add_val_cnt == 1 && del_val_cnt == 0) {
1439 453 : pav->pwd_reset = true;
1440 :
1441 453 : ret = acl_check_extended_right(tmp_ctx,
1442 : module,
1443 : req,
1444 : objectclass,
1445 : sd,
1446 : acl_user_token(module),
1447 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1448 : SEC_ADS_CONTROL_ACCESS,
1449 : sid);
1450 : /* Very strange, but we get constraint violation in this case */
1451 453 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1452 21 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1453 : }
1454 453 : goto checked;
1455 : }
1456 :
1457 : /*
1458 : * Everything else is handled by the password_hash module where it will
1459 : * fail, but with the correct error code when the module is again
1460 : * checking the attributes. As the change request will lack the
1461 : * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1462 : * any modification attempt that went this way will be rejected.
1463 : */
1464 :
1465 210 : talloc_free(tmp_ctx);
1466 210 : return LDB_SUCCESS;
1467 :
1468 12498 : checked:
1469 12498 : if (ret != LDB_SUCCESS) {
1470 123 : dsdb_acl_debug(sd, acl_user_token(module),
1471 123 : req->op.mod.message->dn,
1472 : true,
1473 : 10);
1474 123 : talloc_free(tmp_ctx);
1475 123 : return ret;
1476 : }
1477 :
1478 12375 : ret = ldb_request_add_control(req,
1479 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1480 12375 : if (ret != LDB_SUCCESS) {
1481 0 : ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1482 : "Unable to register ACL validation control!\n");
1483 0 : return ret;
1484 : }
1485 12375 : return LDB_SUCCESS;
1486 : }
1487 :
1488 : /*
1489 : * Context needed by acl_callback
1490 : */
1491 : struct acl_callback_context {
1492 : struct ldb_request *request;
1493 : struct ldb_module *module;
1494 : };
1495 :
1496 : /*
1497 : * @brief Copy the password validation control to the reply.
1498 : *
1499 : * Copy the dsdb_control_password_acl_validation control from the request,
1500 : * to the reply. The control is used by the audit_log module to identify
1501 : * password rests.
1502 : *
1503 : * @param req the ldb request.
1504 : * @param ares the result, updated with the control.
1505 : */
1506 85379 : static void copy_password_acl_validation_control(
1507 : struct ldb_request *req,
1508 : struct ldb_reply *ares)
1509 : {
1510 85379 : struct ldb_control *pav_ctrl = NULL;
1511 85379 : struct dsdb_control_password_acl_validation *pav = NULL;
1512 :
1513 85379 : pav_ctrl = ldb_request_get_control(
1514 : discard_const(req),
1515 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1516 85379 : if (pav_ctrl == NULL) {
1517 73004 : return;
1518 : }
1519 :
1520 12375 : pav = talloc_get_type_abort(
1521 : pav_ctrl->data,
1522 : struct dsdb_control_password_acl_validation);
1523 12375 : if (pav == NULL) {
1524 0 : return;
1525 : }
1526 12375 : ldb_reply_add_control(
1527 : ares,
1528 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1529 : false,
1530 : pav);
1531 : }
1532 : /*
1533 : * @brief call back function for acl_modify.
1534 : *
1535 : * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1536 : * the request to the reply.
1537 : *
1538 : * @param req the ldb_request.
1539 : * @param ares the operation result.
1540 : *
1541 : * @return the LDB_STATUS
1542 : */
1543 85389 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1544 : {
1545 85389 : struct acl_callback_context *ac = NULL;
1546 :
1547 85389 : ac = talloc_get_type(req->context, struct acl_callback_context);
1548 :
1549 85389 : if (!ares) {
1550 0 : return ldb_module_done(
1551 : ac->request,
1552 : NULL,
1553 : NULL,
1554 : LDB_ERR_OPERATIONS_ERROR);
1555 : }
1556 :
1557 : /* pass on to the callback */
1558 85389 : switch (ares->type) {
1559 0 : case LDB_REPLY_ENTRY:
1560 0 : return ldb_module_send_entry(
1561 : ac->request,
1562 : ares->message,
1563 : ares->controls);
1564 :
1565 10 : case LDB_REPLY_REFERRAL:
1566 10 : return ldb_module_send_referral(
1567 : ac->request,
1568 : ares->referral);
1569 :
1570 85379 : case LDB_REPLY_DONE:
1571 : /*
1572 : * Copy the ACL control from the request to the response
1573 : */
1574 85379 : copy_password_acl_validation_control(req, ares);
1575 85379 : return ldb_module_done(
1576 : ac->request,
1577 : ares->controls,
1578 : ares->response,
1579 : ares->error);
1580 :
1581 0 : default:
1582 : /* Can't happen */
1583 0 : return LDB_ERR_OPERATIONS_ERROR;
1584 : }
1585 : }
1586 :
1587 366347 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1588 : {
1589 : int ret;
1590 366347 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1591 : const struct dsdb_schema *schema;
1592 : unsigned int i;
1593 : const struct dsdb_class *objectclass;
1594 : struct ldb_result *acl_res;
1595 : struct security_descriptor *sd;
1596 366347 : struct dom_sid *sid = NULL;
1597 : struct ldb_control *as_system;
1598 : struct ldb_control *is_undelete;
1599 366347 : struct ldb_control *implicit_validated_write_control = NULL;
1600 : bool userPassword;
1601 366347 : bool password_rights_checked = false;
1602 : TALLOC_CTX *tmp_ctx;
1603 366347 : const struct ldb_message *msg = req->op.mod.message;
1604 : static const char *acl_attrs[] = {
1605 : "nTSecurityDescriptor",
1606 : "objectClass",
1607 : "objectSid",
1608 : NULL
1609 : };
1610 366347 : struct acl_callback_context *context = NULL;
1611 366347 : struct ldb_request *new_req = NULL;
1612 366347 : struct dsdb_control_password_acl_validation *pav = NULL;
1613 366347 : struct ldb_control **controls = NULL;
1614 :
1615 366347 : if (ldb_dn_is_special(msg->dn)) {
1616 558 : return ldb_next_request(module, req);
1617 : }
1618 :
1619 365789 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1620 365789 : if (as_system != NULL) {
1621 123635 : as_system->critical = 0;
1622 : }
1623 :
1624 365789 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1625 :
1626 365789 : implicit_validated_write_control = ldb_request_get_control(
1627 : req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID);
1628 365789 : if (implicit_validated_write_control != NULL) {
1629 84 : implicit_validated_write_control->critical = 0;
1630 : }
1631 :
1632 : /* Don't print this debug statement if elements[0].name is going to be NULL */
1633 365789 : if (msg->num_elements > 0) {
1634 365508 : DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
1635 : }
1636 365789 : if (dsdb_module_am_system(module) || as_system) {
1637 278852 : return ldb_next_request(module, req);
1638 : }
1639 :
1640 86937 : tmp_ctx = talloc_new(req);
1641 86937 : if (tmp_ctx == NULL) {
1642 0 : return ldb_oom(ldb);
1643 : }
1644 :
1645 86937 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
1646 : acl_attrs,
1647 : DSDB_FLAG_NEXT_MODULE |
1648 : DSDB_FLAG_AS_SYSTEM |
1649 : DSDB_SEARCH_SHOW_RECYCLED,
1650 : req);
1651 :
1652 86937 : if (ret != LDB_SUCCESS) {
1653 121 : goto fail;
1654 : }
1655 :
1656 86816 : userPassword = dsdb_user_password_support(module, req, req);
1657 :
1658 86816 : schema = dsdb_get_schema(ldb, tmp_ctx);
1659 86816 : if (!schema) {
1660 0 : talloc_free(tmp_ctx);
1661 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1662 : "acl_modify: Error obtaining schema.");
1663 : }
1664 :
1665 86816 : ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1666 86816 : if (ret != LDB_SUCCESS) {
1667 0 : talloc_free(tmp_ctx);
1668 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1669 : "acl_modify: Error retrieving security descriptor.");
1670 : }
1671 : /* Theoretically we pass the check if the object has no sd */
1672 86816 : if (!sd) {
1673 0 : goto success;
1674 : }
1675 :
1676 86816 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1677 86816 : if (!objectclass) {
1678 0 : talloc_free(tmp_ctx);
1679 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1680 : "acl_modify: Error retrieving object class for GUID.");
1681 : }
1682 86816 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1683 198188 : for (i=0; i < msg->num_elements; i++) {
1684 112807 : const struct ldb_message_element *el = &msg->elements[i];
1685 : const struct dsdb_attribute *attr;
1686 :
1687 : /*
1688 : * This basic attribute existence check with the right errorcode
1689 : * is needed since this module is the first one which requests
1690 : * schema attribute information.
1691 : * The complete attribute checking is done in the
1692 : * "objectclass_attrs" module behind this one.
1693 : *
1694 : * NOTE: "clearTextPassword" is not defined in the schema.
1695 : */
1696 112807 : attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1697 112807 : if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1698 4 : ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
1699 : "on entry '%s' was not found in the schema!",
1700 2 : req->op.mod.message->elements[i].name,
1701 2 : ldb_dn_get_linearized(req->op.mod.message->dn));
1702 2 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1703 2 : goto fail;
1704 : }
1705 :
1706 112805 : if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
1707 25232 : uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1708 25232 : uint32_t access_mask = 0;
1709 :
1710 25232 : if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1711 11381 : access_mask |= SEC_STD_WRITE_OWNER;
1712 : }
1713 25232 : if (sd_flags & SECINFO_DACL) {
1714 25145 : access_mask |= SEC_STD_WRITE_DAC;
1715 : }
1716 25232 : if (sd_flags & SECINFO_SACL) {
1717 11312 : access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1718 : }
1719 :
1720 25232 : ret = acl_check_access_on_attribute(module,
1721 : tmp_ctx,
1722 : sd,
1723 : sid,
1724 : access_mask,
1725 : attr,
1726 : objectclass);
1727 25232 : if (ret != LDB_SUCCESS) {
1728 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1729 : "Object %s has no write dacl access\n",
1730 0 : ldb_dn_get_linearized(msg->dn));
1731 0 : dsdb_acl_debug(sd,
1732 : acl_user_token(module),
1733 0 : msg->dn,
1734 : true,
1735 : 10);
1736 0 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1737 0 : goto fail;
1738 : }
1739 87573 : } else if (ldb_attr_cmp("member", el->name) == 0) {
1740 6253 : ret = acl_check_self_membership(tmp_ctx,
1741 : module,
1742 : req,
1743 : sd,
1744 : sid,
1745 : attr,
1746 : objectclass);
1747 6253 : if (ret != LDB_SUCCESS) {
1748 51 : goto fail;
1749 : }
1750 81320 : } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
1751 : /* this one is not affected by any rights, we should let it through
1752 : so that passwords_hash returns the correct error */
1753 60 : continue;
1754 81260 : } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1755 58633 : (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
1756 68009 : ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1757 : /*
1758 : * Ideally we would do the acl_check_password_rights
1759 : * before we checked the other attributes, i.e. in a
1760 : * loop before the current one.
1761 : * Have not done this as yet in order to limit the size
1762 : * of the change. To limit the possibility of breaking
1763 : * the ACL logic.
1764 : */
1765 14380 : if (password_rights_checked) {
1766 1623 : continue;
1767 : }
1768 12757 : ret = acl_check_password_rights(tmp_ctx,
1769 : module,
1770 : req,
1771 : sd,
1772 : sid,
1773 : objectclass,
1774 : userPassword,
1775 : &pav);
1776 12757 : if (ret != LDB_SUCCESS) {
1777 123 : goto fail;
1778 : }
1779 12634 : password_rights_checked = true;
1780 66880 : } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1781 1269 : ret = acl_check_spn(tmp_ctx,
1782 : module,
1783 : req,
1784 : el,
1785 : sd,
1786 : sid,
1787 : attr,
1788 : objectclass,
1789 : implicit_validated_write_control);
1790 1269 : if (ret != LDB_SUCCESS) {
1791 216 : goto fail;
1792 : }
1793 65611 : } else if (ldb_attr_cmp("dnsHostName", el->name) == 0) {
1794 645 : ret = acl_check_dns_host_name(tmp_ctx,
1795 : module,
1796 : req,
1797 : el,
1798 : sd,
1799 : sid,
1800 : attr,
1801 : objectclass,
1802 : implicit_validated_write_control);
1803 645 : if (ret != LDB_SUCCESS) {
1804 171 : goto fail;
1805 : }
1806 64966 : } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
1807 : /*
1808 : * in case of undelete op permissions on
1809 : * isDeleted are irrelevant and
1810 : * distinguishedName is removed by the
1811 : * tombstone_reanimate module
1812 : */
1813 274 : continue;
1814 64692 : } else if (implicit_validated_write_control != NULL) {
1815 : /* Allow the update. */
1816 252 : continue;
1817 : } else {
1818 64440 : ret = acl_check_access_on_attribute(module,
1819 : tmp_ctx,
1820 : sd,
1821 : sid,
1822 : SEC_ADS_WRITE_PROP,
1823 : attr,
1824 : objectclass);
1825 64440 : if (ret != LDB_SUCCESS) {
1826 872 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1827 : "Object %s has no write property access\n",
1828 37 : ldb_dn_get_linearized(msg->dn));
1829 872 : dsdb_acl_debug(sd,
1830 : acl_user_token(module),
1831 37 : msg->dn,
1832 : true,
1833 : 10);
1834 872 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1835 872 : goto fail;
1836 : }
1837 : }
1838 : }
1839 :
1840 85381 : success:
1841 85381 : talloc_free(tmp_ctx);
1842 85381 : context = talloc_zero(req, struct acl_callback_context);
1843 :
1844 85381 : if (context == NULL) {
1845 0 : return ldb_oom(ldb);
1846 : }
1847 85381 : context->request = req;
1848 85381 : context->module = module;
1849 85381 : ret = ldb_build_mod_req(
1850 : &new_req,
1851 : ldb,
1852 : req,
1853 : req->op.mod.message,
1854 : req->controls,
1855 : context,
1856 : acl_callback,
1857 : req);
1858 85381 : if (ret != LDB_SUCCESS) {
1859 0 : return ret;
1860 : }
1861 85381 : return ldb_next_request(module, new_req);
1862 1556 : fail:
1863 1556 : talloc_free(tmp_ctx);
1864 : /*
1865 : * We copy the pav into the result, so that the password reset
1866 : * logging code in audit_log can log failed password reset attempts.
1867 : */
1868 1556 : if (pav) {
1869 123 : struct ldb_control *control = NULL;
1870 :
1871 123 : controls = talloc_zero_array(req, struct ldb_control *, 2);
1872 123 : if (controls == NULL) {
1873 0 : return ldb_oom(ldb);
1874 : }
1875 :
1876 123 : control = talloc(controls, struct ldb_control);
1877 :
1878 123 : if (control == NULL) {
1879 0 : return ldb_oom(ldb);
1880 : }
1881 :
1882 123 : control->oid= talloc_strdup(
1883 : control,
1884 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1885 123 : if (control->oid == NULL) {
1886 0 : return ldb_oom(ldb);
1887 : }
1888 123 : control->critical = false;
1889 123 : control->data = pav;
1890 123 : *controls = control;
1891 : }
1892 1556 : return ldb_module_done(req, controls, NULL, ret);
1893 : }
1894 :
1895 : /* similar to the modify for the time being.
1896 : * We need to consider the special delete tree case, though - TODO */
1897 47753 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
1898 : {
1899 : int ret;
1900 : struct ldb_dn *parent;
1901 : struct ldb_context *ldb;
1902 : struct ldb_dn *nc_root;
1903 : struct ldb_control *as_system;
1904 : const struct dsdb_schema *schema;
1905 : const struct dsdb_class *objectclass;
1906 47753 : struct security_descriptor *sd = NULL;
1907 47753 : struct dom_sid *sid = NULL;
1908 : struct ldb_result *acl_res;
1909 : static const char *acl_attrs[] = {
1910 : "nTSecurityDescriptor",
1911 : "objectClass",
1912 : "objectSid",
1913 : NULL
1914 : };
1915 :
1916 47753 : if (ldb_dn_is_special(req->op.del.dn)) {
1917 1 : return ldb_next_request(module, req);
1918 : }
1919 :
1920 47752 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1921 47752 : if (as_system != NULL) {
1922 18377 : as_system->critical = 0;
1923 : }
1924 :
1925 47752 : if (dsdb_module_am_system(module) || as_system) {
1926 19483 : return ldb_next_request(module, req);
1927 : }
1928 :
1929 28269 : DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
1930 :
1931 28269 : ldb = ldb_module_get_ctx(module);
1932 :
1933 28269 : parent = ldb_dn_get_parent(req, req->op.del.dn);
1934 28269 : if (parent == NULL) {
1935 0 : return ldb_oom(ldb);
1936 : }
1937 :
1938 : /* Make sure we aren't deleting a NC */
1939 :
1940 28269 : ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
1941 28269 : if (ret != LDB_SUCCESS) {
1942 0 : return ret;
1943 : }
1944 28269 : if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
1945 0 : talloc_free(nc_root);
1946 0 : DEBUG(10,("acl:deleting a NC\n"));
1947 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1948 0 : return ldb_module_done(req, NULL, NULL,
1949 : LDB_ERR_UNWILLING_TO_PERFORM);
1950 : }
1951 28269 : talloc_free(nc_root);
1952 :
1953 28269 : ret = dsdb_module_search_dn(module, req, &acl_res,
1954 : req->op.del.dn, acl_attrs,
1955 : DSDB_FLAG_NEXT_MODULE |
1956 : DSDB_FLAG_AS_SYSTEM |
1957 : DSDB_SEARCH_SHOW_RECYCLED, req);
1958 : /* we sould be able to find the parent */
1959 28269 : if (ret != LDB_SUCCESS) {
1960 0 : DEBUG(10,("acl: failed to find object %s\n",
1961 : ldb_dn_get_linearized(req->op.rename.olddn)));
1962 0 : return ret;
1963 : }
1964 :
1965 28269 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1966 28269 : if (ret != LDB_SUCCESS) {
1967 0 : return ldb_operr(ldb);
1968 : }
1969 28269 : if (!sd) {
1970 0 : return ldb_operr(ldb);
1971 : }
1972 :
1973 28269 : schema = dsdb_get_schema(ldb, req);
1974 28269 : if (!schema) {
1975 0 : return ldb_operr(ldb);
1976 : }
1977 :
1978 28269 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1979 :
1980 28269 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1981 28269 : if (!objectclass) {
1982 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1983 : "acl_modify: Error retrieving object class for GUID.");
1984 : }
1985 :
1986 28269 : if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
1987 2402 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
1988 : SEC_ADS_DELETE_TREE,
1989 : objectclass);
1990 2402 : if (ret != LDB_SUCCESS) {
1991 0 : return ret;
1992 : }
1993 :
1994 2402 : return ldb_next_request(module, req);
1995 : }
1996 :
1997 : /* First check if we have delete object right */
1998 25867 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
1999 : SEC_STD_DELETE,
2000 : objectclass);
2001 25867 : if (ret == LDB_SUCCESS) {
2002 25664 : return ldb_next_request(module, req);
2003 : }
2004 :
2005 : /* Nope, we don't have delete object. Lets check if we have delete
2006 : * child on the parent */
2007 203 : ret = dsdb_module_check_access_on_dn(module, req, parent,
2008 : SEC_ADS_DELETE_CHILD,
2009 : &objectclass->schemaIDGUID,
2010 : req);
2011 203 : if (ret != LDB_SUCCESS) {
2012 10 : return ret;
2013 : }
2014 :
2015 193 : return ldb_next_request(module, req);
2016 : }
2017 265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
2018 : struct ldb_module *module,
2019 : struct ldb_request *req,
2020 : struct ldb_dn *nc_root)
2021 : {
2022 : int ret;
2023 : struct ldb_result *acl_res;
2024 265 : struct security_descriptor *sd = NULL;
2025 265 : struct dom_sid *sid = NULL;
2026 265 : const struct dsdb_schema *schema = NULL;
2027 265 : const struct dsdb_class *objectclass = NULL;
2028 265 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2029 : static const char *acl_attrs[] = {
2030 : "nTSecurityDescriptor",
2031 : "objectClass",
2032 : "objectSid",
2033 : NULL
2034 : };
2035 :
2036 265 : ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
2037 : nc_root, acl_attrs,
2038 : DSDB_FLAG_NEXT_MODULE |
2039 : DSDB_FLAG_AS_SYSTEM |
2040 : DSDB_SEARCH_SHOW_RECYCLED, req);
2041 265 : if (ret != LDB_SUCCESS) {
2042 0 : DEBUG(10,("acl: failed to find object %s\n",
2043 : ldb_dn_get_linearized(nc_root)));
2044 0 : return ret;
2045 : }
2046 :
2047 265 : ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
2048 265 : sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
2049 265 : schema = dsdb_get_schema(ldb, req);
2050 265 : if (!schema) {
2051 0 : return LDB_ERR_OPERATIONS_ERROR;
2052 : }
2053 265 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2054 265 : if (ret != LDB_SUCCESS || !sd) {
2055 0 : return ldb_operr(ldb_module_get_ctx(module));
2056 : }
2057 265 : return acl_check_extended_right(mem_ctx,
2058 : module,
2059 : req,
2060 : objectclass,
2061 : sd,
2062 : acl_user_token(module),
2063 : GUID_DRS_REANIMATE_TOMBSTONE,
2064 : SEC_ADS_CONTROL_ACCESS, sid);
2065 : }
2066 :
2067 925 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
2068 : {
2069 : int ret;
2070 : struct ldb_dn *oldparent;
2071 : struct ldb_dn *newparent;
2072 : const struct dsdb_schema *schema;
2073 : const struct dsdb_class *objectclass;
2074 925 : const struct dsdb_attribute *attr = NULL;
2075 : struct ldb_context *ldb;
2076 925 : struct security_descriptor *sd = NULL;
2077 925 : struct dom_sid *sid = NULL;
2078 : struct ldb_result *acl_res;
2079 : struct ldb_dn *nc_root;
2080 : struct ldb_control *as_system;
2081 : struct ldb_control *is_undelete;
2082 : TALLOC_CTX *tmp_ctx;
2083 : const char *rdn_name;
2084 : static const char *acl_attrs[] = {
2085 : "nTSecurityDescriptor",
2086 : "objectClass",
2087 : "objectSid",
2088 : NULL
2089 : };
2090 :
2091 925 : if (ldb_dn_is_special(req->op.rename.olddn)) {
2092 0 : return ldb_next_request(module, req);
2093 : }
2094 :
2095 925 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2096 925 : if (as_system != NULL) {
2097 0 : as_system->critical = 0;
2098 : }
2099 :
2100 925 : DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
2101 925 : if (dsdb_module_am_system(module) || as_system) {
2102 312 : return ldb_next_request(module, req);
2103 : }
2104 :
2105 613 : ldb = ldb_module_get_ctx(module);
2106 :
2107 613 : tmp_ctx = talloc_new(req);
2108 613 : if (tmp_ctx == NULL) {
2109 0 : return ldb_oom(ldb);
2110 : }
2111 :
2112 613 : oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
2113 613 : if (oldparent == NULL) {
2114 0 : return ldb_oom(ldb);
2115 : }
2116 613 : newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
2117 613 : if (newparent == NULL) {
2118 0 : return ldb_oom(ldb);
2119 : }
2120 :
2121 : /* Make sure we aren't renaming/moving a NC */
2122 :
2123 613 : ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
2124 613 : if (ret != LDB_SUCCESS) {
2125 0 : return ret;
2126 : }
2127 613 : if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
2128 0 : talloc_free(nc_root);
2129 0 : DEBUG(10,("acl:renaming/moving a NC\n"));
2130 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
2131 0 : return ldb_module_done(req, NULL, NULL,
2132 : LDB_ERR_UNWILLING_TO_PERFORM);
2133 : }
2134 :
2135 : /* special check for undelete operation */
2136 613 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
2137 613 : if (is_undelete != NULL) {
2138 265 : is_undelete->critical = 0;
2139 265 : ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
2140 265 : if (ret != LDB_SUCCESS) {
2141 9 : talloc_free(tmp_ctx);
2142 9 : return ret;
2143 : }
2144 : }
2145 604 : talloc_free(nc_root);
2146 :
2147 : /* Look for the parent */
2148 :
2149 604 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
2150 : req->op.rename.olddn, acl_attrs,
2151 : DSDB_FLAG_NEXT_MODULE |
2152 : DSDB_FLAG_AS_SYSTEM |
2153 : DSDB_SEARCH_SHOW_RECYCLED, req);
2154 : /* we sould be able to find the parent */
2155 604 : if (ret != LDB_SUCCESS) {
2156 0 : DEBUG(10,("acl: failed to find object %s\n",
2157 : ldb_dn_get_linearized(req->op.rename.olddn)));
2158 0 : talloc_free(tmp_ctx);
2159 0 : return ret;
2160 : }
2161 :
2162 604 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
2163 604 : if (ret != LDB_SUCCESS) {
2164 0 : talloc_free(tmp_ctx);
2165 0 : return ldb_operr(ldb);
2166 : }
2167 604 : if (!sd) {
2168 0 : talloc_free(tmp_ctx);
2169 0 : return ldb_operr(ldb);
2170 : }
2171 :
2172 604 : schema = dsdb_get_schema(ldb, acl_res);
2173 604 : if (!schema) {
2174 0 : talloc_free(tmp_ctx);
2175 0 : return ldb_operr(ldb);
2176 : }
2177 :
2178 604 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
2179 :
2180 604 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
2181 604 : if (!objectclass) {
2182 0 : talloc_free(tmp_ctx);
2183 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2184 : "acl_modify: Error retrieving object class for GUID.");
2185 : }
2186 :
2187 604 : attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
2188 604 : if (attr == NULL) {
2189 0 : talloc_free(tmp_ctx);
2190 0 : return ldb_operr(ldb);
2191 : }
2192 :
2193 604 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2194 : SEC_ADS_WRITE_PROP,
2195 : attr, objectclass);
2196 604 : if (ret != LDB_SUCCESS) {
2197 19 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2198 : "Object %s has no wp on %s\n",
2199 : ldb_dn_get_linearized(req->op.rename.olddn),
2200 8 : attr->lDAPDisplayName);
2201 19 : dsdb_acl_debug(sd,
2202 : acl_user_token(module),
2203 : req->op.rename.olddn,
2204 : true,
2205 : 10);
2206 19 : talloc_free(tmp_ctx);
2207 19 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2208 : }
2209 :
2210 585 : rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
2211 585 : if (rdn_name == NULL) {
2212 0 : talloc_free(tmp_ctx);
2213 0 : return ldb_operr(ldb);
2214 : }
2215 :
2216 585 : attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2217 585 : if (attr == NULL) {
2218 0 : talloc_free(tmp_ctx);
2219 0 : return ldb_operr(ldb);
2220 : }
2221 :
2222 585 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
2223 : SEC_ADS_WRITE_PROP,
2224 : attr, objectclass);
2225 585 : if (ret != LDB_SUCCESS) {
2226 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2227 : "Object %s has no wp on %s\n",
2228 : ldb_dn_get_linearized(req->op.rename.olddn),
2229 4 : attr->lDAPDisplayName);
2230 9 : dsdb_acl_debug(sd,
2231 : acl_user_token(module),
2232 : req->op.rename.olddn,
2233 : true,
2234 : 10);
2235 9 : talloc_free(tmp_ctx);
2236 9 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2237 : }
2238 :
2239 576 : if (ldb_dn_compare(oldparent, newparent) == 0) {
2240 : /* regular rename, not move, nothing more to do */
2241 207 : talloc_free(tmp_ctx);
2242 207 : return ldb_next_request(module, req);
2243 : }
2244 :
2245 : /* new parent should have create child */
2246 369 : ret = dsdb_module_check_access_on_dn(module, req, newparent,
2247 : SEC_ADS_CREATE_CHILD,
2248 : &objectclass->schemaIDGUID, req);
2249 369 : if (ret != LDB_SUCCESS) {
2250 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2251 : "acl:access_denied renaming %s",
2252 : ldb_dn_get_linearized(req->op.rename.olddn));
2253 9 : talloc_free(tmp_ctx);
2254 9 : return ret;
2255 : }
2256 :
2257 : /* do we have delete object on the object? */
2258 : /* this access is not necessary for undelete ops */
2259 360 : if (is_undelete == NULL) {
2260 126 : ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
2261 : SEC_STD_DELETE,
2262 : objectclass);
2263 126 : if (ret == LDB_SUCCESS) {
2264 99 : talloc_free(tmp_ctx);
2265 99 : return ldb_next_request(module, req);
2266 : }
2267 : /* what about delete child on the current parent */
2268 27 : ret = dsdb_module_check_access_on_dn(module, req, oldparent,
2269 : SEC_ADS_DELETE_CHILD,
2270 : &objectclass->schemaIDGUID,
2271 : req);
2272 27 : if (ret != LDB_SUCCESS) {
2273 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
2274 : "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
2275 9 : talloc_free(tmp_ctx);
2276 9 : return ldb_module_done(req, NULL, NULL, ret);
2277 : }
2278 : }
2279 252 : talloc_free(tmp_ctx);
2280 :
2281 252 : return ldb_next_request(module, req);
2282 : }
2283 :
2284 609924 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
2285 : struct acl_private *data)
2286 : {
2287 : struct dsdb_attribute *a;
2288 609924 : uint32_t n = 0;
2289 :
2290 609924 : if (data->acl_search) {
2291 : /*
2292 : * If acl:search is activated, the acl_read module
2293 : * protects confidential attributes.
2294 : */
2295 609924 : return LDB_SUCCESS;
2296 : }
2297 :
2298 0 : if ((ac->schema == data->cached_schema_ptr) &&
2299 0 : (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
2300 : {
2301 0 : return LDB_SUCCESS;
2302 : }
2303 :
2304 0 : data->cached_schema_ptr = NULL;
2305 0 : data->cached_schema_loaded_usn = 0;
2306 0 : data->cached_schema_metadata_usn = 0;
2307 0 : TALLOC_FREE(data->confidential_attrs);
2308 :
2309 0 : if (ac->schema == NULL) {
2310 0 : return LDB_SUCCESS;
2311 : }
2312 :
2313 0 : for (a = ac->schema->attributes; a; a = a->next) {
2314 0 : const char **attrs = data->confidential_attrs;
2315 :
2316 0 : if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
2317 0 : continue;
2318 : }
2319 :
2320 0 : attrs = talloc_realloc(data, attrs, const char *, n + 2);
2321 0 : if (attrs == NULL) {
2322 0 : TALLOC_FREE(data->confidential_attrs);
2323 0 : return ldb_module_oom(ac->module);
2324 : }
2325 :
2326 0 : attrs[n] = a->lDAPDisplayName;
2327 0 : attrs[n+1] = NULL;
2328 0 : n++;
2329 :
2330 0 : data->confidential_attrs = attrs;
2331 : }
2332 :
2333 0 : data->cached_schema_ptr = ac->schema;
2334 0 : data->cached_schema_metadata_usn = ac->schema->metadata_usn;
2335 :
2336 0 : return LDB_SUCCESS;
2337 : }
2338 :
2339 33274425 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
2340 : {
2341 : struct acl_context *ac;
2342 : struct acl_private *data;
2343 : struct ldb_result *acl_res;
2344 : static const char *acl_attrs[] = {
2345 : "objectClass",
2346 : "nTSecurityDescriptor",
2347 : "objectSid",
2348 : NULL
2349 : };
2350 : int ret;
2351 : unsigned int i;
2352 :
2353 33274425 : ac = talloc_get_type(req->context, struct acl_context);
2354 33274425 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2355 33274425 : if (!ares) {
2356 0 : return ldb_module_done(ac->req, NULL, NULL,
2357 : LDB_ERR_OPERATIONS_ERROR);
2358 : }
2359 33274425 : if (ares->error != LDB_SUCCESS) {
2360 665456 : return ldb_module_done(ac->req, ares->controls,
2361 : ares->response, ares->error);
2362 : }
2363 :
2364 32608969 : switch (ares->type) {
2365 26643254 : case LDB_REPLY_ENTRY:
2366 26643254 : if (ac->constructed_attrs) {
2367 76 : ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
2368 : acl_attrs,
2369 : DSDB_FLAG_NEXT_MODULE |
2370 : DSDB_FLAG_AS_SYSTEM |
2371 : DSDB_SEARCH_SHOW_RECYCLED,
2372 : req);
2373 76 : if (ret != LDB_SUCCESS) {
2374 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2375 : }
2376 : }
2377 :
2378 26643254 : if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2379 36 : ret = acl_allowedAttributes(ac->module, ac->schema,
2380 22 : acl_res->msgs[0],
2381 : ares->message, ac);
2382 22 : if (ret != LDB_SUCCESS) {
2383 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2384 : }
2385 : }
2386 :
2387 26643254 : if (ac->allowedChildClasses) {
2388 0 : ret = acl_childClasses(ac->module, ac->schema,
2389 0 : acl_res->msgs[0],
2390 : ares->message,
2391 : "allowedChildClasses");
2392 0 : if (ret != LDB_SUCCESS) {
2393 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2394 : }
2395 : }
2396 :
2397 26643254 : if (ac->allowedChildClassesEffective) {
2398 28 : ret = acl_childClassesEffective(ac->module, ac->schema,
2399 18 : acl_res->msgs[0],
2400 : ares->message, ac);
2401 18 : if (ret != LDB_SUCCESS) {
2402 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2403 : }
2404 : }
2405 :
2406 26643254 : if (ac->sDRightsEffective) {
2407 56 : ret = acl_sDRightsEffective(ac->module,
2408 36 : acl_res->msgs[0],
2409 : ares->message, ac);
2410 36 : if (ret != LDB_SUCCESS) {
2411 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2412 : }
2413 : }
2414 :
2415 26643254 : if (data == NULL) {
2416 0 : return ldb_module_send_entry(ac->req, ares->message,
2417 : ares->controls);
2418 : }
2419 :
2420 26643254 : if (ac->am_system) {
2421 0 : return ldb_module_send_entry(ac->req, ares->message,
2422 : ares->controls);
2423 : }
2424 :
2425 26643254 : if (ac->am_administrator) {
2426 9045317 : return ldb_module_send_entry(ac->req, ares->message,
2427 : ares->controls);
2428 : }
2429 :
2430 17597937 : if (data->confidential_attrs != NULL) {
2431 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2432 0 : ldb_msg_remove_attr(ares->message,
2433 0 : data->confidential_attrs[i]);
2434 : }
2435 : }
2436 :
2437 17597937 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2438 :
2439 426385 : case LDB_REPLY_REFERRAL:
2440 426385 : return ldb_module_send_referral(ac->req, ares->referral);
2441 :
2442 5539330 : case LDB_REPLY_DONE:
2443 5539330 : return ldb_module_done(ac->req, ares->controls,
2444 : ares->response, LDB_SUCCESS);
2445 :
2446 : }
2447 0 : return LDB_SUCCESS;
2448 : }
2449 :
2450 20055289 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
2451 : {
2452 : struct ldb_context *ldb;
2453 : struct acl_context *ac;
2454 20055289 : struct ldb_parse_tree *down_tree = req->op.search.tree;
2455 : struct ldb_request *down_req;
2456 : struct acl_private *data;
2457 : int ret;
2458 : unsigned int i;
2459 20055289 : bool modify_search = true;
2460 :
2461 20055289 : if (ldb_dn_is_special(req->op.search.base)) {
2462 737905 : return ldb_next_request(module, req);
2463 : }
2464 :
2465 19317384 : ldb = ldb_module_get_ctx(module);
2466 :
2467 19317384 : ac = talloc_zero(req, struct acl_context);
2468 19317384 : if (ac == NULL) {
2469 0 : return ldb_oom(ldb);
2470 : }
2471 19317384 : data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2472 :
2473 19317384 : ac->module = module;
2474 19317384 : ac->req = req;
2475 19317384 : ac->am_system = dsdb_module_am_system(module);
2476 19317384 : ac->am_administrator = dsdb_module_am_administrator(module);
2477 19317384 : ac->constructed_attrs = false;
2478 19317384 : ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2479 19317384 : ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2480 19317384 : ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2481 19317384 : ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2482 19317384 : ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2483 19317384 : ac->schema = dsdb_get_schema(ldb, ac);
2484 :
2485 19317384 : ac->constructed_attrs |= ac->allowedAttributes;
2486 19317384 : ac->constructed_attrs |= ac->allowedChildClasses;
2487 19317384 : ac->constructed_attrs |= ac->allowedChildClassesEffective;
2488 19317384 : ac->constructed_attrs |= ac->allowedAttributesEffective;
2489 19317384 : ac->constructed_attrs |= ac->sDRightsEffective;
2490 :
2491 19317384 : if (data == NULL) {
2492 0 : modify_search = false;
2493 : }
2494 19317384 : if (ac->am_system) {
2495 13112446 : modify_search = false;
2496 : }
2497 :
2498 19317384 : if (!ac->constructed_attrs && !modify_search) {
2499 13112446 : talloc_free(ac);
2500 13112446 : return ldb_next_request(module, req);
2501 : }
2502 :
2503 6204938 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2504 6204938 : if (data == NULL) {
2505 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2506 : "acl_private data is missing");
2507 : }
2508 :
2509 6204938 : if (!ac->am_system && !ac->am_administrator) {
2510 609924 : ret = acl_search_update_confidential_attrs(ac, data);
2511 609924 : if (ret != LDB_SUCCESS) {
2512 0 : return ret;
2513 : }
2514 :
2515 609924 : if (data->confidential_attrs != NULL) {
2516 0 : down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2517 0 : if (down_tree == NULL) {
2518 0 : return ldb_oom(ldb);
2519 : }
2520 :
2521 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2522 0 : ldb_parse_tree_attr_replace(down_tree,
2523 0 : data->confidential_attrs[i],
2524 : "kludgeACLredactedattribute");
2525 : }
2526 : }
2527 : }
2528 :
2529 6204938 : ret = ldb_build_search_req_ex(&down_req,
2530 : ldb, ac,
2531 : req->op.search.base,
2532 : req->op.search.scope,
2533 : down_tree,
2534 : req->op.search.attrs,
2535 : req->controls,
2536 : ac, acl_search_callback,
2537 : req);
2538 6204938 : LDB_REQ_SET_LOCATION(down_req);
2539 6204938 : if (ret != LDB_SUCCESS) {
2540 0 : return ret;
2541 : }
2542 : /* perform the search */
2543 6204938 : return ldb_next_request(module, down_req);
2544 : }
2545 :
2546 892965 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2547 : {
2548 892965 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2549 892965 : struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2550 :
2551 : /* allow everybody to read the sequence number */
2552 892965 : if (strcmp(req->op.extended.oid,
2553 : LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2554 887885 : return ldb_next_request(module, req);
2555 : }
2556 :
2557 5380 : if (dsdb_module_am_system(module) ||
2558 300 : dsdb_module_am_administrator(module) || as_system) {
2559 5080 : return ldb_next_request(module, req);
2560 : } else {
2561 0 : ldb_asprintf_errstring(ldb,
2562 : "acl_extended: "
2563 : "attempted database modify not permitted. "
2564 : "User %s is not SYSTEM or an administrator",
2565 : acl_user_name(req, module));
2566 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2567 : }
2568 : }
2569 :
2570 : static const struct ldb_module_ops ldb_acl_module_ops = {
2571 : .name = "acl",
2572 : .search = acl_search,
2573 : .add = acl_add,
2574 : .modify = acl_modify,
2575 : .del = acl_delete,
2576 : .rename = acl_rename,
2577 : .extended = acl_extended,
2578 : .init_context = acl_module_init
2579 : };
2580 :
2581 4310 : int ldb_acl_module_init(const char *version)
2582 : {
2583 4310 : LDB_MODULE_CHECK_VERSION(version);
2584 4310 : return ldb_register_module(&ldb_acl_module_ops);
2585 : }
|