Line data Source code
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 :
123 44562 : 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 44562 : hours = ldb_msg_find_ldb_val(msg, "logonHours");
133 44562 : if (!hours) {
134 44560 : DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
135 42816 : return true;
136 : }
137 :
138 2 : if (hours->length != 168/8) {
139 0 : DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
140 0 : return true;
141 : }
142 :
143 2 : lasttime = time(NULL);
144 2 : utctime = gmtime(&lasttime);
145 2 : if (!utctime) {
146 0 : DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
147 : name_for_logs));
148 0 : return false;
149 : }
150 :
151 : /* find the corresponding byte and bit */
152 2 : bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
153 2 : bitmask = 1 << (bitpos % 8);
154 :
155 2 : if (! (hours->data[bitpos/8] & bitmask)) {
156 0 : struct tm *t = localtime(&lasttime);
157 0 : if (!t) {
158 0 : asct = "INVALID TIME";
159 : } else {
160 0 : asct = asctime(t);
161 0 : if (!asct) {
162 0 : asct = "INVALID TIME";
163 : }
164 : }
165 :
166 0 : 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 0 : return false;
170 : }
171 :
172 2 : asct = asctime(utctime);
173 2 : 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 2 : 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 : ****************************************************************************/
183 45342 : _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 45342 : struct timeval tv_now = timeval_current();
198 45342 : NTTIME now = timeval_to_nttime(&tv_now);
199 :
200 45342 : DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
201 :
202 45342 : acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
203 :
204 45342 : 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 45342 : must_change_time = samdb_result_nttime(msg,
209 : "msDS-UserPasswordExpiryTimeComputed", 0);
210 :
211 45342 : workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL);
212 :
213 : /* Quit if the account was disabled. */
214 45342 : if (acct_flags & ACB_DISABLED) {
215 426 : DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
216 426 : return NT_STATUS_ACCOUNT_DISABLED;
217 : }
218 :
219 : /* Quit if the account was locked out. */
220 44916 : if (acct_flags & ACB_AUTOLOCK) {
221 0 : DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
222 0 : return NT_STATUS_ACCOUNT_LOCKED_OUT;
223 : }
224 :
225 : /* Test account expire time */
226 44916 : if (now > acct_expiry) {
227 0 : DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
228 0 : DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
229 : nt_time_string(mem_ctx, acct_expiry)));
230 0 : 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 44916 : if ((must_change_time == 0) && !password_change) {
235 11 : DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n",
236 : name_for_logs));
237 11 : return NT_STATUS_PASSWORD_MUST_CHANGE;
238 : }
239 :
240 : /* check for expired password (but not if this is a password change request) */
241 44905 : if ((must_change_time < now) && !password_change) {
242 0 : DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n",
243 : name_for_logs));
244 0 : DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n",
245 : nt_time_string(mem_ctx, must_change_time)));
246 0 : return NT_STATUS_PASSWORD_EXPIRED;
247 : }
248 :
249 : /* Test workstation. Workstation list is comma separated. */
250 44905 : if (logon_workstation && workstation_list && *workstation_list) {
251 343 : bool invalid_ws = true;
252 : int i;
253 343 : char **workstations = str_list_make(mem_ctx, workstation_list, ",");
254 :
255 686 : for (i = 0; workstations && workstations[i]; i++) {
256 343 : DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
257 : workstations[i], logon_workstation));
258 :
259 343 : if (strequal(workstations[i], logon_workstation)) {
260 0 : invalid_ws = false;
261 0 : break;
262 : }
263 : }
264 :
265 343 : talloc_free(workstations);
266 :
267 343 : if (invalid_ws) {
268 343 : return NT_STATUS_INVALID_WORKSTATION;
269 : }
270 : }
271 :
272 44562 : if (!logon_hours_ok(msg, name_for_logs)) {
273 0 : return NT_STATUS_INVALID_LOGON_HOURS;
274 : }
275 :
276 44562 : if (!allow_domain_trust) {
277 18219 : if (acct_flags & ACB_DOMTRUST) {
278 0 : DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
279 0 : return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
280 : }
281 : }
282 44562 : if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
283 10098 : if (acct_flags & ACB_SVRTRUST) {
284 0 : DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
285 0 : return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
286 : }
287 : }
288 44562 : 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 9072 : if (acct_flags & ACB_WSTRUST) {
292 342 : DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
293 342 : return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
294 : }
295 : }
296 :
297 44220 : return NT_STATUS_OK;
298 : }
299 :
300 85167 : static NTSTATUS authsam_domain_group_filter(TALLOC_CTX *mem_ctx,
301 : char **_filter)
302 : {
303 85167 : char *filter = NULL;
304 :
305 85167 : *_filter = NULL;
306 :
307 85167 : filter = talloc_strdup(mem_ctx, "(&(objectClass=group)");
308 85167 : if (filter == NULL) {
309 0 : return NT_STATUS_NO_MEMORY;
310 : }
311 :
312 : /*
313 : * Skip all builtin groups, they're added later.
314 : */
315 85167 : filter = talloc_asprintf_append_buffer(filter,
316 : "(!(groupType:1.2.840.113556.1.4.803:=%u))",
317 : GROUP_TYPE_BUILTIN_LOCAL_GROUP);
318 85167 : if (filter == NULL) {
319 0 : return NT_STATUS_NO_MEMORY;
320 : }
321 : /*
322 : * Only include security groups.
323 : */
324 85167 : filter = talloc_asprintf_append_buffer(filter,
325 : "(groupType:1.2.840.113556.1.4.803:=%u))",
326 : GROUP_TYPE_SECURITY_ENABLED);
327 85167 : if (filter == NULL) {
328 0 : return NT_STATUS_NO_MEMORY;
329 : }
330 :
331 85167 : *_filter = filter;
332 85167 : return NT_STATUS_OK;
333 : }
334 :
335 45047 : _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 45047 : const char *str = NULL;
350 45047 : 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 45047 : struct dom_sid *sids = NULL;
358 45047 : 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 45047 : user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
364 45047 : NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
365 :
366 45047 : tmp_ctx = talloc_new(user_info_dc);
367 45047 : if (tmp_ctx == NULL) {
368 0 : TALLOC_FREE(user_info_dc);
369 0 : return NT_STATUS_NO_MEMORY;
370 : }
371 :
372 45047 : sids = talloc_array(user_info_dc, struct dom_sid, 2);
373 45047 : if (sids == NULL) {
374 0 : TALLOC_FREE(user_info_dc);
375 0 : return NT_STATUS_NO_MEMORY;
376 : }
377 :
378 45047 : num_sids = 2;
379 :
380 45047 : account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
381 45047 : if (account_sid == NULL) {
382 0 : TALLOC_FREE(user_info_dc);
383 0 : return NT_STATUS_NO_MEMORY;
384 : }
385 :
386 45047 : status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
387 45047 : if (!NT_STATUS_IS_OK(status)) {
388 0 : talloc_free(user_info_dc);
389 0 : return status;
390 : }
391 :
392 45047 : sids[PRIMARY_USER_SID_INDEX] = *account_sid;
393 45047 : sids[PRIMARY_GROUP_SID_INDEX] = *domain_sid;
394 45047 : 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 45047 : status = authsam_domain_group_filter(tmp_ctx, &filter);
402 45047 : if (!NT_STATUS_IS_OK(status)) {
403 0 : TALLOC_FREE(user_info_dc);
404 0 : return status;
405 : }
406 :
407 86024 : primary_group_dn = talloc_asprintf(
408 : tmp_ctx,
409 : "<SID=%s>",
410 45047 : dom_sid_str_buf(&sids[PRIMARY_GROUP_SID_INDEX], &buf));
411 45047 : if (primary_group_dn == NULL) {
412 0 : TALLOC_FREE(user_info_dc);
413 0 : return NT_STATUS_NO_MEMORY;
414 : }
415 :
416 45047 : 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 45047 : status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
428 : user_info_dc, &sids, &num_sids);
429 45047 : if (!NT_STATUS_IS_OK(status)) {
430 0 : talloc_free(user_info_dc);
431 0 : return status;
432 : }
433 :
434 : /* Expands the additional groups */
435 45047 : el = ldb_msg_find_element(msg, "memberOf");
436 200034 : 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 154987 : status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
441 : user_info_dc, &sids, &num_sids);
442 154987 : if (!NT_STATUS_IS_OK(status)) {
443 0 : talloc_free(user_info_dc);
444 0 : return status;
445 : }
446 : }
447 :
448 45047 : user_info_dc->sids = sids;
449 45047 : user_info_dc->num_sids = num_sids;
450 :
451 45047 : user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info);
452 45047 : NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info);
453 :
454 45047 : info->account_name = talloc_steal(info,
455 : ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
456 :
457 45047 : info->user_principal_name = talloc_steal(info,
458 : ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL));
459 45047 : if (info->user_principal_name == NULL && dns_domain_name != NULL) {
460 38474 : info->user_principal_name = talloc_asprintf(info, "%s@%s",
461 : info->account_name,
462 : dns_domain_name);
463 38474 : if (info->user_principal_name == NULL) {
464 0 : TALLOC_FREE(user_info_dc);
465 0 : return NT_STATUS_NO_MEMORY;
466 : }
467 38474 : info->user_principal_constructed = true;
468 : }
469 :
470 45047 : info->domain_name = talloc_strdup(info, domain_name);
471 45047 : if (info->domain_name == NULL) {
472 0 : TALLOC_FREE(user_info_dc);
473 0 : return NT_STATUS_NO_MEMORY;
474 : }
475 :
476 45047 : if (dns_domain_name != NULL) {
477 44951 : info->dns_domain_name = talloc_strdup(info, dns_domain_name);
478 44951 : if (info->dns_domain_name == NULL) {
479 0 : TALLOC_FREE(user_info_dc);
480 0 : return NT_STATUS_NO_MEMORY;
481 : }
482 : }
483 :
484 45047 : str = ldb_msg_find_attr_as_string(msg, "displayName", "");
485 45047 : info->full_name = talloc_strdup(info, str);
486 45047 : if (info->full_name == NULL) {
487 0 : TALLOC_FREE(user_info_dc);
488 0 : return NT_STATUS_NO_MEMORY;
489 : }
490 :
491 45047 : str = ldb_msg_find_attr_as_string(msg, "scriptPath", "");
492 45047 : info->logon_script = talloc_strdup(info, str);
493 45047 : if (info->logon_script == NULL) {
494 0 : TALLOC_FREE(user_info_dc);
495 0 : return NT_STATUS_NO_MEMORY;
496 : }
497 :
498 45047 : str = ldb_msg_find_attr_as_string(msg, "profilePath", "");
499 45047 : info->profile_path = talloc_strdup(info, str);
500 45047 : if (info->profile_path == NULL) {
501 0 : TALLOC_FREE(user_info_dc);
502 0 : return NT_STATUS_NO_MEMORY;
503 : }
504 :
505 45047 : str = ldb_msg_find_attr_as_string(msg, "homeDirectory", "");
506 45047 : info->home_directory = talloc_strdup(info, str);
507 45047 : if (info->home_directory == NULL) {
508 0 : TALLOC_FREE(user_info_dc);
509 0 : return NT_STATUS_NO_MEMORY;
510 : }
511 :
512 45047 : str = ldb_msg_find_attr_as_string(msg, "homeDrive", "");
513 45047 : info->home_drive = talloc_strdup(info, str);
514 45047 : if (info->home_drive == NULL) {
515 0 : TALLOC_FREE(user_info_dc);
516 0 : return NT_STATUS_NO_MEMORY;
517 : }
518 :
519 45047 : info->logon_server = talloc_strdup(info, netbios_name);
520 45047 : if (info->logon_server == NULL) {
521 0 : TALLOC_FREE(user_info_dc);
522 0 : return NT_STATUS_NO_MEMORY;
523 : }
524 :
525 45047 : info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
526 45047 : info->last_logoff = samdb_result_last_logoff(msg);
527 45047 : info->acct_expiry = samdb_result_account_expires(msg);
528 45047 : info->last_password_change = samdb_result_nttime(msg,
529 : "pwdLastSet", 0);
530 : info->allow_password_change
531 45047 : = samdb_result_allow_password_change(sam_ctx, mem_ctx,
532 : domain_dn, msg, "pwdLastSet");
533 45047 : info->force_password_change = samdb_result_nttime(msg,
534 : "msDS-UserPasswordExpiryTimeComputed", 0);
535 45047 : info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0);
536 45047 : info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount",
537 : 0);
538 :
539 45047 : info->acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
540 :
541 45047 : user_info_dc->user_session_key = data_blob_talloc(user_info_dc,
542 : user_sess_key.data,
543 : user_sess_key.length);
544 45047 : if (user_sess_key.data) {
545 16845 : if (user_info_dc->user_session_key.data == NULL) {
546 0 : TALLOC_FREE(user_info_dc);
547 0 : return NT_STATUS_NO_MEMORY;
548 : }
549 : }
550 45047 : user_info_dc->lm_session_key = data_blob_talloc(user_info_dc,
551 : lm_sess_key.data,
552 : lm_sess_key.length);
553 45047 : if (lm_sess_key.data) {
554 16086 : if (user_info_dc->lm_session_key.data == NULL) {
555 0 : TALLOC_FREE(user_info_dc);
556 0 : return NT_STATUS_NO_MEMORY;
557 : }
558 : }
559 :
560 45047 : if (info->acct_flags & ACB_SVRTRUST) {
561 : /* the SID_NT_ENTERPRISE_DCS SID gets added into the
562 : PAC */
563 3979 : 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 3979 : if (user_info_dc->sids == NULL) {
568 0 : TALLOC_FREE(user_info_dc);
569 0 : return NT_STATUS_NO_MEMORY;
570 : }
571 3979 : user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs;
572 3979 : user_info_dc->num_sids++;
573 : }
574 :
575 45047 : 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 859 : 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 859 : if (user_info_dc->sids == NULL) {
583 0 : TALLOC_FREE(user_info_dc);
584 0 : return NT_STATUS_NO_MEMORY;
585 : }
586 859 : user_info_dc->sids[user_info_dc->num_sids] = *domain_sid;
587 859 : sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids],
588 : DOMAIN_RID_ENTERPRISE_READONLY_DCS);
589 859 : user_info_dc->num_sids++;
590 : }
591 :
592 45047 : info->authenticated = true;
593 :
594 45047 : talloc_free(tmp_ctx);
595 45047 : *_user_info_dc = user_info_dc;
596 :
597 45047 : return NT_STATUS_OK;
598 : }
599 :
600 40120 : _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 40120 : char *filter = NULL;
605 : NTSTATUS status;
606 : uint32_t i;
607 40120 : 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 40120 : status = authsam_domain_group_filter(mem_ctx, &filter);
620 40120 : if (!NT_STATUS_IS_OK(status)) {
621 0 : TALLOC_FREE(user_info_dc);
622 0 : return status;
623 : }
624 :
625 : /*
626 : * We loop only over the existing number of
627 : * sids.
628 : */
629 40120 : n = user_info_dc->num_sids;
630 279377 : for (i = 0; i < n; i++) {
631 239257 : 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 239257 : DATA_BLOB dn_blob = data_blob_null;
635 :
636 245501 : snprintf(dn_str,
637 : sizeof(dn_str),
638 : "<SID=%s>",
639 : dom_sid_str_buf(sid, &sid_buf));
640 239257 : 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 239257 : status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
648 : true, filter,
649 : user_info_dc,
650 : &user_info_dc->sids,
651 239257 : &user_info_dc->num_sids);
652 239257 : if (!NT_STATUS_IS_OK(status)) {
653 0 : return status;
654 : }
655 : }
656 :
657 40120 : return NT_STATUS_OK;
658 : }
659 :
660 90630 : 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 90630 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
669 : int ret;
670 :
671 90630 : if (!tmp_ctx) {
672 0 : return NT_STATUS_NO_MEMORY;
673 : }
674 :
675 90630 : nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal,
676 : &user_dn, domain_dn);
677 90630 : if (!NT_STATUS_IS_OK(nt_status)) {
678 5367 : talloc_free(tmp_ctx);
679 5367 : return nt_status;
680 : }
681 :
682 : /* pull the user attributes */
683 85263 : 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 85263 : if (ret != LDB_SUCCESS) {
688 0 : talloc_free(tmp_ctx);
689 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
690 : }
691 85263 : talloc_steal(mem_ctx, *msg);
692 85263 : talloc_steal(mem_ctx, *domain_dn);
693 85263 : talloc_free(tmp_ctx);
694 :
695 85263 : 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 : */
702 158 : 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 158 : DATA_BLOB user_sess_key = data_blob(NULL, 0);
711 158 : DATA_BLOB lm_sess_key = data_blob(NULL, 0);
712 :
713 : struct ldb_message *msg;
714 : struct ldb_dn *domain_dn;
715 :
716 158 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
717 158 : if (!tmp_ctx) {
718 0 : return NT_STATUS_NO_MEMORY;
719 : }
720 :
721 158 : if (principal) {
722 0 : nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
723 : user_attrs, &domain_dn, &msg);
724 0 : if (!NT_STATUS_IS_OK(nt_status)) {
725 0 : talloc_free(tmp_ctx);
726 0 : return nt_status;
727 : }
728 158 : } else if (user_dn) {
729 : struct dom_sid *user_sid, *domain_sid;
730 : int ret;
731 : /* pull the user attributes */
732 158 : 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 158 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
737 0 : talloc_free(tmp_ctx);
738 0 : return NT_STATUS_NO_SUCH_USER;
739 158 : } else if (ret != LDB_SUCCESS) {
740 0 : talloc_free(tmp_ctx);
741 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
742 : }
743 :
744 158 : user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
745 :
746 158 : nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
747 158 : if (!NT_STATUS_IS_OK(nt_status)) {
748 0 : return nt_status;
749 : }
750 :
751 158 : 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 158 : if (!domain_dn) {
755 : struct dom_sid_buf buf;
756 0 : 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 0 : return NT_STATUS_NO_SUCH_USER;
759 : }
760 :
761 : } else {
762 0 : return NT_STATUS_INVALID_PARAMETER;
763 : }
764 :
765 158 : 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 158 : if (!NT_STATUS_IS_OK(nt_status)) {
774 0 : talloc_free(tmp_ctx);
775 0 : return nt_status;
776 : }
777 :
778 158 : talloc_steal(mem_ctx, *user_info_dc);
779 158 : talloc_free(tmp_ctx);
780 :
781 158 : return NT_STATUS_OK;
782 : }
783 :
784 : /*
785 : * Returns the details for the Password Settings Object (PSO), if one applies
786 : * the user.
787 : */
788 3005 : 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 3005 : const char *attrs[] = { "msDS-LockoutThreshold",
794 : "msDS-LockoutObservationWindow",
795 : NULL };
796 3005 : struct ldb_dn *pso_dn = NULL;
797 3005 : struct ldb_result *res = NULL;
798 : int ret;
799 :
800 : /* check if the user has a PSO that applies to it */
801 3005 : pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
802 : "msDS-ResultantPSO");
803 :
804 3005 : if (pso_dn != NULL) {
805 25 : ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
806 25 : if (ret != LDB_SUCCESS) {
807 0 : return ret;
808 : }
809 :
810 25 : *pso_msg = res->msgs[0];
811 : }
812 :
813 3005 : return LDB_SUCCESS;
814 : }
815 :
816 3005 : NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
817 : struct ldb_message *msg,
818 : struct ldb_dn *domain_dn)
819 : {
820 3005 : 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 3005 : struct ldb_message *msg_mod = NULL;
829 3005 : struct ldb_message *pso_msg = NULL;
830 : TALLOC_CTX *mem_ctx;
831 :
832 3005 : mem_ctx = talloc_new(msg);
833 3005 : if (mem_ctx == NULL) {
834 0 : return NT_STATUS_NO_MEMORY;
835 : }
836 :
837 3005 : ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
838 3005 : if (ret != LDB_SUCCESS) {
839 0 : TALLOC_FREE(mem_ctx);
840 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
841 : }
842 :
843 3005 : ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
844 3005 : 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 0 : DBG_ERR("Error (%d) checking PSO for %s",
851 : ret, ldb_dn_get_linearized(msg->dn));
852 : }
853 :
854 5859 : status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
855 3005 : msg, domain_res->msgs[0], pso_msg,
856 : &msg_mod);
857 3005 : if (!NT_STATUS_IS_OK(status)) {
858 0 : TALLOC_FREE(mem_ctx);
859 0 : return status;
860 : }
861 :
862 3005 : if (msg_mod != NULL) {
863 : struct ldb_request *req;
864 :
865 509 : 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 509 : if (ret != LDB_SUCCESS) {
872 0 : goto done;
873 : }
874 :
875 509 : ret = ldb_request_add_control(req,
876 : DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
877 : false, NULL);
878 509 : if (ret != LDB_SUCCESS) {
879 0 : talloc_free(req);
880 0 : goto done;
881 : }
882 :
883 509 : ret = dsdb_autotransaction_request(sam_ctx, req);
884 509 : talloc_free(req);
885 : }
886 :
887 5350 : done:
888 3005 : if (ret != LDB_SUCCESS) {
889 0 : 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 0 : TALLOC_FREE(mem_ctx);
894 0 : return NT_STATUS_INTERNAL_ERROR;
895 : }
896 :
897 3005 : TALLOC_FREE(mem_ctx);
898 3005 : return NT_STATUS_OK;
899 : }
900 :
901 :
902 42855 : 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 42855 : struct ldb_result *domain_res = NULL;
931 42855 : TALLOC_CTX *mem_ctx = NULL;
932 : int32_t sync_interval;
933 : NTTIME sync_interval_nt;
934 :
935 42855 : mem_ctx = talloc_new(msg_mod);
936 42855 : if (mem_ctx == NULL) {
937 0 : return NT_STATUS_NO_MEMORY;
938 : }
939 :
940 42855 : ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
941 : 0);
942 42855 : if (ret != LDB_SUCCESS || domain_res->count != 1) {
943 0 : TALLOC_FREE(mem_ctx);
944 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
945 : }
946 :
947 42855 : sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
948 : "msDS-LogonTimeSyncInterval",
949 : 14);
950 42855 : DEBUG(5, ("sync interval is %d\n", sync_interval));
951 42855 : if (sync_interval == 0){
952 : /*
953 : * Setting msDS-LogonTimeSyncInterval to zero is how you ask
954 : * that nothing happens here.
955 : */
956 0 : TALLOC_FREE(mem_ctx);
957 0 : return NT_STATUS_OK;
958 : }
959 42855 : 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 42855 : uint32_t r = generate_random() % 6;
966 42855 : sync_interval -= r;
967 42855 : 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 42855 : sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
972 :
973 42855 : 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 42855 : if (old_timestamp > now){
979 0 : 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 42855 : } else if (old_timestamp < now - sync_interval_nt){
984 5119 : DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
985 : (long long int)now));
986 :
987 : /* The time has come to update lastLogonTimestamp */
988 5119 : ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
989 : "lastLogonTimestamp", now);
990 :
991 5119 : if (ret != LDB_SUCCESS) {
992 0 : TALLOC_FREE(mem_ctx);
993 0 : return NT_STATUS_NO_MEMORY;
994 : }
995 : }
996 42855 : TALLOC_FREE(mem_ctx);
997 42855 : return NT_STATUS_OK;
998 : }
999 :
1000 : /****************************************************************************
1001 : Look for the specified user in the sam, return ldb result structures
1002 : ****************************************************************************/
1003 :
1004 22844 : 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 22844 : 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 22844 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1018 858 : 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 858 : return NT_STATUS_NO_SUCH_USER;
1021 : }
1022 21986 : if (ret != LDB_SUCCESS) {
1023 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1024 : }
1025 :
1026 21986 : return NT_STATUS_OK;
1027 : }
1028 :
1029 :
1030 : /* Reset the badPwdCount to zero and update the lastLogon time. */
1031 44343 : 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 44343 : bool am_rodc = false;
1048 :
1049 44343 : mem_ctx = talloc_new(msg);
1050 44343 : if (mem_ctx == NULL) {
1051 0 : return NT_STATUS_NO_MEMORY;
1052 : }
1053 :
1054 44343 : lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
1055 44343 : dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
1056 44343 : if (interactive_or_kerberos) {
1057 26035 : badPwdCount = dbBadPwdCount;
1058 : } else {
1059 17718 : badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
1060 : domain_dn, msg);
1061 : }
1062 44343 : lastLogonTimestamp =
1063 44343 : ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
1064 :
1065 44343 : DEBUG(5, ("lastLogonTimestamp is %lld\n",
1066 : (long long int)lastLogonTimestamp));
1067 :
1068 44343 : msg_mod = ldb_msg_new(mem_ctx);
1069 44343 : if (msg_mod == NULL) {
1070 0 : TALLOC_FREE(mem_ctx);
1071 0 : return NT_STATUS_NO_MEMORY;
1072 : }
1073 44343 : msg_mod->dn = msg->dn;
1074 :
1075 44343 : if (lockoutTime != 0) {
1076 : /*
1077 : * This implies "badPwdCount" = 0, see samldb_lockout_time()
1078 : */
1079 36 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
1080 36 : if (ret != LDB_SUCCESS) {
1081 0 : TALLOC_FREE(mem_ctx);
1082 0 : return NT_STATUS_NO_MEMORY;
1083 : }
1084 44307 : } else if (badPwdCount != 0) {
1085 224 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
1086 224 : if (ret != LDB_SUCCESS) {
1087 0 : TALLOC_FREE(mem_ctx);
1088 0 : return NT_STATUS_NO_MEMORY;
1089 : }
1090 : }
1091 :
1092 44343 : tv_now = timeval_current();
1093 44343 : now = timeval_to_nttime(&tv_now);
1094 :
1095 45497 : if (interactive_or_kerberos ||
1096 1266 : (badPwdCount != 0 && lockoutTime == 0)) {
1097 26737 : ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1098 : "lastLogon", now);
1099 26737 : if (ret != LDB_SUCCESS) {
1100 0 : TALLOC_FREE(mem_ctx);
1101 0 : return NT_STATUS_NO_MEMORY;
1102 : }
1103 : }
1104 :
1105 44343 : if (interactive_or_kerberos) {
1106 : int logonCount;
1107 :
1108 26625 : logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
1109 :
1110 26625 : logonCount += 1;
1111 :
1112 26625 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1113 : "logonCount", logonCount);
1114 26625 : if (ret != LDB_SUCCESS) {
1115 0 : TALLOC_FREE(mem_ctx);
1116 0 : return NT_STATUS_NO_MEMORY;
1117 : }
1118 : } else {
1119 : /* Set an unset logonCount to 0 on first successful login */
1120 17718 : if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
1121 16 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1122 : "logonCount", 0);
1123 16 : if (ret != LDB_SUCCESS) {
1124 0 : TALLOC_FREE(mem_ctx);
1125 0 : return NT_STATUS_NO_MEMORY;
1126 : }
1127 : }
1128 : }
1129 :
1130 44343 : ret = samdb_rodc(sam_ctx, &am_rodc);
1131 44343 : if (ret != LDB_SUCCESS) {
1132 0 : TALLOC_FREE(mem_ctx);
1133 0 : return NT_STATUS_INTERNAL_ERROR;
1134 : }
1135 :
1136 44343 : if (!am_rodc) {
1137 42855 : status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
1138 : lastLogonTimestamp, now);
1139 42855 : if (!NT_STATUS_IS_OK(status)) {
1140 0 : TALLOC_FREE(mem_ctx);
1141 0 : return NT_STATUS_NO_MEMORY;
1142 : }
1143 : } else {
1144 : /* Perform the (async) SendToSAM calls for MS-SAMS */
1145 1488 : if (dbBadPwdCount != 0 && send_to_sam != NULL) {
1146 : struct netr_SendToSamBase *base_msg;
1147 17 : struct GUID guid = samdb_result_guid(msg, "objectGUID");
1148 17 : base_msg = talloc_zero(msg, struct netr_SendToSamBase);
1149 :
1150 17 : base_msg->message_type = SendToSamResetBadPasswordCount;
1151 17 : base_msg->message_size = 16;
1152 17 : base_msg->message.reset_bad_password.guid = guid;
1153 17 : *send_to_sam = base_msg;
1154 : }
1155 : }
1156 :
1157 44343 : 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 88921 : for (i=0;i<msg_mod->num_elements;i++) {
1163 58757 : msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1164 : }
1165 :
1166 30754 : 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 30754 : if (ret != LDB_SUCCESS) {
1173 0 : goto done;
1174 : }
1175 :
1176 30754 : ret = ldb_request_add_control(req,
1177 : DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1178 : false, NULL);
1179 30754 : if (ret != LDB_SUCCESS) {
1180 0 : talloc_free(req);
1181 0 : goto done;
1182 : }
1183 :
1184 30754 : ret = dsdb_autotransaction_request(sam_ctx, req);
1185 30754 : talloc_free(req);
1186 : }
1187 :
1188 53901 : done:
1189 44343 : if (ret != LDB_SUCCESS) {
1190 0 : 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 0 : TALLOC_FREE(mem_ctx);
1196 0 : return NT_STATUS_INTERNAL_ERROR;
1197 : }
1198 :
1199 44343 : TALLOC_FREE(mem_ctx);
1200 44343 : return NT_STATUS_OK;
1201 : }
|