Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 :
5 : Copyright (C) Andrew Tridgell 2004
6 : Copyright (C) Volker Lendecke 2004
7 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8 : Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
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 : #include "includes.h"
25 : #include "ldb.h"
26 : #include "ldb_module.h"
27 : #include "ldb_errors.h"
28 : #include "../lib/util/util_ldb.h"
29 : #include "lib/crypto/gmsa.h"
30 : #include "dsdb/samdb/samdb.h"
31 : #include "librpc/gen_ndr/ndr_security.h"
32 : #include "librpc/gen_ndr/ndr_misc.h"
33 : #include "../libds/common/flags.h"
34 : #include "dsdb/common/proto.h"
35 : #include "libcli/ldap/ldap_ndr.h"
36 : #include "param/param.h"
37 : #include "librpc/gen_ndr/ndr_drsblobs.h"
38 : #include "dsdb/common/util.h"
39 : #include "dsdb/gmsa/gkdi.h"
40 : #include "dsdb/gmsa/util.h"
41 : #include "lib/socket/socket.h"
42 : #include "librpc/gen_ndr/irpc.h"
43 : #include "libds/common/flag_mapping.h"
44 : #include "lib/util/access.h"
45 : #include "lib/util/data_blob.h"
46 : #include "lib/util/debug.h"
47 : #include "lib/util/fault.h"
48 : #include "lib/util/sys_rw_data.h"
49 : #include "libcli/util/ntstatus.h"
50 : #include "lib/util/smb_strtox.h"
51 : #include "auth/auth.h"
52 :
53 : #undef strncasecmp
54 : #undef strcasecmp
55 :
56 : /*
57 : * This is included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
58 : * dsdb_request_add_controls()
59 : */
60 : #include "dsdb/samdb/ldb_modules/util.h"
61 :
62 : /* default is 30 minutes: -1e7 * 30 * 60 */
63 : #define DEFAULT_OBSERVATION_WINDOW (-18000000000)
64 :
65 : /*
66 : search the sam for the specified attributes in a specific domain, filter on
67 : objectSid being in domain_sid.
68 : */
69 335 : int samdb_search_domain(struct ldb_context *sam_ldb,
70 : TALLOC_CTX *mem_ctx,
71 : struct ldb_dn *basedn,
72 : struct ldb_message ***res,
73 : const char * const *attrs,
74 : const struct dom_sid *domain_sid,
75 : const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
76 : {
77 0 : va_list ap;
78 0 : int i, count;
79 :
80 335 : va_start(ap, format);
81 335 : count = gendb_search_v(sam_ldb, mem_ctx, basedn,
82 : res, attrs, format, ap);
83 335 : va_end(ap);
84 :
85 335 : i=0;
86 :
87 3289 : while (i<count) {
88 0 : struct dom_sid *entry_sid;
89 :
90 2954 : entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
91 :
92 2954 : if ((entry_sid == NULL) ||
93 2954 : (!dom_sid_in_domain(domain_sid, entry_sid))) {
94 : /* Delete that entry from the result set */
95 858 : (*res)[i] = (*res)[count-1];
96 858 : count -= 1;
97 858 : talloc_free(entry_sid);
98 858 : continue;
99 : }
100 2096 : talloc_free(entry_sid);
101 2096 : i += 1;
102 : }
103 :
104 335 : return count;
105 : }
106 :
107 : /*
108 : search the sam for a single string attribute in exactly 1 record
109 : */
110 2360 : const char *samdb_search_string_v(struct ldb_context *sam_ldb,
111 : TALLOC_CTX *mem_ctx,
112 : struct ldb_dn *basedn,
113 : const char *attr_name,
114 : const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
115 : {
116 117 : int count;
117 2360 : const char *attrs[2] = { NULL, NULL };
118 2360 : struct ldb_message **res = NULL;
119 :
120 2360 : attrs[0] = attr_name;
121 :
122 2360 : count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
123 2360 : if (count > 1) {
124 0 : DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
125 : attr_name, format, count));
126 : }
127 2360 : if (count != 1) {
128 2137 : talloc_free(res);
129 2137 : return NULL;
130 : }
131 :
132 223 : return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
133 : }
134 :
135 : /*
136 : search the sam for a single string attribute in exactly 1 record
137 : */
138 2360 : const char *samdb_search_string(struct ldb_context *sam_ldb,
139 : TALLOC_CTX *mem_ctx,
140 : struct ldb_dn *basedn,
141 : const char *attr_name,
142 : const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
143 : {
144 117 : va_list ap;
145 117 : const char *str;
146 :
147 2360 : va_start(ap, format);
148 2360 : str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
149 2360 : va_end(ap);
150 :
151 2360 : return str;
152 : }
153 :
154 4000 : struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
155 : TALLOC_CTX *mem_ctx,
156 : struct ldb_dn *basedn,
157 : const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
158 : {
159 188 : va_list ap;
160 188 : struct ldb_dn *ret;
161 4000 : struct ldb_message **res = NULL;
162 188 : int count;
163 :
164 4000 : va_start(ap, format);
165 4000 : count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
166 4000 : va_end(ap);
167 :
168 4000 : if (count != 1) return NULL;
169 :
170 4000 : ret = talloc_steal(mem_ctx, res[0]->dn);
171 4000 : talloc_free(res);
172 :
173 4000 : return ret;
174 : }
175 :
176 : /*
177 : search the sam for a dom_sid attribute in exactly 1 record
178 : */
179 981 : struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
180 : TALLOC_CTX *mem_ctx,
181 : struct ldb_dn *basedn,
182 : const char *attr_name,
183 : const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
184 : {
185 0 : va_list ap;
186 0 : int count;
187 0 : struct ldb_message **res;
188 981 : const char *attrs[2] = { NULL, NULL };
189 0 : struct dom_sid *sid;
190 :
191 981 : attrs[0] = attr_name;
192 :
193 981 : va_start(ap, format);
194 981 : count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
195 981 : va_end(ap);
196 981 : if (count > 1) {
197 0 : DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
198 : attr_name, format, count));
199 : }
200 981 : if (count != 1) {
201 0 : talloc_free(res);
202 0 : return NULL;
203 : }
204 981 : sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
205 981 : talloc_free(res);
206 981 : return sid;
207 : }
208 :
209 : /*
210 : search the sam for a single integer attribute in exactly 1 record
211 : */
212 2529 : unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
213 : TALLOC_CTX *mem_ctx,
214 : unsigned int default_value,
215 : struct ldb_dn *basedn,
216 : const char *attr_name,
217 : const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
218 : {
219 146 : va_list ap;
220 146 : int count;
221 146 : struct ldb_message **res;
222 2529 : const char *attrs[2] = { NULL, NULL };
223 :
224 2529 : attrs[0] = attr_name;
225 :
226 2529 : va_start(ap, format);
227 2529 : count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
228 2529 : va_end(ap);
229 :
230 2529 : if (count != 1) {
231 0 : return default_value;
232 : }
233 :
234 2529 : return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
235 : }
236 :
237 : /*
238 : search the sam for a single signed 64 bit integer attribute in exactly 1 record
239 : */
240 788160 : int64_t samdb_search_int64(struct ldb_context *sam_ldb,
241 : TALLOC_CTX *mem_ctx,
242 : int64_t default_value,
243 : struct ldb_dn *basedn,
244 : const char *attr_name,
245 : const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
246 : {
247 27882 : va_list ap;
248 27882 : int count;
249 27882 : struct ldb_message **res;
250 788160 : const char *attrs[2] = { NULL, NULL };
251 :
252 788160 : attrs[0] = attr_name;
253 :
254 788160 : va_start(ap, format);
255 788160 : count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
256 788160 : va_end(ap);
257 :
258 788160 : if (count != 1) {
259 0 : return default_value;
260 : }
261 :
262 788160 : return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
263 : }
264 :
265 : /*
266 : search the sam for multiple records each giving a single string attribute
267 : return the number of matches, or -1 on error
268 : */
269 0 : int samdb_search_string_multiple(struct ldb_context *sam_ldb,
270 : TALLOC_CTX *mem_ctx,
271 : struct ldb_dn *basedn,
272 : const char ***strs,
273 : const char *attr_name,
274 : const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
275 : {
276 0 : va_list ap;
277 0 : int count, i;
278 0 : const char *attrs[2] = { NULL, NULL };
279 0 : struct ldb_message **res = NULL;
280 :
281 0 : attrs[0] = attr_name;
282 :
283 0 : va_start(ap, format);
284 0 : count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
285 0 : va_end(ap);
286 :
287 0 : if (count <= 0) {
288 0 : return count;
289 : }
290 :
291 : /* make sure its single valued */
292 0 : for (i=0;i<count;i++) {
293 0 : if (res[i]->num_elements != 1) {
294 0 : DEBUG(1,("samdb: search for %s %s not single valued\n",
295 : attr_name, format));
296 0 : talloc_free(res);
297 0 : return -1;
298 : }
299 : }
300 :
301 0 : *strs = talloc_array(mem_ctx, const char *, count+1);
302 0 : if (! *strs) {
303 0 : talloc_free(res);
304 0 : return -1;
305 : }
306 :
307 0 : for (i=0;i<count;i++) {
308 0 : (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
309 : }
310 0 : (*strs)[count] = NULL;
311 :
312 0 : return count;
313 : }
314 :
315 336674 : struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
316 : const char *attr, struct ldb_dn *default_value)
317 : {
318 336674 : struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
319 336674 : if (!ret_dn) {
320 48085 : return default_value;
321 : }
322 278743 : return ret_dn;
323 : }
324 :
325 : /*
326 : pull a rid from a objectSid in a result set.
327 : */
328 789926 : uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
329 : const char *attr, uint32_t default_value)
330 : {
331 28721 : struct dom_sid *sid;
332 28721 : uint32_t rid;
333 :
334 789926 : sid = samdb_result_dom_sid(mem_ctx, msg, attr);
335 789926 : if (sid == NULL) {
336 0 : return default_value;
337 : }
338 789926 : rid = sid->sub_auths[sid->num_auths-1];
339 789926 : talloc_free(sid);
340 789926 : return rid;
341 : }
342 :
343 : /*
344 : pull a dom_sid structure from a objectSid in a result set.
345 : */
346 6086943 : struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
347 : const char *attr)
348 : {
349 255920 : ssize_t ret;
350 255920 : const struct ldb_val *v;
351 255920 : struct dom_sid *sid;
352 6086943 : v = ldb_msg_find_ldb_val(msg, attr);
353 6086943 : if (v == NULL) {
354 4056036 : return NULL;
355 : }
356 1832490 : sid = talloc(mem_ctx, struct dom_sid);
357 1832490 : if (sid == NULL) {
358 0 : return NULL;
359 : }
360 1832490 : ret = sid_parse(v->data, v->length, sid);
361 1832490 : if (ret == -1) {
362 0 : talloc_free(sid);
363 0 : return NULL;
364 : }
365 1774987 : return sid;
366 : }
367 :
368 :
369 : /**
370 : * Makes an auth_SidAttr structure from a objectSid in a result set and a
371 : * supplied attribute value.
372 : *
373 : * @param [in] mem_ctx Talloc memory context on which to allocate the auth_SidAttr.
374 : * @param [in] msg The message from which to take the objectSid.
375 : * @param [in] attr The attribute name, usually "objectSid".
376 : * @param [in] attrs SE_GROUP_* flags to go with the SID.
377 : * @returns A pointer to the auth_SidAttr structure, or NULL on failure.
378 : */
379 1313 : struct auth_SidAttr *samdb_result_dom_sid_attrs(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
380 : const char *attr, uint32_t attrs)
381 : {
382 0 : ssize_t ret;
383 0 : const struct ldb_val *v;
384 0 : struct auth_SidAttr *sid;
385 1313 : v = ldb_msg_find_ldb_val(msg, attr);
386 1313 : if (v == NULL) {
387 0 : return NULL;
388 : }
389 1313 : sid = talloc(mem_ctx, struct auth_SidAttr);
390 1313 : if (sid == NULL) {
391 0 : return NULL;
392 : }
393 1313 : ret = sid_parse(v->data, v->length, &sid->sid);
394 1313 : if (ret == -1) {
395 0 : talloc_free(sid);
396 0 : return NULL;
397 : }
398 1313 : sid->attrs = attrs;
399 1313 : return sid;
400 : }
401 :
402 : /*
403 : pull a dom_sid structure from a objectSid in a result set.
404 : */
405 4168243 : int samdb_result_dom_sid_buf(const struct ldb_message *msg,
406 : const char *attr,
407 : struct dom_sid *sid)
408 : {
409 15428 : ssize_t ret;
410 4168243 : const struct ldb_val *v = NULL;
411 4168243 : v = ldb_msg_find_ldb_val(msg, attr);
412 4168243 : if (v == NULL) {
413 610297 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
414 : }
415 3557944 : ret = sid_parse(v->data, v->length, sid);
416 3557944 : if (ret == -1) {
417 0 : return LDB_ERR_OPERATIONS_ERROR;
418 : }
419 3542518 : return LDB_SUCCESS;
420 : }
421 :
422 : /*
423 : pull a guid structure from a objectGUID in a result set.
424 : */
425 137942447 : struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
426 : {
427 1751126 : const struct ldb_val *v;
428 1751126 : struct GUID guid;
429 1751126 : NTSTATUS status;
430 :
431 137942447 : v = ldb_msg_find_ldb_val(msg, attr);
432 137942447 : if (!v) return GUID_zero();
433 :
434 103237647 : status = GUID_from_ndr_blob(v, &guid);
435 103237647 : if (!NT_STATUS_IS_OK(status)) {
436 0 : return GUID_zero();
437 : }
438 :
439 103237647 : return guid;
440 : }
441 :
442 : /*
443 : pull a sid prefix from a objectSid in a result set.
444 : this is used to find the domain sid for a user
445 : */
446 0 : struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
447 : const char *attr)
448 : {
449 0 : struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
450 0 : if (!sid || sid->num_auths < 1) return NULL;
451 0 : sid->num_auths--;
452 0 : return sid;
453 : }
454 :
455 : /*
456 : pull a NTTIME in a result set.
457 : */
458 463178 : NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
459 : NTTIME default_value)
460 : {
461 463178 : return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
462 : }
463 :
464 : /*
465 : * Windows stores 0 for lastLogoff.
466 : * But when a MS DC return the lastLogoff (as Logoff Time)
467 : * it returns INT64_MAX, not returning this value in this case
468 : * cause windows 2008 and newer version to fail for SMB requests
469 : */
470 79225 : NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
471 : {
472 79225 : NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
473 :
474 79225 : if (ret == 0)
475 79224 : ret = INT64_MAX;
476 :
477 79225 : return ret;
478 : }
479 :
480 : /*
481 : * Windows uses both 0 and 9223372036854775807 (INT64_MAX) to
482 : * indicate an account doesn't expire.
483 : *
484 : * When Windows initially creates an account, it sets
485 : * accountExpires = 9223372036854775807 (INT64_MAX). However,
486 : * when changing from an account having a specific expiration date to
487 : * that account never expiring, it sets accountExpires = 0.
488 : *
489 : * Consolidate that logic here to allow clearer logic for account expiry in
490 : * the rest of the code.
491 : */
492 253168 : NTTIME samdb_result_account_expires(const struct ldb_message *msg)
493 : {
494 253168 : NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
495 : 0);
496 :
497 253168 : if (ret == 0)
498 11 : ret = INT64_MAX;
499 :
500 253168 : return ret;
501 : }
502 :
503 : /*
504 : construct the allow_password_change field from the PwdLastSet attribute and the
505 : domain password settings
506 : */
507 83692 : NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
508 : TALLOC_CTX *mem_ctx,
509 : struct ldb_dn *domain_dn,
510 : const struct ldb_message *msg,
511 : const char *attr)
512 : {
513 83692 : uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
514 3228 : int64_t minPwdAge;
515 :
516 83692 : if (attr_time == 0) {
517 1763 : return 0;
518 : }
519 :
520 81929 : minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
521 :
522 : /* yes, this is a -= not a += as minPwdAge is stored as the negative
523 : of the number of 100-nano-seconds */
524 81929 : attr_time -= minPwdAge;
525 :
526 81929 : return attr_time;
527 : }
528 :
529 : /*
530 : pull a samr_Password structure from a result set.
531 : */
532 325036 : struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
533 : {
534 325036 : struct samr_Password *hash = NULL;
535 325036 : const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
536 325036 : if (val && (val->length >= sizeof(hash->hash))) {
537 301328 : hash = talloc(mem_ctx, struct samr_Password);
538 301328 : if (hash == NULL) {
539 0 : return NULL;
540 : }
541 301328 : talloc_keep_secret(hash);
542 301328 : memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
543 : }
544 314657 : return hash;
545 : }
546 :
547 : /*
548 : pull an array of samr_Password structures from a result set.
549 : */
550 394754 : unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
551 : const char *attr, struct samr_Password **hashes)
552 : {
553 12252 : unsigned int count, i;
554 394754 : const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
555 :
556 394754 : *hashes = NULL;
557 394754 : if (!val) {
558 247780 : return 0;
559 : }
560 139885 : if (val->length % 16 != 0) {
561 : /*
562 : * The length is wrong. Don’t try to read beyond the end of the
563 : * buffer.
564 : */
565 0 : return 0;
566 : }
567 139885 : count = val->length / 16;
568 139885 : if (count == 0) {
569 0 : return 0;
570 : }
571 :
572 139885 : *hashes = talloc_array(mem_ctx, struct samr_Password, count);
573 139885 : if (! *hashes) {
574 0 : return 0;
575 : }
576 139885 : talloc_keep_secret(*hashes);
577 :
578 333493 : for (i=0;i<count;i++) {
579 188445 : memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
580 : }
581 :
582 134722 : return count;
583 : }
584 :
585 3766 : NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
586 : struct loadparm_context *lp_ctx,
587 : const struct ldb_message *msg,
588 : unsigned int idx,
589 : const struct samr_Password **lm_pwd,
590 : const struct samr_Password **nt_pwd)
591 : {
592 1 : struct samr_Password *lmPwdHash, *ntPwdHash;
593 :
594 3766 : if (nt_pwd) {
595 1 : unsigned int num_nt;
596 3766 : num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
597 3766 : if (num_nt <= idx) {
598 2471 : *nt_pwd = NULL;
599 : } else {
600 1295 : *nt_pwd = &ntPwdHash[idx];
601 : }
602 : }
603 3766 : if (lm_pwd) {
604 : /* Ensure that if we have turned off LM
605 : * authentication, that we never use the LM hash, even
606 : * if we store it */
607 0 : if (lpcfg_lanman_auth(lp_ctx)) {
608 0 : unsigned int num_lm;
609 0 : num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
610 0 : if (num_lm <= idx) {
611 0 : *lm_pwd = NULL;
612 : } else {
613 0 : *lm_pwd = &lmPwdHash[idx];
614 : }
615 : } else {
616 0 : *lm_pwd = NULL;
617 : }
618 : }
619 3766 : return NT_STATUS_OK;
620 : }
621 :
622 47886 : NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
623 : struct loadparm_context *lp_ctx,
624 : const struct ldb_message *msg,
625 : struct samr_Password **nt_pwd)
626 : {
627 1733 : struct samr_Password *ntPwdHash;
628 :
629 47886 : if (nt_pwd) {
630 1733 : unsigned int num_nt;
631 47886 : num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
632 47886 : if (num_nt == 0) {
633 15413 : *nt_pwd = NULL;
634 32473 : } else if (num_nt > 1) {
635 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
636 : } else {
637 32473 : *nt_pwd = &ntPwdHash[0];
638 : }
639 : }
640 47886 : return NT_STATUS_OK;
641 : }
642 :
643 30462 : NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
644 : struct loadparm_context *lp_ctx,
645 : const struct ldb_message *msg,
646 : struct samr_Password **nt_pwd)
647 : {
648 1442 : uint16_t acct_flags;
649 :
650 30462 : acct_flags = samdb_result_acct_flags(msg,
651 : "msDS-User-Account-Control-Computed");
652 : /* Quit if the account was locked out. */
653 30462 : if (acct_flags & ACB_AUTOLOCK) {
654 191 : DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
655 : ldb_dn_get_linearized(msg->dn)));
656 191 : return NT_STATUS_ACCOUNT_LOCKED_OUT;
657 : }
658 :
659 30271 : return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
660 : nt_pwd);
661 : }
662 :
663 : /*
664 : pull a samr_LogonHours structure from a result set.
665 : */
666 6373 : struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
667 : {
668 6373 : struct samr_LogonHours hours = {};
669 6373 : size_t units_per_week = 168;
670 6373 : const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
671 :
672 6373 : if (val) {
673 279 : units_per_week = val->length * 8;
674 : }
675 :
676 6373 : hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
677 6373 : if (!hours.bits) {
678 0 : return hours;
679 : }
680 6373 : hours.units_per_week = units_per_week;
681 6373 : memset(hours.bits, 0xFF, units_per_week/8);
682 6373 : if (val) {
683 279 : memcpy(hours.bits, val->data, val->length);
684 : }
685 :
686 6373 : return hours;
687 : }
688 :
689 : /*
690 : pull a set of account_flags from a result set.
691 :
692 : Naturally, this requires that userAccountControl and
693 : (if not null) the attributes 'attr' be already
694 : included in msg
695 : */
696 268143 : uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
697 : {
698 268143 : uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
699 268143 : uint32_t attr_flags = 0;
700 268143 : uint32_t acct_flags = ds_uf2acb(userAccountControl);
701 268143 : if (attr) {
702 236680 : attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
703 236680 : if (attr_flags == UF_ACCOUNTDISABLE) {
704 0 : DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
705 : ldb_dn_get_linearized(msg->dn)));
706 : }
707 236680 : acct_flags |= ds_uf2acb(attr_flags);
708 : }
709 :
710 268143 : return acct_flags;
711 : }
712 :
713 3145 : NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
714 : struct ldb_message *msg,
715 : const char *attr,
716 : struct lsa_BinaryString *s)
717 : {
718 0 : int i;
719 3145 : const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
720 :
721 3145 : ZERO_STRUCTP(s);
722 :
723 3145 : if (!val) {
724 2542 : return NT_STATUS_OK;
725 : }
726 :
727 603 : if ((val->length % 2) != 0) {
728 : /*
729 : * If the on-disk data is not even in length, we know
730 : * it is corrupt, and can not be safely pushed. We
731 : * would either truncate, send an uninitialised
732 : * byte or send a forced zero byte
733 : */
734 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
735 : }
736 :
737 603 : s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
738 603 : if (!s->array) {
739 0 : return NT_STATUS_NO_MEMORY;
740 : }
741 603 : s->length = s->size = val->length;
742 :
743 : /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
744 6030 : for (i = 0; i < s->length / 2; i++) {
745 5427 : s->array[i] = SVAL(val->data, i * 2);
746 : }
747 :
748 603 : return NT_STATUS_OK;
749 : }
750 :
751 : /* Find an attribute, with a particular value */
752 :
753 : /* The current callers of this function expect a very specific
754 : * behaviour: In particular, objectClass subclass equivalence is not
755 : * wanted. This means that we should not lookup the schema for the
756 : * comparison function */
757 58076909 : struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
758 : const struct ldb_message *msg,
759 : const char *name, const char *value)
760 : {
761 1126710 : unsigned int i;
762 58076909 : struct ldb_message_element *el = ldb_msg_find_element(msg, name);
763 :
764 58076909 : if (!el) {
765 177 : return NULL;
766 : }
767 :
768 127799011 : for (i=0;i<el->num_values;i++) {
769 117243527 : if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
770 46905575 : return el;
771 : }
772 : }
773 :
774 10044447 : return NULL;
775 : }
776 :
777 531396 : static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
778 : struct ldb_message *msg,
779 : const char *name,
780 : const char *set_value,
781 : unsigned attr_flags,
782 : bool *added)
783 : {
784 41951 : int ret;
785 41951 : struct ldb_message_element *el;
786 :
787 531396 : SMB_ASSERT(attr_flags != 0);
788 :
789 531396 : el = ldb_msg_find_element(msg, name);
790 531396 : if (el) {
791 226858 : if (added != NULL) {
792 2774 : *added = false;
793 : }
794 :
795 226858 : return LDB_SUCCESS;
796 : }
797 :
798 304538 : ret = ldb_msg_add_empty(msg, name,
799 : attr_flags,
800 : &el);
801 304538 : if (ret != LDB_SUCCESS) {
802 0 : return ret;
803 : }
804 :
805 304538 : if (set_value != NULL) {
806 274147 : ret = ldb_msg_add_string(msg, name, set_value);
807 274147 : if (ret != LDB_SUCCESS) {
808 0 : return ret;
809 : }
810 : }
811 :
812 304538 : if (added != NULL) {
813 301876 : *added = true;
814 : }
815 302240 : return LDB_SUCCESS;
816 : }
817 :
818 226746 : int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
819 : {
820 226746 : return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, LDB_FLAG_MOD_ADD, NULL);
821 : }
822 :
823 : /*
824 : add a dom_sid element to a message
825 : */
826 48658 : int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
827 : const char *attr_name, const struct dom_sid *sid)
828 : {
829 2179 : struct ldb_val v;
830 2179 : enum ndr_err_code ndr_err;
831 :
832 48658 : ndr_err = ndr_push_struct_blob(&v, mem_ctx,
833 : sid,
834 : (ndr_push_flags_fn_t)ndr_push_dom_sid);
835 48658 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
836 0 : return ldb_operr(sam_ldb);
837 : }
838 48658 : return ldb_msg_add_value(msg, attr_name, &v, NULL);
839 : }
840 :
841 :
842 : /*
843 : add a delete element operation to a message
844 : */
845 1273 : int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
846 : const char *attr_name)
847 : {
848 : /* we use an empty replace rather than a delete, as it allows for
849 : dsdb_replace() to be used everywhere */
850 1273 : return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
851 : }
852 :
853 : /*
854 : add an add attribute value to a message or enhance an existing attribute
855 : which has the same name and the add flag set.
856 : */
857 259 : int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
858 : struct ldb_message *msg, const char *attr_name,
859 : const char *value)
860 : {
861 4 : struct ldb_message_element *el;
862 4 : struct ldb_val val;
863 4 : char *v;
864 4 : unsigned int i;
865 259 : bool found = false;
866 4 : int ret;
867 :
868 259 : v = talloc_strdup(mem_ctx, value);
869 259 : if (v == NULL) {
870 0 : return ldb_oom(sam_ldb);
871 : }
872 :
873 259 : val.data = (uint8_t *) v;
874 259 : val.length = strlen(v);
875 :
876 259 : if (val.length == 0) {
877 : /* allow empty strings as non-existent attributes */
878 0 : return LDB_SUCCESS;
879 : }
880 :
881 262 : for (i = 0; i < msg->num_elements; i++) {
882 3 : el = &msg->elements[i];
883 3 : if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
884 0 : (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
885 0 : found = true;
886 0 : break;
887 : }
888 : }
889 259 : if (!found) {
890 259 : ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
891 : &el);
892 259 : if (ret != LDB_SUCCESS) {
893 0 : return ret;
894 : }
895 : }
896 :
897 259 : ret = ldb_msg_element_add_value(msg->elements, el, &val);
898 259 : if (ret != LDB_SUCCESS) {
899 0 : return ldb_oom(sam_ldb);
900 : }
901 :
902 255 : return LDB_SUCCESS;
903 : }
904 :
905 : /*
906 : add a delete attribute value to a message or enhance an existing attribute
907 : which has the same name and the delete flag set.
908 : */
909 249 : int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
910 : struct ldb_message *msg, const char *attr_name,
911 : const char *value)
912 : {
913 2 : struct ldb_message_element *el;
914 2 : struct ldb_val val;
915 2 : char *v;
916 2 : unsigned int i;
917 249 : bool found = false;
918 2 : int ret;
919 :
920 249 : v = talloc_strdup(mem_ctx, value);
921 249 : if (v == NULL) {
922 0 : return ldb_oom(sam_ldb);
923 : }
924 :
925 249 : val.data = (uint8_t *) v;
926 249 : val.length = strlen(v);
927 :
928 249 : if (val.length == 0) {
929 : /* allow empty strings as non-existent attributes */
930 0 : return LDB_SUCCESS;
931 : }
932 :
933 249 : for (i = 0; i < msg->num_elements; i++) {
934 0 : el = &msg->elements[i];
935 0 : if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
936 0 : (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
937 0 : found = true;
938 0 : break;
939 : }
940 : }
941 249 : if (!found) {
942 249 : ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
943 : &el);
944 249 : if (ret != LDB_SUCCESS) {
945 0 : return ret;
946 : }
947 : }
948 :
949 249 : ret = ldb_msg_element_add_value(msg->elements, el, &val);
950 249 : if (ret != LDB_SUCCESS) {
951 0 : return ldb_oom(sam_ldb);
952 : }
953 :
954 247 : return LDB_SUCCESS;
955 : }
956 :
957 : /*
958 : add a int element to a message
959 : */
960 1264461 : int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
961 : const char *attr_name, int v)
962 : {
963 1264461 : const char *s = talloc_asprintf(mem_ctx, "%d", v);
964 1264461 : if (s == NULL) {
965 0 : return ldb_oom(sam_ldb);
966 : }
967 1264461 : return ldb_msg_add_string(msg, attr_name, s);
968 : }
969 :
970 69276 : int samdb_msg_add_int_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
971 : const char *attr_name, int v, int flags)
972 : {
973 69276 : const char *s = talloc_asprintf(mem_ctx, "%d", v);
974 69276 : if (s == NULL) {
975 0 : return ldb_oom(sam_ldb);
976 : }
977 69276 : return ldb_msg_add_string_flags(msg, attr_name, s, flags);
978 : }
979 :
980 : /*
981 : * Add an unsigned int element to a message
982 : *
983 : * The issue here is that we have not yet first cast to int32_t explicitly,
984 : * before we cast to an signed int to printf() into the %d or cast to a
985 : * int64_t before we then cast to a long long to printf into a %lld.
986 : *
987 : * There are *no* unsigned integers in Active Directory LDAP, even the RID
988 : * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
989 : * (See the schema, and the syntax definitions in schema_syntax.c).
990 : *
991 : */
992 992155 : int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
993 : const char *attr_name, unsigned int v)
994 : {
995 992155 : return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
996 : }
997 :
998 69276 : int samdb_msg_add_uint_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
999 : const char *attr_name, unsigned int v, int flags)
1000 : {
1001 69276 : return samdb_msg_add_int_flags(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
1002 : }
1003 :
1004 : /*
1005 : add a (signed) int64_t element to a message
1006 : */
1007 3377770 : int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1008 : const char *attr_name, int64_t v)
1009 : {
1010 3377770 : const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
1011 3377770 : if (s == NULL) {
1012 0 : return ldb_oom(sam_ldb);
1013 : }
1014 3377770 : return ldb_msg_add_string(msg, attr_name, s);
1015 : }
1016 :
1017 : /*
1018 : * Add an unsigned int64_t (uint64_t) element to a message
1019 : *
1020 : * The issue here is that we have not yet first cast to int32_t explicitly,
1021 : * before we cast to an signed int to printf() into the %d or cast to a
1022 : * int64_t before we then cast to a long long to printf into a %lld.
1023 : *
1024 : * There are *no* unsigned integers in Active Directory LDAP, even the RID
1025 : * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1026 : * (See the schema, and the syntax definitions in schema_syntax.c).
1027 : *
1028 : */
1029 2487218 : int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1030 : const char *attr_name, uint64_t v)
1031 : {
1032 2487218 : return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
1033 : }
1034 :
1035 : /*
1036 : append a int element to a message
1037 : */
1038 724 : int samdb_msg_append_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1039 : const char *attr_name, int v, int flags)
1040 : {
1041 724 : const char *s = talloc_asprintf(mem_ctx, "%d", v);
1042 724 : if (s == NULL) {
1043 0 : return ldb_oom(sam_ldb);
1044 : }
1045 724 : return ldb_msg_append_string(msg, attr_name, s, flags);
1046 : }
1047 :
1048 : /*
1049 : * Append an unsigned int element to a message
1050 : *
1051 : * The issue here is that we have not yet first cast to int32_t explicitly,
1052 : * before we cast to an signed int to printf() into the %d or cast to a
1053 : * int64_t before we then cast to a long long to printf into a %lld.
1054 : *
1055 : * There are *no* unsigned integers in Active Directory LDAP, even the RID
1056 : * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1057 : * (See the schema, and the syntax definitions in schema_syntax.c).
1058 : *
1059 : */
1060 598 : int samdb_msg_append_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1061 : const char *attr_name, unsigned int v, int flags)
1062 : {
1063 598 : return samdb_msg_append_int(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
1064 : }
1065 :
1066 : /*
1067 : append a (signed) int64_t element to a message
1068 : */
1069 5606 : int samdb_msg_append_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1070 : const char *attr_name, int64_t v, int flags)
1071 : {
1072 5606 : const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
1073 5606 : if (s == NULL) {
1074 0 : return ldb_oom(sam_ldb);
1075 : }
1076 5606 : return ldb_msg_append_string(msg, attr_name, s, flags);
1077 : }
1078 :
1079 : /*
1080 : * Append an unsigned int64_t (uint64_t) element to a message
1081 : *
1082 : * The issue here is that we have not yet first cast to int32_t explicitly,
1083 : * before we cast to an signed int to printf() into the %d or cast to a
1084 : * int64_t before we then cast to a long long to printf into a %lld.
1085 : *
1086 : * There are *no* unsigned integers in Active Directory LDAP, even the RID
1087 : * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1088 : * (See the schema, and the syntax definitions in schema_syntax.c).
1089 : *
1090 : */
1091 5606 : int samdb_msg_append_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1092 : const char *attr_name, uint64_t v, int flags)
1093 : {
1094 5606 : return samdb_msg_append_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v, flags);
1095 : }
1096 :
1097 : /*
1098 : add a samr_Password element to a message
1099 : */
1100 20481 : int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1101 : const char *attr_name, const struct samr_Password *hash)
1102 : {
1103 211 : struct ldb_val val;
1104 20481 : val.data = talloc_memdup(mem_ctx, hash->hash, 16);
1105 20481 : if (!val.data) {
1106 0 : return ldb_oom(sam_ldb);
1107 : }
1108 20481 : val.length = 16;
1109 20481 : return ldb_msg_add_value(msg, attr_name, &val, NULL);
1110 : }
1111 :
1112 : /*
1113 : add a samr_Password array to a message
1114 : */
1115 20064 : int samdb_msg_add_hashes(struct ldb_context *ldb,
1116 : TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1117 : const char *attr_name, struct samr_Password *hashes,
1118 : unsigned int count)
1119 : {
1120 205 : struct ldb_val val;
1121 205 : unsigned int i;
1122 20064 : val.data = talloc_array_size(mem_ctx, 16, count);
1123 20064 : val.length = count*16;
1124 20064 : if (!val.data) {
1125 0 : return ldb_oom(ldb);
1126 : }
1127 53303 : for (i=0;i<count;i++) {
1128 33239 : memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
1129 : }
1130 20064 : return ldb_msg_add_value(msg, attr_name, &val, NULL);
1131 : }
1132 :
1133 : /*
1134 : add a acct_flags element to a message
1135 : */
1136 864 : int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1137 : const char *attr_name, uint32_t v)
1138 : {
1139 864 : return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
1140 : }
1141 :
1142 : /*
1143 : add a logon_hours element to a message
1144 : */
1145 99 : int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1146 : const char *attr_name, struct samr_LogonHours *hours)
1147 : {
1148 0 : struct ldb_val val;
1149 99 : val.length = hours->units_per_week / 8;
1150 99 : val.data = hours->bits;
1151 99 : return ldb_msg_add_value(msg, attr_name, &val, NULL);
1152 : }
1153 :
1154 : /*
1155 : add a parameters element to a message
1156 : */
1157 72 : int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
1158 : const char *attr_name, struct lsa_BinaryString *parameters)
1159 : {
1160 0 : int i;
1161 0 : struct ldb_val val;
1162 72 : if ((parameters->length % 2) != 0) {
1163 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1164 : }
1165 :
1166 72 : val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
1167 72 : if (val.data == NULL) {
1168 0 : return LDB_ERR_OPERATIONS_ERROR;
1169 : }
1170 72 : val.length = parameters->length;
1171 720 : for (i = 0; i < parameters->length / 2; i++) {
1172 : /*
1173 : * The on-disk format needs to be in the 'network'
1174 : * format, parameters->array is a uint16_t array of
1175 : * length parameters->length / 2
1176 : */
1177 648 : SSVAL(val.data, i * 2, parameters->array[i]);
1178 : }
1179 72 : return ldb_msg_add_steal_value(msg, attr_name, &val);
1180 : }
1181 :
1182 : /*
1183 : * Sets an unsigned int element in a message
1184 : *
1185 : * The issue here is that we have not yet first cast to int32_t explicitly,
1186 : * before we cast to an signed int to printf() into the %d or cast to a
1187 : * int64_t before we then cast to a long long to printf into a %lld.
1188 : *
1189 : * There are *no* unsigned integers in Active Directory LDAP, even the RID
1190 : * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
1191 : * (See the schema, and the syntax definitions in schema_syntax.c).
1192 : *
1193 : */
1194 48108 : int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
1195 : struct ldb_message *msg, const char *attr_name,
1196 : unsigned int v)
1197 : {
1198 106 : struct ldb_message_element *el;
1199 :
1200 48108 : el = ldb_msg_find_element(msg, attr_name);
1201 48108 : if (el) {
1202 24073 : el->num_values = 0;
1203 : }
1204 48108 : return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
1205 : }
1206 :
1207 : /*
1208 : * Handle ldb_request in transaction
1209 : */
1210 16065 : int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
1211 : struct ldb_request *req)
1212 : {
1213 258 : int ret;
1214 :
1215 16065 : ret = ldb_transaction_start(sam_ldb);
1216 16065 : if (ret != LDB_SUCCESS) {
1217 0 : return ret;
1218 : }
1219 :
1220 16065 : ret = ldb_request(sam_ldb, req);
1221 16065 : if (ret == LDB_SUCCESS) {
1222 16065 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1223 : }
1224 :
1225 16065 : if (ret == LDB_SUCCESS) {
1226 16035 : return ldb_transaction_commit(sam_ldb);
1227 : }
1228 30 : ldb_transaction_cancel(sam_ldb);
1229 :
1230 30 : return ret;
1231 : }
1232 :
1233 : /*
1234 : return a default security descriptor
1235 : */
1236 322 : struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1237 : {
1238 0 : struct security_descriptor *sd;
1239 :
1240 322 : sd = security_descriptor_initialise(mem_ctx);
1241 :
1242 322 : return sd;
1243 : }
1244 :
1245 181590 : struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1246 : {
1247 181590 : struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
1248 6077 : struct ldb_dn *aggregate_dn;
1249 181590 : if (!schema_dn) {
1250 0 : return NULL;
1251 : }
1252 :
1253 181590 : aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
1254 181590 : if (!aggregate_dn) {
1255 0 : return NULL;
1256 : }
1257 181590 : if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
1258 0 : return NULL;
1259 : }
1260 175513 : return aggregate_dn;
1261 : }
1262 :
1263 735529 : struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1264 : {
1265 26314 : struct ldb_dn *new_dn;
1266 :
1267 735529 : new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1268 735529 : if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1269 0 : talloc_free(new_dn);
1270 0 : return NULL;
1271 : }
1272 709215 : return new_dn;
1273 : }
1274 :
1275 4 : struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1276 : {
1277 0 : struct ldb_dn *new_dn;
1278 :
1279 4 : new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1280 4 : if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
1281 0 : talloc_free(new_dn);
1282 0 : return NULL;
1283 : }
1284 4 : return new_dn;
1285 : }
1286 :
1287 483101 : struct ldb_dn *samdb_system_container_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1288 : {
1289 483101 : struct ldb_dn *new_dn = NULL;
1290 17034 : bool ok;
1291 :
1292 483101 : new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
1293 483101 : if (new_dn == NULL) {
1294 0 : return NULL;
1295 : }
1296 :
1297 483101 : ok = ldb_dn_add_child_fmt(new_dn, "CN=System");
1298 483101 : if (!ok) {
1299 0 : TALLOC_FREE(new_dn);
1300 0 : return NULL;
1301 : }
1302 :
1303 466067 : return new_dn;
1304 : }
1305 :
1306 3528 : struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1307 : {
1308 96 : struct ldb_dn *new_dn;
1309 :
1310 3528 : new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1311 3528 : if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1312 0 : talloc_free(new_dn);
1313 0 : return NULL;
1314 : }
1315 3432 : return new_dn;
1316 : }
1317 :
1318 21277 : struct ldb_dn *samdb_extended_rights_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1319 : {
1320 246 : struct ldb_dn *new_dn;
1321 :
1322 21277 : new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1323 21277 : if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Extended-Rights")) {
1324 0 : talloc_free(new_dn);
1325 0 : return NULL;
1326 : }
1327 21031 : return new_dn;
1328 : }
1329 :
1330 387 : struct ldb_dn *samdb_configuration_dn(struct ldb_context *sam_ctx,
1331 : TALLOC_CTX *mem_ctx,
1332 : const char *dn_str)
1333 : {
1334 387 : struct ldb_dn *config_dn = NULL;
1335 387 : struct ldb_dn *child_dn = NULL;
1336 44 : bool ok;
1337 :
1338 387 : config_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
1339 387 : if (config_dn == NULL) {
1340 0 : return NULL;
1341 : }
1342 :
1343 387 : child_dn = ldb_dn_new(mem_ctx, sam_ctx, dn_str);
1344 387 : if (child_dn == NULL) {
1345 0 : talloc_free(config_dn);
1346 0 : return NULL;
1347 : }
1348 :
1349 387 : ok = ldb_dn_add_child(config_dn, child_dn);
1350 387 : talloc_free(child_dn);
1351 387 : if (!ok) {
1352 0 : talloc_free(config_dn);
1353 0 : return NULL;
1354 : }
1355 :
1356 343 : return config_dn;
1357 : }
1358 :
1359 287 : struct ldb_dn *samdb_gkdi_root_key_container_dn(struct ldb_context *sam_ctx,
1360 : TALLOC_CTX *mem_ctx)
1361 : {
1362 : /*
1363 : * [MS-GKDI] says the root key container is to be found in “CN=Sid Key
1364 : * Service,CN=Services”, but that is not correct.
1365 : */
1366 287 : return samdb_configuration_dn(sam_ctx,
1367 : mem_ctx,
1368 : "CN=Master Root Keys,"
1369 : "CN=Group Key Distribution Service,"
1370 : "CN=Services");
1371 : }
1372 :
1373 136 : struct ldb_dn *samdb_gkdi_root_key_dn(struct ldb_context *sam_ctx,
1374 : TALLOC_CTX *mem_ctx,
1375 : const struct GUID *root_key_id)
1376 : {
1377 136 : struct ldb_dn *root_key_dn = NULL;
1378 136 : struct ldb_dn *child_dn = NULL;
1379 22 : struct GUID_txt_buf guid_buf;
1380 136 : char *root_key_id_string = NULL;
1381 22 : bool ok;
1382 :
1383 136 : root_key_id_string = GUID_buf_string(root_key_id, &guid_buf);
1384 136 : if (root_key_id_string == NULL) {
1385 0 : return NULL;
1386 : }
1387 :
1388 136 : root_key_dn = samdb_gkdi_root_key_container_dn(sam_ctx, mem_ctx);
1389 136 : if (root_key_dn == NULL) {
1390 0 : return NULL;
1391 : }
1392 :
1393 136 : child_dn = ldb_dn_new_fmt(mem_ctx,
1394 : sam_ctx,
1395 : "CN=%s",
1396 : root_key_id_string);
1397 136 : if (child_dn == NULL) {
1398 0 : talloc_free(root_key_dn);
1399 0 : return NULL;
1400 : }
1401 :
1402 136 : ok = ldb_dn_add_child(root_key_dn, child_dn);
1403 136 : talloc_free(child_dn);
1404 136 : if (!ok) {
1405 0 : talloc_free(root_key_dn);
1406 0 : return NULL;
1407 : }
1408 :
1409 114 : return root_key_dn;
1410 : }
1411 :
1412 : /*
1413 : work out the domain sid for the current open ldb
1414 : */
1415 7423314 : const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1416 : {
1417 718808 : TALLOC_CTX *tmp_ctx;
1418 718808 : const struct dom_sid *domain_sid;
1419 7423314 : const char *attrs[] = {
1420 : "objectSid",
1421 : NULL
1422 : };
1423 718808 : struct ldb_result *res;
1424 718808 : int ret;
1425 :
1426 : /* see if we have a cached copy */
1427 7423314 : domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1428 7423314 : if (domain_sid) {
1429 6521041 : return domain_sid;
1430 : }
1431 :
1432 189677 : tmp_ctx = talloc_new(ldb);
1433 189677 : if (tmp_ctx == NULL) {
1434 0 : goto failed;
1435 : }
1436 :
1437 189677 : ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1438 :
1439 189677 : if (ret != LDB_SUCCESS) {
1440 425 : goto failed;
1441 : }
1442 :
1443 189252 : if (res->count != 1) {
1444 0 : goto failed;
1445 : }
1446 :
1447 189252 : domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1448 189252 : if (domain_sid == NULL) {
1449 0 : goto failed;
1450 : }
1451 :
1452 : /* cache the domain_sid in the ldb */
1453 189252 : if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1454 0 : goto failed;
1455 : }
1456 :
1457 189252 : talloc_steal(ldb, domain_sid);
1458 189252 : talloc_free(tmp_ctx);
1459 :
1460 189252 : return domain_sid;
1461 :
1462 425 : failed:
1463 425 : talloc_free(tmp_ctx);
1464 425 : return NULL;
1465 : }
1466 :
1467 : /*
1468 : get domain sid from cache
1469 : */
1470 15148 : const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
1471 : {
1472 15148 : return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1473 : }
1474 :
1475 127 : bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
1476 : {
1477 22 : TALLOC_CTX *tmp_ctx;
1478 22 : struct dom_sid *dom_sid_new;
1479 22 : struct dom_sid *dom_sid_old;
1480 :
1481 : /* see if we have a cached copy */
1482 127 : dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1483 : "cache.domain_sid"), struct dom_sid);
1484 :
1485 127 : tmp_ctx = talloc_new(ldb);
1486 127 : if (tmp_ctx == NULL) {
1487 0 : goto failed;
1488 : }
1489 :
1490 127 : dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1491 127 : if (!dom_sid_new) {
1492 0 : goto failed;
1493 : }
1494 :
1495 : /* cache the domain_sid in the ldb */
1496 127 : if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1497 0 : goto failed;
1498 : }
1499 :
1500 127 : talloc_steal(ldb, dom_sid_new);
1501 127 : talloc_free(tmp_ctx);
1502 127 : talloc_free(dom_sid_old);
1503 :
1504 127 : return true;
1505 :
1506 0 : failed:
1507 0 : DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1508 0 : talloc_free(tmp_ctx);
1509 0 : return false;
1510 : }
1511 :
1512 : /*
1513 : work out the domain guid for the current open ldb
1514 : */
1515 147 : const struct GUID *samdb_domain_guid(struct ldb_context *ldb)
1516 : {
1517 147 : TALLOC_CTX *tmp_ctx = NULL;
1518 147 : struct GUID *domain_guid = NULL;
1519 147 : const char *attrs[] = {
1520 : "objectGUID",
1521 : NULL
1522 : };
1523 147 : struct ldb_result *res = NULL;
1524 21 : int ret;
1525 :
1526 : /* see if we have a cached copy */
1527 147 : domain_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.domain_guid");
1528 147 : if (domain_guid) {
1529 0 : return domain_guid;
1530 : }
1531 :
1532 147 : tmp_ctx = talloc_new(ldb);
1533 147 : if (tmp_ctx == NULL) {
1534 0 : goto failed;
1535 : }
1536 :
1537 147 : ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectGUID=*");
1538 147 : if (ret != LDB_SUCCESS) {
1539 0 : goto failed;
1540 : }
1541 :
1542 147 : if (res->count != 1) {
1543 0 : goto failed;
1544 : }
1545 :
1546 147 : domain_guid = talloc(tmp_ctx, struct GUID);
1547 147 : if (domain_guid == NULL) {
1548 0 : goto failed;
1549 : }
1550 147 : *domain_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1551 :
1552 : /* cache the domain_sid in the ldb */
1553 147 : if (ldb_set_opaque(ldb, "cache.domain_guid", domain_guid) != LDB_SUCCESS) {
1554 0 : goto failed;
1555 : }
1556 :
1557 147 : talloc_steal(ldb, domain_guid);
1558 147 : talloc_free(tmp_ctx);
1559 :
1560 147 : return domain_guid;
1561 :
1562 0 : failed:
1563 0 : talloc_free(tmp_ctx);
1564 0 : return NULL;
1565 : }
1566 :
1567 342 : bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
1568 : {
1569 45 : TALLOC_CTX *tmp_ctx;
1570 45 : struct ldb_dn *ntds_settings_dn_new;
1571 45 : struct ldb_dn *ntds_settings_dn_old;
1572 :
1573 : /* see if we have a forced copy from provision */
1574 342 : ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
1575 : "forced.ntds_settings_dn"), struct ldb_dn);
1576 :
1577 342 : tmp_ctx = talloc_new(ldb);
1578 342 : if (tmp_ctx == NULL) {
1579 0 : goto failed;
1580 : }
1581 :
1582 342 : ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
1583 342 : if (!ntds_settings_dn_new) {
1584 0 : goto failed;
1585 : }
1586 :
1587 : /* set the DN in the ldb to avoid lookups during provision */
1588 342 : if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
1589 0 : goto failed;
1590 : }
1591 :
1592 342 : talloc_steal(ldb, ntds_settings_dn_new);
1593 342 : talloc_free(tmp_ctx);
1594 342 : talloc_free(ntds_settings_dn_old);
1595 :
1596 342 : return true;
1597 :
1598 0 : failed:
1599 0 : DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
1600 0 : talloc_free(tmp_ctx);
1601 0 : return false;
1602 : }
1603 :
1604 : /*
1605 : work out the ntds settings dn for the current open ldb
1606 : */
1607 436112 : struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1608 : {
1609 5130 : TALLOC_CTX *tmp_ctx;
1610 436112 : const char *root_attrs[] = { "dsServiceName", NULL };
1611 5130 : int ret;
1612 5130 : struct ldb_result *root_res;
1613 5130 : struct ldb_dn *settings_dn;
1614 :
1615 : /* see if we have a cached copy */
1616 436112 : settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
1617 436112 : if (settings_dn) {
1618 2367 : return ldb_dn_copy(mem_ctx, settings_dn);
1619 : }
1620 :
1621 433745 : tmp_ctx = talloc_new(mem_ctx);
1622 433745 : if (tmp_ctx == NULL) {
1623 0 : goto failed;
1624 : }
1625 :
1626 433745 : ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1627 433745 : if (ret != LDB_SUCCESS) {
1628 22 : DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1629 : ldb_errstring(ldb)));
1630 22 : goto failed;
1631 : }
1632 :
1633 433723 : if (root_res->count != 1) {
1634 0 : goto failed;
1635 : }
1636 :
1637 433723 : settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1638 :
1639 : /* note that we do not cache the DN here, as that would mean
1640 : * we could not handle server renames at runtime. Only
1641 : * provision sets up forced.ntds_settings_dn */
1642 :
1643 433723 : talloc_steal(mem_ctx, settings_dn);
1644 433723 : talloc_free(tmp_ctx);
1645 :
1646 433723 : return settings_dn;
1647 :
1648 22 : failed:
1649 22 : DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1650 22 : talloc_free(tmp_ctx);
1651 22 : return NULL;
1652 : }
1653 :
1654 : /*
1655 : work out the ntds settings invocationID/objectGUID for the current open ldb
1656 : */
1657 1785914 : static const struct GUID *samdb_ntds_GUID(struct ldb_context *ldb,
1658 : const char *attribute,
1659 : const char *cache_name)
1660 : {
1661 131729 : TALLOC_CTX *tmp_ctx;
1662 1785914 : const char *attrs[] = { attribute, NULL };
1663 131729 : int ret;
1664 131729 : struct ldb_result *res;
1665 131729 : struct GUID *ntds_guid;
1666 1785914 : struct ldb_dn *ntds_settings_dn = NULL;
1667 1785914 : const char *errstr = NULL;
1668 :
1669 : /* see if we have a cached copy */
1670 1785914 : ntds_guid = (struct GUID *)ldb_get_opaque(ldb, cache_name);
1671 1785914 : if (ntds_guid != NULL) {
1672 1582343 : return ntds_guid;
1673 : }
1674 :
1675 73385 : tmp_ctx = talloc_new(ldb);
1676 73385 : if (tmp_ctx == NULL) {
1677 0 : goto failed;
1678 : }
1679 :
1680 73385 : ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
1681 73385 : if (ntds_settings_dn == NULL) {
1682 19 : errstr = "samdb_ntds_settings_dn() returned NULL";
1683 19 : goto failed;
1684 : }
1685 :
1686 73366 : ret = ldb_search(ldb, tmp_ctx, &res, ntds_settings_dn,
1687 : LDB_SCOPE_BASE, attrs, NULL);
1688 73366 : if (ret) {
1689 0 : errstr = ldb_errstring(ldb);
1690 0 : goto failed;
1691 : }
1692 :
1693 73366 : if (res->count != 1) {
1694 0 : errstr = "incorrect number of results from base search";
1695 0 : goto failed;
1696 : }
1697 :
1698 73366 : ntds_guid = talloc(tmp_ctx, struct GUID);
1699 73366 : if (ntds_guid == NULL) {
1700 0 : goto failed;
1701 : }
1702 :
1703 73366 : *ntds_guid = samdb_result_guid(res->msgs[0], attribute);
1704 :
1705 73366 : if (GUID_all_zero(ntds_guid)) {
1706 0 : if (ldb_msg_find_ldb_val(res->msgs[0], attribute)) {
1707 0 : errstr = "failed to find the GUID attribute";
1708 : } else {
1709 0 : errstr = "failed to parse the GUID";
1710 : }
1711 0 : goto failed;
1712 : }
1713 :
1714 : /* cache the domain_sid in the ldb */
1715 73366 : if (ldb_set_opaque(ldb, cache_name, ntds_guid) != LDB_SUCCESS) {
1716 0 : errstr = "ldb_set_opaque() failed";
1717 0 : goto failed;
1718 : }
1719 :
1720 73366 : talloc_steal(ldb, ntds_guid);
1721 73366 : talloc_free(tmp_ctx);
1722 :
1723 73366 : return ntds_guid;
1724 :
1725 19 : failed:
1726 19 : DBG_WARNING("Failed to find our own NTDS Settings %s in the ldb: %s!\n",
1727 : attribute, errstr);
1728 19 : talloc_free(tmp_ctx);
1729 19 : return NULL;
1730 : }
1731 :
1732 : /*
1733 : work out the ntds settings objectGUID for the current open ldb
1734 : */
1735 68567 : const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
1736 : {
1737 68567 : return samdb_ntds_GUID(ldb, "objectGUID", "cache.ntds_guid");
1738 : }
1739 :
1740 : /*
1741 : work out the ntds settings invocationId for the current open ldb
1742 : */
1743 1717347 : const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
1744 : {
1745 1717347 : return samdb_ntds_GUID(ldb, "invocationId", "cache.invocation_id");
1746 : }
1747 :
1748 418 : static bool samdb_set_ntds_GUID(struct ldb_context *ldb,
1749 : const struct GUID *ntds_guid_in,
1750 : const char *attribute,
1751 : const char *cache_name)
1752 : {
1753 44 : TALLOC_CTX *tmp_ctx;
1754 44 : struct GUID *ntds_guid_new;
1755 44 : struct GUID *ntds_guid_old;
1756 :
1757 : /* see if we have a cached copy */
1758 418 : ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, cache_name);
1759 :
1760 418 : tmp_ctx = talloc_new(ldb);
1761 418 : if (tmp_ctx == NULL) {
1762 0 : goto failed;
1763 : }
1764 :
1765 418 : ntds_guid_new = talloc(tmp_ctx, struct GUID);
1766 418 : if (!ntds_guid_new) {
1767 0 : goto failed;
1768 : }
1769 :
1770 418 : *ntds_guid_new = *ntds_guid_in;
1771 :
1772 : /* cache the domain_sid in the ldb */
1773 418 : if (ldb_set_opaque(ldb, cache_name, ntds_guid_new) != LDB_SUCCESS) {
1774 0 : goto failed;
1775 : }
1776 :
1777 418 : talloc_steal(ldb, ntds_guid_new);
1778 418 : talloc_free(tmp_ctx);
1779 418 : talloc_free(ntds_guid_old);
1780 :
1781 418 : return true;
1782 :
1783 0 : failed:
1784 0 : DBG_WARNING("Failed to set our own cached %s in the ldb!\n",
1785 : attribute);
1786 0 : talloc_free(tmp_ctx);
1787 0 : return false;
1788 : }
1789 :
1790 76 : bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
1791 : {
1792 76 : return samdb_set_ntds_GUID(ldb,
1793 : ntds_guid_in,
1794 : "objectGUID",
1795 : "cache.ntds_guid");
1796 : }
1797 :
1798 342 : bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
1799 : {
1800 342 : return samdb_set_ntds_GUID(ldb,
1801 : invocation_id_in,
1802 : "invocationId",
1803 : "cache.invocation_id");
1804 : }
1805 :
1806 : /*
1807 : work out the server dn for the current open ldb
1808 : */
1809 122078 : struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1810 : {
1811 122078 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1812 767 : struct ldb_dn *dn;
1813 122078 : if (!tmp_ctx) {
1814 0 : return NULL;
1815 : }
1816 122078 : dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
1817 122078 : talloc_free(tmp_ctx);
1818 122078 : return dn;
1819 :
1820 : }
1821 :
1822 : /*
1823 : work out the server dn for the current open ldb
1824 : */
1825 10096 : struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
1826 : {
1827 294 : struct ldb_dn *server_dn;
1828 294 : struct ldb_dn *servers_dn;
1829 294 : struct ldb_dn *server_site_dn;
1830 :
1831 : /* TODO: there must be a saner way to do this!! */
1832 10096 : server_dn = samdb_server_dn(ldb, mem_ctx);
1833 10096 : if (!server_dn) return NULL;
1834 :
1835 10094 : servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1836 10094 : talloc_free(server_dn);
1837 10094 : if (!servers_dn) return NULL;
1838 :
1839 10094 : server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
1840 10094 : talloc_free(servers_dn);
1841 :
1842 10094 : return server_site_dn;
1843 : }
1844 :
1845 : /*
1846 : find the site name from a computers DN record
1847 : */
1848 5 : int samdb_find_site_for_computer(struct ldb_context *ldb,
1849 : TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
1850 : const char **site_name)
1851 : {
1852 0 : int ret;
1853 0 : struct ldb_dn *dn;
1854 0 : const struct ldb_val *rdn_val;
1855 :
1856 5 : *site_name = NULL;
1857 :
1858 5 : ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
1859 5 : if (ret != LDB_SUCCESS) {
1860 0 : return ret;
1861 : }
1862 :
1863 5 : if (!ldb_dn_remove_child_components(dn, 2)) {
1864 0 : talloc_free(dn);
1865 0 : return LDB_ERR_INVALID_DN_SYNTAX;
1866 : }
1867 :
1868 5 : rdn_val = ldb_dn_get_rdn_val(dn);
1869 5 : if (rdn_val == NULL) {
1870 0 : return LDB_ERR_OPERATIONS_ERROR;
1871 : }
1872 :
1873 5 : (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
1874 5 : talloc_free(dn);
1875 5 : if (!*site_name) {
1876 0 : return LDB_ERR_OPERATIONS_ERROR;
1877 : }
1878 5 : return LDB_SUCCESS;
1879 : }
1880 :
1881 : /*
1882 : find the NTDS GUID from a computers DN record
1883 : */
1884 5 : int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
1885 : struct GUID *ntds_guid)
1886 : {
1887 0 : int ret;
1888 0 : struct ldb_dn *dn;
1889 :
1890 5 : *ntds_guid = GUID_zero();
1891 :
1892 5 : ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
1893 5 : if (ret != LDB_SUCCESS) {
1894 0 : return ret;
1895 : }
1896 :
1897 5 : if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
1898 0 : talloc_free(dn);
1899 0 : return LDB_ERR_OPERATIONS_ERROR;
1900 : }
1901 :
1902 5 : ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
1903 5 : talloc_free(dn);
1904 5 : return ret;
1905 : }
1906 :
1907 : /*
1908 : find a 'reference' DN that points at another object
1909 : (eg. serverReference, rIDManagerReference etc)
1910 : */
1911 224527 : int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
1912 : const char *attribute, struct ldb_dn **dn)
1913 : {
1914 729 : const char *attrs[2];
1915 729 : struct ldb_result *res;
1916 729 : int ret;
1917 :
1918 224527 : attrs[0] = attribute;
1919 224527 : attrs[1] = NULL;
1920 :
1921 224527 : ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
1922 224527 : if (ret != LDB_SUCCESS) {
1923 0 : ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
1924 : ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
1925 0 : return ret;
1926 : }
1927 :
1928 224527 : *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
1929 224527 : if (!*dn) {
1930 4 : if (!ldb_msg_find_element(res->msgs[0], attribute)) {
1931 4 : ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
1932 : ldb_dn_get_linearized(base));
1933 : } else {
1934 0 : ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
1935 : ldb_dn_get_linearized(base));
1936 : }
1937 4 : talloc_free(res);
1938 4 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
1939 : }
1940 :
1941 224523 : talloc_free(res);
1942 224523 : return LDB_SUCCESS;
1943 : }
1944 :
1945 : /*
1946 : find if a DN (must have GUID component!) is our ntdsDsa
1947 : */
1948 4617 : int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
1949 : {
1950 82 : NTSTATUS status;
1951 82 : struct GUID dn_guid;
1952 82 : const struct GUID *our_ntds_guid;
1953 4617 : status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
1954 4617 : if (!NT_STATUS_IS_OK(status)) {
1955 0 : return LDB_ERR_OPERATIONS_ERROR;
1956 : }
1957 :
1958 4617 : our_ntds_guid = samdb_ntds_objectGUID(ldb);
1959 4617 : if (!our_ntds_guid) {
1960 0 : DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
1961 0 : return LDB_ERR_OPERATIONS_ERROR;
1962 : }
1963 :
1964 4617 : *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
1965 4617 : return LDB_SUCCESS;
1966 : }
1967 :
1968 : /*
1969 : find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
1970 : */
1971 3958 : int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
1972 : const char *attribute, bool *is_ntdsa)
1973 : {
1974 80 : int ret;
1975 80 : struct ldb_dn *referenced_dn;
1976 3958 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1977 3958 : if (tmp_ctx == NULL) {
1978 0 : return LDB_ERR_OPERATIONS_ERROR;
1979 : }
1980 3958 : ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
1981 3958 : if (ret != LDB_SUCCESS) {
1982 0 : DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
1983 0 : return ret;
1984 : }
1985 :
1986 3958 : ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
1987 :
1988 3958 : talloc_free(tmp_ctx);
1989 3958 : return ret;
1990 : }
1991 :
1992 : /*
1993 : find our machine account via the serverReference attribute in the
1994 : server DN
1995 : */
1996 107803 : int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
1997 : {
1998 334 : struct ldb_dn *server_dn;
1999 334 : int ret;
2000 :
2001 107803 : server_dn = samdb_server_dn(ldb, mem_ctx);
2002 107803 : if (server_dn == NULL) {
2003 0 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
2004 : }
2005 :
2006 107803 : ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
2007 107803 : talloc_free(server_dn);
2008 :
2009 107803 : return ret;
2010 : }
2011 :
2012 : /*
2013 : find the RID Manager$ DN via the rIDManagerReference attribute in the
2014 : base DN
2015 : */
2016 270 : int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
2017 : {
2018 270 : return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
2019 : "rIDManagerReference", dn);
2020 : }
2021 :
2022 : /*
2023 : find the RID Set DN via the rIDSetReferences attribute in our
2024 : machine account DN
2025 : */
2026 107703 : int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
2027 : {
2028 107703 : struct ldb_dn *server_ref_dn = NULL;
2029 311 : int ret;
2030 :
2031 107703 : ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
2032 107703 : if (ret != LDB_SUCCESS) {
2033 0 : return ret;
2034 : }
2035 107703 : ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
2036 107703 : talloc_free(server_ref_dn);
2037 107703 : return ret;
2038 : }
2039 :
2040 7881 : const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
2041 : {
2042 7881 : const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
2043 : mem_ctx));
2044 :
2045 7881 : if (val == NULL) {
2046 2 : return NULL;
2047 : }
2048 :
2049 7879 : return (const char *) val->data;
2050 : }
2051 :
2052 : /*
2053 : * Finds the client site by using the client's IP address.
2054 : * The "subnet_name" returns the name of the subnet if parameter != NULL
2055 : *
2056 : * Has a Windows-based fallback to provide the only site available, or an empty
2057 : * string if there are multiple sites.
2058 : */
2059 3620 : const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2060 : const char *ip_address, char **subnet_name,
2061 : bool fallback)
2062 : {
2063 3620 : const char *attrs[] = { "cn", "siteObject", NULL };
2064 3620 : struct ldb_dn *sites_container_dn = NULL;
2065 3620 : struct ldb_dn *subnets_dn = NULL;
2066 3620 : struct ldb_dn *sites_dn = NULL;
2067 3620 : struct ldb_result *res = NULL;
2068 3620 : const struct ldb_val *val = NULL;
2069 3620 : const char *site_name = NULL;
2070 3620 : const char *l_subnet_name = NULL;
2071 3620 : const char *allow_list[2] = { NULL, NULL };
2072 98 : unsigned int i, count;
2073 98 : int ret;
2074 :
2075 : /*
2076 : * if we don't have a client ip e.g. ncalrpc
2077 : * the server site is the client site
2078 : */
2079 3620 : if (ip_address == NULL) {
2080 98 : return samdb_server_site_name(ldb, mem_ctx);
2081 : }
2082 :
2083 3522 : sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
2084 3522 : if (sites_container_dn == NULL) {
2085 0 : goto exit;
2086 : }
2087 :
2088 3522 : subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
2089 3522 : if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
2090 0 : goto exit;
2091 : }
2092 :
2093 3522 : ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
2094 : attrs, NULL);
2095 3522 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2096 0 : count = 0;
2097 3522 : } else if (ret != LDB_SUCCESS) {
2098 0 : goto exit;
2099 : } else {
2100 3522 : count = res->count;
2101 : }
2102 :
2103 3522 : for (i = 0; i < count; i++) {
2104 0 : l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
2105 : NULL);
2106 :
2107 0 : allow_list[0] = l_subnet_name;
2108 :
2109 0 : if (allow_access_nolog(NULL, allow_list, "", ip_address)) {
2110 0 : sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
2111 0 : res->msgs[i],
2112 : "siteObject");
2113 0 : if (sites_dn == NULL) {
2114 : /* No reference, maybe another subnet matches */
2115 0 : continue;
2116 : }
2117 :
2118 : /* "val" cannot be NULL here since "sites_dn" != NULL */
2119 0 : val = ldb_dn_get_rdn_val(sites_dn);
2120 0 : site_name = talloc_strdup(mem_ctx,
2121 0 : (const char *) val->data);
2122 :
2123 0 : TALLOC_FREE(sites_dn);
2124 :
2125 0 : break;
2126 : }
2127 : }
2128 :
2129 3522 : if (site_name == NULL && fallback) {
2130 : /* This is the Windows Server fallback rule: when no subnet
2131 : * exists and we have only one site available then use it (it
2132 : * is for sure the same as our server site). If more sites do
2133 : * exist then we don't know which one to use and set the site
2134 : * name to "". */
2135 3458 : size_t cnt = 0;
2136 3458 : ret = dsdb_domain_count(
2137 : ldb,
2138 : &cnt,
2139 : sites_container_dn,
2140 : NULL,
2141 : LDB_SCOPE_SUBTREE,
2142 : "(objectClass=site)");
2143 3458 : if (ret != LDB_SUCCESS) {
2144 0 : goto exit;
2145 : }
2146 3458 : if (cnt == 1) {
2147 3318 : site_name = samdb_server_site_name(ldb, mem_ctx);
2148 : } else {
2149 140 : site_name = talloc_strdup(mem_ctx, "");
2150 : }
2151 3458 : l_subnet_name = NULL;
2152 : }
2153 :
2154 3522 : if (subnet_name != NULL) {
2155 216 : *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
2156 : }
2157 :
2158 3306 : exit:
2159 3522 : TALLOC_FREE(sites_container_dn);
2160 3522 : TALLOC_FREE(subnets_dn);
2161 3522 : TALLOC_FREE(res);
2162 :
2163 3426 : return site_name;
2164 : }
2165 :
2166 : /*
2167 : work out if we are the PDC for the domain of the current open ldb
2168 : */
2169 3892 : bool samdb_is_pdc(struct ldb_context *ldb)
2170 : {
2171 80 : int ret;
2172 80 : bool is_pdc;
2173 :
2174 3892 : ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner",
2175 : &is_pdc);
2176 3892 : if (ret != LDB_SUCCESS) {
2177 0 : DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n",
2178 : ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
2179 : ldb_errstring(ldb)));
2180 0 : return false;
2181 : }
2182 :
2183 3892 : return is_pdc;
2184 : }
2185 :
2186 : /*
2187 : work out if we are a Global Catalog server for the domain of the current open ldb
2188 : */
2189 4299 : bool samdb_is_gc(struct ldb_context *ldb)
2190 : {
2191 4299 : uint32_t options = 0;
2192 4299 : if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
2193 0 : return false;
2194 : }
2195 4299 : return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
2196 : }
2197 :
2198 : /* Find a domain object in the parents of a particular DN. */
2199 12 : int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
2200 : struct ldb_dn **parent_dn, const char **errstring)
2201 : {
2202 0 : TALLOC_CTX *local_ctx;
2203 12 : struct ldb_dn *sdn = dn;
2204 12 : struct ldb_result *res = NULL;
2205 12 : int ret = LDB_SUCCESS;
2206 12 : const char *attrs[] = { NULL };
2207 :
2208 12 : local_ctx = talloc_new(mem_ctx);
2209 12 : if (local_ctx == NULL) return ldb_oom(ldb);
2210 :
2211 24 : while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
2212 24 : ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
2213 : "(|(objectClass=domain)(objectClass=builtinDomain))");
2214 24 : if (ret == LDB_SUCCESS) {
2215 24 : if (res->count == 1) {
2216 12 : break;
2217 : }
2218 : } else {
2219 0 : break;
2220 : }
2221 : }
2222 :
2223 12 : if (ret != LDB_SUCCESS) {
2224 0 : *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
2225 : ldb_dn_get_linearized(dn),
2226 : ldb_dn_get_linearized(sdn),
2227 : ldb_errstring(ldb));
2228 0 : talloc_free(local_ctx);
2229 0 : return ret;
2230 : }
2231 : /* should never be true with 'ret=LDB_SUCCESS', here to satisfy clang */
2232 12 : if (res == NULL) {
2233 0 : talloc_free(local_ctx);
2234 0 : return LDB_ERR_OTHER;
2235 : }
2236 12 : if (res->count != 1) {
2237 0 : *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
2238 : ldb_dn_get_linearized(dn));
2239 0 : DEBUG(0,(__location__ ": %s\n", *errstring));
2240 0 : talloc_free(local_ctx);
2241 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
2242 : }
2243 :
2244 12 : *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
2245 12 : talloc_free(local_ctx);
2246 12 : return ret;
2247 : }
2248 :
2249 0 : static void pwd_timeout_debug(struct tevent_context *unused1,
2250 : struct tevent_timer *unused2,
2251 : struct timeval unused3,
2252 : void *unused4)
2253 : {
2254 0 : DEBUG(0, ("WARNING: check_password_complexity: password script "
2255 : "took more than 1 second to run\n"));
2256 0 : }
2257 :
2258 :
2259 : /*
2260 : * Performs checks on a user password (plaintext UNIX format - attribute
2261 : * "password"). The remaining parameters have to be extracted from the domain
2262 : * object in the AD.
2263 : *
2264 : * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
2265 : */
2266 17458 : enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
2267 : struct loadparm_context *lp_ctx,
2268 : const char *account_name,
2269 : const char *user_principal_name,
2270 : const char *full_name,
2271 : const DATA_BLOB *utf8_blob,
2272 : const uint32_t pwdProperties,
2273 : const uint32_t minPwdLength)
2274 : {
2275 56 : const struct loadparm_substitution *lp_sub =
2276 17458 : lpcfg_noop_substitution();
2277 17458 : char *password_script = NULL;
2278 17458 : const char *utf8_pw = (const char *)utf8_blob->data;
2279 :
2280 : /*
2281 : * This looks strange because it is.
2282 : *
2283 : * The check for the number of characters in the password
2284 : * should clearly not be against the byte length, or else a
2285 : * single UTF8 character would count for more than one.
2286 : *
2287 : * We have chosen to use the number of 16-bit units that the
2288 : * password encodes to as the measure of length. This is not
2289 : * the same as the number of codepoints, if a password
2290 : * contains a character beyond the Basic Multilingual Plane
2291 : * (above 65535) it will count for more than one "character".
2292 : */
2293 :
2294 17458 : size_t password_characters_roughly = strlen_m(utf8_pw);
2295 :
2296 : /* checks if the "minPwdLength" property is satisfied */
2297 17458 : if (minPwdLength > password_characters_roughly) {
2298 191 : return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
2299 : }
2300 :
2301 : /* We might not be asked to check the password complexity */
2302 17267 : if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
2303 83 : return SAMR_VALIDATION_STATUS_SUCCESS;
2304 : }
2305 :
2306 17184 : if (password_characters_roughly == 0) {
2307 0 : return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2308 : }
2309 :
2310 17184 : password_script = lpcfg_check_password_script(lp_ctx, lp_sub, mem_ctx);
2311 17184 : if (password_script != NULL && *password_script != '\0') {
2312 23 : int check_ret = 0;
2313 23 : int error = 0;
2314 23 : ssize_t nwritten = 0;
2315 23 : struct tevent_context *event_ctx = NULL;
2316 23 : struct tevent_req *req = NULL;
2317 23 : int cps_stdin = -1;
2318 23 : const char * const cmd[4] = {
2319 : "/bin/sh", "-c",
2320 : password_script,
2321 : NULL
2322 : };
2323 :
2324 23 : event_ctx = tevent_context_init(mem_ctx);
2325 23 : if (event_ctx == NULL) {
2326 0 : TALLOC_FREE(password_script);
2327 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2328 : }
2329 :
2330 : /* Gives a warning after 1 second, terminates after 10 */
2331 23 : tevent_add_timer(event_ctx, event_ctx,
2332 : tevent_timeval_current_ofs(1, 0),
2333 : pwd_timeout_debug, NULL);
2334 :
2335 23 : check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", account_name, 1);
2336 23 : if (check_ret != 0) {
2337 0 : TALLOC_FREE(password_script);
2338 0 : TALLOC_FREE(event_ctx);
2339 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2340 : }
2341 23 : if (user_principal_name != NULL) {
2342 20 : check_ret = setenv("SAMBA_CPS_USER_PRINCIPAL_NAME",
2343 : user_principal_name, 1);
2344 : } else {
2345 3 : unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
2346 : }
2347 23 : if (check_ret != 0) {
2348 0 : TALLOC_FREE(password_script);
2349 0 : TALLOC_FREE(event_ctx);
2350 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2351 : }
2352 23 : if (full_name != NULL) {
2353 0 : check_ret = setenv("SAMBA_CPS_FULL_NAME", full_name, 1);
2354 : } else {
2355 23 : unsetenv("SAMBA_CPS_FULL_NAME");
2356 : }
2357 23 : if (check_ret != 0) {
2358 0 : TALLOC_FREE(password_script);
2359 0 : TALLOC_FREE(event_ctx);
2360 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2361 : }
2362 :
2363 23 : req = samba_runcmd_send(event_ctx, event_ctx,
2364 : tevent_timeval_current_ofs(10, 0),
2365 : 100, 100, cmd, NULL);
2366 23 : unsetenv("SAMBA_CPS_ACCOUNT_NAME");
2367 23 : unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
2368 23 : unsetenv("SAMBA_CPS_FULL_NAME");
2369 23 : if (req == NULL) {
2370 0 : TALLOC_FREE(password_script);
2371 0 : TALLOC_FREE(event_ctx);
2372 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2373 : }
2374 :
2375 23 : cps_stdin = samba_runcmd_export_stdin(req);
2376 :
2377 23 : nwritten = write_data(
2378 23 : cps_stdin, utf8_blob->data, utf8_blob->length);
2379 23 : if (nwritten == -1) {
2380 0 : close(cps_stdin);
2381 0 : TALLOC_FREE(password_script);
2382 0 : TALLOC_FREE(event_ctx);
2383 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2384 : }
2385 :
2386 23 : close(cps_stdin);
2387 :
2388 23 : if (!tevent_req_poll(req, event_ctx)) {
2389 0 : TALLOC_FREE(password_script);
2390 0 : TALLOC_FREE(event_ctx);
2391 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2392 : }
2393 :
2394 23 : check_ret = samba_runcmd_recv(req, &error);
2395 23 : TALLOC_FREE(event_ctx);
2396 :
2397 23 : if (error == ETIMEDOUT) {
2398 0 : DEBUG(0, ("check_password_complexity: check password script took too long!\n"));
2399 0 : TALLOC_FREE(password_script);
2400 0 : return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
2401 : }
2402 23 : DEBUG(5,("check_password_complexity: check password script (%s) "
2403 : "returned [%d]\n", password_script, check_ret));
2404 :
2405 23 : if (check_ret != 0) {
2406 6 : DEBUG(1,("check_password_complexity: "
2407 : "check password script said new password is not good "
2408 : "enough!\n"));
2409 6 : TALLOC_FREE(password_script);
2410 6 : return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2411 : }
2412 :
2413 17 : TALLOC_FREE(password_script);
2414 17 : return SAMR_VALIDATION_STATUS_SUCCESS;
2415 : }
2416 :
2417 17161 : TALLOC_FREE(password_script);
2418 :
2419 : /*
2420 : * Here are the standard AD password quality rules, which we
2421 : * run after the script.
2422 : */
2423 :
2424 17161 : if (!check_password_quality(utf8_pw)) {
2425 47 : return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
2426 : }
2427 :
2428 17058 : return SAMR_VALIDATION_STATUS_SUCCESS;
2429 : }
2430 :
2431 : /*
2432 : * Callback for "samdb_set_password" password change
2433 : */
2434 2124 : int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
2435 : {
2436 103 : int ret;
2437 :
2438 2124 : if (!ares) {
2439 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2440 : }
2441 :
2442 2124 : if (ares->error != LDB_SUCCESS) {
2443 204 : ret = ares->error;
2444 204 : req->context = talloc_steal(req,
2445 : ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2446 204 : talloc_free(ares);
2447 204 : return ldb_request_done(req, ret);
2448 : }
2449 :
2450 1920 : if (ares->type != LDB_REPLY_DONE) {
2451 0 : talloc_free(ares);
2452 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
2453 : }
2454 :
2455 1920 : req->context = talloc_steal(req,
2456 : ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
2457 1920 : talloc_free(ares);
2458 1920 : return ldb_request_done(req, LDB_SUCCESS);
2459 : }
2460 :
2461 2138 : static NTSTATUS samdb_set_password_request(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2462 : struct ldb_dn *user_dn,
2463 : const DATA_BLOB *new_password,
2464 : const struct samr_Password *ntNewHash,
2465 : enum dsdb_password_checked old_password_checked,
2466 : bool permit_interdomain_trust,
2467 : struct ldb_request **req_out)
2468 : {
2469 103 : struct ldb_message *msg;
2470 103 : struct ldb_message_element *el;
2471 103 : struct ldb_request *req;
2472 103 : int ret;
2473 2138 : bool hash_values = false;
2474 :
2475 2138 : *req_out = NULL;
2476 :
2477 : #define CHECK_RET(x) \
2478 : if (x != LDB_SUCCESS) { \
2479 : talloc_free(msg); \
2480 : return NT_STATUS_NO_MEMORY; \
2481 : }
2482 :
2483 2138 : msg = ldb_msg_new(mem_ctx);
2484 2138 : if (msg == NULL) {
2485 0 : return NT_STATUS_NO_MEMORY;
2486 : }
2487 2138 : msg->dn = user_dn;
2488 2138 : if ((new_password != NULL)
2489 1784 : && ((ntNewHash == NULL))) {
2490 : /* we have the password as plaintext UTF16 */
2491 1778 : CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
2492 97 : new_password, NULL));
2493 1778 : el = ldb_msg_find_element(msg, "clearTextPassword");
2494 1778 : el->flags = LDB_FLAG_MOD_REPLACE;
2495 360 : } else if ((new_password == NULL)
2496 360 : && ((ntNewHash != NULL))) {
2497 : /* we have a password as NT hash */
2498 360 : if (ntNewHash != NULL) {
2499 360 : CHECK_RET(samdb_msg_add_hash(ldb, msg, msg,
2500 6 : "unicodePwd", ntNewHash));
2501 360 : el = ldb_msg_find_element(msg, "unicodePwd");
2502 360 : el->flags = LDB_FLAG_MOD_REPLACE;
2503 : }
2504 360 : hash_values = true;
2505 : } else {
2506 : /* the password wasn't specified correctly */
2507 0 : talloc_free(msg);
2508 0 : return NT_STATUS_INVALID_PARAMETER;
2509 : }
2510 :
2511 : #undef CHECK_RET
2512 :
2513 : /* build modify request */
2514 2138 : ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
2515 : samdb_set_password_callback, NULL);
2516 2138 : if (ret != LDB_SUCCESS) {
2517 0 : talloc_free(msg);
2518 0 : return NT_STATUS_NO_MEMORY;
2519 : }
2520 :
2521 : /* Tie the lifetime of the message to that of the request. */
2522 2138 : talloc_steal(req, msg);
2523 :
2524 : /* A password change operation */
2525 2138 : if (old_password_checked == DSDB_PASSWORD_CHECKED_AND_CORRECT) {
2526 31 : struct dsdb_control_password_change *change;
2527 :
2528 883 : change = talloc(req, struct dsdb_control_password_change);
2529 883 : if (change == NULL) {
2530 0 : talloc_free(req);
2531 0 : return NT_STATUS_NO_MEMORY;
2532 : }
2533 :
2534 883 : change->old_password_checked = old_password_checked;
2535 :
2536 883 : ret = ldb_request_add_control(req,
2537 : DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID,
2538 : true, change);
2539 883 : if (ret != LDB_SUCCESS) {
2540 0 : talloc_free(req);
2541 0 : return NT_STATUS_NO_MEMORY;
2542 : }
2543 : }
2544 2138 : if (hash_values) {
2545 360 : ret = ldb_request_add_control(req,
2546 : DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
2547 : true, NULL);
2548 360 : if (ret != LDB_SUCCESS) {
2549 0 : talloc_free(req);
2550 0 : return NT_STATUS_NO_MEMORY;
2551 : }
2552 : }
2553 2138 : if (permit_interdomain_trust) {
2554 414 : ret = ldb_request_add_control(req,
2555 : DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
2556 : false, NULL);
2557 414 : if (ret != LDB_SUCCESS) {
2558 0 : talloc_free(req);
2559 0 : return NT_STATUS_NO_MEMORY;
2560 : }
2561 : }
2562 2138 : ret = ldb_request_add_control(req,
2563 : DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
2564 : true, NULL);
2565 2138 : if (ret != LDB_SUCCESS) {
2566 0 : talloc_free(req);
2567 0 : return NT_STATUS_NO_MEMORY;
2568 : }
2569 :
2570 2138 : *req_out = req;
2571 :
2572 2138 : return NT_STATUS_OK;
2573 : }
2574 :
2575 : /*
2576 : * Sets the user password using plaintext UTF16 (attribute "new_password") or NT
2577 : * (attribute "ntNewHash") hash. Also pass the old LM and/or NT hash (attributes
2578 : * "lmOldHash"/"ntOldHash") if it is a user change or not. The "rejectReason"
2579 : * gives some more information if the change failed.
2580 : *
2581 : * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2582 : * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2583 : * NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_NO_MEMORY
2584 : */
2585 2093 : static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2586 : struct ldb_dn *user_dn,
2587 : const DATA_BLOB *new_password,
2588 : const struct samr_Password *ntNewHash,
2589 : enum dsdb_password_checked old_password_checked,
2590 : enum samPwdChangeReason *reject_reason,
2591 : struct samr_DomInfo1 **_dominfo,
2592 : bool permit_interdomain_trust)
2593 : {
2594 103 : struct ldb_request *req;
2595 2093 : struct dsdb_control_password_change_status *pwd_stat = NULL;
2596 103 : int ret;
2597 2093 : NTSTATUS status = NT_STATUS_OK;
2598 :
2599 2093 : status = samdb_set_password_request(ldb,
2600 : mem_ctx,
2601 : user_dn,
2602 : new_password,
2603 : ntNewHash,
2604 : old_password_checked,
2605 : permit_interdomain_trust,
2606 : &req);
2607 2093 : if (!NT_STATUS_IS_OK(status)) {
2608 0 : return status;
2609 : }
2610 :
2611 2093 : ret = ldb_request(ldb, req);
2612 2093 : if (ret == LDB_SUCCESS) {
2613 2077 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
2614 : }
2615 :
2616 2093 : if (req->context != NULL) {
2617 2077 : struct ldb_control *control = talloc_get_type_abort(req->context,
2618 : struct ldb_control);
2619 2077 : pwd_stat = talloc_get_type_abort(control->data,
2620 : struct dsdb_control_password_change_status);
2621 2077 : talloc_steal(mem_ctx, pwd_stat);
2622 : }
2623 :
2624 2093 : talloc_free(req);
2625 :
2626 : /* Sets the domain info (if requested) */
2627 2093 : if (_dominfo != NULL) {
2628 0 : struct samr_DomInfo1 *dominfo;
2629 :
2630 467 : dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
2631 467 : if (dominfo == NULL) {
2632 0 : return NT_STATUS_NO_MEMORY;
2633 : }
2634 :
2635 467 : if (pwd_stat != NULL) {
2636 452 : dominfo->min_password_length = pwd_stat->domain_data.minPwdLength;
2637 452 : dominfo->password_properties = pwd_stat->domain_data.pwdProperties;
2638 452 : dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
2639 452 : dominfo->max_password_age = pwd_stat->domain_data.maxPwdAge;
2640 452 : dominfo->min_password_age = pwd_stat->domain_data.minPwdAge;
2641 : }
2642 :
2643 467 : *_dominfo = dominfo;
2644 : }
2645 :
2646 2093 : if (reject_reason != NULL) {
2647 467 : if (pwd_stat != NULL) {
2648 452 : *reject_reason = pwd_stat->reject_reason;
2649 : } else {
2650 15 : *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
2651 : }
2652 : }
2653 :
2654 2093 : if (pwd_stat != NULL) {
2655 2077 : talloc_free(pwd_stat);
2656 : }
2657 :
2658 2093 : if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
2659 188 : const char *errmsg = ldb_errstring(ldb);
2660 188 : char *endptr = NULL;
2661 188 : WERROR werr = WERR_GEN_FAILURE;
2662 188 : status = NT_STATUS_UNSUCCESSFUL;
2663 188 : if (errmsg != NULL) {
2664 188 : werr = W_ERROR(strtol(errmsg, &endptr, 16));
2665 188 : DBG_WARNING("%s\n", errmsg);
2666 : }
2667 188 : if (endptr != errmsg) {
2668 188 : if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
2669 0 : status = NT_STATUS_WRONG_PASSWORD;
2670 : }
2671 188 : if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
2672 188 : status = NT_STATUS_PASSWORD_RESTRICTION;
2673 : }
2674 188 : if (W_ERROR_EQUAL(werr, WERR_ACCOUNT_LOCKED_OUT)) {
2675 0 : status = NT_STATUS_ACCOUNT_LOCKED_OUT;
2676 : }
2677 : }
2678 1905 : } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2679 : /* don't let the caller know if an account doesn't exist */
2680 0 : status = NT_STATUS_WRONG_PASSWORD;
2681 1802 : } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
2682 16 : status = NT_STATUS_ACCESS_DENIED;
2683 1786 : } else if (ret != LDB_SUCCESS) {
2684 0 : DEBUG(1, ("Failed to set password on %s: %s\n",
2685 : ldb_dn_get_linearized(user_dn),
2686 : ldb_errstring(ldb)));
2687 0 : status = NT_STATUS_UNSUCCESSFUL;
2688 : }
2689 :
2690 2093 : return status;
2691 : }
2692 :
2693 1679 : NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2694 : struct ldb_dn *user_dn,
2695 : const DATA_BLOB *new_password,
2696 : const struct samr_Password *ntNewHash,
2697 : enum dsdb_password_checked old_password_checked,
2698 : enum samPwdChangeReason *reject_reason,
2699 : struct samr_DomInfo1 **_dominfo)
2700 : {
2701 1679 : return samdb_set_password_internal(ldb, mem_ctx,
2702 : user_dn,
2703 : new_password,
2704 : ntNewHash,
2705 : old_password_checked,
2706 : reject_reason, _dominfo,
2707 : false); /* reject trusts */
2708 : }
2709 :
2710 : /*
2711 : * Sets the user password using plaintext UTF16 (attribute "new_password") or NT
2712 : * (attribute "ntNewHash") hash. Also pass the old LM and/or NT hash (attributes
2713 : * "lmOldHash"/"ntOldHash") if it is a user change or not. The "rejectReason"
2714 : * gives some more information if the change failed.
2715 : *
2716 : * This wrapper function for "samdb_set_password" takes a SID as input rather
2717 : * than a user DN.
2718 : *
2719 : * This call encapsulates a new LDB transaction for changing the password;
2720 : * therefore the user hasn't to start a new one.
2721 : *
2722 : * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
2723 : * NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
2724 : * NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
2725 : * NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_NO_MEMORY
2726 : * NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
2727 : */
2728 414 : NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
2729 : const struct dom_sid *user_sid,
2730 : const uint32_t *new_version, /* optional for trusts */
2731 : const DATA_BLOB *new_password,
2732 : const struct samr_Password *ntNewHash,
2733 : enum dsdb_password_checked old_password_checked,
2734 : enum samPwdChangeReason *reject_reason,
2735 : struct samr_DomInfo1 **_dominfo)
2736 : {
2737 414 : TALLOC_CTX *frame = talloc_stackframe();
2738 31 : NTSTATUS nt_status;
2739 31 : static const char * const attrs[] = {
2740 : "userAccountControl",
2741 : "sAMAccountName",
2742 : NULL
2743 : };
2744 414 : struct ldb_message *user_msg = NULL;
2745 31 : int ret;
2746 414 : uint32_t uac = 0;
2747 :
2748 414 : ret = ldb_transaction_start(ldb);
2749 414 : if (ret != LDB_SUCCESS) {
2750 0 : DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
2751 0 : TALLOC_FREE(frame);
2752 0 : return NT_STATUS_TRANSACTION_ABORTED;
2753 : }
2754 :
2755 414 : ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
2756 : LDB_SCOPE_SUBTREE, attrs, 0,
2757 : "(&(objectSid=%s)(objectClass=user))",
2758 : ldap_encode_ndr_dom_sid(frame, user_sid));
2759 414 : if (ret != LDB_SUCCESS) {
2760 0 : ldb_transaction_cancel(ldb);
2761 0 : DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
2762 : "returning NO_SUCH_USER\n",
2763 : dom_sid_string(frame, user_sid),
2764 : ldb_strerror(ret), ldb_errstring(ldb)));
2765 0 : TALLOC_FREE(frame);
2766 0 : return NT_STATUS_NO_SUCH_USER;
2767 : }
2768 :
2769 414 : uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
2770 414 : if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
2771 0 : ldb_transaction_cancel(ldb);
2772 0 : DEBUG(1, ("samdb_set_password_sid: invalid "
2773 : "userAccountControl[0x%08X] for SID[%s] DN[%s], "
2774 : "returning NO_SUCH_USER\n",
2775 : (unsigned)uac, dom_sid_string(frame, user_sid),
2776 : ldb_dn_get_linearized(user_msg->dn)));
2777 0 : TALLOC_FREE(frame);
2778 0 : return NT_STATUS_NO_SUCH_USER;
2779 : }
2780 :
2781 414 : if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
2782 0 : static const char * const tdo_attrs[] = {
2783 : "trustAuthIncoming",
2784 : "trustDirection",
2785 : NULL
2786 : };
2787 114 : struct ldb_message *tdo_msg = NULL;
2788 114 : const char *account_name = NULL;
2789 0 : uint32_t trust_direction;
2790 0 : uint32_t i;
2791 114 : const struct ldb_val *old_val = NULL;
2792 114 : struct trustAuthInOutBlob old_blob = {
2793 : .count = 0,
2794 : };
2795 114 : uint32_t old_version = 0;
2796 114 : struct AuthenticationInformation *old_version_a = NULL;
2797 114 : uint32_t _new_version = 0;
2798 114 : struct trustAuthInOutBlob new_blob = {
2799 : .count = 0,
2800 : };
2801 114 : struct ldb_val new_val = {
2802 : .length = 0,
2803 : };
2804 114 : struct timeval tv = timeval_current();
2805 114 : NTTIME now = timeval_to_nttime(&tv);
2806 0 : enum ndr_err_code ndr_err;
2807 :
2808 114 : if (new_password == NULL && ntNewHash == NULL) {
2809 0 : ldb_transaction_cancel(ldb);
2810 0 : DEBUG(1, ("samdb_set_password_sid: "
2811 : "no new password provided "
2812 : "sAMAccountName for SID[%s] DN[%s], "
2813 : "returning INVALID_PARAMETER\n",
2814 : dom_sid_string(frame, user_sid),
2815 : ldb_dn_get_linearized(user_msg->dn)));
2816 0 : TALLOC_FREE(frame);
2817 0 : return NT_STATUS_INVALID_PARAMETER;
2818 : }
2819 :
2820 114 : if (new_password != NULL && ntNewHash != NULL) {
2821 0 : ldb_transaction_cancel(ldb);
2822 0 : DEBUG(1, ("samdb_set_password_sid: "
2823 : "two new passwords provided "
2824 : "sAMAccountName for SID[%s] DN[%s], "
2825 : "returning INVALID_PARAMETER\n",
2826 : dom_sid_string(frame, user_sid),
2827 : ldb_dn_get_linearized(user_msg->dn)));
2828 0 : TALLOC_FREE(frame);
2829 0 : return NT_STATUS_INVALID_PARAMETER;
2830 : }
2831 :
2832 114 : if (new_password != NULL && (new_password->length % 2)) {
2833 0 : ldb_transaction_cancel(ldb);
2834 0 : DEBUG(2, ("samdb_set_password_sid: "
2835 : "invalid utf16 length (%zu) "
2836 : "sAMAccountName for SID[%s] DN[%s], "
2837 : "returning WRONG_PASSWORD\n",
2838 : new_password->length,
2839 : dom_sid_string(frame, user_sid),
2840 : ldb_dn_get_linearized(user_msg->dn)));
2841 0 : TALLOC_FREE(frame);
2842 0 : return NT_STATUS_WRONG_PASSWORD;
2843 : }
2844 :
2845 114 : if (new_password != NULL && new_password->length >= 500) {
2846 0 : ldb_transaction_cancel(ldb);
2847 0 : DEBUG(2, ("samdb_set_password_sid: "
2848 : "utf16 password too long (%zu) "
2849 : "sAMAccountName for SID[%s] DN[%s], "
2850 : "returning WRONG_PASSWORD\n",
2851 : new_password->length,
2852 : dom_sid_string(frame, user_sid),
2853 : ldb_dn_get_linearized(user_msg->dn)));
2854 0 : TALLOC_FREE(frame);
2855 0 : return NT_STATUS_WRONG_PASSWORD;
2856 : }
2857 :
2858 114 : account_name = ldb_msg_find_attr_as_string(user_msg,
2859 : "sAMAccountName", NULL);
2860 114 : if (account_name == NULL) {
2861 0 : ldb_transaction_cancel(ldb);
2862 0 : DEBUG(1, ("samdb_set_password_sid: missing "
2863 : "sAMAccountName for SID[%s] DN[%s], "
2864 : "returning NO_SUCH_USER\n",
2865 : dom_sid_string(frame, user_sid),
2866 : ldb_dn_get_linearized(user_msg->dn)));
2867 0 : TALLOC_FREE(frame);
2868 0 : return NT_STATUS_NO_SUCH_USER;
2869 : }
2870 :
2871 114 : nt_status = dsdb_trust_search_tdo_by_type(ldb,
2872 : SEC_CHAN_DOMAIN,
2873 : account_name,
2874 : tdo_attrs,
2875 : frame, &tdo_msg);
2876 114 : if (!NT_STATUS_IS_OK(nt_status)) {
2877 0 : ldb_transaction_cancel(ldb);
2878 0 : DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
2879 : "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
2880 : "returning INTERNAL_DB_CORRUPTION\n",
2881 : nt_errstr(nt_status), account_name,
2882 : dom_sid_string(frame, user_sid),
2883 : ldb_dn_get_linearized(user_msg->dn)));
2884 0 : TALLOC_FREE(frame);
2885 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2886 : }
2887 :
2888 114 : trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
2889 : "trustDirection", 0);
2890 114 : if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
2891 0 : ldb_transaction_cancel(ldb);
2892 0 : DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
2893 : "not inbound for sAMAccountName[%s] "
2894 : "DN[%s] TDO[%s], "
2895 : "returning INTERNAL_DB_CORRUPTION\n",
2896 : (unsigned)trust_direction,
2897 : account_name,
2898 : ldb_dn_get_linearized(user_msg->dn),
2899 : ldb_dn_get_linearized(tdo_msg->dn)));
2900 0 : TALLOC_FREE(frame);
2901 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2902 : }
2903 :
2904 114 : old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
2905 114 : if (old_val != NULL) {
2906 114 : ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
2907 : (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2908 114 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2909 0 : ldb_transaction_cancel(ldb);
2910 0 : DEBUG(1, ("samdb_set_password_sid: "
2911 : "failed(%s) to parse "
2912 : "trustAuthOutgoing sAMAccountName[%s] "
2913 : "DN[%s] TDO[%s], "
2914 : "returning INTERNAL_DB_CORRUPTION\n",
2915 : ndr_map_error2string(ndr_err),
2916 : account_name,
2917 : ldb_dn_get_linearized(user_msg->dn),
2918 : ldb_dn_get_linearized(tdo_msg->dn)));
2919 :
2920 0 : TALLOC_FREE(frame);
2921 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2922 : }
2923 : }
2924 :
2925 300 : for (i = old_blob.current.count; i > 0; i--) {
2926 186 : struct AuthenticationInformation *a =
2927 186 : &old_blob.current.array[i - 1];
2928 :
2929 186 : switch (a->AuthType) {
2930 0 : case TRUST_AUTH_TYPE_NONE:
2931 0 : if (i == old_blob.current.count) {
2932 : /*
2933 : * remove TRUST_AUTH_TYPE_NONE at the
2934 : * end
2935 : */
2936 0 : old_blob.current.count--;
2937 : }
2938 0 : break;
2939 :
2940 72 : case TRUST_AUTH_TYPE_VERSION:
2941 72 : old_version_a = a;
2942 72 : old_version = a->AuthInfo.version.version;
2943 72 : break;
2944 :
2945 114 : case TRUST_AUTH_TYPE_CLEAR:
2946 114 : break;
2947 :
2948 0 : case TRUST_AUTH_TYPE_NT4OWF:
2949 0 : break;
2950 : }
2951 : }
2952 :
2953 114 : if (new_version == NULL) {
2954 0 : _new_version = 0;
2955 0 : new_version = &_new_version;
2956 : }
2957 :
2958 114 : if (old_version_a != NULL && *new_version != (old_version + 1)) {
2959 36 : old_version_a->LastUpdateTime = now;
2960 36 : old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
2961 : }
2962 :
2963 114 : new_blob.count = MAX(old_blob.current.count, 2);
2964 114 : new_blob.current.array = talloc_zero_array(frame,
2965 : struct AuthenticationInformation,
2966 : new_blob.count);
2967 114 : if (new_blob.current.array == NULL) {
2968 0 : ldb_transaction_cancel(ldb);
2969 0 : TALLOC_FREE(frame);
2970 0 : return NT_STATUS_NO_MEMORY;
2971 : }
2972 114 : new_blob.previous.array = talloc_zero_array(frame,
2973 : struct AuthenticationInformation,
2974 : new_blob.count);
2975 114 : if (new_blob.current.array == NULL) {
2976 0 : ldb_transaction_cancel(ldb);
2977 0 : TALLOC_FREE(frame);
2978 0 : return NT_STATUS_NO_MEMORY;
2979 : }
2980 :
2981 300 : for (i = 0; i < old_blob.current.count; i++) {
2982 186 : struct AuthenticationInformation *o =
2983 186 : &old_blob.current.array[i];
2984 186 : struct AuthenticationInformation *p =
2985 186 : &new_blob.previous.array[i];
2986 :
2987 186 : *p = *o;
2988 186 : new_blob.previous.count++;
2989 : }
2990 156 : for (; i < new_blob.count; i++) {
2991 42 : struct AuthenticationInformation *pi =
2992 42 : &new_blob.previous.array[i];
2993 :
2994 42 : if (i == 0) {
2995 : /*
2996 : * new_blob.previous is still empty so
2997 : * we'll do new_blob.previous = new_blob.current
2998 : * below.
2999 : */
3000 0 : break;
3001 : }
3002 :
3003 42 : pi->LastUpdateTime = now;
3004 42 : pi->AuthType = TRUST_AUTH_TYPE_NONE;
3005 42 : new_blob.previous.count++;
3006 : }
3007 :
3008 342 : for (i = 0; i < new_blob.count; i++) {
3009 228 : struct AuthenticationInformation *ci =
3010 228 : &new_blob.current.array[i];
3011 :
3012 228 : ci->LastUpdateTime = now;
3013 228 : switch (i) {
3014 114 : case 0:
3015 114 : if (ntNewHash != NULL) {
3016 0 : ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
3017 0 : ci->AuthInfo.nt4owf.password = *ntNewHash;
3018 0 : break;
3019 : }
3020 :
3021 114 : ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
3022 114 : ci->AuthInfo.clear.size = new_password->length;
3023 114 : ci->AuthInfo.clear.password = new_password->data;
3024 114 : break;
3025 114 : case 1:
3026 114 : ci->AuthType = TRUST_AUTH_TYPE_VERSION;
3027 114 : ci->AuthInfo.version.version = *new_version;
3028 114 : break;
3029 0 : default:
3030 0 : ci->AuthType = TRUST_AUTH_TYPE_NONE;
3031 0 : break;
3032 : }
3033 :
3034 228 : new_blob.current.count++;
3035 : }
3036 :
3037 114 : if (new_blob.previous.count == 0) {
3038 0 : TALLOC_FREE(new_blob.previous.array);
3039 0 : new_blob.previous = new_blob.current;
3040 : }
3041 :
3042 114 : ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
3043 : (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
3044 114 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3045 0 : ldb_transaction_cancel(ldb);
3046 0 : DEBUG(1, ("samdb_set_password_sid: "
3047 : "failed(%s) to generate "
3048 : "trustAuthOutgoing sAMAccountName[%s] "
3049 : "DN[%s] TDO[%s], "
3050 : "returning UNSUCCESSFUL\n",
3051 : ndr_map_error2string(ndr_err),
3052 : account_name,
3053 : ldb_dn_get_linearized(user_msg->dn),
3054 : ldb_dn_get_linearized(tdo_msg->dn)));
3055 0 : TALLOC_FREE(frame);
3056 0 : return NT_STATUS_UNSUCCESSFUL;
3057 : }
3058 :
3059 114 : tdo_msg->num_elements = 0;
3060 114 : TALLOC_FREE(tdo_msg->elements);
3061 :
3062 114 : ret = ldb_msg_append_value(tdo_msg, "trustAuthIncoming",
3063 : &new_val, LDB_FLAG_MOD_REPLACE);
3064 114 : if (ret != LDB_SUCCESS) {
3065 0 : ldb_transaction_cancel(ldb);
3066 0 : TALLOC_FREE(frame);
3067 0 : return NT_STATUS_NO_MEMORY;
3068 : }
3069 :
3070 114 : ret = ldb_modify(ldb, tdo_msg);
3071 114 : if (ret != LDB_SUCCESS) {
3072 0 : nt_status = dsdb_ldb_err_to_ntstatus(ret);
3073 0 : ldb_transaction_cancel(ldb);
3074 0 : DEBUG(1, ("samdb_set_password_sid: "
3075 : "failed to replace "
3076 : "trustAuthOutgoing sAMAccountName[%s] "
3077 : "DN[%s] TDO[%s], "
3078 : "%s - %s\n",
3079 : account_name,
3080 : ldb_dn_get_linearized(user_msg->dn),
3081 : ldb_dn_get_linearized(tdo_msg->dn),
3082 : nt_errstr(nt_status), ldb_errstring(ldb)));
3083 0 : TALLOC_FREE(frame);
3084 0 : return nt_status;
3085 : }
3086 : }
3087 :
3088 445 : nt_status = samdb_set_password_internal(ldb, mem_ctx,
3089 414 : user_msg->dn,
3090 : new_password,
3091 : ntNewHash,
3092 : old_password_checked,
3093 : reject_reason, _dominfo,
3094 : true); /* permit trusts */
3095 414 : if (!NT_STATUS_IS_OK(nt_status)) {
3096 10 : ldb_transaction_cancel(ldb);
3097 10 : TALLOC_FREE(frame);
3098 10 : return nt_status;
3099 : }
3100 :
3101 404 : ret = ldb_transaction_commit(ldb);
3102 404 : if (ret != LDB_SUCCESS) {
3103 0 : DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
3104 : ldb_dn_get_linearized(user_msg->dn),
3105 : ldb_errstring(ldb)));
3106 0 : TALLOC_FREE(frame);
3107 0 : return NT_STATUS_TRANSACTION_ABORTED;
3108 : }
3109 :
3110 404 : TALLOC_FREE(frame);
3111 404 : return NT_STATUS_OK;
3112 : }
3113 :
3114 :
3115 0 : NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
3116 : struct dom_sid *sid, struct ldb_dn **ret_dn)
3117 : {
3118 0 : struct ldb_message *msg;
3119 0 : struct ldb_dn *basedn = NULL;
3120 0 : char *sidstr;
3121 0 : int ret;
3122 :
3123 0 : sidstr = dom_sid_string(mem_ctx, sid);
3124 0 : NT_STATUS_HAVE_NO_MEMORY(sidstr);
3125 :
3126 : /* We might have to create a ForeignSecurityPrincipal, even if this user
3127 : * is in our own domain */
3128 :
3129 0 : msg = ldb_msg_new(sidstr);
3130 0 : if (msg == NULL) {
3131 0 : talloc_free(sidstr);
3132 0 : return NT_STATUS_NO_MEMORY;
3133 : }
3134 :
3135 0 : ret = dsdb_wellknown_dn(sam_ctx, sidstr,
3136 : ldb_get_default_basedn(sam_ctx),
3137 : DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
3138 : &basedn);
3139 0 : if (ret != LDB_SUCCESS) {
3140 0 : DEBUG(0, ("Failed to find DN for "
3141 : "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
3142 0 : talloc_free(sidstr);
3143 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
3144 : }
3145 :
3146 : /* add core elements to the ldb_message for the alias */
3147 0 : msg->dn = basedn;
3148 0 : if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
3149 0 : talloc_free(sidstr);
3150 0 : return NT_STATUS_NO_MEMORY;
3151 : }
3152 :
3153 0 : ret = ldb_msg_add_string(msg, "objectClass",
3154 : "foreignSecurityPrincipal");
3155 0 : if (ret != LDB_SUCCESS) {
3156 0 : talloc_free(sidstr);
3157 0 : return NT_STATUS_NO_MEMORY;
3158 : }
3159 :
3160 : /* create the alias */
3161 0 : ret = ldb_add(sam_ctx, msg);
3162 0 : if (ret != LDB_SUCCESS) {
3163 0 : DEBUG(0,("Failed to create foreignSecurityPrincipal "
3164 : "record %s: %s\n",
3165 : ldb_dn_get_linearized(msg->dn),
3166 : ldb_errstring(sam_ctx)));
3167 0 : talloc_free(sidstr);
3168 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
3169 : }
3170 :
3171 0 : *ret_dn = talloc_steal(mem_ctx, msg->dn);
3172 0 : talloc_free(sidstr);
3173 :
3174 0 : return NT_STATUS_OK;
3175 : }
3176 :
3177 :
3178 : /*
3179 : Find the DN of a domain, assuming it to be a dotted.dns name
3180 : */
3181 :
3182 0 : struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
3183 : {
3184 0 : unsigned int i;
3185 0 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3186 0 : const char *binary_encoded;
3187 0 : const char * const *split_realm;
3188 0 : struct ldb_dn *dn;
3189 :
3190 0 : if (!tmp_ctx) {
3191 0 : return NULL;
3192 : }
3193 :
3194 0 : split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
3195 0 : if (!split_realm) {
3196 0 : talloc_free(tmp_ctx);
3197 0 : return NULL;
3198 : }
3199 0 : dn = ldb_dn_new(mem_ctx, ldb, NULL);
3200 0 : for (i=0; split_realm[i]; i++) {
3201 0 : binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
3202 0 : if (binary_encoded == NULL) {
3203 0 : DEBUG(2, ("Failed to add dc= element to DN %s\n",
3204 : ldb_dn_get_linearized(dn)));
3205 0 : talloc_free(tmp_ctx);
3206 0 : return NULL;
3207 : }
3208 0 : if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
3209 0 : DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
3210 : binary_encoded, ldb_dn_get_linearized(dn)));
3211 0 : talloc_free(tmp_ctx);
3212 0 : return NULL;
3213 : }
3214 : }
3215 0 : if (!ldb_dn_validate(dn)) {
3216 0 : DEBUG(2, ("Failed to validated DN %s\n",
3217 : ldb_dn_get_linearized(dn)));
3218 0 : talloc_free(tmp_ctx);
3219 0 : return NULL;
3220 : }
3221 0 : talloc_free(tmp_ctx);
3222 0 : return dn;
3223 : }
3224 :
3225 :
3226 : /*
3227 : Find the DNS equivalent of a DN, in dotted DNS form
3228 : */
3229 51322 : char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
3230 : {
3231 51322 : int i, num_components = ldb_dn_get_comp_num(dn);
3232 51322 : char *dns_name = talloc_strdup(mem_ctx, "");
3233 51322 : if (dns_name == NULL) {
3234 0 : return NULL;
3235 : }
3236 :
3237 231024 : for (i=0; i<num_components; i++) {
3238 179702 : const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
3239 3443 : char *s;
3240 179702 : if (v == NULL) {
3241 0 : talloc_free(dns_name);
3242 0 : return NULL;
3243 : }
3244 183145 : s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
3245 179702 : (int)v->length, (int)v->length, (char *)v->data);
3246 179702 : if (s == NULL) {
3247 0 : talloc_free(dns_name);
3248 0 : return NULL;
3249 : }
3250 179702 : dns_name = s;
3251 : }
3252 :
3253 : /* remove the last '.' */
3254 51322 : if (dns_name[0] != 0) {
3255 51322 : dns_name[strlen(dns_name)-1] = 0;
3256 : }
3257 :
3258 50238 : return dns_name;
3259 : }
3260 :
3261 : /*
3262 : Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
3263 : name is based on the forest DNS name
3264 : */
3265 4635 : char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
3266 : TALLOC_CTX *mem_ctx,
3267 : const struct GUID *ntds_guid)
3268 : {
3269 4635 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3270 0 : const char *guid_str;
3271 0 : struct ldb_dn *forest_dn;
3272 0 : const char *dnsforest;
3273 0 : char *ret;
3274 :
3275 4635 : guid_str = GUID_string(tmp_ctx, ntds_guid);
3276 4635 : if (guid_str == NULL) {
3277 0 : talloc_free(tmp_ctx);
3278 0 : return NULL;
3279 : }
3280 4635 : forest_dn = ldb_get_root_basedn(samdb);
3281 4635 : if (forest_dn == NULL) {
3282 0 : talloc_free(tmp_ctx);
3283 0 : return NULL;
3284 : }
3285 4635 : dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
3286 4635 : if (dnsforest == NULL) {
3287 0 : talloc_free(tmp_ctx);
3288 0 : return NULL;
3289 : }
3290 4635 : ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
3291 4635 : talloc_free(tmp_ctx);
3292 4635 : return ret;
3293 : }
3294 :
3295 :
3296 : /*
3297 : Find the DN of a domain, be it the netbios or DNS name
3298 : */
3299 22 : struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
3300 : const char *domain_name)
3301 : {
3302 22 : const char * const domain_ref_attrs[] = {
3303 : "ncName", NULL
3304 : };
3305 22 : const char * const domain_ref2_attrs[] = {
3306 : NULL
3307 : };
3308 3 : struct ldb_result *res_domain_ref;
3309 22 : char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
3310 3 : int ret_domain;
3311 :
3312 22 : if (escaped_domain == NULL) {
3313 0 : return NULL;
3314 : }
3315 :
3316 : /* find the domain's DN */
3317 22 : ret_domain = ldb_search(ldb, mem_ctx,
3318 : &res_domain_ref,
3319 : samdb_partitions_dn(ldb, mem_ctx),
3320 : LDB_SCOPE_ONELEVEL,
3321 : domain_ref_attrs,
3322 : "(&(nETBIOSName=%s)(objectclass=crossRef))",
3323 : escaped_domain);
3324 22 : if (ret_domain != LDB_SUCCESS) {
3325 0 : return NULL;
3326 : }
3327 :
3328 22 : if (res_domain_ref->count == 0) {
3329 0 : ret_domain = ldb_search(ldb, mem_ctx,
3330 : &res_domain_ref,
3331 : samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
3332 : LDB_SCOPE_BASE,
3333 : domain_ref2_attrs,
3334 : "(objectclass=domain)");
3335 0 : if (ret_domain != LDB_SUCCESS) {
3336 0 : return NULL;
3337 : }
3338 :
3339 0 : if (res_domain_ref->count == 1) {
3340 0 : return res_domain_ref->msgs[0]->dn;
3341 : }
3342 0 : return NULL;
3343 : }
3344 :
3345 22 : if (res_domain_ref->count > 1) {
3346 0 : DEBUG(0,("Found %d records matching domain [%s]\n",
3347 : ret_domain, domain_name));
3348 0 : return NULL;
3349 : }
3350 :
3351 22 : return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
3352 :
3353 : }
3354 :
3355 :
3356 : /*
3357 : use a GUID to find a DN
3358 : */
3359 668 : int dsdb_find_dn_by_guid(struct ldb_context *ldb,
3360 : TALLOC_CTX *mem_ctx,
3361 : const struct GUID *guid,
3362 : uint32_t dsdb_flags,
3363 : struct ldb_dn **dn)
3364 : {
3365 0 : int ret;
3366 0 : struct ldb_result *res;
3367 668 : const char *attrs[] = { NULL };
3368 0 : struct GUID_txt_buf buf;
3369 668 : char *guid_str = GUID_buf_string(guid, &buf);
3370 :
3371 668 : ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3372 : DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3373 : DSDB_SEARCH_SHOW_EXTENDED_DN |
3374 : DSDB_SEARCH_ONE_ONLY | dsdb_flags,
3375 : "objectGUID=%s", guid_str);
3376 668 : if (ret != LDB_SUCCESS) {
3377 67 : return ret;
3378 : }
3379 :
3380 601 : *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3381 601 : talloc_free(res);
3382 :
3383 601 : return LDB_SUCCESS;
3384 : }
3385 :
3386 : /*
3387 : use a DN to find a GUID with a given attribute name
3388 : */
3389 3841 : int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
3390 : struct ldb_dn *dn, const char *attribute,
3391 : struct GUID *guid)
3392 : {
3393 0 : int ret;
3394 3841 : struct ldb_result *res = NULL;
3395 0 : const char *attrs[2];
3396 3841 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3397 :
3398 3841 : attrs[0] = attribute;
3399 3841 : attrs[1] = NULL;
3400 :
3401 3841 : ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3402 : DSDB_SEARCH_SHOW_DELETED |
3403 : DSDB_SEARCH_SHOW_RECYCLED);
3404 3841 : if (ret != LDB_SUCCESS) {
3405 0 : talloc_free(tmp_ctx);
3406 0 : return ret;
3407 : }
3408 : /* satisfy clang */
3409 3841 : if (res == NULL) {
3410 0 : talloc_free(tmp_ctx);
3411 0 : return LDB_ERR_OTHER;
3412 : }
3413 3841 : if (res->count < 1) {
3414 0 : talloc_free(tmp_ctx);
3415 0 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3416 : }
3417 3841 : *guid = samdb_result_guid(res->msgs[0], attribute);
3418 3841 : talloc_free(tmp_ctx);
3419 3841 : return LDB_SUCCESS;
3420 : }
3421 :
3422 : /*
3423 : use a DN to find a GUID
3424 : */
3425 3841 : int dsdb_find_guid_by_dn(struct ldb_context *ldb,
3426 : struct ldb_dn *dn, struct GUID *guid)
3427 : {
3428 3841 : return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
3429 : }
3430 :
3431 :
3432 :
3433 : /*
3434 : adds the given GUID to the given ldb_message. This value is added
3435 : for the given attr_name (may be either "objectGUID" or "parentGUID").
3436 : This function is used in processing 'add' requests.
3437 : */
3438 926040 : int dsdb_msg_add_guid(struct ldb_message *msg,
3439 : struct GUID *guid,
3440 : const char *attr_name)
3441 : {
3442 83703 : int ret;
3443 83703 : struct ldb_val v;
3444 83703 : NTSTATUS status;
3445 926040 : TALLOC_CTX *tmp_ctx = talloc_init("dsdb_msg_add_guid");
3446 :
3447 926040 : status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
3448 926040 : if (!NT_STATUS_IS_OK(status)) {
3449 0 : ret = LDB_ERR_OPERATIONS_ERROR;
3450 0 : goto done;
3451 : }
3452 :
3453 926040 : ret = ldb_msg_add_steal_value(msg, attr_name, &v);
3454 926040 : if (ret != LDB_SUCCESS) {
3455 0 : DEBUG(4,(__location__ ": Failed to add %s to the message\n",
3456 : attr_name));
3457 0 : goto done;
3458 : }
3459 :
3460 842337 : ret = LDB_SUCCESS;
3461 :
3462 926040 : done:
3463 926040 : talloc_free(tmp_ctx);
3464 926040 : return ret;
3465 :
3466 : }
3467 :
3468 :
3469 : /*
3470 : use a DN to find a SID
3471 : */
3472 8182 : int dsdb_find_sid_by_dn(struct ldb_context *ldb,
3473 : struct ldb_dn *dn, struct dom_sid *sid)
3474 : {
3475 0 : int ret;
3476 8182 : struct ldb_result *res = NULL;
3477 8182 : const char *attrs[] = { "objectSid", NULL };
3478 8182 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3479 0 : struct dom_sid *s;
3480 :
3481 8182 : ZERO_STRUCTP(sid);
3482 :
3483 8182 : ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
3484 : DSDB_SEARCH_SHOW_DELETED |
3485 : DSDB_SEARCH_SHOW_RECYCLED);
3486 8182 : if (ret != LDB_SUCCESS) {
3487 0 : talloc_free(tmp_ctx);
3488 0 : return ret;
3489 : }
3490 8182 : if (res == NULL) {
3491 0 : talloc_free(tmp_ctx);
3492 0 : return LDB_ERR_OTHER;
3493 : }
3494 8182 : if (res->count < 1) {
3495 0 : talloc_free(tmp_ctx);
3496 0 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3497 : }
3498 8182 : s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
3499 8182 : if (s == NULL) {
3500 1927 : talloc_free(tmp_ctx);
3501 1927 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
3502 : }
3503 6255 : *sid = *s;
3504 6255 : talloc_free(tmp_ctx);
3505 6255 : return LDB_SUCCESS;
3506 : }
3507 :
3508 : /*
3509 : use a SID to find a DN
3510 : */
3511 60 : int dsdb_find_dn_by_sid(struct ldb_context *ldb,
3512 : TALLOC_CTX *mem_ctx,
3513 : struct dom_sid *sid, struct ldb_dn **dn)
3514 : {
3515 0 : int ret;
3516 0 : struct ldb_result *res;
3517 60 : const char *attrs[] = { NULL };
3518 60 : char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
3519 :
3520 60 : if (!sid_str) {
3521 0 : return ldb_operr(ldb);
3522 : }
3523 :
3524 60 : ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3525 : DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3526 : DSDB_SEARCH_SHOW_EXTENDED_DN |
3527 : DSDB_SEARCH_ONE_ONLY,
3528 : "objectSid=%s", sid_str);
3529 60 : talloc_free(sid_str);
3530 60 : if (ret != LDB_SUCCESS) {
3531 0 : return ret;
3532 : }
3533 :
3534 60 : *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
3535 60 : talloc_free(res);
3536 :
3537 60 : return LDB_SUCCESS;
3538 : }
3539 :
3540 : /*
3541 : load a repsFromTo blob list for a given partition GUID
3542 : attr must be "repsFrom" or "repsTo"
3543 : */
3544 73649 : WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3545 : const char *attr, struct repsFromToBlob **r, uint32_t *count)
3546 : {
3547 73649 : const char *attrs[] = { attr, NULL };
3548 73649 : struct ldb_result *res = NULL;
3549 73649 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3550 490 : unsigned int i;
3551 490 : struct ldb_message_element *el;
3552 490 : int ret;
3553 :
3554 73649 : *r = NULL;
3555 73649 : *count = 0;
3556 :
3557 73649 : if (tmp_ctx == NULL) {
3558 0 : return WERR_NOT_ENOUGH_MEMORY;
3559 : }
3560 :
3561 73649 : ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
3562 73649 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3563 : /* partition hasn't been replicated yet */
3564 0 : talloc_free(tmp_ctx);
3565 0 : return WERR_OK;
3566 : }
3567 73649 : if (ret != LDB_SUCCESS) {
3568 0 : DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
3569 0 : talloc_free(tmp_ctx);
3570 0 : return WERR_DS_DRA_INTERNAL_ERROR;
3571 : }
3572 :
3573 : /* satisfy clang */
3574 73649 : if (res == NULL) {
3575 0 : talloc_free(tmp_ctx);
3576 0 : return WERR_DS_DRA_INTERNAL_ERROR;
3577 : }
3578 73649 : el = ldb_msg_find_element(res->msgs[0], attr);
3579 73649 : if (el == NULL) {
3580 : /* it's OK to be empty */
3581 48259 : talloc_free(tmp_ctx);
3582 48259 : return WERR_OK;
3583 : }
3584 :
3585 25390 : *count = el->num_values;
3586 25390 : *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
3587 25390 : if (*r == NULL) {
3588 0 : talloc_free(tmp_ctx);
3589 0 : return WERR_DS_DRA_INTERNAL_ERROR;
3590 : }
3591 :
3592 68644 : for (i=0; i<(*count); i++) {
3593 0 : enum ndr_err_code ndr_err;
3594 43254 : ndr_err = ndr_pull_struct_blob(&el->values[i],
3595 : mem_ctx,
3596 43254 : &(*r)[i],
3597 : (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3598 43254 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3599 0 : talloc_free(tmp_ctx);
3600 0 : return WERR_DS_DRA_INTERNAL_ERROR;
3601 : }
3602 : }
3603 :
3604 25390 : talloc_free(tmp_ctx);
3605 :
3606 25390 : return WERR_OK;
3607 : }
3608 :
3609 : /*
3610 : save the repsFromTo blob list for a given partition GUID
3611 : attr must be "repsFrom" or "repsTo"
3612 : */
3613 11965 : WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
3614 : const char *attr, struct repsFromToBlob *r, uint32_t count)
3615 : {
3616 11965 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
3617 0 : struct ldb_message *msg;
3618 0 : struct ldb_message_element *el;
3619 0 : unsigned int i;
3620 :
3621 11965 : if (tmp_ctx == NULL) {
3622 0 : goto failed;
3623 : }
3624 :
3625 11965 : msg = ldb_msg_new(tmp_ctx);
3626 11965 : if (msg == NULL) {
3627 0 : goto failed;
3628 : }
3629 11965 : msg->dn = dn;
3630 11965 : if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
3631 0 : goto failed;
3632 : }
3633 :
3634 11965 : el->values = talloc_array(msg, struct ldb_val, count);
3635 11965 : if (!el->values) {
3636 0 : goto failed;
3637 : }
3638 :
3639 34747 : for (i=0; i<count; i++) {
3640 0 : struct ldb_val v;
3641 0 : enum ndr_err_code ndr_err;
3642 :
3643 22782 : ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
3644 22782 : &r[i],
3645 : (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3646 22782 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3647 0 : goto failed;
3648 : }
3649 :
3650 22782 : el->num_values++;
3651 22782 : el->values[i] = v;
3652 : }
3653 :
3654 11965 : if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
3655 0 : DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
3656 0 : goto failed;
3657 : }
3658 :
3659 11965 : talloc_free(tmp_ctx);
3660 :
3661 11965 : return WERR_OK;
3662 :
3663 0 : failed:
3664 0 : talloc_free(tmp_ctx);
3665 0 : return WERR_DS_DRA_INTERNAL_ERROR;
3666 : }
3667 :
3668 :
3669 : /*
3670 : load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
3671 : object for a partition
3672 : */
3673 63355 : int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
3674 : uint64_t *uSN, uint64_t *urgent_uSN)
3675 : {
3676 490 : struct ldb_request *req;
3677 490 : int ret;
3678 63355 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
3679 490 : struct dsdb_control_current_partition *p_ctrl;
3680 490 : struct ldb_result *res;
3681 :
3682 63355 : if (tmp_ctx == NULL) {
3683 0 : return ldb_oom(ldb);
3684 : }
3685 :
3686 63355 : res = talloc_zero(tmp_ctx, struct ldb_result);
3687 63355 : if (!res) {
3688 0 : talloc_free(tmp_ctx);
3689 0 : return ldb_oom(ldb);
3690 : }
3691 :
3692 63355 : ret = ldb_build_search_req(&req, ldb, tmp_ctx,
3693 : ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
3694 : LDB_SCOPE_BASE,
3695 : NULL, NULL,
3696 : NULL,
3697 : res, ldb_search_default_callback,
3698 : NULL);
3699 63355 : if (ret != LDB_SUCCESS) {
3700 0 : talloc_free(tmp_ctx);
3701 0 : return ret;
3702 : }
3703 :
3704 63355 : p_ctrl = talloc(req, struct dsdb_control_current_partition);
3705 63355 : if (p_ctrl == NULL) {
3706 0 : talloc_free(tmp_ctx);
3707 0 : return ldb_oom(ldb);
3708 : }
3709 63355 : p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
3710 63355 : p_ctrl->dn = dn;
3711 :
3712 63355 : ret = ldb_request_add_control(req,
3713 : DSDB_CONTROL_CURRENT_PARTITION_OID,
3714 : false, p_ctrl);
3715 63355 : if (ret != LDB_SUCCESS) {
3716 0 : talloc_free(tmp_ctx);
3717 0 : return ret;
3718 : }
3719 :
3720 : /* Run the new request */
3721 63355 : ret = ldb_request(ldb, req);
3722 :
3723 63355 : if (ret == LDB_SUCCESS) {
3724 63355 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
3725 : }
3726 :
3727 63355 : if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
3728 : /* it hasn't been created yet, which means
3729 : an implicit value of zero */
3730 2558 : *uSN = 0;
3731 2558 : talloc_free(tmp_ctx);
3732 2558 : return LDB_SUCCESS;
3733 : }
3734 :
3735 60797 : if (ret != LDB_SUCCESS) {
3736 0 : talloc_free(tmp_ctx);
3737 0 : return ret;
3738 : }
3739 :
3740 60797 : if (res->count < 1) {
3741 0 : *uSN = 0;
3742 0 : if (urgent_uSN) {
3743 0 : *urgent_uSN = 0;
3744 : }
3745 : } else {
3746 60797 : *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
3747 60797 : if (urgent_uSN) {
3748 55567 : *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
3749 : }
3750 : }
3751 :
3752 60797 : talloc_free(tmp_ctx);
3753 :
3754 60797 : return LDB_SUCCESS;
3755 : }
3756 :
3757 15494 : int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
3758 : const struct drsuapi_DsReplicaCursor2 *c2)
3759 : {
3760 15494 : return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3761 : }
3762 :
3763 2823 : int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
3764 : const struct drsuapi_DsReplicaCursor *c2)
3765 : {
3766 2823 : return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
3767 : }
3768 :
3769 : /*
3770 : * Return the NTDS object for a GUID, confirming it is in the
3771 : * configuration partition and a nTDSDSA object
3772 : */
3773 44973 : int samdb_get_ntds_obj_by_guid(TALLOC_CTX *mem_ctx,
3774 : struct ldb_context *sam_ctx,
3775 : const struct GUID *objectGUID,
3776 : const char **attrs,
3777 : struct ldb_message **msg)
3778 : {
3779 1143 : int ret;
3780 1143 : struct ldb_result *res;
3781 1143 : struct GUID_txt_buf guid_buf;
3782 44973 : char *guid_str = GUID_buf_string(objectGUID, &guid_buf);
3783 44973 : struct ldb_dn *config_dn = NULL;
3784 :
3785 44973 : config_dn = ldb_get_config_basedn(sam_ctx);
3786 44973 : if (config_dn == NULL) {
3787 0 : return ldb_operr(sam_ctx);
3788 : }
3789 :
3790 44973 : ret = dsdb_search(sam_ctx,
3791 : mem_ctx,
3792 : &res,
3793 : config_dn,
3794 : LDB_SCOPE_SUBTREE,
3795 : attrs,
3796 : DSDB_SEARCH_ONE_ONLY,
3797 : "(&(objectGUID=%s)(objectClass=nTDSDSA))",
3798 : guid_str);
3799 44973 : if (ret != LDB_SUCCESS) {
3800 24 : return ret;
3801 : }
3802 44949 : if (msg) {
3803 44883 : *msg = talloc_steal(mem_ctx, res->msgs[0]);
3804 : }
3805 44949 : TALLOC_FREE(res);
3806 43806 : return ret;
3807 : }
3808 :
3809 :
3810 : /*
3811 : see if a computer identified by its objectGUID is a RODC
3812 : */
3813 40503 : int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
3814 : {
3815 : /* 1) find the DN for this servers NTDSDSA object
3816 : 2) search for the msDS-isRODC attribute
3817 : 3) if not present then not a RODC
3818 : 4) if present and TRUE then is a RODC
3819 : */
3820 40503 : const char *attrs[] = { "msDS-isRODC", NULL };
3821 1143 : int ret;
3822 1143 : struct ldb_message *msg;
3823 40503 : TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
3824 :
3825 40503 : if (tmp_ctx == NULL) {
3826 0 : return ldb_oom(sam_ctx);
3827 : }
3828 :
3829 40503 : ret = samdb_get_ntds_obj_by_guid(tmp_ctx,
3830 : sam_ctx,
3831 : objectGUID,
3832 : attrs, &msg);
3833 :
3834 40503 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3835 2 : *is_rodc = false;
3836 2 : talloc_free(tmp_ctx);
3837 2 : return LDB_SUCCESS;
3838 : }
3839 :
3840 40501 : if (ret != LDB_SUCCESS) {
3841 0 : DEBUG(1,("Failed to find our own NTDS Settings object by objectGUID=%s!\n",
3842 : GUID_string(tmp_ctx, objectGUID)));
3843 0 : *is_rodc = false;
3844 0 : talloc_free(tmp_ctx);
3845 0 : return ret;
3846 : }
3847 :
3848 40501 : ret = ldb_msg_find_attr_as_bool(msg, "msDS-isRODC", 0);
3849 40501 : *is_rodc = (ret == 1);
3850 :
3851 40501 : talloc_free(tmp_ctx);
3852 40501 : return LDB_SUCCESS;
3853 : }
3854 :
3855 :
3856 : /*
3857 : see if we are a RODC
3858 : */
3859 1831457 : int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
3860 : {
3861 166886 : const struct GUID *objectGUID;
3862 166886 : int ret;
3863 166886 : bool *cached;
3864 :
3865 : /* see if we have a cached copy */
3866 1831457 : cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
3867 1831457 : if (cached) {
3868 1790937 : *am_rodc = *cached;
3869 1790937 : return LDB_SUCCESS;
3870 : }
3871 :
3872 40520 : objectGUID = samdb_ntds_objectGUID(sam_ctx);
3873 40520 : if (!objectGUID) {
3874 19 : return ldb_operr(sam_ctx);
3875 : }
3876 :
3877 40501 : ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
3878 40501 : if (ret != LDB_SUCCESS) {
3879 0 : return ret;
3880 : }
3881 :
3882 40501 : cached = talloc(sam_ctx, bool);
3883 40501 : if (cached == NULL) {
3884 0 : return ldb_oom(sam_ctx);
3885 : }
3886 40501 : *cached = *am_rodc;
3887 :
3888 40501 : ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
3889 40501 : if (ret != LDB_SUCCESS) {
3890 0 : talloc_free(cached);
3891 0 : return ldb_operr(sam_ctx);
3892 : }
3893 :
3894 39358 : return LDB_SUCCESS;
3895 : }
3896 :
3897 3022 : int samdb_dns_host_name(struct ldb_context *sam_ctx, const char **host_name)
3898 : {
3899 3022 : const char *_host_name = NULL;
3900 3022 : const char *attrs[] = { "dnsHostName", NULL };
3901 3022 : TALLOC_CTX *tmp_ctx = NULL;
3902 1 : int ret;
3903 3022 : struct ldb_result *res = NULL;
3904 :
3905 3022 : _host_name = (const char *)ldb_get_opaque(sam_ctx, "cache.dns_host_name");
3906 3022 : if (_host_name != NULL) {
3907 2895 : *host_name = _host_name;
3908 2895 : return LDB_SUCCESS;
3909 : }
3910 :
3911 127 : tmp_ctx = talloc_new(sam_ctx);
3912 127 : if (tmp_ctx == NULL) {
3913 0 : return ldb_oom(sam_ctx);
3914 : }
3915 :
3916 127 : ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, NULL, attrs, 0);
3917 :
3918 127 : if (res == NULL || res->count != 1 || ret != LDB_SUCCESS) {
3919 0 : DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s\n",
3920 : ldb_errstring(sam_ctx)));
3921 0 : TALLOC_FREE(tmp_ctx);
3922 0 : return ret;
3923 : }
3924 :
3925 127 : _host_name = ldb_msg_find_attr_as_string(res->msgs[0],
3926 : "dnsHostName",
3927 : NULL);
3928 127 : if (_host_name == NULL) {
3929 0 : DEBUG(0, ("Failed to get dnsHostName from rootDSE\n"));
3930 0 : TALLOC_FREE(tmp_ctx);
3931 0 : return LDB_ERR_OPERATIONS_ERROR;
3932 : }
3933 127 : ret = ldb_set_opaque(sam_ctx, "cache.dns_host_name",
3934 : discard_const_p(char *, _host_name));
3935 127 : if (ret != LDB_SUCCESS) {
3936 0 : TALLOC_FREE(tmp_ctx);
3937 0 : return ldb_operr(sam_ctx);
3938 : }
3939 :
3940 127 : *host_name = talloc_steal(sam_ctx, _host_name);
3941 :
3942 127 : TALLOC_FREE(tmp_ctx);
3943 127 : return LDB_SUCCESS;
3944 : }
3945 :
3946 692 : bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
3947 : {
3948 47 : TALLOC_CTX *tmp_ctx;
3949 47 : bool *cached;
3950 :
3951 692 : tmp_ctx = talloc_new(ldb);
3952 692 : if (tmp_ctx == NULL) {
3953 0 : goto failed;
3954 : }
3955 :
3956 692 : cached = talloc(tmp_ctx, bool);
3957 692 : if (!cached) {
3958 0 : goto failed;
3959 : }
3960 :
3961 692 : *cached = am_rodc;
3962 692 : if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
3963 0 : goto failed;
3964 : }
3965 :
3966 692 : talloc_steal(ldb, cached);
3967 692 : talloc_free(tmp_ctx);
3968 692 : return true;
3969 :
3970 0 : failed:
3971 0 : DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
3972 0 : talloc_free(tmp_ctx);
3973 0 : return false;
3974 : }
3975 :
3976 :
3977 : /*
3978 : * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
3979 : * flags are DS_NTDSSETTINGS_OPT_*
3980 : */
3981 0 : int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
3982 : uint32_t *options)
3983 : {
3984 0 : int rc;
3985 0 : TALLOC_CTX *tmp_ctx;
3986 0 : struct ldb_result *res;
3987 0 : struct ldb_dn *site_dn;
3988 0 : const char *attrs[] = { "options", NULL };
3989 :
3990 0 : tmp_ctx = talloc_new(ldb_ctx);
3991 0 : if (tmp_ctx == NULL)
3992 0 : goto failed;
3993 :
3994 : /* Retrieve the site dn for the ldb that we
3995 : * have open. This is our local site.
3996 : */
3997 0 : site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
3998 0 : if (site_dn == NULL)
3999 0 : goto failed;
4000 :
4001 : /* Perform a one level (child) search from the local
4002 : * site distinguished name. We're looking for the
4003 : * "options" attribute within the nTDSSiteSettings
4004 : * object
4005 : */
4006 0 : rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
4007 : LDB_SCOPE_ONELEVEL, attrs,
4008 : "objectClass=nTDSSiteSettings");
4009 :
4010 0 : if (rc != LDB_SUCCESS || res->count != 1)
4011 0 : goto failed;
4012 :
4013 0 : *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
4014 :
4015 0 : talloc_free(tmp_ctx);
4016 :
4017 0 : return LDB_SUCCESS;
4018 :
4019 0 : failed:
4020 0 : DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
4021 0 : talloc_free(tmp_ctx);
4022 0 : return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
4023 : }
4024 :
4025 : /*
4026 : return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
4027 :
4028 : flags are DS_NTDS_OPTION_*
4029 : */
4030 17909 : int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
4031 : {
4032 72 : TALLOC_CTX *tmp_ctx;
4033 17909 : const char *attrs[] = { "options", NULL };
4034 72 : int ret;
4035 72 : struct ldb_result *res;
4036 :
4037 17909 : tmp_ctx = talloc_new(ldb);
4038 17909 : if (tmp_ctx == NULL) {
4039 0 : goto failed;
4040 : }
4041 :
4042 17909 : ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
4043 17909 : if (ret != LDB_SUCCESS) {
4044 0 : goto failed;
4045 : }
4046 :
4047 17909 : if (res->count != 1) {
4048 0 : goto failed;
4049 : }
4050 :
4051 17909 : *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
4052 :
4053 17909 : talloc_free(tmp_ctx);
4054 :
4055 17909 : return LDB_SUCCESS;
4056 :
4057 0 : failed:
4058 0 : DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
4059 0 : talloc_free(tmp_ctx);
4060 0 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4061 : }
4062 :
4063 0 : const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
4064 : {
4065 0 : const char *attrs[] = { "objectCategory", NULL };
4066 0 : int ret;
4067 0 : struct ldb_result *res;
4068 :
4069 0 : ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
4070 0 : if (ret != LDB_SUCCESS) {
4071 0 : goto failed;
4072 : }
4073 :
4074 0 : if (res->count != 1) {
4075 0 : goto failed;
4076 : }
4077 :
4078 0 : return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
4079 :
4080 0 : failed:
4081 0 : DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
4082 0 : return NULL;
4083 : }
4084 :
4085 : /*
4086 : * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
4087 : * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
4088 : */
4089 734 : const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
4090 : {
4091 0 : char **tokens, *ret;
4092 0 : size_t i;
4093 :
4094 734 : tokens = str_list_make(mem_ctx, cn, " -_");
4095 734 : if (tokens == NULL || tokens[0] == NULL) {
4096 0 : return NULL;
4097 : }
4098 :
4099 : /* "tolower()" and "toupper()" should also work properly on 0x00 */
4100 734 : tokens[0][0] = tolower(tokens[0][0]);
4101 2799 : for (i = 1; tokens[i] != NULL; i++)
4102 2065 : tokens[i][0] = toupper(tokens[i][0]);
4103 :
4104 734 : ret = talloc_strdup(mem_ctx, tokens[0]);
4105 734 : if (ret == NULL) {
4106 0 : talloc_free(tokens);
4107 0 : return NULL;
4108 : }
4109 2799 : for (i = 1; tokens[i] != NULL; i++) {
4110 2065 : ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
4111 2065 : if (ret == NULL) {
4112 0 : talloc_free(tokens);
4113 0 : return NULL;
4114 : }
4115 : }
4116 :
4117 734 : talloc_free(tokens);
4118 :
4119 734 : return ret;
4120 : }
4121 :
4122 : /*
4123 : * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
4124 : */
4125 2885364 : int dsdb_functional_level(struct ldb_context *ldb)
4126 : {
4127 170435 : unsigned long long *domainFunctionality =
4128 2885364 : talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), unsigned long long);
4129 2885364 : if (!domainFunctionality) {
4130 : /* this is expected during initial provision */
4131 139420 : DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
4132 139420 : return DS_DOMAIN_FUNCTION_2000;
4133 : }
4134 2745944 : return *domainFunctionality;
4135 : }
4136 :
4137 : /*
4138 : * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
4139 : */
4140 3332 : int dsdb_forest_functional_level(struct ldb_context *ldb)
4141 : {
4142 23 : unsigned long long *forestFunctionality =
4143 3332 : talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), unsigned long long);
4144 3332 : if (!forestFunctionality) {
4145 0 : DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
4146 0 : return DS_DOMAIN_FUNCTION_2000;
4147 : }
4148 3332 : return *forestFunctionality;
4149 : }
4150 :
4151 : /*
4152 : * This detects and returns the DC functional level (DS_DOMAIN_FUNCTION_*)
4153 : */
4154 264778 : int dsdb_dc_functional_level(struct ldb_context *ldb)
4155 : {
4156 15100 : unsigned long long *dcFunctionality =
4157 264778 : talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), unsigned long long);
4158 264778 : if (!dcFunctionality) {
4159 : /* this is expected during initial provision */
4160 2 : DEBUG(4,(__location__ ": WARNING: domainControllerFunctionality not setup\n"));
4161 2 : return DS_DOMAIN_FUNCTION_2008_R2;
4162 : }
4163 264776 : return *dcFunctionality;
4164 : }
4165 :
4166 130 : const char *dsdb_dc_operatingSystemVersion(int dc_functional_level)
4167 : {
4168 130 : const char *operatingSystemVersion = NULL;
4169 :
4170 : /*
4171 : * While we are there also update
4172 : * operatingSystem and operatingSystemVersion
4173 : * as at least operatingSystemVersion is really
4174 : * important for some clients/applications (like exchange).
4175 : */
4176 :
4177 130 : if (dc_functional_level >= DS_DOMAIN_FUNCTION_2016) {
4178 : /* Pretend Windows 2016 */
4179 24 : operatingSystemVersion = "10.0 (14393)";
4180 104 : } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012_R2) {
4181 : /* Pretend Windows 2012 R2 */
4182 1 : operatingSystemVersion = "6.3 (9600)";
4183 103 : } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012) {
4184 : /* Pretend Windows 2012 */
4185 0 : operatingSystemVersion = "6.2 (9200)";
4186 : } else {
4187 : /* Pretend Windows 2008 R2 */
4188 103 : operatingSystemVersion = "6.1 (7600)";
4189 : }
4190 :
4191 130 : return operatingSystemVersion;
4192 : }
4193 :
4194 71 : int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_context *lp_ctx)
4195 : {
4196 71 : TALLOC_CTX *frame = talloc_stackframe();
4197 4 : int ret;
4198 :
4199 4 : int db_dc_functional_level;
4200 4 : int db_domain_functional_level;
4201 4 : int db_forest_functional_level;
4202 71 : int lp_dc_functional_level = lpcfg_ad_dc_functional_level(lp_ctx);
4203 4 : bool am_rodc;
4204 71 : struct ldb_message *msg = NULL;
4205 71 : struct ldb_dn *dc_ntds_settings_dn = NULL;
4206 71 : struct ldb_dn *dc_computer_dn = NULL;
4207 71 : const char *operatingSystem = NULL;
4208 71 : const char *operatingSystemVersion = NULL;
4209 :
4210 71 : db_dc_functional_level = dsdb_dc_functional_level(ldb_ctx);
4211 71 : db_domain_functional_level = dsdb_functional_level(ldb_ctx);
4212 71 : db_forest_functional_level = dsdb_forest_functional_level(ldb_ctx);
4213 :
4214 71 : if (lp_dc_functional_level < db_domain_functional_level) {
4215 1 : DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
4216 : "which is less than the domain functional level of %d\n",
4217 : lp_dc_functional_level, db_domain_functional_level);
4218 1 : TALLOC_FREE(frame);
4219 1 : return LDB_ERR_CONSTRAINT_VIOLATION;
4220 : }
4221 :
4222 70 : if (lp_dc_functional_level < db_forest_functional_level) {
4223 0 : DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
4224 : "which is less than the forest functional level of %d\n",
4225 : lp_dc_functional_level, db_forest_functional_level);
4226 0 : TALLOC_FREE(frame);
4227 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
4228 : }
4229 :
4230 : /* Check if we need to update the DB */
4231 70 : if (db_dc_functional_level == lp_dc_functional_level) {
4232 : /*
4233 : * Note that this early return means
4234 : * we're not updating operatingSystem and
4235 : * operatingSystemVersion.
4236 : *
4237 : * But at least for now that's
4238 : * exactly what we want.
4239 : */
4240 67 : TALLOC_FREE(frame);
4241 67 : return LDB_SUCCESS;
4242 : }
4243 :
4244 : /* Confirm we are not an RODC before we try a modify */
4245 3 : ret = samdb_rodc(ldb_ctx, &am_rodc);
4246 3 : if (ret != LDB_SUCCESS) {
4247 0 : DBG_ERR("Failed to determine if this server is an RODC\n");
4248 0 : TALLOC_FREE(frame);
4249 0 : return ret;
4250 : }
4251 :
4252 3 : if (am_rodc) {
4253 0 : DBG_WARNING("Unable to update DC's msDS-Behavior-Version "
4254 : "(from %d to %d) and operatingSystem[Version] "
4255 : "as we are an RODC\n",
4256 : db_dc_functional_level, lp_dc_functional_level);
4257 0 : TALLOC_FREE(frame);
4258 0 : return LDB_SUCCESS;
4259 : }
4260 :
4261 3 : dc_ntds_settings_dn = samdb_ntds_settings_dn(ldb_ctx, frame);
4262 :
4263 3 : if (dc_ntds_settings_dn == NULL) {
4264 0 : DBG_ERR("Failed to find own NTDS Settings DN\n");
4265 0 : TALLOC_FREE(frame);
4266 0 : return LDB_ERR_NO_SUCH_OBJECT;
4267 : }
4268 :
4269 : /* Now update our msDS-Behavior-Version */
4270 :
4271 3 : msg = ldb_msg_new(frame);
4272 3 : if (msg == NULL) {
4273 0 : DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
4274 0 : TALLOC_FREE(frame);
4275 0 : return LDB_ERR_OPERATIONS_ERROR;
4276 : }
4277 :
4278 3 : msg->dn = dc_ntds_settings_dn;
4279 :
4280 3 : ret = samdb_msg_add_int(ldb_ctx, frame, msg, "msDS-Behavior-Version", lp_dc_functional_level);
4281 3 : if (ret != LDB_SUCCESS) {
4282 0 : DBG_ERR("Failed to set new msDS-Behavior-Version on message\n");
4283 0 : TALLOC_FREE(frame);
4284 0 : return LDB_ERR_OPERATIONS_ERROR;
4285 : }
4286 :
4287 3 : ret = dsdb_replace(ldb_ctx, msg, 0);
4288 3 : if (ret != LDB_SUCCESS) {
4289 0 : DBG_ERR("Failed to update DB with new msDS-Behavior-Version on %s: %s\n",
4290 : ldb_dn_get_linearized(dc_ntds_settings_dn),
4291 : ldb_errstring(ldb_ctx));
4292 0 : TALLOC_FREE(frame);
4293 0 : return ret;
4294 : }
4295 :
4296 : /*
4297 : * We have to update the opaque because this particular ldb_context
4298 : * will not re-read the DB
4299 : */
4300 : {
4301 3 : unsigned long long *val = talloc(ldb_ctx, unsigned long long);
4302 3 : if (!val) {
4303 0 : TALLOC_FREE(frame);
4304 0 : return LDB_ERR_OPERATIONS_ERROR;
4305 : }
4306 3 : *val = lp_dc_functional_level;
4307 3 : ret = ldb_set_opaque(ldb_ctx,
4308 : "domainControllerFunctionality", val);
4309 3 : if (ret != LDB_SUCCESS) {
4310 0 : DBG_ERR("Failed to re-set domainControllerFunctionality opaque\n");
4311 0 : TALLOC_FREE(val);
4312 0 : TALLOC_FREE(frame);
4313 0 : return ret;
4314 : }
4315 : }
4316 :
4317 : /*
4318 : * While we are there also update
4319 : * operatingSystem and operatingSystemVersion
4320 : * as at least operatingSystemVersion is really
4321 : * important for some clients/applications (like exchange).
4322 : */
4323 :
4324 3 : operatingSystem = talloc_asprintf(frame, "Samba-%s",
4325 : samba_version_string());
4326 3 : if (operatingSystem == NULL) {
4327 0 : TALLOC_FREE(frame);
4328 0 : return ldb_oom(ldb_ctx);
4329 : }
4330 :
4331 3 : operatingSystemVersion = dsdb_dc_operatingSystemVersion(db_dc_functional_level);
4332 :
4333 3 : ret = samdb_server_reference_dn(ldb_ctx, frame, &dc_computer_dn);
4334 3 : if (ret != LDB_SUCCESS) {
4335 0 : DBG_ERR("Failed to get the dc_computer_dn: %s\n",
4336 : ldb_errstring(ldb_ctx));
4337 0 : TALLOC_FREE(frame);
4338 0 : return ret;
4339 : }
4340 :
4341 3 : msg = ldb_msg_new(frame);
4342 3 : if (msg == NULL) {
4343 0 : DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
4344 0 : TALLOC_FREE(frame);
4345 0 : return LDB_ERR_OPERATIONS_ERROR;
4346 : }
4347 :
4348 3 : msg->dn = dc_computer_dn;
4349 :
4350 3 : ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
4351 : "operatingSystem",
4352 : operatingSystem);
4353 3 : if (ret != LDB_SUCCESS) {
4354 0 : DBG_ERR("Failed to set new operatingSystem on message\n");
4355 0 : TALLOC_FREE(frame);
4356 0 : return ldb_operr(ldb_ctx);
4357 : }
4358 :
4359 3 : ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
4360 : "operatingSystemVersion",
4361 : operatingSystemVersion);
4362 3 : if (ret != LDB_SUCCESS) {
4363 0 : DBG_ERR("Failed to set new operatingSystemVersion on message\n");
4364 0 : TALLOC_FREE(frame);
4365 0 : return ldb_operr(ldb_ctx);
4366 : }
4367 :
4368 3 : ret = dsdb_replace(ldb_ctx, msg, 0);
4369 3 : if (ret != LDB_SUCCESS) {
4370 0 : DBG_ERR("Failed to update DB with new operatingSystem[Version] on %s: %s\n",
4371 : ldb_dn_get_linearized(dc_computer_dn),
4372 : ldb_errstring(ldb_ctx));
4373 0 : TALLOC_FREE(frame);
4374 0 : return ret;
4375 : }
4376 :
4377 3 : TALLOC_FREE(frame);
4378 2 : return LDB_SUCCESS;
4379 : }
4380 :
4381 :
4382 : /*
4383 : set a GUID in an extended DN structure
4384 : */
4385 24316 : int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
4386 : {
4387 41 : struct ldb_val v;
4388 41 : NTSTATUS status;
4389 41 : int ret;
4390 :
4391 24316 : status = GUID_to_ndr_blob(guid, dn, &v);
4392 24316 : if (!NT_STATUS_IS_OK(status)) {
4393 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
4394 : }
4395 :
4396 24316 : ret = ldb_dn_set_extended_component(dn, component_name, &v);
4397 24316 : data_blob_free(&v);
4398 24316 : return ret;
4399 : }
4400 :
4401 : /*
4402 : return a GUID from a extended DN structure
4403 : */
4404 17603043 : NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
4405 : {
4406 269084 : const struct ldb_val *v;
4407 :
4408 17603043 : v = ldb_dn_get_extended_component(dn, component_name);
4409 17603043 : if (v == NULL) {
4410 207275 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4411 : }
4412 :
4413 17395768 : return GUID_from_ndr_blob(v, guid);
4414 : }
4415 :
4416 : /*
4417 : return a uint64_t from a extended DN structure
4418 : */
4419 128572 : NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
4420 : {
4421 24 : const struct ldb_val *v;
4422 128572 : int error = 0;
4423 :
4424 128572 : v = ldb_dn_get_extended_component(dn, component_name);
4425 128572 : if (v == NULL) {
4426 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4427 : }
4428 :
4429 : /* Just check we don't allow the caller to fill our stack */
4430 128572 : if (v->length >= 64) {
4431 0 : return NT_STATUS_INVALID_PARAMETER;
4432 128572 : } else {
4433 128572 : char s[v->length+1];
4434 128572 : memcpy(s, v->data, v->length);
4435 128572 : s[v->length] = 0;
4436 :
4437 128572 : *val = smb_strtoull(s, NULL, 0, &error, SMB_STR_STANDARD);
4438 128572 : if (error != 0) {
4439 0 : return NT_STATUS_INVALID_PARAMETER;
4440 : }
4441 : }
4442 128572 : return NT_STATUS_OK;
4443 : }
4444 :
4445 : /*
4446 : return a NTTIME from a extended DN structure
4447 : */
4448 48933 : NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
4449 : {
4450 48933 : return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
4451 : }
4452 :
4453 : /*
4454 : return a uint32_t from a extended DN structure
4455 : */
4456 5173805 : NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
4457 : {
4458 19558 : const struct ldb_val *v;
4459 5173805 : int error = 0;
4460 :
4461 5173805 : v = ldb_dn_get_extended_component(dn, component_name);
4462 5173805 : if (v == NULL) {
4463 5030288 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4464 : }
4465 :
4466 : /* Just check we don't allow the caller to fill our stack */
4467 143517 : if (v->length >= 32) {
4468 0 : return NT_STATUS_INVALID_PARAMETER;
4469 143517 : } else {
4470 143517 : char s[v->length + 1];
4471 143517 : memcpy(s, v->data, v->length);
4472 143517 : s[v->length] = 0;
4473 143517 : *val = smb_strtoul(s, NULL, 0, &error, SMB_STR_STANDARD);
4474 143517 : if (error != 0) {
4475 0 : return NT_STATUS_INVALID_PARAMETER;
4476 : }
4477 : }
4478 :
4479 143517 : return NT_STATUS_OK;
4480 : }
4481 :
4482 : /*
4483 : return a dom_sid from a extended DN structure
4484 : */
4485 3595284 : NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
4486 : {
4487 103532 : const struct ldb_val *sid_blob;
4488 103532 : enum ndr_err_code ndr_err;
4489 :
4490 3595284 : sid_blob = ldb_dn_get_extended_component(dn, component_name);
4491 3595284 : if (!sid_blob) {
4492 621923 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4493 : }
4494 :
4495 2973361 : ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
4496 : (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
4497 2973361 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4498 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
4499 0 : return status;
4500 : }
4501 :
4502 2973361 : return NT_STATUS_OK;
4503 : }
4504 :
4505 :
4506 : /*
4507 : return RMD_FLAGS directly from a ldb_dn
4508 : returns 0 if not found
4509 : */
4510 720574 : uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
4511 : {
4512 720574 : uint32_t rmd_flags = 0;
4513 720574 : NTSTATUS status = dsdb_get_extended_dn_uint32(dn, &rmd_flags,
4514 : "RMD_FLAGS");
4515 720574 : if (NT_STATUS_IS_OK(status)) {
4516 49166 : return rmd_flags;
4517 : }
4518 652159 : return 0;
4519 : }
4520 :
4521 : /*
4522 : return RMD_FLAGS directly from a ldb_val for a DN
4523 : returns 0 if RMD_FLAGS is not found
4524 : */
4525 19584097 : uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
4526 : {
4527 422854 : const char *p;
4528 422854 : uint32_t flags;
4529 422854 : char *end;
4530 19584097 : int error = 0;
4531 :
4532 19584097 : if (val->length < 13) {
4533 0 : return 0;
4534 : }
4535 19584097 : p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
4536 19584097 : if (!p) {
4537 15351934 : return 0;
4538 : }
4539 3818541 : flags = smb_strtoul(p+11, &end, 10, &error, SMB_STR_STANDARD);
4540 3818541 : if (!end || *end != '>' || error != 0) {
4541 : /* it must end in a > */
4542 0 : return 0;
4543 : }
4544 3809309 : return flags;
4545 : }
4546 :
4547 : /*
4548 : return true if a ldb_val containing a DN in storage form is deleted
4549 : */
4550 57246 : bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
4551 : {
4552 57246 : return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
4553 : }
4554 :
4555 : /*
4556 : return true if a ldb_val containing a DN in storage form is
4557 : in the upgraded w2k3 linked attribute format
4558 : */
4559 11986 : bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
4560 : {
4561 11986 : return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
4562 : }
4563 :
4564 : /*
4565 : return a DN for a wellknown GUID
4566 : */
4567 943562 : int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
4568 : struct ldb_dn *nc_root, const char *wk_guid,
4569 : struct ldb_dn **wkguid_dn)
4570 : {
4571 943562 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
4572 943562 : const char *attrs[] = { NULL };
4573 77167 : int ret;
4574 77167 : struct ldb_dn *dn;
4575 943562 : struct ldb_result *res = NULL;
4576 :
4577 943562 : if (tmp_ctx == NULL) {
4578 0 : return ldb_oom(samdb);
4579 : }
4580 :
4581 : /* construct the magic WKGUID DN */
4582 943562 : dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
4583 : wk_guid, ldb_dn_get_linearized(nc_root));
4584 943562 : if (!wkguid_dn) {
4585 0 : talloc_free(tmp_ctx);
4586 0 : return ldb_operr(samdb);
4587 : }
4588 :
4589 943562 : ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
4590 : DSDB_SEARCH_SHOW_DELETED |
4591 : DSDB_SEARCH_SHOW_RECYCLED);
4592 943562 : if (ret != LDB_SUCCESS) {
4593 553144 : talloc_free(tmp_ctx);
4594 553144 : return ret;
4595 : }
4596 : /* fix clang warning */
4597 390418 : if (res == NULL){
4598 0 : talloc_free(tmp_ctx);
4599 0 : return LDB_ERR_OTHER;
4600 : }
4601 :
4602 390418 : (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
4603 390418 : talloc_free(tmp_ctx);
4604 390418 : return LDB_SUCCESS;
4605 : }
4606 :
4607 :
4608 2355 : static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
4609 : {
4610 2355 : return ldb_dn_compare(*dn1, *dn2);
4611 : }
4612 :
4613 : /*
4614 : find a NC root given a DN within the NC by reading the rootDSE namingContexts
4615 : */
4616 985 : static int dsdb_find_nc_root_string_based(struct ldb_context *samdb,
4617 : TALLOC_CTX *mem_ctx,
4618 : struct ldb_dn *dn,
4619 : struct ldb_dn **nc_root)
4620 : {
4621 985 : const char *root_attrs[] = { "namingContexts", NULL };
4622 44 : TALLOC_CTX *tmp_ctx;
4623 44 : int ret;
4624 44 : struct ldb_message_element *el;
4625 44 : struct ldb_result *root_res;
4626 44 : unsigned int i;
4627 44 : struct ldb_dn **nc_dns;
4628 :
4629 985 : tmp_ctx = talloc_new(samdb);
4630 985 : if (tmp_ctx == NULL) {
4631 0 : return ldb_oom(samdb);
4632 : }
4633 :
4634 985 : ret = ldb_search(samdb, tmp_ctx, &root_res,
4635 : ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
4636 985 : if (ret != LDB_SUCCESS || root_res->count == 0) {
4637 0 : DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
4638 0 : talloc_free(tmp_ctx);
4639 0 : return ret;
4640 : }
4641 :
4642 985 : el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
4643 985 : if ((el == NULL) || (el->num_values < 3)) {
4644 44 : struct ldb_message *tmp_msg;
4645 :
4646 874 : DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.\n"));
4647 :
4648 : /* This generates a temporary list of NCs in order to let the
4649 : * provisioning work. */
4650 874 : tmp_msg = ldb_msg_new(tmp_ctx);
4651 874 : if (tmp_msg == NULL) {
4652 0 : talloc_free(tmp_ctx);
4653 0 : return ldb_oom(samdb);
4654 : }
4655 874 : ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4656 : ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
4657 874 : if (ret != LDB_SUCCESS) {
4658 0 : talloc_free(tmp_ctx);
4659 0 : return ret;
4660 : }
4661 874 : ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4662 : ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
4663 874 : if (ret != LDB_SUCCESS) {
4664 0 : talloc_free(tmp_ctx);
4665 0 : return ret;
4666 : }
4667 874 : ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
4668 : ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
4669 874 : if (ret != LDB_SUCCESS) {
4670 0 : talloc_free(tmp_ctx);
4671 0 : return ret;
4672 : }
4673 874 : el = &tmp_msg->elements[0];
4674 : }
4675 :
4676 985 : nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
4677 985 : if (!nc_dns) {
4678 0 : talloc_free(tmp_ctx);
4679 0 : return ldb_oom(samdb);
4680 : }
4681 :
4682 4114 : for (i=0; i<el->num_values; i++) {
4683 3129 : nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
4684 3129 : if (nc_dns[i] == NULL) {
4685 0 : talloc_free(tmp_ctx);
4686 0 : return ldb_operr(samdb);
4687 : }
4688 : }
4689 :
4690 985 : TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
4691 :
4692 3099 : for (i=0; i<el->num_values; i++) {
4693 3087 : if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
4694 973 : (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
4695 973 : talloc_free(tmp_ctx);
4696 973 : return LDB_SUCCESS;
4697 : }
4698 : }
4699 :
4700 12 : talloc_free(tmp_ctx);
4701 12 : return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4702 : }
4703 :
4704 : struct dsdb_get_partition_and_dn {
4705 : TALLOC_CTX *mem_ctx;
4706 : unsigned int count;
4707 : struct ldb_dn *dn;
4708 : struct ldb_dn *partition_dn;
4709 : bool want_partition_dn;
4710 : };
4711 :
4712 9960731 : static int dsdb_get_partition_and_dn(struct ldb_request *req,
4713 : struct ldb_reply *ares)
4714 : {
4715 775092 : int ret;
4716 9960731 : struct dsdb_get_partition_and_dn *context = req->context;
4717 9960731 : struct ldb_control *partition_ctrl = NULL;
4718 9960731 : struct dsdb_control_current_partition *partition = NULL;
4719 :
4720 9960731 : if (!ares) {
4721 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
4722 : }
4723 9960731 : if (ares->error != LDB_SUCCESS
4724 2153513 : && ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4725 1 : return ldb_request_done(req, ares->error);
4726 : }
4727 :
4728 9960730 : switch (ares->type) {
4729 4165794 : case LDB_REPLY_ENTRY:
4730 4165794 : if (context->count != 0) {
4731 0 : return ldb_request_done(req,
4732 : LDB_ERR_CONSTRAINT_VIOLATION);
4733 : }
4734 4165794 : context->count++;
4735 :
4736 4165794 : context->dn = talloc_steal(context->mem_ctx,
4737 : ares->message->dn);
4738 4165794 : break;
4739 :
4740 0 : case LDB_REPLY_REFERRAL:
4741 0 : talloc_free(ares);
4742 0 : return ldb_request_done(req, LDB_SUCCESS);
4743 :
4744 5794936 : case LDB_REPLY_DONE:
4745 512907 : partition_ctrl
4746 5794936 : = ldb_reply_get_control(ares,
4747 : DSDB_CONTROL_CURRENT_PARTITION_OID);
4748 5794936 : if (!context->want_partition_dn ||
4749 : partition_ctrl == NULL) {
4750 16726 : ret = ares->error;
4751 16726 : talloc_free(ares);
4752 :
4753 16726 : return ldb_request_done(req, ret);
4754 : }
4755 :
4756 512863 : partition
4757 5778210 : = talloc_get_type_abort(partition_ctrl->data,
4758 : struct dsdb_control_current_partition);
4759 512863 : context->partition_dn
4760 5778210 : = ldb_dn_copy(context->mem_ctx, partition->dn);
4761 5778210 : if (context->partition_dn == NULL) {
4762 0 : return ldb_request_done(req,
4763 : LDB_ERR_OPERATIONS_ERROR);
4764 : }
4765 :
4766 5778210 : ret = ares->error;
4767 5778210 : talloc_free(ares);
4768 :
4769 5778210 : return ldb_request_done(req, ret);
4770 : }
4771 :
4772 4165794 : talloc_free(ares);
4773 4165794 : return LDB_SUCCESS;
4774 : }
4775 :
4776 : /*
4777 : find a NC root given a DN within the NC
4778 : */
4779 5794937 : int dsdb_normalise_dn_and_find_nc_root(struct ldb_context *samdb,
4780 : TALLOC_CTX *mem_ctx,
4781 : struct ldb_dn *dn,
4782 : struct ldb_dn **normalised_dn,
4783 : struct ldb_dn **nc_root)
4784 : {
4785 512907 : TALLOC_CTX *tmp_ctx;
4786 512907 : int ret;
4787 512907 : struct ldb_request *req;
4788 512907 : struct ldb_result *res;
4789 5794937 : struct ldb_dn *search_dn = dn;
4790 512907 : static const char * attrs[] = { NULL };
4791 5794937 : bool has_extended = ldb_dn_has_extended(dn);
4792 5794937 : bool has_normal_components = ldb_dn_get_comp_num(dn) >= 1;
4793 5794937 : struct dsdb_get_partition_and_dn context = {
4794 : .mem_ctx = mem_ctx,
4795 5794937 : .want_partition_dn = nc_root != NULL
4796 : };
4797 :
4798 5794937 : if (!has_extended && !has_normal_components) {
4799 0 : return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT,
4800 : "Request for NC root for rootDSE (\"\") denied.");
4801 : }
4802 :
4803 5794937 : tmp_ctx = talloc_new(samdb);
4804 5794937 : if (tmp_ctx == NULL) {
4805 0 : return ldb_oom(samdb);
4806 : }
4807 :
4808 5794937 : res = talloc_zero(tmp_ctx, struct ldb_result);
4809 5794937 : if (res == NULL) {
4810 0 : talloc_free(tmp_ctx);
4811 0 : return ldb_oom(samdb);
4812 : }
4813 :
4814 5794937 : if (has_extended && has_normal_components) {
4815 176773 : bool minimise_ok;
4816 2863405 : search_dn = ldb_dn_copy(tmp_ctx, dn);
4817 2863405 : if (search_dn == NULL) {
4818 0 : talloc_free(tmp_ctx);
4819 0 : return ldb_oom(samdb);
4820 : }
4821 2863405 : minimise_ok = ldb_dn_minimise(search_dn);
4822 2863405 : if (!minimise_ok) {
4823 0 : talloc_free(tmp_ctx);
4824 0 : return ldb_operr(samdb);
4825 : }
4826 : }
4827 :
4828 5794937 : ret = ldb_build_search_req(&req, samdb, tmp_ctx,
4829 : search_dn,
4830 : LDB_SCOPE_BASE,
4831 : NULL,
4832 : attrs,
4833 : NULL,
4834 : &context,
4835 : dsdb_get_partition_and_dn,
4836 : NULL);
4837 5794937 : if (ret != LDB_SUCCESS) {
4838 0 : talloc_free(tmp_ctx);
4839 0 : return ret;
4840 : }
4841 :
4842 5794937 : ret = ldb_request_add_control(req,
4843 : DSDB_CONTROL_CURRENT_PARTITION_OID,
4844 : false, NULL);
4845 5794937 : if (ret != LDB_SUCCESS) {
4846 0 : talloc_free(tmp_ctx);
4847 0 : return ret;
4848 : }
4849 :
4850 5794937 : ret = dsdb_request_add_controls(req,
4851 : DSDB_SEARCH_SHOW_RECYCLED|
4852 : DSDB_SEARCH_SHOW_DELETED|
4853 : DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
4854 5794937 : if (ret != LDB_SUCCESS) {
4855 0 : talloc_free(tmp_ctx);
4856 0 : return ret;
4857 : }
4858 :
4859 5794937 : ret = ldb_request(samdb, req);
4860 5794937 : if (ret == LDB_SUCCESS) {
4861 5794936 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4862 : }
4863 :
4864 : /*
4865 : * This could be a new DN, not in the DB, which is OK. If we
4866 : * don't need the normalised DN, we can continue.
4867 : *
4868 : * We may be told the partition it would be in in the search
4869 : * reply control, or if not we can do a string-based match.
4870 : */
4871 :
4872 5794937 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4873 1629142 : if (normalised_dn != NULL) {
4874 8 : talloc_free(tmp_ctx);
4875 8 : return ret;
4876 : }
4877 1629134 : ret = LDB_SUCCESS;
4878 1629134 : ldb_reset_err_string(samdb);
4879 4165795 : } else if (ret != LDB_SUCCESS) {
4880 1 : talloc_free(tmp_ctx);
4881 1 : return ret;
4882 : }
4883 :
4884 5794928 : if (normalised_dn != NULL) {
4885 18694 : if (context.count != 1) {
4886 : /* No results */
4887 0 : ldb_asprintf_errstring(samdb,
4888 : "Request for NC root for %s failed to return any results.",
4889 : ldb_dn_get_linearized(dn));
4890 0 : talloc_free(tmp_ctx);
4891 0 : return LDB_ERR_NO_SUCH_OBJECT;
4892 : }
4893 18694 : *normalised_dn = context.dn;
4894 : }
4895 :
4896 : /*
4897 : * If the user did not need to find the nc_root,
4898 : * we are done
4899 : */
4900 5794928 : if (nc_root == NULL) {
4901 15725 : talloc_free(tmp_ctx);
4902 15725 : return ret;
4903 : }
4904 :
4905 : /*
4906 : * When we are working locally, both for the case were
4907 : * we find the DN, and the case where we fail, we get
4908 : * back via controls the partition it was in or should
4909 : * have been in, to return to the client
4910 : */
4911 5779203 : if (context.partition_dn != NULL) {
4912 5778210 : (*nc_root) = context.partition_dn;
4913 :
4914 5778210 : talloc_free(tmp_ctx);
4915 5778210 : return ret;
4916 : }
4917 :
4918 : /*
4919 : * This is a remote operation, which is a little harder as we
4920 : * have a work out the nc_root from the list of NCs. If we did
4921 : * at least resolve the DN to a string, get that now, it makes
4922 : * the string-based match below possible for a GUID-based
4923 : * input over remote LDAP.
4924 : */
4925 993 : if (context.dn) {
4926 6 : dn = context.dn;
4927 987 : } else if (has_extended && !has_normal_components) {
4928 8 : ldb_asprintf_errstring(samdb,
4929 : "Cannot determine NC root "
4930 : "for a not-found bare extended DN %s.",
4931 : ldb_dn_get_extended_linearized(tmp_ctx, dn, 1));
4932 8 : talloc_free(tmp_ctx);
4933 8 : return LDB_ERR_NO_SUCH_OBJECT;
4934 : }
4935 :
4936 : /*
4937 : * Either we are working against a remote LDAP
4938 : * server or the object doesn't exist locally.
4939 : *
4940 : * This means any GUID that was present in the DN
4941 : * therefore could not be evaluated, so do a
4942 : * string-based match instead.
4943 : */
4944 985 : talloc_free(tmp_ctx);
4945 985 : return dsdb_find_nc_root_string_based(samdb,
4946 : mem_ctx,
4947 : dn,
4948 : nc_root);
4949 : }
4950 :
4951 : /*
4952 : find a NC root given a DN within the NC
4953 : */
4954 5757953 : int dsdb_find_nc_root(struct ldb_context *samdb,
4955 : TALLOC_CTX *mem_ctx,
4956 : struct ldb_dn *dn,
4957 : struct ldb_dn **nc_root)
4958 : {
4959 5757953 : return dsdb_normalise_dn_and_find_nc_root(samdb,
4960 : mem_ctx,
4961 : dn,
4962 : NULL,
4963 : nc_root);
4964 : }
4965 :
4966 : /*
4967 : find the deleted objects DN for any object, by looking for the NC
4968 : root, then looking up the wellknown GUID
4969 : */
4970 373153 : int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
4971 : TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
4972 : struct ldb_dn **do_dn)
4973 : {
4974 112 : struct ldb_dn *nc_root;
4975 112 : int ret;
4976 :
4977 373153 : ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
4978 373153 : if (ret != LDB_SUCCESS) {
4979 0 : return ret;
4980 : }
4981 :
4982 373153 : ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
4983 373153 : talloc_free(nc_root);
4984 373153 : return ret;
4985 : }
4986 :
4987 : /*
4988 : return the tombstoneLifetime, in days
4989 : */
4990 59 : int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
4991 : {
4992 2 : struct ldb_dn *dn;
4993 59 : dn = ldb_get_config_basedn(ldb);
4994 59 : if (!dn) {
4995 0 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
4996 : }
4997 59 : dn = ldb_dn_copy(ldb, dn);
4998 59 : if (!dn) {
4999 0 : return ldb_operr(ldb);
5000 : }
5001 : /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
5002 : be a wellknown GUID for this */
5003 59 : if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
5004 0 : talloc_free(dn);
5005 0 : return ldb_operr(ldb);
5006 : }
5007 :
5008 59 : *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
5009 59 : talloc_free(dn);
5010 59 : return LDB_SUCCESS;
5011 : }
5012 :
5013 : /*
5014 : compare a ldb_val to a string case insensitively
5015 : */
5016 0 : int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
5017 : {
5018 0 : size_t len = strlen(s);
5019 0 : int ret;
5020 0 : if (len > v->length) return 1;
5021 0 : ret = strncasecmp(s, (const char *)v->data, v->length);
5022 0 : if (ret != 0) return ret;
5023 0 : if (v->length > len && v->data[len] != 0) {
5024 0 : return -1;
5025 : }
5026 0 : return 0;
5027 : }
5028 :
5029 :
5030 : /*
5031 : load the UDV for a partition in v2 format
5032 : The list is returned sorted, and with our local cursor added
5033 : */
5034 18345 : int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
5035 : struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
5036 : {
5037 20 : static const char *attrs[] = { "replUpToDateVector", NULL };
5038 18345 : struct ldb_result *r = NULL;
5039 20 : const struct ldb_val *ouv_value;
5040 20 : unsigned int i;
5041 20 : int ret;
5042 18345 : uint64_t highest_usn = 0;
5043 20 : const struct GUID *our_invocation_id;
5044 20 : static const struct timeval tv1970;
5045 18345 : NTTIME nt1970 = timeval_to_nttime(&tv1970);
5046 :
5047 18345 : ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
5048 18345 : if (ret != LDB_SUCCESS) {
5049 0 : return ret;
5050 : }
5051 : /* fix clang warning */
5052 18345 : if (r == NULL) {
5053 0 : return LDB_ERR_OTHER;
5054 : }
5055 18345 : ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
5056 18345 : if (ouv_value) {
5057 0 : enum ndr_err_code ndr_err;
5058 0 : struct replUpToDateVectorBlob ouv;
5059 :
5060 11445 : ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
5061 : (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5062 11445 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5063 0 : talloc_free(r);
5064 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
5065 : }
5066 11445 : if (ouv.version != 2) {
5067 : /* we always store as version 2, and
5068 : * replUpToDateVector is not replicated
5069 : */
5070 0 : talloc_free(r);
5071 0 : return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
5072 : }
5073 :
5074 11445 : *count = ouv.ctr.ctr2.count;
5075 11445 : *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
5076 : } else {
5077 6900 : *count = 0;
5078 6900 : *cursors = NULL;
5079 : }
5080 :
5081 18345 : talloc_free(r);
5082 :
5083 18345 : our_invocation_id = samdb_ntds_invocation_id(samdb);
5084 18345 : if (!our_invocation_id) {
5085 0 : DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
5086 0 : talloc_free(*cursors);
5087 0 : return ldb_operr(samdb);
5088 : }
5089 :
5090 18345 : ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
5091 18345 : if (ret != LDB_SUCCESS) {
5092 : /* nothing to add - this can happen after a vampire */
5093 315 : TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
5094 315 : return LDB_SUCCESS;
5095 : }
5096 :
5097 30857 : for (i=0; i<*count; i++) {
5098 12827 : if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
5099 0 : (*cursors)[i].highest_usn = highest_usn;
5100 0 : (*cursors)[i].last_sync_success = nt1970;
5101 0 : TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
5102 0 : return LDB_SUCCESS;
5103 : }
5104 : }
5105 :
5106 18030 : (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
5107 18030 : if (! *cursors) {
5108 0 : return ldb_oom(samdb);
5109 : }
5110 :
5111 18030 : (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
5112 18030 : (*cursors)[*count].highest_usn = highest_usn;
5113 18030 : (*cursors)[*count].last_sync_success = nt1970;
5114 18030 : (*count)++;
5115 :
5116 18030 : TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
5117 :
5118 18010 : return LDB_SUCCESS;
5119 : }
5120 :
5121 : /*
5122 : load the UDV for a partition in version 1 format
5123 : The list is returned sorted, and with our local cursor added
5124 : */
5125 0 : int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
5126 : struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
5127 : {
5128 0 : struct drsuapi_DsReplicaCursor2 *v2 = NULL;
5129 0 : uint32_t i;
5130 0 : int ret;
5131 :
5132 0 : ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
5133 0 : if (ret != LDB_SUCCESS) {
5134 0 : return ret;
5135 : }
5136 :
5137 0 : if (*count == 0) {
5138 0 : talloc_free(v2);
5139 0 : *cursors = NULL;
5140 0 : return LDB_SUCCESS;
5141 : }
5142 :
5143 0 : *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
5144 0 : if (*cursors == NULL) {
5145 0 : talloc_free(v2);
5146 0 : return ldb_oom(samdb);
5147 : }
5148 :
5149 0 : for (i=0; i<*count; i++) {
5150 0 : (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
5151 0 : (*cursors)[i].highest_usn = v2[i].highest_usn;
5152 : }
5153 0 : talloc_free(v2);
5154 0 : return LDB_SUCCESS;
5155 : }
5156 :
5157 : /*
5158 : add a set of controls to a ldb_request structure based on a set of
5159 : flags. See util.h for a list of available flags
5160 : */
5161 71551183 : int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
5162 : {
5163 3255977 : int ret;
5164 71551183 : if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
5165 469496 : struct ldb_search_options_control *options;
5166 : /* Using the phantom root control allows us to search all partitions */
5167 19813605 : options = talloc(req, struct ldb_search_options_control);
5168 19813605 : if (options == NULL) {
5169 0 : return LDB_ERR_OPERATIONS_ERROR;
5170 : }
5171 19813605 : options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
5172 :
5173 19813605 : ret = ldb_request_add_control(req,
5174 : LDB_CONTROL_SEARCH_OPTIONS_OID,
5175 : true, options);
5176 19813605 : if (ret != LDB_SUCCESS) {
5177 0 : return ret;
5178 : }
5179 : }
5180 :
5181 71551183 : if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
5182 333716 : ret = ldb_request_add_control(req,
5183 : DSDB_CONTROL_NO_GLOBAL_CATALOG,
5184 : false, NULL);
5185 333716 : if (ret != LDB_SUCCESS) {
5186 0 : return ret;
5187 : }
5188 : }
5189 :
5190 71551183 : if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
5191 22001930 : ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
5192 22001930 : if (ret != LDB_SUCCESS) {
5193 0 : return ret;
5194 : }
5195 : }
5196 :
5197 71551183 : if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
5198 34021687 : ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
5199 34021687 : if (ret != LDB_SUCCESS) {
5200 0 : return ret;
5201 : }
5202 : }
5203 :
5204 71551183 : if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
5205 7541856 : ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
5206 7541856 : if (ret != LDB_SUCCESS) {
5207 0 : return ret;
5208 : }
5209 : }
5210 :
5211 71551183 : if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
5212 18086365 : struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
5213 18086365 : if (!extended_ctrl) {
5214 0 : return LDB_ERR_OPERATIONS_ERROR;
5215 : }
5216 18086365 : extended_ctrl->type = 1;
5217 :
5218 18086365 : ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
5219 18086365 : if (ret != LDB_SUCCESS) {
5220 0 : return ret;
5221 : }
5222 : }
5223 :
5224 71551183 : if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
5225 1422223 : ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
5226 1422223 : if (ret != LDB_SUCCESS) {
5227 0 : return ret;
5228 : }
5229 : }
5230 :
5231 71551183 : if (dsdb_flags & DSDB_MODIFY_RELAX) {
5232 89 : ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
5233 89 : if (ret != LDB_SUCCESS) {
5234 0 : return ret;
5235 : }
5236 : }
5237 :
5238 71551183 : if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
5239 10 : ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
5240 10 : if (ret != LDB_SUCCESS) {
5241 0 : return ret;
5242 : }
5243 : }
5244 :
5245 71551183 : if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
5246 19408718 : ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
5247 19408718 : if (ret != LDB_SUCCESS) {
5248 0 : return ret;
5249 : }
5250 : }
5251 :
5252 71551183 : if (dsdb_flags & DSDB_TREE_DELETE) {
5253 29735 : ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
5254 29735 : if (ret != LDB_SUCCESS) {
5255 0 : return ret;
5256 : }
5257 : }
5258 :
5259 71551183 : if (dsdb_flags & DSDB_PROVISION) {
5260 0 : ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
5261 0 : if (ret != LDB_SUCCESS) {
5262 0 : return ret;
5263 : }
5264 : }
5265 :
5266 : /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
5267 71551183 : if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
5268 11 : ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
5269 11 : if (ret != LDB_SUCCESS) {
5270 0 : return ret;
5271 : }
5272 : }
5273 :
5274 71551183 : if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
5275 : /*
5276 : * This must not be critical, as it will only be
5277 : * handled (and need to be handled) if the other
5278 : * attributes in the request bring password_hash into
5279 : * action
5280 : */
5281 16 : ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
5282 16 : if (ret != LDB_SUCCESS) {
5283 0 : return ret;
5284 : }
5285 : }
5286 :
5287 71551183 : if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
5288 29429 : ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
5289 29429 : if (ret != LDB_SUCCESS) {
5290 0 : return ret;
5291 : }
5292 : }
5293 :
5294 71551183 : if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
5295 0 : ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
5296 0 : if (ret != LDB_SUCCESS) {
5297 0 : return ret;
5298 : }
5299 : }
5300 :
5301 71551183 : if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
5302 50 : ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
5303 50 : if (ret != LDB_SUCCESS) {
5304 0 : return ret;
5305 : }
5306 : }
5307 :
5308 71551183 : if (dsdb_flags & DSDB_FLAG_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE) {
5309 147 : ret = ldb_request_add_control(req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID, true, NULL);
5310 147 : if (ret != LDB_SUCCESS) {
5311 0 : return ret;
5312 : }
5313 : }
5314 :
5315 71551183 : if (dsdb_flags & DSDB_MARK_REQ_UNTRUSTED) {
5316 5645 : ldb_req_mark_untrusted(req);
5317 : }
5318 :
5319 68295206 : return LDB_SUCCESS;
5320 : }
5321 :
5322 : /*
5323 : returns true if a control with the specified "oid" exists
5324 : */
5325 89295531 : bool dsdb_request_has_control(struct ldb_request *req, const char *oid)
5326 : {
5327 89295531 : return (ldb_request_get_control(req, oid) != NULL);
5328 : }
5329 :
5330 : /*
5331 : an add with a set of controls
5332 : */
5333 101 : int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
5334 : uint32_t dsdb_flags)
5335 : {
5336 22 : struct ldb_request *req;
5337 22 : int ret;
5338 :
5339 101 : ret = ldb_build_add_req(&req, ldb, ldb,
5340 : message,
5341 : NULL,
5342 : NULL,
5343 : ldb_op_default_callback,
5344 : NULL);
5345 :
5346 101 : if (ret != LDB_SUCCESS) return ret;
5347 :
5348 101 : ret = dsdb_request_add_controls(req, dsdb_flags);
5349 101 : if (ret != LDB_SUCCESS) {
5350 0 : talloc_free(req);
5351 0 : return ret;
5352 : }
5353 :
5354 101 : ret = dsdb_autotransaction_request(ldb, req);
5355 :
5356 101 : talloc_free(req);
5357 101 : return ret;
5358 : }
5359 :
5360 : /*
5361 : a modify with a set of controls
5362 : */
5363 15427 : int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
5364 : uint32_t dsdb_flags)
5365 : {
5366 229 : struct ldb_request *req;
5367 229 : int ret;
5368 :
5369 15427 : ret = ldb_build_mod_req(&req, ldb, ldb,
5370 : message,
5371 : NULL,
5372 : NULL,
5373 : ldb_op_default_callback,
5374 : NULL);
5375 :
5376 15427 : if (ret != LDB_SUCCESS) return ret;
5377 :
5378 15427 : ret = dsdb_request_add_controls(req, dsdb_flags);
5379 15427 : if (ret != LDB_SUCCESS) {
5380 0 : talloc_free(req);
5381 0 : return ret;
5382 : }
5383 :
5384 15427 : ret = dsdb_autotransaction_request(ldb, req);
5385 :
5386 15427 : talloc_free(req);
5387 15427 : return ret;
5388 : }
5389 :
5390 : /*
5391 : a delete with a set of flags
5392 : */
5393 437 : int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
5394 : uint32_t dsdb_flags)
5395 : {
5396 7 : struct ldb_request *req;
5397 7 : int ret;
5398 :
5399 437 : ret = ldb_build_del_req(&req, ldb, ldb,
5400 : dn,
5401 : NULL,
5402 : NULL,
5403 : ldb_op_default_callback,
5404 : NULL);
5405 :
5406 437 : if (ret != LDB_SUCCESS) return ret;
5407 :
5408 437 : ret = dsdb_request_add_controls(req, dsdb_flags);
5409 437 : if (ret != LDB_SUCCESS) {
5410 0 : talloc_free(req);
5411 0 : return ret;
5412 : }
5413 :
5414 437 : ret = dsdb_autotransaction_request(ldb, req);
5415 :
5416 437 : talloc_free(req);
5417 437 : return ret;
5418 : }
5419 :
5420 : /*
5421 : like dsdb_modify() but set all the element flags to
5422 : LDB_FLAG_MOD_REPLACE
5423 : */
5424 3096 : int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
5425 : {
5426 205 : unsigned int i;
5427 :
5428 : /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
5429 10218 : for (i=0;i<msg->num_elements;i++) {
5430 7122 : msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5431 : }
5432 :
5433 3096 : return dsdb_modify(ldb, msg, dsdb_flags);
5434 : }
5435 :
5436 341231 : const char *dsdb_search_scope_as_string(enum ldb_scope scope)
5437 : {
5438 249 : const char *scope_str;
5439 :
5440 341231 : switch (scope) {
5441 173098 : case LDB_SCOPE_BASE:
5442 173098 : scope_str = "BASE";
5443 173098 : break;
5444 78321 : case LDB_SCOPE_ONELEVEL:
5445 78321 : scope_str = "ONE";
5446 78321 : break;
5447 89575 : case LDB_SCOPE_SUBTREE:
5448 89575 : scope_str = "SUB";
5449 89575 : break;
5450 0 : default:
5451 0 : scope_str = "<Invalid scope>";
5452 0 : break;
5453 : }
5454 341231 : return scope_str;
5455 : }
5456 :
5457 :
5458 : /*
5459 : search for attrs on one DN, allowing for dsdb_flags controls
5460 : */
5461 2391658 : int dsdb_search_dn(struct ldb_context *ldb,
5462 : TALLOC_CTX *mem_ctx,
5463 : struct ldb_result **_result,
5464 : struct ldb_dn *basedn,
5465 : const char * const *attrs,
5466 : uint32_t dsdb_flags)
5467 : {
5468 114952 : int ret;
5469 114952 : struct ldb_request *req;
5470 114952 : struct ldb_result *res;
5471 2391658 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5472 :
5473 2391658 : if (tmp_ctx == NULL) {
5474 0 : return ldb_oom(ldb);
5475 : }
5476 :
5477 2391658 : res = talloc_zero(tmp_ctx, struct ldb_result);
5478 2391658 : if (!res) {
5479 0 : talloc_free(tmp_ctx);
5480 0 : return ldb_oom(ldb);
5481 : }
5482 :
5483 2391658 : ret = ldb_build_search_req(&req, ldb, res,
5484 : basedn,
5485 : LDB_SCOPE_BASE,
5486 : NULL,
5487 : attrs,
5488 : NULL,
5489 : res,
5490 : ldb_search_default_callback,
5491 : NULL);
5492 2391658 : if (ret != LDB_SUCCESS) {
5493 0 : talloc_free(tmp_ctx);
5494 0 : return ret;
5495 : }
5496 :
5497 2391658 : ret = dsdb_request_add_controls(req, dsdb_flags);
5498 2391658 : if (ret != LDB_SUCCESS) {
5499 0 : talloc_free(tmp_ctx);
5500 0 : return ret;
5501 : }
5502 :
5503 2391658 : ret = ldb_request(ldb, req);
5504 2391658 : if (ret == LDB_SUCCESS) {
5505 2391658 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
5506 : }
5507 :
5508 2391658 : talloc_free(req);
5509 2391658 : if (ret != LDB_SUCCESS) {
5510 793084 : DBG_INFO("flags=0x%08x %s -> %s (%s)\n",
5511 : dsdb_flags,
5512 : basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5513 : basedn,
5514 : 1):"NULL",
5515 : ldb_errstring(ldb), ldb_strerror(ret));
5516 793084 : talloc_free(tmp_ctx);
5517 793084 : return ret;
5518 : }
5519 :
5520 1598574 : DBG_DEBUG("flags=0x%08x %s -> %d\n",
5521 : dsdb_flags,
5522 : basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5523 : basedn,
5524 : 1):"NULL",
5525 : res->count);
5526 :
5527 1598574 : *_result = talloc_steal(mem_ctx, res);
5528 :
5529 1598574 : talloc_free(tmp_ctx);
5530 1598574 : return LDB_SUCCESS;
5531 : }
5532 :
5533 : /*
5534 : search for attrs on one DN, by the GUID of the DN, allowing for
5535 : dsdb_flags controls
5536 : */
5537 3570 : int dsdb_search_by_dn_guid(struct ldb_context *ldb,
5538 : TALLOC_CTX *mem_ctx,
5539 : struct ldb_result **_result,
5540 : const struct GUID *guid,
5541 : const char * const *attrs,
5542 : uint32_t dsdb_flags)
5543 : {
5544 3570 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5545 0 : struct ldb_dn *dn;
5546 0 : int ret;
5547 :
5548 3570 : if (tmp_ctx == NULL) {
5549 0 : return ldb_oom(ldb);
5550 : }
5551 :
5552 3570 : dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
5553 3570 : if (dn == NULL) {
5554 0 : talloc_free(tmp_ctx);
5555 0 : return ldb_oom(ldb);
5556 : }
5557 :
5558 3570 : ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
5559 3570 : talloc_free(tmp_ctx);
5560 3570 : return ret;
5561 : }
5562 :
5563 45 : NTSTATUS gmsa_system_password_update_request(
5564 : struct ldb_context *ldb,
5565 : TALLOC_CTX *mem_ctx,
5566 : struct ldb_dn *dn,
5567 : const uint8_t
5568 : password_buf[static const GMSA_PASSWORD_NULL_TERMINATED_LEN],
5569 : struct ldb_request **request_out)
5570 : {
5571 45 : DATA_BLOB password_blob = {};
5572 45 : struct ldb_request *request = NULL;
5573 0 : NTSTATUS status;
5574 0 : int ret;
5575 :
5576 45 : dn = ldb_dn_copy(mem_ctx, dn);
5577 45 : if (dn == NULL) {
5578 0 : return NT_STATUS_INTERNAL_ERROR;
5579 : }
5580 :
5581 : /* Make a copy of the password. */
5582 45 : password_blob = data_blob_talloc(mem_ctx,
5583 : password_buf,
5584 : GMSA_PASSWORD_LEN);
5585 45 : if (password_blob.data == NULL) {
5586 0 : talloc_free(dn);
5587 0 : return NT_STATUS_NO_MEMORY;
5588 : }
5589 :
5590 45 : status = samdb_set_password_request(ldb,
5591 : mem_ctx,
5592 : dn,
5593 : &password_blob,
5594 : NULL,
5595 : DSDB_PASSWORD_RESET,
5596 : false /* reject trusts */,
5597 : &request);
5598 45 : if (!NT_STATUS_IS_OK(status)) {
5599 0 : data_blob_free(&password_blob);
5600 0 : talloc_free(dn);
5601 0 : return status;
5602 : }
5603 :
5604 : /* Tie the lifetime of the password to that of the request. */
5605 45 : talloc_steal(request, password_blob.data);
5606 :
5607 : /* Tie the lifetime of the DN to that of the request. */
5608 45 : talloc_steal(request, dn);
5609 :
5610 : /* Make sure the password update happens as System. */
5611 45 : ret = dsdb_request_add_controls(request, DSDB_FLAG_AS_SYSTEM);
5612 45 : if (ret) {
5613 0 : talloc_free(request);
5614 0 : return NT_STATUS_NO_MEMORY;
5615 : }
5616 :
5617 45 : *request_out = request;
5618 45 : return NT_STATUS_OK;
5619 : }
5620 :
5621 : /*
5622 : general search with dsdb_flags for controls
5623 : */
5624 3384738 : int dsdb_search(struct ldb_context *ldb,
5625 : TALLOC_CTX *mem_ctx,
5626 : struct ldb_result **_result,
5627 : struct ldb_dn *basedn,
5628 : enum ldb_scope scope,
5629 : const char * const *attrs,
5630 : uint32_t dsdb_flags,
5631 : const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
5632 : {
5633 123122 : int ret;
5634 123122 : struct ldb_request *req;
5635 123122 : struct ldb_result *res;
5636 123122 : va_list ap;
5637 3384738 : char *expression = NULL;
5638 3384738 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5639 123122 : int tries;
5640 3384738 : const int max_tries = 5;
5641 :
5642 : /* cross-partitions searches with a basedn break multi-domain support */
5643 3384738 : SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
5644 :
5645 3384738 : if (tmp_ctx == NULL) {
5646 0 : return ldb_oom(ldb);
5647 : }
5648 :
5649 3384738 : res = talloc(tmp_ctx, struct ldb_result);
5650 3384738 : if (!res) {
5651 0 : talloc_free(tmp_ctx);
5652 0 : return ldb_oom(ldb);
5653 : }
5654 :
5655 3384738 : if (exp_fmt) {
5656 3041501 : va_start(ap, exp_fmt);
5657 3041501 : expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
5658 3041501 : va_end(ap);
5659 :
5660 3041501 : if (!expression) {
5661 0 : talloc_free(tmp_ctx);
5662 0 : return ldb_oom(ldb);
5663 : }
5664 : }
5665 :
5666 3384759 : for (tries = 0; tries < max_tries; ++tries) {
5667 3384759 : bool retry = true;
5668 :
5669 3384759 : *res = (struct ldb_result){};
5670 :
5671 3384759 : ret = ldb_build_search_req(&req, ldb, tmp_ctx,
5672 : basedn,
5673 : scope,
5674 : expression,
5675 : attrs,
5676 : NULL,
5677 : res,
5678 : ldb_search_default_callback,
5679 : NULL);
5680 3384759 : if (ret != LDB_SUCCESS) {
5681 0 : talloc_free(tmp_ctx);
5682 257604 : return ret;
5683 : }
5684 :
5685 3384759 : ret = dsdb_request_add_controls(req, dsdb_flags);
5686 3384759 : if (ret != LDB_SUCCESS) {
5687 0 : talloc_free(tmp_ctx);
5688 0 : ldb_reset_err_string(ldb);
5689 0 : return ret;
5690 : }
5691 :
5692 3384759 : ret = ldb_request(ldb, req);
5693 3384759 : if (ret == LDB_SUCCESS) {
5694 3384759 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
5695 : }
5696 :
5697 3384759 : if (ret != LDB_SUCCESS) {
5698 647 : DBG_INFO("%s flags=0x%08x %s %s -> %s (%s)\n",
5699 : dsdb_search_scope_as_string(scope),
5700 : dsdb_flags,
5701 : basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5702 : basedn,
5703 : 1):"NULL",
5704 : expression?expression:"NULL",
5705 : ldb_errstring(ldb), ldb_strerror(ret));
5706 647 : talloc_free(tmp_ctx);
5707 647 : return ret;
5708 : }
5709 :
5710 3384112 : if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
5711 1108311 : if (res->count == 0) {
5712 256957 : DBG_INFO("%s SEARCH_ONE_ONLY flags=0x%08x %s %s -> %u results\n",
5713 : dsdb_search_scope_as_string(scope),
5714 : dsdb_flags,
5715 : basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5716 : basedn,
5717 : 1):"NULL",
5718 : expression?expression:"NULL", res->count);
5719 256957 : talloc_free(tmp_ctx);
5720 256957 : ldb_reset_err_string(ldb);
5721 256957 : return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
5722 : }
5723 851354 : if (res->count != 1) {
5724 0 : DBG_INFO("%s SEARCH_ONE_ONLY flags=0x%08x %s %s -> %u (expected 1) results\n",
5725 : dsdb_search_scope_as_string(scope),
5726 : dsdb_flags,
5727 : basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5728 : basedn,
5729 : 1):"NULL",
5730 : expression?expression:"NULL", res->count);
5731 0 : talloc_free(tmp_ctx);
5732 0 : ldb_reset_err_string(ldb);
5733 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
5734 : }
5735 : }
5736 :
5737 3127155 : if (!(dsdb_flags & DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS)) {
5738 3017090 : break;
5739 : }
5740 :
5741 : /*
5742 : * If we’re searching for passwords, we must account for the
5743 : * possibility that one or more of the accounts are Group
5744 : * Managed Service Accounts with out‐of‐date keys. In such a
5745 : * case, we must derive the new password(s), update the keys,
5746 : * and perform the search again to get the updated results.
5747 : *
5748 : * The following attributes are necessary in order for this to
5749 : * work properly:
5750 : *
5751 : * • msDS-ManagedPasswordId
5752 : * • msDS-ManagedPasswordInterval
5753 : * • objectClass
5754 : * • objectSid
5755 : * • whenCreated
5756 : */
5757 :
5758 342390 : ret = dsdb_update_gmsa_keys(ldb, tmp_ctx, res, &retry);
5759 342390 : if (ret) {
5760 0 : talloc_free(tmp_ctx);
5761 0 : return ret;
5762 : }
5763 342390 : if (!retry) {
5764 330165 : break;
5765 : }
5766 : }
5767 3127134 : if (tries == max_tries) {
5768 0 : talloc_free(tmp_ctx);
5769 0 : ldb_reset_err_string(ldb);
5770 0 : return ldb_operr(ldb);
5771 : }
5772 :
5773 3127134 : *_result = talloc_steal(mem_ctx, res);
5774 :
5775 3127134 : DBG_DEBUG("%s flags=0x%08x %s %s -> %d\n",
5776 : dsdb_search_scope_as_string(scope),
5777 : dsdb_flags,
5778 : basedn?ldb_dn_get_extended_linearized(tmp_ctx,
5779 : basedn,
5780 : 1):"NULL",
5781 : expression?expression:"NULL",
5782 : res->count);
5783 3127134 : talloc_free(tmp_ctx);
5784 3127134 : return LDB_SUCCESS;
5785 : }
5786 :
5787 :
5788 : /*
5789 : general search with dsdb_flags for controls
5790 : returns exactly 1 record or an error
5791 : */
5792 813019 : int dsdb_search_one(struct ldb_context *ldb,
5793 : TALLOC_CTX *mem_ctx,
5794 : struct ldb_message **msg,
5795 : struct ldb_dn *basedn,
5796 : enum ldb_scope scope,
5797 : const char * const *attrs,
5798 : uint32_t dsdb_flags,
5799 : const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
5800 : {
5801 33014 : int ret;
5802 33014 : struct ldb_result *res;
5803 33014 : va_list ap;
5804 813019 : char *expression = NULL;
5805 813019 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
5806 :
5807 813019 : if (tmp_ctx == NULL) {
5808 0 : return ldb_oom(ldb);
5809 : }
5810 :
5811 813019 : dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
5812 :
5813 813019 : res = talloc_zero(tmp_ctx, struct ldb_result);
5814 813019 : if (!res) {
5815 0 : talloc_free(tmp_ctx);
5816 0 : return ldb_oom(ldb);
5817 : }
5818 :
5819 813019 : if (exp_fmt) {
5820 694322 : va_start(ap, exp_fmt);
5821 694322 : expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
5822 694322 : va_end(ap);
5823 :
5824 694322 : if (!expression) {
5825 0 : talloc_free(tmp_ctx);
5826 0 : return ldb_oom(ldb);
5827 : }
5828 694322 : ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
5829 : dsdb_flags, "%s", expression);
5830 : } else {
5831 118697 : ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
5832 : dsdb_flags, NULL);
5833 : }
5834 :
5835 813019 : if (ret != LDB_SUCCESS) {
5836 257507 : talloc_free(tmp_ctx);
5837 257507 : return ret;
5838 : }
5839 :
5840 555512 : *msg = talloc_steal(mem_ctx, res->msgs[0]);
5841 555512 : talloc_free(tmp_ctx);
5842 :
5843 555512 : return LDB_SUCCESS;
5844 : }
5845 :
5846 : /* returns back the forest DNS name */
5847 4855 : const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
5848 : {
5849 4855 : const char *forest_name = ldb_dn_canonical_string(mem_ctx,
5850 : ldb_get_root_basedn(ldb));
5851 68 : char *p;
5852 :
5853 4855 : if (forest_name == NULL) {
5854 0 : return NULL;
5855 : }
5856 :
5857 4855 : p = strchr(forest_name, '/');
5858 4855 : if (p) {
5859 4855 : *p = '\0';
5860 : }
5861 :
5862 4787 : return forest_name;
5863 : }
5864 :
5865 : /* returns back the default domain DNS name */
5866 675 : const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
5867 : {
5868 675 : const char *domain_name = ldb_dn_canonical_string(mem_ctx,
5869 : ldb_get_default_basedn(ldb));
5870 0 : char *p;
5871 :
5872 675 : if (domain_name == NULL) {
5873 0 : return NULL;
5874 : }
5875 :
5876 675 : p = strchr(domain_name, '/');
5877 675 : if (p) {
5878 675 : *p = '\0';
5879 : }
5880 :
5881 675 : return domain_name;
5882 : }
5883 :
5884 : /*
5885 : validate that an DSA GUID belongs to the specified user sid.
5886 : The user SID must be a domain controller account (either RODC or
5887 : RWDC)
5888 : */
5889 1482 : int dsdb_validate_dsa_guid(struct ldb_context *ldb,
5890 : const struct GUID *dsa_guid,
5891 : const struct dom_sid *sid)
5892 : {
5893 : /* strategy:
5894 : - find DN of record with the DSA GUID in the
5895 : configuration partition (objectGUID)
5896 : - remove "NTDS Settings" component from DN
5897 : - do a base search on that DN for serverReference with
5898 : extended-dn enabled
5899 : - extract objectSid from resulting serverReference
5900 : attribute
5901 : - check this sid matches the sid argument
5902 : */
5903 0 : struct ldb_dn *config_dn;
5904 1482 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
5905 0 : struct ldb_message *msg;
5906 1482 : const char *attrs1[] = { NULL };
5907 1482 : const char *attrs2[] = { "serverReference", NULL };
5908 0 : int ret;
5909 0 : struct ldb_dn *dn, *account_dn;
5910 0 : struct dom_sid sid2;
5911 0 : NTSTATUS status;
5912 :
5913 1482 : if (tmp_ctx == NULL) {
5914 0 : return ldb_oom(ldb);
5915 : }
5916 :
5917 1482 : config_dn = ldb_get_config_basedn(ldb);
5918 :
5919 1482 : ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
5920 : attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
5921 1482 : if (ret != LDB_SUCCESS) {
5922 0 : DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
5923 : GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
5924 0 : talloc_free(tmp_ctx);
5925 0 : return ldb_operr(ldb);
5926 : }
5927 1482 : dn = msg->dn;
5928 :
5929 1482 : if (!ldb_dn_remove_child_components(dn, 1)) {
5930 0 : talloc_free(tmp_ctx);
5931 0 : return ldb_operr(ldb);
5932 : }
5933 :
5934 1482 : ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
5935 : attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
5936 : "(objectClass=server)");
5937 1482 : if (ret != LDB_SUCCESS) {
5938 0 : DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
5939 : GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
5940 0 : talloc_free(tmp_ctx);
5941 0 : return ldb_operr(ldb);
5942 : }
5943 :
5944 1482 : account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
5945 1482 : if (account_dn == NULL) {
5946 0 : DEBUG(1,(__location__ ": Failed to find account dn "
5947 : "(serverReference) for %s, parent of DSA with "
5948 : "objectGUID %s, sid %s\n",
5949 : ldb_dn_get_linearized(msg->dn),
5950 : GUID_string(tmp_ctx, dsa_guid),
5951 : dom_sid_string(tmp_ctx, sid)));
5952 0 : talloc_free(tmp_ctx);
5953 0 : return ldb_operr(ldb);
5954 : }
5955 :
5956 1482 : status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
5957 1482 : if (!NT_STATUS_IS_OK(status)) {
5958 0 : DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
5959 : GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
5960 0 : talloc_free(tmp_ctx);
5961 0 : return ldb_operr(ldb);
5962 : }
5963 :
5964 1482 : if (!dom_sid_equal(sid, &sid2)) {
5965 : /* someone is trying to spoof another account */
5966 0 : DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
5967 : GUID_string(tmp_ctx, dsa_guid),
5968 : dom_sid_string(tmp_ctx, sid),
5969 : dom_sid_string(tmp_ctx, &sid2)));
5970 0 : talloc_free(tmp_ctx);
5971 0 : return ldb_operr(ldb);
5972 : }
5973 :
5974 1482 : talloc_free(tmp_ctx);
5975 1482 : return LDB_SUCCESS;
5976 : }
5977 :
5978 : static const char * const secret_attributes[] = {
5979 : DSDB_SECRET_ATTRIBUTES,
5980 : NULL
5981 : };
5982 :
5983 : /*
5984 : check if the attribute belongs to the RODC filtered attribute set
5985 : Note that attributes that are in the filtered attribute set are the
5986 : ones that _are_ always sent to a RODC
5987 : */
5988 68861 : bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
5989 : {
5990 : /* they never get secret attributes */
5991 68861 : if (ldb_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
5992 15349 : return false;
5993 : }
5994 :
5995 : /* they do get non-secret critical attributes */
5996 53512 : if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
5997 53275 : return true;
5998 : }
5999 :
6000 : /* they do get non-secret attributes marked as being in the FAS */
6001 237 : if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
6002 0 : return true;
6003 : }
6004 :
6005 : /* other attributes are denied */
6006 237 : return false;
6007 : }
6008 :
6009 : /* return fsmo role dn and role owner dn for a particular role*/
6010 56 : WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
6011 : struct ldb_context *ldb,
6012 : uint32_t role,
6013 : struct ldb_dn **fsmo_role_dn,
6014 : struct ldb_dn **role_owner_dn)
6015 : {
6016 0 : int ret;
6017 56 : switch (role) {
6018 4 : case DREPL_NAMING_MASTER:
6019 4 : *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
6020 4 : ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
6021 4 : if (ret != LDB_SUCCESS) {
6022 0 : DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s\n",
6023 : ldb_errstring(ldb)));
6024 0 : talloc_free(tmp_ctx);
6025 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6026 : }
6027 4 : break;
6028 4 : case DREPL_INFRASTRUCTURE_MASTER:
6029 4 : *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
6030 4 : ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
6031 4 : if (ret != LDB_SUCCESS) {
6032 0 : DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s\n",
6033 : ldb_errstring(ldb)));
6034 0 : talloc_free(tmp_ctx);
6035 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6036 : }
6037 4 : break;
6038 6 : case DREPL_RID_MASTER:
6039 6 : ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
6040 6 : if (ret != LDB_SUCCESS) {
6041 0 : DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
6042 0 : talloc_free(tmp_ctx);
6043 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6044 : }
6045 :
6046 6 : ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
6047 6 : if (ret != LDB_SUCCESS) {
6048 0 : DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s\n",
6049 : ldb_errstring(ldb)));
6050 0 : talloc_free(tmp_ctx);
6051 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6052 : }
6053 6 : break;
6054 4 : case DREPL_SCHEMA_MASTER:
6055 4 : *fsmo_role_dn = ldb_get_schema_basedn(ldb);
6056 4 : ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
6057 4 : if (ret != LDB_SUCCESS) {
6058 0 : DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s\n",
6059 : ldb_errstring(ldb)));
6060 0 : talloc_free(tmp_ctx);
6061 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6062 : }
6063 4 : break;
6064 38 : case DREPL_PDC_MASTER:
6065 38 : *fsmo_role_dn = ldb_get_default_basedn(ldb);
6066 38 : ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
6067 38 : if (ret != LDB_SUCCESS) {
6068 0 : DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s\n",
6069 : ldb_errstring(ldb)));
6070 0 : talloc_free(tmp_ctx);
6071 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6072 : }
6073 38 : break;
6074 0 : default:
6075 0 : return WERR_DS_DRA_INTERNAL_ERROR;
6076 : }
6077 56 : return WERR_OK;
6078 : }
6079 :
6080 34 : const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
6081 : TALLOC_CTX *mem_ctx,
6082 : struct ldb_dn *server_dn)
6083 : {
6084 0 : int ldb_ret;
6085 34 : struct ldb_result *res = NULL;
6086 34 : const char * const attrs[] = { "dNSHostName", NULL};
6087 :
6088 34 : ldb_ret = ldb_search(ldb, mem_ctx, &res,
6089 : server_dn,
6090 : LDB_SCOPE_BASE,
6091 : attrs, NULL);
6092 34 : if (ldb_ret != LDB_SUCCESS) {
6093 0 : DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s\n",
6094 : ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
6095 0 : return NULL;
6096 : }
6097 :
6098 34 : return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
6099 : }
6100 :
6101 : /*
6102 : returns true if an attribute is in the filter,
6103 : false otherwise, provided that attribute value is provided with the expression
6104 : */
6105 0 : bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
6106 : const char *attr)
6107 : {
6108 0 : unsigned int i;
6109 0 : switch (tree->operation) {
6110 0 : case LDB_OP_AND:
6111 : case LDB_OP_OR:
6112 0 : for (i=0;i<tree->u.list.num_elements;i++) {
6113 0 : if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
6114 : attr))
6115 0 : return true;
6116 : }
6117 0 : return false;
6118 0 : case LDB_OP_NOT:
6119 0 : return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
6120 0 : case LDB_OP_EQUALITY:
6121 0 : if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
6122 0 : return true;
6123 : }
6124 0 : return false;
6125 0 : case LDB_OP_GREATER:
6126 : case LDB_OP_LESS:
6127 : case LDB_OP_APPROX:
6128 0 : if (ldb_attr_cmp(tree->u.comparison.attr, attr) == 0) {
6129 0 : return true;
6130 : }
6131 0 : return false;
6132 0 : case LDB_OP_SUBSTRING:
6133 0 : if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
6134 0 : return true;
6135 : }
6136 0 : return false;
6137 0 : case LDB_OP_PRESENT:
6138 : /* (attrname=*) is not filtered out */
6139 0 : return false;
6140 0 : case LDB_OP_EXTENDED:
6141 0 : if (tree->u.extended.attr &&
6142 0 : ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
6143 0 : return true;
6144 : }
6145 0 : return false;
6146 : }
6147 0 : return false;
6148 : }
6149 :
6150 1571 : int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
6151 : const char *location, const char *func,
6152 : const char *reason)
6153 : {
6154 1571 : if (reason == NULL) {
6155 0 : reason = win_errstr(werr);
6156 : }
6157 1571 : ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
6158 : W_ERROR_V(werr), reason, location, func);
6159 1571 : return ldb_ecode;
6160 : }
6161 :
6162 : /*
6163 : map an ldb error code to an approximate NTSTATUS code
6164 : */
6165 43 : NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
6166 : {
6167 43 : switch (err) {
6168 14 : case LDB_SUCCESS:
6169 43 : return NT_STATUS_OK;
6170 :
6171 0 : case LDB_ERR_PROTOCOL_ERROR:
6172 0 : return NT_STATUS_DEVICE_PROTOCOL_ERROR;
6173 :
6174 0 : case LDB_ERR_TIME_LIMIT_EXCEEDED:
6175 0 : return NT_STATUS_IO_TIMEOUT;
6176 :
6177 0 : case LDB_ERR_SIZE_LIMIT_EXCEEDED:
6178 0 : return NT_STATUS_BUFFER_TOO_SMALL;
6179 :
6180 0 : case LDB_ERR_COMPARE_FALSE:
6181 : case LDB_ERR_COMPARE_TRUE:
6182 0 : return NT_STATUS_REVISION_MISMATCH;
6183 :
6184 0 : case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
6185 0 : return NT_STATUS_NOT_SUPPORTED;
6186 :
6187 20 : case LDB_ERR_STRONG_AUTH_REQUIRED:
6188 : case LDB_ERR_CONFIDENTIALITY_REQUIRED:
6189 : case LDB_ERR_SASL_BIND_IN_PROGRESS:
6190 : case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
6191 : case LDB_ERR_INVALID_CREDENTIALS:
6192 : case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
6193 : case LDB_ERR_UNWILLING_TO_PERFORM:
6194 20 : return NT_STATUS_ACCESS_DENIED;
6195 :
6196 9 : case LDB_ERR_NO_SUCH_OBJECT:
6197 9 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6198 :
6199 0 : case LDB_ERR_REFERRAL:
6200 : case LDB_ERR_NO_SUCH_ATTRIBUTE:
6201 0 : return NT_STATUS_NOT_FOUND;
6202 :
6203 0 : case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
6204 0 : return NT_STATUS_NOT_SUPPORTED;
6205 :
6206 0 : case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
6207 0 : return NT_STATUS_BUFFER_TOO_SMALL;
6208 :
6209 0 : case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
6210 : case LDB_ERR_INAPPROPRIATE_MATCHING:
6211 : case LDB_ERR_CONSTRAINT_VIOLATION:
6212 : case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
6213 : case LDB_ERR_INVALID_DN_SYNTAX:
6214 : case LDB_ERR_NAMING_VIOLATION:
6215 : case LDB_ERR_OBJECT_CLASS_VIOLATION:
6216 : case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
6217 : case LDB_ERR_NOT_ALLOWED_ON_RDN:
6218 0 : return NT_STATUS_INVALID_PARAMETER;
6219 :
6220 0 : case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
6221 : case LDB_ERR_ENTRY_ALREADY_EXISTS:
6222 0 : return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
6223 :
6224 0 : case LDB_ERR_BUSY:
6225 0 : return NT_STATUS_NETWORK_BUSY;
6226 :
6227 0 : case LDB_ERR_ALIAS_PROBLEM:
6228 : case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
6229 : case LDB_ERR_UNAVAILABLE:
6230 : case LDB_ERR_LOOP_DETECT:
6231 : case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
6232 : case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
6233 : case LDB_ERR_OTHER:
6234 : case LDB_ERR_OPERATIONS_ERROR:
6235 0 : break;
6236 : }
6237 0 : return NT_STATUS_UNSUCCESSFUL;
6238 : }
6239 :
6240 :
6241 : /*
6242 : create a new naming context that will hold a partial replica
6243 : */
6244 0 : int dsdb_create_partial_replica_NC(struct ldb_context *ldb, struct ldb_dn *dn)
6245 : {
6246 0 : TALLOC_CTX *tmp_ctx = talloc_new(ldb);
6247 0 : struct ldb_message *msg;
6248 0 : int ret;
6249 :
6250 0 : if (tmp_ctx == NULL) {
6251 0 : return ldb_oom(ldb);
6252 : }
6253 :
6254 0 : msg = ldb_msg_new(tmp_ctx);
6255 0 : if (msg == NULL) {
6256 0 : talloc_free(tmp_ctx);
6257 0 : return ldb_oom(ldb);
6258 : }
6259 :
6260 0 : msg->dn = dn;
6261 0 : ret = ldb_msg_add_string(msg, "objectClass", "top");
6262 0 : if (ret != LDB_SUCCESS) {
6263 0 : talloc_free(tmp_ctx);
6264 0 : return ldb_oom(ldb);
6265 : }
6266 :
6267 : /* [MS-DRSR] implies that we should only add the 'top'
6268 : * objectclass, but that would cause lots of problems with our
6269 : * objectclass code as top is not structural, so we add
6270 : * 'domainDNS' as well to keep things sane. We're expecting
6271 : * this new NC to be of objectclass domainDNS after
6272 : * replication anyway
6273 : */
6274 0 : ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
6275 0 : if (ret != LDB_SUCCESS) {
6276 0 : talloc_free(tmp_ctx);
6277 0 : return ldb_oom(ldb);
6278 : }
6279 :
6280 0 : ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
6281 : INSTANCE_TYPE_IS_NC_HEAD|
6282 : INSTANCE_TYPE_NC_ABOVE|
6283 : INSTANCE_TYPE_UNINSTANT);
6284 0 : if (ret != LDB_SUCCESS) {
6285 0 : talloc_free(tmp_ctx);
6286 0 : return ldb_oom(ldb);
6287 : }
6288 :
6289 0 : ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
6290 0 : if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
6291 0 : DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
6292 : ldb_dn_get_linearized(dn),
6293 : ldb_errstring(ldb), ldb_strerror(ret)));
6294 0 : talloc_free(tmp_ctx);
6295 0 : return ret;
6296 : }
6297 :
6298 0 : DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
6299 :
6300 0 : talloc_free(tmp_ctx);
6301 0 : return LDB_SUCCESS;
6302 : }
6303 :
6304 : /*
6305 : * Return the effective badPwdCount
6306 : *
6307 : * This requires that the user_msg have (if present):
6308 : * - badPasswordTime
6309 : * - badPwdCount
6310 : *
6311 : * This also requires that the domain_msg have (if present):
6312 : * - lockOutObservationWindow
6313 : */
6314 35798 : int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
6315 : int64_t lockOutObservationWindow,
6316 : NTTIME now)
6317 : {
6318 1411 : int64_t badPasswordTime;
6319 35798 : badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
6320 :
6321 35798 : if (badPasswordTime - lockOutObservationWindow >= now) {
6322 2003 : return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
6323 : } else {
6324 32384 : return 0;
6325 : }
6326 : }
6327 :
6328 : /*
6329 : * Returns a user's PSO, or NULL if none was found
6330 : */
6331 27572 : static struct ldb_result *lookup_user_pso(struct ldb_context *sam_ldb,
6332 : TALLOC_CTX *mem_ctx,
6333 : const struct ldb_message *user_msg,
6334 : const char * const *attrs)
6335 : {
6336 27572 : struct ldb_result *res = NULL;
6337 27572 : struct ldb_dn *pso_dn = NULL;
6338 1410 : int ret;
6339 :
6340 : /* if the user has a PSO that applies, then use the PSO's setting */
6341 27572 : pso_dn = ldb_msg_find_attr_as_dn(sam_ldb, mem_ctx, user_msg,
6342 : "msDS-ResultantPSO");
6343 :
6344 27572 : if (pso_dn != NULL) {
6345 :
6346 220 : ret = dsdb_search_dn(sam_ldb, mem_ctx, &res, pso_dn, attrs, 0);
6347 220 : if (ret != LDB_SUCCESS) {
6348 :
6349 : /*
6350 : * log the error. The caller should fallback to using
6351 : * the default domain password settings
6352 : */
6353 0 : DBG_ERR("Error retrieving msDS-ResultantPSO %s for %s\n",
6354 : ldb_dn_get_linearized(pso_dn),
6355 : ldb_dn_get_linearized(user_msg->dn));
6356 : }
6357 220 : talloc_free(pso_dn);
6358 : }
6359 27572 : return res;
6360 : }
6361 :
6362 : /*
6363 : * Return the msDS-LockoutObservationWindow for a user message
6364 : *
6365 : * This requires that the user_msg have (if present):
6366 : * - msDS-ResultantPSO
6367 : */
6368 27572 : int64_t samdb_result_msds_LockoutObservationWindow(
6369 : struct ldb_context *sam_ldb,
6370 : TALLOC_CTX *mem_ctx,
6371 : struct ldb_dn *domain_dn,
6372 : const struct ldb_message *user_msg)
6373 : {
6374 1410 : int64_t lockOutObservationWindow;
6375 27572 : struct ldb_result *res = NULL;
6376 27572 : const char *attrs[] = { "msDS-LockoutObservationWindow",
6377 : NULL };
6378 27572 : if (domain_dn == NULL) {
6379 0 : smb_panic("domain dn is NULL");
6380 : }
6381 27572 : res = lookup_user_pso(sam_ldb, mem_ctx, user_msg, attrs);
6382 :
6383 27572 : if (res != NULL) {
6384 0 : lockOutObservationWindow =
6385 220 : ldb_msg_find_attr_as_int64(res->msgs[0],
6386 : "msDS-LockoutObservationWindow",
6387 : DEFAULT_OBSERVATION_WINDOW);
6388 220 : talloc_free(res);
6389 : } else {
6390 :
6391 : /* no PSO was found, lookup the default domain setting */
6392 1410 : lockOutObservationWindow =
6393 27352 : samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
6394 : "lockOutObservationWindow", NULL);
6395 : }
6396 27572 : return lockOutObservationWindow;
6397 : }
6398 :
6399 : /*
6400 : * Return the effective badPwdCount
6401 : *
6402 : * This requires that the user_msg have (if present):
6403 : * - badPasswordTime
6404 : * - badPwdCount
6405 : * - msDS-ResultantPSO
6406 : */
6407 4703 : int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
6408 : TALLOC_CTX *mem_ctx,
6409 : struct ldb_dn *domain_dn,
6410 : const struct ldb_message *user_msg)
6411 : {
6412 4703 : struct timeval tv_now = timeval_current();
6413 4703 : NTTIME now = timeval_to_nttime(&tv_now);
6414 0 : int64_t lockOutObservationWindow =
6415 4703 : samdb_result_msds_LockoutObservationWindow(
6416 : sam_ldb, mem_ctx, domain_dn, user_msg);
6417 4703 : return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
6418 : }
6419 :
6420 : /*
6421 : * Returns the lockoutThreshold that applies. If a PSO is specified, then that
6422 : * setting is used over the domain defaults
6423 : */
6424 4018 : static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
6425 : struct ldb_message *pso_msg)
6426 : {
6427 4018 : if (pso_msg != NULL) {
6428 40 : return ldb_msg_find_attr_as_int(pso_msg,
6429 : "msDS-LockoutThreshold", 0);
6430 : } else {
6431 3978 : return ldb_msg_find_attr_as_int(domain_msg,
6432 : "lockoutThreshold", 0);
6433 : }
6434 : }
6435 :
6436 : /*
6437 : * Returns the lockOutObservationWindow that applies. If a PSO is specified,
6438 : * then that setting is used over the domain defaults
6439 : */
6440 762 : static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
6441 : struct ldb_message *pso_msg)
6442 : {
6443 762 : if (pso_msg != NULL) {
6444 40 : return ldb_msg_find_attr_as_int64(pso_msg,
6445 : "msDS-LockoutObservationWindow",
6446 : DEFAULT_OBSERVATION_WINDOW);
6447 : } else {
6448 722 : return ldb_msg_find_attr_as_int64(domain_msg,
6449 : "lockOutObservationWindow",
6450 : DEFAULT_OBSERVATION_WINDOW);
6451 : }
6452 : }
6453 :
6454 : /*
6455 : * Prepare an update to the badPwdCount and associated attributes.
6456 : *
6457 : * This requires that the user_msg have (if present):
6458 : * - objectSid
6459 : * - badPasswordTime
6460 : * - badPwdCount
6461 : *
6462 : * This also requires that the domain_msg have (if present):
6463 : * - pwdProperties
6464 : * - lockoutThreshold
6465 : * - lockOutObservationWindow
6466 : *
6467 : * This also requires that the pso_msg have (if present):
6468 : * - msDS-LockoutThreshold
6469 : * - msDS-LockoutObservationWindow
6470 : */
6471 4018 : NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
6472 : struct ldb_context *sam_ctx,
6473 : struct ldb_message *user_msg,
6474 : struct ldb_message *domain_msg,
6475 : struct ldb_message *pso_msg,
6476 : struct ldb_message **_mod_msg)
6477 : {
6478 1 : int ret, badPwdCount;
6479 1 : unsigned int i;
6480 1 : int64_t lockoutThreshold, lockOutObservationWindow;
6481 1 : struct dom_sid *sid;
6482 4018 : struct timeval tv_now = timeval_current();
6483 4018 : NTTIME now = timeval_to_nttime(&tv_now);
6484 1 : NTSTATUS status;
6485 4018 : uint32_t pwdProperties, rid = 0;
6486 1 : struct ldb_message *mod_msg;
6487 :
6488 4018 : sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
6489 :
6490 4018 : pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
6491 : "pwdProperties", -1);
6492 4018 : if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
6493 4018 : status = dom_sid_split_rid(NULL, sid, NULL, &rid);
6494 4018 : if (!NT_STATUS_IS_OK(status)) {
6495 : /*
6496 : * This can't happen anyway, but always try
6497 : * and update the badPwdCount on failure
6498 : */
6499 0 : rid = 0;
6500 : }
6501 : }
6502 4018 : TALLOC_FREE(sid);
6503 :
6504 : /*
6505 : * Work out if we are doing password lockout on the domain.
6506 : * Also, the built in administrator account is exempt:
6507 : * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
6508 : */
6509 4018 : lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
6510 4018 : if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
6511 3256 : DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
6512 : ldb_dn_get_linearized(user_msg->dn)));
6513 3256 : return NT_STATUS_OK;
6514 : }
6515 :
6516 762 : mod_msg = ldb_msg_new(mem_ctx);
6517 762 : if (mod_msg == NULL) {
6518 0 : return NT_STATUS_NO_MEMORY;
6519 : }
6520 762 : mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
6521 762 : if (mod_msg->dn == NULL) {
6522 0 : TALLOC_FREE(mod_msg);
6523 0 : return NT_STATUS_NO_MEMORY;
6524 : }
6525 :
6526 762 : lockOutObservationWindow = get_lockout_observation_window(domain_msg,
6527 : pso_msg);
6528 :
6529 762 : badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
6530 :
6531 762 : badPwdCount++;
6532 :
6533 762 : ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
6534 762 : if (ret != LDB_SUCCESS) {
6535 0 : TALLOC_FREE(mod_msg);
6536 0 : return NT_STATUS_NO_MEMORY;
6537 : }
6538 762 : ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
6539 762 : if (ret != LDB_SUCCESS) {
6540 0 : TALLOC_FREE(mod_msg);
6541 0 : return NT_STATUS_NO_MEMORY;
6542 : }
6543 :
6544 762 : if (dsdb_account_is_trust(user_msg)) {
6545 : /* Trust accounts cannot be locked out. */
6546 750 : } else if (badPwdCount >= lockoutThreshold) {
6547 110 : ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
6548 110 : if (ret != LDB_SUCCESS) {
6549 0 : TALLOC_FREE(mod_msg);
6550 0 : return NT_STATUS_NO_MEMORY;
6551 : }
6552 110 : DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
6553 : ldb_dn_get_linearized(user_msg->dn), badPwdCount));
6554 : } else {
6555 640 : DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
6556 : ldb_dn_get_linearized(user_msg->dn), badPwdCount));
6557 : }
6558 :
6559 : /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
6560 2396 : for (i=0; i< mod_msg->num_elements; i++) {
6561 1634 : mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6562 : }
6563 :
6564 762 : *_mod_msg = mod_msg;
6565 762 : return NT_STATUS_OK;
6566 : }
6567 :
6568 : /**
6569 : * Sets defaults for a User object
6570 : * List of default attributes set:
6571 : * accountExpires, badPasswordTime, badPwdCount,
6572 : * codePage, countryCode, lastLogoff, lastLogon
6573 : * logonCount, pwdLastSet
6574 : */
6575 30459 : int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
6576 : struct ldb_message *usr_obj,
6577 : struct ldb_request *req)
6578 : {
6579 221 : size_t i;
6580 221 : int ret;
6581 221 : static const struct attribute_values {
6582 : const char *name;
6583 : const char *value;
6584 : const char *add_value;
6585 : const char *mod_value;
6586 : const char *control;
6587 : unsigned add_flags;
6588 : unsigned mod_flags;
6589 : } map[] = {
6590 : {
6591 : .name = "accountExpires",
6592 : .add_value = "9223372036854775807",
6593 : .mod_value = "0",
6594 : },
6595 : {
6596 : .name = "badPasswordTime",
6597 : .value = "0"
6598 : },
6599 : {
6600 : .name = "badPwdCount",
6601 : .value = "0"
6602 : },
6603 : {
6604 : .name = "codePage",
6605 : .value = "0"
6606 : },
6607 : {
6608 : .name = "countryCode",
6609 : .value = "0"
6610 : },
6611 : {
6612 : .name = "lastLogoff",
6613 : .value = "0"
6614 : },
6615 : {
6616 : .name = "lastLogon",
6617 : .value = "0"
6618 : },
6619 : {
6620 : .name = "logonCount",
6621 : .value = "0"
6622 : },
6623 : {
6624 : .name = "logonHours",
6625 : .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
6626 : },
6627 : {
6628 : .name = "pwdLastSet",
6629 : .value = "0",
6630 : .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
6631 : },
6632 : {
6633 : .name = "adminCount",
6634 : .mod_value = "0",
6635 : },
6636 : {
6637 : .name = "operatorCount",
6638 : .mod_value = "0",
6639 : },
6640 : };
6641 :
6642 395967 : for (i = 0; i < ARRAY_SIZE(map); i++) {
6643 365508 : bool added = false;
6644 365508 : const char *value = NULL;
6645 365508 : unsigned flags = 0;
6646 :
6647 365508 : if (req != NULL && req->operation == LDB_ADD) {
6648 364788 : value = map[i].add_value;
6649 364788 : flags = map[i].add_flags;
6650 : } else {
6651 720 : value = map[i].mod_value;
6652 720 : flags = map[i].mod_flags;
6653 : }
6654 :
6655 365508 : if (value == NULL) {
6656 334929 : value = map[i].value;
6657 : }
6658 :
6659 365508 : if (value != NULL) {
6660 274251 : flags |= LDB_FLAG_MOD_ADD;
6661 : }
6662 :
6663 365508 : if (flags == 0) {
6664 60858 : continue;
6665 : }
6666 :
6667 306860 : ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
6668 304650 : map[i].name,
6669 : value, flags,
6670 : &added);
6671 304650 : if (ret != LDB_SUCCESS) {
6672 0 : return ret;
6673 : }
6674 :
6675 304650 : if (req != NULL && added && map[i].control != NULL) {
6676 30442 : ret = ldb_request_add_control(req,
6677 30221 : map[i].control,
6678 : false, NULL);
6679 30442 : if (ret != LDB_SUCCESS) {
6680 0 : return ret;
6681 : }
6682 : }
6683 : }
6684 :
6685 30238 : return LDB_SUCCESS;
6686 : }
6687 :
6688 : /**
6689 : * Sets 'sAMAccountType on user object based on userAccountControl.
6690 : * This function is used in processing both 'add' and 'modify' requests.
6691 : * @param ldb Current ldb_context
6692 : * @param usr_obj ldb_message representing User object
6693 : * @param user_account_control Value for userAccountControl flags
6694 : * @param account_type_p Optional pointer to account_type to return
6695 : * @return LDB_SUCCESS or LDB_ERR* code on failure
6696 : */
6697 30350 : int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
6698 : uint32_t user_account_control, uint32_t *account_type_p)
6699 : {
6700 221 : int ret;
6701 221 : uint32_t account_type;
6702 :
6703 30350 : account_type = ds_uf2atype(user_account_control);
6704 30350 : if (account_type == 0) {
6705 0 : ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
6706 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
6707 : }
6708 30350 : ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
6709 : "sAMAccountType",
6710 : account_type,
6711 : LDB_FLAG_MOD_REPLACE);
6712 30350 : if (ret != LDB_SUCCESS) {
6713 0 : return ret;
6714 : }
6715 :
6716 30350 : if (account_type_p) {
6717 0 : *account_type_p = account_type;
6718 : }
6719 :
6720 30129 : return LDB_SUCCESS;
6721 : }
6722 :
6723 : /**
6724 : * Determine and set primaryGroupID based on userAccountControl value.
6725 : * This function is used in processing both 'add' and 'modify' requests.
6726 : * @param ldb Current ldb_context
6727 : * @param usr_obj ldb_message representing User object
6728 : * @param user_account_control Value for userAccountControl flags
6729 : * @param group_rid_p Optional pointer to group RID to return
6730 : * @return LDB_SUCCESS or LDB_ERR* code on failure
6731 : */
6732 30222 : int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
6733 : uint32_t user_account_control, uint32_t *group_rid_p)
6734 : {
6735 199 : int ret;
6736 199 : uint32_t rid;
6737 :
6738 30222 : rid = ds_uf2prim_group_rid(user_account_control);
6739 :
6740 30222 : ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
6741 : "primaryGroupID", rid,
6742 : LDB_FLAG_MOD_REPLACE);
6743 30222 : if (ret != LDB_SUCCESS) {
6744 0 : return ret;
6745 : }
6746 :
6747 30222 : if (group_rid_p) {
6748 30222 : *group_rid_p = rid;
6749 : }
6750 :
6751 30023 : return LDB_SUCCESS;
6752 : }
6753 :
6754 : /**
6755 : * Returns True if the source and target DNs both have the same naming context,
6756 : * i.e. they're both in the same partition.
6757 : */
6758 3720 : bool dsdb_objects_have_same_nc(struct ldb_context *ldb,
6759 : TALLOC_CTX *mem_ctx,
6760 : struct ldb_dn *source_dn,
6761 : struct ldb_dn *target_dn)
6762 : {
6763 0 : TALLOC_CTX *tmp_ctx;
6764 3720 : struct ldb_dn *source_nc = NULL;
6765 3720 : struct ldb_dn *target_nc = NULL;
6766 0 : int ret;
6767 3720 : bool same_nc = true;
6768 :
6769 3720 : tmp_ctx = talloc_new(mem_ctx);
6770 3720 : if (tmp_ctx == NULL) {
6771 0 : return ldb_oom(ldb);
6772 : }
6773 :
6774 3720 : ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
6775 : /* fix clang warning */
6776 3720 : if (source_nc == NULL) {
6777 0 : ret = LDB_ERR_OTHER;
6778 : }
6779 3720 : if (ret != LDB_SUCCESS) {
6780 0 : DBG_ERR("Failed to find base DN for source %s: %s\n",
6781 : ldb_dn_get_linearized(source_dn), ldb_errstring(ldb));
6782 0 : talloc_free(tmp_ctx);
6783 0 : return true;
6784 : }
6785 :
6786 3720 : ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
6787 : /* fix clang warning */
6788 3720 : if (target_nc == NULL) {
6789 0 : ret = LDB_ERR_OTHER;
6790 : }
6791 3720 : if (ret != LDB_SUCCESS) {
6792 0 : DBG_ERR("Failed to find base DN for target %s: %s\n",
6793 : ldb_dn_get_linearized(target_dn), ldb_errstring(ldb));
6794 0 : talloc_free(tmp_ctx);
6795 0 : return true;
6796 : }
6797 :
6798 3720 : same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
6799 :
6800 3720 : talloc_free(tmp_ctx);
6801 :
6802 3720 : return same_nc;
6803 : }
6804 : /*
6805 : * Context for dsdb_count_domain_callback
6806 : */
6807 : struct dsdb_count_domain_context {
6808 : /*
6809 : * Number of matching records
6810 : */
6811 : size_t count;
6812 : /*
6813 : * sid of the domain that the records must belong to.
6814 : * if NULL records can belong to any domain.
6815 : */
6816 : struct dom_sid *dom_sid;
6817 : };
6818 :
6819 : /*
6820 : * @brief ldb async callback for dsdb_domain_count.
6821 : *
6822 : * count the number of records in the database matching an LDAP query,
6823 : * optionally filtering for domain membership.
6824 : *
6825 : * @param [in,out] req the ldb request being processed
6826 : * req->context contains:
6827 : * count The number of matching records
6828 : * dom_sid The domain sid, if present records must belong
6829 : * to the domain to be counted.
6830 : *@param [in,out] ares The query result.
6831 : *
6832 : * @return an LDB error code
6833 : *
6834 : */
6835 11307 : static int dsdb_count_domain_callback(
6836 : struct ldb_request *req,
6837 : struct ldb_reply *ares)
6838 : {
6839 :
6840 11307 : if (ares == NULL) {
6841 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
6842 : }
6843 11307 : if (ares->error != LDB_SUCCESS) {
6844 0 : int error = ares->error;
6845 0 : TALLOC_FREE(ares);
6846 0 : return ldb_request_done(req, error);
6847 : }
6848 :
6849 11307 : switch (ares->type) {
6850 7231 : case LDB_REPLY_ENTRY:
6851 : {
6852 7231 : struct dsdb_count_domain_context *context = NULL;
6853 96 : ssize_t ret;
6854 96 : bool in_domain;
6855 96 : struct dom_sid sid;
6856 96 : const struct ldb_val *v;
6857 :
6858 7231 : context = req->context;
6859 7231 : if (context->dom_sid == NULL) {
6860 5001 : context->count++;
6861 5001 : break;
6862 : }
6863 :
6864 2230 : v = ldb_msg_find_ldb_val(ares->message, "objectSid");
6865 2230 : if (v == NULL) {
6866 0 : break;
6867 : }
6868 :
6869 2230 : ret = sid_parse(v->data, v->length, &sid);
6870 2230 : if (ret == -1) {
6871 0 : break;
6872 : }
6873 :
6874 2230 : in_domain = dom_sid_in_domain(context->dom_sid, &sid);
6875 2230 : if (!in_domain) {
6876 1092 : break;
6877 : }
6878 :
6879 1138 : context->count++;
6880 1138 : break;
6881 : }
6882 336 : case LDB_REPLY_REFERRAL:
6883 336 : break;
6884 :
6885 3644 : case LDB_REPLY_DONE:
6886 3740 : TALLOC_FREE(ares);
6887 3740 : return ldb_request_done(req, LDB_SUCCESS);
6888 : }
6889 :
6890 7567 : TALLOC_FREE(ares);
6891 :
6892 7567 : return LDB_SUCCESS;
6893 : }
6894 :
6895 : /*
6896 : * @brief Count the number of records matching a query.
6897 : *
6898 : * Count the number of entries in the database matching the supplied query,
6899 : * optionally filtering only those entries belonging to the supplied domain.
6900 : *
6901 : * @param ldb [in] Current ldb context
6902 : * @param count [out] Pointer to the count
6903 : * @param base [in] The base dn for the query
6904 : * @param dom_sid [in] The domain sid, if non NULL records that are not a member
6905 : * of the domain are ignored.
6906 : * @param scope [in] Search scope.
6907 : * @param exp_fmt [in] format string for the query.
6908 : *
6909 : * @return LDB_STATUS code.
6910 : */
6911 3740 : int PRINTF_ATTRIBUTE(6, 7) dsdb_domain_count(
6912 : struct ldb_context *ldb,
6913 : size_t *count,
6914 : struct ldb_dn *base,
6915 : struct dom_sid *dom_sid,
6916 : enum ldb_scope scope,
6917 : const char *exp_fmt, ...)
6918 : {
6919 3740 : TALLOC_CTX *tmp_ctx = NULL;
6920 3740 : struct ldb_request *req = NULL;
6921 3740 : struct dsdb_count_domain_context *context = NULL;
6922 3740 : char *expression = NULL;
6923 3740 : const char *object_sid[] = {"objectSid", NULL};
6924 3740 : const char *none[] = {NULL};
6925 96 : va_list ap;
6926 96 : int ret;
6927 :
6928 3740 : *count = 0;
6929 3740 : tmp_ctx = talloc_new(ldb);
6930 3740 : if (tmp_ctx == NULL) {
6931 0 : return ldb_oom(ldb);
6932 : }
6933 :
6934 3740 : context = talloc_zero(tmp_ctx, struct dsdb_count_domain_context);
6935 3740 : if (context == NULL) {
6936 0 : return LDB_ERR_OPERATIONS_ERROR;
6937 : }
6938 3740 : context->dom_sid = dom_sid;
6939 :
6940 3740 : if (exp_fmt) {
6941 3740 : va_start(ap, exp_fmt);
6942 3740 : expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
6943 3740 : va_end(ap);
6944 :
6945 3740 : if (expression == NULL) {
6946 0 : TALLOC_FREE(context);
6947 0 : TALLOC_FREE(tmp_ctx);
6948 0 : return LDB_ERR_OPERATIONS_ERROR;
6949 : }
6950 : }
6951 :
6952 3740 : ret = ldb_build_search_req(
6953 : &req,
6954 : ldb,
6955 : tmp_ctx,
6956 : base,
6957 : scope,
6958 : expression,
6959 : (dom_sid == NULL) ? none : object_sid,
6960 : NULL,
6961 : context,
6962 : dsdb_count_domain_callback,
6963 : NULL);
6964 3740 : ldb_req_set_location(req, "dsdb_domain_count");
6965 :
6966 3740 : if (ret != LDB_SUCCESS) goto done;
6967 :
6968 3740 : ret = ldb_request(ldb, req);
6969 :
6970 3740 : if (ret == LDB_SUCCESS) {
6971 3740 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
6972 3740 : if (ret == LDB_SUCCESS) {
6973 3740 : *count = context->count;
6974 : }
6975 : }
6976 :
6977 :
6978 0 : done:
6979 3740 : TALLOC_FREE(expression);
6980 3740 : TALLOC_FREE(req);
6981 3740 : TALLOC_FREE(context);
6982 3740 : TALLOC_FREE(tmp_ctx);
6983 :
6984 3740 : return ret;
6985 : }
6986 :
6987 : /*
6988 : * Returns 1 if 'sids' contains the Protected Users group SID for the domain, 0
6989 : * if not. Returns a negative value on error.
6990 : */
6991 77905 : int dsdb_is_protected_user(struct ldb_context *ldb,
6992 : const struct auth_SidAttr *sids,
6993 : uint32_t num_sids)
6994 : {
6995 77905 : const struct dom_sid *domain_sid = NULL;
6996 3187 : struct dom_sid protected_users_sid;
6997 3187 : uint32_t i;
6998 :
6999 77905 : domain_sid = samdb_domain_sid(ldb);
7000 77905 : if (domain_sid == NULL) {
7001 0 : return -1;
7002 : }
7003 :
7004 77905 : protected_users_sid = *domain_sid;
7005 77905 : if (!sid_append_rid(&protected_users_sid, DOMAIN_RID_PROTECTED_USERS)) {
7006 0 : return -1;
7007 : }
7008 :
7009 564036 : for (i = 0; i < num_sids; ++i) {
7010 486205 : if (dom_sid_equal(&protected_users_sid, &sids[i].sid)) {
7011 74 : return 1;
7012 : }
7013 : }
7014 :
7015 74644 : return 0;
7016 : }
7017 :
7018 427105 : bool dsdb_account_is_trust(const struct ldb_message *msg)
7019 : {
7020 13479 : uint32_t userAccountControl;
7021 :
7022 427105 : userAccountControl = ldb_msg_find_attr_as_uint(msg,
7023 : "userAccountControl",
7024 : 0);
7025 427105 : return userAccountControl & UF_TRUST_ACCOUNT_MASK;
7026 : }
|