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