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 extended_access_check_attribute {
50 : const char *oa_name;
51 : const uint32_t requires_rights;
52 : };
53 :
54 : struct acl_private {
55 : bool acl_search;
56 : const char **password_attrs;
57 : void *cached_schema_ptr;
58 : uint64_t cached_schema_metadata_usn;
59 : uint64_t cached_schema_loaded_usn;
60 : const char **confidential_attrs;
61 : bool userPassword_support;
62 : };
63 :
64 : struct acl_context {
65 : struct ldb_module *module;
66 : struct ldb_request *req;
67 : bool am_system;
68 : bool am_administrator;
69 : bool modify_search;
70 : bool constructed_attrs;
71 : bool allowedAttributes;
72 : bool allowedAttributesEffective;
73 : bool allowedChildClasses;
74 : bool allowedChildClassesEffective;
75 : bool sDRightsEffective;
76 : bool userPassword;
77 : const char * const *attrs;
78 : struct dsdb_schema *schema;
79 : };
80 :
81 132453 : static int acl_module_init(struct ldb_module *module)
82 : {
83 : struct ldb_context *ldb;
84 : struct acl_private *data;
85 : int ret;
86 : unsigned int i, n, j;
87 : TALLOC_CTX *mem_ctx;
88 : static const char * const attrs[] = { "passwordAttribute", NULL };
89 : static const char * const secret_attrs[] = {
90 : DSDB_SECRET_ATTRIBUTES
91 : };
92 : struct ldb_result *res;
93 : struct ldb_message *msg;
94 : struct ldb_message_element *password_attributes;
95 :
96 132453 : ldb = ldb_module_get_ctx(module);
97 :
98 132453 : ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
99 132453 : if (ret != LDB_SUCCESS) {
100 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
101 : "acl_module_init: Unable to register control with rootdse!\n");
102 0 : return ldb_operr(ldb);
103 : }
104 :
105 132453 : data = talloc_zero(module, struct acl_private);
106 132453 : if (data == NULL) {
107 0 : return ldb_oom(ldb);
108 : }
109 :
110 132453 : data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
111 : NULL, "acl", "search", true);
112 132453 : ldb_module_set_private(module, data);
113 :
114 132453 : mem_ctx = talloc_new(module);
115 132453 : if (!mem_ctx) {
116 0 : return ldb_oom(ldb);
117 : }
118 :
119 132453 : ret = dsdb_module_search_dn(module, mem_ctx, &res,
120 : ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"),
121 : attrs,
122 : DSDB_FLAG_NEXT_MODULE |
123 : DSDB_FLAG_AS_SYSTEM,
124 : NULL);
125 132453 : if (ret != LDB_SUCCESS) {
126 0 : goto done;
127 : }
128 132453 : if (res->count == 0) {
129 0 : goto done;
130 : }
131 :
132 132453 : if (res->count > 1) {
133 0 : talloc_free(mem_ctx);
134 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
135 : }
136 :
137 132453 : msg = res->msgs[0];
138 :
139 132453 : password_attributes = ldb_msg_find_element(msg, "passwordAttribute");
140 132453 : if (!password_attributes) {
141 0 : goto done;
142 : }
143 132453 : data->password_attrs = talloc_array(data, const char *,
144 : password_attributes->num_values +
145 : ARRAY_SIZE(secret_attrs) + 1);
146 132453 : if (!data->password_attrs) {
147 0 : talloc_free(mem_ctx);
148 0 : return ldb_oom(ldb);
149 : }
150 :
151 127712 : n = 0;
152 2776706 : for (i=0; i < password_attributes->num_values; i++) {
153 2648994 : data->password_attrs[n] = (const char *)password_attributes->values[i].data;
154 2648994 : talloc_steal(data->password_attrs, password_attributes->values[i].data);
155 2648994 : n++;
156 : }
157 :
158 1982054 : for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
159 1787968 : bool found = false;
160 :
161 24172525 : for (j=0; j < n; j++) {
162 24238833 : if (strcasecmp(data->password_attrs[j], secret_attrs[i]) == 0) {
163 1787918 : found = true;
164 1787918 : break;
165 : }
166 : }
167 :
168 1854342 : if (found) {
169 1854276 : continue;
170 : }
171 :
172 66 : data->password_attrs[n] = talloc_strdup(data->password_attrs,
173 0 : secret_attrs[i]);
174 66 : if (data->password_attrs[n] == NULL) {
175 0 : talloc_free(mem_ctx);
176 0 : return ldb_oom(ldb);
177 : }
178 66 : n++;
179 : }
180 132453 : data->password_attrs[n] = NULL;
181 :
182 132453 : done:
183 132453 : talloc_free(mem_ctx);
184 132453 : ret = ldb_next_init(module);
185 :
186 132453 : if (ret != LDB_SUCCESS) {
187 0 : return ret;
188 : }
189 :
190 : /*
191 : * Check this after the modules have be initialised so we
192 : * can actually read the backend DB.
193 : */
194 : data->userPassword_support
195 132453 : = dsdb_user_password_support(module,
196 : module,
197 : NULL);
198 132453 : return ret;
199 : }
200 :
201 22 : static int acl_allowedAttributes(struct ldb_module *module,
202 : const struct dsdb_schema *schema,
203 : struct ldb_message *sd_msg,
204 : struct ldb_message *msg,
205 : struct acl_context *ac)
206 : {
207 : struct ldb_message_element *oc_el;
208 22 : struct ldb_context *ldb = ldb_module_get_ctx(module);
209 : TALLOC_CTX *mem_ctx;
210 : const char **attr_list;
211 : int i, ret;
212 : const struct dsdb_class *objectclass;
213 :
214 : /* If we don't have a schema yet, we can't do anything... */
215 22 : if (schema == NULL) {
216 0 : ldb_asprintf_errstring(ldb, "cannot add allowedAttributes to %s because no schema is loaded", ldb_dn_get_linearized(msg->dn));
217 0 : return LDB_ERR_OPERATIONS_ERROR;
218 : }
219 :
220 : /* Must remove any existing attribute */
221 22 : if (ac->allowedAttributes) {
222 4 : ldb_msg_remove_attr(msg, "allowedAttributes");
223 : }
224 :
225 22 : mem_ctx = talloc_new(msg);
226 22 : if (!mem_ctx) {
227 0 : return ldb_oom(ldb);
228 : }
229 :
230 22 : oc_el = ldb_msg_find_element(sd_msg, "objectClass");
231 22 : attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL);
232 22 : if (!attr_list) {
233 0 : ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes");
234 0 : talloc_free(mem_ctx);
235 0 : return LDB_ERR_OPERATIONS_ERROR;
236 : }
237 :
238 : /*
239 : * Get the top-most structural object class for the ACL check
240 : */
241 22 : objectclass = dsdb_get_last_structural_class(ac->schema,
242 : oc_el);
243 22 : if (objectclass == NULL) {
244 0 : ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s",
245 : ldb_dn_get_linearized(sd_msg->dn));
246 0 : talloc_free(mem_ctx);
247 0 : return LDB_ERR_OPERATIONS_ERROR;
248 : }
249 :
250 22 : if (ac->allowedAttributes) {
251 938 : for (i=0; attr_list && attr_list[i]; i++) {
252 934 : ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]);
253 : }
254 : }
255 22 : if (ac->allowedAttributesEffective) {
256 : struct security_descriptor *sd;
257 22 : struct dom_sid *sid = NULL;
258 22 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
259 : LDB_CONTROL_AS_SYSTEM_OID);
260 :
261 22 : if (as_system != NULL) {
262 0 : as_system->critical = 0;
263 : }
264 :
265 22 : ldb_msg_remove_attr(msg, "allowedAttributesEffective");
266 22 : if (ac->am_system || as_system) {
267 0 : for (i=0; attr_list && attr_list[i]; i++) {
268 0 : ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
269 : }
270 0 : return LDB_SUCCESS;
271 : }
272 :
273 22 : ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), mem_ctx, sd_msg, &sd);
274 :
275 22 : if (ret != LDB_SUCCESS) {
276 0 : return ret;
277 : }
278 :
279 22 : sid = samdb_result_dom_sid(mem_ctx, sd_msg, "objectSid");
280 3568 : for (i=0; attr_list && attr_list[i]; i++) {
281 3546 : const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
282 3546 : attr_list[i]);
283 3546 : if (!attr) {
284 0 : return ldb_operr(ldb);
285 : }
286 : /* remove constructed attributes */
287 3546 : if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED
288 3016 : || attr->systemOnly
289 1685 : || (attr->linkID != 0 && attr->linkID % 2 != 0 )) {
290 1989 : continue;
291 : }
292 1557 : ret = acl_check_access_on_attribute(module,
293 : msg,
294 : sd,
295 : sid,
296 : SEC_ADS_WRITE_PROP,
297 : attr,
298 : objectclass);
299 1557 : if (ret == LDB_SUCCESS) {
300 531 : ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]);
301 : }
302 : }
303 : }
304 22 : return LDB_SUCCESS;
305 : }
306 :
307 0 : static int acl_childClasses(struct ldb_module *module,
308 : const struct dsdb_schema *schema,
309 : struct ldb_message *sd_msg,
310 : struct ldb_message *msg,
311 : const char *attrName)
312 : {
313 : struct ldb_message_element *oc_el;
314 : struct ldb_message_element *allowedClasses;
315 : const struct dsdb_class *sclass;
316 : unsigned int i, j;
317 : int ret;
318 :
319 : /* If we don't have a schema yet, we can't do anything... */
320 0 : if (schema == NULL) {
321 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));
322 0 : return LDB_ERR_OPERATIONS_ERROR;
323 : }
324 :
325 : /* Must remove any existing attribute, or else confusion reins */
326 0 : ldb_msg_remove_attr(msg, attrName);
327 0 : ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses);
328 0 : if (ret != LDB_SUCCESS) {
329 0 : return ret;
330 : }
331 :
332 0 : oc_el = ldb_msg_find_element(sd_msg, "objectClass");
333 :
334 0 : for (i=0; oc_el && i < oc_el->num_values; i++) {
335 0 : sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
336 0 : if (!sclass) {
337 : /* We don't know this class? what is going on? */
338 0 : continue;
339 : }
340 :
341 0 : for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
342 0 : ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]);
343 : }
344 : }
345 0 : if (allowedClasses->num_values > 1) {
346 0 : TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
347 0 : for (i=1 ; i < allowedClasses->num_values; i++) {
348 0 : struct ldb_val *val1 = &allowedClasses->values[i-1];
349 0 : struct ldb_val *val2 = &allowedClasses->values[i];
350 0 : if (data_blob_cmp(val1, val2) == 0) {
351 0 : memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val));
352 0 : allowedClasses->num_values--;
353 0 : i--;
354 : }
355 : }
356 : }
357 :
358 0 : return LDB_SUCCESS;
359 : }
360 :
361 18 : static int acl_childClassesEffective(struct ldb_module *module,
362 : const struct dsdb_schema *schema,
363 : struct ldb_message *sd_msg,
364 : struct ldb_message *msg,
365 : struct acl_context *ac)
366 : {
367 : struct ldb_message_element *oc_el;
368 18 : struct ldb_message_element *allowedClasses = NULL;
369 : const struct dsdb_class *sclass;
370 : struct security_descriptor *sd;
371 18 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
372 : LDB_CONTROL_AS_SYSTEM_OID);
373 18 : struct dom_sid *sid = NULL;
374 : unsigned int i, j;
375 : int ret;
376 :
377 18 : if (as_system != NULL) {
378 0 : as_system->critical = 0;
379 : }
380 :
381 18 : if (ac->am_system || as_system) {
382 0 : return acl_childClasses(module, schema, sd_msg, msg, "allowedChildClassesEffective");
383 : }
384 :
385 : /* If we don't have a schema yet, we can't do anything... */
386 18 : if (schema == NULL) {
387 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));
388 0 : return LDB_ERR_OPERATIONS_ERROR;
389 : }
390 :
391 : /* Must remove any existing attribute, or else confusion reins */
392 18 : ldb_msg_remove_attr(msg, "allowedChildClassesEffective");
393 :
394 18 : oc_el = ldb_msg_find_element(sd_msg, "objectClass");
395 18 : ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
396 18 : if (ret != LDB_SUCCESS) {
397 0 : return ret;
398 : }
399 :
400 18 : sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
401 54 : for (i=0; oc_el && i < oc_el->num_values; i++) {
402 36 : sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]);
403 36 : if (!sclass) {
404 : /* We don't know this class? what is going on? */
405 0 : continue;
406 : }
407 :
408 1698 : for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) {
409 : const struct dsdb_class *sc;
410 :
411 1662 : sc = dsdb_class_by_lDAPDisplayName(schema,
412 1662 : sclass->possibleInferiors[j]);
413 1662 : if (!sc) {
414 : /* We don't know this class? what is going on? */
415 0 : continue;
416 : }
417 :
418 1662 : ret = acl_check_access_on_objectclass(module, ac,
419 : sd, sid,
420 : SEC_ADS_CREATE_CHILD,
421 : sc);
422 1662 : if (ret == LDB_SUCCESS) {
423 9 : ldb_msg_add_string(msg, "allowedChildClassesEffective",
424 9 : sclass->possibleInferiors[j]);
425 : }
426 : }
427 : }
428 18 : allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective");
429 18 : if (!allowedClasses) {
430 9 : return LDB_SUCCESS;
431 : }
432 :
433 9 : if (allowedClasses->num_values > 1) {
434 0 : TYPESAFE_QSORT(allowedClasses->values, allowedClasses->num_values, data_blob_cmp);
435 0 : for (i=1 ; i < allowedClasses->num_values; i++) {
436 0 : struct ldb_val *val1 = &allowedClasses->values[i-1];
437 0 : struct ldb_val *val2 = &allowedClasses->values[i];
438 0 : if (data_blob_cmp(val1, val2) == 0) {
439 0 : memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val));
440 0 : allowedClasses->num_values--;
441 0 : i--;
442 : }
443 : }
444 : }
445 9 : return LDB_SUCCESS;
446 : }
447 :
448 36 : static int acl_sDRightsEffective(struct ldb_module *module,
449 : struct ldb_message *sd_msg,
450 : struct ldb_message *msg,
451 : struct acl_context *ac)
452 : {
453 36 : struct ldb_context *ldb = ldb_module_get_ctx(module);
454 : struct ldb_message_element *rightsEffective;
455 : int ret;
456 : struct security_descriptor *sd;
457 36 : struct ldb_control *as_system = ldb_request_get_control(ac->req,
458 : LDB_CONTROL_AS_SYSTEM_OID);
459 36 : struct dom_sid *sid = NULL;
460 36 : uint32_t flags = 0;
461 :
462 36 : if (as_system != NULL) {
463 0 : as_system->critical = 0;
464 : }
465 :
466 : /* Must remove any existing attribute, or else confusion reins */
467 36 : ldb_msg_remove_attr(msg, "sDRightsEffective");
468 36 : ret = ldb_msg_add_empty(msg, "sDRightsEffective", 0, &rightsEffective);
469 36 : if (ret != LDB_SUCCESS) {
470 0 : return ret;
471 : }
472 36 : if (ac->am_system || as_system) {
473 0 : flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL;
474 : } else {
475 : const struct dsdb_class *objectclass;
476 : const struct dsdb_attribute *attr;
477 :
478 36 : objectclass = dsdb_get_structural_oc_from_msg(ac->schema, sd_msg);
479 36 : if (objectclass == NULL) {
480 0 : return ldb_operr(ldb);
481 : }
482 :
483 36 : attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
484 : "nTSecurityDescriptor");
485 36 : if (attr == NULL) {
486 0 : return ldb_operr(ldb);
487 : }
488 :
489 : /* Get the security descriptor from the message */
490 36 : ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
491 36 : if (ret != LDB_SUCCESS) {
492 0 : return ret;
493 : }
494 36 : sid = samdb_result_dom_sid(msg, sd_msg, "objectSid");
495 36 : ret = acl_check_access_on_attribute(module,
496 : msg,
497 : sd,
498 : sid,
499 : SEC_STD_WRITE_OWNER,
500 : attr,
501 : objectclass);
502 36 : if (ret == LDB_SUCCESS) {
503 18 : flags |= SECINFO_OWNER | SECINFO_GROUP;
504 : }
505 36 : ret = acl_check_access_on_attribute(module,
506 : msg,
507 : sd,
508 : sid,
509 : SEC_STD_WRITE_DAC,
510 : attr,
511 : objectclass);
512 36 : if (ret == LDB_SUCCESS) {
513 27 : flags |= SECINFO_DACL;
514 : }
515 36 : ret = acl_check_access_on_attribute(module,
516 : msg,
517 : sd,
518 : sid,
519 : SEC_FLAG_SYSTEM_SECURITY,
520 : attr,
521 : objectclass);
522 36 : if (ret == LDB_SUCCESS) {
523 9 : flags |= SECINFO_SACL;
524 : }
525 : }
526 36 : return samdb_msg_add_uint(ldb_module_get_ctx(module), msg, msg,
527 : "sDRightsEffective", flags);
528 : }
529 :
530 484 : static int acl_validate_spn_value(TALLOC_CTX *mem_ctx,
531 : struct ldb_context *ldb,
532 : const char *spn_value,
533 : uint32_t userAccountControl,
534 : const char *samAccountName,
535 : const char *dnsHostName,
536 : const char *netbios_name,
537 : const char *ntds_guid)
538 : {
539 : int ret, princ_size;
540 : krb5_context krb_ctx;
541 : krb5_error_code kerr;
542 : krb5_principal principal;
543 : char *instanceName;
544 : char *serviceType;
545 : char *serviceName;
546 484 : const char *forest_name = samdb_forest_name(ldb, mem_ctx);
547 484 : const char *base_domain = samdb_default_domain_name(ldb, mem_ctx);
548 484 : struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
549 : struct loadparm_context);
550 770 : bool is_dc = (userAccountControl & UF_SERVER_TRUST_ACCOUNT) ||
551 286 : (userAccountControl & UF_PARTIAL_SECRETS_ACCOUNT);
552 :
553 484 : if (strcasecmp_m(spn_value, samAccountName) == 0) {
554 : /* MacOS X sets this value, and setting an SPN of your
555 : * own samAccountName is both pointless and safe */
556 0 : return LDB_SUCCESS;
557 : }
558 :
559 484 : kerr = smb_krb5_init_context_basic(mem_ctx,
560 : lp_ctx,
561 : &krb_ctx);
562 484 : if (kerr != 0) {
563 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
564 : "Could not initialize kerberos context.");
565 : }
566 :
567 484 : ret = krb5_parse_name(krb_ctx, spn_value, &principal);
568 484 : if (ret) {
569 0 : krb5_free_context(krb_ctx);
570 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
571 : }
572 :
573 484 : princ_size = krb5_princ_size(krb_ctx, principal);
574 484 : if (princ_size < 2) {
575 0 : DBG_WARNING("princ_size=%d\n", princ_size);
576 0 : goto fail;
577 : }
578 :
579 484 : instanceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
580 : principal, 1);
581 484 : serviceType = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
582 : principal, 0);
583 484 : if (krb5_princ_size(krb_ctx, principal) == 3) {
584 391 : serviceName = smb_krb5_principal_get_comp_string(mem_ctx, krb_ctx,
585 : principal, 2);
586 : } else {
587 93 : serviceName = NULL;
588 : }
589 :
590 484 : if (serviceName) {
591 391 : if (!is_dc) {
592 63 : DBG_WARNING("is_dc=false, serviceName=%s,"
593 : "serviceType=%s\n", serviceName,
594 : serviceType);
595 63 : goto fail;
596 : }
597 328 : if (strcasecmp(serviceType, "ldap") == 0) {
598 151 : if (strcasecmp(serviceName, netbios_name) != 0 &&
599 73 : strcasecmp(serviceName, forest_name) != 0) {
600 36 : DBG_WARNING("serviceName=%s\n", serviceName);
601 36 : goto fail;
602 : }
603 :
604 218 : } else if (strcasecmp(serviceType, "gc") == 0) {
605 36 : if (strcasecmp(serviceName, forest_name) != 0) {
606 18 : DBG_WARNING("serviceName=%s\n", serviceName);
607 18 : goto fail;
608 : }
609 : } else {
610 213 : if (strcasecmp(serviceName, base_domain) != 0 &&
611 55 : strcasecmp(serviceName, netbios_name) != 0) {
612 18 : DBG_WARNING("serviceType=%s, "
613 : "serviceName=%s\n",
614 : serviceType, serviceName);
615 18 : goto fail;
616 : }
617 : }
618 : }
619 : /* instanceName can be samAccountName without $ or dnsHostName
620 : * or "ntds_guid._msdcs.forest_domain for DC objects */
621 349 : if (strlen(instanceName) == (strlen(samAccountName) - 1)
622 208 : && strncasecmp(instanceName, samAccountName,
623 208 : strlen(samAccountName) - 1) == 0) {
624 208 : goto success;
625 : }
626 222 : if ((dnsHostName != NULL) &&
627 141 : (strcasecmp(instanceName, dnsHostName) == 0)) {
628 104 : goto success;
629 : }
630 37 : if (is_dc) {
631 : const char *guid_str;
632 37 : guid_str = talloc_asprintf(mem_ctx,"%s._msdcs.%s",
633 : ntds_guid,
634 : forest_name);
635 37 : if (strcasecmp(instanceName, guid_str) == 0) {
636 19 : goto success;
637 : }
638 : }
639 :
640 18 : fail:
641 153 : krb5_free_principal(krb_ctx, principal);
642 153 : krb5_free_context(krb_ctx);
643 153 : ldb_debug_set(ldb, LDB_DEBUG_WARNING,
644 : "acl: spn validation failed for "
645 : "spn[%s] uac[0x%x] account[%s] hostname[%s] "
646 : "nbname[%s] ntds[%s] forest[%s] domain[%s]\n",
647 : spn_value, (unsigned)userAccountControl,
648 : samAccountName, dnsHostName,
649 : netbios_name, ntds_guid,
650 : forest_name, base_domain);
651 153 : return LDB_ERR_CONSTRAINT_VIOLATION;
652 :
653 331 : success:
654 331 : krb5_free_principal(krb_ctx, principal);
655 331 : krb5_free_context(krb_ctx);
656 331 : return LDB_SUCCESS;
657 : }
658 :
659 1388 : static int acl_check_spn(TALLOC_CTX *mem_ctx,
660 : struct ldb_module *module,
661 : struct ldb_request *req,
662 : struct security_descriptor *sd,
663 : struct dom_sid *sid,
664 : const struct dsdb_attribute *attr,
665 : const struct dsdb_class *objectclass)
666 : {
667 : int ret;
668 : unsigned int i;
669 1388 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
670 1388 : struct ldb_context *ldb = ldb_module_get_ctx(module);
671 : struct ldb_result *acl_res;
672 : struct ldb_result *netbios_res;
673 : struct ldb_message_element *el;
674 1388 : struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
675 : uint32_t userAccountControl;
676 : const char *samAccountName;
677 : const char *dnsHostName;
678 : const char *netbios_name;
679 : struct GUID ntds;
680 1388 : char *ntds_guid = NULL;
681 :
682 : static const char *acl_attrs[] = {
683 : "samAccountName",
684 : "dnsHostName",
685 : "userAccountControl",
686 : NULL
687 : };
688 : static const char *netbios_attrs[] = {
689 : "nETBIOSName",
690 : NULL
691 : };
692 :
693 : /* if we have wp, we can do whatever we like */
694 1388 : if (acl_check_access_on_attribute(module,
695 : tmp_ctx,
696 : sd,
697 : sid,
698 : SEC_ADS_WRITE_PROP,
699 : attr, objectclass) == LDB_SUCCESS) {
700 883 : talloc_free(tmp_ctx);
701 883 : return LDB_SUCCESS;
702 : }
703 :
704 505 : ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
705 : GUID_DRS_VALIDATE_SPN,
706 : SEC_ADS_SELF_WRITE,
707 : sid);
708 :
709 505 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
710 27 : dsdb_acl_debug(sd, acl_user_token(module),
711 27 : req->op.mod.message->dn,
712 : true,
713 : 10);
714 27 : talloc_free(tmp_ctx);
715 27 : return ret;
716 : }
717 :
718 478 : ret = dsdb_module_search_dn(module, tmp_ctx,
719 478 : &acl_res, req->op.mod.message->dn,
720 : acl_attrs,
721 : DSDB_FLAG_NEXT_MODULE |
722 : DSDB_FLAG_AS_SYSTEM |
723 : DSDB_SEARCH_SHOW_RECYCLED,
724 : req);
725 478 : if (ret != LDB_SUCCESS) {
726 0 : talloc_free(tmp_ctx);
727 0 : return ret;
728 : }
729 :
730 478 : userAccountControl = ldb_msg_find_attr_as_uint(acl_res->msgs[0], "userAccountControl", 0);
731 478 : dnsHostName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "dnsHostName", NULL);
732 478 : samAccountName = ldb_msg_find_attr_as_string(acl_res->msgs[0], "samAccountName", NULL);
733 :
734 478 : ret = dsdb_module_search(module, tmp_ctx,
735 : &netbios_res, partitions_dn,
736 : LDB_SCOPE_ONELEVEL,
737 : netbios_attrs,
738 : DSDB_FLAG_NEXT_MODULE |
739 : DSDB_FLAG_AS_SYSTEM,
740 : req,
741 : "(ncName=%s)",
742 : ldb_dn_get_linearized(ldb_get_default_basedn(ldb)));
743 :
744 478 : netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
745 :
746 478 : el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName");
747 478 : if (!el) {
748 0 : talloc_free(tmp_ctx);
749 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
750 : "Error finding element for servicePrincipalName.");
751 : }
752 :
753 : /* NTDSDSA objectGuid of object we are checking SPN for */
754 478 : if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
755 397 : ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
756 397 : req->op.mod.message->dn, &ntds, req);
757 397 : if (ret != LDB_SUCCESS) {
758 0 : ldb_asprintf_errstring(ldb, "Failed to find NTDSDSA objectGuid for %s: %s",
759 0 : ldb_dn_get_linearized(req->op.mod.message->dn),
760 : ldb_strerror(ret));
761 0 : talloc_free(tmp_ctx);
762 0 : return LDB_ERR_OPERATIONS_ERROR;
763 : }
764 397 : ntds_guid = GUID_string(tmp_ctx, &ntds);
765 : }
766 :
767 809 : for (i=0; i < el->num_values; i++) {
768 484 : ret = acl_validate_spn_value(tmp_ctx,
769 : ldb,
770 484 : (char *)el->values[i].data,
771 : userAccountControl,
772 : samAccountName,
773 : dnsHostName,
774 : netbios_name,
775 : ntds_guid);
776 484 : if (ret != LDB_SUCCESS) {
777 153 : talloc_free(tmp_ctx);
778 153 : return ret;
779 : }
780 : }
781 325 : talloc_free(tmp_ctx);
782 325 : return LDB_SUCCESS;
783 : }
784 :
785 490186 : static int acl_add(struct ldb_module *module, struct ldb_request *req)
786 : {
787 : int ret;
788 : struct ldb_dn *parent;
789 : struct ldb_context *ldb;
790 : const struct dsdb_schema *schema;
791 : const struct dsdb_class *objectclass;
792 : struct ldb_control *as_system;
793 : struct ldb_message_element *el;
794 490186 : unsigned int instanceType = 0;
795 :
796 490186 : if (ldb_dn_is_special(req->op.add.message->dn)) {
797 508 : return ldb_next_request(module, req);
798 : }
799 :
800 489678 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
801 489678 : if (as_system != NULL) {
802 85 : as_system->critical = 0;
803 : }
804 :
805 489678 : if (dsdb_module_am_system(module) || as_system) {
806 4047 : return ldb_next_request(module, req);
807 : }
808 :
809 485631 : ldb = ldb_module_get_ctx(module);
810 :
811 485631 : parent = ldb_dn_get_parent(req, req->op.add.message->dn);
812 485631 : if (parent == NULL) {
813 0 : return ldb_oom(ldb);
814 : }
815 :
816 485631 : schema = dsdb_get_schema(ldb, req);
817 485631 : if (!schema) {
818 0 : return ldb_operr(ldb);
819 : }
820 :
821 485631 : objectclass = dsdb_get_structural_oc_from_msg(schema, req->op.add.message);
822 485631 : if (!objectclass) {
823 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
824 : "acl: unable to find or validate structural objectClass on %s\n",
825 0 : ldb_dn_get_linearized(req->op.add.message->dn));
826 0 : return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
827 : }
828 :
829 485631 : el = ldb_msg_find_element(req->op.add.message, "instanceType");
830 485631 : if ((el != NULL) && (el->num_values != 1)) {
831 1 : ldb_set_errstring(ldb, "acl: the 'instanceType' attribute is single-valued!");
832 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
833 : }
834 :
835 485630 : instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
836 : "instanceType", 0);
837 485630 : if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
838 : static const char *no_attrs[] = { NULL };
839 : struct ldb_result *partition_res;
840 : struct ldb_dn *partitions_dn;
841 :
842 579 : partitions_dn = samdb_partitions_dn(ldb, req);
843 579 : if (!partitions_dn) {
844 0 : ldb_set_errstring(ldb, "acl: CN=partitions dn could not be generated!");
845 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
846 : }
847 :
848 579 : ret = dsdb_module_search(module, req, &partition_res,
849 : partitions_dn, LDB_SCOPE_ONELEVEL,
850 : no_attrs,
851 : DSDB_FLAG_NEXT_MODULE |
852 : DSDB_FLAG_AS_SYSTEM |
853 : DSDB_SEARCH_ONE_ONLY |
854 : DSDB_SEARCH_SHOW_RECYCLED,
855 : req,
856 : "(&(nCName=%s)(objectClass=crossRef))",
857 579 : ldb_dn_get_linearized(req->op.add.message->dn));
858 :
859 579 : if (ret == LDB_SUCCESS) {
860 : /* Check that we can write to the crossRef object MS-ADTS 3.1.1.5.2.8.2 */
861 0 : ret = dsdb_module_check_access_on_dn(module, req, partition_res->msgs[0]->dn,
862 : SEC_ADS_WRITE_PROP,
863 : &objectclass->schemaIDGUID, req);
864 0 : if (ret != LDB_SUCCESS) {
865 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
866 : "acl: ACL check failed on crossRef object %s: %s\n",
867 0 : ldb_dn_get_linearized(partition_res->msgs[0]->dn),
868 : ldb_errstring(ldb));
869 0 : return ret;
870 : }
871 :
872 : /*
873 : * TODO: Remaining checks, like if we are
874 : * the naming master etc need to be handled
875 : * in the instanceType module
876 : */
877 0 : return ldb_next_request(module, req);
878 : }
879 :
880 : /* Check that we can create a crossRef object MS-ADTS 3.1.1.5.2.8.2 */
881 579 : ret = dsdb_module_check_access_on_dn(module, req, partitions_dn,
882 : SEC_ADS_CREATE_CHILD,
883 : &objectclass->schemaIDGUID, req);
884 942 : if (ret == LDB_ERR_NO_SUCH_OBJECT &&
885 363 : ldb_request_get_control(req, LDB_CONTROL_RELAX_OID))
886 : {
887 : /* Allow provision bootstrap */
888 300 : ret = LDB_SUCCESS;
889 : }
890 516 : if (ret != LDB_SUCCESS) {
891 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
892 : "acl: ACL check failed on CN=Partitions crossRef container %s: %s\n",
893 : ldb_dn_get_linearized(partitions_dn), ldb_errstring(ldb));
894 0 : return ret;
895 : }
896 :
897 : /*
898 : * TODO: Remaining checks, like if we are the naming
899 : * master and adding the crossRef object need to be
900 : * handled in the instanceType module
901 : */
902 579 : return ldb_next_request(module, req);
903 : }
904 :
905 485051 : ret = dsdb_module_check_access_on_dn(module, req, parent,
906 : SEC_ADS_CREATE_CHILD,
907 : &objectclass->schemaIDGUID, req);
908 485051 : if (ret != LDB_SUCCESS) {
909 26 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
910 : "acl: unable to get access to %s\n",
911 26 : ldb_dn_get_linearized(req->op.add.message->dn));
912 26 : return ret;
913 : }
914 485025 : return ldb_next_request(module, req);
915 : }
916 :
917 : /* ckecks if modifications are allowed on "Member" attribute */
918 6219 : static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
919 : struct ldb_module *module,
920 : struct ldb_request *req,
921 : struct security_descriptor *sd,
922 : struct dom_sid *sid,
923 : const struct dsdb_attribute *attr,
924 : const struct dsdb_class *objectclass)
925 : {
926 : int ret;
927 : unsigned int i;
928 6219 : struct ldb_context *ldb = ldb_module_get_ctx(module);
929 : struct ldb_dn *user_dn;
930 : struct ldb_message_element *member_el;
931 : /* if we have wp, we can do whatever we like */
932 6219 : if (acl_check_access_on_attribute(module,
933 : mem_ctx,
934 : sd,
935 : sid,
936 : SEC_ADS_WRITE_PROP,
937 : attr, objectclass) == LDB_SUCCESS) {
938 6159 : return LDB_SUCCESS;
939 : }
940 : /* if we are adding/deleting ourselves, check for self membership */
941 60 : ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
942 60 : &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
943 : &user_dn);
944 60 : if (ret != LDB_SUCCESS) {
945 0 : return ret;
946 : }
947 60 : member_el = ldb_msg_find_element(req->op.mod.message, "member");
948 60 : if (!member_el) {
949 0 : return ldb_operr(ldb);
950 : }
951 : /* user can only remove oneself */
952 60 : if (member_el->num_values == 0) {
953 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
954 : }
955 87 : for (i = 0; i < member_el->num_values; i++) {
956 118 : if (strcasecmp((const char *)member_el->values[i].data,
957 69 : ldb_dn_get_extended_linearized(mem_ctx, user_dn, 1)) != 0) {
958 42 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
959 : }
960 : }
961 18 : ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
962 : GUID_DRS_SELF_MEMBERSHIP,
963 : SEC_ADS_SELF_WRITE,
964 : sid);
965 18 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
966 9 : dsdb_acl_debug(sd, acl_user_token(module),
967 9 : req->op.mod.message->dn,
968 : true,
969 : 10);
970 : }
971 18 : return ret;
972 : }
973 :
974 11388 : static int acl_check_password_rights(
975 : TALLOC_CTX *mem_ctx,
976 : struct ldb_module *module,
977 : struct ldb_request *req,
978 : struct security_descriptor *sd,
979 : struct dom_sid *sid,
980 : const struct dsdb_class *objectclass,
981 : bool userPassword,
982 : struct dsdb_control_password_acl_validation **control_for_response)
983 : {
984 11388 : int ret = LDB_SUCCESS;
985 11388 : unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0;
986 11388 : unsigned int del_val_cnt = 0, add_val_cnt = 0, rep_val_cnt = 0;
987 : struct ldb_message_element *el;
988 : struct ldb_message *msg;
989 11388 : struct ldb_control *c = NULL;
990 11388 : const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
991 : "unicodePwd", NULL }, **l;
992 11388 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
993 11388 : struct dsdb_control_password_acl_validation *pav = NULL;
994 :
995 11388 : if (tmp_ctx == NULL) {
996 0 : return LDB_ERR_OPERATIONS_ERROR;
997 : }
998 :
999 11388 : pav = talloc_zero(req, struct dsdb_control_password_acl_validation);
1000 11388 : if (pav == NULL) {
1001 0 : talloc_free(tmp_ctx);
1002 0 : return LDB_ERR_OPERATIONS_ERROR;
1003 : }
1004 : /*
1005 : * Set control_for_response to pav so it can be added to the response
1006 : * and be passed up to the audit_log module which uses it to identify
1007 : * password reset attempts.
1008 : */
1009 11388 : *control_for_response = pav;
1010 :
1011 11388 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OID);
1012 11388 : if (c != NULL) {
1013 189 : pav->pwd_reset = false;
1014 :
1015 : /*
1016 : * The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
1017 : * have a user password change and not a set as the message
1018 : * looks like. In it's value blob it contains the NT and/or LM
1019 : * hash of the old password specified by the user. This control
1020 : * is used by the SAMR and "kpasswd" password change mechanisms.
1021 : *
1022 : * This control can't be used by real LDAP clients,
1023 : * the only caller is samdb_set_password_internal(),
1024 : * so we don't have to strict verification of the input.
1025 : */
1026 189 : ret = acl_check_extended_right(tmp_ctx,
1027 : sd,
1028 : acl_user_token(module),
1029 : GUID_DRS_USER_CHANGE_PASSWORD,
1030 : SEC_ADS_CONTROL_ACCESS,
1031 : sid);
1032 189 : goto checked;
1033 : }
1034 :
1035 11199 : c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
1036 11199 : if (c != NULL) {
1037 258 : pav->pwd_reset = true;
1038 :
1039 : /*
1040 : * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without
1041 : * "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we
1042 : * have a force password set.
1043 : * This control is used by the SAMR/NETLOGON/LSA password
1044 : * reset mechanisms.
1045 : *
1046 : * This control can't be used by real LDAP clients,
1047 : * the only caller is samdb_set_password_internal(),
1048 : * so we don't have to strict verification of the input.
1049 : */
1050 258 : ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1051 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1052 : SEC_ADS_CONTROL_ACCESS,
1053 : sid);
1054 258 : goto checked;
1055 : }
1056 :
1057 10941 : el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
1058 10941 : if (el != NULL) {
1059 : /*
1060 : * dBCSPwd is only allowed with a control.
1061 : */
1062 0 : talloc_free(tmp_ctx);
1063 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1064 : }
1065 :
1066 10941 : msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message);
1067 10941 : if (msg == NULL) {
1068 0 : return ldb_module_oom(module);
1069 : }
1070 43692 : for (l = passwordAttrs; *l != NULL; l++) {
1071 32823 : if ((!userPassword) && (ldb_attr_cmp(*l, "userPassword") == 0)) {
1072 8880 : continue;
1073 : }
1074 :
1075 51386 : while ((el = ldb_msg_find_element(msg, *l)) != NULL) {
1076 12329 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1077 1395 : ++del_attr_cnt;
1078 1395 : del_val_cnt += el->num_values;
1079 : }
1080 12329 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
1081 1363 : ++add_attr_cnt;
1082 1363 : add_val_cnt += el->num_values;
1083 : }
1084 12329 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1085 9571 : ++rep_attr_cnt;
1086 9571 : rep_val_cnt += el->num_values;
1087 : }
1088 12329 : ldb_msg_remove_element(msg, el);
1089 : }
1090 : }
1091 :
1092 : /* single deletes will be handled by the "password_hash" LDB module
1093 : * later in the stack, so we let it though here */
1094 10941 : if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) {
1095 49 : talloc_free(tmp_ctx);
1096 49 : return LDB_SUCCESS;
1097 : }
1098 :
1099 :
1100 10892 : if (rep_attr_cnt > 0) {
1101 9557 : pav->pwd_reset = true;
1102 :
1103 9557 : ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1104 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1105 : SEC_ADS_CONTROL_ACCESS,
1106 : sid);
1107 9557 : goto checked;
1108 : }
1109 :
1110 1335 : if (add_attr_cnt != del_attr_cnt) {
1111 81 : pav->pwd_reset = true;
1112 :
1113 81 : ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1114 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1115 : SEC_ADS_CONTROL_ACCESS,
1116 : sid);
1117 81 : goto checked;
1118 : }
1119 :
1120 1254 : if (add_val_cnt == 1 && del_val_cnt == 1) {
1121 787 : pav->pwd_reset = false;
1122 :
1123 787 : ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1124 : GUID_DRS_USER_CHANGE_PASSWORD,
1125 : SEC_ADS_CONTROL_ACCESS,
1126 : sid);
1127 : /* Very strange, but we get constraint violation in this case */
1128 787 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1129 18 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1130 : }
1131 787 : goto checked;
1132 : }
1133 :
1134 467 : if (add_val_cnt == 1 && del_val_cnt == 0) {
1135 313 : pav->pwd_reset = true;
1136 :
1137 313 : ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
1138 : GUID_DRS_FORCE_CHANGE_PASSWORD,
1139 : SEC_ADS_CONTROL_ACCESS,
1140 : sid);
1141 : /* Very strange, but we get constraint violation in this case */
1142 313 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
1143 21 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
1144 : }
1145 313 : goto checked;
1146 : }
1147 :
1148 : /*
1149 : * Everything else is handled by the password_hash module where it will
1150 : * fail, but with the correct error code when the module is again
1151 : * checking the attributes. As the change request will lack the
1152 : * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that
1153 : * any modification attempt that went this way will be rejected.
1154 : */
1155 :
1156 154 : talloc_free(tmp_ctx);
1157 154 : return LDB_SUCCESS;
1158 :
1159 11185 : checked:
1160 11185 : if (ret != LDB_SUCCESS) {
1161 126 : dsdb_acl_debug(sd, acl_user_token(module),
1162 126 : req->op.mod.message->dn,
1163 : true,
1164 : 10);
1165 126 : talloc_free(tmp_ctx);
1166 126 : return ret;
1167 : }
1168 :
1169 11059 : ret = ldb_request_add_control(req,
1170 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav);
1171 11059 : if (ret != LDB_SUCCESS) {
1172 0 : ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1173 : "Unable to register ACL validation control!\n");
1174 0 : return ret;
1175 : }
1176 10987 : return LDB_SUCCESS;
1177 : }
1178 :
1179 : /*
1180 : * Context needed by acl_callback
1181 : */
1182 : struct acl_callback_context {
1183 : struct ldb_request *request;
1184 : struct ldb_module *module;
1185 : };
1186 :
1187 : /*
1188 : * @brief Copy the password validation control to the reply.
1189 : *
1190 : * Copy the dsdb_control_password_acl_validation control from the request,
1191 : * to the reply. The control is used by the audit_log module to identify
1192 : * password rests.
1193 : *
1194 : * @param req the ldb request.
1195 : * @param ares the result, updated with the control.
1196 : */
1197 88236 : static void copy_password_acl_validation_control(
1198 : struct ldb_request *req,
1199 : struct ldb_reply *ares)
1200 : {
1201 88236 : struct ldb_control *pav_ctrl = NULL;
1202 88236 : struct dsdb_control_password_acl_validation *pav = NULL;
1203 :
1204 88236 : pav_ctrl = ldb_request_get_control(
1205 : discard_const(req),
1206 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1207 88236 : if (pav_ctrl == NULL) {
1208 74523 : return;
1209 : }
1210 :
1211 11059 : pav = talloc_get_type_abort(
1212 : pav_ctrl->data,
1213 : struct dsdb_control_password_acl_validation);
1214 11059 : if (pav == NULL) {
1215 0 : return;
1216 : }
1217 11059 : ldb_reply_add_control(
1218 : ares,
1219 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID,
1220 : false,
1221 : pav);
1222 : }
1223 : /*
1224 : * @brief call back function for acl_modify.
1225 : *
1226 : * Calls acl_copy to copy the dsdb_control_password_acl_validation from
1227 : * the request to the reply.
1228 : *
1229 : * @param req the ldb_request.
1230 : * @param ares the operation result.
1231 : *
1232 : * @return the LDB_STATUS
1233 : */
1234 88246 : static int acl_callback(struct ldb_request *req, struct ldb_reply *ares)
1235 : {
1236 88246 : struct acl_callback_context *ac = NULL;
1237 :
1238 88246 : ac = talloc_get_type(req->context, struct acl_callback_context);
1239 :
1240 88246 : if (!ares) {
1241 0 : return ldb_module_done(
1242 : ac->request,
1243 : NULL,
1244 : NULL,
1245 : LDB_ERR_OPERATIONS_ERROR);
1246 : }
1247 :
1248 : /* pass on to the callback */
1249 88246 : switch (ares->type) {
1250 0 : case LDB_REPLY_ENTRY:
1251 0 : return ldb_module_send_entry(
1252 : ac->request,
1253 : ares->message,
1254 : ares->controls);
1255 :
1256 10 : case LDB_REPLY_REFERRAL:
1257 10 : return ldb_module_send_referral(
1258 : ac->request,
1259 : ares->referral);
1260 :
1261 88236 : case LDB_REPLY_DONE:
1262 : /*
1263 : * Copy the ACL control from the request to the response
1264 : */
1265 88236 : copy_password_acl_validation_control(req, ares);
1266 88236 : return ldb_module_done(
1267 : ac->request,
1268 : ares->controls,
1269 : ares->response,
1270 : ares->error);
1271 :
1272 0 : default:
1273 : /* Can't happen */
1274 0 : return LDB_ERR_OPERATIONS_ERROR;
1275 : }
1276 : }
1277 :
1278 400870 : static int acl_modify(struct ldb_module *module, struct ldb_request *req)
1279 : {
1280 : int ret;
1281 400870 : struct ldb_context *ldb = ldb_module_get_ctx(module);
1282 : const struct dsdb_schema *schema;
1283 : unsigned int i;
1284 : const struct dsdb_class *objectclass;
1285 : struct ldb_result *acl_res;
1286 : struct security_descriptor *sd;
1287 400870 : struct dom_sid *sid = NULL;
1288 : struct ldb_control *as_system;
1289 : struct ldb_control *is_undelete;
1290 : bool userPassword;
1291 400870 : bool password_rights_checked = false;
1292 : TALLOC_CTX *tmp_ctx;
1293 400870 : const struct ldb_message *msg = req->op.mod.message;
1294 : static const char *acl_attrs[] = {
1295 : "nTSecurityDescriptor",
1296 : "objectClass",
1297 : "objectSid",
1298 : NULL
1299 : };
1300 400870 : struct acl_callback_context *context = NULL;
1301 400870 : struct ldb_request *new_req = NULL;
1302 400870 : struct dsdb_control_password_acl_validation *pav = NULL;
1303 400870 : struct ldb_control **controls = NULL;
1304 :
1305 400870 : if (ldb_dn_is_special(msg->dn)) {
1306 657 : return ldb_next_request(module, req);
1307 : }
1308 :
1309 400213 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1310 400213 : if (as_system != NULL) {
1311 121816 : as_system->critical = 0;
1312 : }
1313 :
1314 400213 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1315 :
1316 : /* Don't print this debug statement if elements[0].name is going to be NULL */
1317 400213 : if (msg->num_elements > 0) {
1318 399935 : DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
1319 : }
1320 400213 : if (dsdb_module_am_system(module) || as_system) {
1321 310785 : return ldb_next_request(module, req);
1322 : }
1323 :
1324 89428 : tmp_ctx = talloc_new(req);
1325 89428 : if (tmp_ctx == NULL) {
1326 0 : return ldb_oom(ldb);
1327 : }
1328 :
1329 89428 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
1330 : acl_attrs,
1331 : DSDB_FLAG_NEXT_MODULE |
1332 : DSDB_FLAG_AS_SYSTEM |
1333 : DSDB_SEARCH_SHOW_RECYCLED,
1334 : req);
1335 :
1336 89428 : if (ret != LDB_SUCCESS) {
1337 122 : goto fail;
1338 : }
1339 :
1340 89306 : userPassword = dsdb_user_password_support(module, req, req);
1341 :
1342 89306 : schema = dsdb_get_schema(ldb, tmp_ctx);
1343 89306 : if (!schema) {
1344 0 : talloc_free(tmp_ctx);
1345 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1346 : "acl_modify: Error obtaining schema.");
1347 : }
1348 :
1349 89306 : ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
1350 89306 : if (ret != LDB_SUCCESS) {
1351 0 : talloc_free(tmp_ctx);
1352 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1353 : "acl_modify: Error retrieving security descriptor.");
1354 : }
1355 : /* Theoretically we pass the check if the object has no sd */
1356 89306 : if (!sd) {
1357 0 : goto success;
1358 : }
1359 :
1360 89306 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1361 89306 : if (!objectclass) {
1362 0 : talloc_free(tmp_ctx);
1363 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1364 : "acl_modify: Error retrieving object class for GUID.");
1365 : }
1366 89306 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1367 207047 : for (i=0; i < msg->num_elements; i++) {
1368 118809 : const struct ldb_message_element *el = &msg->elements[i];
1369 : const struct dsdb_attribute *attr;
1370 :
1371 : /*
1372 : * This basic attribute existence check with the right errorcode
1373 : * is needed since this module is the first one which requests
1374 : * schema attribute information.
1375 : * The complete attribute checking is done in the
1376 : * "objectclass_attrs" module behind this one.
1377 : *
1378 : * NOTE: "clearTextPassword" is not defined in the schema.
1379 : */
1380 118809 : attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1381 118809 : if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
1382 4 : ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
1383 : "on entry '%s' was not found in the schema!",
1384 2 : req->op.mod.message->elements[i].name,
1385 2 : ldb_dn_get_linearized(req->op.mod.message->dn));
1386 2 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
1387 2 : goto fail;
1388 : }
1389 :
1390 118807 : if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
1391 22647 : uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
1392 22647 : uint32_t access_mask = 0;
1393 :
1394 22647 : if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
1395 8796 : access_mask |= SEC_STD_WRITE_OWNER;
1396 : }
1397 22647 : if (sd_flags & SECINFO_DACL) {
1398 22556 : access_mask |= SEC_STD_WRITE_DAC;
1399 : }
1400 22647 : if (sd_flags & SECINFO_SACL) {
1401 8723 : access_mask |= SEC_FLAG_SYSTEM_SECURITY;
1402 : }
1403 :
1404 22647 : ret = acl_check_access_on_attribute(module,
1405 : tmp_ctx,
1406 : sd,
1407 : sid,
1408 : access_mask,
1409 : attr,
1410 : objectclass);
1411 22647 : if (ret != LDB_SUCCESS) {
1412 0 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1413 : "Object %s has no write dacl access\n",
1414 0 : ldb_dn_get_linearized(msg->dn));
1415 0 : dsdb_acl_debug(sd,
1416 : acl_user_token(module),
1417 0 : msg->dn,
1418 : true,
1419 : 10);
1420 0 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1421 0 : goto fail;
1422 : }
1423 96160 : } else if (ldb_attr_cmp("member", el->name) == 0) {
1424 6219 : ret = acl_check_self_membership(tmp_ctx,
1425 : module,
1426 : req,
1427 : sd,
1428 : sid,
1429 : attr,
1430 : objectclass);
1431 6219 : if (ret != LDB_SUCCESS) {
1432 51 : goto fail;
1433 : }
1434 89941 : } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
1435 : /* this one is not affected by any rights, we should let it through
1436 : so that passwords_hash returns the correct error */
1437 216 : continue;
1438 89725 : } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
1439 63247 : (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
1440 78260 : ldb_attr_cmp("clearTextPassword", el->name) == 0) {
1441 : /*
1442 : * Ideally we would do the acl_check_password_rights
1443 : * before we checked the other attributes, i.e. in a
1444 : * loop before the current one.
1445 : * Have not done this as yet in order to limit the size
1446 : * of the change. To limit the possibility of breaking
1447 : * the ACL logic.
1448 : */
1449 12677 : if (password_rights_checked) {
1450 1289 : continue;
1451 : }
1452 11388 : ret = acl_check_password_rights(tmp_ctx,
1453 : module,
1454 : req,
1455 : sd,
1456 : sid,
1457 : objectclass,
1458 : userPassword,
1459 : &pav);
1460 11388 : if (ret != LDB_SUCCESS) {
1461 126 : goto fail;
1462 : }
1463 11190 : password_rights_checked = true;
1464 77048 : } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
1465 1388 : ret = acl_check_spn(tmp_ctx,
1466 : module,
1467 : req,
1468 : sd,
1469 : sid,
1470 : attr,
1471 : objectclass);
1472 1388 : if (ret != LDB_SUCCESS) {
1473 180 : goto fail;
1474 : }
1475 75660 : } else if (is_undelete != NULL && (ldb_attr_cmp("isDeleted", el->name) == 0)) {
1476 : /*
1477 : * in case of undelete op permissions on
1478 : * isDeleted are irrelevant and
1479 : * distinguishedName is removed by the
1480 : * tombstone_reanimate module
1481 : */
1482 274 : continue;
1483 : } else {
1484 75386 : ret = acl_check_access_on_attribute(module,
1485 : tmp_ctx,
1486 : sd,
1487 : sid,
1488 : SEC_ADS_WRITE_PROP,
1489 : attr,
1490 : objectclass);
1491 75386 : if (ret != LDB_SUCCESS) {
1492 709 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1493 : "Object %s has no write property access\n",
1494 38 : ldb_dn_get_linearized(msg->dn));
1495 709 : dsdb_acl_debug(sd,
1496 : acl_user_token(module),
1497 38 : msg->dn,
1498 : true,
1499 : 10);
1500 709 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1501 709 : goto fail;
1502 : }
1503 : }
1504 : }
1505 :
1506 88238 : success:
1507 88238 : talloc_free(tmp_ctx);
1508 88238 : context = talloc_zero(req, struct acl_callback_context);
1509 :
1510 88238 : if (context == NULL) {
1511 0 : return ldb_oom(ldb);
1512 : }
1513 88238 : context->request = req;
1514 88238 : context->module = module;
1515 88238 : ret = ldb_build_mod_req(
1516 : &new_req,
1517 : ldb,
1518 : req,
1519 : req->op.mod.message,
1520 : req->controls,
1521 : context,
1522 : acl_callback,
1523 : req);
1524 88238 : if (ret != LDB_SUCCESS) {
1525 0 : return ret;
1526 : }
1527 88238 : return ldb_next_request(module, new_req);
1528 1190 : fail:
1529 1190 : talloc_free(tmp_ctx);
1530 : /*
1531 : * We copy the pav into the result, so that the password reset
1532 : * logging code in audit_log can log failed password reset attempts.
1533 : */
1534 1190 : if (pav) {
1535 126 : struct ldb_control *control = NULL;
1536 :
1537 126 : controls = talloc_zero_array(req, struct ldb_control *, 2);
1538 126 : if (controls == NULL) {
1539 0 : return ldb_oom(ldb);
1540 : }
1541 :
1542 126 : control = talloc(controls, struct ldb_control);
1543 :
1544 126 : if (control == NULL) {
1545 0 : return ldb_oom(ldb);
1546 : }
1547 :
1548 126 : control->oid= talloc_strdup(
1549 : control,
1550 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
1551 126 : if (control->oid == NULL) {
1552 0 : return ldb_oom(ldb);
1553 : }
1554 126 : control->critical = false;
1555 126 : control->data = pav;
1556 126 : *controls = control;
1557 : }
1558 1190 : return ldb_module_done(req, controls, NULL, ret);
1559 : }
1560 :
1561 : /* similar to the modify for the time being.
1562 : * We need to consider the special delete tree case, though - TODO */
1563 53194 : static int acl_delete(struct ldb_module *module, struct ldb_request *req)
1564 : {
1565 : int ret;
1566 : struct ldb_dn *parent;
1567 : struct ldb_context *ldb;
1568 : struct ldb_dn *nc_root;
1569 : struct ldb_control *as_system;
1570 : const struct dsdb_schema *schema;
1571 : const struct dsdb_class *objectclass;
1572 53194 : struct security_descriptor *sd = NULL;
1573 53194 : struct dom_sid *sid = NULL;
1574 : struct ldb_result *acl_res;
1575 : static const char *acl_attrs[] = {
1576 : "nTSecurityDescriptor",
1577 : "objectClass",
1578 : "objectSid",
1579 : NULL
1580 : };
1581 :
1582 53194 : if (ldb_dn_is_special(req->op.del.dn)) {
1583 1 : return ldb_next_request(module, req);
1584 : }
1585 :
1586 53193 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1587 53193 : if (as_system != NULL) {
1588 25025 : as_system->critical = 0;
1589 : }
1590 :
1591 53193 : if (dsdb_module_am_system(module) || as_system) {
1592 26734 : return ldb_next_request(module, req);
1593 : }
1594 :
1595 26459 : DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
1596 :
1597 26459 : ldb = ldb_module_get_ctx(module);
1598 :
1599 26459 : parent = ldb_dn_get_parent(req, req->op.del.dn);
1600 26459 : if (parent == NULL) {
1601 0 : return ldb_oom(ldb);
1602 : }
1603 :
1604 : /* Make sure we aren't deleting a NC */
1605 :
1606 26459 : ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
1607 26459 : if (ret != LDB_SUCCESS) {
1608 0 : return ret;
1609 : }
1610 26459 : if (ldb_dn_compare(nc_root, req->op.del.dn) == 0) {
1611 0 : talloc_free(nc_root);
1612 0 : DEBUG(10,("acl:deleting a NC\n"));
1613 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1614 0 : return ldb_module_done(req, NULL, NULL,
1615 : LDB_ERR_UNWILLING_TO_PERFORM);
1616 : }
1617 26459 : talloc_free(nc_root);
1618 :
1619 26459 : ret = dsdb_module_search_dn(module, req, &acl_res,
1620 : req->op.del.dn, acl_attrs,
1621 : DSDB_FLAG_NEXT_MODULE |
1622 : DSDB_FLAG_AS_SYSTEM |
1623 : DSDB_SEARCH_SHOW_RECYCLED, req);
1624 : /* we sould be able to find the parent */
1625 26459 : if (ret != LDB_SUCCESS) {
1626 0 : DEBUG(10,("acl: failed to find object %s\n",
1627 : ldb_dn_get_linearized(req->op.rename.olddn)));
1628 0 : return ret;
1629 : }
1630 :
1631 26459 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1632 26459 : if (ret != LDB_SUCCESS) {
1633 0 : return ldb_operr(ldb);
1634 : }
1635 26459 : if (!sd) {
1636 0 : return ldb_operr(ldb);
1637 : }
1638 :
1639 26459 : schema = dsdb_get_schema(ldb, req);
1640 26459 : if (!schema) {
1641 0 : return ldb_operr(ldb);
1642 : }
1643 :
1644 26459 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1645 :
1646 26459 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1647 26459 : if (!objectclass) {
1648 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1649 : "acl_modify: Error retrieving object class for GUID.");
1650 : }
1651 :
1652 26459 : if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
1653 1067 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
1654 : SEC_ADS_DELETE_TREE,
1655 : objectclass);
1656 1067 : if (ret != LDB_SUCCESS) {
1657 0 : return ret;
1658 : }
1659 :
1660 1067 : return ldb_next_request(module, req);
1661 : }
1662 :
1663 : /* First check if we have delete object right */
1664 25392 : ret = acl_check_access_on_objectclass(module, req, sd, sid,
1665 : SEC_STD_DELETE,
1666 : objectclass);
1667 25392 : if (ret == LDB_SUCCESS) {
1668 25189 : return ldb_next_request(module, req);
1669 : }
1670 :
1671 : /* Nope, we don't have delete object. Lets check if we have delete
1672 : * child on the parent */
1673 203 : ret = dsdb_module_check_access_on_dn(module, req, parent,
1674 : SEC_ADS_DELETE_CHILD,
1675 : &objectclass->schemaIDGUID,
1676 : req);
1677 203 : if (ret != LDB_SUCCESS) {
1678 10 : return ret;
1679 : }
1680 :
1681 193 : return ldb_next_request(module, req);
1682 : }
1683 265 : static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx,
1684 : struct ldb_module *module,
1685 : struct ldb_request *req,
1686 : struct ldb_dn *nc_root)
1687 : {
1688 : int ret;
1689 : struct ldb_result *acl_res;
1690 265 : struct security_descriptor *sd = NULL;
1691 265 : struct dom_sid *sid = NULL;
1692 : static const char *acl_attrs[] = {
1693 : "nTSecurityDescriptor",
1694 : "objectClass",
1695 : "objectSid",
1696 : NULL
1697 : };
1698 :
1699 265 : ret = dsdb_module_search_dn(module, mem_ctx, &acl_res,
1700 : nc_root, acl_attrs,
1701 : DSDB_FLAG_NEXT_MODULE |
1702 : DSDB_FLAG_AS_SYSTEM |
1703 : DSDB_SEARCH_SHOW_RECYCLED, req);
1704 265 : if (ret != LDB_SUCCESS) {
1705 0 : DEBUG(10,("acl: failed to find object %s\n",
1706 : ldb_dn_get_linearized(nc_root)));
1707 0 : return ret;
1708 : }
1709 :
1710 265 : ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
1711 265 : sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
1712 265 : if (ret != LDB_SUCCESS || !sd) {
1713 0 : return ldb_operr(ldb_module_get_ctx(module));
1714 : }
1715 265 : return acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
1716 : GUID_DRS_REANIMATE_TOMBSTONE,
1717 : SEC_ADS_CONTROL_ACCESS, sid);
1718 : }
1719 :
1720 1183 : static int acl_rename(struct ldb_module *module, struct ldb_request *req)
1721 : {
1722 : int ret;
1723 : struct ldb_dn *oldparent;
1724 : struct ldb_dn *newparent;
1725 : const struct dsdb_schema *schema;
1726 : const struct dsdb_class *objectclass;
1727 1183 : const struct dsdb_attribute *attr = NULL;
1728 : struct ldb_context *ldb;
1729 1183 : struct security_descriptor *sd = NULL;
1730 1183 : struct dom_sid *sid = NULL;
1731 : struct ldb_result *acl_res;
1732 : struct ldb_dn *nc_root;
1733 : struct ldb_control *as_system;
1734 : struct ldb_control *is_undelete;
1735 : TALLOC_CTX *tmp_ctx;
1736 : const char *rdn_name;
1737 : static const char *acl_attrs[] = {
1738 : "nTSecurityDescriptor",
1739 : "objectClass",
1740 : "objectSid",
1741 : NULL
1742 : };
1743 :
1744 1183 : if (ldb_dn_is_special(req->op.rename.olddn)) {
1745 0 : return ldb_next_request(module, req);
1746 : }
1747 :
1748 1183 : as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
1749 1183 : if (as_system != NULL) {
1750 0 : as_system->critical = 0;
1751 : }
1752 :
1753 1183 : DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn)));
1754 1183 : if (dsdb_module_am_system(module) || as_system) {
1755 605 : return ldb_next_request(module, req);
1756 : }
1757 :
1758 578 : ldb = ldb_module_get_ctx(module);
1759 :
1760 578 : tmp_ctx = talloc_new(req);
1761 578 : if (tmp_ctx == NULL) {
1762 0 : return ldb_oom(ldb);
1763 : }
1764 :
1765 578 : oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
1766 578 : if (oldparent == NULL) {
1767 0 : return ldb_oom(ldb);
1768 : }
1769 578 : newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
1770 578 : if (newparent == NULL) {
1771 0 : return ldb_oom(ldb);
1772 : }
1773 :
1774 : /* Make sure we aren't renaming/moving a NC */
1775 :
1776 578 : ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
1777 578 : if (ret != LDB_SUCCESS) {
1778 0 : return ret;
1779 : }
1780 578 : if (ldb_dn_compare(nc_root, req->op.rename.olddn) == 0) {
1781 0 : talloc_free(nc_root);
1782 0 : DEBUG(10,("acl:renaming/moving a NC\n"));
1783 : /* Windows returns "ERR_UNWILLING_TO_PERFORM */
1784 0 : return ldb_module_done(req, NULL, NULL,
1785 : LDB_ERR_UNWILLING_TO_PERFORM);
1786 : }
1787 :
1788 : /* special check for undelete operation */
1789 578 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
1790 578 : if (is_undelete != NULL) {
1791 265 : is_undelete->critical = 0;
1792 265 : ret = acl_check_reanimate_tombstone(tmp_ctx, module, req, nc_root);
1793 265 : if (ret != LDB_SUCCESS) {
1794 9 : talloc_free(tmp_ctx);
1795 9 : return ret;
1796 : }
1797 : }
1798 569 : talloc_free(nc_root);
1799 :
1800 : /* Look for the parent */
1801 :
1802 569 : ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res,
1803 : req->op.rename.olddn, acl_attrs,
1804 : DSDB_FLAG_NEXT_MODULE |
1805 : DSDB_FLAG_AS_SYSTEM |
1806 : DSDB_SEARCH_SHOW_RECYCLED, req);
1807 : /* we sould be able to find the parent */
1808 569 : if (ret != LDB_SUCCESS) {
1809 0 : DEBUG(10,("acl: failed to find object %s\n",
1810 : ldb_dn_get_linearized(req->op.rename.olddn)));
1811 0 : talloc_free(tmp_ctx);
1812 0 : return ret;
1813 : }
1814 :
1815 569 : ret = dsdb_get_sd_from_ldb_message(ldb, req, acl_res->msgs[0], &sd);
1816 569 : if (ret != LDB_SUCCESS) {
1817 0 : talloc_free(tmp_ctx);
1818 0 : return ldb_operr(ldb);
1819 : }
1820 569 : if (!sd) {
1821 0 : talloc_free(tmp_ctx);
1822 0 : return ldb_operr(ldb);
1823 : }
1824 :
1825 569 : schema = dsdb_get_schema(ldb, acl_res);
1826 569 : if (!schema) {
1827 0 : talloc_free(tmp_ctx);
1828 0 : return ldb_operr(ldb);
1829 : }
1830 :
1831 569 : sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
1832 :
1833 569 : objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
1834 569 : if (!objectclass) {
1835 0 : talloc_free(tmp_ctx);
1836 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
1837 : "acl_modify: Error retrieving object class for GUID.");
1838 : }
1839 :
1840 569 : attr = dsdb_attribute_by_lDAPDisplayName(schema, "name");
1841 569 : if (attr == NULL) {
1842 0 : talloc_free(tmp_ctx);
1843 0 : return ldb_operr(ldb);
1844 : }
1845 :
1846 569 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
1847 : SEC_ADS_WRITE_PROP,
1848 : attr, objectclass);
1849 569 : if (ret != LDB_SUCCESS) {
1850 19 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1851 : "Object %s has no wp on %s\n",
1852 : ldb_dn_get_linearized(req->op.rename.olddn),
1853 8 : attr->lDAPDisplayName);
1854 19 : dsdb_acl_debug(sd,
1855 : acl_user_token(module),
1856 : req->op.rename.olddn,
1857 : true,
1858 : 10);
1859 19 : talloc_free(tmp_ctx);
1860 19 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1861 : }
1862 :
1863 550 : rdn_name = ldb_dn_get_rdn_name(req->op.rename.olddn);
1864 550 : if (rdn_name == NULL) {
1865 0 : talloc_free(tmp_ctx);
1866 0 : return ldb_operr(ldb);
1867 : }
1868 :
1869 550 : attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
1870 550 : if (attr == NULL) {
1871 0 : talloc_free(tmp_ctx);
1872 0 : return ldb_operr(ldb);
1873 : }
1874 :
1875 550 : ret = acl_check_access_on_attribute(module, tmp_ctx, sd, sid,
1876 : SEC_ADS_WRITE_PROP,
1877 : attr, objectclass);
1878 550 : if (ret != LDB_SUCCESS) {
1879 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1880 : "Object %s has no wp on %s\n",
1881 : ldb_dn_get_linearized(req->op.rename.olddn),
1882 4 : attr->lDAPDisplayName);
1883 9 : dsdb_acl_debug(sd,
1884 : acl_user_token(module),
1885 : req->op.rename.olddn,
1886 : true,
1887 : 10);
1888 9 : talloc_free(tmp_ctx);
1889 9 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
1890 : }
1891 :
1892 541 : if (ldb_dn_compare(oldparent, newparent) == 0) {
1893 : /* regular rename, not move, nothing more to do */
1894 176 : talloc_free(tmp_ctx);
1895 176 : return ldb_next_request(module, req);
1896 : }
1897 :
1898 : /* new parent should have create child */
1899 365 : ret = dsdb_module_check_access_on_dn(module, req, newparent,
1900 : SEC_ADS_CREATE_CHILD,
1901 : &objectclass->schemaIDGUID, req);
1902 365 : if (ret != LDB_SUCCESS) {
1903 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1904 : "acl:access_denied renaming %s",
1905 : ldb_dn_get_linearized(req->op.rename.olddn));
1906 9 : talloc_free(tmp_ctx);
1907 9 : return ret;
1908 : }
1909 :
1910 : /* do we have delete object on the object? */
1911 : /* this access is not necessary for undelete ops */
1912 356 : if (is_undelete == NULL) {
1913 122 : ret = acl_check_access_on_objectclass(module, tmp_ctx, sd, sid,
1914 : SEC_STD_DELETE,
1915 : objectclass);
1916 122 : if (ret == LDB_SUCCESS) {
1917 95 : talloc_free(tmp_ctx);
1918 95 : return ldb_next_request(module, req);
1919 : }
1920 : /* what about delete child on the current parent */
1921 27 : ret = dsdb_module_check_access_on_dn(module, req, oldparent,
1922 : SEC_ADS_DELETE_CHILD,
1923 : &objectclass->schemaIDGUID,
1924 : req);
1925 27 : if (ret != LDB_SUCCESS) {
1926 9 : ldb_asprintf_errstring(ldb_module_get_ctx(module),
1927 : "acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn));
1928 9 : talloc_free(tmp_ctx);
1929 9 : return ldb_module_done(req, NULL, NULL, ret);
1930 : }
1931 : }
1932 252 : talloc_free(tmp_ctx);
1933 :
1934 252 : return ldb_next_request(module, req);
1935 : }
1936 :
1937 21099783 : static int acl_search_update_confidential_attrs(struct acl_context *ac,
1938 : struct acl_private *data)
1939 : {
1940 : struct dsdb_attribute *a;
1941 21099783 : uint32_t n = 0;
1942 :
1943 21099783 : if (data->acl_search) {
1944 : /*
1945 : * If acl:search is activated, the acl_read module
1946 : * protects confidential attributes.
1947 : */
1948 20742319 : return LDB_SUCCESS;
1949 : }
1950 :
1951 0 : if ((ac->schema == data->cached_schema_ptr) &&
1952 0 : (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
1953 : {
1954 0 : return LDB_SUCCESS;
1955 : }
1956 :
1957 0 : data->cached_schema_ptr = NULL;
1958 0 : data->cached_schema_loaded_usn = 0;
1959 0 : data->cached_schema_metadata_usn = 0;
1960 0 : TALLOC_FREE(data->confidential_attrs);
1961 :
1962 0 : if (ac->schema == NULL) {
1963 0 : return LDB_SUCCESS;
1964 : }
1965 :
1966 0 : for (a = ac->schema->attributes; a; a = a->next) {
1967 0 : const char **attrs = data->confidential_attrs;
1968 :
1969 0 : if (!(a->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) {
1970 0 : continue;
1971 : }
1972 :
1973 0 : attrs = talloc_realloc(data, attrs, const char *, n + 2);
1974 0 : if (attrs == NULL) {
1975 0 : TALLOC_FREE(data->confidential_attrs);
1976 0 : return ldb_module_oom(ac->module);
1977 : }
1978 :
1979 0 : attrs[n] = a->lDAPDisplayName;
1980 0 : attrs[n+1] = NULL;
1981 0 : n++;
1982 :
1983 0 : data->confidential_attrs = attrs;
1984 : }
1985 :
1986 0 : data->cached_schema_ptr = ac->schema;
1987 0 : data->cached_schema_metadata_usn = ac->schema->metadata_usn;
1988 :
1989 0 : return LDB_SUCCESS;
1990 : }
1991 :
1992 29519706 : static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares)
1993 : {
1994 : struct acl_context *ac;
1995 : struct acl_private *data;
1996 : struct ldb_result *acl_res;
1997 : static const char *acl_attrs[] = {
1998 : "objectClass",
1999 : "nTSecurityDescriptor",
2000 : "objectSid",
2001 : NULL
2002 : };
2003 : int ret;
2004 : unsigned int i;
2005 :
2006 29519706 : ac = talloc_get_type(req->context, struct acl_context);
2007 29519706 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2008 29519706 : if (!ares) {
2009 0 : return ldb_module_done(ac->req, NULL, NULL,
2010 : LDB_ERR_OPERATIONS_ERROR);
2011 : }
2012 29519706 : if (ares->error != LDB_SUCCESS) {
2013 32700 : return ldb_module_done(ac->req, ares->controls,
2014 : ares->response, ares->error);
2015 : }
2016 :
2017 29487006 : switch (ares->type) {
2018 24319759 : case LDB_REPLY_ENTRY:
2019 24319759 : if (ac->constructed_attrs) {
2020 76 : ret = dsdb_module_search_dn(ac->module, ac, &acl_res, ares->message->dn,
2021 : acl_attrs,
2022 : DSDB_FLAG_NEXT_MODULE |
2023 : DSDB_FLAG_AS_SYSTEM |
2024 : DSDB_SEARCH_SHOW_RECYCLED,
2025 : req);
2026 76 : if (ret != LDB_SUCCESS) {
2027 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2028 : }
2029 : }
2030 :
2031 24319759 : if (ac->allowedAttributes || ac->allowedAttributesEffective) {
2032 36 : ret = acl_allowedAttributes(ac->module, ac->schema,
2033 22 : acl_res->msgs[0],
2034 : ares->message, ac);
2035 22 : if (ret != LDB_SUCCESS) {
2036 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2037 : }
2038 : }
2039 :
2040 24319759 : if (ac->allowedChildClasses) {
2041 0 : ret = acl_childClasses(ac->module, ac->schema,
2042 0 : acl_res->msgs[0],
2043 : ares->message,
2044 : "allowedChildClasses");
2045 0 : if (ret != LDB_SUCCESS) {
2046 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2047 : }
2048 : }
2049 :
2050 24319759 : if (ac->allowedChildClassesEffective) {
2051 28 : ret = acl_childClassesEffective(ac->module, ac->schema,
2052 18 : acl_res->msgs[0],
2053 : ares->message, ac);
2054 18 : if (ret != LDB_SUCCESS) {
2055 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2056 : }
2057 : }
2058 :
2059 24319759 : if (ac->sDRightsEffective) {
2060 56 : ret = acl_sDRightsEffective(ac->module,
2061 36 : acl_res->msgs[0],
2062 : ares->message, ac);
2063 36 : if (ret != LDB_SUCCESS) {
2064 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
2065 : }
2066 : }
2067 :
2068 24319759 : if (data == NULL) {
2069 0 : return ldb_module_send_entry(ac->req, ares->message,
2070 : ares->controls);
2071 : }
2072 :
2073 24319759 : if (ac->am_system) {
2074 0 : return ldb_module_send_entry(ac->req, ares->message,
2075 : ares->controls);
2076 : }
2077 :
2078 24319759 : if (data->password_attrs != NULL) {
2079 510231455 : for (i = 0; data->password_attrs[i]; i++) {
2080 810479580 : if ((!ac->userPassword) &&
2081 467585580 : (ldb_attr_cmp(data->password_attrs[i],
2082 : "userPassword") == 0))
2083 : {
2084 23379279 : continue;
2085 : }
2086 :
2087 463015901 : ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
2088 : }
2089 : }
2090 :
2091 24319759 : if (ac->am_administrator) {
2092 8207949 : return ldb_module_send_entry(ac->req, ares->message,
2093 : ares->controls);
2094 : }
2095 :
2096 16111810 : ret = acl_search_update_confidential_attrs(ac, data);
2097 16111810 : if (ret != LDB_SUCCESS) {
2098 0 : return ret;
2099 : }
2100 :
2101 16111810 : if (data->confidential_attrs != NULL) {
2102 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2103 0 : ldb_msg_remove_attr(ares->message,
2104 0 : data->confidential_attrs[i]);
2105 : }
2106 : }
2107 :
2108 16111810 : return ldb_module_send_entry(ac->req, ares->message, ares->controls);
2109 :
2110 212106 : case LDB_REPLY_REFERRAL:
2111 212106 : return ldb_module_send_referral(ac->req, ares->referral);
2112 :
2113 4955141 : case LDB_REPLY_DONE:
2114 4955141 : return ldb_module_done(ac->req, ares->controls,
2115 : ares->response, LDB_SUCCESS);
2116 :
2117 : }
2118 0 : return LDB_SUCCESS;
2119 : }
2120 :
2121 21634365 : static int acl_search(struct ldb_module *module, struct ldb_request *req)
2122 : {
2123 : struct ldb_context *ldb;
2124 : struct acl_context *ac;
2125 : struct ldb_parse_tree *down_tree;
2126 : struct ldb_request *down_req;
2127 : struct acl_private *data;
2128 : int ret;
2129 : unsigned int i;
2130 :
2131 21634365 : if (ldb_dn_is_special(req->op.search.base)) {
2132 5005754 : return ldb_next_request(module, req);
2133 : }
2134 :
2135 16628611 : ldb = ldb_module_get_ctx(module);
2136 :
2137 16628611 : ac = talloc_zero(req, struct acl_context);
2138 16628611 : if (ac == NULL) {
2139 0 : return ldb_oom(ldb);
2140 : }
2141 16628611 : data = talloc_get_type(ldb_module_get_private(module), struct acl_private);
2142 :
2143 16628611 : ac->module = module;
2144 16628611 : ac->req = req;
2145 16628611 : ac->am_system = dsdb_module_am_system(module);
2146 16628611 : ac->am_administrator = dsdb_module_am_administrator(module);
2147 16628611 : ac->constructed_attrs = false;
2148 16628611 : ac->modify_search = true;
2149 16628611 : ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
2150 16628611 : ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
2151 16628611 : ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
2152 16628611 : ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
2153 16628611 : ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
2154 16628611 : ac->userPassword = true;
2155 16628611 : ac->schema = dsdb_get_schema(ldb, ac);
2156 :
2157 16628611 : ac->constructed_attrs |= ac->allowedAttributes;
2158 16628611 : ac->constructed_attrs |= ac->allowedChildClasses;
2159 16628611 : ac->constructed_attrs |= ac->allowedChildClassesEffective;
2160 16628611 : ac->constructed_attrs |= ac->allowedAttributesEffective;
2161 16628611 : ac->constructed_attrs |= ac->sDRightsEffective;
2162 :
2163 16628611 : if (data == NULL) {
2164 0 : ac->modify_search = false;
2165 : }
2166 16628611 : if (ac->am_system) {
2167 11640638 : ac->modify_search = false;
2168 : }
2169 :
2170 16628611 : if (!ac->constructed_attrs && !ac->modify_search) {
2171 11640638 : talloc_free(ac);
2172 11640638 : return ldb_next_request(module, req);
2173 : }
2174 :
2175 4987973 : data = talloc_get_type(ldb_module_get_private(ac->module), struct acl_private);
2176 4987973 : if (data == NULL) {
2177 0 : return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
2178 : "acl_private data is missing");
2179 : }
2180 4987973 : ac->userPassword = data->userPassword_support;
2181 :
2182 4987973 : ret = acl_search_update_confidential_attrs(ac, data);
2183 4987973 : if (ret != LDB_SUCCESS) {
2184 0 : return ret;
2185 : }
2186 :
2187 4987973 : down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
2188 4987973 : if (down_tree == NULL) {
2189 0 : return ldb_oom(ldb);
2190 : }
2191 :
2192 4987973 : if (!ac->am_system && data->password_attrs) {
2193 104413124 : for (i = 0; data->password_attrs[i]; i++) {
2194 178301020 : if ((!ac->userPassword) &&
2195 99105360 : (ldb_attr_cmp(data->password_attrs[i],
2196 : "userPassword") == 0))
2197 : {
2198 4955268 : continue;
2199 : }
2200 :
2201 94804192 : ldb_parse_tree_attr_replace(down_tree,
2202 88452321 : data->password_attrs[i],
2203 : "kludgeACLredactedattribute");
2204 : }
2205 : }
2206 :
2207 4987973 : if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) {
2208 0 : for (i = 0; data->confidential_attrs[i]; i++) {
2209 0 : ldb_parse_tree_attr_replace(down_tree,
2210 0 : data->confidential_attrs[i],
2211 : "kludgeACLredactedattribute");
2212 : }
2213 : }
2214 :
2215 4987973 : ret = ldb_build_search_req_ex(&down_req,
2216 : ldb, ac,
2217 : req->op.search.base,
2218 : req->op.search.scope,
2219 : down_tree,
2220 : req->op.search.attrs,
2221 : req->controls,
2222 : ac, acl_search_callback,
2223 : req);
2224 4987973 : LDB_REQ_SET_LOCATION(down_req);
2225 4987973 : if (ret != LDB_SUCCESS) {
2226 0 : return ret;
2227 : }
2228 : /* perform the search */
2229 4987973 : return ldb_next_request(module, down_req);
2230 : }
2231 :
2232 1111687 : static int acl_extended(struct ldb_module *module, struct ldb_request *req)
2233 : {
2234 1111687 : struct ldb_context *ldb = ldb_module_get_ctx(module);
2235 1111687 : struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
2236 :
2237 : /* allow everybody to read the sequence number */
2238 1111687 : if (strcmp(req->op.extended.oid,
2239 : LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
2240 1106279 : return ldb_next_request(module, req);
2241 : }
2242 :
2243 5604 : if (dsdb_module_am_system(module) ||
2244 196 : dsdb_module_am_administrator(module) || as_system) {
2245 5408 : return ldb_next_request(module, req);
2246 : } else {
2247 0 : ldb_asprintf_errstring(ldb,
2248 : "acl_extended: "
2249 : "attempted database modify not permitted. "
2250 : "User %s is not SYSTEM or an administrator",
2251 : acl_user_name(req, module));
2252 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2253 : }
2254 : }
2255 :
2256 : static const struct ldb_module_ops ldb_acl_module_ops = {
2257 : .name = "acl",
2258 : .search = acl_search,
2259 : .add = acl_add,
2260 : .modify = acl_modify,
2261 : .del = acl_delete,
2262 : .rename = acl_rename,
2263 : .extended = acl_extended,
2264 : .init_context = acl_module_init
2265 : };
2266 :
2267 5536 : int ldb_acl_module_init(const char *version)
2268 : {
2269 5536 : LDB_MODULE_CHECK_VERSION(version);
2270 5536 : return ldb_register_module(&ldb_acl_module_ops);
2271 : }
|