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