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