1 /*
2 Unix SMB/CIFS implementation.
3
4 interface functions for the sam database
5
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
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 2 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, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "lib/ldb/include/ldb.h"
30 #include "lib/ldb/include/ldb_errors.h"
31 #include "libcli/security/security.h"
32 #include "libcli/auth/libcli_auth.h"
33 #include "libcli/ldap/ldap.h"
34 #include "system/time.h"
35 #include "system/filesys.h"
36 #include "db_wrap.h"
37 #include "dsdb/samdb/samdb.h"
38 #include "dsdb/common/flags.h"
39
40 /*
41 connect to the SAM database
42 return an opaque context pointer on success, or NULL on failure
43 */
samdb_connect(TALLOC_CTX * mem_ctx,struct auth_session_info * session_info)44 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx,
45 struct auth_session_info *session_info)
46 {
47 struct ldb_context *ldb;
48 ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
49 NULL, 0, NULL);
50 if (!ldb) {
51 return NULL;
52 }
53 return ldb;
54 }
55
56 /*
57 search the sam for the specified attributes in a specific domain, filter on
58 objectSid being in domain_sid.
59 */
samdb_search_domain(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,struct ldb_message *** res,const char * const * attrs,const struct dom_sid * domain_sid,const char * format,...)60 int samdb_search_domain(struct ldb_context *sam_ldb,
61 TALLOC_CTX *mem_ctx,
62 struct ldb_dn *basedn,
63 struct ldb_message ***res,
64 const char * const *attrs,
65 const struct dom_sid *domain_sid,
66 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
67 {
68 va_list ap;
69 int i, count;
70
71 va_start(ap, format);
72 count = gendb_search_v(sam_ldb, mem_ctx, basedn,
73 res, attrs, format, ap);
74 va_end(ap);
75
76 i=0;
77
78 while (i<count) {
79 struct dom_sid *entry_sid;
80
81 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
82
83 if ((entry_sid == NULL) ||
84 (!dom_sid_in_domain(domain_sid, entry_sid))) {
85 /* Delete that entry from the result set */
86 (*res)[i] = (*res)[count-1];
87 count -= 1;
88 talloc_free(entry_sid);
89 continue;
90 }
91 talloc_free(entry_sid);
92 i += 1;
93 }
94
95 return count;
96 }
97
98 /*
99 search the sam for a single string attribute in exactly 1 record
100 */
samdb_search_string_v(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,const char * attr_name,const char * format,va_list ap)101 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
102 TALLOC_CTX *mem_ctx,
103 struct ldb_dn *basedn,
104 const char *attr_name,
105 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
106 {
107 int count;
108 const char *attrs[2] = { NULL, NULL };
109 struct ldb_message **res = NULL;
110
111 attrs[0] = attr_name;
112
113 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
114 if (count > 1) {
115 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
116 attr_name, format, count));
117 }
118 if (count != 1) {
119 talloc_free(res);
120 return NULL;
121 }
122
123 return samdb_result_string(res[0], attr_name, NULL);
124 }
125
126
127 /*
128 search the sam for a single string attribute in exactly 1 record
129 */
samdb_search_string(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,const char * attr_name,const char * format,...)130 const char *samdb_search_string(struct ldb_context *sam_ldb,
131 TALLOC_CTX *mem_ctx,
132 struct ldb_dn *basedn,
133 const char *attr_name,
134 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
135 {
136 va_list ap;
137 const char *str;
138
139 va_start(ap, format);
140 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
141 va_end(ap);
142
143 return str;
144 }
145
samdb_search_dn(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,const char * format,...)146 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
147 TALLOC_CTX *mem_ctx,
148 struct ldb_dn *basedn,
149 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
150 {
151 va_list ap;
152 struct ldb_dn *ret;
153 struct ldb_message **res = NULL;
154 int count;
155
156 va_start(ap, format);
157 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
158 va_end(ap);
159
160 if (count != 1) return NULL;
161
162 ret = talloc_steal(mem_ctx, res[0]->dn);
163 talloc_free(res);
164
165 return ret;
166 }
167
168 /*
169 search the sam for a dom_sid attribute in exactly 1 record
170 */
samdb_search_dom_sid(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,const char * attr_name,const char * format,...)171 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
172 TALLOC_CTX *mem_ctx,
173 struct ldb_dn *basedn,
174 const char *attr_name,
175 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
176 {
177 va_list ap;
178 int count;
179 struct ldb_message **res;
180 const char *attrs[2] = { NULL, NULL };
181 struct dom_sid *sid;
182
183 attrs[0] = attr_name;
184
185 va_start(ap, format);
186 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
187 va_end(ap);
188 if (count > 1) {
189 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
190 attr_name, format, count));
191 }
192 if (count != 1) {
193 talloc_free(res);
194 return NULL;
195 }
196 sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
197 talloc_free(res);
198 return sid;
199 }
200
201 /*
202 return the count of the number of records in the sam matching the query
203 */
samdb_search_count(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,const char * format,...)204 int samdb_search_count(struct ldb_context *sam_ldb,
205 TALLOC_CTX *mem_ctx,
206 struct ldb_dn *basedn,
207 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
208 {
209 va_list ap;
210 struct ldb_message **res;
211 const char * const attrs[] = { NULL };
212 int ret;
213
214 va_start(ap, format);
215 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
216 va_end(ap);
217
218 return ret;
219 }
220
221
222 /*
223 search the sam for a single integer attribute in exactly 1 record
224 */
samdb_search_uint(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,uint_t default_value,struct ldb_dn * basedn,const char * attr_name,const char * format,...)225 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
226 TALLOC_CTX *mem_ctx,
227 uint_t default_value,
228 struct ldb_dn *basedn,
229 const char *attr_name,
230 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
231 {
232 va_list ap;
233 int count;
234 struct ldb_message **res;
235 const char *attrs[2] = { NULL, NULL };
236
237 attrs[0] = attr_name;
238
239 va_start(ap, format);
240 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
241 va_end(ap);
242
243 if (count != 1) {
244 return default_value;
245 }
246
247 return samdb_result_uint(res[0], attr_name, default_value);
248 }
249
250 /*
251 search the sam for a single signed 64 bit integer attribute in exactly 1 record
252 */
samdb_search_int64(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,int64_t default_value,struct ldb_dn * basedn,const char * attr_name,const char * format,...)253 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
254 TALLOC_CTX *mem_ctx,
255 int64_t default_value,
256 struct ldb_dn *basedn,
257 const char *attr_name,
258 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
259 {
260 va_list ap;
261 int count;
262 struct ldb_message **res;
263 const char *attrs[2] = { NULL, NULL };
264
265 attrs[0] = attr_name;
266
267 va_start(ap, format);
268 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
269 va_end(ap);
270
271 if (count != 1) {
272 return default_value;
273 }
274
275 return samdb_result_int64(res[0], attr_name, default_value);
276 }
277
278 /*
279 search the sam for multipe records each giving a single string attribute
280 return the number of matches, or -1 on error
281 */
samdb_search_string_multiple(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * basedn,const char *** strs,const char * attr_name,const char * format,...)282 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
283 TALLOC_CTX *mem_ctx,
284 struct ldb_dn *basedn,
285 const char ***strs,
286 const char *attr_name,
287 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
288 {
289 va_list ap;
290 int count, i;
291 const char *attrs[2] = { NULL, NULL };
292 struct ldb_message **res = NULL;
293
294 attrs[0] = attr_name;
295
296 va_start(ap, format);
297 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
298 va_end(ap);
299
300 if (count <= 0) {
301 return count;
302 }
303
304 /* make sure its single valued */
305 for (i=0;i<count;i++) {
306 if (res[i]->num_elements != 1) {
307 DEBUG(1,("samdb: search for %s %s not single valued\n",
308 attr_name, format));
309 talloc_free(res);
310 return -1;
311 }
312 }
313
314 *strs = talloc_array(mem_ctx, const char *, count+1);
315 if (! *strs) {
316 talloc_free(res);
317 return -1;
318 }
319
320 for (i=0;i<count;i++) {
321 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
322 }
323 (*strs)[count] = NULL;
324
325 return count;
326 }
327
328 /*
329 pull a uint from a result set.
330 */
samdb_result_uint(const struct ldb_message * msg,const char * attr,uint_t default_value)331 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
332 {
333 return ldb_msg_find_attr_as_uint(msg, attr, default_value);
334 }
335
336 /*
337 pull a (signed) int64 from a result set.
338 */
samdb_result_int64(const struct ldb_message * msg,const char * attr,int64_t default_value)339 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
340 {
341 return ldb_msg_find_attr_as_int64(msg, attr, default_value);
342 }
343
344 /*
345 pull a string from a result set.
346 */
samdb_result_string(const struct ldb_message * msg,const char * attr,const char * default_value)347 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
348 const char *default_value)
349 {
350 return ldb_msg_find_attr_as_string(msg, attr, default_value);
351 }
352
samdb_result_dn(struct ldb_context * ldb,TALLOC_CTX * mem_ctx,const struct ldb_message * msg,const char * attr,struct ldb_dn * default_value)353 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
354 const char *attr, struct ldb_dn *default_value)
355 {
356 struct ldb_dn *res_dn;
357 const char *string = samdb_result_string(msg, attr, NULL);
358 if (string == NULL) return default_value;
359 res_dn = ldb_dn_new(mem_ctx, ldb, string);
360 if ( ! ldb_dn_validate(res_dn)) {
361 talloc_free(res_dn);
362 return NULL;
363 }
364 return res_dn;
365 }
366
367 /*
368 pull a rid from a objectSid in a result set.
369 */
samdb_result_rid_from_sid(TALLOC_CTX * mem_ctx,const struct ldb_message * msg,const char * attr,uint32_t default_value)370 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
371 const char *attr, uint32_t default_value)
372 {
373 struct dom_sid *sid;
374 uint32_t rid;
375
376 sid = samdb_result_dom_sid(mem_ctx, msg, attr);
377 if (sid == NULL) {
378 return default_value;
379 }
380 rid = sid->sub_auths[sid->num_auths-1];
381 talloc_free(sid);
382 return rid;
383 }
384
385 /*
386 pull a dom_sid structure from a objectSid in a result set.
387 */
samdb_result_dom_sid(TALLOC_CTX * mem_ctx,const struct ldb_message * msg,const char * attr)388 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
389 const char *attr)
390 {
391 const struct ldb_val *v;
392 struct dom_sid *sid;
393 NTSTATUS status;
394 v = ldb_msg_find_ldb_val(msg, attr);
395 if (v == NULL) {
396 return NULL;
397 }
398 sid = talloc(mem_ctx, struct dom_sid);
399 if (sid == NULL) {
400 return NULL;
401 }
402 status = ndr_pull_struct_blob(v, sid, sid,
403 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
404 if (!NT_STATUS_IS_OK(status)) {
405 talloc_free(sid);
406 return NULL;
407 }
408 return sid;
409 }
410
411 /*
412 pull a guid structure from a objectGUID in a result set.
413 */
samdb_result_guid(const struct ldb_message * msg,const char * attr)414 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
415 {
416 const struct ldb_val *v;
417 NTSTATUS status;
418 struct GUID guid;
419 TALLOC_CTX *mem_ctx;
420
421 ZERO_STRUCT(guid);
422
423 v = ldb_msg_find_ldb_val(msg, attr);
424 if (!v) return guid;
425
426 mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
427 if (!mem_ctx) return guid;
428 status = ndr_pull_struct_blob(v, mem_ctx, &guid,
429 (ndr_pull_flags_fn_t)ndr_pull_GUID);
430 talloc_free(mem_ctx);
431 if (!NT_STATUS_IS_OK(status)) {
432 return guid;
433 }
434
435 return guid;
436 }
437
438 /*
439 pull a sid prefix from a objectSid in a result set.
440 this is used to find the domain sid for a user
441 */
samdb_result_sid_prefix(TALLOC_CTX * mem_ctx,const struct ldb_message * msg,const char * attr)442 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
443 const char *attr)
444 {
445 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
446 if (!sid || sid->num_auths < 1) return NULL;
447 sid->num_auths--;
448 return sid;
449 }
450
451 /*
452 pull a NTTIME in a result set.
453 */
samdb_result_nttime(struct ldb_message * msg,const char * attr,NTTIME default_value)454 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
455 {
456 const char *str = ldb_msg_find_attr_as_string(msg, attr, NULL);
457 if (!str) return default_value;
458 return nttime_from_string(str);
459 }
460
461 /*
462 pull a uint64_t from a result set.
463 */
samdb_result_uint64(struct ldb_message * msg,const char * attr,uint64_t default_value)464 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
465 {
466 return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
467 }
468
469
470 /*
471 construct the allow_password_change field from the PwdLastSet attribute and the
472 domain password settings
473 */
samdb_result_allow_password_change(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * domain_dn,struct ldb_message * msg,const char * attr)474 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
475 TALLOC_CTX *mem_ctx,
476 struct ldb_dn *domain_dn,
477 struct ldb_message *msg,
478 const char *attr)
479 {
480 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
481 int64_t minPwdAge;
482
483 if (attr_time == 0) {
484 return 0;
485 }
486
487 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
488
489 /* yes, this is a -= not a += as minPwdAge is stored as the negative
490 of the number of 100-nano-seconds */
491 attr_time -= minPwdAge;
492
493 return attr_time;
494 }
495
496 /*
497 construct the force_password_change field from the PwdLastSet attribute and the
498 domain password settings
499 */
samdb_result_force_password_change(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * domain_dn,struct ldb_message * msg)500 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
501 TALLOC_CTX *mem_ctx,
502 struct ldb_dn *domain_dn,
503 struct ldb_message *msg)
504 {
505 uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
506 uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
507 int64_t maxPwdAge;
508
509 if (user_flags & UF_DONT_EXPIRE_PASSWD) {
510 return 0x7FFFFFFFFFFFFFFFULL;
511 }
512
513 if (attr_time == 0) {
514 return 0;
515 }
516
517 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
518 if (maxPwdAge == 0) {
519 return 0;
520 } else {
521 attr_time -= maxPwdAge;
522 }
523
524 return attr_time;
525 }
526
527 /*
528 pull a samr_Password structutre from a result set.
529 */
samdb_result_hash(TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr)530 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
531 {
532 struct samr_Password *hash = NULL;
533 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
534 if (val && (val->length >= sizeof(hash->hash))) {
535 hash = talloc(mem_ctx, struct samr_Password);
536 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
537 }
538 return hash;
539 }
540
541 /*
542 pull an array of samr_Password structutres from a result set.
543 */
samdb_result_hashes(TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr,struct samr_Password ** hashes)544 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
545 const char *attr, struct samr_Password **hashes)
546 {
547 uint_t count = 0;
548 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
549 int i;
550
551 *hashes = NULL;
552 if (!val) {
553 return 0;
554 }
555 count = val->length / 16;
556 if (count == 0) {
557 return 0;
558 }
559
560 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
561 if (! *hashes) {
562 return 0;
563 }
564
565 for (i=0;i<count;i++) {
566 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
567 }
568
569 return count;
570 }
571
samdb_result_passwords(TALLOC_CTX * mem_ctx,struct ldb_message * msg,struct samr_Password ** lm_pwd,struct samr_Password ** nt_pwd)572 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
573 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
574 {
575 struct samr_Password *lmPwdHash, *ntPwdHash;
576 if (nt_pwd) {
577 int num_nt;
578 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
579 if (num_nt == 0) {
580 *nt_pwd = NULL;
581 } else if (num_nt > 1) {
582 return NT_STATUS_INTERNAL_DB_CORRUPTION;
583 } else {
584 *nt_pwd = &ntPwdHash[0];
585 }
586 }
587 if (lm_pwd) {
588 int num_lm;
589 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
590 if (num_lm == 0) {
591 *lm_pwd = NULL;
592 } else if (num_lm > 1) {
593 return NT_STATUS_INTERNAL_DB_CORRUPTION;
594 } else {
595 *lm_pwd = &lmPwdHash[0];
596 }
597 }
598 return NT_STATUS_OK;
599 }
600
601 /*
602 pull a samr_LogonHours structutre from a result set.
603 */
samdb_result_logon_hours(TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr)604 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
605 {
606 struct samr_LogonHours hours;
607 const int units_per_week = 168;
608 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
609 ZERO_STRUCT(hours);
610 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
611 if (!hours.bits) {
612 return hours;
613 }
614 hours.units_per_week = units_per_week;
615 memset(hours.bits, 0xFF, units_per_week);
616 if (val) {
617 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
618 }
619 return hours;
620 }
621
622 /*
623 pull a set of account_flags from a result set.
624 */
samdb_result_acct_flags(struct ldb_message * msg,const char * attr)625 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
626 {
627 uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0);
628 return samdb_uf2acb(userAccountControl);
629 }
630
631
632 /* Find an attribute, with a particular value */
samdb_find_attribute(struct ldb_context * ldb,const struct ldb_message * msg,const char * name,const char * value)633 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
634 const struct ldb_message *msg,
635 const char *name, const char *value)
636 {
637 int i;
638 struct ldb_message_element *el = ldb_msg_find_element(msg, name);
639 struct ldb_val v;
640
641 v.data = discard_const_p(uint8_t, value);
642 v.length = strlen(value);
643
644 if (!el) {
645 return NULL;
646 }
647
648 for (i=0;i<el->num_values;i++) {
649 if (strcasecmp(value, (char *)el->values[i].data) == 0) {
650 return el;
651 }
652 }
653
654 return NULL;
655 }
656
samdb_find_or_add_value(struct ldb_context * ldb,struct ldb_message * msg,const char * name,const char * set_value)657 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
658 {
659 if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
660 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
661 }
662 return LDB_SUCCESS;
663 }
664
samdb_find_or_add_attribute(struct ldb_context * ldb,struct ldb_message * msg,const char * name,const char * set_value)665 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
666 {
667 struct ldb_message_element *el;
668
669 el = ldb_msg_find_element(msg, name);
670 if (el) {
671 return LDB_SUCCESS;
672 }
673
674 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
675 }
676
677
678 /*
679 copy from a template record to a message
680 */
samdb_copy_template(struct ldb_context * ldb,struct ldb_message * msg,const char * filter,const char ** errstring)681 int samdb_copy_template(struct ldb_context *ldb,
682 struct ldb_message *msg, const char *filter,
683 const char **errstring)
684 {
685 struct ldb_result *res;
686 struct ldb_message *t;
687 int ret, i, j;
688 struct ldb_dn *basedn = ldb_dn_new(ldb, ldb, "cn=Templates");
689
690 *errstring = NULL;
691
692 /* pull the template record */
693 ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res);
694 talloc_free(basedn);
695 if (ret != LDB_SUCCESS) {
696 *errstring = talloc_steal(msg, ldb_errstring(ldb));
697 return ret;
698 }
699 if (res->count != 1) {
700 *errstring = talloc_asprintf(msg, "samdb_copy_template: ERROR: template '%s' matched %d records, expected 1\n", filter,
701 res->count);
702 talloc_free(res);
703 return LDB_ERR_OPERATIONS_ERROR;
704 }
705 t = res->msgs[0];
706
707 for (i = 0; i < t->num_elements; i++) {
708 struct ldb_message_element *el = &t->elements[i];
709 /* some elements should not be copied from the template */
710 if (strcasecmp(el->name, "cn") == 0 ||
711 strcasecmp(el->name, "name") == 0 ||
712 strcasecmp(el->name, "sAMAccountName") == 0 ||
713 strcasecmp(el->name, "sAMAccountName") == 0 ||
714 strcasecmp(el->name, "distinguishedName") == 0 ||
715 strcasecmp(el->name, "objectGUID") == 0) {
716 continue;
717 }
718 for (j = 0; j < el->num_values; j++) {
719 if (strcasecmp(el->name, "objectClass") == 0) {
720 if (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
721 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
722 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
723 strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
724 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
725 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
726 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0) {
727 continue;
728 }
729 ret = samdb_find_or_add_value(ldb, msg, el->name,
730 (char *)el->values[j].data);
731 if (ret) {
732 *errstring = talloc_asprintf(msg, "Adding objectClass %s failed.\n", el->values[j].data);
733 talloc_free(res);
734 return ret;
735 }
736 } else {
737 ret = samdb_find_or_add_attribute(ldb, msg, el->name,
738 (char *)el->values[j].data);
739 if (ret) {
740 *errstring = talloc_asprintf(msg, "Adding attribute %s failed.\n", el->name);
741 talloc_free(res);
742 return ret;
743 }
744 }
745 }
746 }
747
748 talloc_free(res);
749
750 return LDB_SUCCESS;
751 }
752
753
754 /*
755 add a string element to a message
756 */
samdb_msg_add_string(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,const char * str)757 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758 const char *attr_name, const char *str)
759 {
760 char *s = talloc_strdup(mem_ctx, str);
761 char *a = talloc_strdup(mem_ctx, attr_name);
762 if (s == NULL || a == NULL) {
763 return LDB_ERR_OPERATIONS_ERROR;
764 }
765 return ldb_msg_add_string(msg, a, s);
766 }
767
768 /*
769 add a dom_sid element to a message
770 */
samdb_msg_add_dom_sid(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,struct dom_sid * sid)771 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
772 const char *attr_name, struct dom_sid *sid)
773 {
774 struct ldb_val v;
775 NTSTATUS status;
776 status = ndr_push_struct_blob(&v, mem_ctx, sid,
777 (ndr_push_flags_fn_t)ndr_push_dom_sid);
778 if (!NT_STATUS_IS_OK(status)) {
779 return -1;
780 }
781 return ldb_msg_add_value(msg, attr_name, &v, NULL);
782 }
783
784
785 /*
786 add a delete element operation to a message
787 */
samdb_msg_add_delete(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name)788 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
789 const char *attr_name)
790 {
791 /* we use an empty replace rather than a delete, as it allows for
792 samdb_replace() to be used everywhere */
793 return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
794 }
795
796 /*
797 add a add attribute value to a message
798 */
samdb_msg_add_addval(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,const char * value)799 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
800 const char *attr_name, const char *value)
801 {
802 struct ldb_message_element *el;
803 char *a, *v;
804 int ret;
805 a = talloc_strdup(mem_ctx, attr_name);
806 if (a == NULL)
807 return -1;
808 v = talloc_strdup(mem_ctx, value);
809 if (v == NULL)
810 return -1;
811 ret = ldb_msg_add_string(msg, a, v);
812 if (ret != 0)
813 return ret;
814 el = ldb_msg_find_element(msg, a);
815 if (el == NULL)
816 return -1;
817 el->flags = LDB_FLAG_MOD_ADD;
818 return 0;
819 }
820
821 /*
822 add a delete attribute value to a message
823 */
samdb_msg_add_delval(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,const char * value)824 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
825 const char *attr_name, const char *value)
826 {
827 struct ldb_message_element *el;
828 char *a, *v;
829 int ret;
830 a = talloc_strdup(mem_ctx, attr_name);
831 if (a == NULL)
832 return -1;
833 v = talloc_strdup(mem_ctx, value);
834 if (v == NULL)
835 return -1;
836 ret = ldb_msg_add_string(msg, a, v);
837 if (ret != 0)
838 return ret;
839 el = ldb_msg_find_element(msg, a);
840 if (el == NULL)
841 return -1;
842 el->flags = LDB_FLAG_MOD_DELETE;
843 return 0;
844 }
845
846 /*
847 add a int element to a message
848 */
samdb_msg_add_int(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,int v)849 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
850 const char *attr_name, int v)
851 {
852 const char *s = talloc_asprintf(mem_ctx, "%d", v);
853 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
854 }
855
856 /*
857 add a uint_t element to a message
858 */
samdb_msg_add_uint(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,uint_t v)859 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
860 const char *attr_name, uint_t v)
861 {
862 const char *s = talloc_asprintf(mem_ctx, "%u", v);
863 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
864 }
865
866 /*
867 add a (signed) int64_t element to a message
868 */
samdb_msg_add_int64(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,int64_t v)869 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
870 const char *attr_name, int64_t v)
871 {
872 const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
873 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
874 }
875
876 /*
877 add a uint64_t element to a message
878 */
samdb_msg_add_uint64(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,uint64_t v)879 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
880 const char *attr_name, uint64_t v)
881 {
882 const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
883 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
884 }
885
886 /*
887 add a samr_Password element to a message
888 */
samdb_msg_add_hash(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,struct samr_Password * hash)889 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
890 const char *attr_name, struct samr_Password *hash)
891 {
892 struct ldb_val val;
893 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
894 if (!val.data) {
895 return -1;
896 }
897 val.length = 16;
898 return ldb_msg_add_value(msg, attr_name, &val, NULL);
899 }
900
901 /*
902 add a samr_Password array to a message
903 */
samdb_msg_add_hashes(TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,struct samr_Password * hashes,uint_t count)904 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
905 const char *attr_name, struct samr_Password *hashes, uint_t count)
906 {
907 struct ldb_val val;
908 int i;
909 val.data = talloc_array_size(mem_ctx, 16, count);
910 val.length = count*16;
911 if (!val.data) {
912 return -1;
913 }
914 for (i=0;i<count;i++) {
915 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
916 }
917 return ldb_msg_add_value(msg, attr_name, &val, NULL);
918 }
919
920 /*
921 add a acct_flags element to a message
922 */
samdb_msg_add_acct_flags(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,uint32_t v)923 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
924 const char *attr_name, uint32_t v)
925 {
926 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
927 }
928
929 /*
930 add a logon_hours element to a message
931 */
samdb_msg_add_logon_hours(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,struct samr_LogonHours * hours)932 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
933 const char *attr_name, struct samr_LogonHours *hours)
934 {
935 struct ldb_val val;
936 val.length = hours->units_per_week / 8;
937 val.data = hours->bits;
938 return ldb_msg_add_value(msg, attr_name, &val, NULL);
939 }
940
941 /*
942 add a general value element to a message
943 */
samdb_msg_add_value(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,const struct ldb_val * val)944 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
945 const char *attr_name, const struct ldb_val *val)
946 {
947 return ldb_msg_add_value(msg, attr_name, val, NULL);
948 }
949
950 /*
951 sets a general value element to a message
952 */
samdb_msg_set_value(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,const struct ldb_val * val)953 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
954 const char *attr_name, const struct ldb_val *val)
955 {
956 struct ldb_message_element *el;
957
958 el = ldb_msg_find_element(msg, attr_name);
959 if (el) {
960 el->num_values = 0;
961 }
962 return ldb_msg_add_value(msg, attr_name, val, NULL);
963 }
964
965 /*
966 set a string element in a message
967 */
samdb_msg_set_string(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg,const char * attr_name,const char * str)968 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
969 const char *attr_name, const char *str)
970 {
971 struct ldb_message_element *el;
972
973 el = ldb_msg_find_element(msg, attr_name);
974 if (el) {
975 el->num_values = 0;
976 }
977 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
978 }
979
980 /*
981 add a record
982 */
samdb_add(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg)983 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
984 {
985 return ldb_add(sam_ldb, msg);
986 }
987
988 /*
989 delete a record
990 */
samdb_delete(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_dn * dn)991 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
992 {
993 return ldb_delete(sam_ldb, dn);
994 }
995
996 /*
997 modify a record
998 */
samdb_modify(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg)999 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1000 {
1001 return ldb_modify(sam_ldb, msg);
1002 }
1003
1004 /*
1005 replace elements in a record
1006 */
samdb_replace(struct ldb_context * sam_ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg)1007 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1008 {
1009 int i;
1010
1011 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1012 for (i=0;i<msg->num_elements;i++) {
1013 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1014 }
1015
1016 /* modify the samdb record */
1017 return samdb_modify(sam_ldb, mem_ctx, msg);
1018 }
1019
1020 /*
1021 return a default security descriptor
1022 */
samdb_default_security_descriptor(TALLOC_CTX * mem_ctx)1023 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1024 {
1025 struct security_descriptor *sd;
1026
1027 sd = security_descriptor_initialise(mem_ctx);
1028
1029 return sd;
1030 }
1031
samdb_base_dn(struct ldb_context * sam_ctx)1032 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
1033 {
1034 return ldb_get_default_basedn(sam_ctx);
1035 }
1036
1037
samdb_partitions_dn(struct ldb_context * sam_ctx,TALLOC_CTX * mem_ctx)1038 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
1039 {
1040 struct ldb_dn *new_dn;
1041
1042 new_dn = ldb_dn_copy(mem_ctx, samdb_base_dn(sam_ctx));
1043 if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions,CN=Configuration")) {
1044 talloc_free(new_dn);
1045 return NULL;
1046 }
1047 return new_dn;
1048 }
1049
1050 /*
1051 work out the domain sid for the current open ldb
1052 */
samdb_domain_sid(struct ldb_context * ldb)1053 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
1054 {
1055 const char *attrs[] = { "rootDomainNamingContext", NULL };
1056 int ret;
1057 struct ldb_result *res = NULL;
1058 TALLOC_CTX *tmp_ctx;
1059 struct dom_sid *domain_sid;
1060 const char *basedn_s;
1061 struct ldb_dn *basedn;
1062
1063 /* see if we have a cached copy */
1064 domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
1065 if (domain_sid) {
1066 return domain_sid;
1067 }
1068
1069 tmp_ctx = talloc_new(ldb);
1070 if (tmp_ctx == NULL) {
1071 goto failed;
1072 }
1073
1074 basedn = ldb_dn_new(tmp_ctx, ldb, NULL);
1075 if (basedn == NULL) {
1076 goto failed;
1077 }
1078
1079 /* find the basedn of the domain from the rootdse */
1080 ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, attrs, &res);
1081 talloc_steal(tmp_ctx, res);
1082 if (ret != LDB_SUCCESS || res->count != 1) {
1083 goto failed;
1084 }
1085
1086 basedn_s = ldb_msg_find_attr_as_string(res->msgs[0], "rootDomainNamingContext", NULL);
1087 if (basedn_s == NULL) {
1088 goto failed;
1089 }
1090
1091 basedn = ldb_dn_new(tmp_ctx, ldb, basedn_s);
1092 if ( ! ldb_dn_validate(basedn)) {
1093 goto failed;
1094 }
1095
1096 /* find the domain_sid */
1097 domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, basedn,
1098 "objectSid", "objectClass=domainDNS");
1099 if (domain_sid == NULL) {
1100 goto failed;
1101 }
1102
1103 /* cache the domain_sid in the ldb */
1104 if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1105 goto failed;
1106 }
1107
1108 talloc_steal(ldb, domain_sid);
1109 talloc_free(tmp_ctx);
1110
1111 return domain_sid;
1112
1113 failed:
1114 DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1115 talloc_free(tmp_ctx);
1116 return NULL;
1117 }
1118
1119 /*
1120 check that a password is sufficiently complex
1121 */
samdb_password_complexity_ok(const char * pass)1122 static BOOL samdb_password_complexity_ok(const char *pass)
1123 {
1124 return check_password_quality(pass);
1125 }
1126
1127
1128
1129 /*
1130 set the user password using plaintext, obeying any user or domain
1131 password restrictions
1132
1133 note that this function doesn't actually store the result in the
1134 database, it just fills in the "mod" structure with ldb modify
1135 elements to setup the correct change when samdb_replace() is
1136 called. This allows the caller to combine the change with other
1137 changes (as is needed by some of the set user info levels)
1138
1139 The caller should probably have a transaction wrapping this
1140 */
samdb_set_password(struct ldb_context * ctx,TALLOC_CTX * mem_ctx,struct ldb_dn * user_dn,struct ldb_dn * domain_dn,struct ldb_message * mod,const char * new_pass,struct samr_Password * lmNewHash,struct samr_Password * ntNewHash,BOOL user_change,BOOL restrictions,enum samr_RejectReason * reject_reason,struct samr_DomInfo1 ** _dominfo)1141 _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1142 struct ldb_dn *user_dn,
1143 struct ldb_dn *domain_dn,
1144 struct ldb_message *mod,
1145 const char *new_pass,
1146 struct samr_Password *lmNewHash,
1147 struct samr_Password *ntNewHash,
1148 BOOL user_change,
1149 BOOL restrictions,
1150 enum samr_RejectReason *reject_reason,
1151 struct samr_DomInfo1 **_dominfo)
1152 {
1153 const char * const user_attrs[] = { "userAccountControl", "sambaLMPwdHistory",
1154 "sambaNTPwdHistory",
1155 "lmPwdHash", "ntPwdHash",
1156 "objectSid",
1157 "pwdLastSet", NULL };
1158 const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
1159 "maxPwdAge", "minPwdAge",
1160 "minPwdLength", NULL };
1161 NTTIME pwdLastSet;
1162 int64_t minPwdAge;
1163 uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1164 uint_t userAccountControl;
1165 struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1166 struct samr_Password local_lmNewHash, local_ntNewHash;
1167 int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1168 struct dom_sid *domain_sid;
1169 struct ldb_message **res;
1170 int count;
1171 time_t now = time(NULL);
1172 NTTIME now_nt;
1173 int i;
1174
1175 /* we need to know the time to compute password age */
1176 unix_to_nt_time(&now_nt, now);
1177
1178 /* pull all the user parameters */
1179 count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1180 if (count != 1) {
1181 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1182 }
1183 userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0);
1184 sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1185 "sambaLMPwdHistory", &sambaLMPwdHistory);
1186 sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0],
1187 "sambaNTPwdHistory", &sambaNTPwdHistory);
1188 lmPwdHash = samdb_result_hash(mem_ctx, res[0], "lmPwdHash");
1189 ntPwdHash = samdb_result_hash(mem_ctx, res[0], "ntPwdHash");
1190 pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0);
1191
1192 if (domain_dn) {
1193 /* pull the domain parameters */
1194 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1195 if (count != 1) {
1196 DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
1197 ldb_dn_get_linearized(domain_dn),
1198 ldb_dn_get_linearized(user_dn)));
1199 return NT_STATUS_NO_SUCH_DOMAIN;
1200 }
1201 } else {
1202 /* work out the domain sid, and pull the domain from there */
1203 domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1204 if (domain_sid == NULL) {
1205 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1206 }
1207
1208 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
1209 "(objectSid=%s)",
1210 ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1211 if (count != 1) {
1212 DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
1213 dom_sid_string(mem_ctx, domain_sid),
1214 ldb_dn_get_linearized(user_dn)));
1215 return NT_STATUS_NO_SUCH_DOMAIN;
1216 }
1217 }
1218
1219 pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0);
1220 pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0);
1221 minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0);
1222 minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0);
1223
1224 if (_dominfo) {
1225 struct samr_DomInfo1 *dominfo;
1226 /* on failure we need to fill in the reject reasons */
1227 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1228 if (dominfo == NULL) {
1229 return NT_STATUS_NO_MEMORY;
1230 }
1231 dominfo->min_password_length = minPwdLength;
1232 dominfo->password_properties = pwdProperties;
1233 dominfo->password_history_length = pwdHistoryLength;
1234 dominfo->max_password_age = minPwdAge;
1235 dominfo->min_password_age = minPwdAge;
1236 *_dominfo = dominfo;
1237 }
1238
1239 if (new_pass) {
1240 /* check the various password restrictions */
1241 if (restrictions && minPwdLength > strlen_m(new_pass)) {
1242 if (reject_reason) {
1243 *reject_reason = SAMR_REJECT_TOO_SHORT;
1244 }
1245 return NT_STATUS_PASSWORD_RESTRICTION;
1246 }
1247
1248 /* possibly check password complexity */
1249 if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1250 !samdb_password_complexity_ok(new_pass)) {
1251 if (reject_reason) {
1252 *reject_reason = SAMR_REJECT_COMPLEXITY;
1253 }
1254 return NT_STATUS_PASSWORD_RESTRICTION;
1255 }
1256
1257 /* compute the new nt and lm hashes */
1258 if (E_deshash(new_pass, local_lmNewHash.hash)) {
1259 lmNewHash = &local_lmNewHash;
1260 }
1261 if (!E_md4hash(new_pass, local_ntNewHash.hash)) {
1262 /* If we can't convert this password to UCS2, then we should not accept it */
1263 if (reject_reason) {
1264 *reject_reason = SAMR_REJECT_OTHER;
1265 }
1266 return NT_STATUS_PASSWORD_RESTRICTION;
1267 }
1268 ntNewHash = &local_ntNewHash;
1269 }
1270
1271 if (restrictions && user_change) {
1272 /* are all password changes disallowed? */
1273 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1274 if (reject_reason) {
1275 *reject_reason = SAMR_REJECT_OTHER;
1276 }
1277 return NT_STATUS_PASSWORD_RESTRICTION;
1278 }
1279
1280 /* can this user change password? */
1281 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1282 if (reject_reason) {
1283 *reject_reason = SAMR_REJECT_OTHER;
1284 }
1285 return NT_STATUS_PASSWORD_RESTRICTION;
1286 }
1287
1288 /* yes, this is a minus. The ages are in negative 100nsec units! */
1289 if (pwdLastSet - minPwdAge > now_nt) {
1290 if (reject_reason) {
1291 *reject_reason = SAMR_REJECT_OTHER;
1292 }
1293 return NT_STATUS_PASSWORD_RESTRICTION;
1294 }
1295
1296 /* check the immediately past password */
1297 if (pwdHistoryLength > 0) {
1298 if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1299 if (reject_reason) {
1300 *reject_reason = SAMR_REJECT_IN_HISTORY;
1301 }
1302 return NT_STATUS_PASSWORD_RESTRICTION;
1303 }
1304 if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1305 if (reject_reason) {
1306 *reject_reason = SAMR_REJECT_IN_HISTORY;
1307 }
1308 return NT_STATUS_PASSWORD_RESTRICTION;
1309 }
1310 }
1311
1312 /* check the password history */
1313 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1314 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1315
1316 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1317 if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1318 if (reject_reason) {
1319 *reject_reason = SAMR_REJECT_IN_HISTORY;
1320 }
1321 return NT_STATUS_PASSWORD_RESTRICTION;
1322 }
1323 }
1324 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1325 if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1326 if (reject_reason) {
1327 *reject_reason = SAMR_REJECT_IN_HISTORY;
1328 }
1329 return NT_STATUS_PASSWORD_RESTRICTION;
1330 }
1331 }
1332 }
1333
1334 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1335
1336 /* the password is acceptable. Start forming the new fields */
1337 if (new_pass) {
1338 /* if we know the cleartext, then only set it.
1339 * Modules in ldb will set all the appropriate
1340 * hashes */
1341 CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod,
1342 "sambaPassword", new_pass));
1343 } else {
1344 /* We don't have the cleartext, so delete the old one
1345 * and set what we have of the hashes */
1346 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword"));
1347
1348 if (lmNewHash) {
1349 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "lmPwdHash", lmNewHash));
1350 } else {
1351 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "lmPwdHash"));
1352 }
1353
1354 if (ntNewHash) {
1355 CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "ntPwdHash", ntNewHash));
1356 } else {
1357 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "ntPwdHash"));
1358 }
1359 }
1360
1361 return NT_STATUS_OK;
1362 }
1363
1364
1365 /*
1366 set the user password using plaintext, obeying any user or domain
1367 password restrictions
1368
1369 This wrapper function takes a SID as input, rather than a user DN,
1370 and actually performs the password change
1371
1372 */
samdb_set_password_sid(struct ldb_context * ctx,TALLOC_CTX * mem_ctx,const struct dom_sid * user_sid,const char * new_pass,struct samr_Password * lmNewHash,struct samr_Password * ntNewHash,BOOL user_change,BOOL restrictions,enum samr_RejectReason * reject_reason,struct samr_DomInfo1 ** _dominfo)1373 _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
1374 const struct dom_sid *user_sid,
1375 const char *new_pass,
1376 struct samr_Password *lmNewHash,
1377 struct samr_Password *ntNewHash,
1378 BOOL user_change,
1379 BOOL restrictions,
1380 enum samr_RejectReason *reject_reason,
1381 struct samr_DomInfo1 **_dominfo)
1382 {
1383 NTSTATUS nt_status;
1384 struct ldb_dn *user_dn;
1385 struct ldb_message *msg;
1386 int ret;
1387
1388 ret = ldb_transaction_start(ctx);
1389 if (ret) {
1390 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1391 return NT_STATUS_TRANSACTION_ABORTED;
1392 }
1393
1394 user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
1395 "(&(objectSid=%s)(objectClass=user))",
1396 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1397 if (!user_dn) {
1398 ldb_transaction_cancel(ctx);
1399 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1400 dom_sid_string(mem_ctx, user_sid)));
1401 return NT_STATUS_NO_SUCH_USER;
1402 }
1403
1404 msg = ldb_msg_new(mem_ctx);
1405 if (msg == NULL) {
1406 ldb_transaction_cancel(ctx);
1407 return NT_STATUS_NO_MEMORY;
1408 }
1409
1410 msg->dn = ldb_dn_copy(msg, user_dn);
1411 if (!msg->dn) {
1412 ldb_transaction_cancel(ctx);
1413 return NT_STATUS_NO_MEMORY;
1414 }
1415
1416 nt_status = samdb_set_password(ctx, mem_ctx,
1417 user_dn, NULL,
1418 msg, new_pass,
1419 lmNewHash, ntNewHash,
1420 user_change, /* This is a password set, not change */
1421 restrictions, /* run restriction tests */
1422 reject_reason, _dominfo);
1423 if (!NT_STATUS_IS_OK(nt_status)) {
1424 ldb_transaction_cancel(ctx);
1425 return nt_status;
1426 }
1427
1428 /* modify the samdb record */
1429 ret = samdb_replace(ctx, mem_ctx, msg);
1430 if (ret != 0) {
1431 ldb_transaction_cancel(ctx);
1432 return NT_STATUS_ACCESS_DENIED;
1433 }
1434
1435 ret = ldb_transaction_commit(ctx);
1436 if (ret != 0) {
1437 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1438 ldb_dn_get_linearized(msg->dn),
1439 ldb_errstring(ctx)));
1440 return NT_STATUS_TRANSACTION_ABORTED;
1441 }
1442 return NT_STATUS_OK;
1443 }
1444
1445 /****************************************************************************
1446 Create the SID list for this user.
1447 ****************************************************************************/
security_token_create(TALLOC_CTX * mem_ctx,struct dom_sid * user_sid,struct dom_sid * group_sid,int n_groupSIDs,struct dom_sid ** groupSIDs,BOOL is_authenticated,struct security_token ** token)1448 NTSTATUS security_token_create(TALLOC_CTX *mem_ctx,
1449 struct dom_sid *user_sid,
1450 struct dom_sid *group_sid,
1451 int n_groupSIDs,
1452 struct dom_sid **groupSIDs,
1453 BOOL is_authenticated,
1454 struct security_token **token)
1455 {
1456 struct security_token *ptoken;
1457 int i;
1458 NTSTATUS status;
1459
1460 ptoken = security_token_initialise(mem_ctx);
1461 NT_STATUS_HAVE_NO_MEMORY(ptoken);
1462
1463 ptoken->sids = talloc_array(ptoken, struct dom_sid *, n_groupSIDs + 5);
1464 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids);
1465
1466 ptoken->user_sid = talloc_reference(ptoken, user_sid);
1467 ptoken->group_sid = talloc_reference(ptoken, group_sid);
1468 ptoken->privilege_mask = 0;
1469
1470 ptoken->sids[0] = ptoken->user_sid;
1471 ptoken->sids[1] = ptoken->group_sid;
1472
1473 /*
1474 * Finally add the "standard" SIDs.
1475 * The only difference between guest and "anonymous"
1476 * is the addition of Authenticated_Users.
1477 */
1478 ptoken->sids[2] = dom_sid_parse_talloc(ptoken->sids, SID_WORLD);
1479 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[2]);
1480 ptoken->sids[3] = dom_sid_parse_talloc(ptoken->sids, SID_NT_NETWORK);
1481 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[3]);
1482 ptoken->num_sids = 4;
1483
1484 if (is_authenticated) {
1485 ptoken->sids[4] = dom_sid_parse_talloc(ptoken->sids, SID_NT_AUTHENTICATED_USERS);
1486 NT_STATUS_HAVE_NO_MEMORY(ptoken->sids[4]);
1487 ptoken->num_sids++;
1488 }
1489
1490 for (i = 0; i < n_groupSIDs; i++) {
1491 size_t check_sid_idx;
1492 for (check_sid_idx = 1;
1493 check_sid_idx < ptoken->num_sids;
1494 check_sid_idx++) {
1495 if (dom_sid_equal(ptoken->sids[check_sid_idx], groupSIDs[i])) {
1496 break;
1497 }
1498 }
1499
1500 if (check_sid_idx == ptoken->num_sids) {
1501 ptoken->sids[ptoken->num_sids++] = talloc_reference(ptoken->sids, groupSIDs[i]);
1502 }
1503 }
1504
1505 /* setup the privilege mask for this token */
1506 status = samdb_privilege_setup(ptoken);
1507 if (!NT_STATUS_IS_OK(status)) {
1508 talloc_free(ptoken);
1509 return status;
1510 }
1511
1512 security_token_debug(10, ptoken);
1513
1514 *token = ptoken;
1515
1516 return NT_STATUS_OK;
1517 }
1518
1519
samdb_create_foreign_security_principal(struct ldb_context * sam_ctx,TALLOC_CTX * mem_ctx,struct dom_sid * sid,struct ldb_dn ** ret_dn)1520 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
1521 struct dom_sid *sid, struct ldb_dn **ret_dn)
1522 {
1523 struct ldb_message *msg;
1524 struct ldb_dn *basedn;
1525 const char *sidstr;
1526 int ret;
1527
1528 sidstr = dom_sid_string(mem_ctx, sid);
1529 NT_STATUS_HAVE_NO_MEMORY(sidstr);
1530
1531 /* We might have to create a ForeignSecurityPrincipal, even if this user
1532 * is in our own domain */
1533
1534 msg = ldb_msg_new(mem_ctx);
1535 if (msg == NULL) {
1536 return NT_STATUS_NO_MEMORY;
1537 }
1538
1539 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1540 * put the ForeignSecurityPrincipals? d_state->domain_dn does
1541 * not work, this is wrong for the Builtin domain, there's no
1542 * cn=For...,cn=Builtin,dc={BASEDN}. -- vl
1543 */
1544
1545 basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1546 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1547
1548 if (basedn == NULL) {
1549 DEBUG(0, ("Failed to find DN for "
1550 "ForeignSecurityPrincipal container\n"));
1551 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1552 }
1553
1554 /* add core elements to the ldb_message for the alias */
1555 msg->dn = ldb_dn_copy(mem_ctx, basedn);
1556 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1557 return NT_STATUS_NO_MEMORY;
1558
1559 samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1560 "objectClass",
1561 "foreignSecurityPrincipal");
1562
1563 /* create the alias */
1564 ret = samdb_add(sam_ctx, mem_ctx, msg);
1565 if (ret != 0) {
1566 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1567 "record %s: %s\n",
1568 ldb_dn_get_linearized(msg->dn),
1569 ldb_errstring(sam_ctx)));
1570 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1571 }
1572 *ret_dn = msg->dn;
1573 return NT_STATUS_OK;
1574 }
1575