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