1 /*
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2010
5    Copyright (C) Gerald Carter                             2003
6    Copyright (C) Stefan Metzmacher                         2005
7    Copyright (C) Matthias Dieter Wallnöfer                 2009
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "includes.h"
24 #include "system/time.h"
25 #include "auth/auth.h"
26 #include <ldb.h>
27 #include "dsdb/samdb/samdb.h"
28 #include "libcli/security/security.h"
29 #include "auth/auth_sam.h"
30 #include "dsdb/common/util.h"
31 #include "libcli/ldap/ldap_ndr.h"
32 #include "param/param.h"
33 #include "librpc/gen_ndr/ndr_winbind_c.h"
34 
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_AUTH
37 
38 #define KRBTGT_ATTRS				\
39 	/* required for the krb5 kdc */		\
40 	"objectClass",				\
41 	"sAMAccountName",			\
42 	"userPrincipalName",			\
43 	"servicePrincipalName",			\
44 	"msDS-KeyVersionNumber",		\
45 	"msDS-SecondaryKrbTgtNumber",		\
46 	"msDS-SupportedEncryptionTypes",	\
47 	"supplementalCredentials",		\
48 	"msDS-AllowedToDelegateTo",		\
49 						\
50 	/* passwords */				\
51 	"dBCSPwd",				\
52 	"unicodePwd",				\
53 						\
54 	"userAccountControl",	                \
55 	"msDS-User-Account-Control-Computed",	\
56 	"objectSid",				\
57 						\
58 	"pwdLastSet",				\
59 	"msDS-UserPasswordExpiryTimeComputed",	\
60 	"accountExpires"
61 
62 const char *krbtgt_attrs[] = {
63 	KRBTGT_ATTRS, NULL
64 };
65 
66 const char *server_attrs[] = {
67 	KRBTGT_ATTRS, NULL
68 };
69 
70 const char *user_attrs[] = {
71 	/*
72 	 * This ordering (having msDS-ResultantPSO first) is
73 	 * important.  By processing this attribute first it is
74 	 * available in the operational module for the other PSO
75 	 * attribute calcuations to use.
76 	 */
77 	"msDS-ResultantPSO",
78 
79 	KRBTGT_ATTRS,
80 
81 	"logonHours",
82 
83 	/*
84 	 * To allow us to zero the badPwdCount and lockoutTime on
85 	 * successful logon, without database churn
86 	 */
87 	"lockoutTime",
88 
89 	/*
90 	 * Needed for SendToSAM requests
91 	 */
92 	"objectGUID",
93 
94 	/* check 'allowed workstations' */
95 	"userWorkstations",
96 
97 	/* required for user_info_dc, not access control: */
98 	"displayName",
99 	"scriptPath",
100 	"profilePath",
101 	"homeDirectory",
102 	"homeDrive",
103 	"lastLogon",
104 	"lastLogonTimestamp",
105 	"lastLogoff",
106 	"accountExpires",
107 	"badPwdCount",
108 	"logonCount",
109 	"primaryGroupID",
110 	"memberOf",
111 	"badPasswordTime",
112 	"lmPwdHistory",
113 	"ntPwdHistory",
114 	NULL,
115 };
116 
117 /****************************************************************************
118  Check if a user is allowed to logon at this time. Note this is the
119  servers local time, as logon hours are just specified as a weekly
120  bitmask.
121 ****************************************************************************/
122 
logon_hours_ok(struct ldb_message * msg,const char * name_for_logs)123 static bool logon_hours_ok(struct ldb_message *msg, const char *name_for_logs)
124 {
125 	/* In logon hours first bit is Sunday from 12AM to 1AM */
126 	const struct ldb_val *hours;
127 	struct tm *utctime;
128 	time_t lasttime;
129 	const char *asct;
130 	uint8_t bitmask, bitpos;
131 
132 	hours = ldb_msg_find_ldb_val(msg, "logonHours");
133 	if (!hours) {
134 		DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
135 		return true;
136 	}
137 
138 	if (hours->length != 168/8) {
139 		DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
140 		return true;
141 	}
142 
143 	lasttime = time(NULL);
144 	utctime = gmtime(&lasttime);
145 	if (!utctime) {
146 		DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
147 			name_for_logs));
148 		return false;
149 	}
150 
151 	/* find the corresponding byte and bit */
152 	bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
153 	bitmask = 1 << (bitpos % 8);
154 
155 	if (! (hours->data[bitpos/8] & bitmask)) {
156 		struct tm *t = localtime(&lasttime);
157 		if (!t) {
158 			asct = "INVALID TIME";
159 		} else {
160 			asct = asctime(t);
161 			if (!asct) {
162 				asct = "INVALID TIME";
163 			}
164 		}
165 
166 		DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
167 			  "logon at this time (%s).\n",
168 			  name_for_logs, asct ));
169 		return false;
170 	}
171 
172 	asct = asctime(utctime);
173 	DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
174 		name_for_logs, asct ? asct : "UNKNOWN TIME" ));
175 
176 	return true;
177 }
178 
179 /****************************************************************************
180  Do a specific test for a SAM_ACCOUNT being valid for this connection
181  (ie not disabled, expired and the like).
182 ****************************************************************************/
authsam_account_ok(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,uint32_t logon_parameters,struct ldb_dn * domain_dn,struct ldb_message * msg,const char * logon_workstation,const char * name_for_logs,bool allow_domain_trust,bool password_change)183 _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
184 				     struct ldb_context *sam_ctx,
185 				     uint32_t logon_parameters,
186 				     struct ldb_dn *domain_dn,
187 				     struct ldb_message *msg,
188 				     const char *logon_workstation,
189 				     const char *name_for_logs,
190 				     bool allow_domain_trust,
191 				     bool password_change)
192 {
193 	uint16_t acct_flags;
194 	const char *workstation_list;
195 	NTTIME acct_expiry;
196 	NTTIME must_change_time;
197 	struct timeval tv_now = timeval_current();
198 	NTTIME now = timeval_to_nttime(&tv_now);
199 
200 	DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
201 
202 	acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
203 
204 	acct_expiry = samdb_result_account_expires(msg);
205 
206 	/* Check for when we must change this password, taking the
207 	 * userAccountControl flags into account */
208 	must_change_time = samdb_result_nttime(msg,
209 			"msDS-UserPasswordExpiryTimeComputed", 0);
210 
211 	workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL);
212 
213 	/* Quit if the account was disabled. */
214 	if (acct_flags & ACB_DISABLED) {
215 		DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
216 		return NT_STATUS_ACCOUNT_DISABLED;
217 	}
218 
219 	/* Quit if the account was locked out. */
220 	if (acct_flags & ACB_AUTOLOCK) {
221 		DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
222 		return NT_STATUS_ACCOUNT_LOCKED_OUT;
223 	}
224 
225 	/* Test account expire time */
226 	if (now > acct_expiry) {
227 		DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
228 		DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
229 			 nt_time_string(mem_ctx, acct_expiry)));
230 		return NT_STATUS_ACCOUNT_EXPIRED;
231 	}
232 
233 	/* check for immediate expiry "must change at next logon" (but not if this is a password change request) */
234 	if ((must_change_time == 0) && !password_change) {
235 		DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n",
236 			 name_for_logs));
237 		return NT_STATUS_PASSWORD_MUST_CHANGE;
238 	}
239 
240 	/* check for expired password (but not if this is a password change request) */
241 	if ((must_change_time < now) && !password_change) {
242 		DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n",
243 			 name_for_logs));
244 		DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n",
245 			 nt_time_string(mem_ctx, must_change_time)));
246 		return NT_STATUS_PASSWORD_EXPIRED;
247 	}
248 
249 	/* Test workstation. Workstation list is comma separated. */
250 	if (logon_workstation && workstation_list && *workstation_list) {
251 		bool invalid_ws = true;
252 		int i;
253 		char **workstations = str_list_make(mem_ctx, workstation_list, ",");
254 
255 		for (i = 0; workstations && workstations[i]; i++) {
256 			DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
257 				  workstations[i], logon_workstation));
258 
259 			if (strequal(workstations[i], logon_workstation)) {
260 				invalid_ws = false;
261 				break;
262 			}
263 		}
264 
265 		talloc_free(workstations);
266 
267 		if (invalid_ws) {
268 			return NT_STATUS_INVALID_WORKSTATION;
269 		}
270 	}
271 
272 	if (!logon_hours_ok(msg, name_for_logs)) {
273 		return NT_STATUS_INVALID_LOGON_HOURS;
274 	}
275 
276 	if (!allow_domain_trust) {
277 		if (acct_flags & ACB_DOMTRUST) {
278 			DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
279 			return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
280 		}
281 	}
282 	if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
283 		if (acct_flags & ACB_SVRTRUST) {
284 			DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
285 			return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
286 		}
287 	}
288 	if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
289 		/* TODO: this fails with current solaris client. We
290 		   need to work with Gordon to work out why */
291 		if (acct_flags & ACB_WSTRUST) {
292 			DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
293 			return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
294 		}
295 	}
296 
297 	return NT_STATUS_OK;
298 }
299 
authsam_domain_group_filter(TALLOC_CTX * mem_ctx,char ** _filter)300 static NTSTATUS authsam_domain_group_filter(TALLOC_CTX *mem_ctx,
301 					    char **_filter)
302 {
303 	char *filter = NULL;
304 
305 	*_filter = NULL;
306 
307 	filter = talloc_strdup(mem_ctx, "(&(objectClass=group)");
308 	if (filter == NULL) {
309 		return NT_STATUS_NO_MEMORY;
310 	}
311 
312 	/*
313 	 * Skip all builtin groups, they're added later.
314 	 */
315 	filter = talloc_asprintf_append_buffer(filter,
316 				"(!(groupType:1.2.840.113556.1.4.803:=%u))",
317 				GROUP_TYPE_BUILTIN_LOCAL_GROUP);
318 	if (filter == NULL) {
319 		return NT_STATUS_NO_MEMORY;
320 	}
321 	/*
322 	 * Only include security groups.
323 	 */
324 	filter = talloc_asprintf_append_buffer(filter,
325 				"(groupType:1.2.840.113556.1.4.803:=%u))",
326 				GROUP_TYPE_SECURITY_ENABLED);
327 	if (filter == NULL) {
328 		return NT_STATUS_NO_MEMORY;
329 	}
330 
331 	*_filter = filter;
332 	return NT_STATUS_OK;
333 }
334 
authsam_make_user_info_dc(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,const char * netbios_name,const char * domain_name,const char * dns_domain_name,struct ldb_dn * domain_dn,struct ldb_message * msg,DATA_BLOB user_sess_key,DATA_BLOB lm_sess_key,struct auth_user_info_dc ** _user_info_dc)335 _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx,
336 					   struct ldb_context *sam_ctx,
337 					   const char *netbios_name,
338 					   const char *domain_name,
339 					   const char *dns_domain_name,
340 					   struct ldb_dn *domain_dn,
341 					   struct ldb_message *msg,
342 					   DATA_BLOB user_sess_key,
343 					   DATA_BLOB lm_sess_key,
344 					   struct auth_user_info_dc **_user_info_dc)
345 {
346 	NTSTATUS status;
347 	struct auth_user_info_dc *user_info_dc;
348 	struct auth_user_info *info;
349 	const char *str = NULL;
350 	char *filter = NULL;
351 	/* SIDs for the account and his primary group */
352 	struct dom_sid *account_sid;
353 	struct dom_sid_buf buf;
354 	const char *primary_group_dn;
355 	DATA_BLOB primary_group_blob;
356 	/* SID structures for the expanded group memberships */
357 	struct dom_sid *sids = NULL;
358 	unsigned int num_sids = 0, i;
359 	struct dom_sid *domain_sid;
360 	TALLOC_CTX *tmp_ctx;
361 	struct ldb_message_element *el;
362 
363 	user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
364 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
365 
366 	tmp_ctx = talloc_new(user_info_dc);
367 	if (tmp_ctx == NULL) {
368 		TALLOC_FREE(user_info_dc);
369 		return NT_STATUS_NO_MEMORY;
370 	}
371 
372 	sids = talloc_array(user_info_dc, struct dom_sid, 2);
373 	if (sids == NULL) {
374 		TALLOC_FREE(user_info_dc);
375 		return NT_STATUS_NO_MEMORY;
376 	}
377 
378 	num_sids = 2;
379 
380 	account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
381 	if (account_sid == NULL) {
382 		TALLOC_FREE(user_info_dc);
383 		return NT_STATUS_NO_MEMORY;
384 	}
385 
386 	status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
387 	if (!NT_STATUS_IS_OK(status)) {
388 		talloc_free(user_info_dc);
389 		return status;
390 	}
391 
392 	sids[PRIMARY_USER_SID_INDEX] = *account_sid;
393 	sids[PRIMARY_GROUP_SID_INDEX] = *domain_sid;
394 	sid_append_rid(&sids[PRIMARY_GROUP_SID_INDEX], ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0));
395 
396 	/*
397 	 * Filter out builtin groups from this token. We will search
398 	 * for builtin groups later, and not include them in the PAC
399 	 * or SamLogon validation info.
400 	 */
401 	status = authsam_domain_group_filter(tmp_ctx, &filter);
402 	if (!NT_STATUS_IS_OK(status)) {
403 		TALLOC_FREE(user_info_dc);
404 		return status;
405 	}
406 
407 	primary_group_dn = talloc_asprintf(
408 		tmp_ctx,
409 		"<SID=%s>",
410 		dom_sid_str_buf(&sids[PRIMARY_GROUP_SID_INDEX], &buf));
411 	if (primary_group_dn == NULL) {
412 		TALLOC_FREE(user_info_dc);
413 		return NT_STATUS_NO_MEMORY;
414 	}
415 
416 	primary_group_blob = data_blob_string_const(primary_group_dn);
417 
418 	/* Expands the primary group - this function takes in
419 	 * memberOf-like values, so we fake one up with the
420 	 * <SID=S-...> format of DN and then let it expand
421 	 * them, as long as they meet the filter - so only
422 	 * domain groups, not builtin groups
423 	 *
424 	 * The primary group is still treated specially, so we set the
425 	 * 'only childs' flag to true
426 	 */
427 	status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
428 					   user_info_dc, &sids, &num_sids);
429 	if (!NT_STATUS_IS_OK(status)) {
430 		talloc_free(user_info_dc);
431 		return status;
432 	}
433 
434 	/* Expands the additional groups */
435 	el = ldb_msg_find_element(msg, "memberOf");
436 	for (i = 0; el && i < el->num_values; i++) {
437 		/* This function takes in memberOf values and expands
438 		 * them, as long as they meet the filter - so only
439 		 * domain groups, not builtin groups */
440 		status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
441 						   user_info_dc, &sids, &num_sids);
442 		if (!NT_STATUS_IS_OK(status)) {
443 			talloc_free(user_info_dc);
444 			return status;
445 		}
446 	}
447 
448 	user_info_dc->sids = sids;
449 	user_info_dc->num_sids = num_sids;
450 
451 	user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info);
452 	NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info);
453 
454 	info->account_name = talloc_steal(info,
455 		ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
456 
457 	info->user_principal_name = talloc_steal(info,
458 		ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL));
459 	if (info->user_principal_name == NULL && dns_domain_name != NULL) {
460 		info->user_principal_name = talloc_asprintf(info, "%s@%s",
461 					info->account_name,
462 					dns_domain_name);
463 		if (info->user_principal_name == NULL) {
464 			TALLOC_FREE(user_info_dc);
465 			return NT_STATUS_NO_MEMORY;
466 		}
467 		info->user_principal_constructed = true;
468 	}
469 
470 	info->domain_name = talloc_strdup(info, domain_name);
471 	if (info->domain_name == NULL) {
472 		TALLOC_FREE(user_info_dc);
473 		return NT_STATUS_NO_MEMORY;
474 	}
475 
476 	if (dns_domain_name != NULL) {
477 		info->dns_domain_name = talloc_strdup(info, dns_domain_name);
478 		if (info->dns_domain_name == NULL) {
479 			TALLOC_FREE(user_info_dc);
480 			return NT_STATUS_NO_MEMORY;
481 		}
482 	}
483 
484 	str = ldb_msg_find_attr_as_string(msg, "displayName", "");
485 	info->full_name = talloc_strdup(info, str);
486 	if (info->full_name == NULL) {
487 		TALLOC_FREE(user_info_dc);
488 		return NT_STATUS_NO_MEMORY;
489 	}
490 
491 	str = ldb_msg_find_attr_as_string(msg, "scriptPath", "");
492 	info->logon_script = talloc_strdup(info, str);
493 	if (info->logon_script == NULL) {
494 		TALLOC_FREE(user_info_dc);
495 		return NT_STATUS_NO_MEMORY;
496 	}
497 
498 	str = ldb_msg_find_attr_as_string(msg, "profilePath", "");
499 	info->profile_path = talloc_strdup(info, str);
500 	if (info->profile_path == NULL) {
501 		TALLOC_FREE(user_info_dc);
502 		return NT_STATUS_NO_MEMORY;
503 	}
504 
505 	str = ldb_msg_find_attr_as_string(msg, "homeDirectory", "");
506 	info->home_directory = talloc_strdup(info, str);
507 	if (info->home_directory == NULL) {
508 		TALLOC_FREE(user_info_dc);
509 		return NT_STATUS_NO_MEMORY;
510 	}
511 
512 	str = ldb_msg_find_attr_as_string(msg, "homeDrive", "");
513 	info->home_drive = talloc_strdup(info, str);
514 	if (info->home_drive == NULL) {
515 		TALLOC_FREE(user_info_dc);
516 		return NT_STATUS_NO_MEMORY;
517 	}
518 
519 	info->logon_server = talloc_strdup(info, netbios_name);
520 	if (info->logon_server == NULL) {
521 		TALLOC_FREE(user_info_dc);
522 		return NT_STATUS_NO_MEMORY;
523 	}
524 
525 	info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
526 	info->last_logoff = samdb_result_last_logoff(msg);
527 	info->acct_expiry = samdb_result_account_expires(msg);
528 	info->last_password_change = samdb_result_nttime(msg,
529 		"pwdLastSet", 0);
530 	info->allow_password_change
531 		= samdb_result_allow_password_change(sam_ctx, mem_ctx,
532 			domain_dn, msg, "pwdLastSet");
533 	info->force_password_change = samdb_result_nttime(msg,
534 		"msDS-UserPasswordExpiryTimeComputed", 0);
535 	info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0);
536 	info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount",
537 		0);
538 
539 	info->acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
540 
541 	user_info_dc->user_session_key = data_blob_talloc(user_info_dc,
542 							 user_sess_key.data,
543 							 user_sess_key.length);
544 	if (user_sess_key.data) {
545 		if (user_info_dc->user_session_key.data == NULL) {
546 			TALLOC_FREE(user_info_dc);
547 			return NT_STATUS_NO_MEMORY;
548 		}
549 	}
550 	user_info_dc->lm_session_key = data_blob_talloc(user_info_dc,
551 						       lm_sess_key.data,
552 						       lm_sess_key.length);
553 	if (lm_sess_key.data) {
554 		if (user_info_dc->lm_session_key.data == NULL) {
555 			TALLOC_FREE(user_info_dc);
556 			return NT_STATUS_NO_MEMORY;
557 		}
558 	}
559 
560 	if (info->acct_flags & ACB_SVRTRUST) {
561 		/* the SID_NT_ENTERPRISE_DCS SID gets added into the
562 		   PAC */
563 		user_info_dc->sids = talloc_realloc(user_info_dc,
564 						   user_info_dc->sids,
565 						   struct dom_sid,
566 						   user_info_dc->num_sids+1);
567 		if (user_info_dc->sids == NULL) {
568 			TALLOC_FREE(user_info_dc);
569 			return NT_STATUS_NO_MEMORY;
570 		}
571 		user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs;
572 		user_info_dc->num_sids++;
573 	}
574 
575 	if ((info->acct_flags & (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) ==
576 	    (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) {
577 		/* the DOMAIN_RID_ENTERPRISE_READONLY_DCS PAC */
578 		user_info_dc->sids = talloc_realloc(user_info_dc,
579 						   user_info_dc->sids,
580 						   struct dom_sid,
581 						   user_info_dc->num_sids+1);
582 		if (user_info_dc->sids == NULL) {
583 			TALLOC_FREE(user_info_dc);
584 			return NT_STATUS_NO_MEMORY;
585 		}
586 		user_info_dc->sids[user_info_dc->num_sids] = *domain_sid;
587 		sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids],
588 			    DOMAIN_RID_ENTERPRISE_READONLY_DCS);
589 		user_info_dc->num_sids++;
590 	}
591 
592 	info->authenticated = true;
593 
594 	talloc_free(tmp_ctx);
595 	*_user_info_dc = user_info_dc;
596 
597 	return NT_STATUS_OK;
598 }
599 
authsam_update_user_info_dc(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,struct auth_user_info_dc * user_info_dc)600 _PUBLIC_ NTSTATUS authsam_update_user_info_dc(TALLOC_CTX *mem_ctx,
601 			struct ldb_context *sam_ctx,
602 			struct auth_user_info_dc *user_info_dc)
603 {
604 	char *filter = NULL;
605 	NTSTATUS status;
606 	uint32_t i;
607 	uint32_t n = 0;
608 
609 	/*
610 	 * This function exists to expand group memberships
611 	 * in the local domain (forest), as the token
612 	 * may come from a different domain.
613 	 */
614 
615 	/*
616 	 * Filter out builtin groups from this token. We will search
617 	 * for builtin groups later.
618 	 */
619 	status = authsam_domain_group_filter(mem_ctx, &filter);
620 	if (!NT_STATUS_IS_OK(status)) {
621 		TALLOC_FREE(user_info_dc);
622 		return status;
623 	}
624 
625 	/*
626 	 * We loop only over the existing number of
627 	 * sids.
628 	 */
629 	n = user_info_dc->num_sids;
630 	for (i = 0; i < n; i++) {
631 		struct dom_sid *sid = &user_info_dc->sids[i];
632 		struct dom_sid_buf sid_buf;
633 		char dn_str[sizeof(sid_buf.buf)*2];
634 		DATA_BLOB dn_blob = data_blob_null;
635 
636 		snprintf(dn_str,
637 			sizeof(dn_str),
638 			"<SID=%s>",
639 			dom_sid_str_buf(sid, &sid_buf));
640 		dn_blob = data_blob_string_const(dn_str);
641 
642 		/*
643 		 * We already have the SID in the token, so set
644 		 * 'only childs' flag to true and add all
645 		 * groups which match the filter.
646 		 */
647 		status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
648 						   true, filter,
649 						   user_info_dc,
650 						   &user_info_dc->sids,
651 						   &user_info_dc->num_sids);
652 		if (!NT_STATUS_IS_OK(status)) {
653 			return status;
654 		}
655 	}
656 
657 	return NT_STATUS_OK;
658 }
659 
sam_get_results_principal(struct ldb_context * sam_ctx,TALLOC_CTX * mem_ctx,const char * principal,const char ** attrs,struct ldb_dn ** domain_dn,struct ldb_message ** msg)660 NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
661 				   TALLOC_CTX *mem_ctx, const char *principal,
662 				   const char **attrs,
663 				   struct ldb_dn **domain_dn,
664 				   struct ldb_message **msg)
665 {
666 	struct ldb_dn *user_dn;
667 	NTSTATUS nt_status;
668 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
669 	int ret;
670 
671 	if (!tmp_ctx) {
672 		return NT_STATUS_NO_MEMORY;
673 	}
674 
675 	nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal,
676 					      &user_dn, domain_dn);
677 	if (!NT_STATUS_IS_OK(nt_status)) {
678 		talloc_free(tmp_ctx);
679 		return nt_status;
680 	}
681 
682 	/* pull the user attributes */
683 	ret = dsdb_search_one(sam_ctx, tmp_ctx, msg, user_dn,
684 			      LDB_SCOPE_BASE, attrs,
685 			      DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
686 			      "(objectClass=*)");
687 	if (ret != LDB_SUCCESS) {
688 		talloc_free(tmp_ctx);
689 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
690 	}
691 	talloc_steal(mem_ctx, *msg);
692 	talloc_steal(mem_ctx, *domain_dn);
693 	talloc_free(tmp_ctx);
694 
695 	return NT_STATUS_OK;
696 }
697 
698 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
699 
700  Supply either a principal or a DN
701 */
authsam_get_user_info_dc_principal(TALLOC_CTX * mem_ctx,struct loadparm_context * lp_ctx,struct ldb_context * sam_ctx,const char * principal,struct ldb_dn * user_dn,struct auth_user_info_dc ** user_info_dc)702 NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
703 					   struct loadparm_context *lp_ctx,
704 					   struct ldb_context *sam_ctx,
705 					   const char *principal,
706 					   struct ldb_dn *user_dn,
707 					   struct auth_user_info_dc **user_info_dc)
708 {
709 	NTSTATUS nt_status;
710 	DATA_BLOB user_sess_key = data_blob(NULL, 0);
711 	DATA_BLOB lm_sess_key = data_blob(NULL, 0);
712 
713 	struct ldb_message *msg;
714 	struct ldb_dn *domain_dn;
715 
716 	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
717 	if (!tmp_ctx) {
718 		return NT_STATUS_NO_MEMORY;
719 	}
720 
721 	if (principal) {
722 		nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
723 						      user_attrs, &domain_dn, &msg);
724 		if (!NT_STATUS_IS_OK(nt_status)) {
725 			talloc_free(tmp_ctx);
726 			return nt_status;
727 		}
728 	} else if (user_dn) {
729 		struct dom_sid *user_sid, *domain_sid;
730 		int ret;
731 		/* pull the user attributes */
732 		ret = dsdb_search_one(sam_ctx, tmp_ctx, &msg, user_dn,
733 				      LDB_SCOPE_BASE, user_attrs,
734 				      DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
735 				      "(objectClass=*)");
736 		if (ret == LDB_ERR_NO_SUCH_OBJECT) {
737 			talloc_free(tmp_ctx);
738 			return NT_STATUS_NO_SUCH_USER;
739 		} else if (ret != LDB_SUCCESS) {
740 			talloc_free(tmp_ctx);
741 			return NT_STATUS_INTERNAL_DB_CORRUPTION;
742 		}
743 
744 		user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
745 
746 		nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
747 		if (!NT_STATUS_IS_OK(nt_status)) {
748 			return nt_status;
749 		}
750 
751 		domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
752 					  "(&(objectSid=%s)(objectClass=domain))",
753 					    ldap_encode_ndr_dom_sid(tmp_ctx, domain_sid));
754 		if (!domain_dn) {
755 			struct dom_sid_buf buf;
756 			DEBUG(3, ("authsam_get_user_info_dc_principal: Failed to find domain with: SID %s\n",
757 				  dom_sid_str_buf(domain_sid, &buf)));
758 			return NT_STATUS_NO_SUCH_USER;
759 		}
760 
761 	} else {
762 		return NT_STATUS_INVALID_PARAMETER;
763 	}
764 
765 	nt_status = authsam_make_user_info_dc(tmp_ctx, sam_ctx,
766 					     lpcfg_netbios_name(lp_ctx),
767 					     lpcfg_sam_name(lp_ctx),
768 					     lpcfg_sam_dnsname(lp_ctx),
769 					     domain_dn,
770 					     msg,
771 					     user_sess_key, lm_sess_key,
772 					     user_info_dc);
773 	if (!NT_STATUS_IS_OK(nt_status)) {
774 		talloc_free(tmp_ctx);
775 		return nt_status;
776 	}
777 
778 	talloc_steal(mem_ctx, *user_info_dc);
779 	talloc_free(tmp_ctx);
780 
781 	return NT_STATUS_OK;
782 }
783 
784 /*
785  * Returns the details for the Password Settings Object (PSO), if one applies
786  * the user.
787  */
authsam_get_user_pso(struct ldb_context * sam_ctx,TALLOC_CTX * mem_ctx,struct ldb_message * user_msg,struct ldb_message ** pso_msg)788 static int authsam_get_user_pso(struct ldb_context *sam_ctx,
789 				TALLOC_CTX *mem_ctx,
790 				struct ldb_message *user_msg,
791 				struct ldb_message **pso_msg)
792 {
793 	const char *attrs[] = { "msDS-LockoutThreshold",
794 				"msDS-LockoutObservationWindow",
795 				NULL };
796 	struct ldb_dn *pso_dn = NULL;
797 	struct ldb_result *res = NULL;
798 	int ret;
799 
800 	/* check if the user has a PSO that applies to it */
801 	pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
802 					 "msDS-ResultantPSO");
803 
804 	if (pso_dn != NULL) {
805 		ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
806 		if (ret != LDB_SUCCESS) {
807 			return ret;
808 		}
809 
810 		*pso_msg = res->msgs[0];
811 	}
812 
813 	return LDB_SUCCESS;
814 }
815 
authsam_update_bad_pwd_count(struct ldb_context * sam_ctx,struct ldb_message * msg,struct ldb_dn * domain_dn)816 NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
817 				      struct ldb_message *msg,
818 				      struct ldb_dn *domain_dn)
819 {
820 	const char *attrs[] = { "lockoutThreshold",
821 				"lockOutObservationWindow",
822 				"lockoutDuration",
823 				"pwdProperties",
824 				NULL };
825 	int ret;
826 	NTSTATUS status;
827 	struct ldb_result *domain_res;
828 	struct ldb_message *msg_mod = NULL;
829 	struct ldb_message *pso_msg = NULL;
830 	TALLOC_CTX *mem_ctx;
831 
832 	mem_ctx = talloc_new(msg);
833 	if (mem_ctx == NULL) {
834 		return NT_STATUS_NO_MEMORY;
835 	}
836 
837 	ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
838 	if (ret != LDB_SUCCESS) {
839 		TALLOC_FREE(mem_ctx);
840 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
841 	}
842 
843 	ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
844 	if (ret != LDB_SUCCESS) {
845 
846 		/*
847 		 * fallback to using the domain defaults so that we still
848 		 * record the bad password attempt
849 		 */
850 		DBG_ERR("Error (%d) checking PSO for %s",
851 			ret, ldb_dn_get_linearized(msg->dn));
852 	}
853 
854 	status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
855 					   msg, domain_res->msgs[0], pso_msg,
856 					   &msg_mod);
857 	if (!NT_STATUS_IS_OK(status)) {
858 		TALLOC_FREE(mem_ctx);
859 		return status;
860 	}
861 
862 	if (msg_mod != NULL) {
863 		struct ldb_request *req;
864 
865 		ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
866 					msg_mod,
867 					NULL,
868 					NULL,
869 					ldb_op_default_callback,
870 					NULL);
871 		if (ret != LDB_SUCCESS) {
872 			goto done;
873 		}
874 
875 		ret = ldb_request_add_control(req,
876 					      DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
877 					      false, NULL);
878 		if (ret != LDB_SUCCESS) {
879 			talloc_free(req);
880 			goto done;
881 		}
882 
883 		ret = dsdb_autotransaction_request(sam_ctx, req);
884 		talloc_free(req);
885 	}
886 
887 done:
888 	if (ret != LDB_SUCCESS) {
889 		DBG_ERR("Failed to update badPwdCount, badPasswordTime or "
890 			"set lockoutTime on %s: %s\n",
891 			ldb_dn_get_linearized(msg->dn),
892 			ldb_errstring(sam_ctx));
893 		TALLOC_FREE(mem_ctx);
894 		return NT_STATUS_INTERNAL_ERROR;
895 	}
896 
897 	TALLOC_FREE(mem_ctx);
898 	return NT_STATUS_OK;
899 }
900 
901 
authsam_update_lastlogon_timestamp(struct ldb_context * sam_ctx,struct ldb_message * msg_mod,struct ldb_dn * domain_dn,NTTIME old_timestamp,NTTIME now)902 static NTSTATUS authsam_update_lastlogon_timestamp(struct ldb_context *sam_ctx,
903 					    struct ldb_message *msg_mod,
904 					    struct ldb_dn *domain_dn,
905 					    NTTIME old_timestamp,
906 					    NTTIME now)
907 {
908 	/*
909 	 * We only set lastLogonTimestamp if the current value is older than
910 	 * now - msDS-LogonTimeSyncInterval days.
911 	 *
912 	 * msDS-LogonTimeSyncInterval is an int32_t number of days, while
913 	 * lastLogonTimestamp is in the 64 bit 100ns NTTIME format.
914 	 *
915 	 * The docs say: "the initial update, after the domain functional
916 	 * level is raised to DS_BEHAVIOR_WIN2003 or higher, is calculated as
917 	 * 14 days minus a random percentage of 5 days", but we aren't doing
918 	 * that. The blogosphere seems to think that this randomised update
919 	 * happens everytime, but [MS-ADA1] doesn't agree.
920 	 *
921 	 * Dochelp referred us to the following blog post:
922 	 * http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
923 	 *
924 	 * en msDS-LogonTimeSyncInterval is zero, the lastLogonTimestamp is
925 	 * not changed.
926 	 */
927 	static const char *attrs[] = { "msDS-LogonTimeSyncInterval",
928 					NULL };
929 	int ret;
930 	struct ldb_result *domain_res = NULL;
931 	TALLOC_CTX *mem_ctx = NULL;
932 	int32_t sync_interval;
933 	NTTIME sync_interval_nt;
934 
935 	mem_ctx = talloc_new(msg_mod);
936 	if (mem_ctx == NULL) {
937 		return NT_STATUS_NO_MEMORY;
938 	}
939 
940 	ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
941 			     0);
942 	if (ret != LDB_SUCCESS || domain_res->count != 1) {
943 		TALLOC_FREE(mem_ctx);
944 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
945 	}
946 
947 	sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
948 						 "msDS-LogonTimeSyncInterval",
949 						 14);
950 	DEBUG(5, ("sync interval is %d\n", sync_interval));
951 	if (sync_interval == 0){
952 		/*
953 		 * Setting msDS-LogonTimeSyncInterval to zero is how you ask
954 		 * that nothing happens here.
955 		 */
956 		TALLOC_FREE(mem_ctx);
957 		return NT_STATUS_OK;
958 	}
959 	else if (sync_interval >= 5){
960 		/*
961 		 * Subtract "a random percentage of 5" days. Presumably this
962 		 * percentage is between 0 and 100, and modulus is accurate
963 		 * enough.
964 		 */
965 		uint32_t r = generate_random() % 6;
966 		sync_interval -= r;
967 		DEBUG(5, ("randomised sync interval is %d (-%d)\n", sync_interval, r));
968 	}
969 	/* In the case where sync_interval < 5 there is no randomisation */
970 
971 	sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
972 
973 	DEBUG(5, ("old timestamp is %lld, threshold %lld, diff %lld\n",
974 		  (long long int)old_timestamp,
975 		  (long long int)(now - sync_interval_nt),
976 		  (long long int)(old_timestamp - now + sync_interval_nt)));
977 
978 	if (old_timestamp > now){
979 		DEBUG(0, ("lastLogonTimestamp is in the future! (%lld > %lld)\n",
980 			  (long long int)old_timestamp, (long long int)now));
981 		/* then what? */
982 
983 	} else if (old_timestamp < now - sync_interval_nt){
984 		DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
985 			  (long long int)now));
986 
987 		/* The time has come to update lastLogonTimestamp */
988 		ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
989 					  "lastLogonTimestamp", now);
990 
991 		if (ret != LDB_SUCCESS) {
992 			TALLOC_FREE(mem_ctx);
993 			return NT_STATUS_NO_MEMORY;
994 		}
995 	}
996 	TALLOC_FREE(mem_ctx);
997 	return NT_STATUS_OK;
998 }
999 
1000 /****************************************************************************
1001  Look for the specified user in the sam, return ldb result structures
1002 ****************************************************************************/
1003 
authsam_search_account(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,const char * account_name,struct ldb_dn * domain_dn,struct ldb_message ** ret_msg)1004 NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
1005 					 const char *account_name,
1006 					 struct ldb_dn *domain_dn,
1007 					 struct ldb_message **ret_msg)
1008 {
1009 	int ret;
1010 
1011 	/* pull the user attributes */
1012 	ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
1013 			      user_attrs,
1014 			      DSDB_SEARCH_SHOW_EXTENDED_DN,
1015 			      "(&(sAMAccountName=%s)(objectclass=user))",
1016 			      ldb_binary_encode_string(mem_ctx, account_name));
1017 	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1018 		DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n",
1019 			 account_name, ldb_dn_get_linearized(domain_dn)));
1020 		return NT_STATUS_NO_SUCH_USER;
1021 	}
1022 	if (ret != LDB_SUCCESS) {
1023 		return NT_STATUS_INTERNAL_DB_CORRUPTION;
1024 	}
1025 
1026 	return NT_STATUS_OK;
1027 }
1028 
1029 
1030 /* Reset the badPwdCount to zero and update the lastLogon time. */
authsam_logon_success_accounting(struct ldb_context * sam_ctx,const struct ldb_message * msg,struct ldb_dn * domain_dn,bool interactive_or_kerberos,struct netr_SendToSamBase ** send_to_sam)1031 NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
1032 					  const struct ldb_message *msg,
1033 					  struct ldb_dn *domain_dn,
1034 					  bool interactive_or_kerberos,
1035 					  struct netr_SendToSamBase **send_to_sam)
1036 {
1037 	int ret;
1038 	NTSTATUS status;
1039 	int badPwdCount;
1040 	int dbBadPwdCount;
1041 	int64_t lockoutTime;
1042 	struct ldb_message *msg_mod;
1043 	TALLOC_CTX *mem_ctx;
1044 	struct timeval tv_now;
1045 	NTTIME now;
1046 	NTTIME lastLogonTimestamp;
1047 	bool am_rodc = false;
1048 
1049 	mem_ctx = talloc_new(msg);
1050 	if (mem_ctx == NULL) {
1051 		return NT_STATUS_NO_MEMORY;
1052 	}
1053 
1054 	lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
1055 	dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
1056 	if (interactive_or_kerberos) {
1057 		badPwdCount = dbBadPwdCount;
1058 	} else {
1059 		badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
1060 								 domain_dn, msg);
1061 	}
1062 	lastLogonTimestamp =
1063 		ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
1064 
1065 	DEBUG(5, ("lastLogonTimestamp is %lld\n",
1066 		  (long long int)lastLogonTimestamp));
1067 
1068 	msg_mod = ldb_msg_new(mem_ctx);
1069 	if (msg_mod == NULL) {
1070 		TALLOC_FREE(mem_ctx);
1071 		return NT_STATUS_NO_MEMORY;
1072 	}
1073 	msg_mod->dn = msg->dn;
1074 
1075 	if (lockoutTime != 0) {
1076 		/*
1077 		 * This implies "badPwdCount" = 0, see samldb_lockout_time()
1078 		 */
1079 		ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
1080 		if (ret != LDB_SUCCESS) {
1081 			TALLOC_FREE(mem_ctx);
1082 			return NT_STATUS_NO_MEMORY;
1083 		}
1084 	} else if (badPwdCount != 0) {
1085 		ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
1086 		if (ret != LDB_SUCCESS) {
1087 			TALLOC_FREE(mem_ctx);
1088 			return NT_STATUS_NO_MEMORY;
1089 		}
1090 	}
1091 
1092 	tv_now = timeval_current();
1093 	now = timeval_to_nttime(&tv_now);
1094 
1095 	if (interactive_or_kerberos ||
1096 	    (badPwdCount != 0 && lockoutTime == 0)) {
1097 		ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1098 					  "lastLogon", now);
1099 		if (ret != LDB_SUCCESS) {
1100 			TALLOC_FREE(mem_ctx);
1101 			return NT_STATUS_NO_MEMORY;
1102 		}
1103 	}
1104 
1105 	if (interactive_or_kerberos) {
1106 		int logonCount;
1107 
1108 		logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
1109 
1110 		logonCount += 1;
1111 
1112 		ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1113 					"logonCount", logonCount);
1114 		if (ret != LDB_SUCCESS) {
1115 			TALLOC_FREE(mem_ctx);
1116 			return NT_STATUS_NO_MEMORY;
1117 		}
1118 	} else {
1119 		/* Set an unset logonCount to 0 on first successful login */
1120 		if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
1121 			ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1122 						"logonCount", 0);
1123 			if (ret != LDB_SUCCESS) {
1124 				TALLOC_FREE(mem_ctx);
1125 				return NT_STATUS_NO_MEMORY;
1126 			}
1127 		}
1128 	}
1129 
1130 	ret = samdb_rodc(sam_ctx, &am_rodc);
1131 	if (ret != LDB_SUCCESS) {
1132 		TALLOC_FREE(mem_ctx);
1133 		return NT_STATUS_INTERNAL_ERROR;
1134 	}
1135 
1136 	if (!am_rodc) {
1137 		status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
1138 							    lastLogonTimestamp, now);
1139 		if (!NT_STATUS_IS_OK(status)) {
1140 			TALLOC_FREE(mem_ctx);
1141 			return NT_STATUS_NO_MEMORY;
1142 		}
1143 	} else {
1144 		/* Perform the (async) SendToSAM calls for MS-SAMS */
1145 		if (dbBadPwdCount != 0 && send_to_sam != NULL) {
1146 			struct netr_SendToSamBase *base_msg;
1147 			struct GUID guid = samdb_result_guid(msg, "objectGUID");
1148 			base_msg = talloc_zero(msg, struct netr_SendToSamBase);
1149 
1150 			base_msg->message_type = SendToSamResetBadPasswordCount;
1151 			base_msg->message_size = 16;
1152 			base_msg->message.reset_bad_password.guid = guid;
1153 			*send_to_sam = base_msg;
1154 		}
1155 	}
1156 
1157 	if (msg_mod->num_elements > 0) {
1158 		unsigned int i;
1159 		struct ldb_request *req;
1160 
1161 		/* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1162 		for (i=0;i<msg_mod->num_elements;i++) {
1163 			msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1164 		}
1165 
1166 		ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
1167 					msg_mod,
1168 					NULL,
1169 					NULL,
1170 					ldb_op_default_callback,
1171 					NULL);
1172 		if (ret != LDB_SUCCESS) {
1173 			goto done;
1174 		}
1175 
1176 		ret = ldb_request_add_control(req,
1177 					      DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1178 					      false, NULL);
1179 		if (ret != LDB_SUCCESS) {
1180 			talloc_free(req);
1181 			goto done;
1182 		}
1183 
1184 		ret = dsdb_autotransaction_request(sam_ctx, req);
1185 		talloc_free(req);
1186 	}
1187 
1188 done:
1189 	if (ret != LDB_SUCCESS) {
1190 		DEBUG(0, ("Failed to set badPwdCount and lockoutTime "
1191 			  "to 0 and/or  lastlogon to now (%lld) "
1192 			  "%s: %s\n", (long long int)now,
1193 			  ldb_dn_get_linearized(msg_mod->dn),
1194 			  ldb_errstring(sam_ctx)));
1195 		TALLOC_FREE(mem_ctx);
1196 		return NT_STATUS_INTERNAL_ERROR;
1197 	}
1198 
1199 	TALLOC_FREE(mem_ctx);
1200 	return NT_STATUS_OK;
1201 }
1202