/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- samdb_search_domain
- samdb_search_string_v
- samdb_search_string
- samdb_search_dn
- samdb_search_dom_sid
- samdb_search_count
- samdb_search_uint
- samdb_search_int64
- samdb_search_string_multiple
- samdb_result_uint
- samdb_result_int64
- samdb_result_string
- samdb_result_dn
- samdb_result_rid_from_sid
- samdb_result_dom_sid
- samdb_result_guid
- samdb_result_sid_prefix
- samdb_result_nttime
- samdb_result_account_expires
- samdb_result_uint64
- samdb_result_allow_password_change
- samdb_result_force_password_change
- samdb_result_hash
- samdb_result_hashes
- samdb_result_passwords
- samdb_result_logon_hours
- samdb_result_acct_flags
- samdb_result_parameters
- samdb_find_attribute
- samdb_find_or_add_value
- samdb_find_or_add_attribute
- samdb_msg_add_string
- samdb_msg_add_dom_sid
- samdb_msg_add_delete
- samdb_msg_add_addval
- samdb_msg_add_delval
- samdb_msg_add_int
- samdb_msg_add_uint
- samdb_msg_add_int64
- samdb_msg_add_uint64
- samdb_msg_add_hash
- samdb_msg_add_hashes
- samdb_msg_add_acct_flags
- samdb_msg_add_logon_hours
- samdb_msg_add_parameters
- samdb_msg_add_value
- samdb_msg_set_value
- samdb_msg_set_string
- samdb_replace
- samdb_default_security_descriptor
- samdb_base_dn
- samdb_config_dn
- samdb_schema_dn
- samdb_root_dn
- samdb_partitions_dn
- samdb_sites_dn
- samdb_domain_sid
- samdb_set_domain_sid
- samdb_result_fsmo_name
- samdb_ntds_settings_dn
- samdb_ntds_invocation_id
- samdb_set_ntds_invocation_id
- samdb_ntds_objectGUID
- samdb_set_ntds_objectGUID
- samdb_server_dn
- samdb_server_site_dn
- samdb_is_pdc
- samdb_is_gc
- samdb_search_for_parent_domain
- samdb_password_complexity_ok
- samdb_set_password
- samdb_set_password_sid
- samdb_create_foreign_security_principal
- samdb_dns_domain_to_dn
- samdb_domain_to_dn
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_errors.h"
28 #include "../lib/util/util_ldb.h"
29 #include "../lib/crypto/crypto.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_security.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "dsdb/common/flags.h"
35 #include "dsdb/common/proto.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "param/param.h"
38 #include "libcli/auth/libcli_auth.h"
39
40 /*
41 search the sam for the specified attributes in a specific domain, filter on
42 objectSid being in domain_sid.
43 */
44 int samdb_search_domain(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
45 TALLOC_CTX *mem_ctx,
46 struct ldb_dn *basedn,
47 struct ldb_message ***res,
48 const char * const *attrs,
49 const struct dom_sid *domain_sid,
50 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
51 {
52 va_list ap;
53 int i, count;
54
55 va_start(ap, format);
56 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
57 res, attrs, format, ap);
58 va_end(ap);
59
60 i=0;
61
62 while (i<count) {
63 struct dom_sid *entry_sid;
64
65 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
66
67 if ((entry_sid == NULL) ||
68 (!dom_sid_in_domain(domain_sid, entry_sid))) {
69 /* Delete that entry from the result set */
70 (*res)[i] = (*res)[count-1];
71 count -= 1;
72 talloc_free(entry_sid);
73 continue;
74 }
75 talloc_free(entry_sid);
76 i += 1;
77 }
78
79 return count;
80 }
81
82 /*
83 search the sam for a single string attribute in exactly 1 record
84 */
85 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
86 TALLOC_CTX *mem_ctx,
87 struct ldb_dn *basedn,
88 const char *attr_name,
89 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
90 {
91 int count;
92 const char *attrs[2] = { NULL, NULL };
93 struct ldb_message **res = NULL;
94
95 attrs[0] = attr_name;
96
97 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
98 if (count > 1) {
99 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
100 attr_name, format, count));
101 }
102 if (count != 1) {
103 talloc_free(res);
104 return NULL;
105 }
106
107 return samdb_result_string(res[0], attr_name, NULL);
108 }
109
110
111 /*
112 search the sam for a single string attribute in exactly 1 record
113 */
114 const char *samdb_search_string(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
115 TALLOC_CTX *mem_ctx,
116 struct ldb_dn *basedn,
117 const char *attr_name,
118 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
119 {
120 va_list ap;
121 const char *str;
122
123 va_start(ap, format);
124 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
125 va_end(ap);
126
127 return str;
128 }
129
130 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
131 TALLOC_CTX *mem_ctx,
132 struct ldb_dn *basedn,
133 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
134 {
135 va_list ap;
136 struct ldb_dn *ret;
137 struct ldb_message **res = NULL;
138 int count;
139
140 va_start(ap, format);
141 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
142 va_end(ap);
143
144 if (count != 1) return NULL;
145
146 ret = talloc_steal(mem_ctx, res[0]->dn);
147 talloc_free(res);
148
149 return ret;
150 }
151
152 /*
153 search the sam for a dom_sid attribute in exactly 1 record
154 */
155 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
156 TALLOC_CTX *mem_ctx,
157 struct ldb_dn *basedn,
158 const char *attr_name,
159 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
160 {
161 va_list ap;
162 int count;
163 struct ldb_message **res;
164 const char *attrs[2] = { NULL, NULL };
165 struct dom_sid *sid;
166
167 attrs[0] = attr_name;
168
169 va_start(ap, format);
170 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
171 va_end(ap);
172 if (count > 1) {
173 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
174 attr_name, format, count));
175 }
176 if (count != 1) {
177 talloc_free(res);
178 return NULL;
179 }
180 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
181 talloc_free(res);
182 return sid;
183 }
184
185 /*
186 return the count of the number of records in the sam matching the query
187 */
188 int samdb_search_count(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
189 TALLOC_CTX *mem_ctx,
190 struct ldb_dn *basedn,
191 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
192 {
193 va_list ap;
194 struct ldb_message **res;
195 const char * const attrs[] = { NULL };
196 int ret;
197
198 va_start(ap, format);
199 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
200 va_end(ap);
201
202 return ret;
203 }
204
205
206 /*
207 search the sam for a single integer attribute in exactly 1 record
208 */
209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
210 TALLOC_CTX *mem_ctx,
211 uint_t default_value,
212 struct ldb_dn *basedn,
213 const char *attr_name,
214 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215 {
216 va_list ap;
217 int count;
218 struct ldb_message **res;
219 const char *attrs[2] = { NULL, NULL };
220
221 attrs[0] = attr_name;
222
223 va_start(ap, format);
224 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
225 va_end(ap);
226
227 if (count != 1) {
228 return default_value;
229 }
230
231 return samdb_result_uint(res[0], attr_name, default_value);
232 }
233
234 /*
235 search the sam for a single signed 64 bit integer attribute in exactly 1 record
236 */
237 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
238 TALLOC_CTX *mem_ctx,
239 int64_t default_value,
240 struct ldb_dn *basedn,
241 const char *attr_name,
242 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
243 {
244 va_list ap;
245 int count;
246 struct ldb_message **res;
247 const char *attrs[2] = { NULL, NULL };
248
249 attrs[0] = attr_name;
250
251 va_start(ap, format);
252 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
253 va_end(ap);
254
255 if (count != 1) {
256 return default_value;
257 }
258
259 return samdb_result_int64(res[0], attr_name, default_value);
260 }
261
262 /*
263 search the sam for multipe records each giving a single string attribute
264 return the number of matches, or -1 on error
265 */
266 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
267 TALLOC_CTX *mem_ctx,
268 struct ldb_dn *basedn,
269 const char ***strs,
270 const char *attr_name,
271 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
272 {
273 va_list ap;
274 int count, i;
275 const char *attrs[2] = { NULL, NULL };
276 struct ldb_message **res = NULL;
277
278 attrs[0] = attr_name;
279
280 va_start(ap, format);
281 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
282 va_end(ap);
283
284 if (count <= 0) {
285 return count;
286 }
287
288 /* make sure its single valued */
289 for (i=0;i<count;i++) {
290 if (res[i]->num_elements != 1) {
291 DEBUG(1,("samdb: search for %s %s not single valued\n",
292 attr_name, format));
293 talloc_free(res);
294 return -1;
295 }
296 }
297
298 *strs = talloc_array(mem_ctx, const char *, count+1);
299 if (! *strs) {
300 talloc_free(res);
301 return -1;
302 }
303
304 for (i=0;i<count;i++) {
305 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
306 }
307 (*strs)[count] = NULL;
308
309 return count;
310 }
311
312 /*
313 pull a uint from a result set.
314 */
315 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
/* [<][>][^][v][top][bottom][index][help] */
316 {
317 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
318 }
319
320 /*
321 pull a (signed) int64 from a result set.
322 */
323 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
/* [<][>][^][v][top][bottom][index][help] */
324 {
325 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
326 }
327
328 /*
329 pull a string from a result set.
330 */
331 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
/* [<][>][^][v][top][bottom][index][help] */
332 const char *default_value)
333 {
334 return ldb_msg_find_attr_as_string(msg, attr, default_value);
335 }
336
337 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
338 const char *attr, struct ldb_dn *default_value)
339 {
340 struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
341 if (!ret_dn) {
342 return default_value;
343 }
344 return ret_dn;
345 }
346
347 /*
348 pull a rid from a objectSid in a result set.
349 */
350 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
351 const char *attr, uint32_t default_value)
352 {
353 struct dom_sid *sid;
354 uint32_t rid;
355
356 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
357 if (sid == NULL) {
358 return default_value;
359 }
360 rid = sid->sub_auths[sid->num_auths-1];
361 talloc_free(sid);
362 return rid;
363 }
364
365 /*
366 pull a dom_sid structure from a objectSid in a result set.
367 */
368 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
369 const char *attr)
370 {
371 const struct ldb_val *v;
372 struct dom_sid *sid;
373 enum ndr_err_code ndr_err;
374 v = ldb_msg_find_ldb_val(msg, attr);
375 if (v == NULL) {
376 return NULL;
377 }
378 sid = talloc(mem_ctx, struct dom_sid);
379 if (sid == NULL) {
380 return NULL;
381 }
382 ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
383 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
385 talloc_free(sid);
386 return NULL;
387 }
388 return sid;
389 }
390
391 /*
392 pull a guid structure from a objectGUID in a result set.
393 */
394 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
/* [<][>][^][v][top][bottom][index][help] */
395 {
396 const struct ldb_val *v;
397 enum ndr_err_code ndr_err;
398 struct GUID guid;
399 TALLOC_CTX *mem_ctx;
400
401 ZERO_STRUCT(guid);
402
403 v = ldb_msg_find_ldb_val(msg, attr);
404 if (!v) return guid;
405
406 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
407 if (!mem_ctx) return guid;
408 ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
409 (ndr_pull_flags_fn_t)ndr_pull_GUID);
410 talloc_free(mem_ctx);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
412 return guid;
413 }
414
415 return guid;
416 }
417
418 /*
419 pull a sid prefix from a objectSid in a result set.
420 this is used to find the domain sid for a user
421 */
422 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
423 const char *attr)
424 {
425 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
426 if (!sid || sid->num_auths < 1) return NULL;
427 sid->num_auths--;
428 return sid;
429 }
430
431 /*
432 pull a NTTIME in a result set.
433 */
434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
/* [<][>][^][v][top][bottom][index][help] */
435 {
436 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
437 }
438
439 /*
440 * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
441 * indicate an account doesn't expire.
442 *
443 * When Windows initially creates an account, it sets
444 * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF). However,
445 * when changing from an account having a specific expiration date to
446 * that account never expiring, it sets accountExpires = 0.
447 *
448 * Consolidate that logic here to allow clearer logic for account expiry in
449 * the rest of the code.
450 */
451 NTTIME samdb_result_account_expires(struct ldb_message *msg)
/* [<][>][^][v][top][bottom][index][help] */
452 {
453 NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
454 0);
455
456 if (ret == 0)
457 ret = 0x7FFFFFFFFFFFFFFFULL;
458
459 return ret;
460 }
461
462 /*
463 pull a uint64_t from a result set.
464 */
465 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
/* [<][>][^][v][top][bottom][index][help] */
466 {
467 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
468 }
469
470
471 /*
472 construct the allow_password_change field from the PwdLastSet attribute and the
473 domain password settings
474 */
475 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
476 TALLOC_CTX *mem_ctx,
477 struct ldb_dn *domain_dn,
478 struct ldb_message *msg,
479 const char *attr)
480 {
481 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
482 int64_t minPwdAge;
483
484 if (attr_time == 0) {
485 return 0;
486 }
487
488 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
489
490 /* yes, this is a -= not a += as minPwdAge is stored as the negative
491 of the number of 100-nano-seconds */
492 attr_time -= minPwdAge;
493
494 return attr_time;
495 }
496
497 /*
498 construct the force_password_change field from the PwdLastSet
499 attribute, the userAccountControl and the domain password settings
500 */
501 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
/* [<][>][^][v][top][bottom][index][help] */
502 TALLOC_CTX *mem_ctx,
503 struct ldb_dn *domain_dn,
504 struct ldb_message *msg)
505 {
506 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
507 uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
508 int64_t maxPwdAge;
509
510 /* Machine accounts don't expire, and there is a flag for 'no expiry' */
511 if (!(userAccountControl & UF_NORMAL_ACCOUNT)
512 || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
513 return 0x7FFFFFFFFFFFFFFFULL;
514 }
515
516 if (attr_time == 0) {
517 return 0;
518 }
519
520 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
521 if (maxPwdAge == 0) {
522 return 0x7FFFFFFFFFFFFFFFULL;
523 } else {
524 attr_time -= maxPwdAge;
525 }
526
527 return attr_time;
528 }
529
530 /*
531 pull a samr_Password structutre from a result set.
532 */
533 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
/* [<][>][^][v][top][bottom][index][help] */
534 {
535 struct samr_Password *hash = NULL;
536 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
537 if (val && (val->length >= sizeof(hash->hash))) {
538 hash = talloc(mem_ctx, struct samr_Password);
539 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
540 }
541 return hash;
542 }
543
544 /*
545 pull an array of samr_Password structutres from a result set.
546 */
547 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
548 const char *attr, struct samr_Password **hashes)
549 {
550 uint_t count = 0;
551 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
552 int i;
553
554 *hashes = NULL;
555 if (!val) {
556 return 0;
557 }
558 count = val->length / 16;
559 if (count == 0) {
560 return 0;
561 }
562
563 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
564 if (! *hashes) {
565 return 0;
566 }
567
568 for (i=0;i<count;i++) {
569 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
570 }
571
572 return count;
573 }
574
575 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
576 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
577 {
578 struct samr_Password *lmPwdHash, *ntPwdHash;
579 if (nt_pwd) {
580 int num_nt;
581 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
582 if (num_nt == 0) {
583 *nt_pwd = NULL;
584 } else if (num_nt > 1) {
585 return NT_STATUS_INTERNAL_DB_CORRUPTION;
586 } else {
587 *nt_pwd = &ntPwdHash[0];
588 }
589 }
590 if (lm_pwd) {
591 /* Ensure that if we have turned off LM
592 * authentication, that we never use the LM hash, even
593 * if we store it */
594 if (lp_lanman_auth(lp_ctx)) {
595 int num_lm;
596 num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
597 if (num_lm == 0) {
598 *lm_pwd = NULL;
599 } else if (num_lm > 1) {
600 return NT_STATUS_INTERNAL_DB_CORRUPTION;
601 } else {
602 *lm_pwd = &lmPwdHash[0];
603 }
604 } else {
605 *lm_pwd = NULL;
606 }
607 }
608 return NT_STATUS_OK;
609 }
610
611 /*
612 pull a samr_LogonHours structutre from a result set.
613 */
614 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
/* [<][>][^][v][top][bottom][index][help] */
615 {
616 struct samr_LogonHours hours;
617 const int units_per_week = 168;
618 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
619 ZERO_STRUCT(hours);
620 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
621 if (!hours.bits) {
622 return hours;
623 }
624 hours.units_per_week = units_per_week;
625 memset(hours.bits, 0xFF, units_per_week);
626 if (val) {
627 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
628 }
629 return hours;
630 }
631
632 /*
633 pull a set of account_flags from a result set.
634
635 This requires that the attributes:
636 pwdLastSet
637 userAccountControl
638 be included in 'msg'
639 */
640 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
641 struct ldb_message *msg, struct ldb_dn *domain_dn)
642 {
643 uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
644 uint32_t acct_flags = samdb_uf2acb(userAccountControl);
645 NTTIME must_change_time;
646 NTTIME now;
647
648 must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx,
649 domain_dn, msg);
650
651 /* Test account expire time */
652 unix_to_nt_time(&now, time(NULL));
653 /* check for expired password */
654 if (must_change_time < now) {
655 acct_flags |= ACB_PW_EXPIRED;
656 }
657 return acct_flags;
658 }
659
660 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
661 struct ldb_message *msg,
662 const char *attr)
663 {
664 struct lsa_BinaryString s;
665 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
666
667 ZERO_STRUCT(s);
668
669 if (!val) {
670 return s;
671 }
672
673 s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
674 if (!s.array) {
675 return s;
676 }
677 s.length = s.size = val->length/2;
678 memcpy(s.array, val->data, val->length);
679
680 return s;
681 }
682
683 /* Find an attribute, with a particular value */
684
685 /* The current callers of this function expect a very specific
686 * behaviour: In particular, objectClass subclass equivilance is not
687 * wanted. This means that we should not lookup the schema for the
688 * comparison function */
689 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
/* [<][>][^][v][top][bottom][index][help] */
690 const struct ldb_message *msg,
691 const char *name, const char *value)
692 {
693 int i;
694 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
695
696 if (!el) {
697 return NULL;
698 }
699
700 for (i=0;i<el->num_values;i++) {
701 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
702 return el;
703 }
704 }
705
706 return NULL;
707 }
708
709 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
/* [<][>][^][v][top][bottom][index][help] */
710 {
711 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
712 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
713 }
714 return LDB_SUCCESS;
715 }
716
717 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
/* [<][>][^][v][top][bottom][index][help] */
718 {
719 struct ldb_message_element *el;
720
721 el = ldb_msg_find_element(msg, name);
722 if (el) {
723 return LDB_SUCCESS;
724 }
725
726 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
727 }
728
729
730
731 /*
732 add a string element to a message
733 */
734 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
735 const char *attr_name, const char *str)
736 {
737 char *s = talloc_strdup(mem_ctx, str);
738 char *a = talloc_strdup(mem_ctx, attr_name);
739 if (s == NULL || a == NULL) {
740 return LDB_ERR_OPERATIONS_ERROR;
741 }
742 return ldb_msg_add_string(msg, a, s);
743 }
744
745 /*
746 add a dom_sid element to a message
747 */
748 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
749 const char *attr_name, struct dom_sid *sid)
750 {
751 struct ldb_val v;
752 enum ndr_err_code ndr_err;
753
754 ndr_err = ndr_push_struct_blob(&v, mem_ctx,
755 lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
756 sid,
757 (ndr_push_flags_fn_t)ndr_push_dom_sid);
758 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
759 return -1;
760 }
761 return ldb_msg_add_value(msg, attr_name, &v, NULL);
762 }
763
764
765 /*
766 add a delete element operation to a message
767 */
768 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
769 const char *attr_name)
770 {
771 /* we use an empty replace rather than a delete, as it allows for
772 samdb_replace() to be used everywhere */
773 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
774 }
775
776 /*
777 add a add attribute value to a message
778 */
779 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
780 const char *attr_name, const char *value)
781 {
782 struct ldb_message_element *el;
783 char *a, *v;
784 int ret;
785 a = talloc_strdup(mem_ctx, attr_name);
786 if (a == NULL)
787 return -1;
788 v = talloc_strdup(mem_ctx, value);
789 if (v == NULL)
790 return -1;
791 ret = ldb_msg_add_string(msg, a, v);
792 if (ret != 0)
793 return ret;
794 el = ldb_msg_find_element(msg, a);
795 if (el == NULL)
796 return -1;
797 el->flags = LDB_FLAG_MOD_ADD;
798 return 0;
799 }
800
801 /*
802 add a delete attribute value to a message
803 */
804 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
805 const char *attr_name, const char *value)
806 {
807 struct ldb_message_element *el;
808 char *a, *v;
809 int ret;
810 a = talloc_strdup(mem_ctx, attr_name);
811 if (a == NULL)
812 return -1;
813 v = talloc_strdup(mem_ctx, value);
814 if (v == NULL)
815 return -1;
816 ret = ldb_msg_add_string(msg, a, v);
817 if (ret != 0)
818 return ret;
819 el = ldb_msg_find_element(msg, a);
820 if (el == NULL)
821 return -1;
822 el->flags = LDB_FLAG_MOD_DELETE;
823 return 0;
824 }
825
826 /*
827 add a int element to a message
828 */
829 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
830 const char *attr_name, int v)
831 {
832 const char *s = talloc_asprintf(mem_ctx, "%d", v);
833 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
834 }
835
836 /*
837 add a uint_t element to a message
838 */
839 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
840 const char *attr_name, uint_t v)
841 {
842 const char *s = talloc_asprintf(mem_ctx, "%u", v);
843 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
844 }
845
846 /*
847 add a (signed) int64_t element to a message
848 */
849 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
850 const char *attr_name, int64_t v)
851 {
852 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
853 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
854 }
855
856 /*
857 add a uint64_t element to a message
858 */
859 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
860 const char *attr_name, uint64_t v)
861 {
862 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
863 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
864 }
865
866 /*
867 add a samr_Password element to a message
868 */
869 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
870 const char *attr_name, struct samr_Password *hash)
871 {
872 struct ldb_val val;
873 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
874 if (!val.data) {
875 return -1;
876 }
877 val.length = 16;
878 return ldb_msg_add_value(msg, attr_name, &val, NULL);
879 }
880
881 /*
882 add a samr_Password array to a message
883 */
884 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
885 const char *attr_name, struct samr_Password *hashes, uint_t count)
886 {
887 struct ldb_val val;
888 int i;
889 val.data = talloc_array_size(mem_ctx, 16, count);
890 val.length = count*16;
891 if (!val.data) {
892 return -1;
893 }
894 for (i=0;i<count;i++) {
895 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
896 }
897 return ldb_msg_add_value(msg, attr_name, &val, NULL);
898 }
899
900 /*
901 add a acct_flags element to a message
902 */
903 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
904 const char *attr_name, uint32_t v)
905 {
906 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
907 }
908
909 /*
910 add a logon_hours element to a message
911 */
912 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
913 const char *attr_name, struct samr_LogonHours *hours)
914 {
915 struct ldb_val val;
916 val.length = hours->units_per_week / 8;
917 val.data = hours->bits;
918 return ldb_msg_add_value(msg, attr_name, &val, NULL);
919 }
920
921 /*
922 add a parameters element to a message
923 */
924 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
925 const char *attr_name, struct lsa_BinaryString *parameters)
926 {
927 struct ldb_val val;
928 val.length = parameters->length * 2;
929 val.data = (uint8_t *)parameters->array;
930 return ldb_msg_add_value(msg, attr_name, &val, NULL);
931 }
932 /*
933 add a general value element to a message
934 */
935 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
936 const char *attr_name, const struct ldb_val *val)
937 {
938 return ldb_msg_add_value(msg, attr_name, val, NULL);
939 }
940
941 /*
942 sets a general value element to a message
943 */
944 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
945 const char *attr_name, const struct ldb_val *val)
946 {
947 struct ldb_message_element *el;
948
949 el = ldb_msg_find_element(msg, attr_name);
950 if (el) {
951 el->num_values = 0;
952 }
953 return ldb_msg_add_value(msg, attr_name, val, NULL);
954 }
955
956 /*
957 set a string element in a message
958 */
959 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
960 const char *attr_name, const char *str)
961 {
962 struct ldb_message_element *el;
963
964 el = ldb_msg_find_element(msg, attr_name);
965 if (el) {
966 el->num_values = 0;
967 }
968 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
969 }
970
971 /*
972 replace elements in a record
973 */
974 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
/* [<][>][^][v][top][bottom][index][help] */
975 {
976 int i;
977
978 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
979 for (i=0;i<msg->num_elements;i++) {
980 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
981 }
982
983 /* modify the samdb record */
984 return ldb_modify(sam_ldb, msg);
985 }
986
987 /*
988 return a default security descriptor
989 */
990 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
/* [<][>][^][v][top][bottom][index][help] */
991 {
992 struct security_descriptor *sd;
993
994 sd = security_descriptor_initialise(mem_ctx);
995
996 return sd;
997 }
998
999 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1000 {
1001 return ldb_get_default_basedn(sam_ctx);
1002 }
1003
1004 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1005 {
1006 return ldb_get_config_basedn(sam_ctx);
1007 }
1008
1009 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1010 {
1011 return ldb_get_schema_basedn(sam_ctx);
1012 }
1013
1014 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1015 {
1016 return ldb_get_root_basedn(sam_ctx);
1017 }
1018
1019 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1020 {
1021 struct ldb_dn *new_dn;
1022
1023 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1024 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1025 talloc_free(new_dn);
1026 return NULL;
1027 }
1028 return new_dn;
1029 }
1030
1031 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1032 {
1033 struct ldb_dn *new_dn;
1034
1035 new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1036 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1037 talloc_free(new_dn);
1038 return NULL;
1039 }
1040 return new_dn;
1041 }
1042
1043 /*
1044 work out the domain sid for the current open ldb
1045 */
1046 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
/* [<][>][^][v][top][bottom][index][help] */
1047 {
1048 TALLOC_CTX *tmp_ctx;
1049 const struct dom_sid *domain_sid;
1050 const char *attrs[] = {
1051 "objectSid",
1052 NULL
1053 };
1054 struct ldb_result *res;
1055 int ret;
1056
1057 /* see if we have a cached copy */
1058 domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1059 if (domain_sid) {
1060 return domain_sid;
1061 }
1062
1063 tmp_ctx = talloc_new(ldb);
1064 if (tmp_ctx == NULL) {
1065 goto failed;
1066 }
1067
1068 ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1069
1070 if (ret != LDB_SUCCESS) {
1071 goto failed;
1072 }
1073
1074 if (res->count != 1) {
1075 goto failed;
1076 }
1077
1078 domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1079 if (domain_sid == NULL) {
1080 goto failed;
1081 }
1082
1083 /* cache the domain_sid in the ldb */
1084 if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1085 goto failed;
1086 }
1087
1088 talloc_steal(ldb, domain_sid);
1089 talloc_free(tmp_ctx);
1090
1091 return domain_sid;
1092
1093 failed:
1094 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1095 talloc_free(tmp_ctx);
1096 return NULL;
1097 }
1098
1099 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
/* [<][>][^][v][top][bottom][index][help] */
1100 {
1101 TALLOC_CTX *tmp_ctx;
1102 struct dom_sid *dom_sid_new;
1103 struct dom_sid *dom_sid_old;
1104
1105 /* see if we have a cached copy */
1106 dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
1107 "cache.domain_sid"), struct dom_sid);
1108
1109 tmp_ctx = talloc_new(ldb);
1110 if (tmp_ctx == NULL) {
1111 goto failed;
1112 }
1113
1114 dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1115 if (!dom_sid_new) {
1116 goto failed;
1117 }
1118
1119 /* cache the domain_sid in the ldb */
1120 if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1121 goto failed;
1122 }
1123
1124 talloc_steal(ldb, dom_sid_new);
1125 talloc_free(tmp_ctx);
1126 talloc_free(dom_sid_old);
1127
1128 return true;
1129
1130 failed:
1131 DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1132 talloc_free(tmp_ctx);
1133 return false;
1134 }
1135
1136 /* Obtain the short name of the flexible single master operator
1137 * (FSMO), such as the PDC Emulator */
1138 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
/* [<][>][^][v][top][bottom][index][help] */
1139 const char *attr)
1140 {
1141 /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1142 struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1143 const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1144 const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1145
1146 if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1147 /* Ensure this matches the format. This gives us a
1148 * bit more confidence that a 'cn' value will be a
1149 * ascii string */
1150 return NULL;
1151 }
1152 if (val) {
1153 return (char *)val->data;
1154 }
1155 return NULL;
1156 }
1157
1158 /*
1159 work out the ntds settings dn for the current open ldb
1160 */
1161 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
/* [<][>][^][v][top][bottom][index][help] */
1162 {
1163 TALLOC_CTX *tmp_ctx;
1164 const char *root_attrs[] = { "dsServiceName", NULL };
1165 int ret;
1166 struct ldb_result *root_res;
1167 struct ldb_dn *settings_dn;
1168
1169 /* see if we have a cached copy */
1170 settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1171 if (settings_dn) {
1172 return settings_dn;
1173 }
1174
1175 tmp_ctx = talloc_new(ldb);
1176 if (tmp_ctx == NULL) {
1177 goto failed;
1178 }
1179
1180
1181 ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1182 if (ret) {
1183 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
1184 ldb_errstring(ldb)));
1185 goto failed;
1186 }
1187
1188 if (root_res->count != 1) {
1189 goto failed;
1190 }
1191
1192 settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1193
1194 /* cache the domain_sid in the ldb */
1195 if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1196 goto failed;
1197 }
1198
1199 talloc_steal(ldb, settings_dn);
1200 talloc_free(tmp_ctx);
1201
1202 return settings_dn;
1203
1204 failed:
1205 DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1206 talloc_free(tmp_ctx);
1207 return NULL;
1208 }
1209
1210 /*
1211 work out the ntds settings invocationId for the current open ldb
1212 */
1213 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
/* [<][>][^][v][top][bottom][index][help] */
1214 {
1215 TALLOC_CTX *tmp_ctx;
1216 const char *attrs[] = { "invocationId", NULL };
1217 int ret;
1218 struct ldb_result *res;
1219 struct GUID *invocation_id;
1220
1221 /* see if we have a cached copy */
1222 invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1223 if (invocation_id) {
1224 return invocation_id;
1225 }
1226
1227 tmp_ctx = talloc_new(ldb);
1228 if (tmp_ctx == NULL) {
1229 goto failed;
1230 }
1231
1232 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1233 if (ret) {
1234 goto failed;
1235 }
1236
1237 if (res->count != 1) {
1238 goto failed;
1239 }
1240
1241 invocation_id = talloc(tmp_ctx, struct GUID);
1242 if (!invocation_id) {
1243 goto failed;
1244 }
1245
1246 *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1247
1248 /* cache the domain_sid in the ldb */
1249 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1250 goto failed;
1251 }
1252
1253 talloc_steal(ldb, invocation_id);
1254 talloc_free(tmp_ctx);
1255
1256 return invocation_id;
1257
1258 failed:
1259 DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1260 talloc_free(tmp_ctx);
1261 return NULL;
1262 }
1263
1264 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
/* [<][>][^][v][top][bottom][index][help] */
1265 {
1266 TALLOC_CTX *tmp_ctx;
1267 struct GUID *invocation_id_new;
1268 struct GUID *invocation_id_old;
1269
1270 /* see if we have a cached copy */
1271 invocation_id_old = (struct GUID *)ldb_get_opaque(ldb,
1272 "cache.invocation_id");
1273
1274 tmp_ctx = talloc_new(ldb);
1275 if (tmp_ctx == NULL) {
1276 goto failed;
1277 }
1278
1279 invocation_id_new = talloc(tmp_ctx, struct GUID);
1280 if (!invocation_id_new) {
1281 goto failed;
1282 }
1283
1284 *invocation_id_new = *invocation_id_in;
1285
1286 /* cache the domain_sid in the ldb */
1287 if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1288 goto failed;
1289 }
1290
1291 talloc_steal(ldb, invocation_id_new);
1292 talloc_free(tmp_ctx);
1293 talloc_free(invocation_id_old);
1294
1295 return true;
1296
1297 failed:
1298 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1299 talloc_free(tmp_ctx);
1300 return false;
1301 }
1302
1303 /*
1304 work out the ntds settings objectGUID for the current open ldb
1305 */
1306 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
/* [<][>][^][v][top][bottom][index][help] */
1307 {
1308 TALLOC_CTX *tmp_ctx;
1309 const char *attrs[] = { "objectGUID", NULL };
1310 int ret;
1311 struct ldb_result *res;
1312 struct GUID *ntds_guid;
1313
1314 /* see if we have a cached copy */
1315 ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1316 if (ntds_guid) {
1317 return ntds_guid;
1318 }
1319
1320 tmp_ctx = talloc_new(ldb);
1321 if (tmp_ctx == NULL) {
1322 goto failed;
1323 }
1324
1325 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1326 if (ret) {
1327 goto failed;
1328 }
1329
1330 if (res->count != 1) {
1331 goto failed;
1332 }
1333
1334 ntds_guid = talloc(tmp_ctx, struct GUID);
1335 if (!ntds_guid) {
1336 goto failed;
1337 }
1338
1339 *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1340
1341 /* cache the domain_sid in the ldb */
1342 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1343 goto failed;
1344 }
1345
1346 talloc_steal(ldb, ntds_guid);
1347 talloc_free(tmp_ctx);
1348
1349 return ntds_guid;
1350
1351 failed:
1352 DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1353 talloc_free(tmp_ctx);
1354 return NULL;
1355 }
1356
1357 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
/* [<][>][^][v][top][bottom][index][help] */
1358 {
1359 TALLOC_CTX *tmp_ctx;
1360 struct GUID *ntds_guid_new;
1361 struct GUID *ntds_guid_old;
1362
1363 /* see if we have a cached copy */
1364 ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1365
1366 tmp_ctx = talloc_new(ldb);
1367 if (tmp_ctx == NULL) {
1368 goto failed;
1369 }
1370
1371 ntds_guid_new = talloc(tmp_ctx, struct GUID);
1372 if (!ntds_guid_new) {
1373 goto failed;
1374 }
1375
1376 *ntds_guid_new = *ntds_guid_in;
1377
1378 /* cache the domain_sid in the ldb */
1379 if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1380 goto failed;
1381 }
1382
1383 talloc_steal(ldb, ntds_guid_new);
1384 talloc_free(tmp_ctx);
1385 talloc_free(ntds_guid_old);
1386
1387 return true;
1388
1389 failed:
1390 DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1391 talloc_free(tmp_ctx);
1392 return false;
1393 }
1394
1395 /*
1396 work out the server dn for the current open ldb
1397 */
1398 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1399 {
1400 return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1401 }
1402
1403 /*
1404 work out the server dn for the current open ldb
1405 */
1406 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
/* [<][>][^][v][top][bottom][index][help] */
1407 {
1408 struct ldb_dn *server_dn;
1409 struct ldb_dn *server_site_dn;
1410
1411 server_dn = samdb_server_dn(ldb, mem_ctx);
1412 if (!server_dn) return NULL;
1413
1414 server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1415
1416 talloc_free(server_dn);
1417 return server_site_dn;
1418 }
1419
1420 /*
1421 work out if we are the PDC for the domain of the current open ldb
1422 */
1423 bool samdb_is_pdc(struct ldb_context *ldb)
/* [<][>][^][v][top][bottom][index][help] */
1424 {
1425 const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1426 int ret;
1427 struct ldb_result *dom_res;
1428 TALLOC_CTX *tmp_ctx;
1429 bool is_pdc;
1430 struct ldb_dn *pdc;
1431
1432 tmp_ctx = talloc_new(ldb);
1433 if (tmp_ctx == NULL) {
1434 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1435 return false;
1436 }
1437
1438 ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1439 if (ret) {
1440 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
1441 ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
1442 ldb_errstring(ldb)));
1443 goto failed;
1444 }
1445 if (dom_res->count != 1) {
1446 goto failed;
1447 }
1448
1449 pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1450
1451 if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1452 is_pdc = true;
1453 } else {
1454 is_pdc = false;
1455 }
1456
1457 talloc_free(tmp_ctx);
1458
1459 return is_pdc;
1460
1461 failed:
1462 DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1463 talloc_free(tmp_ctx);
1464 return false;
1465 }
1466
1467 /*
1468 work out if we are a Global Catalog server for the domain of the current open ldb
1469 */
1470 bool samdb_is_gc(struct ldb_context *ldb)
/* [<][>][^][v][top][bottom][index][help] */
1471 {
1472 const char *attrs[] = { "options", NULL };
1473 int ret, options;
1474 struct ldb_result *res;
1475 TALLOC_CTX *tmp_ctx;
1476
1477 tmp_ctx = talloc_new(ldb);
1478 if (tmp_ctx == NULL) {
1479 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1480 return false;
1481 }
1482
1483 /* Query cn=ntds settings,.... */
1484 ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1485 if (ret) {
1486 talloc_free(tmp_ctx);
1487 return false;
1488 }
1489 if (res->count != 1) {
1490 talloc_free(tmp_ctx);
1491 return false;
1492 }
1493
1494 options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1495 talloc_free(tmp_ctx);
1496
1497 /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1498 if (options & 0x000000001) {
1499 return true;
1500 }
1501 return false;
1502 }
1503
1504 /* Find a domain object in the parents of a particular DN. */
1505 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
/* [<][>][^][v][top][bottom][index][help] */
1506 struct ldb_dn **parent_dn, const char **errstring)
1507 {
1508 TALLOC_CTX *local_ctx;
1509 struct ldb_dn *sdn = dn;
1510 struct ldb_result *res = NULL;
1511 int ret = 0;
1512 const char *attrs[] = { NULL };
1513
1514 local_ctx = talloc_new(mem_ctx);
1515 if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1516
1517 while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1518 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1519 "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1520 if (ret == LDB_SUCCESS) {
1521 if (res->count == 1) {
1522 break;
1523 }
1524 } else {
1525 break;
1526 }
1527 }
1528
1529 if (ret != LDB_SUCCESS) {
1530 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1531 ldb_dn_get_linearized(dn),
1532 ldb_dn_get_linearized(sdn),
1533 ldb_errstring(ldb));
1534 talloc_free(local_ctx);
1535 return ret;
1536 }
1537 if (res->count != 1) {
1538 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1539 ldb_dn_get_linearized(dn));
1540 talloc_free(local_ctx);
1541 return LDB_ERR_CONSTRAINT_VIOLATION;
1542 }
1543
1544 *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1545 talloc_free(local_ctx);
1546 return ret;
1547 }
1548
1549 /*
1550 check that a password is sufficiently complex
1551 */
1552 static bool samdb_password_complexity_ok(const char *pass)
/* [<][>][^][v][top][bottom][index][help] */
1553 {
1554 return check_password_quality(pass);
1555 }
1556
1557
1558
1559 /*
1560 set the user password using plaintext, obeying any user or domain
1561 password restrictions
1562
1563 note that this function doesn't actually store the result in the
1564 database, it just fills in the "mod" structure with ldb modify
1565 elements to setup the correct change when samdb_replace() is
1566 called. This allows the caller to combine the change with other
1567 changes (as is needed by some of the set user info levels)
1568
1569 The caller should probably have a transaction wrapping this
1570 */
1571 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1572 struct ldb_dn *user_dn,
1573 struct ldb_dn *domain_dn,
1574 struct ldb_message *mod,
1575 const DATA_BLOB *new_password,
1576 struct samr_Password *lmNewHash,
1577 struct samr_Password *ntNewHash,
1578 bool user_change,
1579 enum samr_RejectReason *reject_reason,
1580 struct samr_DomInfo1 **_dominfo)
1581 {
1582 const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
1583 "ntPwdHistory",
1584 "dBCSPwd", "unicodePwd",
1585 "objectSid",
1586 "pwdLastSet", NULL };
1587 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1588 "maxPwdAge", "minPwdAge",
1589 "minPwdLength", NULL };
1590 NTTIME pwdLastSet;
1591 int64_t minPwdAge;
1592 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1593 uint_t userAccountControl;
1594 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1595 struct samr_Password local_lmNewHash, local_ntNewHash;
1596 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1597 struct dom_sid *domain_sid;
1598 struct ldb_message **res;
1599 bool restrictions;
1600 int count;
1601 time_t now = time(NULL);
1602 NTTIME now_nt;
1603 int i;
1604
1605 /* we need to know the time to compute password age */
1606 unix_to_nt_time(&now_nt, now);
1607
1608 /* pull all the user parameters */
1609 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1610 if (count != 1) {
1611 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1612 }
1613 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1614 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1615 "lmPwdHistory", &sambaLMPwdHistory);
1616 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1617 "ntPwdHistory", &sambaNTPwdHistory);
1618 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd");
1619 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd");
1620 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1621
1622 /* Only non-trust accounts have restrictions (possibly this
1623 * test is the wrong way around, but I like to be restrictive
1624 * if possible */
1625 restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1626 |UF_WORKSTATION_TRUST_ACCOUNT
1627 |UF_SERVER_TRUST_ACCOUNT));
1628
1629 if (domain_dn) {
1630 /* pull the domain parameters */
1631 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1632 if (count != 1) {
1633 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1634 ldb_dn_get_linearized(domain_dn),
1635 ldb_dn_get_linearized(user_dn)));
1636 return NT_STATUS_NO_SUCH_DOMAIN;
1637 }
1638 } else {
1639 /* work out the domain sid, and pull the domain from there */
1640 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1641 if (domain_sid == NULL) {
1642 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1643 }
1644
1645 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1646 "(objectSid=%s)",
1647 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1648 if (count != 1) {
1649 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1650 dom_sid_string(mem_ctx, domain_sid),
1651 ldb_dn_get_linearized(user_dn)));
1652 return NT_STATUS_NO_SUCH_DOMAIN;
1653 }
1654 }
1655
1656 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1657 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1658 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1659 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1660
1661 if (_dominfo) {
1662 struct samr_DomInfo1 *dominfo;
1663 /* on failure we need to fill in the reject reasons */
1664 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1665 if (dominfo == NULL) {
1666 return NT_STATUS_NO_MEMORY;
1667 }
1668 dominfo->min_password_length = minPwdLength;
1669 dominfo->password_properties = pwdProperties;
1670 dominfo->password_history_length = pwdHistoryLength;
1671 dominfo->max_password_age = minPwdAge;
1672 dominfo->min_password_age = minPwdAge;
1673 *_dominfo = dominfo;
1674 }
1675
1676 if (restrictions && new_password) {
1677 char *new_pass;
1678
1679 /* check the various password restrictions */
1680 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1681 if (reject_reason) {
1682 *reject_reason = SAMR_REJECT_TOO_SHORT;
1683 }
1684 return NT_STATUS_PASSWORD_RESTRICTION;
1685 }
1686
1687 /* Create the NT hash */
1688 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1689
1690 ntNewHash = &local_ntNewHash;
1691
1692 /* Only check complexity if we can convert it at all. Assuming unconvertable passwords are 'strong' */
1693 if (convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
1694 CH_UTF16, CH_UNIX,
1695 new_password->data, new_password->length,
1696 (void **)&new_pass, NULL, false)) {
1697
1698
1699 /* possibly check password complexity */
1700 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1701 !samdb_password_complexity_ok(new_pass)) {
1702 if (reject_reason) {
1703 *reject_reason = SAMR_REJECT_COMPLEXITY;
1704 }
1705 return NT_STATUS_PASSWORD_RESTRICTION;
1706 }
1707
1708 /* compute the new lm hashes (for checking history - case insenitivly!) */
1709 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1710 lmNewHash = &local_lmNewHash;
1711 }
1712
1713 }
1714 }
1715
1716 if (restrictions && user_change) {
1717 /* are all password changes disallowed? */
1718 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1719 if (reject_reason) {
1720 *reject_reason = SAMR_REJECT_OTHER;
1721 }
1722 return NT_STATUS_PASSWORD_RESTRICTION;
1723 }
1724
1725 /* can this user change password? */
1726 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1727 if (reject_reason) {
1728 *reject_reason = SAMR_REJECT_OTHER;
1729 }
1730 return NT_STATUS_PASSWORD_RESTRICTION;
1731 }
1732
1733 /* yes, this is a minus. The ages are in negative 100nsec units! */
1734 if (pwdLastSet - minPwdAge > now_nt) {
1735 if (reject_reason) {
1736 *reject_reason = SAMR_REJECT_OTHER;
1737 }
1738 return NT_STATUS_PASSWORD_RESTRICTION;
1739 }
1740
1741 /* check the immediately past password */
1742 if (pwdHistoryLength > 0) {
1743 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1744 if (reject_reason) {
1745 *reject_reason = SAMR_REJECT_IN_HISTORY;
1746 }
1747 return NT_STATUS_PASSWORD_RESTRICTION;
1748 }
1749 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1750 if (reject_reason) {
1751 *reject_reason = SAMR_REJECT_IN_HISTORY;
1752 }
1753 return NT_STATUS_PASSWORD_RESTRICTION;
1754 }
1755 }
1756
1757 /* check the password history */
1758 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1759 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1760
1761 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1762 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1763 if (reject_reason) {
1764 *reject_reason = SAMR_REJECT_IN_HISTORY;
1765 }
1766 return NT_STATUS_PASSWORD_RESTRICTION;
1767 }
1768 }
1769 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1770 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1771 if (reject_reason) {
1772 *reject_reason = SAMR_REJECT_IN_HISTORY;
1773 }
1774 return NT_STATUS_PASSWORD_RESTRICTION;
1775 }
1776 }
1777 }
1778
1779 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1780
1781 /* the password is acceptable. Start forming the new fields */
1782 if (new_password) {
1783 /* if we know the cleartext UTF16 password, then set it.
1784 * Modules in ldb will set all the appropriate
1785 * hashes */
1786 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1787 } else {
1788 /* We don't have the cleartext, so delete the old one
1789 * and set what we have of the hashes */
1790 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1791
1792 if (lmNewHash) {
1793 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1794 } else {
1795 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1796 }
1797
1798 if (ntNewHash) {
1799 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1800 } else {
1801 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1802 }
1803 }
1804
1805 return NT_STATUS_OK;
1806 }
1807
1808
1809 /*
1810 set the user password using plaintext, obeying any user or domain
1811 password restrictions
1812
1813 This wrapper function takes a SID as input, rather than a user DN,
1814 and actually performs the password change
1815
1816 */
1817 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1818 const struct dom_sid *user_sid,
1819 const DATA_BLOB *new_pass,
1820 struct samr_Password *lmNewHash,
1821 struct samr_Password *ntNewHash,
1822 bool user_change,
1823 enum samr_RejectReason *reject_reason,
1824 struct samr_DomInfo1 **_dominfo)
1825 {
1826 NTSTATUS nt_status;
1827 struct ldb_dn *user_dn;
1828 struct ldb_message *msg;
1829 int ret;
1830
1831 ret = ldb_transaction_start(ctx);
1832 if (ret) {
1833 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1834 return NT_STATUS_TRANSACTION_ABORTED;
1835 }
1836
1837 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1838 "(&(objectSid=%s)(objectClass=user))",
1839 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1840 if (!user_dn) {
1841 ldb_transaction_cancel(ctx);
1842 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1843 dom_sid_string(mem_ctx, user_sid)));
1844 return NT_STATUS_NO_SUCH_USER;
1845 }
1846
1847 msg = ldb_msg_new(mem_ctx);
1848 if (msg == NULL) {
1849 ldb_transaction_cancel(ctx);
1850 return NT_STATUS_NO_MEMORY;
1851 }
1852
1853 msg->dn = ldb_dn_copy(msg, user_dn);
1854 if (!msg->dn) {
1855 ldb_transaction_cancel(ctx);
1856 return NT_STATUS_NO_MEMORY;
1857 }
1858
1859 nt_status = samdb_set_password(ctx, mem_ctx,
1860 user_dn, NULL,
1861 msg, new_pass,
1862 lmNewHash, ntNewHash,
1863 user_change, /* This is a password set, not change */
1864 reject_reason, _dominfo);
1865 if (!NT_STATUS_IS_OK(nt_status)) {
1866 ldb_transaction_cancel(ctx);
1867 return nt_status;
1868 }
1869
1870 /* modify the samdb record */
1871 ret = samdb_replace(ctx, mem_ctx, msg);
1872 if (ret != 0) {
1873 ldb_transaction_cancel(ctx);
1874 return NT_STATUS_ACCESS_DENIED;
1875 }
1876
1877 ret = ldb_transaction_commit(ctx);
1878 if (ret != 0) {
1879 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1880 ldb_dn_get_linearized(msg->dn),
1881 ldb_errstring(ctx)));
1882 return NT_STATUS_TRANSACTION_ABORTED;
1883 }
1884 return NT_STATUS_OK;
1885 }
1886
1887
1888
1889 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1890 struct dom_sid *sid, struct ldb_dn **ret_dn)
1891 {
1892 struct ldb_message *msg;
1893 struct ldb_dn *basedn;
1894 const char *sidstr;
1895 int ret;
1896
1897 sidstr = dom_sid_string(mem_ctx, sid);
1898 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1899
1900 /* We might have to create a ForeignSecurityPrincipal, even if this user
1901 * is in our own domain */
1902
1903 msg = ldb_msg_new(mem_ctx);
1904 if (msg == NULL) {
1905 return NT_STATUS_NO_MEMORY;
1906 }
1907
1908 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1909 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1910 * not work, this is wrong for the Builtin domain, there's no
1911 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1912 */
1913
1914 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1915 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1916
1917 if (basedn == NULL) {
1918 DEBUG(0, ("Failed to find DN for "
1919 "ForeignSecurityPrincipal container\n"));
1920 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1921 }
1922
1923 /* add core elements to the ldb_message for the alias */
1924 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1925 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1926 return NT_STATUS_NO_MEMORY;
1927
1928 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1929 "objectClass",
1930 "foreignSecurityPrincipal");
1931
1932 /* create the alias */
1933 ret = ldb_add(sam_ctx, msg);
1934 if (ret != 0) {
1935 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1936 "record %s: %s\n",
1937 ldb_dn_get_linearized(msg->dn),
1938 ldb_errstring(sam_ctx)));
1939 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1940 }
1941 *ret_dn = msg->dn;
1942 return NT_STATUS_OK;
1943 }
1944
1945
1946 /*
1947 Find the DN of a domain, assuming it to be a dotted.dns name
1948 */
1949
1950 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
/* [<][>][^][v][top][bottom][index][help] */
1951 {
1952 int i;
1953 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1954 const char *binary_encoded;
1955 const char **split_realm;
1956 struct ldb_dn *dn;
1957
1958 if (!tmp_ctx) {
1959 return NULL;
1960 }
1961
1962 split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1963 if (!split_realm) {
1964 talloc_free(tmp_ctx);
1965 return NULL;
1966 }
1967 dn = ldb_dn_new(mem_ctx, ldb, NULL);
1968 for (i=0; split_realm[i]; i++) {
1969 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1970 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1971 DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1972 binary_encoded, ldb_dn_get_linearized(dn)));
1973 talloc_free(tmp_ctx);
1974 return NULL;
1975 }
1976 }
1977 if (!ldb_dn_validate(dn)) {
1978 DEBUG(2, ("Failed to validated DN %s\n",
1979 ldb_dn_get_linearized(dn)));
1980 return NULL;
1981 }
1982 return dn;
1983 }
1984 /*
1985 Find the DN of a domain, be it the netbios or DNS name
1986 */
1987
1988 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
1989 const char *domain_name)
1990 {
1991 const char * const domain_ref_attrs[] = {
1992 "ncName", NULL
1993 };
1994 const char * const domain_ref2_attrs[] = {
1995 NULL
1996 };
1997 struct ldb_result *res_domain_ref;
1998 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1999 /* find the domain's DN */
2000 int ret_domain = ldb_search(ldb, mem_ctx,
2001 &res_domain_ref,
2002 samdb_partitions_dn(ldb, mem_ctx),
2003 LDB_SCOPE_ONELEVEL,
2004 domain_ref_attrs,
2005 "(&(nETBIOSName=%s)(objectclass=crossRef))",
2006 escaped_domain);
2007 if (ret_domain != 0) {
2008 return NULL;
2009 }
2010
2011 if (res_domain_ref->count == 0) {
2012 ret_domain = ldb_search(ldb, mem_ctx,
2013 &res_domain_ref,
2014 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2015 LDB_SCOPE_BASE,
2016 domain_ref2_attrs,
2017 "(objectclass=domain)");
2018 if (ret_domain != 0) {
2019 return NULL;
2020 }
2021
2022 if (res_domain_ref->count == 1) {
2023 return res_domain_ref->msgs[0]->dn;
2024 }
2025 return NULL;
2026 }
2027
2028 if (res_domain_ref->count > 1) {
2029 DEBUG(0,("Found %d records matching domain [%s]\n",
2030 ret_domain, domain_name));
2031 return NULL;
2032 }
2033
2034 return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2035
2036 }