Line data Source code
1 : /*
2 : SAM ldb module
3 :
4 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2014
5 : Copyright (C) Simo Sorce 2004-2008
6 : Copyright (C) Matthias Dieter Wallnöfer 2009-2011
7 : Copyright (C) Matthieu Patou 2012
8 : Copyright (C) Catalyst.Net Ltd 2017
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : /*
25 : * Name: ldb
26 : *
27 : * Component: ldb samldb module
28 : *
29 : * Description: various internal DSDB triggers - most for SAM specific objects
30 : *
31 : * Author: Simo Sorce
32 : */
33 :
34 : #include "includes.h"
35 : #include "libcli/ldap/ldap_ndr.h"
36 : #include "ldb_module.h"
37 : #include "auth/auth.h"
38 : #include "dsdb/samdb/samdb.h"
39 : #include "dsdb/samdb/ldb_modules/util.h"
40 : #include "dsdb/samdb/ldb_modules/ridalloc.h"
41 : #include "libcli/security/security.h"
42 : #include "librpc/gen_ndr/ndr_security.h"
43 : #include "ldb_wrap.h"
44 : #include "param/param.h"
45 : #include "libds/common/flag_mapping.h"
46 : #include "system/network.h"
47 : #include "librpc/gen_ndr/irpc.h"
48 : #include "lib/util/smb_strtox.h"
49 :
50 : #undef strcasecmp
51 :
52 : struct samldb_ctx;
53 : enum samldb_add_type {
54 : SAMLDB_TYPE_USER,
55 : SAMLDB_TYPE_GROUP,
56 : SAMLDB_TYPE_CLASS,
57 : SAMLDB_TYPE_ATTRIBUTE
58 : };
59 :
60 : typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
61 :
62 : struct samldb_step {
63 : struct samldb_step *next;
64 : samldb_step_fn_t fn;
65 : };
66 :
67 : struct samldb_ctx {
68 : struct ldb_module *module;
69 : struct ldb_request *req;
70 :
71 : /* used for add operations */
72 : enum samldb_add_type type;
73 :
74 : /* the resulting message */
75 : struct ldb_message *msg;
76 :
77 : /* used in "samldb_find_for_defaultObjectCategory" */
78 : struct ldb_dn *dn, *res_dn;
79 :
80 : /* all the async steps necessary to complete the operation */
81 : struct samldb_step *steps;
82 : struct samldb_step *curstep;
83 :
84 : /* If someone set an ares to forward controls and response back to the caller */
85 : struct ldb_reply *ares;
86 : };
87 :
88 942925 : static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
89 : struct ldb_request *req)
90 : {
91 : struct ldb_context *ldb;
92 : struct samldb_ctx *ac;
93 :
94 942925 : ldb = ldb_module_get_ctx(module);
95 :
96 942925 : ac = talloc_zero(req, struct samldb_ctx);
97 942925 : if (ac == NULL) {
98 0 : ldb_oom(ldb);
99 0 : return NULL;
100 : }
101 :
102 942925 : ac->module = module;
103 942925 : ac->req = req;
104 :
105 942925 : return ac;
106 : }
107 :
108 319178 : static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
109 : {
110 : struct samldb_step *step, *stepper;
111 :
112 319178 : step = talloc_zero(ac, struct samldb_step);
113 319178 : if (step == NULL) {
114 0 : return ldb_oom(ldb_module_get_ctx(ac->module));
115 : }
116 :
117 319178 : step->fn = fn;
118 :
119 319178 : if (ac->steps == NULL) {
120 237195 : ac->steps = step;
121 237195 : ac->curstep = step;
122 : } else {
123 81983 : if (ac->curstep == NULL)
124 0 : return ldb_operr(ldb_module_get_ctx(ac->module));
125 160329 : for (stepper = ac->curstep; stepper->next != NULL;
126 22683 : stepper = stepper->next);
127 81983 : stepper->next = step;
128 : }
129 :
130 274355 : return LDB_SUCCESS;
131 : }
132 :
133 237162 : static int samldb_first_step(struct samldb_ctx *ac)
134 : {
135 237162 : if (ac->steps == NULL) {
136 0 : return ldb_operr(ldb_module_get_ctx(ac->module));
137 : }
138 :
139 237162 : ac->curstep = ac->steps;
140 237162 : return ac->curstep->fn(ac);
141 : }
142 :
143 318942 : static int samldb_next_step(struct samldb_ctx *ac)
144 : {
145 318942 : if (ac->curstep->next) {
146 81944 : ac->curstep = ac->curstep->next;
147 81944 : return ac->curstep->fn(ac);
148 : }
149 :
150 : /* We exit the samldb module here. If someone set an "ares" to forward
151 : * controls and response back to the caller, use them. */
152 236998 : if (ac->ares) {
153 236998 : return ldb_module_done(ac->req, ac->ares->controls,
154 198890 : ac->ares->response, LDB_SUCCESS);
155 : } else {
156 0 : return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
157 : }
158 : }
159 :
160 236077 : static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr,
161 : const char *attr_conflict,
162 : struct ldb_dn *base_dn)
163 : {
164 236077 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
165 236077 : const char * const no_attrs[] = { NULL };
166 : struct ldb_result *res;
167 : const char *enc_str;
168 : struct ldb_message_element *el;
169 : int ret;
170 :
171 236077 : el = dsdb_get_single_valued_attr(ac->msg, attr,
172 236077 : ac->req->operation);
173 236077 : if (el == NULL) {
174 : /* we are not affected */
175 476 : return LDB_SUCCESS;
176 : }
177 :
178 235601 : if (el->num_values > 1) {
179 2 : ldb_asprintf_errstring(ldb,
180 : "samldb: %s has %u values, should be single-valued!",
181 : attr, el->num_values);
182 2 : return LDB_ERR_CONSTRAINT_VIOLATION;
183 235599 : } else if (el->num_values == 0) {
184 18 : ldb_asprintf_errstring(ldb,
185 : "samldb: new value for %s not provided for mandatory, single-valued attribute!",
186 : attr);
187 18 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
188 : }
189 235581 : if (el->values[0].length == 0) {
190 0 : ldb_asprintf_errstring(ldb,
191 : "samldb: %s is of zero length, should have a value!",
192 : attr);
193 0 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
194 : }
195 235581 : enc_str = ldb_binary_encode(ac, el->values[0]);
196 :
197 235581 : if (enc_str == NULL) {
198 0 : return ldb_module_oom(ac->module);
199 : }
200 :
201 : /* Make sure that attr (eg) "sAMAccountName" is only used once */
202 :
203 235581 : if (attr_conflict != NULL) {
204 1569 : ret = dsdb_module_search(ac->module, ac, &res,
205 : base_dn,
206 : LDB_SCOPE_SUBTREE, no_attrs,
207 : DSDB_FLAG_NEXT_MODULE, ac->req,
208 : "(|(%s=%s)(%s=%s))",
209 : attr, enc_str,
210 : attr_conflict, enc_str);
211 : } else {
212 234012 : ret = dsdb_module_search(ac->module, ac, &res,
213 : base_dn,
214 : LDB_SCOPE_SUBTREE, no_attrs,
215 : DSDB_FLAG_NEXT_MODULE, ac->req,
216 : "(%s=%s)", attr, enc_str);
217 : }
218 235581 : if (ret != LDB_SUCCESS) {
219 0 : return ret;
220 : }
221 235581 : if (res->count > 1) {
222 0 : return ldb_operr(ldb);
223 235581 : } else if (res->count == 1) {
224 601 : if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0) {
225 78 : ldb_asprintf_errstring(ldb,
226 : "samldb: %s '%s' already in use!",
227 : attr, enc_str);
228 78 : return LDB_ERR_ENTRY_ALREADY_EXISTS;
229 : }
230 : }
231 235503 : talloc_free(res);
232 :
233 235503 : return LDB_SUCCESS;
234 : }
235 :
236 28323 : static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac)
237 : {
238 28323 : int ret = samldb_unique_attr_check(ac, "samAccountName", NULL,
239 : ldb_get_default_basedn(
240 : ldb_module_get_ctx(ac->module)));
241 28323 : if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) {
242 9 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
243 : }
244 28323 : return ret;
245 : }
246 :
247 971 : static int samldb_schema_attributeid_valid_check(struct samldb_ctx *ac)
248 : {
249 971 : int ret = samldb_unique_attr_check(ac, "attributeID", "governsID",
250 : ldb_get_schema_basedn(
251 : ldb_module_get_ctx(ac->module)));
252 971 : if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
253 9 : ret = LDB_ERR_UNWILLING_TO_PERFORM;
254 : }
255 971 : return ret;
256 : }
257 :
258 598 : static int samldb_schema_governsid_valid_check(struct samldb_ctx *ac)
259 : {
260 598 : int ret = samldb_unique_attr_check(ac, "governsID", "attributeID",
261 : ldb_get_schema_basedn(
262 : ldb_module_get_ctx(ac->module)));
263 598 : if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
264 9 : ret = LDB_ERR_UNWILLING_TO_PERFORM;
265 : }
266 598 : return ret;
267 : }
268 :
269 206042 : static int samldb_schema_ldapdisplayname_valid_check(struct samldb_ctx *ac)
270 : {
271 206042 : int ret = samldb_unique_attr_check(ac, "lDAPDisplayName", NULL,
272 : ldb_get_schema_basedn(
273 : ldb_module_get_ctx(ac->module)));
274 206042 : if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
275 36 : ret = LDB_ERR_UNWILLING_TO_PERFORM;
276 : }
277 206042 : return ret;
278 : }
279 :
280 63 : static int samldb_check_linkid_used(struct samldb_ctx *ac,
281 : struct dsdb_schema *schema,
282 : struct ldb_dn *schema_dn,
283 : struct ldb_context *ldb,
284 : int32_t linkID,
285 : bool *found)
286 : {
287 : int ret;
288 : struct ldb_result *ldb_res;
289 :
290 63 : if (dsdb_attribute_by_linkID(schema, linkID)) {
291 24 : *found = true;
292 24 : return LDB_SUCCESS;
293 : }
294 :
295 39 : ret = dsdb_module_search(ac->module, ac,
296 : &ldb_res,
297 : schema_dn, LDB_SCOPE_ONELEVEL, NULL,
298 : DSDB_FLAG_NEXT_MODULE,
299 : ac->req,
300 : "(linkID=%d)", linkID);
301 39 : if (ret != LDB_SUCCESS) {
302 0 : ldb_debug_set(ldb, LDB_DEBUG_ERROR,
303 : __location__": Searching for linkID=%d failed - %s\n",
304 : linkID,
305 : ldb_errstring(ldb));
306 0 : return ldb_operr(ldb);
307 : }
308 :
309 39 : *found = (ldb_res->count != 0);
310 39 : talloc_free(ldb_res);
311 :
312 39 : return LDB_SUCCESS;
313 : }
314 :
315 : /* Find the next open forward linkID in the schema. */
316 27 : static int samldb_generate_next_linkid(struct samldb_ctx *ac,
317 : struct dsdb_schema *schema,
318 : int32_t *next_linkID)
319 : {
320 : int ret;
321 : struct ldb_context *ldb;
322 : struct ldb_dn *schema_dn;
323 27 : bool linkID_used = true;
324 :
325 : /*
326 : * Windows starts at about 0xB0000000 in order to stop potential
327 : * collisions with future additions to the schema. We pass this
328 : * around as a signed int sometimes, but this should be sufficient.
329 : */
330 27 : *next_linkID = 0x40000000;
331 :
332 27 : ldb = ldb_module_get_ctx(ac->module);
333 27 : schema_dn = ldb_get_schema_basedn(ldb);
334 :
335 39 : while (linkID_used) {
336 42 : *next_linkID += 2;
337 42 : ret = samldb_check_linkid_used(ac, schema,
338 : schema_dn, ldb,
339 : *next_linkID, &linkID_used);
340 42 : if (ret != LDB_SUCCESS) {
341 0 : return ret;
342 : }
343 : }
344 :
345 27 : return LDB_SUCCESS;
346 : }
347 :
348 962 : static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
349 : {
350 : int ret;
351 962 : bool ok, found = false;
352 : struct ldb_message_element *el;
353 : const char *enc_str;
354 : const struct dsdb_attribute *attr;
355 : struct ldb_context *ldb;
356 : struct ldb_dn *schema_dn;
357 : struct dsdb_schema *schema;
358 962 : int32_t new_linkID = 0;
359 :
360 962 : ldb = ldb_module_get_ctx(ac->module);
361 962 : schema = dsdb_get_schema(ldb, ac);
362 962 : schema_dn = ldb_get_schema_basedn(ldb);
363 :
364 962 : el = dsdb_get_single_valued_attr(ac->msg, "linkID",
365 962 : ac->req->operation);
366 962 : if (el == NULL) {
367 762 : return LDB_SUCCESS;
368 : }
369 :
370 200 : enc_str = ldb_binary_encode(ac, el->values[0]);
371 200 : if (enc_str == NULL) {
372 0 : return ldb_module_oom(ac->module);
373 : }
374 :
375 200 : ok = (strcmp(enc_str, "0") == 0);
376 200 : if (ok) {
377 0 : return LDB_SUCCESS;
378 : }
379 :
380 : /*
381 : * This OID indicates that the caller wants the linkID
382 : * to be automatically generated. We therefore assign
383 : * it the next open linkID.
384 : */
385 200 : ok = (strcmp(enc_str, "1.2.840.113556.1.2.50") == 0);
386 200 : if (ok) {
387 27 : ret = samldb_generate_next_linkid(ac, schema, &new_linkID);
388 27 : if (ret != LDB_SUCCESS) {
389 0 : return ret;
390 : }
391 :
392 27 : ldb_msg_remove_element(ac->msg, el);
393 27 : ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
394 : new_linkID);
395 27 : return ret;
396 : }
397 :
398 : /*
399 : * Using either the attributeID or lDAPDisplayName of
400 : * another attribute in the linkID field indicates that
401 : * we should make this the backlink of that attribute.
402 : */
403 173 : attr = dsdb_attribute_by_attributeID_oid(schema, enc_str);
404 173 : if (attr == NULL) {
405 155 : attr = dsdb_attribute_by_lDAPDisplayName(schema, enc_str);
406 : }
407 :
408 173 : if (attr != NULL) {
409 : /*
410 : * The attribute we're adding this as a backlink of must
411 : * be a forward link.
412 : */
413 39 : if (attr->linkID % 2 != 0) {
414 18 : return LDB_ERR_UNWILLING_TO_PERFORM;
415 : }
416 :
417 21 : new_linkID = attr->linkID + 1;
418 :
419 : /* Make sure that this backlink doesn't already exist. */
420 21 : ret = samldb_check_linkid_used(ac, schema,
421 : schema_dn, ldb,
422 : new_linkID, &found);
423 21 : if (ret != LDB_SUCCESS) {
424 0 : return ret;
425 : }
426 :
427 21 : if (found) {
428 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
429 : }
430 :
431 12 : ldb_msg_remove_element(ac->msg, el);
432 12 : ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
433 : new_linkID);
434 12 : return ret;
435 : }
436 :
437 134 : schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
438 134 : ret = samldb_unique_attr_check(ac, "linkID", NULL, schema_dn);
439 134 : if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
440 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
441 : } else {
442 125 : return ret;
443 : }
444 : }
445 :
446 9 : static int samldb_check_mapiid_used(struct samldb_ctx *ac,
447 : struct dsdb_schema *schema,
448 : struct ldb_dn *schema_dn,
449 : struct ldb_context *ldb,
450 : int32_t mapiid,
451 : bool *found)
452 : {
453 : int ret;
454 : struct ldb_result *ldb_res;
455 :
456 9 : ret = dsdb_module_search(ac->module, ac,
457 : &ldb_res,
458 : schema_dn, LDB_SCOPE_ONELEVEL, NULL,
459 : DSDB_FLAG_NEXT_MODULE,
460 : ac->req,
461 : "(mAPIID=%d)", mapiid);
462 9 : if (ret != LDB_SUCCESS) {
463 0 : ldb_debug_set(ldb, LDB_DEBUG_ERROR,
464 : __location__": Searching for mAPIID=%d failed - %s\n",
465 : mapiid,
466 : ldb_errstring(ldb));
467 0 : return ldb_operr(ldb);
468 : }
469 :
470 9 : *found = (ldb_res->count != 0);
471 9 : talloc_free(ldb_res);
472 :
473 9 : return LDB_SUCCESS;
474 : }
475 :
476 9 : static int samldb_generate_next_mapiid(struct samldb_ctx *ac,
477 : struct dsdb_schema *schema,
478 : int32_t *next_mapiid)
479 : {
480 : int ret;
481 : struct ldb_context *ldb;
482 : struct ldb_dn *schema_dn;
483 9 : bool mapiid_used = true;
484 :
485 : /* Windows' generation seems to start about here */
486 9 : *next_mapiid = 60000;
487 :
488 9 : ldb = ldb_module_get_ctx(ac->module);
489 9 : schema_dn = ldb_get_schema_basedn(ldb);
490 :
491 13 : while (mapiid_used) {
492 9 : *next_mapiid += 1;
493 9 : ret = samldb_check_mapiid_used(ac, schema,
494 : schema_dn, ldb,
495 : *next_mapiid, &mapiid_used);
496 9 : if (ret != LDB_SUCCESS) {
497 0 : return ret;
498 : }
499 : }
500 :
501 9 : return LDB_SUCCESS;
502 : }
503 :
504 926 : static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac)
505 : {
506 : int ret;
507 : bool ok;
508 : struct ldb_message_element *el;
509 : const char *enc_str;
510 : struct ldb_context *ldb;
511 : struct ldb_dn *schema_dn;
512 : struct dsdb_schema *schema;
513 926 : int32_t new_mapiid = 0;
514 :
515 : /*
516 : * The mAPIID of a new attribute should be automatically generated
517 : * if a specific OID is put as the mAPIID, as according to
518 : * [MS-ADTS] 3.1.1.2.3.2.
519 : */
520 :
521 926 : ldb = ldb_module_get_ctx(ac->module);
522 926 : schema = dsdb_get_schema(ldb, ac);
523 926 : schema_dn = ldb_get_schema_basedn(ldb);
524 :
525 926 : el = dsdb_get_single_valued_attr(ac->msg, "mAPIID",
526 926 : ac->req->operation);
527 926 : if (el == NULL) {
528 908 : return LDB_SUCCESS;
529 : }
530 :
531 18 : enc_str = ldb_binary_encode(ac, el->values[0]);
532 18 : if (enc_str == NULL) {
533 0 : return ldb_module_oom(ac->module);
534 : }
535 :
536 18 : ok = (strcmp(enc_str, "1.2.840.113556.1.2.49") == 0);
537 18 : if (ok) {
538 9 : ret = samldb_generate_next_mapiid(ac, schema,
539 : &new_mapiid);
540 9 : if (ret != LDB_SUCCESS) {
541 0 : return ret;
542 : }
543 :
544 9 : ldb_msg_remove_element(ac->msg, el);
545 9 : ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
546 : "mAPIID", new_mapiid);
547 9 : return ret;
548 : }
549 :
550 9 : schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
551 9 : ret = samldb_unique_attr_check(ac, "mAPIID", NULL, schema_dn);
552 9 : if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
553 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
554 : } else {
555 0 : return ret;
556 : }
557 : }
558 :
559 : /* sAMAccountName handling */
560 5612 : static int samldb_generate_sAMAccountName(struct ldb_context *ldb,
561 : struct ldb_message *msg)
562 : {
563 : char *name;
564 :
565 : /* Format: $000000-000000000000 */
566 :
567 5612 : name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
568 5612 : (unsigned int)generate_random(),
569 5612 : (unsigned int)generate_random(),
570 5612 : (unsigned int)generate_random());
571 5612 : if (name == NULL) {
572 0 : return ldb_oom(ldb);
573 : }
574 5612 : return ldb_msg_add_steal_string(msg, "sAMAccountName", name);
575 : }
576 :
577 27547 : static int samldb_check_sAMAccountName(struct samldb_ctx *ac)
578 : {
579 27547 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
580 : int ret;
581 :
582 27547 : if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
583 5612 : ret = samldb_generate_sAMAccountName(ldb, ac->msg);
584 5612 : if (ret != LDB_SUCCESS) {
585 0 : return ret;
586 : }
587 : }
588 :
589 27547 : ret = samldb_sam_accountname_valid_check(ac);
590 27547 : if (ret != LDB_SUCCESS) {
591 7 : return ret;
592 : }
593 :
594 27540 : return samldb_next_step(ac);
595 : }
596 :
597 :
598 22788 : static bool samldb_msg_add_sid(struct ldb_message *msg,
599 : const char *name,
600 : const struct dom_sid *sid)
601 : {
602 : struct ldb_val v;
603 : enum ndr_err_code ndr_err;
604 :
605 22788 : ndr_err = ndr_push_struct_blob(&v, msg, sid,
606 : (ndr_push_flags_fn_t)ndr_push_dom_sid);
607 22788 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
608 0 : return false;
609 : }
610 22788 : return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
611 : }
612 :
613 :
614 : /* allocate a SID using our RID Set */
615 22771 : static int samldb_allocate_sid(struct samldb_ctx *ac)
616 : {
617 : uint32_t rid;
618 : struct dom_sid *sid;
619 22771 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
620 : int ret;
621 :
622 22771 : ret = ridalloc_allocate_rid(ac->module, &rid, ac->req);
623 22771 : if (ret != LDB_SUCCESS) {
624 0 : return ret;
625 : }
626 :
627 22771 : sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
628 22771 : if (sid == NULL) {
629 0 : return ldb_module_oom(ac->module);
630 : }
631 :
632 22771 : if ( ! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
633 0 : return ldb_operr(ldb);
634 : }
635 :
636 22771 : return samldb_next_step(ac);
637 : }
638 :
639 : /*
640 : see if a krbtgt_number is available
641 : */
642 41 : static bool samldb_krbtgtnumber_available(struct samldb_ctx *ac,
643 : uint32_t krbtgt_number)
644 : {
645 41 : TALLOC_CTX *tmp_ctx = talloc_new(ac);
646 : struct ldb_result *res;
647 41 : const char * const no_attrs[] = { NULL };
648 : int ret;
649 :
650 41 : ret = dsdb_module_search(ac->module, tmp_ctx, &res,
651 : ldb_get_default_basedn(ldb_module_get_ctx(ac->module)),
652 : LDB_SCOPE_SUBTREE, no_attrs,
653 : DSDB_FLAG_NEXT_MODULE,
654 : ac->req,
655 : "(msDC-SecondaryKrbTgtNumber=%u)",
656 : krbtgt_number);
657 41 : if (ret == LDB_SUCCESS && res->count == 0) {
658 41 : talloc_free(tmp_ctx);
659 41 : return true;
660 : }
661 0 : talloc_free(tmp_ctx);
662 0 : return false;
663 : }
664 :
665 : /* special handling for add in RODC join */
666 41 : static int samldb_rodc_add(struct samldb_ctx *ac)
667 : {
668 41 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
669 : uint32_t krbtgt_number, i_start, i;
670 : int ret;
671 : struct ldb_val newpass_utf16;
672 :
673 : /* find a unused msDC-SecondaryKrbTgtNumber */
674 41 : i_start = generate_random() & 0xFFFF;
675 41 : if (i_start == 0) {
676 0 : i_start = 1;
677 : }
678 :
679 41 : for (i=i_start; i<=0xFFFF; i++) {
680 41 : if (samldb_krbtgtnumber_available(ac, i)) {
681 41 : krbtgt_number = i;
682 41 : goto found;
683 : }
684 : }
685 0 : for (i=1; i<i_start; i++) {
686 0 : if (samldb_krbtgtnumber_available(ac, i)) {
687 0 : krbtgt_number = i;
688 0 : goto found;
689 : }
690 : }
691 :
692 0 : ldb_asprintf_errstring(ldb,
693 : "%08X: Unable to find available msDS-SecondaryKrbTgtNumber",
694 0 : W_ERROR_V(WERR_NO_SYSTEM_RESOURCES));
695 0 : return LDB_ERR_OTHER;
696 :
697 41 : found:
698 41 : ret = ldb_msg_add_empty(ac->msg, "msDS-SecondaryKrbTgtNumber",
699 : LDB_FLAG_INTERNAL_DISABLE_VALIDATION, NULL);
700 41 : if (ret != LDB_SUCCESS) {
701 0 : return ldb_operr(ldb);
702 : }
703 :
704 41 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
705 : "msDS-SecondaryKrbTgtNumber", krbtgt_number);
706 41 : if (ret != LDB_SUCCESS) {
707 0 : return ldb_operr(ldb);
708 : }
709 :
710 41 : ret = ldb_msg_add_fmt(ac->msg, "sAMAccountName", "krbtgt_%u",
711 : krbtgt_number);
712 41 : if (ret != LDB_SUCCESS) {
713 0 : return ldb_operr(ldb);
714 : }
715 :
716 41 : newpass_utf16 = data_blob_talloc_zero(ac->module, 256);
717 41 : if (newpass_utf16.data == NULL) {
718 0 : return ldb_oom(ldb);
719 : }
720 : /*
721 : * Note that the password_hash module will ignore
722 : * this value and use it's own generate_secret_buffer()
723 : * that's why we can just use generate_random_buffer()
724 : * here.
725 : */
726 41 : generate_random_buffer(newpass_utf16.data, newpass_utf16.length);
727 41 : ret = ldb_msg_add_steal_value(ac->msg, "clearTextPassword", &newpass_utf16);
728 41 : if (ret != LDB_SUCCESS) {
729 0 : return ldb_operr(ldb);
730 : }
731 :
732 41 : return samldb_next_step(ac);
733 : }
734 :
735 31592 : static int samldb_find_for_defaultObjectCategory(struct samldb_ctx *ac)
736 : {
737 31592 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
738 : struct ldb_result *res;
739 31592 : const char * const no_attrs[] = { NULL };
740 : int ret;
741 :
742 31592 : ac->res_dn = NULL;
743 :
744 31592 : ret = dsdb_module_search(ac->module, ac, &res,
745 : ac->dn, LDB_SCOPE_BASE, no_attrs,
746 : DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
747 : | DSDB_FLAG_NEXT_MODULE,
748 : ac->req,
749 : "(objectClass=classSchema)");
750 31592 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
751 : /* Don't be pricky when the DN doesn't exist if we have the */
752 : /* RELAX control specified */
753 252 : if (ldb_request_get_control(ac->req,
754 : LDB_CONTROL_RELAX_OID) == NULL) {
755 0 : ldb_set_errstring(ldb,
756 : "samldb_find_defaultObjectCategory: "
757 : "Invalid DN for 'defaultObjectCategory'!");
758 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
759 : }
760 : }
761 31592 : if ((ret != LDB_ERR_NO_SUCH_OBJECT) && (ret != LDB_SUCCESS)) {
762 0 : return ret;
763 : }
764 :
765 31592 : if (ret == LDB_SUCCESS) {
766 : /* ensure the defaultObjectCategory has a full GUID */
767 : struct ldb_message *m;
768 31340 : m = ldb_msg_new(ac->msg);
769 31340 : if (m == NULL) {
770 0 : return ldb_oom(ldb);
771 : }
772 31340 : m->dn = ac->msg->dn;
773 31340 : if (ldb_msg_add_string(m, "defaultObjectCategory",
774 31340 : ldb_dn_get_extended_linearized(m, res->msgs[0]->dn, 1)) !=
775 : LDB_SUCCESS) {
776 0 : return ldb_oom(ldb);
777 : }
778 31340 : m->elements[0].flags = LDB_FLAG_MOD_REPLACE;
779 :
780 31340 : ret = dsdb_module_modify(ac->module, m,
781 : DSDB_FLAG_NEXT_MODULE,
782 : ac->req);
783 31340 : if (ret != LDB_SUCCESS) {
784 0 : return ret;
785 : }
786 : }
787 :
788 :
789 31592 : ac->res_dn = ac->dn;
790 :
791 31592 : return samldb_next_step(ac);
792 : }
793 :
794 : /**
795 : * msDS-IntId attributeSchema attribute handling
796 : * during LDB_ADD request processing
797 : */
798 174362 : static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac)
799 : {
800 : int ret;
801 : bool id_exists;
802 : uint32_t msds_intid;
803 : int32_t system_flags;
804 : struct ldb_context *ldb;
805 : struct ldb_result *ldb_res;
806 : struct ldb_dn *schema_dn;
807 : struct samldb_msds_intid_persistant *msds_intid_struct;
808 : struct dsdb_schema *schema;
809 :
810 174362 : ldb = ldb_module_get_ctx(ac->module);
811 174362 : schema_dn = ldb_get_schema_basedn(ldb);
812 :
813 : /* replicated update should always go through */
814 174362 : if (ldb_request_get_control(ac->req,
815 : DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
816 0 : return LDB_SUCCESS;
817 : }
818 :
819 : /* msDS-IntId is handled by system and should never be
820 : * passed by clients */
821 174362 : if (ldb_msg_find_element(ac->msg, "msDS-IntId")) {
822 18 : return LDB_ERR_UNWILLING_TO_PERFORM;
823 : }
824 :
825 : /* do not generate msDS-IntId if Relax control is passed */
826 174344 : if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
827 143166 : return LDB_SUCCESS;
828 : }
829 :
830 : /* check Functional Level */
831 245 : if (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003) {
832 53 : return LDB_SUCCESS;
833 : }
834 :
835 : /* check systemFlags for SCHEMA_BASE_OBJECT flag */
836 192 : system_flags = ldb_msg_find_attr_as_int(ac->msg, "systemFlags", 0);
837 192 : if (system_flags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) {
838 0 : return LDB_SUCCESS;
839 : }
840 192 : schema = dsdb_get_schema(ldb, NULL);
841 192 : if (!schema) {
842 0 : ldb_debug_set(ldb, LDB_DEBUG_FATAL,
843 : "samldb_schema_info_update: no dsdb_schema loaded");
844 0 : DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
845 0 : return ldb_operr(ldb);
846 : }
847 :
848 192 : msds_intid_struct = (struct samldb_msds_intid_persistant*) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
849 192 : if (!msds_intid_struct) {
850 136 : msds_intid_struct = talloc(ldb, struct samldb_msds_intid_persistant);
851 : /* Generate new value for msDs-IntId
852 : * Value should be in 0x80000000..0xBFFFFFFF range */
853 136 : msds_intid = generate_random() % 0X3FFFFFFF;
854 136 : msds_intid += 0x80000000;
855 136 : msds_intid_struct->msds_intid = msds_intid;
856 136 : DEBUG(2, ("No samldb_msds_intid_persistant struct, allocating a new one\n"));
857 : } else {
858 56 : msds_intid = msds_intid_struct->msds_intid;
859 : }
860 :
861 : /* probe id values until unique one is found */
862 : do {
863 192 : msds_intid++;
864 192 : if (msds_intid > 0xBFFFFFFF) {
865 0 : msds_intid = 0x80000001;
866 : }
867 : /*
868 : * We search in the schema if we have already this
869 : * intid (using dsdb_attribute_by_attributeID_id
870 : * because in the range 0x80000000 0xBFFFFFFFF,
871 : * attributeID is a DSDB_ATTID_TYPE_INTID).
872 : *
873 : * If so generate another random value.
874 : *
875 : * We have to check the DB in case someone else has
876 : * modified the database while we are doing our
877 : * changes too (this case should be very bery rare) in
878 : * order to be sure.
879 : */
880 192 : if (dsdb_attribute_by_attributeID_id(schema, msds_intid)) {
881 0 : id_exists = true;
882 0 : msds_intid = generate_random() % 0X3FFFFFFF;
883 0 : msds_intid += 0x80000000;
884 0 : continue;
885 : }
886 :
887 :
888 192 : ret = dsdb_module_search(ac->module, ac,
889 : &ldb_res,
890 : schema_dn, LDB_SCOPE_ONELEVEL, NULL,
891 : DSDB_FLAG_NEXT_MODULE,
892 : ac->req,
893 : "(msDS-IntId=%d)", msds_intid);
894 192 : if (ret != LDB_SUCCESS) {
895 0 : ldb_debug_set(ldb, LDB_DEBUG_ERROR,
896 : __location__": Searching for msDS-IntId=%d failed - %s\n",
897 : msds_intid,
898 : ldb_errstring(ldb));
899 0 : return ldb_operr(ldb);
900 : }
901 192 : id_exists = (ldb_res->count > 0);
902 192 : talloc_free(ldb_res);
903 :
904 192 : } while(id_exists);
905 192 : msds_intid_struct->msds_intid = msds_intid;
906 192 : ldb_set_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE, msds_intid_struct);
907 :
908 192 : return samdb_msg_add_int(ldb, ac->msg, ac->msg, "msDS-IntId",
909 : msds_intid);
910 : }
911 :
912 :
913 : /*
914 : * samldb_add_entry (async)
915 : */
916 :
917 237167 : static int samldb_add_entry_callback(struct ldb_request *req,
918 : struct ldb_reply *ares)
919 : {
920 : struct ldb_context *ldb;
921 : struct samldb_ctx *ac;
922 : int ret;
923 :
924 237167 : ac = talloc_get_type(req->context, struct samldb_ctx);
925 237167 : ldb = ldb_module_get_ctx(ac->module);
926 :
927 237167 : if (!ares) {
928 0 : return ldb_module_done(ac->req, NULL, NULL,
929 : LDB_ERR_OPERATIONS_ERROR);
930 : }
931 :
932 237167 : if (ares->type == LDB_REPLY_REFERRAL) {
933 0 : return ldb_module_send_referral(ac->req, ares->referral);
934 : }
935 :
936 237167 : if (ares->error != LDB_SUCCESS) {
937 169 : return ldb_module_done(ac->req, ares->controls,
938 : ares->response, ares->error);
939 : }
940 236998 : if (ares->type != LDB_REPLY_DONE) {
941 0 : ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
942 0 : return ldb_module_done(ac->req, NULL, NULL,
943 : LDB_ERR_OPERATIONS_ERROR);
944 : }
945 :
946 : /* The caller may wish to get controls back from the add */
947 236998 : ac->ares = talloc_steal(ac, ares);
948 :
949 236998 : ret = samldb_next_step(ac);
950 236998 : if (ret != LDB_SUCCESS) {
951 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
952 : }
953 198890 : return ret;
954 : }
955 :
956 237155 : static int samldb_add_entry(struct samldb_ctx *ac)
957 : {
958 : struct ldb_context *ldb;
959 : struct ldb_request *req;
960 : int ret;
961 :
962 237155 : ldb = ldb_module_get_ctx(ac->module);
963 :
964 566049 : ret = ldb_build_add_req(&req, ldb, ac,
965 237155 : ac->msg,
966 199047 : ac->req->controls,
967 : ac, samldb_add_entry_callback,
968 : ac->req);
969 237155 : LDB_REQ_SET_LOCATION(req);
970 237155 : if (ret != LDB_SUCCESS) {
971 0 : return ret;
972 : }
973 :
974 237155 : return ldb_next_request(ac->module, req);
975 : }
976 :
977 : /*
978 : * return true if msg carries an attributeSchema that is intended to be RODC
979 : * filtered but is also a system-critical attribute.
980 : */
981 205986 : static bool check_rodc_critical_attribute(struct ldb_message *msg)
982 : {
983 : uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
984 :
985 205986 : schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
986 205986 : searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
987 205986 : rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE
988 : | SEARCH_FLAG_CONFIDENTIAL);
989 :
990 242588 : if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
991 47111 : ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
992 0 : return true;
993 : } else {
994 205986 : return false;
995 : }
996 : }
997 :
998 :
999 233533 : static int samldb_fill_object(struct samldb_ctx *ac)
1000 : {
1001 233533 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1002 : int ret;
1003 :
1004 : /* Add information for the different account types */
1005 233533 : switch(ac->type) {
1006 19863 : case SAMLDB_TYPE_USER: {
1007 19863 : struct ldb_control *rodc_control = ldb_request_get_control(ac->req,
1008 : LDB_CONTROL_RODC_DCPROMO_OID);
1009 19863 : if (rodc_control != NULL) {
1010 : /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
1011 41 : rodc_control->critical = false;
1012 41 : ret = samldb_add_step(ac, samldb_rodc_add);
1013 41 : if (ret != LDB_SUCCESS) return ret;
1014 : }
1015 :
1016 : /* check if we have a valid sAMAccountName */
1017 19863 : ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1018 19863 : if (ret != LDB_SUCCESS) return ret;
1019 :
1020 19863 : ret = samldb_add_step(ac, samldb_add_entry);
1021 19863 : if (ret != LDB_SUCCESS) return ret;
1022 19646 : break;
1023 : }
1024 :
1025 7684 : case SAMLDB_TYPE_GROUP: {
1026 : /* check if we have a valid sAMAccountName */
1027 7684 : ret = samldb_add_step(ac, samldb_check_sAMAccountName);
1028 7684 : if (ret != LDB_SUCCESS) return ret;
1029 :
1030 7684 : ret = samldb_add_step(ac, samldb_add_entry);
1031 7684 : if (ret != LDB_SUCCESS) return ret;
1032 6900 : break;
1033 : }
1034 :
1035 31624 : case SAMLDB_TYPE_CLASS: {
1036 31624 : const char *lDAPDisplayName = NULL;
1037 : const struct ldb_val *rdn_value, *def_obj_cat_val;
1038 31624 : unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "objectClassCategory", -2);
1039 :
1040 : /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
1041 31624 : if (!ldb_msg_find_element(ac->msg, "subClassOf")) {
1042 162 : ret = ldb_msg_add_string(ac->msg, "subClassOf", "top");
1043 162 : if (ret != LDB_SUCCESS) return ret;
1044 : }
1045 :
1046 31624 : ret = samdb_find_or_add_attribute(ldb, ac->msg,
1047 : "rdnAttId", "cn");
1048 31624 : if (ret != LDB_SUCCESS) return ret;
1049 :
1050 : /* do not allow one to mark an attributeSchema as RODC filtered if it
1051 : * is system-critical */
1052 31624 : if (check_rodc_critical_attribute(ac->msg)) {
1053 0 : ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
1054 0 : ldb_dn_get_linearized(ac->msg->dn));
1055 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1056 : }
1057 :
1058 31624 : rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1059 31624 : if (rdn_value == NULL) {
1060 0 : return ldb_operr(ldb);
1061 : }
1062 31624 : if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1063 : /* the RDN has prefix "CN" */
1064 364 : ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1065 364 : samdb_cn_to_lDAPDisplayName(ac->msg,
1066 364 : (const char *) rdn_value->data));
1067 364 : if (ret != LDB_SUCCESS) {
1068 0 : ldb_oom(ldb);
1069 0 : return ret;
1070 : }
1071 : }
1072 :
1073 31624 : lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1074 : "lDAPDisplayName",
1075 : NULL);
1076 31624 : ret = ldb_valid_attr_name(lDAPDisplayName);
1077 56204 : if (ret != 1 ||
1078 56204 : lDAPDisplayName[0] == '*' ||
1079 26080 : lDAPDisplayName[0] == '@')
1080 : {
1081 0 : return dsdb_module_werror(ac->module,
1082 : LDB_ERR_UNWILLING_TO_PERFORM,
1083 : WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1084 : "lDAPDisplayName is invalid");
1085 : }
1086 :
1087 31624 : if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1088 : struct GUID guid;
1089 : /* a new GUID */
1090 428 : guid = GUID_random();
1091 428 : ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1092 428 : if (ret != LDB_SUCCESS) {
1093 0 : ldb_oom(ldb);
1094 0 : return ret;
1095 : }
1096 : }
1097 :
1098 31624 : def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
1099 : "defaultObjectCategory");
1100 31624 : if (def_obj_cat_val != NULL) {
1101 : /* "defaultObjectCategory" has been set by the caller.
1102 : * Do some checks for consistency.
1103 : * NOTE: The real constraint check (that
1104 : * 'defaultObjectCategory' is the DN of the new
1105 : * objectclass or any parent of it) is still incomplete.
1106 : * For now we say that 'defaultObjectCategory' is valid
1107 : * if it exists and it is of objectclass "classSchema".
1108 : */
1109 31324 : ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
1110 31324 : if (ac->dn == NULL) {
1111 0 : ldb_set_errstring(ldb,
1112 : "Invalid DN for 'defaultObjectCategory'!");
1113 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
1114 : }
1115 : } else {
1116 : /* "defaultObjectCategory" has not been set by the
1117 : * caller. Use the entry DN for it. */
1118 300 : ac->dn = ac->msg->dn;
1119 :
1120 300 : ret = ldb_msg_add_string(ac->msg, "defaultObjectCategory",
1121 300 : ldb_dn_alloc_linearized(ac->msg, ac->dn));
1122 300 : if (ret != LDB_SUCCESS) {
1123 0 : ldb_oom(ldb);
1124 0 : return ret;
1125 : }
1126 : }
1127 :
1128 31624 : ret = samldb_add_step(ac, samldb_add_entry);
1129 31624 : if (ret != LDB_SUCCESS) return ret;
1130 :
1131 : /* Now perform the checks for the 'defaultObjectCategory'. The
1132 : * lookup DN was already saved in "ac->dn" */
1133 31624 : ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
1134 31624 : if (ret != LDB_SUCCESS) return ret;
1135 :
1136 : /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
1137 31624 : if (v == -2) {
1138 : /* Windows 2003 does this*/
1139 10 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "objectClassCategory", 0);
1140 10 : if (ret != LDB_SUCCESS) {
1141 0 : return ret;
1142 : }
1143 : }
1144 26080 : break;
1145 : }
1146 :
1147 174362 : case SAMLDB_TYPE_ATTRIBUTE: {
1148 174362 : const char *lDAPDisplayName = NULL;
1149 : const struct ldb_val *rdn_value;
1150 : struct ldb_message_element *el;
1151 174362 : rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1152 174362 : if (rdn_value == NULL) {
1153 0 : return ldb_operr(ldb);
1154 : }
1155 174362 : if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
1156 : /* the RDN has prefix "CN" */
1157 106 : ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
1158 106 : samdb_cn_to_lDAPDisplayName(ac->msg,
1159 106 : (const char *) rdn_value->data));
1160 106 : if (ret != LDB_SUCCESS) {
1161 0 : ldb_oom(ldb);
1162 0 : return ret;
1163 : }
1164 : }
1165 :
1166 174362 : lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
1167 : "lDAPDisplayName",
1168 : NULL);
1169 174362 : ret = ldb_valid_attr_name(lDAPDisplayName);
1170 309807 : if (ret != 1 ||
1171 309807 : lDAPDisplayName[0] == '*' ||
1172 143429 : lDAPDisplayName[0] == '@')
1173 : {
1174 0 : return dsdb_module_werror(ac->module,
1175 : LDB_ERR_UNWILLING_TO_PERFORM,
1176 : WERR_DS_INVALID_LDAP_DISPLAY_NAME,
1177 : "lDAPDisplayName is invalid");
1178 : }
1179 :
1180 : /* do not allow one to mark an attributeSchema as RODC filtered if it
1181 : * is system-critical */
1182 174362 : if (check_rodc_critical_attribute(ac->msg)) {
1183 0 : ldb_asprintf_errstring(ldb,
1184 : "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
1185 0 : ldb_dn_get_linearized(ac->msg->dn));
1186 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1187 : }
1188 :
1189 174362 : ret = samdb_find_or_add_attribute(ldb, ac->msg,
1190 : "isSingleValued", "FALSE");
1191 174362 : if (ret != LDB_SUCCESS) return ret;
1192 :
1193 174362 : if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
1194 : struct GUID guid;
1195 : /* a new GUID */
1196 263 : guid = GUID_random();
1197 263 : ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
1198 263 : if (ret != LDB_SUCCESS) {
1199 0 : ldb_oom(ldb);
1200 0 : return ret;
1201 : }
1202 : }
1203 :
1204 174362 : el = ldb_msg_find_element(ac->msg, "attributeSyntax");
1205 174362 : if (el) {
1206 : /*
1207 : * No need to scream if there isn't as we have code later on
1208 : * that will take care of it.
1209 : */
1210 174362 : const struct dsdb_syntax *syntax = find_syntax_map_by_ad_oid((const char *)el->values[0].data);
1211 174362 : if (!syntax) {
1212 0 : DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
1213 : (const char *)el->values[0].data));
1214 : } else {
1215 174362 : unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "oMSyntax", 0);
1216 174362 : const struct ldb_val *val = ldb_msg_find_ldb_val(ac->msg, "oMObjectClass");
1217 :
1218 174362 : if (v == 0) {
1219 0 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "oMSyntax", syntax->oMSyntax);
1220 0 : if (ret != LDB_SUCCESS) {
1221 0 : return ret;
1222 : }
1223 : }
1224 174362 : if (!val) {
1225 150104 : struct ldb_val val2 = ldb_val_dup(ldb, &syntax->oMObjectClass);
1226 150104 : if (val2.length > 0) {
1227 57 : ret = ldb_msg_add_value(ac->msg, "oMObjectClass", &val2, NULL);
1228 57 : if (ret != LDB_SUCCESS) {
1229 0 : return ret;
1230 : }
1231 : }
1232 : }
1233 : }
1234 : }
1235 :
1236 : /* handle msDS-IntID attribute */
1237 174362 : ret = samldb_add_handle_msDS_IntId(ac);
1238 174362 : if (ret != LDB_SUCCESS) return ret;
1239 :
1240 174344 : ret = samldb_add_step(ac, samldb_add_entry);
1241 174344 : if (ret != LDB_SUCCESS) return ret;
1242 143411 : break;
1243 : }
1244 :
1245 0 : default:
1246 0 : ldb_asprintf_errstring(ldb, "Invalid entry type!");
1247 0 : return LDB_ERR_OPERATIONS_ERROR;
1248 : break;
1249 : }
1250 :
1251 233515 : return samldb_first_step(ac);
1252 : }
1253 :
1254 3649 : static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1255 : {
1256 3649 : struct ldb_context *ldb = NULL;
1257 3649 : const struct ldb_val *rdn_value = NULL;
1258 3649 : struct ldb_message_element *sid_el = NULL;
1259 3649 : struct dom_sid *sid = NULL;
1260 3649 : struct ldb_control *as_system = NULL;
1261 3649 : struct ldb_control *provision = NULL;
1262 3649 : bool allowed = false;
1263 : int ret;
1264 :
1265 3649 : ldb = ldb_module_get_ctx(ac->module);
1266 :
1267 3649 : as_system = ldb_request_get_control(ac->req, LDB_CONTROL_AS_SYSTEM_OID);
1268 3649 : if (as_system != NULL) {
1269 15 : allowed = true;
1270 : }
1271 :
1272 3649 : provision = ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID);
1273 3649 : if (provision != NULL) {
1274 3632 : allowed = true;
1275 : }
1276 :
1277 3649 : sid_el = ldb_msg_find_element(ac->msg, "objectSid");
1278 :
1279 3649 : if (!allowed && sid_el == NULL) {
1280 1 : return dsdb_module_werror(ac->module,
1281 : LDB_ERR_OBJECT_CLASS_VIOLATION,
1282 : WERR_DS_MISSING_REQUIRED_ATT,
1283 : "objectSid missing on foreignSecurityPrincipal");
1284 : }
1285 :
1286 3648 : if (!allowed) {
1287 1 : return dsdb_module_werror(ac->module,
1288 : LDB_ERR_UNWILLING_TO_PERFORM,
1289 : WERR_DS_ILLEGAL_MOD_OPERATION,
1290 : "foreignSecurityPrincipal object not allowed");
1291 : }
1292 :
1293 3647 : if (sid_el != NULL) {
1294 3630 : sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1295 3630 : if (sid == NULL) {
1296 0 : ldb_set_errstring(ldb,
1297 : "samldb: invalid objectSid!");
1298 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
1299 : }
1300 : }
1301 :
1302 3017 : if (sid == NULL) {
1303 17 : rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
1304 17 : if (rdn_value == NULL) {
1305 0 : return ldb_operr(ldb);
1306 : }
1307 17 : sid = dom_sid_parse_talloc(ac->msg,
1308 17 : (const char *)rdn_value->data);
1309 17 : if (sid == NULL) {
1310 0 : ldb_set_errstring(ldb,
1311 : "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
1312 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
1313 : }
1314 17 : if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
1315 0 : return ldb_operr(ldb);
1316 : }
1317 : }
1318 :
1319 : /* finally proceed with adding the entry */
1320 3647 : ret = samldb_add_step(ac, samldb_add_entry);
1321 3647 : if (ret != LDB_SUCCESS) return ret;
1322 :
1323 3647 : return samldb_first_step(ac);
1324 : }
1325 :
1326 205986 : static int samldb_schema_info_update(struct samldb_ctx *ac)
1327 : {
1328 : int ret;
1329 : struct ldb_context *ldb;
1330 : struct dsdb_schema *schema;
1331 :
1332 : /* replicated update should always go through */
1333 205986 : if (ldb_request_get_control(ac->req,
1334 : DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1335 0 : return LDB_SUCCESS;
1336 : }
1337 :
1338 : /* do not update schemaInfo during provisioning */
1339 205986 : if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID)) {
1340 168030 : return LDB_SUCCESS;
1341 : }
1342 :
1343 1479 : ldb = ldb_module_get_ctx(ac->module);
1344 1479 : schema = dsdb_get_schema(ldb, NULL);
1345 1479 : if (!schema) {
1346 0 : ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1347 : "samldb_schema_info_update: no dsdb_schema loaded");
1348 0 : DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
1349 0 : return ldb_operr(ldb);
1350 : }
1351 :
1352 1479 : ret = dsdb_module_schema_info_update(ac->module, schema,
1353 : DSDB_FLAG_NEXT_MODULE|
1354 : DSDB_FLAG_AS_SYSTEM,
1355 : ac->req);
1356 1479 : if (ret != LDB_SUCCESS) {
1357 0 : ldb_asprintf_errstring(ldb,
1358 : "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
1359 : ldb_errstring(ldb));
1360 0 : return ret;
1361 : }
1362 :
1363 1479 : return LDB_SUCCESS;
1364 : }
1365 :
1366 : static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
1367 : static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
1368 : struct dom_sid *sid,
1369 : uint32_t req_uac,
1370 : uint32_t user_account_control,
1371 : uint32_t user_account_control_old);
1372 :
1373 : /*
1374 : * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
1375 : *
1376 : * Has to be invoked on "add" and "modify" operations on "user", "computer" and
1377 : * "group" objects.
1378 : * ac->msg contains the "add"/"modify" message
1379 : * ac->type contains the object type (main objectclass)
1380 : */
1381 27581 : static int samldb_objectclass_trigger(struct samldb_ctx *ac)
1382 : {
1383 27581 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1384 27581 : void *skip_allocate_sids = ldb_get_opaque(ldb,
1385 : "skip_allocate_sids");
1386 : struct ldb_message_element *el, *el2;
1387 : struct dom_sid *sid;
1388 : int ret;
1389 :
1390 : /* make sure that "sAMAccountType" is not specified */
1391 27581 : el = ldb_msg_find_element(ac->msg, "sAMAccountType");
1392 27581 : if (el != NULL) {
1393 1 : ldb_set_errstring(ldb,
1394 : "samldb: sAMAccountType must not be specified!");
1395 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
1396 : }
1397 :
1398 : /* Step 1: objectSid assignment */
1399 :
1400 : /* Don't allow the objectSid to be changed. But beside the RELAX
1401 : * control we have also to guarantee that it can always be set with
1402 : * SYSTEM permissions. This is needed for the "samba3sam" backend. */
1403 27580 : sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1404 32302 : if ((sid != NULL) && (!dsdb_module_am_system(ac->module)) &&
1405 4722 : (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
1406 0 : ldb_set_errstring(ldb,
1407 : "samldb: objectSid must not be specified!");
1408 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1409 : }
1410 :
1411 : /* but generate a new SID when we do have an add operations */
1412 27580 : if ((sid == NULL) && (ac->req->operation == LDB_ADD) && !skip_allocate_sids) {
1413 22804 : ret = samldb_add_step(ac, samldb_allocate_sid);
1414 22804 : if (ret != LDB_SUCCESS) return ret;
1415 : }
1416 :
1417 27580 : switch(ac->type) {
1418 19890 : case SAMLDB_TYPE_USER: {
1419 19890 : bool uac_generated = false, uac_add_flags = false;
1420 :
1421 : /* Step 1.2: Default values */
1422 19890 : ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req);
1423 19890 : if (ret != LDB_SUCCESS) return ret;
1424 :
1425 : /* On add operations we might need to generate a
1426 : * "userAccountControl" (if it isn't specified). */
1427 19890 : el = ldb_msg_find_element(ac->msg, "userAccountControl");
1428 19890 : if ((el == NULL) && (ac->req->operation == LDB_ADD)) {
1429 16415 : ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1430 : "userAccountControl",
1431 : UF_NORMAL_ACCOUNT);
1432 16415 : if (ret != LDB_SUCCESS) {
1433 0 : return ret;
1434 : }
1435 16362 : uac_generated = true;
1436 16362 : uac_add_flags = true;
1437 : }
1438 :
1439 19890 : el = ldb_msg_find_element(ac->msg, "userAccountControl");
1440 19890 : if (el != NULL) {
1441 : uint32_t raw_uac;
1442 : uint32_t user_account_control;
1443 : /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
1444 19890 : user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
1445 : "userAccountControl",
1446 : 0);
1447 19890 : raw_uac = user_account_control;
1448 : /*
1449 : * "userAccountControl" = 0 or missing one of
1450 : * the types means "UF_NORMAL_ACCOUNT". See
1451 : * MS-SAMR 3.1.1.8.10 point 8
1452 : */
1453 19890 : if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
1454 30 : user_account_control = UF_NORMAL_ACCOUNT | user_account_control;
1455 30 : uac_generated = true;
1456 : }
1457 :
1458 : /*
1459 : * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
1460 : */
1461 19890 : if ((user_account_control & UF_LOCKOUT) != 0) {
1462 7 : user_account_control &= ~UF_LOCKOUT;
1463 7 : uac_generated = true;
1464 : }
1465 19890 : if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
1466 7 : user_account_control &= ~UF_PASSWORD_EXPIRED;
1467 7 : uac_generated = true;
1468 : }
1469 :
1470 19890 : ret = samldb_check_user_account_control_rules(ac, NULL,
1471 : raw_uac,
1472 : user_account_control,
1473 : 0);
1474 19890 : if (ret != LDB_SUCCESS) {
1475 18 : return ret;
1476 : }
1477 :
1478 : /* Workstation and (read-only) DC objects do need objectclass "computer" */
1479 19872 : if ((samdb_find_attribute(ldb, ac->msg,
1480 17945 : "objectclass", "computer") == NULL) &&
1481 17945 : (user_account_control &
1482 : (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) {
1483 9 : ldb_set_errstring(ldb,
1484 : "samldb: Requested account type does need objectclass 'computer'!");
1485 9 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
1486 : }
1487 :
1488 : /* add "sAMAccountType" attribute */
1489 19863 : ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
1490 19863 : if (ret != LDB_SUCCESS) {
1491 0 : return ret;
1492 : }
1493 :
1494 : /* "isCriticalSystemObject" might be set */
1495 19863 : if (user_account_control &
1496 : (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
1497 687 : ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1498 : "TRUE");
1499 687 : if (ret != LDB_SUCCESS) {
1500 0 : return ret;
1501 : }
1502 687 : el2 = ldb_msg_find_element(ac->msg,
1503 : "isCriticalSystemObject");
1504 687 : el2->flags = LDB_FLAG_MOD_REPLACE;
1505 19176 : } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
1506 1054 : ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
1507 : "FALSE");
1508 1054 : if (ret != LDB_SUCCESS) {
1509 0 : return ret;
1510 : }
1511 1054 : el2 = ldb_msg_find_element(ac->msg,
1512 : "isCriticalSystemObject");
1513 1054 : el2->flags = LDB_FLAG_MOD_REPLACE;
1514 : }
1515 :
1516 : /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
1517 19863 : if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
1518 : uint32_t rid;
1519 :
1520 19741 : ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
1521 19741 : if (ret != LDB_SUCCESS) {
1522 0 : return ret;
1523 : }
1524 : /*
1525 : * Older AD deployments don't know about the
1526 : * RODC group
1527 : */
1528 19741 : if (rid == DOMAIN_RID_READONLY_DCS) {
1529 100 : ret = samldb_prim_group_tester(ac, rid);
1530 100 : if (ret != LDB_SUCCESS) {
1531 0 : return ret;
1532 : }
1533 : }
1534 : }
1535 :
1536 : /* Step 1.5: Add additional flags when needed */
1537 : /* Obviously this is done when the "userAccountControl"
1538 : * has been generated here (tested against Windows
1539 : * Server) */
1540 19863 : if (uac_generated) {
1541 16453 : if (uac_add_flags) {
1542 16415 : user_account_control |= UF_ACCOUNTDISABLE;
1543 16415 : user_account_control |= UF_PASSWD_NOTREQD;
1544 : }
1545 :
1546 16453 : ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
1547 : "userAccountControl",
1548 : user_account_control);
1549 16453 : if (ret != LDB_SUCCESS) {
1550 0 : return ret;
1551 : }
1552 : }
1553 :
1554 : }
1555 19646 : break;
1556 : }
1557 :
1558 7690 : case SAMLDB_TYPE_GROUP: {
1559 : const char *tempstr;
1560 :
1561 : /* Step 2.2: Default values */
1562 7690 : tempstr = talloc_asprintf(ac->msg, "%d",
1563 : GTYPE_SECURITY_GLOBAL_GROUP);
1564 7690 : if (tempstr == NULL) return ldb_operr(ldb);
1565 7690 : ret = samdb_find_or_add_attribute(ldb, ac->msg,
1566 : "groupType", tempstr);
1567 7690 : if (ret != LDB_SUCCESS) return ret;
1568 :
1569 : /* Step 2.3: "groupType" -> "sAMAccountType" */
1570 7690 : el = ldb_msg_find_element(ac->msg, "groupType");
1571 7690 : if (el != NULL) {
1572 : uint32_t group_type, account_type;
1573 :
1574 7690 : group_type = ldb_msg_find_attr_as_uint(ac->msg,
1575 : "groupType", 0);
1576 :
1577 : /* The creation of builtin groups requires the
1578 : * RELAX control */
1579 7690 : if (group_type == GTYPE_SECURITY_BUILTIN_LOCAL_GROUP) {
1580 2544 : if (ldb_request_get_control(ac->req,
1581 : LDB_CONTROL_RELAX_OID) == NULL) {
1582 3 : return LDB_ERR_UNWILLING_TO_PERFORM;
1583 : }
1584 : }
1585 :
1586 7687 : account_type = ds_gtype2atype(group_type);
1587 7687 : if (account_type == 0) {
1588 3 : ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
1589 3 : return LDB_ERR_UNWILLING_TO_PERFORM;
1590 : }
1591 7684 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
1592 : "sAMAccountType",
1593 : account_type);
1594 7684 : if (ret != LDB_SUCCESS) {
1595 0 : return ret;
1596 : }
1597 7684 : el2 = ldb_msg_find_element(ac->msg, "sAMAccountType");
1598 7684 : el2->flags = LDB_FLAG_MOD_REPLACE;
1599 : }
1600 6900 : break;
1601 : }
1602 :
1603 0 : default:
1604 0 : ldb_asprintf_errstring(ldb,
1605 : "Invalid entry type!");
1606 0 : return LDB_ERR_OPERATIONS_ERROR;
1607 : break;
1608 : }
1609 :
1610 26546 : return LDB_SUCCESS;
1611 : }
1612 :
1613 : /*
1614 : * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
1615 : *
1616 : * Has to be invoked on "add" and "modify" operations on "user" and "computer"
1617 : * objects.
1618 : * ac->msg contains the "add"/"modify" message
1619 : */
1620 :
1621 231 : static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid)
1622 : {
1623 231 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1624 : struct dom_sid *sid;
1625 : struct ldb_result *res;
1626 : int ret;
1627 231 : const char * const noattrs[] = { NULL };
1628 :
1629 231 : sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
1630 231 : if (sid == NULL) {
1631 0 : return ldb_operr(ldb);
1632 : }
1633 :
1634 231 : ret = dsdb_module_search(ac->module, ac, &res,
1635 : ldb_get_default_basedn(ldb),
1636 : LDB_SCOPE_SUBTREE,
1637 : noattrs, DSDB_FLAG_NEXT_MODULE,
1638 : ac->req,
1639 : "(objectSid=%s)",
1640 : ldap_encode_ndr_dom_sid(ac, sid));
1641 231 : if (ret != LDB_SUCCESS) {
1642 0 : return ret;
1643 : }
1644 231 : if (res->count != 1) {
1645 0 : talloc_free(res);
1646 0 : ldb_asprintf_errstring(ldb,
1647 : "Failed to find primary group with RID %u!",
1648 : rid);
1649 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
1650 : }
1651 231 : talloc_free(res);
1652 :
1653 231 : return LDB_SUCCESS;
1654 : }
1655 :
1656 19901 : static int samldb_prim_group_set(struct samldb_ctx *ac)
1657 : {
1658 19901 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1659 : uint32_t rid;
1660 :
1661 19901 : rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
1662 19901 : if (rid == (uint32_t) -1) {
1663 : /* we aren't affected of any primary group set */
1664 19573 : return LDB_SUCCESS;
1665 :
1666 132 : } else if (!ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
1667 10 : ldb_set_errstring(ldb,
1668 : "The primary group isn't settable on add operations!");
1669 10 : return LDB_ERR_UNWILLING_TO_PERFORM;
1670 : }
1671 :
1672 122 : return samldb_prim_group_tester(ac, rid);
1673 : }
1674 :
1675 107 : static int samldb_prim_group_change(struct samldb_ctx *ac)
1676 : {
1677 107 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
1678 107 : const char * const attrs[] = {
1679 : "primaryGroupID",
1680 : "memberOf",
1681 : "userAccountControl",
1682 : NULL };
1683 : struct ldb_result *res, *group_res;
1684 : struct ldb_message_element *el;
1685 : struct ldb_message *msg;
1686 107 : uint32_t search_flags =
1687 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_EXTENDED_DN;
1688 : uint32_t prev_rid, new_rid, uac;
1689 : struct dom_sid *prev_sid, *new_sid;
1690 : struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
1691 107 : const char *new_prim_group_dn_ext_str = NULL;
1692 107 : struct ldb_dn *user_dn = NULL;
1693 107 : const char *user_dn_ext_str = NULL;
1694 : int ret;
1695 107 : const char * const noattrs[] = { NULL };
1696 :
1697 107 : el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
1698 107 : ac->req->operation);
1699 107 : if (el == NULL) {
1700 : /* we are not affected */
1701 3 : return LDB_SUCCESS;
1702 : }
1703 :
1704 : /* Fetch information from the existing object */
1705 :
1706 104 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
1707 : search_flags, ac->req);
1708 104 : if (ret != LDB_SUCCESS) {
1709 0 : return ret;
1710 : }
1711 104 : user_dn = res->msgs[0]->dn;
1712 104 : user_dn_ext_str = ldb_dn_get_extended_linearized(ac, user_dn, 1);
1713 104 : if (user_dn_ext_str == NULL) {
1714 0 : return ldb_operr(ldb);
1715 : }
1716 :
1717 104 : uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
1718 :
1719 : /* Finds out the DN of the old primary group */
1720 :
1721 104 : prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
1722 : (uint32_t) -1);
1723 104 : if (prev_rid == (uint32_t) -1) {
1724 : /* User objects do always have a mandatory "primaryGroupID"
1725 : * attribute. If this doesn't exist then the object is of the
1726 : * wrong type. This is the exact Windows error code */
1727 3 : return LDB_ERR_OBJECT_CLASS_VIOLATION;
1728 : }
1729 :
1730 101 : prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
1731 101 : if (prev_sid == NULL) {
1732 0 : return ldb_operr(ldb);
1733 : }
1734 :
1735 : /* Finds out the DN of the new primary group
1736 : * Notice: in order to parse the primary group ID correctly we create
1737 : * a temporary message here. */
1738 :
1739 101 : msg = ldb_msg_new(ac->msg);
1740 101 : if (msg == NULL) {
1741 0 : return ldb_module_oom(ac->module);
1742 : }
1743 101 : ret = ldb_msg_add(msg, el, 0);
1744 101 : if (ret != LDB_SUCCESS) {
1745 0 : return ret;
1746 : }
1747 101 : new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
1748 101 : talloc_free(msg);
1749 101 : if (new_rid == (uint32_t) -1) {
1750 : /* we aren't affected of any primary group change */
1751 3 : return LDB_SUCCESS;
1752 : }
1753 :
1754 98 : if (prev_rid == new_rid) {
1755 11 : return LDB_SUCCESS;
1756 : }
1757 :
1758 87 : if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
1759 1 : ldb_asprintf_errstring(ldb,
1760 : "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
1761 : "primaryGroupID=%u!",
1762 1 : W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1763 : DOMAIN_RID_DCS);
1764 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
1765 : }
1766 :
1767 86 : if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != DOMAIN_RID_READONLY_DCS) {
1768 1 : ldb_asprintf_errstring(ldb,
1769 : "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
1770 : "primaryGroupID=%u!",
1771 1 : W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
1772 : DOMAIN_RID_READONLY_DCS);
1773 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
1774 : }
1775 :
1776 85 : ret = dsdb_module_search(ac->module, ac, &group_res,
1777 : ldb_get_default_basedn(ldb),
1778 : LDB_SCOPE_SUBTREE,
1779 : noattrs, search_flags,
1780 : ac->req,
1781 : "(objectSid=%s)",
1782 : ldap_encode_ndr_dom_sid(ac, prev_sid));
1783 85 : if (ret != LDB_SUCCESS) {
1784 0 : return ret;
1785 : }
1786 85 : if (group_res->count != 1) {
1787 0 : return ldb_operr(ldb);
1788 : }
1789 85 : prev_prim_group_dn = group_res->msgs[0]->dn;
1790 :
1791 85 : new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
1792 85 : if (new_sid == NULL) {
1793 0 : return ldb_operr(ldb);
1794 : }
1795 :
1796 85 : ret = dsdb_module_search(ac->module, ac, &group_res,
1797 : ldb_get_default_basedn(ldb),
1798 : LDB_SCOPE_SUBTREE,
1799 : noattrs, search_flags,
1800 : ac->req,
1801 : "(objectSid=%s)",
1802 : ldap_encode_ndr_dom_sid(ac, new_sid));
1803 85 : if (ret != LDB_SUCCESS) {
1804 0 : return ret;
1805 : }
1806 85 : if (group_res->count != 1) {
1807 : /* Here we know if the specified new primary group candidate is
1808 : * valid or not. */
1809 3 : return LDB_ERR_UNWILLING_TO_PERFORM;
1810 : }
1811 82 : new_prim_group_dn = group_res->msgs[0]->dn;
1812 82 : new_prim_group_dn_ext_str = ldb_dn_get_extended_linearized(ac,
1813 : new_prim_group_dn, 1);
1814 82 : if (new_prim_group_dn_ext_str == NULL) {
1815 0 : return ldb_operr(ldb);
1816 : }
1817 :
1818 : /* We need to be already a normal member of the new primary
1819 : * group in order to be successful. */
1820 82 : el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
1821 : new_prim_group_dn_ext_str);
1822 82 : if (el == NULL) {
1823 4 : return LDB_ERR_UNWILLING_TO_PERFORM;
1824 : }
1825 :
1826 : /* Remove the "member" attribute on the new primary group */
1827 78 : msg = ldb_msg_new(ac->msg);
1828 78 : if (msg == NULL) {
1829 0 : return ldb_module_oom(ac->module);
1830 : }
1831 78 : msg->dn = new_prim_group_dn;
1832 :
1833 78 : ret = samdb_msg_add_delval(ldb, msg, msg, "member", user_dn_ext_str);
1834 78 : if (ret != LDB_SUCCESS) {
1835 0 : return ret;
1836 : }
1837 :
1838 78 : ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1839 78 : if (ret != LDB_SUCCESS) {
1840 0 : return ret;
1841 : }
1842 78 : talloc_free(msg);
1843 :
1844 : /* Add a "member" attribute for the previous primary group */
1845 78 : msg = ldb_msg_new(ac->msg);
1846 78 : if (msg == NULL) {
1847 0 : return ldb_module_oom(ac->module);
1848 : }
1849 78 : msg->dn = prev_prim_group_dn;
1850 :
1851 78 : ret = samdb_msg_add_addval(ldb, msg, msg, "member", user_dn_ext_str);
1852 78 : if (ret != LDB_SUCCESS) {
1853 0 : return ret;
1854 : }
1855 :
1856 78 : ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
1857 78 : if (ret != LDB_SUCCESS) {
1858 0 : return ret;
1859 : }
1860 78 : talloc_free(msg);
1861 :
1862 78 : return LDB_SUCCESS;
1863 : }
1864 :
1865 20008 : static int samldb_prim_group_trigger(struct samldb_ctx *ac)
1866 : {
1867 : int ret;
1868 :
1869 20008 : if (ac->req->operation == LDB_ADD) {
1870 19901 : ret = samldb_prim_group_set(ac);
1871 : } else {
1872 107 : ret = samldb_prim_group_change(ac);
1873 : }
1874 :
1875 20008 : return ret;
1876 : }
1877 :
1878 30706 : static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
1879 : uint32_t user_account_control)
1880 : {
1881 : size_t i;
1882 30706 : int ret = 0;
1883 30706 : bool need_check = false;
1884 : const struct uac_to_guid {
1885 : uint32_t uac;
1886 : bool never;
1887 : uint32_t needs;
1888 : uint32_t not_with;
1889 : const char *error_string;
1890 30706 : } map[] = {
1891 : {
1892 : .uac = UF_TEMP_DUPLICATE_ACCOUNT,
1893 : .never = true,
1894 : .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
1895 : },
1896 : {
1897 : .uac = UF_PARTIAL_SECRETS_ACCOUNT,
1898 : .needs = UF_WORKSTATION_TRUST_ACCOUNT,
1899 : .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
1900 : },
1901 : {
1902 : .uac = UF_TRUSTED_FOR_DELEGATION,
1903 : .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1904 : .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1905 : },
1906 : {
1907 : .uac = UF_NORMAL_ACCOUNT,
1908 : .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
1909 : .error_string = "Setting more than one account type not permitted"
1910 : },
1911 : {
1912 : .uac = UF_WORKSTATION_TRUST_ACCOUNT,
1913 : .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
1914 : .error_string = "Setting more than one account type not permitted"
1915 : },
1916 : {
1917 : .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
1918 : .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
1919 : .error_string = "Setting more than one account type not permitted"
1920 : },
1921 : {
1922 : .uac = UF_SERVER_TRUST_ACCOUNT,
1923 : .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
1924 : .error_string = "Setting more than one account type not permitted"
1925 : },
1926 : {
1927 : .uac = UF_TRUSTED_FOR_DELEGATION,
1928 : .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
1929 : .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
1930 : }
1931 : };
1932 :
1933 125330 : for (i = 0; i < ARRAY_SIZE(map); i++) {
1934 125330 : if (user_account_control & map[i].uac) {
1935 30380 : need_check = true;
1936 30380 : break;
1937 : }
1938 : }
1939 30706 : if (need_check == false) {
1940 0 : return LDB_SUCCESS;
1941 : }
1942 :
1943 275873 : for (i = 0; i < ARRAY_SIZE(map); i++) {
1944 245513 : uint32_t this_uac = user_account_control & map[i].uac;
1945 245513 : if (this_uac != 0) {
1946 31949 : if (map[i].never) {
1947 16 : ret = LDB_ERR_OTHER;
1948 16 : break;
1949 31933 : } else if (map[i].needs != 0) {
1950 204 : if ((map[i].needs & user_account_control) == 0) {
1951 3 : ret = LDB_ERR_OTHER;
1952 3 : break;
1953 : }
1954 31729 : } else if (map[i].not_with != 0) {
1955 31729 : if ((map[i].not_with & user_account_control) != 0) {
1956 1 : ret = LDB_ERR_OTHER;
1957 1 : break;
1958 : }
1959 : }
1960 : }
1961 : }
1962 30706 : if (ret != LDB_SUCCESS) {
1963 20 : switch (ac->req->operation) {
1964 7 : case LDB_ADD:
1965 12 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1966 : "Failed to add %s: %s",
1967 7 : ldb_dn_get_linearized(ac->msg->dn),
1968 2 : map[i].error_string);
1969 7 : break;
1970 13 : case LDB_MODIFY:
1971 24 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
1972 : "Failed to modify %s: %s",
1973 13 : ldb_dn_get_linearized(ac->msg->dn),
1974 2 : map[i].error_string);
1975 13 : break;
1976 0 : default:
1977 0 : return ldb_module_operr(ac->module);
1978 : }
1979 21404 : }
1980 30380 : return ret;
1981 : }
1982 :
1983 : /**
1984 : * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
1985 : *
1986 : */
1987 30686 : static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
1988 : struct dom_sid *sid,
1989 : uint32_t user_account_control,
1990 : uint32_t user_account_control_old)
1991 : {
1992 : size_t i;
1993 30686 : int ret = 0;
1994 30686 : bool need_acl_check = false;
1995 : struct ldb_result *res;
1996 30686 : const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
1997 : struct security_token *user_token;
1998 : struct security_descriptor *domain_sd;
1999 30686 : struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
2000 30686 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2001 : const struct uac_to_guid {
2002 : uint32_t uac;
2003 : uint32_t priv_to_change_from;
2004 : const char *oid;
2005 : const char *guid;
2006 : enum sec_privilege privilege;
2007 : bool delete_is_privileged;
2008 : bool admin_required;
2009 : const char *error_string;
2010 30686 : } map[] = {
2011 : {
2012 : .uac = UF_PASSWD_NOTREQD,
2013 : .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
2014 : .error_string = "Adding the UF_PASSWD_NOTREQD bit in userAccountControl requires the Update-Password-Not-Required-Bit right that was not given on the Domain object"
2015 : },
2016 : {
2017 : .uac = UF_DONT_EXPIRE_PASSWD,
2018 : .guid = GUID_DRS_UNEXPIRE_PASSWORD,
2019 : .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
2020 : },
2021 : {
2022 : .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
2023 : .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
2024 : .error_string = "Adding the UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED bit in userAccountControl requires the Enable-Per-User-Reversibly-Encrypted-Password right that was not given on the Domain object"
2025 : },
2026 : {
2027 : .uac = UF_SERVER_TRUST_ACCOUNT,
2028 : .guid = GUID_DRS_DS_INSTALL_REPLICA,
2029 : .error_string = "Adding the UF_SERVER_TRUST_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
2030 : },
2031 : {
2032 : .uac = UF_PARTIAL_SECRETS_ACCOUNT,
2033 : .guid = GUID_DRS_DS_INSTALL_REPLICA,
2034 : .error_string = "Adding the UF_PARTIAL_SECRETS_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
2035 : },
2036 : {
2037 : .uac = UF_WORKSTATION_TRUST_ACCOUNT,
2038 : .priv_to_change_from = UF_NORMAL_ACCOUNT,
2039 : .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
2040 : },
2041 : {
2042 : .uac = UF_NORMAL_ACCOUNT,
2043 : .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
2044 : .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
2045 : },
2046 : {
2047 : .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
2048 : .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2049 : .error_string = "Updating the UF_INTERDOMAIN_TRUST_ACCOUNT bit in userAccountControl is not permitted over LDAP. This bit is restricted to the LSA CreateTrustedDomain interface",
2050 : .delete_is_privileged = true
2051 : },
2052 : {
2053 : .uac = UF_TRUSTED_FOR_DELEGATION,
2054 : .privilege = SEC_PRIV_ENABLE_DELEGATION,
2055 : .delete_is_privileged = true,
2056 : .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2057 : },
2058 : {
2059 : .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
2060 : .privilege = SEC_PRIV_ENABLE_DELEGATION,
2061 : .delete_is_privileged = true,
2062 : .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
2063 : }
2064 :
2065 : };
2066 :
2067 30686 : if (dsdb_module_am_system(ac->module)) {
2068 1670 : return LDB_SUCCESS;
2069 : }
2070 :
2071 187362 : for (i = 0; i < ARRAY_SIZE(map); i++) {
2072 187591 : if (user_account_control & map[i].uac) {
2073 28690 : need_acl_check = true;
2074 28690 : break;
2075 : }
2076 : }
2077 28919 : if (need_acl_check == false) {
2078 0 : return LDB_SUCCESS;
2079 : }
2080 :
2081 28919 : user_token = acl_user_token(ac->module);
2082 28919 : if (user_token == NULL) {
2083 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2084 : }
2085 :
2086 28919 : ret = dsdb_module_search_dn(ac->module, ac, &res,
2087 : domain_dn,
2088 : sd_attrs,
2089 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2090 : ac->req);
2091 28919 : if (ret != LDB_SUCCESS) {
2092 0 : return ret;
2093 : }
2094 28919 : if (res->count != 1) {
2095 0 : return ldb_module_operr(ac->module);
2096 : }
2097 :
2098 28919 : ret = dsdb_get_sd_from_ldb_message(ldb,
2099 28919 : ac, res->msgs[0], &domain_sd);
2100 :
2101 28919 : if (ret != LDB_SUCCESS) {
2102 0 : return ret;
2103 : }
2104 :
2105 317751 : for (i = 0; i < ARRAY_SIZE(map); i++) {
2106 289097 : uint32_t this_uac_new = user_account_control & map[i].uac;
2107 289097 : uint32_t this_uac_old = user_account_control_old & map[i].uac;
2108 289097 : if (this_uac_new != this_uac_old) {
2109 30481 : if (this_uac_old != 0) {
2110 9368 : if (map[i].delete_is_privileged == false) {
2111 9354 : continue;
2112 : }
2113 : }
2114 21127 : if (map[i].oid) {
2115 79 : struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
2116 79 : if (control == NULL) {
2117 16 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2118 : }
2119 21048 : } else if (map[i].privilege != SEC_PRIV_INVALID) {
2120 366 : bool have_priv = security_token_has_privilege(user_token,
2121 58 : map[i].privilege);
2122 366 : if (have_priv == false) {
2123 8 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2124 : }
2125 20682 : } else if (map[i].priv_to_change_from & user_account_control_old) {
2126 92 : bool is_admin = security_token_has_builtin_administrators(user_token);
2127 92 : if (is_admin == false) {
2128 5 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2129 : }
2130 20590 : } else if (map[i].guid) {
2131 2416 : ret = acl_check_extended_right(ac, domain_sd,
2132 : user_token,
2133 479 : map[i].guid,
2134 : SEC_ADS_CONTROL_ACCESS,
2135 : sid);
2136 : } else {
2137 18074 : ret = LDB_SUCCESS;
2138 : }
2139 21027 : if (ret != LDB_SUCCESS) {
2140 36 : break;
2141 : }
2142 : }
2143 : }
2144 28919 : if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2145 36 : switch (ac->req->operation) {
2146 11 : case LDB_ADD:
2147 20 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2148 : "Failed to add %s: %s",
2149 11 : ldb_dn_get_linearized(ac->msg->dn),
2150 2 : map[i].error_string);
2151 11 : break;
2152 25 : case LDB_MODIFY:
2153 48 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
2154 : "Failed to modify %s: %s",
2155 25 : ldb_dn_get_linearized(ac->msg->dn),
2156 2 : map[i].error_string);
2157 25 : break;
2158 0 : default:
2159 0 : return ldb_module_operr(ac->module);
2160 : }
2161 36 : if (map[i].guid) {
2162 7 : dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
2163 : domain_dn,
2164 : true,
2165 : 10);
2166 : }
2167 : }
2168 28690 : return ret;
2169 : }
2170 :
2171 30706 : static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
2172 : struct dom_sid *sid,
2173 : uint32_t req_uac,
2174 : uint32_t user_account_control,
2175 : uint32_t user_account_control_old)
2176 : {
2177 : int ret;
2178 30706 : struct dsdb_control_password_user_account_control *uac = NULL;
2179 :
2180 30706 : ret = samldb_check_user_account_control_invariants(ac, user_account_control);
2181 30706 : if (ret != LDB_SUCCESS) {
2182 20 : return ret;
2183 : }
2184 30686 : ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
2185 30686 : if (ret != LDB_SUCCESS) {
2186 36 : return ret;
2187 : }
2188 :
2189 30650 : uac = talloc_zero(ac->req,
2190 : struct dsdb_control_password_user_account_control);
2191 30650 : if (uac == NULL) {
2192 0 : return ldb_module_oom(ac->module);
2193 : }
2194 :
2195 30650 : uac->req_flags = req_uac;
2196 30650 : uac->old_flags = user_account_control_old;
2197 30650 : uac->new_flags = user_account_control;
2198 :
2199 30650 : ret = ldb_request_add_control(ac->req,
2200 : DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID,
2201 : false, uac);
2202 30324 : if (ret != LDB_SUCCESS) {
2203 0 : return ret;
2204 : }
2205 :
2206 30324 : return ret;
2207 : }
2208 :
2209 :
2210 : /**
2211 : * This function is called on LDB modify operations. It performs some additions/
2212 : * replaces on the current LDB message when "userAccountControl" changes.
2213 : */
2214 10822 : static int samldb_user_account_control_change(struct samldb_ctx *ac)
2215 : {
2216 10822 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2217 : uint32_t old_uac;
2218 : uint32_t new_uac;
2219 : uint32_t raw_uac;
2220 : uint32_t old_ufa;
2221 : uint32_t new_ufa;
2222 : uint32_t old_uac_computed;
2223 : uint32_t clear_uac;
2224 : uint32_t old_atype;
2225 : uint32_t new_atype;
2226 : uint32_t old_pgrid;
2227 : uint32_t new_pgrid;
2228 : NTTIME old_lockoutTime;
2229 : struct ldb_message_element *el;
2230 : struct ldb_val *val;
2231 : struct ldb_val computer_val;
2232 : struct ldb_message *tmp_msg;
2233 : struct dom_sid *sid;
2234 : int ret;
2235 : struct ldb_result *res;
2236 10822 : const char * const attrs[] = {
2237 : "objectClass",
2238 : "isCriticalSystemObject",
2239 : "userAccountControl",
2240 : "msDS-User-Account-Control-Computed",
2241 : "lockoutTime",
2242 : "objectSid",
2243 : NULL
2244 : };
2245 10822 : bool is_computer = false;
2246 10822 : bool old_is_critical = false;
2247 10822 : bool new_is_critical = false;
2248 :
2249 10822 : el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2250 10822 : ac->req->operation);
2251 10822 : if (el == NULL || el->num_values == 0) {
2252 6 : ldb_asprintf_errstring(ldb,
2253 : "%08X: samldb: 'userAccountControl' can't be deleted!",
2254 6 : W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2255 6 : return LDB_ERR_UNWILLING_TO_PERFORM;
2256 : }
2257 :
2258 : /* Create a temporary message for fetching the "userAccountControl" */
2259 10816 : tmp_msg = ldb_msg_new(ac->msg);
2260 10816 : if (tmp_msg == NULL) {
2261 0 : return ldb_module_oom(ac->module);
2262 : }
2263 10816 : ret = ldb_msg_add(tmp_msg, el, 0);
2264 10816 : if (ret != LDB_SUCCESS) {
2265 0 : return ret;
2266 : }
2267 10816 : raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
2268 : "userAccountControl",
2269 : 0);
2270 10816 : talloc_free(tmp_msg);
2271 : /*
2272 : * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
2273 : * are only generated and not stored. We ignore them almost
2274 : * completely, along with unknown bits and UF_SCRIPT.
2275 : *
2276 : * The only exception is ACB_AUTOLOCK, which features in
2277 : * clear_acb when the bit is cleared in this modify operation.
2278 : *
2279 : * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
2280 : * ignored by clients and servers
2281 : */
2282 10816 : new_uac = raw_uac & UF_SETTABLE_BITS;
2283 :
2284 : /* Fetch the old "userAccountControl" and "objectClass" */
2285 10816 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2286 : DSDB_FLAG_NEXT_MODULE, ac->req);
2287 10816 : if (ret != LDB_SUCCESS) {
2288 0 : return ret;
2289 : }
2290 10816 : old_uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
2291 10816 : if (old_uac == 0) {
2292 0 : return ldb_operr(ldb);
2293 : }
2294 10816 : old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
2295 : "msDS-User-Account-Control-Computed", 0);
2296 10816 : old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
2297 : "lockoutTime", 0);
2298 10816 : old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
2299 : "isCriticalSystemObject", 0);
2300 : /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
2301 10816 : el = ldb_msg_find_element(res->msgs[0], "objectClass");
2302 10816 : if (el == NULL) {
2303 0 : return ldb_operr(ldb);
2304 : }
2305 10816 : computer_val = data_blob_string_const("computer");
2306 10816 : val = ldb_msg_find_val(el, &computer_val);
2307 10816 : if (val != NULL) {
2308 1325 : is_computer = true;
2309 : }
2310 :
2311 10816 : old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
2312 10816 : old_atype = ds_uf2atype(old_ufa);
2313 10816 : old_pgrid = ds_uf2prim_group_rid(old_uac);
2314 :
2315 10816 : new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
2316 10816 : if (new_ufa == 0) {
2317 : /*
2318 : * "userAccountControl" = 0 or missing one of the
2319 : * types means "UF_NORMAL_ACCOUNT". See MS-SAMR
2320 : * 3.1.1.8.10 point 8
2321 : */
2322 220 : new_ufa = UF_NORMAL_ACCOUNT;
2323 220 : new_uac |= new_ufa;
2324 : }
2325 10816 : sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2326 10816 : if (sid == NULL) {
2327 0 : return ldb_module_operr(ac->module);
2328 : }
2329 :
2330 10816 : ret = samldb_check_user_account_control_rules(ac, sid,
2331 : raw_uac,
2332 : new_uac,
2333 : old_uac);
2334 10816 : if (ret != LDB_SUCCESS) {
2335 38 : return ret;
2336 : }
2337 :
2338 10778 : new_atype = ds_uf2atype(new_ufa);
2339 10778 : new_pgrid = ds_uf2prim_group_rid(new_uac);
2340 :
2341 10778 : clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
2342 :
2343 10778 : switch (new_ufa) {
2344 9682 : case UF_NORMAL_ACCOUNT:
2345 9682 : new_is_critical = old_is_critical;
2346 9682 : break;
2347 :
2348 0 : case UF_INTERDOMAIN_TRUST_ACCOUNT:
2349 0 : new_is_critical = true;
2350 0 : break;
2351 :
2352 536 : case UF_WORKSTATION_TRUST_ACCOUNT:
2353 536 : new_is_critical = false;
2354 536 : if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
2355 94 : if (!is_computer) {
2356 3 : ldb_asprintf_errstring(ldb,
2357 : "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
2358 : "requires objectclass 'computer'!",
2359 3 : W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2360 3 : return LDB_ERR_UNWILLING_TO_PERFORM;
2361 : }
2362 91 : new_is_critical = true;
2363 : }
2364 497 : break;
2365 :
2366 523 : case UF_SERVER_TRUST_ACCOUNT:
2367 523 : if (!is_computer) {
2368 3 : ldb_asprintf_errstring(ldb,
2369 : "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
2370 : "requires objectclass 'computer'!",
2371 3 : W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
2372 3 : return LDB_ERR_UNWILLING_TO_PERFORM;
2373 : }
2374 484 : new_is_critical = true;
2375 484 : break;
2376 :
2377 0 : default:
2378 0 : ldb_asprintf_errstring(ldb,
2379 : "%08X: samldb: invalid userAccountControl[0x%08X]",
2380 0 : W_ERROR_V(WERR_INVALID_PARAMETER), raw_uac);
2381 0 : return LDB_ERR_OTHER;
2382 : }
2383 :
2384 10772 : if (old_atype != new_atype) {
2385 105 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2386 : "sAMAccountType", new_atype);
2387 105 : if (ret != LDB_SUCCESS) {
2388 0 : return ret;
2389 : }
2390 105 : el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2391 105 : el->flags = LDB_FLAG_MOD_REPLACE;
2392 : }
2393 :
2394 : /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
2395 10772 : if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
2396 : /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
2397 10 : ldb_msg_remove_attr(ac->msg, "lockoutTime");
2398 10 : ret = samdb_msg_add_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
2399 : (NTTIME)0);
2400 10 : if (ret != LDB_SUCCESS) {
2401 0 : return ret;
2402 : }
2403 10 : el = ldb_msg_find_element(ac->msg, "lockoutTime");
2404 10 : el->flags = LDB_FLAG_MOD_REPLACE;
2405 : }
2406 :
2407 : /* "isCriticalSystemObject" might be set/changed */
2408 10772 : if (old_is_critical != new_is_critical) {
2409 44 : ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
2410 : new_is_critical ? "TRUE": "FALSE");
2411 44 : if (ret != LDB_SUCCESS) {
2412 0 : return ret;
2413 : }
2414 44 : el = ldb_msg_find_element(ac->msg,
2415 : "isCriticalSystemObject");
2416 44 : el->flags = LDB_FLAG_MOD_REPLACE;
2417 : }
2418 :
2419 10772 : if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
2420 : (old_pgrid != new_pgrid)) {
2421 : /* Older AD deployments don't know about the RODC group */
2422 137 : if (new_pgrid == DOMAIN_RID_READONLY_DCS) {
2423 9 : ret = samldb_prim_group_tester(ac, new_pgrid);
2424 9 : if (ret != LDB_SUCCESS) {
2425 0 : return ret;
2426 : }
2427 : }
2428 :
2429 137 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg,
2430 : "primaryGroupID", new_pgrid);
2431 137 : if (ret != LDB_SUCCESS) {
2432 0 : return ret;
2433 : }
2434 137 : el = ldb_msg_find_element(ac->msg,
2435 : "primaryGroupID");
2436 137 : el->flags = LDB_FLAG_MOD_REPLACE;
2437 : }
2438 :
2439 : /* Propagate eventual "userAccountControl" attribute changes */
2440 10772 : if (old_uac != new_uac) {
2441 10328 : char *tempstr = talloc_asprintf(ac->msg, "%d",
2442 : new_uac);
2443 10328 : if (tempstr == NULL) {
2444 0 : return ldb_module_oom(ac->module);
2445 : }
2446 :
2447 : /* Overwrite "userAccountControl" correctly */
2448 10328 : el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
2449 10328 : ac->req->operation);
2450 10328 : el->values[0].data = (uint8_t *) tempstr;
2451 10328 : el->values[0].length = strlen(tempstr);
2452 : } else {
2453 444 : ldb_msg_remove_attr(ac->msg, "userAccountControl");
2454 : }
2455 :
2456 10663 : return LDB_SUCCESS;
2457 : }
2458 :
2459 83 : static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac,
2460 : struct dom_sid *sid)
2461 : {
2462 83 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2463 83 : int ret = 0;
2464 83 : struct ldb_result *res = NULL;
2465 83 : const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
2466 83 : struct security_token *user_token = NULL;
2467 83 : struct security_descriptor *domain_sd = NULL;
2468 83 : struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
2469 83 : const char *operation = "";
2470 :
2471 83 : if (dsdb_module_am_system(ac->module)) {
2472 1 : return LDB_SUCCESS;
2473 : }
2474 :
2475 82 : switch (ac->req->operation) {
2476 0 : case LDB_ADD:
2477 0 : operation = "add";
2478 0 : break;
2479 82 : case LDB_MODIFY:
2480 82 : operation = "modify";
2481 82 : break;
2482 0 : default:
2483 0 : return ldb_module_operr(ac->module);
2484 : }
2485 :
2486 82 : user_token = acl_user_token(ac->module);
2487 82 : if (user_token == NULL) {
2488 0 : return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
2489 : }
2490 :
2491 82 : ret = dsdb_module_search_dn(ac->module, ac, &res,
2492 : domain_dn,
2493 : sd_attrs,
2494 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
2495 : ac->req);
2496 82 : if (ret != LDB_SUCCESS) {
2497 0 : return ret;
2498 : }
2499 82 : if (res->count != 1) {
2500 0 : return ldb_module_operr(ac->module);
2501 : }
2502 :
2503 82 : ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd);
2504 82 : if (ret != LDB_SUCCESS) {
2505 0 : return ret;
2506 : }
2507 :
2508 82 : ret = acl_check_extended_right(ac, domain_sd,
2509 : user_token,
2510 : GUID_DRS_UNEXPIRE_PASSWORD,
2511 : SEC_ADS_CONTROL_ACCESS,
2512 : sid);
2513 82 : if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2514 82 : return ret;
2515 : }
2516 :
2517 0 : ldb_debug_set(ldb, LDB_DEBUG_WARNING,
2518 : "Failed to %s %s: "
2519 : "Setting pwdLastSet to -1 requires the "
2520 : "Unexpire-Password right that was not given "
2521 : "on the Domain object",
2522 : operation,
2523 0 : ldb_dn_get_linearized(ac->msg->dn));
2524 0 : dsdb_acl_debug(domain_sd, user_token,
2525 : domain_dn, true, 10);
2526 :
2527 0 : return ret;
2528 : }
2529 :
2530 : /**
2531 : * This function is called on LDB modify operations. It performs some additions/
2532 : * replaces on the current LDB message when "pwdLastSet" changes.
2533 : */
2534 356 : static int samldb_pwd_last_set_change(struct samldb_ctx *ac)
2535 : {
2536 356 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2537 356 : NTTIME last_set = 0;
2538 356 : struct ldb_message_element *el = NULL;
2539 356 : struct ldb_message *tmp_msg = NULL;
2540 356 : struct dom_sid *self_sid = NULL;
2541 : int ret;
2542 356 : struct ldb_result *res = NULL;
2543 356 : const char * const attrs[] = {
2544 : "objectSid",
2545 : NULL
2546 : };
2547 :
2548 356 : el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet",
2549 356 : ac->req->operation);
2550 356 : if (el == NULL || el->num_values == 0) {
2551 6 : ldb_asprintf_errstring(ldb,
2552 : "%08X: samldb: 'pwdLastSet' can't be deleted!",
2553 6 : W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2554 6 : return LDB_ERR_UNWILLING_TO_PERFORM;
2555 : }
2556 :
2557 : /* Create a temporary message for fetching the "userAccountControl" */
2558 350 : tmp_msg = ldb_msg_new(ac->msg);
2559 350 : if (tmp_msg == NULL) {
2560 0 : return ldb_module_oom(ac->module);
2561 : }
2562 350 : ret = ldb_msg_add(tmp_msg, el, 0);
2563 350 : if (ret != LDB_SUCCESS) {
2564 0 : return ret;
2565 : }
2566 350 : last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0);
2567 350 : talloc_free(tmp_msg);
2568 :
2569 : /*
2570 : * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
2571 : */
2572 350 : if (last_set != UINT64_MAX) {
2573 256 : return LDB_SUCCESS;
2574 : }
2575 :
2576 : /* Fetch the "objectSid" */
2577 83 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2578 : DSDB_FLAG_NEXT_MODULE, ac->req);
2579 83 : if (ret != LDB_SUCCESS) {
2580 0 : return ret;
2581 : }
2582 83 : self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2583 83 : if (self_sid == NULL) {
2584 0 : return ldb_module_operr(ac->module);
2585 : }
2586 :
2587 83 : ret = samldb_check_pwd_last_set_acl(ac, self_sid);
2588 83 : if (ret != LDB_SUCCESS) {
2589 0 : return ret;
2590 : }
2591 :
2592 83 : return LDB_SUCCESS;
2593 : }
2594 :
2595 157 : static int samldb_lockout_time(struct samldb_ctx *ac)
2596 : {
2597 157 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2598 : NTTIME lockoutTime;
2599 : struct ldb_message_element *el;
2600 : struct ldb_message *tmp_msg;
2601 : int ret;
2602 :
2603 157 : el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime",
2604 157 : ac->req->operation);
2605 157 : if (el == NULL || el->num_values == 0) {
2606 0 : ldb_asprintf_errstring(ldb,
2607 : "%08X: samldb: 'lockoutTime' can't be deleted!",
2608 0 : W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
2609 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
2610 : }
2611 :
2612 : /* Create a temporary message for fetching the "lockoutTime" */
2613 157 : tmp_msg = ldb_msg_new(ac->msg);
2614 157 : if (tmp_msg == NULL) {
2615 0 : return ldb_module_oom(ac->module);
2616 : }
2617 157 : ret = ldb_msg_add(tmp_msg, el, 0);
2618 157 : if (ret != LDB_SUCCESS) {
2619 0 : return ret;
2620 : }
2621 157 : lockoutTime = ldb_msg_find_attr_as_int64(tmp_msg,
2622 : "lockoutTime",
2623 : 0);
2624 157 : talloc_free(tmp_msg);
2625 :
2626 157 : if (lockoutTime != 0) {
2627 55 : return LDB_SUCCESS;
2628 : }
2629 :
2630 : /* lockoutTime == 0 resets badPwdCount */
2631 102 : ldb_msg_remove_attr(ac->msg, "badPwdCount");
2632 102 : ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
2633 : "badPwdCount", 0);
2634 102 : if (ret != LDB_SUCCESS) {
2635 0 : return ret;
2636 : }
2637 102 : el = ldb_msg_find_element(ac->msg, "badPwdCount");
2638 102 : el->flags = LDB_FLAG_MOD_REPLACE;
2639 :
2640 102 : return LDB_SUCCESS;
2641 : }
2642 :
2643 102 : static int samldb_group_type_change(struct samldb_ctx *ac)
2644 : {
2645 102 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2646 : uint32_t group_type, old_group_type, account_type;
2647 : struct ldb_message_element *el;
2648 : struct ldb_message *tmp_msg;
2649 : int ret;
2650 : struct ldb_result *res;
2651 102 : const char * const attrs[] = { "groupType", NULL };
2652 :
2653 102 : el = dsdb_get_single_valued_attr(ac->msg, "groupType",
2654 102 : ac->req->operation);
2655 102 : if (el == NULL) {
2656 : /* we are not affected */
2657 3 : return LDB_SUCCESS;
2658 : }
2659 :
2660 : /* Create a temporary message for fetching the "groupType" */
2661 99 : tmp_msg = ldb_msg_new(ac->msg);
2662 99 : if (tmp_msg == NULL) {
2663 0 : return ldb_module_oom(ac->module);
2664 : }
2665 99 : ret = ldb_msg_add(tmp_msg, el, 0);
2666 99 : if (ret != LDB_SUCCESS) {
2667 0 : return ret;
2668 : }
2669 99 : group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
2670 99 : talloc_free(tmp_msg);
2671 :
2672 99 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
2673 : DSDB_FLAG_NEXT_MODULE |
2674 : DSDB_SEARCH_SHOW_DELETED, ac->req);
2675 99 : if (ret != LDB_SUCCESS) {
2676 0 : return ret;
2677 : }
2678 99 : old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
2679 99 : if (old_group_type == 0) {
2680 0 : return ldb_operr(ldb);
2681 : }
2682 :
2683 : /* Group type switching isn't so easy as it seems: We can only
2684 : * change in this directions: global <-> universal <-> local
2685 : * On each step also the group type itself
2686 : * (security/distribution) is variable. */
2687 :
2688 99 : if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
2689 99 : switch (group_type) {
2690 39 : case GTYPE_SECURITY_GLOBAL_GROUP:
2691 : case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
2692 : /* change to "universal" allowed */
2693 39 : if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
2694 0 : (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
2695 9 : ldb_set_errstring(ldb,
2696 : "samldb: Change from security/distribution local group forbidden!");
2697 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
2698 : }
2699 30 : break;
2700 :
2701 27 : case GTYPE_SECURITY_UNIVERSAL_GROUP:
2702 : case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
2703 : /* each change allowed */
2704 27 : break;
2705 18 : case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
2706 : case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
2707 : /* change to "universal" allowed */
2708 18 : if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
2709 0 : (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
2710 9 : ldb_set_errstring(ldb,
2711 : "samldb: Change from security/distribution global group forbidden!");
2712 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
2713 : }
2714 9 : break;
2715 :
2716 15 : case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
2717 : default:
2718 : /* we don't allow this "groupType" values */
2719 15 : return LDB_ERR_UNWILLING_TO_PERFORM;
2720 : break;
2721 : }
2722 0 : }
2723 :
2724 66 : account_type = ds_gtype2atype(group_type);
2725 66 : if (account_type == 0) {
2726 0 : ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
2727 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
2728 : }
2729 66 : ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
2730 : account_type);
2731 66 : if (ret != LDB_SUCCESS) {
2732 0 : return ret;
2733 : }
2734 66 : el = ldb_msg_find_element(ac->msg, "sAMAccountType");
2735 66 : el->flags = LDB_FLAG_MOD_REPLACE;
2736 :
2737 66 : return LDB_SUCCESS;
2738 : }
2739 :
2740 3127 : static int samldb_member_check(struct samldb_ctx *ac)
2741 : {
2742 3127 : const char * const attrs[] = { "objectSid", NULL };
2743 3127 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2744 : struct ldb_message_element *el;
2745 : struct ldb_dn *member_dn;
2746 : struct dom_sid *sid;
2747 : struct ldb_result *res;
2748 : struct dom_sid *group_sid;
2749 : unsigned int i, j;
2750 : int ret;
2751 :
2752 : /* Fetch information from the existing object */
2753 :
2754 3127 : ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2755 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
2756 3127 : if (ret != LDB_SUCCESS) {
2757 0 : return ret;
2758 : }
2759 3127 : if (res->count != 1) {
2760 0 : return ldb_operr(ldb);
2761 : }
2762 :
2763 3127 : group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
2764 3127 : if (group_sid == NULL) {
2765 0 : return ldb_operr(ldb);
2766 : }
2767 :
2768 : /* We've to walk over all modification entries and consider the "member"
2769 : * ones. */
2770 10295 : for (i = 0; i < ac->msg->num_elements; i++) {
2771 7210 : if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
2772 0 : continue;
2773 : }
2774 :
2775 7171 : el = &ac->msg->elements[i];
2776 14736 : for (j = 0; j < el->num_values; j++) {
2777 : struct ldb_result *group_res;
2778 7568 : const char *group_attrs[] = { "primaryGroupID" , NULL };
2779 : uint32_t prim_group_rid;
2780 :
2781 7568 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
2782 : /* Deletes will be handled in
2783 : * repl_meta_data, and deletes not
2784 : * matching a member will return
2785 : * LDB_ERR_UNWILLING_TO_PERFORM
2786 : * there */
2787 976 : continue;
2788 : }
2789 :
2790 7191 : member_dn = ldb_dn_from_ldb_val(ac, ldb,
2791 7191 : &el->values[j]);
2792 7191 : if (!ldb_dn_validate(member_dn)) {
2793 3 : return ldb_operr(ldb);
2794 : }
2795 :
2796 : /* Denies to add "member"s to groups which are primary
2797 : * ones for them - in this case return
2798 : * ERR_ENTRY_ALREADY_EXISTS. */
2799 :
2800 7191 : ret = dsdb_module_search_dn(ac->module, ac, &group_res,
2801 : member_dn, group_attrs,
2802 : DSDB_FLAG_NEXT_MODULE, ac->req);
2803 7191 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2804 : /* member DN doesn't exist yet */
2805 0 : continue;
2806 : }
2807 7191 : if (ret != LDB_SUCCESS) {
2808 0 : return ret;
2809 : }
2810 7191 : prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
2811 7191 : if (prim_group_rid == (uint32_t) -1) {
2812 : /* the member hasn't to be a user account ->
2813 : * therefore no check needed in this case. */
2814 266 : continue;
2815 : }
2816 :
2817 6925 : sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
2818 : prim_group_rid);
2819 6925 : if (sid == NULL) {
2820 0 : return ldb_operr(ldb);
2821 : }
2822 :
2823 6925 : if (dom_sid_equal(group_sid, sid)) {
2824 3 : ldb_asprintf_errstring(ldb,
2825 : "samldb: member %s already set via primaryGroupID %u",
2826 : ldb_dn_get_linearized(member_dn), prim_group_rid);
2827 3 : return LDB_ERR_ENTRY_ALREADY_EXISTS;
2828 : }
2829 : }
2830 : }
2831 :
2832 3124 : talloc_free(res);
2833 :
2834 3124 : return LDB_SUCCESS;
2835 : }
2836 :
2837 : /* SAM objects have special rules regarding the "description" attribute on
2838 : * modify operations. */
2839 1056 : static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
2840 : {
2841 1056 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2842 1056 : const char * const attrs[] = { "objectClass", "description", NULL };
2843 : struct ldb_result *res;
2844 : unsigned int i;
2845 : int ret;
2846 :
2847 : /* Fetch information from the existing object */
2848 1056 : ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
2849 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
2850 : "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
2851 1056 : if (ret != LDB_SUCCESS) {
2852 : /* don't treat it specially ... let normal error codes
2853 : happen from other places */
2854 0 : ldb_reset_err_string(ldb);
2855 0 : return LDB_SUCCESS;
2856 : }
2857 1056 : if (res->count == 0) {
2858 : /* we didn't match the filter */
2859 299 : talloc_free(res);
2860 299 : return LDB_SUCCESS;
2861 : }
2862 :
2863 : /* We've to walk over all modification entries and consider the
2864 : * "description" ones. */
2865 2554 : for (i = 0; i < ac->msg->num_elements; i++) {
2866 1872 : if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
2867 760 : ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
2868 760 : *modified = true;
2869 : }
2870 : }
2871 :
2872 757 : talloc_free(res);
2873 :
2874 757 : return LDB_SUCCESS;
2875 : }
2876 :
2877 : /* This trigger adapts the "servicePrincipalName" attributes if the
2878 : * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
2879 1394 : static int samldb_service_principal_names_change(struct samldb_ctx *ac)
2880 : {
2881 1394 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
2882 1394 : struct ldb_message_element *el = NULL, *el2 = NULL;
2883 : struct ldb_message *msg;
2884 1394 : const char * const attrs[] = { "servicePrincipalName", NULL };
2885 : struct ldb_result *res;
2886 1394 : const char *dns_hostname = NULL, *old_dns_hostname = NULL,
2887 1394 : *sam_accountname = NULL, *old_sam_accountname = NULL;
2888 : unsigned int i, j;
2889 : int ret;
2890 :
2891 1783 : el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
2892 1394 : ac->req->operation);
2893 1394 : el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
2894 1394 : ac->req->operation);
2895 1394 : if ((el == NULL) && (el2 == NULL)) {
2896 : /* we are not affected */
2897 9 : return LDB_SUCCESS;
2898 : }
2899 :
2900 : /* Create a temporary message for fetching the "dNSHostName" */
2901 1385 : if (el != NULL) {
2902 631 : const char *dns_attrs[] = { "dNSHostName", NULL };
2903 631 : msg = ldb_msg_new(ac->msg);
2904 631 : if (msg == NULL) {
2905 0 : return ldb_module_oom(ac->module);
2906 : }
2907 631 : ret = ldb_msg_add(msg, el, 0);
2908 631 : if (ret != LDB_SUCCESS) {
2909 0 : return ret;
2910 : }
2911 631 : dns_hostname = talloc_strdup(ac,
2912 : ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
2913 631 : if (dns_hostname == NULL) {
2914 0 : return ldb_module_oom(ac->module);
2915 : }
2916 :
2917 631 : talloc_free(msg);
2918 :
2919 631 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
2920 : dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
2921 631 : if (ret == LDB_SUCCESS) {
2922 631 : old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
2923 : }
2924 : }
2925 :
2926 : /* Create a temporary message for fetching the "sAMAccountName" */
2927 1385 : if (el2 != NULL) {
2928 767 : char *tempstr, *tempstr2 = NULL;
2929 767 : const char *acct_attrs[] = { "sAMAccountName", NULL };
2930 :
2931 767 : msg = ldb_msg_new(ac->msg);
2932 767 : if (msg == NULL) {
2933 0 : return ldb_module_oom(ac->module);
2934 : }
2935 767 : ret = ldb_msg_add(msg, el2, 0);
2936 767 : if (ret != LDB_SUCCESS) {
2937 0 : return ret;
2938 : }
2939 767 : tempstr = talloc_strdup(ac,
2940 : ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
2941 767 : talloc_free(msg);
2942 :
2943 767 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
2944 : DSDB_FLAG_NEXT_MODULE, ac->req);
2945 767 : if (ret == LDB_SUCCESS) {
2946 767 : tempstr2 = talloc_strdup(ac,
2947 767 : ldb_msg_find_attr_as_string(res->msgs[0],
2948 : "sAMAccountName", NULL));
2949 : }
2950 :
2951 :
2952 : /* The "sAMAccountName" needs some additional trimming: we need
2953 : * to remove the trailing "$"s if they exist. */
2954 1278 : if ((tempstr != NULL) && (tempstr[0] != '\0') &&
2955 761 : (tempstr[strlen(tempstr) - 1] == '$')) {
2956 175 : tempstr[strlen(tempstr) - 1] = '\0';
2957 : }
2958 1282 : if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
2959 767 : (tempstr2[strlen(tempstr2) - 1] == '$')) {
2960 178 : tempstr2[strlen(tempstr2) - 1] = '\0';
2961 : }
2962 767 : sam_accountname = tempstr;
2963 767 : old_sam_accountname = tempstr2;
2964 : }
2965 :
2966 1385 : if (old_dns_hostname == NULL) {
2967 : /* we cannot change when the old name is unknown */
2968 1303 : dns_hostname = NULL;
2969 : }
2970 1467 : if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
2971 82 : (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
2972 : /* The "dNSHostName" didn't change */
2973 39 : dns_hostname = NULL;
2974 : }
2975 :
2976 1385 : if (old_sam_accountname == NULL) {
2977 : /* we cannot change when the old name is unknown */
2978 618 : sam_accountname = NULL;
2979 : }
2980 2146 : if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
2981 761 : (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
2982 : /* The "sAMAccountName" didn't change */
2983 471 : sam_accountname = NULL;
2984 : }
2985 :
2986 1385 : if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
2987 : /* Well, there are information missing (old name(s)) or the
2988 : * names didn't change. We've nothing to do and can exit here */
2989 982 : return LDB_SUCCESS;
2990 : }
2991 :
2992 : /* Potential "servicePrincipalName" changes in the same request have to
2993 : * be handled before the update (Windows behaviour). */
2994 325 : el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
2995 325 : if (el != NULL) {
2996 23 : msg = ldb_msg_new(ac->msg);
2997 23 : if (msg == NULL) {
2998 0 : return ldb_module_oom(ac->module);
2999 : }
3000 23 : msg->dn = ac->msg->dn;
3001 :
3002 : do {
3003 23 : ret = ldb_msg_add(msg, el, el->flags);
3004 23 : if (ret != LDB_SUCCESS) {
3005 0 : return ret;
3006 : }
3007 :
3008 23 : ldb_msg_remove_element(ac->msg, el);
3009 :
3010 23 : el = ldb_msg_find_element(ac->msg,
3011 : "servicePrincipalName");
3012 23 : } while (el != NULL);
3013 :
3014 23 : ret = dsdb_module_modify(ac->module, msg,
3015 : DSDB_FLAG_NEXT_MODULE, ac->req);
3016 23 : if (ret != LDB_SUCCESS) {
3017 0 : return ret;
3018 : }
3019 23 : talloc_free(msg);
3020 : }
3021 :
3022 : /* Fetch the "servicePrincipalName"s if any */
3023 325 : ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
3024 : DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
3025 325 : if (ret != LDB_SUCCESS) {
3026 0 : return ret;
3027 : }
3028 325 : if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
3029 0 : return ldb_operr(ldb);
3030 : }
3031 :
3032 325 : if (res->msgs[0]->num_elements == 1) {
3033 : /*
3034 : * Yes, we do have "servicePrincipalName"s. First we update them
3035 : * locally, that means we do always substitute the current
3036 : * "dNSHostName" with the new one and/or "sAMAccountName"
3037 : * without "$" with the new one and then we append the
3038 : * modified "servicePrincipalName"s as a message element
3039 : * replace to the modification request (Windows behaviour). We
3040 : * need also to make sure that the values remain case-
3041 : * insensitively unique.
3042 : */
3043 :
3044 48 : ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
3045 : LDB_FLAG_MOD_REPLACE, &el);
3046 48 : if (ret != LDB_SUCCESS) {
3047 0 : return ret;
3048 : }
3049 :
3050 143 : for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
3051 : char *old_str, *new_str;
3052 95 : char *pos = NULL;
3053 : const char *tok;
3054 : struct ldb_val *vals;
3055 95 : bool found = false;
3056 :
3057 95 : old_str = (char *)
3058 95 : res->msgs[0]->elements[0].values[i].data;
3059 :
3060 95 : new_str = talloc_strdup(ac->msg,
3061 95 : strtok_r(old_str, "/", &pos));
3062 95 : if (new_str == NULL) {
3063 0 : return ldb_module_oom(ac->module);
3064 : }
3065 :
3066 258 : while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
3067 178 : if ((dns_hostname != NULL) &&
3068 83 : (strcasecmp_m(tok, old_dns_hostname) == 0)) {
3069 39 : tok = dns_hostname;
3070 : }
3071 119 : if ((sam_accountname != NULL) &&
3072 24 : (strcasecmp_m(tok, old_sam_accountname) == 0)) {
3073 15 : tok = sam_accountname;
3074 : }
3075 :
3076 95 : new_str = talloc_asprintf(ac->msg, "%s/%s",
3077 : new_str, tok);
3078 95 : if (new_str == NULL) {
3079 0 : return ldb_module_oom(ac->module);
3080 : }
3081 : }
3082 :
3083 : /* Uniqueness check */
3084 161 : for (j = 0; (!found) && (j < el->num_values); j++) {
3085 66 : if (strcasecmp_m((char *)el->values[j].data,
3086 : new_str) == 0) {
3087 15 : found = true;
3088 : }
3089 : }
3090 95 : if (found) {
3091 15 : continue;
3092 : }
3093 :
3094 : /*
3095 : * append the new "servicePrincipalName" -
3096 : * code derived from ldb_msg_add_value().
3097 : *
3098 : * Open coded to make it clear that we must
3099 : * append to the MOD_REPLACE el created above.
3100 : */
3101 80 : vals = talloc_realloc(ac->msg, el->values,
3102 : struct ldb_val,
3103 : el->num_values + 1);
3104 80 : if (vals == NULL) {
3105 0 : return ldb_module_oom(ac->module);
3106 : }
3107 80 : el->values = vals;
3108 80 : el->values[el->num_values] = data_blob_string_const(new_str);
3109 80 : ++(el->num_values);
3110 : }
3111 : }
3112 :
3113 325 : talloc_free(res);
3114 :
3115 325 : return LDB_SUCCESS;
3116 : }
3117 :
3118 : /* This checks the "fSMORoleOwner" attributes */
3119 1244 : static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
3120 : {
3121 1244 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3122 1244 : const char * const no_attrs[] = { NULL };
3123 : struct ldb_message_element *el;
3124 : struct ldb_message *tmp_msg;
3125 : struct ldb_dn *res_dn;
3126 : struct ldb_result *res;
3127 : int ret;
3128 :
3129 1244 : el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
3130 1244 : ac->req->operation);
3131 1244 : if (el == NULL) {
3132 : /* we are not affected */
3133 3 : return LDB_SUCCESS;
3134 : }
3135 :
3136 : /* Create a temporary message for fetching the "fSMORoleOwner" */
3137 1241 : tmp_msg = ldb_msg_new(ac->msg);
3138 1241 : if (tmp_msg == NULL) {
3139 0 : return ldb_module_oom(ac->module);
3140 : }
3141 1241 : ret = ldb_msg_add(tmp_msg, el, 0);
3142 1241 : if (ret != LDB_SUCCESS) {
3143 0 : return ret;
3144 : }
3145 1241 : res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
3146 1241 : talloc_free(tmp_msg);
3147 :
3148 1241 : if (res_dn == NULL) {
3149 6 : ldb_set_errstring(ldb,
3150 : "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3151 6 : if (ac->req->operation == LDB_ADD) {
3152 3 : return LDB_ERR_CONSTRAINT_VIOLATION;
3153 : } else {
3154 3 : return LDB_ERR_UNWILLING_TO_PERFORM;
3155 : }
3156 : }
3157 :
3158 : /* Fetched DN has to reference a "nTDSDSA" entry */
3159 1235 : ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
3160 : no_attrs,
3161 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3162 : ac->req, "(objectClass=nTDSDSA)");
3163 1235 : if (ret != LDB_SUCCESS) {
3164 0 : return ret;
3165 : }
3166 1235 : if (res->count != 1) {
3167 6 : ldb_set_errstring(ldb,
3168 : "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
3169 6 : return LDB_ERR_UNWILLING_TO_PERFORM;
3170 : }
3171 :
3172 1229 : talloc_free(res);
3173 :
3174 1229 : return LDB_SUCCESS;
3175 : }
3176 :
3177 : /*
3178 : * Return zero if the number of zero bits in the address (looking from low to
3179 : * high) is equal to or greater than the length minus the mask. Otherwise it
3180 : * returns -1.
3181 : */
3182 138 : static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
3183 : unsigned int mask)
3184 : {
3185 : /* <address> is an integer in big-endian form, <len> bits long. All
3186 : bits between <mask> and <len> must be zero. */
3187 : int i;
3188 : unsigned int byte_len;
3189 : unsigned int byte_mask;
3190 : unsigned int bit_mask;
3191 138 : if (len == 32) {
3192 58 : DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
3193 : address[0], address[1], address[2], address[3],
3194 : mask);
3195 80 : } else if (len == 128){
3196 80 : DBG_INFO("Looking at address "
3197 : "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
3198 : "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
3199 : address[0], address[1], address[2], address[3],
3200 : address[4], address[5], address[6], address[7],
3201 : address[8], address[9], address[10], address[11],
3202 : address[12], address[13], address[14], address[15],
3203 : mask);
3204 : }
3205 :
3206 138 : if (mask > len){
3207 5 : DBG_INFO("mask %u is too big (> %u)\n", mask, len);
3208 5 : return -1;
3209 : }
3210 133 : if (mask == len){
3211 : /* single address subnet.
3212 : * In IPv4 all 255s is invalid by the bitmask != address rule
3213 : * in MS-ADTS. IPv6 does not suffer.
3214 : */
3215 10 : if (len == 32){
3216 6 : if (address[0] == 255 &&
3217 2 : address[1] == 255 &&
3218 2 : address[2] == 255 &&
3219 1 : address[3] == 255){
3220 1 : return -1;
3221 : }
3222 : }
3223 9 : return 0;
3224 : }
3225 :
3226 123 : byte_len = len / 8;
3227 123 : byte_mask = mask / 8;
3228 :
3229 714 : for (i = byte_len - 1; i > byte_mask; i--){
3230 593 : DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
3231 593 : if (address[i] != 0){
3232 2 : return -1;
3233 : }
3234 : }
3235 121 : bit_mask = (1 << (8 - (mask & 7))) - 1;
3236 121 : DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
3237 : bit_mask & address[byte_mask]);
3238 121 : if (address[byte_mask] & bit_mask){
3239 15 : return -1;
3240 : }
3241 :
3242 : /* According to MS-ADTS, the mask can't exactly equal the bitmask for
3243 : * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
3244 : * because the bitmask implied by "/17" is 255.255.80.0.
3245 : *
3246 : * The bit_mask used in the previous check is the complement of what
3247 : * we want here.
3248 : */
3249 106 : if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
3250 35 : bool ok = false;
3251 39 : for (i = 0; i < byte_mask; i++){
3252 35 : if (address[i] != 255){
3253 31 : ok = true;
3254 31 : break;
3255 : }
3256 : }
3257 35 : if (ok == false){
3258 4 : return -1;
3259 : }
3260 : }
3261 102 : return 0;
3262 : }
3263 :
3264 :
3265 :
3266 163 : static int check_address_roundtrip(const char *address, int family,
3267 : const uint8_t *address_bytes,
3268 : char *buffer, int buffer_len)
3269 : {
3270 : /*
3271 : * Check that the address is in the canonical RFC5952 format for IPv6,
3272 : * and lacks extra leading zeros for each dotted decimal for IPv4.
3273 : * Handily this is what inet_ntop() gives you.
3274 : */
3275 163 : const char *address_redux = inet_ntop(family, address_bytes,
3276 : buffer, buffer_len);
3277 163 : if (address_redux == NULL){
3278 0 : DBG_INFO("Address round trip %s failed unexpectedly"
3279 : " with errno %d\n", address, errno);
3280 0 : return -1;
3281 : }
3282 163 : if (strcasecmp(address, address_redux) != 0){
3283 25 : DBG_INFO("Address %s round trips to %s; fail!\n",
3284 : address, address_redux);
3285 : /* If the address family is IPv6, and the address is in a
3286 : certain range
3287 :
3288 : */
3289 25 : if (strchr(address_redux, '.') != NULL){
3290 7 : DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
3291 : "lying in a range that was once used for "
3292 : "IPv4 embedding (that is, it might also be "
3293 : "represented as '%s').\n", address,
3294 : address_redux));
3295 : }
3296 25 : return -1;
3297 : }
3298 138 : return 0;
3299 : }
3300 :
3301 :
3302 :
3303 : /*
3304 : * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
3305 : * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
3306 : * CIDR address range without saying so explicitly. Here we follow the CIDR
3307 : * spec.
3308 : *
3309 : * Return 0 on success, -1 on error.
3310 : */
3311 208 : static int verify_cidr(const char *cidr)
3312 : {
3313 208 : char *address = NULL, *slash = NULL;
3314 : bool has_colon, has_dot;
3315 : int res, ret;
3316 : unsigned long mask;
3317 208 : uint8_t *address_bytes = NULL;
3318 208 : char *address_redux = NULL;
3319 : unsigned int address_len;
3320 208 : TALLOC_CTX *frame = NULL;
3321 208 : int error = 0;
3322 :
3323 208 : DBG_DEBUG("CIDR is %s\n", cidr);
3324 208 : frame = talloc_stackframe();
3325 208 : address = talloc_strdup(frame, cidr);
3326 208 : if (address == NULL){
3327 0 : goto error;
3328 : }
3329 :
3330 : /* there must be a '/' */
3331 208 : slash = strchr(address, '/');
3332 208 : if (slash == NULL){
3333 2 : goto error;
3334 : }
3335 : /* terminate the address for strchr, inet_pton */
3336 206 : *slash = '\0';
3337 :
3338 206 : mask = smb_strtoul(slash + 1, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
3339 206 : if (mask == 0){
3340 6 : DBG_INFO("Windows does not like the zero mask, "
3341 : "so nor do we: %s\n", cidr);
3342 6 : goto error;
3343 : }
3344 :
3345 200 : if (error != 0){
3346 6 : DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
3347 6 : goto error;
3348 : }
3349 :
3350 194 : address_bytes = talloc_size(frame, sizeof(struct in6_addr));
3351 194 : if (address_bytes == NULL){
3352 0 : goto error;
3353 : }
3354 :
3355 194 : address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
3356 194 : if (address_redux == NULL){
3357 0 : goto error;
3358 : }
3359 :
3360 194 : DBG_INFO("found address %s, mask %lu\n", address, mask);
3361 194 : has_colon = (strchr(address, ':') == NULL) ? false : true;
3362 194 : has_dot = (strchr(address, '.') == NULL) ? false : true;
3363 194 : if (has_dot && has_colon){
3364 : /* This seems to be an IPv4 address embedded in IPv6, which is
3365 : icky. We don't support it. */
3366 2 : DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
3367 : cidr);
3368 2 : goto error;
3369 192 : } else if (has_colon){ /* looks like IPv6 */
3370 115 : res = inet_pton(AF_INET6, address, address_bytes);
3371 115 : if (res != 1) {
3372 10 : DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
3373 10 : goto error;
3374 : }
3375 105 : address_len = 128;
3376 105 : if (check_address_roundtrip(address, AF_INET6, address_bytes,
3377 : address_redux, INET6_ADDRSTRLEN)){
3378 25 : goto error;
3379 : }
3380 77 : } else if (has_dot) {
3381 : /* looks like IPv4 */
3382 77 : if (strcmp(address, "0.0.0.0") == 0){
3383 1 : DBG_INFO("Windows does not like the zero IPv4 address, "
3384 : "so nor do we.\n");
3385 1 : goto error;
3386 : }
3387 76 : res = inet_pton(AF_INET, address, address_bytes);
3388 76 : if (res != 1) {
3389 18 : DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
3390 18 : goto error;
3391 : }
3392 58 : address_len = 32;
3393 :
3394 58 : if (check_address_roundtrip(address, AF_INET, address_bytes,
3395 : address_redux, INET_ADDRSTRLEN)){
3396 0 : goto error;
3397 : }
3398 : } else {
3399 : /* This doesn't look like an IP address at all. */
3400 0 : goto error;
3401 : }
3402 :
3403 138 : ret = check_cidr_zero_bits(address_bytes, address_len, mask);
3404 138 : talloc_free(frame);
3405 138 : return ret;
3406 70 : error:
3407 70 : talloc_free(frame);
3408 70 : return -1;
3409 : }
3410 :
3411 :
3412 208 : static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn)
3413 : {
3414 208 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3415 208 : const char *cidr = NULL;
3416 208 : const struct ldb_val *rdn_value = NULL;
3417 :
3418 208 : rdn_value = ldb_dn_get_rdn_val(dn);
3419 208 : if (rdn_value == NULL) {
3420 0 : ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
3421 : "failed");
3422 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3423 : }
3424 :
3425 208 : cidr = ldb_dn_escape_value(ac, *rdn_value);
3426 208 : DBG_INFO("looking at cidr '%s'\n", cidr);
3427 208 : if (cidr == NULL) {
3428 0 : ldb_set_errstring(ldb,
3429 : "samldb: adding an empty subnet cidr seems wrong");
3430 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3431 : }
3432 :
3433 208 : if (verify_cidr(cidr)){
3434 97 : ldb_set_errstring(ldb,
3435 : "samldb: subnet value is invalid");
3436 97 : return LDB_ERR_INVALID_DN_SYNTAX;
3437 : }
3438 :
3439 111 : return LDB_SUCCESS;
3440 : }
3441 :
3442 542853 : static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req,
3443 : struct ldb_dn *dn)
3444 : {
3445 542853 : bool rodc = false;
3446 : struct loadparm_context *lp_ctx;
3447 : char *referral;
3448 : int ret;
3449 : WERROR err;
3450 :
3451 1085706 : if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) ||
3452 542853 : ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
3453 0 : return NULL;
3454 : }
3455 :
3456 542853 : ret = samdb_rodc(ldb, &rodc);
3457 542853 : if (ret != LDB_SUCCESS) {
3458 19 : DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
3459 0 : return NULL;
3460 : }
3461 :
3462 542834 : if (rodc) {
3463 23 : const char *domain = NULL;
3464 : struct ldb_dn *fsmo_role_dn;
3465 : struct ldb_dn *role_owner_dn;
3466 23 : ldb_set_errstring(ldb, "RODC modify is forbidden!");
3467 23 : lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3468 : struct loadparm_context);
3469 :
3470 23 : err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3471 : &fsmo_role_dn, &role_owner_dn);
3472 23 : if (W_ERROR_IS_OK(err)) {
3473 23 : struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3474 23 : if (server_dn != NULL) {
3475 23 : ldb_dn_remove_child_components(server_dn, 1);
3476 :
3477 23 : domain = samdb_dn_to_dnshostname(ldb, req,
3478 : server_dn);
3479 : }
3480 : }
3481 23 : if (domain == NULL) {
3482 0 : domain = lpcfg_dnsdomain(lp_ctx);
3483 : }
3484 23 : referral = talloc_asprintf(req,
3485 : "ldap://%s/%s",
3486 : domain,
3487 : ldb_dn_get_linearized(dn));
3488 23 : return referral;
3489 : }
3490 :
3491 466095 : return NULL;
3492 : }
3493 :
3494 :
3495 : /* add */
3496 490167 : static int samldb_add(struct ldb_module *module, struct ldb_request *req)
3497 : {
3498 : struct ldb_context *ldb;
3499 : struct samldb_ctx *ac;
3500 : struct ldb_message_element *el;
3501 : int ret;
3502 490167 : char *referral = NULL;
3503 :
3504 490167 : ldb = ldb_module_get_ctx(module);
3505 490167 : ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
3506 :
3507 : /* do not manipulate our control entries */
3508 490167 : if (ldb_dn_is_special(req->op.add.message->dn)) {
3509 508 : return ldb_next_request(module, req);
3510 : }
3511 :
3512 489659 : referral = refer_if_rodc(ldb, req, req->op.add.message->dn);
3513 489659 : if (referral != NULL) {
3514 22 : ret = ldb_module_send_referral(req, referral);
3515 22 : return ret;
3516 : }
3517 :
3518 489637 : el = ldb_msg_find_element(req->op.add.message, "userParameters");
3519 489637 : if (el != NULL && ldb_req_is_untrusted(req)) {
3520 0 : const char *reason = "samldb_add: "
3521 : "setting userParameters is not supported over LDAP, "
3522 : "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3523 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3524 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3525 : }
3526 :
3527 489637 : ac = samldb_ctx_init(module, req);
3528 489637 : if (ac == NULL) {
3529 0 : return ldb_operr(ldb);
3530 : }
3531 :
3532 : /* build the new msg */
3533 489637 : ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
3534 489637 : if (ac->msg == NULL) {
3535 0 : talloc_free(ac);
3536 0 : ldb_debug(ldb, LDB_DEBUG_FATAL,
3537 : "samldb_add: ldb_msg_copy_shallow failed!\n");
3538 0 : return ldb_operr(ldb);
3539 : }
3540 :
3541 489637 : el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3542 489637 : if (el != NULL) {
3543 9 : ret = samldb_fsmo_role_owner_check(ac);
3544 9 : if (ret != LDB_SUCCESS) {
3545 6 : return ret;
3546 : }
3547 : }
3548 :
3549 489631 : if (samdb_find_attribute(ldb, ac->msg,
3550 : "objectclass", "user") != NULL) {
3551 19901 : ac->type = SAMLDB_TYPE_USER;
3552 :
3553 19901 : ret = samldb_prim_group_trigger(ac);
3554 19901 : if (ret != LDB_SUCCESS) {
3555 10 : return ret;
3556 : }
3557 :
3558 19891 : ret = samldb_objectclass_trigger(ac);
3559 19891 : if (ret != LDB_SUCCESS) {
3560 28 : return ret;
3561 : }
3562 :
3563 19863 : return samldb_fill_object(ac);
3564 : }
3565 :
3566 469730 : if (samdb_find_attribute(ldb, ac->msg,
3567 : "objectclass", "group") != NULL) {
3568 7690 : ac->type = SAMLDB_TYPE_GROUP;
3569 :
3570 7690 : ret = samldb_objectclass_trigger(ac);
3571 7690 : if (ret != LDB_SUCCESS) {
3572 6 : return ret;
3573 : }
3574 :
3575 7684 : return samldb_fill_object(ac);
3576 : }
3577 :
3578 : /* perhaps a foreignSecurityPrincipal? */
3579 462040 : if (samdb_find_attribute(ldb, ac->msg,
3580 : "objectclass",
3581 : "foreignSecurityPrincipal") != NULL) {
3582 3649 : return samldb_fill_foreignSecurityPrincipal_object(ac);
3583 : }
3584 :
3585 458391 : if (samdb_find_attribute(ldb, ac->msg,
3586 : "objectclass", "classSchema") != NULL) {
3587 31642 : ac->type = SAMLDB_TYPE_CLASS;
3588 :
3589 : /* If in provision, these checks are too slow to do */
3590 31642 : if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3591 598 : ret = samldb_schema_governsid_valid_check(ac);
3592 598 : if (ret != LDB_SUCCESS) {
3593 9 : return ret;
3594 : }
3595 : }
3596 :
3597 31633 : ret = samldb_schema_ldapdisplayname_valid_check(ac);
3598 31633 : if (ret != LDB_SUCCESS) {
3599 9 : return ret;
3600 : }
3601 :
3602 31624 : ret = samldb_schema_info_update(ac);
3603 31624 : if (ret != LDB_SUCCESS) {
3604 0 : talloc_free(ac);
3605 0 : return ret;
3606 : }
3607 :
3608 31624 : return samldb_fill_object(ac);
3609 : }
3610 :
3611 426749 : if (samdb_find_attribute(ldb, ac->msg,
3612 : "objectclass", "attributeSchema") != NULL) {
3613 174434 : ac->type = SAMLDB_TYPE_ATTRIBUTE;
3614 :
3615 : /* If in provision, these checks are too slow to do */
3616 174434 : if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
3617 971 : ret = samldb_schema_attributeid_valid_check(ac);
3618 971 : if (ret != LDB_SUCCESS) {
3619 9 : return ret;
3620 : }
3621 :
3622 962 : ret = samldb_schema_add_handle_linkid(ac);
3623 962 : if (ret != LDB_SUCCESS) {
3624 36 : return ret;
3625 : }
3626 :
3627 926 : ret = samldb_schema_add_handle_mapiid(ac);
3628 926 : if (ret != LDB_SUCCESS) {
3629 9 : return ret;
3630 : }
3631 : }
3632 :
3633 174380 : ret = samldb_schema_ldapdisplayname_valid_check(ac);
3634 174380 : if (ret != LDB_SUCCESS) {
3635 18 : return ret;
3636 : }
3637 :
3638 174362 : ret = samldb_schema_info_update(ac);
3639 174362 : if (ret != LDB_SUCCESS) {
3640 0 : talloc_free(ac);
3641 0 : return ret;
3642 : }
3643 :
3644 174362 : return samldb_fill_object(ac);
3645 : }
3646 :
3647 252315 : if (samdb_find_attribute(ldb, ac->msg,
3648 : "objectclass", "subnet") != NULL) {
3649 206 : ret = samldb_verify_subnet(ac, ac->msg->dn);
3650 206 : if (ret != LDB_SUCCESS) {
3651 96 : talloc_free(ac);
3652 96 : return ret;
3653 : }
3654 : /* We are just checking the value is valid, and there are no
3655 : values to fill in. */
3656 : }
3657 :
3658 252219 : talloc_free(ac);
3659 :
3660 : /* nothing matched, go on */
3661 252219 : return ldb_next_request(module, req);
3662 : }
3663 :
3664 : /* modify */
3665 399687 : static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
3666 : {
3667 : struct ldb_context *ldb;
3668 : struct samldb_ctx *ac;
3669 : struct ldb_message_element *el, *el2;
3670 : struct ldb_control *is_undelete;
3671 399687 : bool modified = false;
3672 : int ret;
3673 :
3674 399687 : if (ldb_dn_is_special(req->op.mod.message->dn)) {
3675 : /* do not manipulate our control entries */
3676 657 : return ldb_next_request(module, req);
3677 : }
3678 :
3679 399030 : ldb = ldb_module_get_ctx(module);
3680 :
3681 : /*
3682 : * we are going to need some special handling if in Undelete call.
3683 : * Since tombstone_reanimate module will restore certain attributes,
3684 : * we need to relax checks for: sAMAccountType, primaryGroupID
3685 : */
3686 399030 : is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
3687 :
3688 : /* make sure that "objectSid" is not specified */
3689 399030 : el = ldb_msg_find_element(req->op.mod.message, "objectSid");
3690 399030 : if (el != NULL) {
3691 15 : if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
3692 15 : ldb_set_errstring(ldb,
3693 : "samldb: objectSid must not be specified!");
3694 15 : return LDB_ERR_UNWILLING_TO_PERFORM;
3695 : }
3696 : }
3697 399015 : if (is_undelete == NULL) {
3698 : /* make sure that "sAMAccountType" is not specified */
3699 398750 : el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
3700 398750 : if (el != NULL) {
3701 15 : ldb_set_errstring(ldb,
3702 : "samldb: sAMAccountType must not be specified!");
3703 15 : return LDB_ERR_UNWILLING_TO_PERFORM;
3704 : }
3705 : }
3706 : /* make sure that "isCriticalSystemObject" is not specified */
3707 399000 : el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
3708 399000 : if (el != NULL) {
3709 372 : if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
3710 1 : ldb_set_errstring(ldb,
3711 : "samldb: isCriticalSystemObject must not be specified!");
3712 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
3713 : }
3714 : }
3715 :
3716 : /* msDS-IntId is not allowed to be modified
3717 : * except when modification comes from replication */
3718 398999 : if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
3719 36 : if (!ldb_request_get_control(req,
3720 : DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
3721 36 : return LDB_ERR_CONSTRAINT_VIOLATION;
3722 : }
3723 : }
3724 :
3725 398963 : el = ldb_msg_find_element(req->op.mod.message, "userParameters");
3726 398963 : if (el != NULL && ldb_req_is_untrusted(req)) {
3727 0 : const char *reason = "samldb: "
3728 : "setting userParameters is not supported over LDAP, "
3729 : "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
3730 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
3731 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
3732 : }
3733 :
3734 398963 : ac = samldb_ctx_init(module, req);
3735 398963 : if (ac == NULL) {
3736 0 : return ldb_operr(ldb);
3737 : }
3738 :
3739 : /* build the new msg */
3740 398963 : ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3741 398963 : if (ac->msg == NULL) {
3742 0 : talloc_free(ac);
3743 0 : ldb_debug(ldb, LDB_DEBUG_FATAL,
3744 : "samldb_modify: ldb_msg_copy_shallow failed!\n");
3745 0 : return ldb_operr(ldb);
3746 : }
3747 :
3748 398963 : if (is_undelete == NULL) {
3749 398698 : el = ldb_msg_find_element(ac->msg, "primaryGroupID");
3750 398698 : if (el != NULL) {
3751 107 : ret = samldb_prim_group_trigger(ac);
3752 107 : if (ret != LDB_SUCCESS) {
3753 12 : return ret;
3754 : }
3755 : }
3756 : }
3757 :
3758 398951 : el = ldb_msg_find_element(ac->msg, "userAccountControl");
3759 398951 : if (el != NULL) {
3760 10822 : modified = true;
3761 10822 : ret = samldb_user_account_control_change(ac);
3762 10822 : if (ret != LDB_SUCCESS) {
3763 50 : return ret;
3764 : }
3765 : }
3766 :
3767 398901 : el = ldb_msg_find_element(ac->msg, "pwdLastSet");
3768 398901 : if (el != NULL) {
3769 356 : modified = true;
3770 356 : ret = samldb_pwd_last_set_change(ac);
3771 356 : if (ret != LDB_SUCCESS) {
3772 6 : return ret;
3773 : }
3774 : }
3775 :
3776 398895 : el = ldb_msg_find_element(ac->msg, "lockoutTime");
3777 398895 : if (el != NULL) {
3778 157 : modified = true;
3779 157 : ret = samldb_lockout_time(ac);
3780 157 : if (ret != LDB_SUCCESS) {
3781 0 : return ret;
3782 : }
3783 : }
3784 :
3785 398895 : el = ldb_msg_find_element(ac->msg, "groupType");
3786 398895 : if (el != NULL) {
3787 102 : modified = true;
3788 102 : ret = samldb_group_type_change(ac);
3789 102 : if (ret != LDB_SUCCESS) {
3790 33 : return ret;
3791 : }
3792 : }
3793 :
3794 398862 : el = ldb_msg_find_element(ac->msg, "sAMAccountName");
3795 398862 : if (el != NULL) {
3796 776 : ret = samldb_sam_accountname_valid_check(ac);
3797 : /*
3798 : * Other errors are checked for elsewhere, we just
3799 : * want to prevent duplicates
3800 : */
3801 776 : if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
3802 3 : return ret;
3803 : }
3804 : }
3805 :
3806 398859 : el = ldb_msg_find_element(ac->msg, "ldapDisplayName");
3807 398859 : if (el != NULL) {
3808 29 : ret = samldb_schema_ldapdisplayname_valid_check(ac);
3809 29 : if (ret != LDB_SUCCESS) {
3810 18 : return ret;
3811 : }
3812 : }
3813 :
3814 398841 : el = ldb_msg_find_element(ac->msg, "attributeID");
3815 398841 : if (el != NULL) {
3816 27 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3817 : "Once set, attributeID values may not be modified");
3818 27 : return LDB_ERR_CONSTRAINT_VIOLATION;
3819 : }
3820 :
3821 398814 : el = ldb_msg_find_element(ac->msg, "governsID");
3822 398814 : if (el != NULL) {
3823 18 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3824 : "Once set, governsID values may not be modified");
3825 18 : return LDB_ERR_CONSTRAINT_VIOLATION;
3826 : }
3827 :
3828 398796 : el = ldb_msg_find_element(ac->msg, "member");
3829 398796 : if (el != NULL) {
3830 3129 : struct ldb_control *fix_link_sid_ctrl = NULL;
3831 :
3832 3129 : fix_link_sid_ctrl = ldb_request_get_control(ac->req,
3833 : DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID);
3834 3129 : if (fix_link_sid_ctrl == NULL) {
3835 3127 : ret = samldb_member_check(ac);
3836 3127 : if (ret != LDB_SUCCESS) {
3837 3 : return ret;
3838 : }
3839 : }
3840 : }
3841 :
3842 398793 : el = ldb_msg_find_element(ac->msg, "description");
3843 398793 : if (el != NULL) {
3844 1056 : ret = samldb_description_check(ac, &modified);
3845 1056 : if (ret != LDB_SUCCESS) {
3846 0 : return ret;
3847 : }
3848 : }
3849 :
3850 398793 : el = ldb_msg_find_element(ac->msg, "dNSHostName");
3851 398793 : el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
3852 398793 : if ((el != NULL) || (el2 != NULL)) {
3853 1394 : modified = true;
3854 1394 : ret = samldb_service_principal_names_change(ac);
3855 1394 : if (ret != LDB_SUCCESS) {
3856 0 : return ret;
3857 : }
3858 : }
3859 :
3860 398793 : el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
3861 398793 : if (el != NULL) {
3862 1235 : ret = samldb_fsmo_role_owner_check(ac);
3863 1235 : if (ret != LDB_SUCCESS) {
3864 6 : return ret;
3865 : }
3866 : }
3867 :
3868 398787 : if (modified) {
3869 : struct ldb_request *child_req;
3870 :
3871 : /* Now perform the real modifications as a child request */
3872 22194 : ret = ldb_build_mod_req(&child_req, ldb, ac,
3873 13430 : ac->msg,
3874 : req->controls,
3875 : req, dsdb_next_callback,
3876 : req);
3877 13430 : LDB_REQ_SET_LOCATION(child_req);
3878 13430 : if (ret != LDB_SUCCESS) {
3879 0 : return ret;
3880 : }
3881 :
3882 13430 : return ldb_next_request(module, child_req);
3883 : }
3884 :
3885 385357 : talloc_free(ac);
3886 :
3887 : /* no change which interests us, go on */
3888 385357 : return ldb_next_request(module, req);
3889 : }
3890 :
3891 : /* delete */
3892 :
3893 53193 : static int samldb_prim_group_users_check(struct samldb_ctx *ac)
3894 : {
3895 : struct ldb_context *ldb;
3896 : struct dom_sid *sid;
3897 : uint32_t rid;
3898 : NTSTATUS status;
3899 : int ret;
3900 53193 : struct ldb_result *res = NULL;
3901 53193 : struct ldb_result *res_users = NULL;
3902 53193 : const char * const attrs[] = { "objectSid", "isDeleted", NULL };
3903 53193 : const char * const noattrs[] = { NULL };
3904 :
3905 53193 : ldb = ldb_module_get_ctx(ac->module);
3906 :
3907 : /* Finds out the SID/RID of the SAM object */
3908 53193 : ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
3909 : attrs,
3910 : DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
3911 : ac->req);
3912 53193 : if (ret != LDB_SUCCESS) {
3913 0 : return ret;
3914 : }
3915 :
3916 53193 : if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
3917 7 : return LDB_SUCCESS;
3918 : }
3919 :
3920 53179 : sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
3921 53179 : if (sid == NULL) {
3922 : /* No SID - it might not be a SAM object - therefore ok */
3923 32162 : return LDB_SUCCESS;
3924 : }
3925 20956 : status = dom_sid_split_rid(ac, sid, NULL, &rid);
3926 20956 : if (!NT_STATUS_IS_OK(status)) {
3927 0 : return ldb_operr(ldb);
3928 : }
3929 20956 : if (rid == 0) {
3930 : /* Special object (security principal?) */
3931 0 : return LDB_SUCCESS;
3932 : }
3933 : /* do not allow deletion of well-known sids */
3934 20971 : if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID &&
3935 15 : (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
3936 15 : return LDB_ERR_OTHER;
3937 : }
3938 :
3939 : /* Deny delete requests from groups which are primary ones */
3940 20941 : ret = dsdb_module_search(ac->module, ac, &res_users,
3941 : ldb_get_default_basedn(ldb),
3942 : LDB_SCOPE_SUBTREE, noattrs,
3943 : DSDB_FLAG_NEXT_MODULE,
3944 : ac->req,
3945 : "(&(primaryGroupID=%u)(objectClass=user))", rid);
3946 20941 : if (ret != LDB_SUCCESS) {
3947 0 : return ret;
3948 : }
3949 20941 : if (res_users->count > 0) {
3950 5 : ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
3951 : "Refusing to delete %s, as it "
3952 : "is still the primaryGroupID "
3953 : "for %u users",
3954 3 : ldb_dn_get_linearized(res->msgs[0]->dn),
3955 3 : res_users->count);
3956 :
3957 : /*
3958 : * Yes, this seems very wrong, but we have a test
3959 : * for this exact error code in sam.py
3960 : */
3961 3 : return LDB_ERR_ENTRY_ALREADY_EXISTS;
3962 : }
3963 :
3964 20847 : return LDB_SUCCESS;
3965 : }
3966 :
3967 53195 : static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
3968 : {
3969 : struct samldb_ctx *ac;
3970 53195 : char *referral = NULL;
3971 : int ret;
3972 : struct ldb_context *ldb;
3973 :
3974 53195 : if (ldb_dn_is_special(req->op.del.dn)) {
3975 : /* do not manipulate our control entries */
3976 1 : return ldb_next_request(module, req);
3977 : }
3978 :
3979 53194 : ldb = ldb_module_get_ctx(module);
3980 :
3981 53194 : referral = refer_if_rodc(ldb, req, req->op.del.dn);
3982 53194 : if (referral != NULL) {
3983 1 : ret = ldb_module_send_referral(req, referral);
3984 1 : return ret;
3985 : }
3986 :
3987 53193 : ac = samldb_ctx_init(module, req);
3988 53193 : if (ac == NULL) {
3989 0 : return ldb_operr(ldb_module_get_ctx(module));
3990 : }
3991 :
3992 53193 : ret = samldb_prim_group_users_check(ac);
3993 53193 : if (ret != LDB_SUCCESS) {
3994 18 : return ret;
3995 : }
3996 :
3997 53175 : talloc_free(ac);
3998 :
3999 53175 : return ldb_next_request(module, req);
4000 : }
4001 :
4002 : /* rename */
4003 :
4004 1129 : static int check_rename_constraints(struct ldb_message *msg,
4005 : struct samldb_ctx *ac,
4006 : struct ldb_dn *olddn, struct ldb_dn *newdn)
4007 : {
4008 1129 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4009 : struct ldb_dn *dn1, *dn2, *nc_root;
4010 : int32_t systemFlags;
4011 1129 : bool move_op = false;
4012 1129 : bool rename_op = false;
4013 : int ret;
4014 :
4015 : /* Skip the checks if old and new DN are the same, or if we have the
4016 : * relax control specified or if the returned objects is already
4017 : * deleted and needs only to be moved for consistency. */
4018 :
4019 1129 : if (ldb_dn_compare(olddn, newdn) == 0) {
4020 6 : return LDB_SUCCESS;
4021 : }
4022 1123 : if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) {
4023 19 : return LDB_SUCCESS;
4024 : }
4025 :
4026 1104 : if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) {
4027 : /*
4028 : * check originating request if we are supposed
4029 : * to "see" this record in first place.
4030 : */
4031 2 : if (ldb_request_get_control(ac->req, LDB_CONTROL_SHOW_DELETED_OID) == NULL) {
4032 1 : return LDB_ERR_NO_SUCH_OBJECT;
4033 : }
4034 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
4035 : }
4036 :
4037 : /* Objects under CN=System */
4038 :
4039 1102 : dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb));
4040 1102 : if (dn1 == NULL) return ldb_oom(ldb);
4041 :
4042 1102 : if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) {
4043 0 : talloc_free(dn1);
4044 0 : return LDB_ERR_OPERATIONS_ERROR;
4045 : }
4046 :
4047 1103 : if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
4048 1 : (ldb_dn_compare_base(dn1, newdn) != 0)) {
4049 1 : talloc_free(dn1);
4050 1 : ldb_asprintf_errstring(ldb,
4051 : "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
4052 : ldb_dn_get_linearized(olddn));
4053 1 : return LDB_ERR_OTHER;
4054 : }
4055 :
4056 1101 : talloc_free(dn1);
4057 :
4058 : /* LSA objects */
4059 :
4060 2202 : if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) ||
4061 1101 : (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) {
4062 0 : ldb_asprintf_errstring(ldb,
4063 : "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
4064 : ldb_dn_get_linearized(olddn));
4065 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
4066 : }
4067 :
4068 : /* subnet objects */
4069 1101 : if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
4070 2 : ret = samldb_verify_subnet(ac, newdn);
4071 2 : if (ret != LDB_SUCCESS) {
4072 1 : return ret;
4073 : }
4074 : }
4075 :
4076 : /* systemFlags */
4077 :
4078 1100 : dn1 = ldb_dn_get_parent(ac, olddn);
4079 1100 : if (dn1 == NULL) return ldb_oom(ldb);
4080 1100 : dn2 = ldb_dn_get_parent(ac, newdn);
4081 1100 : if (dn2 == NULL) return ldb_oom(ldb);
4082 :
4083 1100 : if (ldb_dn_compare(dn1, dn2) == 0) {
4084 621 : rename_op = true;
4085 : } else {
4086 473 : move_op = true;
4087 : }
4088 :
4089 1100 : talloc_free(dn1);
4090 1100 : talloc_free(dn2);
4091 :
4092 1100 : systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
4093 :
4094 : /* Fetch name context */
4095 :
4096 1100 : ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root);
4097 1100 : if (ret != LDB_SUCCESS) {
4098 0 : return ret;
4099 : }
4100 :
4101 1100 : if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) {
4102 8 : if (move_op) {
4103 0 : ldb_asprintf_errstring(ldb,
4104 : "subtree_rename: Cannot move %s within schema partition",
4105 : ldb_dn_get_linearized(olddn));
4106 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
4107 : }
4108 16 : if (rename_op &&
4109 8 : (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
4110 1 : ldb_asprintf_errstring(ldb,
4111 : "subtree_rename: Cannot rename %s within schema partition",
4112 : ldb_dn_get_linearized(olddn));
4113 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
4114 : }
4115 1092 : } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) {
4116 16 : if (move_op &&
4117 4 : (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
4118 : /* Here we have to do more: control the
4119 : * "ALLOW_LIMITED_MOVE" flag. This means that the
4120 : * grand-grand-parents of two objects have to be equal
4121 : * in order to perform the move (this is used for
4122 : * moving "server" objects in the "sites" container). */
4123 4 : bool limited_move =
4124 4 : systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
4125 :
4126 4 : if (limited_move) {
4127 0 : dn1 = ldb_dn_copy(ac, olddn);
4128 0 : if (dn1 == NULL) return ldb_oom(ldb);
4129 0 : dn2 = ldb_dn_copy(ac, newdn);
4130 0 : if (dn2 == NULL) return ldb_oom(ldb);
4131 :
4132 0 : limited_move &= ldb_dn_remove_child_components(dn1, 3);
4133 0 : limited_move &= ldb_dn_remove_child_components(dn2, 3);
4134 0 : limited_move &= ldb_dn_compare(dn1, dn2) == 0;
4135 :
4136 0 : talloc_free(dn1);
4137 0 : talloc_free(dn2);
4138 : }
4139 :
4140 4 : if (!limited_move
4141 4 : && ldb_request_get_control(ac->req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID) == NULL) {
4142 2 : ldb_asprintf_errstring(ldb,
4143 : "subtree_rename: Cannot move %s to %s in config partition",
4144 : ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4145 2 : return LDB_ERR_UNWILLING_TO_PERFORM;
4146 : }
4147 : }
4148 18 : if (rename_op &&
4149 8 : (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
4150 1 : ldb_asprintf_errstring(ldb,
4151 : "subtree_rename: Cannot rename %s to %s within config partition",
4152 : ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4153 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
4154 : }
4155 1080 : } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) {
4156 1494 : if (move_op &&
4157 469 : (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
4158 1 : ldb_asprintf_errstring(ldb,
4159 : "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
4160 : ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4161 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
4162 : }
4163 1530 : if (rename_op &&
4164 608 : (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
4165 1 : ldb_asprintf_errstring(ldb,
4166 : "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
4167 : ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
4168 1 : return LDB_ERR_UNWILLING_TO_PERFORM;
4169 : }
4170 : }
4171 :
4172 1094 : talloc_free(nc_root);
4173 :
4174 1094 : return LDB_SUCCESS;
4175 : }
4176 :
4177 :
4178 2251 : static int samldb_rename_search_base_callback(struct ldb_request *req,
4179 : struct ldb_reply *ares)
4180 : {
4181 : struct samldb_ctx *ac;
4182 : int ret;
4183 :
4184 2251 : ac = talloc_get_type(req->context, struct samldb_ctx);
4185 :
4186 2251 : if (!ares) {
4187 0 : return ldb_module_done(ac->req, NULL, NULL,
4188 : LDB_ERR_OPERATIONS_ERROR);
4189 : }
4190 2251 : if (ares->error != LDB_SUCCESS) {
4191 0 : return ldb_module_done(ac->req, ares->controls,
4192 : ares->response, ares->error);
4193 : }
4194 :
4195 2251 : switch (ares->type) {
4196 1129 : case LDB_REPLY_ENTRY:
4197 : /*
4198 : * This is the root entry of the originating move
4199 : * respectively rename request. It has been already
4200 : * stored in the list using "subtree_rename_search()".
4201 : * Only this one is subject to constraint checking.
4202 : */
4203 2045 : ret = check_rename_constraints(ares->message, ac,
4204 1123 : ac->req->op.rename.olddn,
4205 1129 : ac->req->op.rename.newdn);
4206 1129 : if (ret != LDB_SUCCESS) {
4207 10 : return ldb_module_done(ac->req, NULL, NULL,
4208 : ret);
4209 : }
4210 1113 : break;
4211 :
4212 0 : case LDB_REPLY_REFERRAL:
4213 : /* ignore */
4214 0 : break;
4215 :
4216 1122 : case LDB_REPLY_DONE:
4217 :
4218 : /*
4219 : * Great, no problem with the rename, so go ahead as
4220 : * if we never were here
4221 : */
4222 1122 : ret = ldb_next_request(ac->module, ac->req);
4223 1122 : talloc_free(ares);
4224 1122 : return ret;
4225 : }
4226 :
4227 1119 : talloc_free(ares);
4228 1119 : return LDB_SUCCESS;
4229 : }
4230 :
4231 :
4232 : /* rename */
4233 1132 : static int samldb_rename(struct ldb_module *module, struct ldb_request *req)
4234 : {
4235 : struct ldb_context *ldb;
4236 : static const char * const attrs[] = { "objectClass", "systemFlags",
4237 : "isDeleted", NULL };
4238 : struct ldb_request *search_req;
4239 : struct samldb_ctx *ac;
4240 : int ret;
4241 :
4242 1132 : if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
4243 0 : return ldb_next_request(module, req);
4244 : }
4245 :
4246 1132 : ldb = ldb_module_get_ctx(module);
4247 :
4248 1132 : ac = samldb_ctx_init(module, req);
4249 1132 : if (!ac) {
4250 0 : return ldb_oom(ldb);
4251 : }
4252 :
4253 1132 : ret = ldb_build_search_req(&search_req, ldb, ac,
4254 : req->op.rename.olddn,
4255 : LDB_SCOPE_BASE,
4256 : "(objectClass=*)",
4257 : attrs,
4258 : NULL,
4259 : ac,
4260 : samldb_rename_search_base_callback,
4261 : req);
4262 1132 : LDB_REQ_SET_LOCATION(search_req);
4263 1132 : if (ret != LDB_SUCCESS) {
4264 0 : return ret;
4265 : }
4266 :
4267 1132 : ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4268 : true, NULL);
4269 1132 : if (ret != LDB_SUCCESS) {
4270 0 : return ret;
4271 : }
4272 :
4273 1132 : return ldb_next_request(ac->module, search_req);
4274 : }
4275 :
4276 : /* extended */
4277 :
4278 34 : static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
4279 : {
4280 34 : struct ldb_context *ldb = ldb_module_get_ctx(module);
4281 : struct dsdb_fsmo_extended_op *exop;
4282 : int ret;
4283 :
4284 34 : exop = talloc_get_type(req->op.extended.data,
4285 : struct dsdb_fsmo_extended_op);
4286 34 : if (!exop) {
4287 0 : ldb_set_errstring(ldb,
4288 : "samldb_extended_allocate_rid_pool: invalid extended data");
4289 0 : return LDB_ERR_PROTOCOL_ERROR;
4290 : }
4291 :
4292 34 : ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
4293 34 : if (ret != LDB_SUCCESS) {
4294 0 : return ret;
4295 : }
4296 :
4297 34 : return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4298 : }
4299 :
4300 995 : static int samldb_extended_allocate_rid(struct ldb_module *module, struct ldb_request *req)
4301 : {
4302 995 : struct ldb_context *ldb = ldb_module_get_ctx(module);
4303 : struct dsdb_extended_allocate_rid *exop;
4304 : int ret;
4305 :
4306 995 : exop = talloc_get_type(req->op.extended.data,
4307 : struct dsdb_extended_allocate_rid);
4308 995 : if (!exop) {
4309 0 : ldb_set_errstring(ldb,
4310 : "samldb_extended_allocate_rid: invalid extended data");
4311 0 : return LDB_ERR_PROTOCOL_ERROR;
4312 : }
4313 :
4314 995 : ret = ridalloc_allocate_rid(module, &exop->rid, req);
4315 995 : if (ret != LDB_SUCCESS) {
4316 2 : return ret;
4317 : }
4318 :
4319 993 : return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4320 : }
4321 :
4322 39 : static int samldb_extended_create_own_rid_set(struct ldb_module *module, struct ldb_request *req)
4323 : {
4324 39 : struct ldb_context *ldb = ldb_module_get_ctx(module);
4325 : int ret;
4326 : struct ldb_dn *dn;
4327 :
4328 39 : if (req->op.extended.data != NULL) {
4329 0 : ldb_set_errstring(ldb,
4330 : "samldb_extended_create_own_rid_set: invalid extended data (should be NULL)");
4331 0 : return LDB_ERR_PROTOCOL_ERROR;
4332 : }
4333 :
4334 39 : ret = ridalloc_create_own_rid_set(module, req,
4335 : &dn, req);
4336 39 : if (ret != LDB_SUCCESS) {
4337 1 : return ret;
4338 : }
4339 :
4340 38 : return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4341 : }
4342 :
4343 1111702 : static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
4344 : {
4345 1111702 : if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
4346 34 : return samldb_extended_allocate_rid_pool(module, req);
4347 : }
4348 :
4349 1111668 : if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID) == 0) {
4350 995 : return samldb_extended_allocate_rid(module, req);
4351 : }
4352 :
4353 1110673 : if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_OWN_RID_SET) == 0) {
4354 39 : return samldb_extended_create_own_rid_set(module, req);
4355 : }
4356 :
4357 1110634 : return ldb_next_request(module, req);
4358 : }
4359 :
4360 :
4361 : static const struct ldb_module_ops ldb_samldb_module_ops = {
4362 : .name = "samldb",
4363 : .add = samldb_add,
4364 : .modify = samldb_modify,
4365 : .del = samldb_delete,
4366 : .rename = samldb_rename,
4367 : .extended = samldb_extended
4368 : };
4369 :
4370 :
4371 5536 : int ldb_samldb_module_init(const char *version)
4372 : {
4373 5536 : LDB_MODULE_CHECK_VERSION(version);
4374 5536 : return ldb_register_module(&ldb_samldb_module_ops);
4375 : }
|