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