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