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 : #include "lib/dbwrap/dbwrap.h"
35 : #include "cluster/cluster.h"
36 :
37 : #undef DBGC_CLASS
38 : #define DBGC_CLASS DBGC_AUTH
39 :
40 : #define KRBTGT_ATTRS \
41 : /* required for the krb5 kdc */ \
42 : "objectClass", \
43 : "sAMAccountName", \
44 : "userPrincipalName", \
45 : "servicePrincipalName", \
46 : "msDS-KeyVersionNumber", \
47 : "msDS-SecondaryKrbTgtNumber", \
48 : "msDS-SupportedEncryptionTypes", \
49 : "supplementalCredentials", \
50 : "msDS-AllowedToDelegateTo", \
51 : "msDS-AllowedToActOnBehalfOfOtherIdentity", \
52 : \
53 : /* passwords */ \
54 : "unicodePwd", \
55 : \
56 : "userAccountControl", \
57 : "msDS-User-Account-Control-Computed", \
58 : "objectSid", \
59 : \
60 : "pwdLastSet", \
61 : "msDS-UserPasswordExpiryTimeComputed", \
62 : "accountExpires", \
63 : \
64 : /* Needed for RODC rule processing */ \
65 : "msDS-KrbTgtLinkBL"
66 :
67 : #define AUTHN_POLICY_ATTRS \
68 : /* Required for authentication policies / silos */ \
69 : "msDS-AssignedAuthNPolicy", \
70 : "msDS-AssignedAuthNPolicySilo"
71 :
72 : const char *krbtgt_attrs[] = {
73 : /*
74 : * Authentication policies will not be enforced on the TGS
75 : * account. Don’t include the relevant attributes in the account search.
76 : */
77 : KRBTGT_ATTRS, NULL
78 : };
79 :
80 : const char *server_attrs[] = {
81 : KRBTGT_ATTRS,
82 : AUTHN_POLICY_ATTRS,
83 : NULL
84 : };
85 :
86 : const char *user_attrs[] = {
87 : /*
88 : * This ordering (having msDS-ResultantPSO first) is
89 : * important. By processing this attribute first it is
90 : * available in the operational module for the other PSO
91 : * attribute calculations to use.
92 : */
93 : "msDS-ResultantPSO",
94 :
95 : KRBTGT_ATTRS,
96 : AUTHN_POLICY_ATTRS,
97 :
98 : "logonHours",
99 :
100 : /*
101 : * To allow us to zero the badPwdCount and lockoutTime on
102 : * successful logon, without database churn
103 : */
104 : "lockoutTime",
105 :
106 : /*
107 : * Needed for SendToSAM requests
108 : */
109 : "objectGUID",
110 :
111 : /* check 'allowed workstations' */
112 : "userWorkstations",
113 :
114 : /* required for user_info_dc, not access control: */
115 : "displayName",
116 : "scriptPath",
117 : "profilePath",
118 : "homeDirectory",
119 : "homeDrive",
120 : "lastLogon",
121 : "lastLogonTimestamp",
122 : "lastLogoff",
123 : "accountExpires",
124 : "badPwdCount",
125 : "logonCount",
126 : "primaryGroupID",
127 : "memberOf",
128 : "badPasswordTime",
129 : "lmPwdHistory",
130 : "ntPwdHistory",
131 : NULL,
132 : };
133 :
134 : /****************************************************************************
135 : Check if a user is allowed to logon at this time. Note this is the
136 : servers local time, as logon hours are just specified as a weekly
137 : bitmask.
138 : ****************************************************************************/
139 :
140 71416 : static bool logon_hours_ok(struct ldb_message *msg, const char *name_for_logs)
141 : {
142 : /* In logon hours first bit is Sunday from 12AM to 1AM */
143 3158 : const struct ldb_val *hours;
144 3158 : struct tm *utctime;
145 3158 : time_t lasttime;
146 3158 : const char *asct;
147 3158 : uint8_t bitmask, bitpos;
148 :
149 71416 : hours = ldb_msg_find_ldb_val(msg, "logonHours");
150 71416 : if (!hours) {
151 71409 : DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
152 71409 : return true;
153 : }
154 :
155 7 : if (hours->length != 168/8) {
156 0 : DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
157 0 : return true;
158 : }
159 :
160 7 : lasttime = time(NULL);
161 7 : utctime = gmtime(&lasttime);
162 7 : if (!utctime) {
163 0 : DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
164 : name_for_logs));
165 0 : return false;
166 : }
167 :
168 : /* find the corresponding byte and bit */
169 7 : bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
170 7 : bitmask = 1 << (bitpos % 8);
171 :
172 7 : if (! (hours->data[bitpos/8] & bitmask)) {
173 4 : struct tm *t = localtime(&lasttime);
174 4 : if (!t) {
175 0 : asct = "INVALID TIME";
176 : } else {
177 4 : asct = asctime(t);
178 4 : if (!asct) {
179 0 : asct = "INVALID TIME";
180 : }
181 : }
182 :
183 4 : DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
184 : "logon at this time (%s).\n",
185 : name_for_logs, asct ));
186 4 : return false;
187 : }
188 :
189 3 : asct = asctime(utctime);
190 3 : DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
191 : name_for_logs, asct ? asct : "UNKNOWN TIME" ));
192 :
193 3 : return true;
194 : }
195 :
196 : /****************************************************************************
197 : Do a specific test for a SAM_ACCOUNT being valid for this connection
198 : (ie not disabled, expired and the like).
199 : ****************************************************************************/
200 72069 : _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
201 : struct ldb_context *sam_ctx,
202 : uint32_t logon_parameters,
203 : struct ldb_dn *domain_dn,
204 : struct ldb_message *msg,
205 : const char *logon_workstation,
206 : const char *name_for_logs,
207 : bool allow_domain_trust,
208 : bool password_change)
209 : {
210 3158 : uint16_t acct_flags;
211 3158 : const char *workstation_list;
212 3158 : NTTIME acct_expiry;
213 3158 : NTTIME must_change_time;
214 72069 : struct timeval tv_now = timeval_current();
215 72069 : NTTIME now = timeval_to_nttime(&tv_now);
216 :
217 72069 : DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
218 :
219 72069 : acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
220 :
221 72069 : acct_expiry = samdb_result_account_expires(msg);
222 :
223 : /* Check for when we must change this password, taking the
224 : * userAccountControl flags into account */
225 72069 : must_change_time = samdb_result_nttime(msg,
226 : "msDS-UserPasswordExpiryTimeComputed", 0);
227 :
228 72069 : workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL);
229 :
230 : /* Quit if the account was disabled. */
231 72069 : if (acct_flags & ACB_DISABLED) {
232 271 : DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
233 271 : return NT_STATUS_ACCOUNT_DISABLED;
234 : }
235 :
236 : /* Quit if the account was locked out. */
237 71798 : if (acct_flags & ACB_AUTOLOCK) {
238 26 : DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
239 26 : return NT_STATUS_ACCOUNT_LOCKED_OUT;
240 : }
241 :
242 : /* Test account expire time */
243 71772 : if (now > acct_expiry) {
244 0 : DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
245 0 : DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
246 : nt_time_string(mem_ctx, acct_expiry)));
247 0 : return NT_STATUS_ACCOUNT_EXPIRED;
248 : }
249 :
250 : /* check for immediate expiry "must change at next logon" (but not if this is a password change request) */
251 71772 : if ((must_change_time == 0) && !password_change) {
252 13 : DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n",
253 : name_for_logs));
254 13 : return NT_STATUS_PASSWORD_MUST_CHANGE;
255 : }
256 :
257 : /* check for expired password (but not if this is a password change request) */
258 71759 : if ((must_change_time < now) && !password_change) {
259 0 : DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n",
260 : name_for_logs));
261 0 : DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n",
262 : nt_time_string(mem_ctx, must_change_time)));
263 0 : return NT_STATUS_PASSWORD_EXPIRED;
264 : }
265 :
266 : /* Test workstation. Workstation list is comma separated. */
267 71759 : if (logon_workstation && workstation_list && *workstation_list) {
268 343 : bool invalid_ws = true;
269 0 : int i;
270 343 : char **workstations = str_list_make(mem_ctx, workstation_list, ",");
271 :
272 686 : for (i = 0; workstations && workstations[i]; i++) {
273 343 : DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
274 : workstations[i], logon_workstation));
275 :
276 343 : if (strequal(workstations[i], logon_workstation)) {
277 0 : invalid_ws = false;
278 0 : break;
279 : }
280 : }
281 :
282 343 : talloc_free(workstations);
283 :
284 343 : if (invalid_ws) {
285 343 : return NT_STATUS_INVALID_WORKSTATION;
286 : }
287 : }
288 :
289 71416 : if (!logon_hours_ok(msg, name_for_logs)) {
290 4 : return NT_STATUS_INVALID_LOGON_HOURS;
291 : }
292 :
293 71412 : if (!allow_domain_trust) {
294 23289 : if (acct_flags & ACB_DOMTRUST) {
295 0 : DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
296 0 : return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
297 : }
298 : }
299 71412 : if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
300 10580 : if (acct_flags & ACB_SVRTRUST) {
301 0 : DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
302 0 : return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
303 : }
304 : }
305 71412 : if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
306 : /* TODO: this fails with current solaris client. We
307 : need to work with Gordon to work out why */
308 9554 : if (acct_flags & ACB_WSTRUST) {
309 342 : DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
310 342 : return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
311 : }
312 : }
313 :
314 71070 : return NT_STATUS_OK;
315 : }
316 :
317 127428 : static NTSTATUS authsam_domain_group_filter(TALLOC_CTX *mem_ctx,
318 : char **_filter)
319 : {
320 127428 : char *filter = NULL;
321 :
322 127428 : *_filter = NULL;
323 :
324 127428 : filter = talloc_strdup(mem_ctx, "(&(objectClass=group)");
325 127428 : if (filter == NULL) {
326 0 : return NT_STATUS_NO_MEMORY;
327 : }
328 :
329 : /*
330 : * Skip all builtin groups, they're added later.
331 : */
332 127428 : talloc_asprintf_addbuf(&filter,
333 : "(!(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
334 : GROUP_TYPE_BUILTIN_LOCAL_GROUP);
335 127428 : if (filter == NULL) {
336 0 : return NT_STATUS_NO_MEMORY;
337 : }
338 : /*
339 : * Only include security groups.
340 : */
341 127428 : talloc_asprintf_addbuf(&filter,
342 : "(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
343 : GROUP_TYPE_SECURITY_ENABLED);
344 127428 : if (filter == NULL) {
345 0 : return NT_STATUS_NO_MEMORY;
346 : }
347 :
348 127428 : *_filter = filter;
349 127428 : return NT_STATUS_OK;
350 : }
351 :
352 78917 : _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx,
353 : struct ldb_context *sam_ctx,
354 : const char *netbios_name,
355 : const char *domain_name,
356 : const char *dns_domain_name,
357 : struct ldb_dn *domain_dn,
358 : const struct ldb_message *msg,
359 : DATA_BLOB user_sess_key,
360 : DATA_BLOB lm_sess_key,
361 : struct auth_user_info_dc **_user_info_dc)
362 : {
363 3200 : NTSTATUS status;
364 3200 : int ret;
365 3200 : struct auth_user_info_dc *user_info_dc;
366 3200 : struct auth_user_info *info;
367 78917 : const char *str = NULL;
368 78917 : char *filter = NULL;
369 : /* SIDs for the account and his primary group */
370 3200 : struct dom_sid *account_sid;
371 3200 : struct dom_sid_buf buf;
372 78917 : const char *primary_group_dn_str = NULL;
373 3200 : DATA_BLOB primary_group_blob;
374 78917 : struct ldb_dn *primary_group_dn = NULL;
375 78917 : struct ldb_message *primary_group_msg = NULL;
376 3200 : unsigned primary_group_type;
377 : /* SID structures for the expanded group memberships */
378 78917 : struct auth_SidAttr *sids = NULL;
379 78917 : uint32_t num_sids = 0;
380 3200 : unsigned int i;
381 3200 : struct dom_sid *domain_sid;
382 3200 : TALLOC_CTX *tmp_ctx;
383 3200 : struct ldb_message_element *el;
384 3200 : static const char * const group_type_attrs[] = { "groupType", NULL };
385 :
386 78917 : if (msg == NULL) {
387 0 : return NT_STATUS_INVALID_PARAMETER;
388 : }
389 :
390 78917 : user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
391 78917 : NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
392 :
393 78917 : tmp_ctx = talloc_new(user_info_dc);
394 78917 : if (tmp_ctx == NULL) {
395 0 : TALLOC_FREE(user_info_dc);
396 0 : return NT_STATUS_NO_MEMORY;
397 : }
398 :
399 : /*
400 : * We'll typically store three SIDs: the SID of the user, the SID of the
401 : * primary group, and a copy of the latter if it's not a resource
402 : * group. Allocate enough memory for these three SIDs.
403 : */
404 78917 : sids = talloc_zero_array(user_info_dc, struct auth_SidAttr, 3);
405 78917 : if (sids == NULL) {
406 0 : TALLOC_FREE(user_info_dc);
407 0 : return NT_STATUS_NO_MEMORY;
408 : }
409 :
410 78917 : num_sids = 2;
411 :
412 78917 : account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
413 78917 : if (account_sid == NULL) {
414 0 : TALLOC_FREE(user_info_dc);
415 0 : return NT_STATUS_NO_MEMORY;
416 : }
417 :
418 78917 : status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
419 78917 : if (!NT_STATUS_IS_OK(status)) {
420 0 : talloc_free(user_info_dc);
421 0 : return status;
422 : }
423 :
424 78917 : sids[PRIMARY_USER_SID_INDEX].sid = *account_sid;
425 78917 : sids[PRIMARY_USER_SID_INDEX].attrs = SE_GROUP_DEFAULT_FLAGS;
426 78917 : sids[PRIMARY_GROUP_SID_INDEX].sid = *domain_sid;
427 78917 : sid_append_rid(&sids[PRIMARY_GROUP_SID_INDEX].sid, ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0));
428 78917 : sids[PRIMARY_GROUP_SID_INDEX].attrs = SE_GROUP_DEFAULT_FLAGS;
429 :
430 : /*
431 : * Filter out builtin groups from this token. We will search
432 : * for builtin groups later, and not include them in the PAC
433 : * or SamLogon validation info.
434 : */
435 78917 : status = authsam_domain_group_filter(tmp_ctx, &filter);
436 78917 : if (!NT_STATUS_IS_OK(status)) {
437 0 : TALLOC_FREE(user_info_dc);
438 0 : return status;
439 : }
440 :
441 78917 : primary_group_dn_str = talloc_asprintf(
442 : tmp_ctx,
443 : "<SID=%s>",
444 78917 : dom_sid_str_buf(&sids[PRIMARY_GROUP_SID_INDEX].sid, &buf));
445 78917 : if (primary_group_dn_str == NULL) {
446 0 : TALLOC_FREE(user_info_dc);
447 0 : return NT_STATUS_NO_MEMORY;
448 : }
449 :
450 : /* Get the DN of the primary group. */
451 78917 : primary_group_dn = ldb_dn_new(tmp_ctx, sam_ctx, primary_group_dn_str);
452 78917 : if (primary_group_dn == NULL) {
453 0 : TALLOC_FREE(user_info_dc);
454 0 : return NT_STATUS_NO_MEMORY;
455 : }
456 :
457 : /*
458 : * Do a search for the primary group, for the purpose of checking
459 : * whether it's a resource group.
460 : */
461 78917 : ret = dsdb_search_one(sam_ctx, tmp_ctx,
462 : &primary_group_msg,
463 : primary_group_dn,
464 : LDB_SCOPE_BASE,
465 : group_type_attrs,
466 : 0,
467 : NULL);
468 78917 : if (ret != LDB_SUCCESS) {
469 0 : talloc_free(user_info_dc);
470 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
471 : }
472 :
473 : /* Check the type of the primary group. */
474 78917 : primary_group_type = ldb_msg_find_attr_as_uint(primary_group_msg, "groupType", 0);
475 78917 : if (primary_group_type & GROUP_TYPE_RESOURCE_GROUP) {
476 : /*
477 : * If it's a resource group, we might as well indicate that in
478 : * its attributes. At any rate, the primary group's attributes
479 : * are unlikely to be used in the code, as there's nowhere to
480 : * store them.
481 : */
482 18 : sids[PRIMARY_GROUP_SID_INDEX].attrs |= SE_GROUP_RESOURCE;
483 : } else {
484 : /*
485 : * The primary group is not a resource group. Make a copy of its
486 : * SID to ensure it is added to the Base SIDs in the PAC.
487 : */
488 78899 : sids[REMAINING_SIDS_INDEX] = sids[PRIMARY_GROUP_SID_INDEX];
489 78899 : ++num_sids;
490 : }
491 :
492 78917 : primary_group_blob = data_blob_string_const(primary_group_dn_str);
493 :
494 : /* Expands the primary group - this function takes in
495 : * memberOf-like values, so we fake one up with the
496 : * <SID=S-...> format of DN and then let it expand
497 : * them, as long as they meet the filter - so only
498 : * domain groups, not builtin groups
499 : *
500 : * The primary group is still treated specially, so we set the
501 : * 'only childs' flag to true
502 : */
503 78917 : status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
504 : user_info_dc, &sids, &num_sids);
505 78917 : if (!NT_STATUS_IS_OK(status)) {
506 0 : talloc_free(user_info_dc);
507 0 : return status;
508 : }
509 :
510 : /* Expands the additional groups */
511 78917 : el = ldb_msg_find_element(msg, "memberOf");
512 328153 : for (i = 0; el && i < el->num_values; i++) {
513 : /* This function takes in memberOf values and expands
514 : * them, as long as they meet the filter - so only
515 : * domain groups, not builtin groups */
516 246036 : status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
517 : user_info_dc, &sids, &num_sids);
518 246036 : if (!NT_STATUS_IS_OK(status)) {
519 0 : talloc_free(user_info_dc);
520 0 : return status;
521 : }
522 : }
523 :
524 78917 : user_info_dc->sids = sids;
525 78917 : user_info_dc->num_sids = num_sids;
526 :
527 78917 : user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info);
528 78917 : if (user_info_dc->info == NULL) {
529 0 : talloc_free(user_info_dc);
530 0 : return NT_STATUS_NO_MEMORY;
531 : }
532 :
533 78917 : str = ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL);
534 78917 : info->account_name = talloc_strdup(info, str);
535 78917 : if (info->account_name == NULL) {
536 0 : TALLOC_FREE(user_info_dc);
537 0 : return NT_STATUS_NO_MEMORY;
538 : }
539 :
540 78917 : str = ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL);
541 78917 : if (str == NULL && dns_domain_name != NULL) {
542 68215 : info->user_principal_name = talloc_asprintf(info, "%s@%s",
543 : info->account_name,
544 : dns_domain_name);
545 68215 : if (info->user_principal_name == NULL) {
546 0 : TALLOC_FREE(user_info_dc);
547 0 : return NT_STATUS_NO_MEMORY;
548 : }
549 68215 : info->user_principal_constructed = true;
550 10702 : } else if (str != NULL) {
551 10604 : info->user_principal_name = talloc_strdup(info, str);
552 10604 : if (info->user_principal_name == NULL) {
553 0 : TALLOC_FREE(user_info_dc);
554 0 : return NT_STATUS_NO_MEMORY;
555 : }
556 : }
557 :
558 78917 : info->domain_name = talloc_strdup(info, domain_name);
559 78917 : if (info->domain_name == NULL) {
560 0 : TALLOC_FREE(user_info_dc);
561 0 : return NT_STATUS_NO_MEMORY;
562 : }
563 :
564 78917 : if (dns_domain_name != NULL) {
565 78819 : info->dns_domain_name = talloc_strdup(info, dns_domain_name);
566 78819 : if (info->dns_domain_name == NULL) {
567 0 : TALLOC_FREE(user_info_dc);
568 0 : return NT_STATUS_NO_MEMORY;
569 : }
570 : }
571 :
572 78917 : str = ldb_msg_find_attr_as_string(msg, "displayName", "");
573 78917 : info->full_name = talloc_strdup(info, str);
574 78917 : if (info->full_name == NULL) {
575 0 : TALLOC_FREE(user_info_dc);
576 0 : return NT_STATUS_NO_MEMORY;
577 : }
578 :
579 78917 : str = ldb_msg_find_attr_as_string(msg, "scriptPath", "");
580 78917 : info->logon_script = talloc_strdup(info, str);
581 78917 : if (info->logon_script == NULL) {
582 0 : TALLOC_FREE(user_info_dc);
583 0 : return NT_STATUS_NO_MEMORY;
584 : }
585 :
586 78917 : str = ldb_msg_find_attr_as_string(msg, "profilePath", "");
587 78917 : info->profile_path = talloc_strdup(info, str);
588 78917 : if (info->profile_path == NULL) {
589 0 : TALLOC_FREE(user_info_dc);
590 0 : return NT_STATUS_NO_MEMORY;
591 : }
592 :
593 78917 : str = ldb_msg_find_attr_as_string(msg, "homeDirectory", "");
594 78917 : info->home_directory = talloc_strdup(info, str);
595 78917 : if (info->home_directory == NULL) {
596 0 : TALLOC_FREE(user_info_dc);
597 0 : return NT_STATUS_NO_MEMORY;
598 : }
599 :
600 78917 : str = ldb_msg_find_attr_as_string(msg, "homeDrive", "");
601 78917 : info->home_drive = talloc_strdup(info, str);
602 78917 : if (info->home_drive == NULL) {
603 0 : TALLOC_FREE(user_info_dc);
604 0 : return NT_STATUS_NO_MEMORY;
605 : }
606 :
607 78917 : info->logon_server = talloc_strdup(info, netbios_name);
608 78917 : if (info->logon_server == NULL) {
609 0 : TALLOC_FREE(user_info_dc);
610 0 : return NT_STATUS_NO_MEMORY;
611 : }
612 :
613 78917 : info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
614 78917 : info->last_logoff = samdb_result_last_logoff(msg);
615 78917 : info->acct_expiry = samdb_result_account_expires(msg);
616 78917 : info->last_password_change = samdb_result_nttime(msg,
617 : "pwdLastSet", 0);
618 3200 : info->allow_password_change
619 78917 : = samdb_result_allow_password_change(sam_ctx, mem_ctx,
620 : domain_dn, msg, "pwdLastSet");
621 78917 : info->force_password_change = samdb_result_nttime(msg,
622 : "msDS-UserPasswordExpiryTimeComputed", 0);
623 78917 : info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0);
624 78917 : info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount",
625 : 0);
626 :
627 78917 : info->acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
628 :
629 78917 : user_info_dc->user_session_key = data_blob_talloc(user_info_dc,
630 : user_sess_key.data,
631 : user_sess_key.length);
632 78917 : if (user_sess_key.data) {
633 0 : if (user_info_dc->user_session_key.data == NULL) {
634 0 : TALLOC_FREE(user_info_dc);
635 0 : return NT_STATUS_NO_MEMORY;
636 : }
637 : }
638 78917 : user_info_dc->lm_session_key = data_blob_talloc(user_info_dc,
639 : lm_sess_key.data,
640 : lm_sess_key.length);
641 78917 : if (lm_sess_key.data) {
642 0 : if (user_info_dc->lm_session_key.data == NULL) {
643 0 : TALLOC_FREE(user_info_dc);
644 0 : return NT_STATUS_NO_MEMORY;
645 : }
646 : }
647 :
648 78917 : if (info->acct_flags & ACB_SVRTRUST) {
649 : /* the SID_NT_ENTERPRISE_DCS SID gets added into the
650 : PAC */
651 3542 : user_info_dc->sids = talloc_realloc(user_info_dc,
652 : user_info_dc->sids,
653 : struct auth_SidAttr,
654 : user_info_dc->num_sids+1);
655 3542 : if (user_info_dc->sids == NULL) {
656 0 : TALLOC_FREE(user_info_dc);
657 0 : return NT_STATUS_NO_MEMORY;
658 : }
659 3542 : user_info_dc->sids[user_info_dc->num_sids].sid = global_sid_Enterprise_DCs;
660 3542 : user_info_dc->sids[user_info_dc->num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
661 3542 : user_info_dc->num_sids++;
662 : }
663 :
664 78917 : if ((info->acct_flags & (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) ==
665 : (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) {
666 : /* the DOMAIN_RID_ENTERPRISE_READONLY_DCS PAC */
667 664 : user_info_dc->sids = talloc_realloc(user_info_dc,
668 : user_info_dc->sids,
669 : struct auth_SidAttr,
670 : user_info_dc->num_sids+1);
671 664 : if (user_info_dc->sids == NULL) {
672 0 : TALLOC_FREE(user_info_dc);
673 0 : return NT_STATUS_NO_MEMORY;
674 : }
675 664 : user_info_dc->sids[user_info_dc->num_sids].sid = *domain_sid;
676 664 : sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids].sid,
677 : DOMAIN_RID_ENTERPRISE_READONLY_DCS);
678 664 : user_info_dc->sids[user_info_dc->num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
679 664 : user_info_dc->num_sids++;
680 : }
681 :
682 78917 : info->user_flags = 0;
683 :
684 78917 : talloc_free(tmp_ctx);
685 78917 : *_user_info_dc = user_info_dc;
686 :
687 78917 : return NT_STATUS_OK;
688 : }
689 :
690 48511 : _PUBLIC_ NTSTATUS authsam_update_user_info_dc(TALLOC_CTX *mem_ctx,
691 : struct ldb_context *sam_ctx,
692 : struct auth_user_info_dc *user_info_dc)
693 : {
694 48511 : char *filter = NULL;
695 1658 : NTSTATUS status;
696 1658 : uint32_t i;
697 48511 : uint32_t n = 0;
698 :
699 : /*
700 : * This function exists to expand group memberships
701 : * in the local domain (forest), as the token
702 : * may come from a different domain.
703 : */
704 :
705 : /*
706 : * Filter out builtin groups from this token. We will search
707 : * for builtin groups later.
708 : */
709 48511 : status = authsam_domain_group_filter(mem_ctx, &filter);
710 48511 : if (!NT_STATUS_IS_OK(status)) {
711 0 : return status;
712 : }
713 :
714 : /*
715 : * We loop only over the existing number of
716 : * sids.
717 : */
718 48511 : n = user_info_dc->num_sids;
719 434005 : for (i = 0; i < n; i++) {
720 385494 : struct dom_sid *sid = &user_info_dc->sids[i].sid;
721 13685 : struct dom_sid_buf sid_buf;
722 13685 : char dn_str[sizeof(sid_buf.buf)*2];
723 385494 : DATA_BLOB dn_blob = data_blob_null;
724 :
725 385494 : snprintf(dn_str,
726 : sizeof(dn_str),
727 : "<SID=%s>",
728 : dom_sid_str_buf(sid, &sid_buf));
729 385494 : dn_blob = data_blob_string_const(dn_str);
730 :
731 : /*
732 : * We already have the SID in the token, so set
733 : * 'only childs' flag to true and add all
734 : * groups which match the filter.
735 : */
736 385494 : status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
737 : true, filter,
738 : user_info_dc,
739 : &user_info_dc->sids,
740 : &user_info_dc->num_sids);
741 385494 : if (!NT_STATUS_IS_OK(status)) {
742 0 : talloc_free(filter);
743 0 : return status;
744 : }
745 : }
746 :
747 48511 : talloc_free(filter);
748 48511 : return NT_STATUS_OK;
749 : }
750 :
751 : /*
752 : * Make a shallow copy of a talloc-allocated user_info_dc structure, holding a
753 : * reference to each of the original fields.
754 : */
755 30597 : NTSTATUS authsam_shallow_copy_user_info_dc(TALLOC_CTX *mem_ctx,
756 : const struct auth_user_info_dc *user_info_dc_in,
757 : struct auth_user_info_dc **user_info_dc_out)
758 : {
759 30597 : struct auth_user_info_dc *user_info_dc = NULL;
760 30597 : NTSTATUS status = NT_STATUS_OK;
761 :
762 30597 : if (user_info_dc_in == NULL) {
763 0 : return NT_STATUS_INVALID_PARAMETER;
764 : }
765 :
766 30597 : if (user_info_dc_out == NULL) {
767 0 : return NT_STATUS_INVALID_PARAMETER;
768 : }
769 :
770 30597 : user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
771 30597 : if (user_info_dc == NULL) {
772 0 : status = NT_STATUS_NO_MEMORY;
773 0 : goto out;
774 : }
775 :
776 30597 : *user_info_dc = *user_info_dc_in;
777 :
778 30597 : if (user_info_dc->info != NULL) {
779 30597 : if (talloc_reference(user_info_dc, user_info_dc->info) == NULL) {
780 0 : status = NT_STATUS_NO_MEMORY;
781 0 : goto out;
782 : }
783 : }
784 :
785 30597 : if (user_info_dc->user_session_key.data != NULL) {
786 0 : if (talloc_reference(user_info_dc, user_info_dc->user_session_key.data) == NULL) {
787 0 : status = NT_STATUS_NO_MEMORY;
788 0 : goto out;
789 : }
790 : }
791 :
792 30597 : if (user_info_dc->lm_session_key.data != NULL) {
793 0 : if (talloc_reference(user_info_dc, user_info_dc->lm_session_key.data) == NULL) {
794 0 : status = NT_STATUS_NO_MEMORY;
795 0 : goto out;
796 : }
797 : }
798 :
799 30597 : if (user_info_dc->sids != NULL) {
800 : /*
801 : * Because we want to modify the SIDs in the user_info_dc
802 : * structure, adding various well-known SIDs such as Asserted
803 : * Identity or Claims Valid, make a copy of the SID array to
804 : * guard against modification of the original.
805 : *
806 : * It’s better not to make a reference, because anything that
807 : * tries to call talloc_realloc() on the original or the copy
808 : * will fail when called for any referenced talloc context.
809 : */
810 30597 : user_info_dc->sids = talloc_memdup(user_info_dc,
811 : user_info_dc->sids,
812 : talloc_get_size(user_info_dc->sids));
813 30597 : if (user_info_dc->sids == NULL) {
814 0 : status = NT_STATUS_NO_MEMORY;
815 0 : goto out;
816 : }
817 : }
818 :
819 30597 : *user_info_dc_out = user_info_dc;
820 30597 : user_info_dc = NULL;
821 :
822 30597 : out:
823 30597 : talloc_free(user_info_dc);
824 30597 : return status;
825 : }
826 :
827 103821 : NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
828 : TALLOC_CTX *mem_ctx, const char *principal,
829 : const char **attrs,
830 : struct ldb_dn **domain_dn,
831 : struct ldb_message **msg)
832 : {
833 3413 : struct ldb_dn *user_dn;
834 3413 : NTSTATUS nt_status;
835 103821 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
836 3413 : int ret;
837 :
838 103821 : if (!tmp_ctx) {
839 0 : return NT_STATUS_NO_MEMORY;
840 : }
841 :
842 103821 : nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal,
843 : &user_dn, domain_dn);
844 103821 : if (!NT_STATUS_IS_OK(nt_status)) {
845 2774 : talloc_free(tmp_ctx);
846 2774 : return nt_status;
847 : }
848 :
849 : /* pull the user attributes */
850 101047 : ret = dsdb_search_one(sam_ctx, tmp_ctx, msg, user_dn,
851 : LDB_SCOPE_BASE, attrs,
852 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
853 : "(objectClass=*)");
854 101047 : if (ret != LDB_SUCCESS) {
855 0 : talloc_free(tmp_ctx);
856 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
857 : }
858 101047 : talloc_steal(mem_ctx, *msg);
859 101047 : talloc_steal(mem_ctx, *domain_dn);
860 101047 : talloc_free(tmp_ctx);
861 :
862 101047 : return NT_STATUS_OK;
863 : }
864 :
865 : /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
866 :
867 : Supply either a principal or a DN
868 : */
869 467 : NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
870 : struct loadparm_context *lp_ctx,
871 : struct ldb_context *sam_ctx,
872 : const char *principal,
873 : struct ldb_dn *user_dn,
874 : struct auth_user_info_dc **user_info_dc)
875 : {
876 41 : NTSTATUS nt_status;
877 467 : DATA_BLOB user_sess_key = data_blob(NULL, 0);
878 467 : DATA_BLOB lm_sess_key = data_blob(NULL, 0);
879 :
880 41 : struct ldb_message *msg;
881 41 : struct ldb_dn *domain_dn;
882 :
883 467 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
884 467 : if (!tmp_ctx) {
885 0 : return NT_STATUS_NO_MEMORY;
886 : }
887 :
888 467 : if (principal) {
889 0 : nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
890 : user_attrs, &domain_dn, &msg);
891 0 : if (!NT_STATUS_IS_OK(nt_status)) {
892 0 : talloc_free(tmp_ctx);
893 0 : return nt_status;
894 : }
895 467 : } else if (user_dn) {
896 41 : struct dom_sid *user_sid, *domain_sid;
897 41 : int ret;
898 : /* pull the user attributes */
899 467 : ret = dsdb_search_one(sam_ctx, tmp_ctx, &msg, user_dn,
900 : LDB_SCOPE_BASE, user_attrs,
901 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
902 : "(objectClass=*)");
903 467 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
904 0 : talloc_free(tmp_ctx);
905 0 : return NT_STATUS_NO_SUCH_USER;
906 467 : } else if (ret != LDB_SUCCESS) {
907 0 : talloc_free(tmp_ctx);
908 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
909 : }
910 :
911 467 : user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
912 :
913 467 : nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
914 467 : if (!NT_STATUS_IS_OK(nt_status)) {
915 0 : talloc_free(tmp_ctx);
916 0 : return nt_status;
917 : }
918 :
919 467 : domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
920 : "(&(objectSid=%s)(objectClass=domain))",
921 : ldap_encode_ndr_dom_sid(tmp_ctx, domain_sid));
922 467 : if (!domain_dn) {
923 0 : struct dom_sid_buf buf;
924 0 : DEBUG(3, ("authsam_get_user_info_dc_principal: Failed to find domain with: SID %s\n",
925 : dom_sid_str_buf(domain_sid, &buf)));
926 0 : talloc_free(tmp_ctx);
927 0 : return NT_STATUS_NO_SUCH_USER;
928 : }
929 :
930 : } else {
931 0 : talloc_free(tmp_ctx);
932 0 : return NT_STATUS_INVALID_PARAMETER;
933 : }
934 :
935 467 : nt_status = authsam_make_user_info_dc(tmp_ctx, sam_ctx,
936 : lpcfg_netbios_name(lp_ctx),
937 : lpcfg_sam_name(lp_ctx),
938 : lpcfg_sam_dnsname(lp_ctx),
939 : domain_dn,
940 : msg,
941 : user_sess_key, lm_sess_key,
942 : user_info_dc);
943 467 : if (!NT_STATUS_IS_OK(nt_status)) {
944 0 : talloc_free(tmp_ctx);
945 0 : return nt_status;
946 : }
947 :
948 467 : talloc_steal(mem_ctx, *user_info_dc);
949 467 : talloc_free(tmp_ctx);
950 :
951 467 : return NT_STATUS_OK;
952 : }
953 :
954 : /*
955 : * Returns the details for the Password Settings Object (PSO), if one applies
956 : * the user.
957 : */
958 3567 : static int authsam_get_user_pso(struct ldb_context *sam_ctx,
959 : TALLOC_CTX *mem_ctx,
960 : struct ldb_message *user_msg,
961 : struct ldb_message **pso_msg)
962 : {
963 3567 : const char *attrs[] = { "msDS-LockoutThreshold",
964 : "msDS-LockoutObservationWindow",
965 : NULL };
966 3567 : struct ldb_dn *pso_dn = NULL;
967 3567 : struct ldb_result *res = NULL;
968 13 : int ret;
969 :
970 : /* check if the user has a PSO that applies to it */
971 3567 : pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
972 : "msDS-ResultantPSO");
973 :
974 3567 : if (pso_dn != NULL) {
975 26 : ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
976 26 : if (ret != LDB_SUCCESS) {
977 0 : return ret;
978 : }
979 :
980 25 : *pso_msg = res->msgs[0];
981 : }
982 :
983 3554 : return LDB_SUCCESS;
984 : }
985 :
986 : /*
987 : * Re-read the bad password and successful logon data for a user.
988 : *
989 : * The DN in the passed user record should contain the "objectGUID" in case the
990 : * object DN has changed.
991 : */
992 41724 : NTSTATUS authsam_reread_user_logon_data(
993 : struct ldb_context *sam_ctx,
994 : TALLOC_CTX *mem_ctx,
995 : const struct ldb_message *user_msg,
996 : struct ldb_message **current)
997 : {
998 41724 : const struct ldb_val *v = NULL;
999 41724 : struct ldb_result *res = NULL;
1000 41724 : uint16_t acct_flags = 0;
1001 41724 : const char *attr_name = "msDS-User-Account-Control-Computed";
1002 :
1003 1197 : int ret;
1004 :
1005 : /*
1006 : * Re-read the account details, using the GUID in case the DN
1007 : * is being changed (this is automatic in LDB because the
1008 : * original search also used DSDB_SEARCH_SHOW_EXTENDED_DN)
1009 : *
1010 : * We re read all the attributes in user_attrs, rather than using a
1011 : * subset to ensure that we can reuse existing validation code.
1012 : */
1013 42921 : ret = dsdb_search_dn(sam_ctx,
1014 : mem_ctx,
1015 : &res,
1016 41724 : user_msg->dn,
1017 : user_attrs,
1018 : DSDB_SEARCH_SHOW_EXTENDED_DN);
1019 41724 : if (ret != LDB_SUCCESS) {
1020 4 : DBG_ERR("Unable to re-read account control data for %s\n",
1021 : ldb_dn_get_linearized(user_msg->dn));
1022 4 : return NT_STATUS_INTERNAL_ERROR;
1023 : }
1024 :
1025 : /*
1026 : * Ensure the account has not been locked out by another request
1027 : */
1028 41720 : v = ldb_msg_find_ldb_val(res->msgs[0], attr_name);
1029 41720 : if (v == NULL || v->data == NULL) {
1030 1 : DBG_ERR("No %s attribute for %s\n",
1031 : attr_name,
1032 : ldb_dn_get_linearized(user_msg->dn));
1033 1 : TALLOC_FREE(res);
1034 1 : return NT_STATUS_INTERNAL_ERROR;
1035 : }
1036 41719 : acct_flags = samdb_result_acct_flags(res->msgs[0], attr_name);
1037 41719 : if (acct_flags & ACB_AUTOLOCK) {
1038 6 : DBG_WARNING(
1039 : "Account for user %s was locked out.\n",
1040 : ldb_dn_get_linearized(user_msg->dn));
1041 6 : TALLOC_FREE(res);
1042 6 : return NT_STATUS_ACCOUNT_LOCKED_OUT;
1043 : }
1044 41713 : *current = talloc_steal(mem_ctx, res->msgs[0]);
1045 41713 : TALLOC_FREE(res);
1046 41713 : return NT_STATUS_OK;
1047 : }
1048 :
1049 106162 : static struct db_context *authsam_get_bad_password_db(
1050 : TALLOC_CTX *mem_ctx,
1051 : struct ldb_context *sam_ctx)
1052 : {
1053 106162 : struct loadparm_context *lp_ctx = NULL;
1054 106162 : const char *db_name = "bad_password";
1055 106162 : struct db_context *db_ctx = NULL;
1056 :
1057 106162 : lp_ctx = ldb_get_opaque(sam_ctx, "loadparm");
1058 106162 : if (lp_ctx == NULL) {
1059 1 : DBG_ERR("Unable to get loadparm_context\n");
1060 1 : return NULL;
1061 : }
1062 :
1063 106161 : db_ctx = cluster_db_tmp_open(mem_ctx, lp_ctx, db_name, TDB_DEFAULT);
1064 106161 : if (db_ctx == NULL) {
1065 4 : DBG_ERR("Unable to open bad password attempts database\n");
1066 4 : return NULL;
1067 : }
1068 100990 : return db_ctx;
1069 : }
1070 :
1071 106157 : static NTSTATUS get_object_sid_as_tdb_data(
1072 : TALLOC_CTX *mem_ctx,
1073 : const struct ldb_message *msg,
1074 : struct dom_sid_buf *buf,
1075 : TDB_DATA *key)
1076 : {
1077 106157 : struct dom_sid *objectsid = NULL;
1078 :
1079 : /*
1080 : * Convert the objectSID to a human readable form to
1081 : * make debugging easier
1082 : */
1083 106157 : objectsid = samdb_result_dom_sid(mem_ctx, msg, "objectSID");
1084 106157 : if (objectsid == NULL) {
1085 3 : DBG_ERR("Unable to extract objectSID\n");
1086 3 : return NT_STATUS_INTERNAL_ERROR;
1087 : }
1088 106154 : dom_sid_str_buf(objectsid, buf);
1089 106154 : key->dptr = (unsigned char *)buf->buf;
1090 106154 : key->dsize = strlen(buf->buf);
1091 :
1092 106154 : talloc_free(objectsid);
1093 :
1094 106154 : return NT_STATUS_OK;
1095 : }
1096 :
1097 : /*
1098 : * Add the users objectSID to the bad password attempt database
1099 : * to indicate that last authentication failed due to a bad password
1100 : */
1101 582 : static NTSTATUS authsam_set_bad_password_indicator(
1102 : struct ldb_context *sam_ctx,
1103 : TALLOC_CTX *mem_ctx,
1104 : const struct ldb_message *msg)
1105 : {
1106 582 : NTSTATUS status = NT_STATUS_OK;
1107 4 : struct dom_sid_buf buf;
1108 582 : TDB_DATA key = {0};
1109 582 : TDB_DATA value = {0};
1110 582 : struct db_context *db = NULL;
1111 :
1112 582 : TALLOC_CTX *ctx = talloc_new(mem_ctx);
1113 582 : if (ctx == NULL) {
1114 0 : return NT_STATUS_NO_MEMORY;
1115 : }
1116 :
1117 582 : db = authsam_get_bad_password_db(ctx, sam_ctx);
1118 582 : if (db == NULL) {
1119 1 : status = NT_STATUS_INTERNAL_ERROR;
1120 1 : goto exit;
1121 : }
1122 :
1123 581 : status = get_object_sid_as_tdb_data(ctx, msg, &buf, &key);
1124 581 : if (!NT_STATUS_IS_OK(status)) {
1125 1 : goto exit;
1126 : }
1127 :
1128 580 : status = dbwrap_store(db, key, value, 0);
1129 580 : if (!NT_STATUS_IS_OK(status)) {
1130 1 : DBG_ERR("Unable to store bad password indicator\n");
1131 : }
1132 579 : exit:
1133 582 : talloc_free(ctx);
1134 582 : return status;
1135 : }
1136 :
1137 : /*
1138 : * see if the users objectSID is in the bad password attempt database
1139 : */
1140 52793 : static NTSTATUS authsam_check_bad_password_indicator(
1141 : struct ldb_context *sam_ctx,
1142 : TALLOC_CTX *mem_ctx,
1143 : bool *exists,
1144 : const struct ldb_message *msg)
1145 : {
1146 52793 : NTSTATUS status = NT_STATUS_OK;
1147 2587 : struct dom_sid_buf buf;
1148 52793 : TDB_DATA key = {0};
1149 52793 : struct db_context *db = NULL;
1150 :
1151 52793 : TALLOC_CTX *ctx = talloc_new(mem_ctx);
1152 52793 : if (ctx == NULL) {
1153 0 : return NT_STATUS_NO_MEMORY;
1154 : }
1155 :
1156 52793 : db = authsam_get_bad_password_db(ctx, sam_ctx);
1157 52793 : if (db == NULL) {
1158 1 : status = NT_STATUS_INTERNAL_ERROR;
1159 1 : goto exit;
1160 : }
1161 :
1162 52792 : status = get_object_sid_as_tdb_data(ctx, msg, &buf, &key);
1163 52792 : if (!NT_STATUS_IS_OK(status)) {
1164 1 : goto exit;
1165 : }
1166 :
1167 52791 : *exists = dbwrap_exists(db, key);
1168 52793 : exit:
1169 52793 : talloc_free(ctx);
1170 52793 : return status;
1171 : }
1172 :
1173 : /*
1174 : * Remove the users objectSID to the bad password attempt database
1175 : * to indicate that last authentication succeeded.
1176 : */
1177 52785 : static NTSTATUS authsam_clear_bad_password_indicator(
1178 : struct ldb_context *sam_ctx,
1179 : TALLOC_CTX *mem_ctx,
1180 : const struct ldb_message *msg)
1181 : {
1182 52785 : NTSTATUS status = NT_STATUS_OK;
1183 2579 : struct dom_sid_buf buf;
1184 52785 : TDB_DATA key = {0};
1185 52785 : struct db_context *db = NULL;
1186 :
1187 52785 : TALLOC_CTX *ctx = talloc_new(mem_ctx);
1188 52785 : if (ctx == NULL) {
1189 0 : return NT_STATUS_NO_MEMORY;
1190 : }
1191 :
1192 52785 : db = authsam_get_bad_password_db(ctx, sam_ctx);
1193 52785 : if (db == NULL) {
1194 1 : status = NT_STATUS_INTERNAL_ERROR;
1195 1 : goto exit;
1196 : }
1197 :
1198 52784 : status = get_object_sid_as_tdb_data(ctx, msg, &buf, &key);
1199 52784 : if (!NT_STATUS_IS_OK(status)) {
1200 1 : goto exit;
1201 : }
1202 :
1203 52783 : status = dbwrap_delete(db, key);
1204 52783 : if (NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, status)) {
1205 : /*
1206 : * Ok there was no bad password indicator this is expected
1207 : */
1208 52423 : status = NT_STATUS_OK;
1209 : }
1210 52783 : if (NT_STATUS_IS_ERR(status)) {
1211 1 : DBG_ERR("Unable to delete bad password indicator, %s %s\n",
1212 : nt_errstr(status),
1213 : get_friendly_nt_error_msg(status));
1214 : }
1215 52782 : exit:
1216 52785 : talloc_free(ctx);
1217 52785 : return status;
1218 : }
1219 :
1220 3568 : NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
1221 : struct ldb_message *msg,
1222 : struct ldb_dn *domain_dn)
1223 : {
1224 3568 : const char *attrs[] = { "lockoutThreshold",
1225 : "lockOutObservationWindow",
1226 : "lockoutDuration",
1227 : "pwdProperties",
1228 : NULL };
1229 14 : int ret;
1230 14 : NTSTATUS status;
1231 14 : struct ldb_result *domain_res;
1232 3568 : struct ldb_message *msg_mod = NULL;
1233 3568 : struct ldb_message *current = NULL;
1234 3568 : struct ldb_message *pso_msg = NULL;
1235 3568 : bool txn_active = false;
1236 14 : TALLOC_CTX *mem_ctx;
1237 :
1238 3568 : mem_ctx = talloc_new(msg);
1239 3568 : if (mem_ctx == NULL) {
1240 0 : return NT_STATUS_NO_MEMORY;
1241 : }
1242 :
1243 3568 : ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
1244 3568 : if (ret != LDB_SUCCESS) {
1245 1 : TALLOC_FREE(mem_ctx);
1246 1 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1247 : }
1248 :
1249 3567 : ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
1250 3567 : if (ret != LDB_SUCCESS) {
1251 :
1252 : /*
1253 : * fallback to using the domain defaults so that we still
1254 : * record the bad password attempt
1255 : */
1256 1 : DBG_ERR("Error (%d) checking PSO for %s\n",
1257 : ret, ldb_dn_get_linearized(msg->dn));
1258 : }
1259 :
1260 : /*
1261 : * To ensure that the bad password count is updated atomically,
1262 : * we need to:
1263 : * begin a transaction
1264 : * re-read the account details,
1265 : * using the <GUID= part of the DN
1266 : * update the bad password count
1267 : * commit the transaction.
1268 : */
1269 :
1270 : /*
1271 : * Start a new transaction
1272 : */
1273 3567 : ret = ldb_transaction_start(sam_ctx);
1274 3567 : if (ret != LDB_SUCCESS) {
1275 1 : status = NT_STATUS_INTERNAL_ERROR;
1276 1 : goto error;
1277 : }
1278 3566 : txn_active = true;
1279 :
1280 : /*
1281 : * Re-read the account details, using the GUID in case the DN
1282 : * is being changed.
1283 : */
1284 3566 : status = authsam_reread_user_logon_data(
1285 : sam_ctx, mem_ctx, msg, ¤t);
1286 3566 : if (!NT_STATUS_IS_OK(status)) {
1287 : /* The re-read can return account locked out, as well
1288 : * as an internal error
1289 : */
1290 7 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
1291 : /*
1292 : * For NT_STATUS_ACCOUNT_LOCKED_OUT we want to commit
1293 : * the transaction. Again to avoid cluttering the
1294 : * audit logs with spurious errors
1295 : */
1296 5 : goto exit;
1297 : }
1298 2 : goto error;
1299 : }
1300 :
1301 : /*
1302 : * Update the bad password count and if required lock the account
1303 : */
1304 3568 : status = dsdb_update_bad_pwd_count(
1305 : mem_ctx,
1306 : sam_ctx,
1307 : current,
1308 3559 : domain_res->msgs[0],
1309 : pso_msg,
1310 : &msg_mod);
1311 3559 : if (!NT_STATUS_IS_OK(status)) {
1312 1 : status = NT_STATUS_INTERNAL_ERROR;
1313 1 : goto error;
1314 : }
1315 :
1316 : /*
1317 : * Write the data back to disk if required.
1318 : */
1319 3558 : if (msg_mod != NULL) {
1320 4 : struct ldb_request *req;
1321 :
1322 582 : ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
1323 : msg_mod,
1324 : NULL,
1325 : NULL,
1326 : ldb_op_default_callback,
1327 : NULL);
1328 582 : if (ret != LDB_SUCCESS) {
1329 1 : TALLOC_FREE(msg_mod);
1330 1 : status = NT_STATUS_INTERNAL_ERROR;
1331 1 : goto error;
1332 : }
1333 :
1334 581 : ret = ldb_request_add_control(req,
1335 : DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1336 : false, NULL);
1337 581 : if (ret != LDB_SUCCESS) {
1338 1 : talloc_free(req);
1339 1 : status = NT_STATUS_INTERNAL_ERROR;
1340 1 : goto error;
1341 : }
1342 :
1343 : /*
1344 : * As we're in a transaction, make the ldb request directly
1345 : * to avoid the nested transaction that would result if we
1346 : * called dsdb_autotransaction_request
1347 : */
1348 580 : ret = ldb_request(sam_ctx, req);
1349 580 : if (ret == LDB_SUCCESS) {
1350 579 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1351 : }
1352 580 : talloc_free(req);
1353 580 : if (ret != LDB_SUCCESS) {
1354 2 : status = NT_STATUS_INTERNAL_ERROR;
1355 2 : goto error;
1356 : }
1357 578 : status = authsam_set_bad_password_indicator(
1358 : sam_ctx, mem_ctx, msg);
1359 578 : if (!NT_STATUS_IS_OK(status)) {
1360 0 : goto error;
1361 : }
1362 : }
1363 : /*
1364 : * Note that we may not have updated the user record, but
1365 : * committing the transaction in that case is still the correct
1366 : * thing to do.
1367 : * If the transaction was cancelled, this would be logged by
1368 : * the dsdb audit log as a failure. When in fact it is expected
1369 : * behaviour.
1370 : */
1371 2976 : exit:
1372 3559 : TALLOC_FREE(mem_ctx);
1373 3559 : ret = ldb_transaction_commit(sam_ctx);
1374 3559 : if (ret != LDB_SUCCESS) {
1375 1 : DBG_ERR("Error (%d) %s, committing transaction,"
1376 : " while updating bad password count"
1377 : " for (%s)\n",
1378 : ret,
1379 : ldb_errstring(sam_ctx),
1380 : ldb_dn_get_linearized(msg->dn));
1381 1 : return NT_STATUS_INTERNAL_ERROR;
1382 : }
1383 3558 : return status;
1384 :
1385 8 : error:
1386 8 : DBG_ERR("Failed to update badPwdCount, badPasswordTime or "
1387 : "set lockoutTime on %s: %s\n",
1388 : ldb_dn_get_linearized(msg->dn),
1389 : ldb_errstring(sam_ctx) != NULL ?
1390 : ldb_errstring(sam_ctx) :nt_errstr(status));
1391 8 : if (txn_active) {
1392 7 : ret = ldb_transaction_cancel(sam_ctx);
1393 7 : if (ret != LDB_SUCCESS) {
1394 1 : DBG_ERR("Error rolling back transaction,"
1395 : " while updating bad password count"
1396 : " on %s: %s\n",
1397 : ldb_dn_get_linearized(msg->dn),
1398 : ldb_errstring(sam_ctx));
1399 : }
1400 : }
1401 8 : TALLOC_FREE(mem_ctx);
1402 8 : return status;
1403 :
1404 : }
1405 :
1406 : /*
1407 : * msDS-LogonTimeSyncInterval is an int32_t number of days.
1408 : *
1409 : * The docs say: "the initial update, after the domain functional
1410 : * level is raised to DS_BEHAVIOR_WIN2003 or higher, is calculated as
1411 : * 14 days minus a random percentage of 5 days", but we aren't doing
1412 : * that. The blogosphere seems to think that this randomised update
1413 : * happens every time, but [MS-ADA1] doesn't agree.
1414 : *
1415 : * Dochelp referred us to the following blog post:
1416 : * http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
1417 : *
1418 : * when msDS-LogonTimeSyncInterval is zero, the lastLogonTimestamp is
1419 : * not changed.
1420 : */
1421 :
1422 52176 : static NTSTATUS authsam_calculate_lastlogon_sync_interval(
1423 : struct ldb_context *sam_ctx,
1424 : TALLOC_CTX *ctx,
1425 : struct ldb_dn *domain_dn,
1426 : NTTIME *sync_interval_nt)
1427 : {
1428 2584 : static const char *attrs[] = { "msDS-LogonTimeSyncInterval",
1429 : NULL };
1430 2584 : int ret;
1431 52176 : struct ldb_result *domain_res = NULL;
1432 52176 : TALLOC_CTX *mem_ctx = NULL;
1433 2584 : uint32_t sync_interval;
1434 :
1435 52176 : mem_ctx = talloc_new(ctx);
1436 52176 : if (mem_ctx == NULL) {
1437 0 : return NT_STATUS_NO_MEMORY;
1438 : }
1439 :
1440 52176 : ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
1441 : 0);
1442 52176 : if (ret != LDB_SUCCESS || domain_res->count != 1) {
1443 0 : TALLOC_FREE(mem_ctx);
1444 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1445 : }
1446 :
1447 52176 : sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
1448 : "msDS-LogonTimeSyncInterval",
1449 : 14);
1450 52176 : DEBUG(5, ("sync interval is %d\n", sync_interval));
1451 52176 : if (sync_interval >= 5){
1452 : /*
1453 : * Subtract "a random percentage of 5" days. Presumably this
1454 : * percentage is between 0 and 100, and modulus is accurate
1455 : * enough.
1456 : */
1457 50472 : uint32_t r = generate_random() % 6;
1458 50472 : sync_interval -= r;
1459 50472 : DBG_INFO("randomised sync interval is %d (-%d)\n", sync_interval, r);
1460 : }
1461 : /* In the case where sync_interval < 5 there is no randomisation */
1462 :
1463 : /*
1464 : * msDS-LogonTimeSyncInterval is an int32_t number of days,
1465 : * while lastLogonTimestamp (to be updated) is in the 64 bit
1466 : * 100ns NTTIME format so we must convert.
1467 : */
1468 52176 : *sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
1469 52176 : TALLOC_FREE(mem_ctx);
1470 52176 : return NT_STATUS_OK;
1471 : }
1472 :
1473 :
1474 : /*
1475 : * We only set lastLogonTimestamp if the current value is older than
1476 : * now - msDS-LogonTimeSyncInterval days.
1477 : *
1478 : * lastLogonTimestamp is in the 64 bit 100ns NTTIME format
1479 : */
1480 89053 : static NTSTATUS authsam_update_lastlogon_timestamp(struct ldb_context *sam_ctx,
1481 : struct ldb_message *msg_mod,
1482 : struct ldb_dn *domain_dn,
1483 : NTTIME old_timestamp,
1484 : NTTIME now,
1485 : NTTIME sync_interval_nt)
1486 : {
1487 3751 : int ret;
1488 89053 : DEBUG(5, ("old timestamp is %lld, threshold %lld, diff %lld\n",
1489 : (long long int)old_timestamp,
1490 : (long long int)(now - sync_interval_nt),
1491 : (long long int)(old_timestamp - now + sync_interval_nt)));
1492 :
1493 89053 : if (sync_interval_nt == 0){
1494 : /*
1495 : * Setting msDS-LogonTimeSyncInterval to zero is how you ask
1496 : * that nothing happens here.
1497 : */
1498 3330 : return NT_STATUS_OK;
1499 : }
1500 85723 : if (old_timestamp > now){
1501 0 : DEBUG(0, ("lastLogonTimestamp is in the future! (%lld > %lld)\n",
1502 : (long long int)old_timestamp, (long long int)now));
1503 : /* then what? */
1504 :
1505 85723 : } else if (old_timestamp < now - sync_interval_nt){
1506 17227 : DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
1507 : (long long int)now));
1508 :
1509 : /* The time has come to update lastLogonTimestamp */
1510 17227 : ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1511 : "lastLogonTimestamp", now);
1512 :
1513 17227 : if (ret != LDB_SUCCESS) {
1514 0 : return NT_STATUS_NO_MEMORY;
1515 : }
1516 : }
1517 85723 : return NT_STATUS_OK;
1518 : }
1519 :
1520 : /****************************************************************************
1521 : Look for the specified user in the sam, return ldb result structures
1522 : ****************************************************************************/
1523 :
1524 29742 : NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
1525 : const char *account_name,
1526 : struct ldb_dn *domain_dn,
1527 : struct ldb_message **ret_msg)
1528 : {
1529 1410 : int ret;
1530 29742 : char *account_name_encoded = NULL;
1531 :
1532 29742 : account_name_encoded = ldb_binary_encode_string(mem_ctx, account_name);
1533 29742 : if (account_name_encoded == NULL) {
1534 0 : return NT_STATUS_NO_MEMORY;
1535 : }
1536 :
1537 : /* pull the user attributes */
1538 29742 : ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
1539 : user_attrs,
1540 : DSDB_SEARCH_SHOW_EXTENDED_DN,
1541 : "(&(sAMAccountName=%s)(objectclass=user))",
1542 : account_name_encoded);
1543 29742 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1544 1313 : DEBUG(3,("authsam_search_account: Couldn't find user [%s] in samdb, under %s\n",
1545 : account_name, ldb_dn_get_linearized(domain_dn)));
1546 1313 : return NT_STATUS_NO_SUCH_USER;
1547 : }
1548 28429 : if (ret != LDB_SUCCESS) {
1549 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1550 : }
1551 :
1552 28429 : return NT_STATUS_OK;
1553 : }
1554 :
1555 :
1556 : /* Reset the badPwdCount to zero and update the lastLogon time. */
1557 52791 : NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
1558 : const struct ldb_message *msg,
1559 : struct ldb_dn *domain_dn,
1560 : bool interactive_or_kerberos,
1561 : TALLOC_CTX *send_to_sam_mem_ctx,
1562 : struct netr_SendToSamBase **send_to_sam)
1563 : {
1564 2585 : int ret;
1565 2585 : NTSTATUS status;
1566 2585 : int badPwdCount;
1567 2585 : int dbBadPwdCount;
1568 2585 : int64_t lockoutTime;
1569 2585 : struct ldb_message *msg_mod;
1570 2585 : TALLOC_CTX *mem_ctx;
1571 2585 : struct timeval tv_now;
1572 2585 : NTTIME now;
1573 2585 : NTTIME lastLogonTimestamp;
1574 2585 : int64_t lockOutObservationWindow;
1575 52791 : NTTIME sync_interval_nt = 0;
1576 52791 : bool am_rodc = false;
1577 52791 : bool txn_active = false;
1578 2585 : bool need_db_reread;
1579 :
1580 52791 : mem_ctx = talloc_new(msg);
1581 52791 : if (mem_ctx == NULL) {
1582 0 : return NT_STATUS_NO_MEMORY;
1583 : }
1584 :
1585 : /*
1586 : * Any update of the last logon data, needs to be done inside a
1587 : * transaction.
1588 : * And the user data needs to be re-read, and the account re-checked
1589 : * for lockout.
1590 : *
1591 : * Howevver we have long-running transactions like replication
1592 : * that could otherwise grind the system to a halt so we first
1593 : * determine if *this* account has seen a bad password,
1594 : * otherwise we only start a transaction if there was a need
1595 : * (because a change was to be made).
1596 : */
1597 :
1598 52791 : status = authsam_check_bad_password_indicator(
1599 : sam_ctx, mem_ctx, &need_db_reread, msg);
1600 52791 : if (!NT_STATUS_IS_OK(status)) {
1601 0 : TALLOC_FREE(mem_ctx);
1602 0 : return status;
1603 : }
1604 :
1605 52791 : if (interactive_or_kerberos == false) {
1606 : /*
1607 : * Avoid calculating this twice, it reads the PSO. A
1608 : * race on this is unimportant.
1609 : */
1610 1403 : lockOutObservationWindow
1611 22751 : = samdb_result_msds_LockoutObservationWindow(
1612 : sam_ctx, mem_ctx, domain_dn, msg);
1613 : }
1614 :
1615 52791 : ret = samdb_rodc(sam_ctx, &am_rodc);
1616 52791 : if (ret != LDB_SUCCESS) {
1617 1 : status = NT_STATUS_INTERNAL_ERROR;
1618 1 : goto error;
1619 : }
1620 :
1621 52790 : if (!am_rodc) {
1622 : /*
1623 : * Avoid reading the main domain DN twice. A race on
1624 : * this is unimportant.
1625 : */
1626 52176 : status = authsam_calculate_lastlogon_sync_interval(
1627 : sam_ctx, mem_ctx, domain_dn, &sync_interval_nt);
1628 :
1629 52176 : if (!NT_STATUS_IS_OK(status)) {
1630 0 : status = NT_STATUS_INTERNAL_ERROR;
1631 0 : goto error;
1632 : }
1633 : }
1634 :
1635 52790 : get_transaction:
1636 :
1637 90142 : if (need_db_reread) {
1638 37720 : struct ldb_message *current = NULL;
1639 :
1640 : /*
1641 : * Start a new transaction
1642 : */
1643 37720 : ret = ldb_transaction_start(sam_ctx);
1644 37720 : if (ret != LDB_SUCCESS) {
1645 1 : status = NT_STATUS_INTERNAL_ERROR;
1646 1 : goto error;
1647 : }
1648 :
1649 37719 : txn_active = true;
1650 :
1651 : /*
1652 : * Re-read the account details, using the GUID
1653 : * embedded in DN so this is safe against a race where
1654 : * it is being renamed.
1655 : */
1656 37719 : status = authsam_reread_user_logon_data(
1657 : sam_ctx, mem_ctx, msg, ¤t);
1658 37719 : if (!NT_STATUS_IS_OK(status)) {
1659 : /*
1660 : * The re-read can return account locked out, as well
1661 : * as an internal error
1662 : */
1663 1 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
1664 : /*
1665 : * For NT_STATUS_ACCOUNT_LOCKED_OUT we want to commit
1666 : * the transaction. Again to avoid cluttering the
1667 : * audit logs with spurious errors
1668 : */
1669 0 : goto exit;
1670 : }
1671 1 : goto error;
1672 : }
1673 37718 : msg = current;
1674 : }
1675 :
1676 90140 : lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
1677 90140 : dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
1678 90140 : tv_now = timeval_current();
1679 90140 : now = timeval_to_nttime(&tv_now);
1680 :
1681 90140 : if (interactive_or_kerberos) {
1682 57578 : badPwdCount = dbBadPwdCount;
1683 : } else {
1684 : /*
1685 : * We get lockOutObservationWindow above, before the
1686 : * transaction
1687 : */
1688 30213 : badPwdCount = dsdb_effective_badPwdCount(
1689 : msg, lockOutObservationWindow, now);
1690 : }
1691 93893 : lastLogonTimestamp =
1692 90140 : ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
1693 :
1694 90140 : DEBUG(5, ("lastLogonTimestamp is %lld\n",
1695 : (long long int)lastLogonTimestamp));
1696 :
1697 90140 : msg_mod = ldb_msg_new(mem_ctx);
1698 90140 : if (msg_mod == NULL) {
1699 1 : status = NT_STATUS_NO_MEMORY;
1700 1 : goto error;
1701 : }
1702 :
1703 : /*
1704 : * By using the DN from msg->dn directly, we allow LDB to
1705 : * prefer the embedded GUID form, so this is actually quite
1706 : * safe even in the case where DN has been changed
1707 : */
1708 90139 : msg_mod->dn = msg->dn;
1709 :
1710 90139 : if (lockoutTime != 0) {
1711 : /*
1712 : * This implies "badPwdCount" = 0, see samldb_lockout_time()
1713 : */
1714 44 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
1715 44 : if (ret != LDB_SUCCESS) {
1716 0 : status = NT_STATUS_NO_MEMORY;
1717 0 : goto error;
1718 : }
1719 90095 : } else if (badPwdCount != 0) {
1720 327 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
1721 327 : if (ret != LDB_SUCCESS) {
1722 0 : status = NT_STATUS_NO_MEMORY;
1723 0 : goto error;
1724 : }
1725 : }
1726 :
1727 90139 : if (interactive_or_kerberos ||
1728 1607 : (badPwdCount != 0 && lockoutTime == 0)) {
1729 60129 : ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1730 : "lastLogon", now);
1731 60129 : if (ret != LDB_SUCCESS) {
1732 1 : status = NT_STATUS_NO_MEMORY;
1733 1 : goto error;
1734 : }
1735 : }
1736 :
1737 90138 : if (interactive_or_kerberos) {
1738 2347 : int logonCount;
1739 :
1740 59925 : logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
1741 :
1742 59925 : logonCount += 1;
1743 :
1744 59925 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1745 : "logonCount", logonCount);
1746 59925 : if (ret != LDB_SUCCESS) {
1747 0 : status = NT_STATUS_NO_MEMORY;
1748 0 : goto error;
1749 : }
1750 : } else {
1751 : /* Set an unset logonCount to 0 on first successful login */
1752 30213 : if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
1753 34 : ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1754 : "logonCount", 0);
1755 34 : if (ret != LDB_SUCCESS) {
1756 0 : TALLOC_FREE(mem_ctx);
1757 0 : return NT_STATUS_NO_MEMORY;
1758 : }
1759 : }
1760 : }
1761 :
1762 90138 : if (!am_rodc) {
1763 89053 : status = authsam_update_lastlogon_timestamp(
1764 : sam_ctx,
1765 : msg_mod,
1766 : domain_dn,
1767 : lastLogonTimestamp,
1768 : now,
1769 : sync_interval_nt);
1770 89053 : if (!NT_STATUS_IS_OK(status)) {
1771 0 : status = NT_STATUS_NO_MEMORY;
1772 0 : goto error;
1773 : }
1774 : } else {
1775 : /* Perform the (async) SendToSAM calls for MS-SAMS */
1776 1085 : if (dbBadPwdCount != 0 && send_to_sam != NULL) {
1777 0 : struct netr_SendToSamBase *base_msg;
1778 17 : struct GUID guid = samdb_result_guid(msg, "objectGUID");
1779 :
1780 17 : base_msg = talloc_zero(send_to_sam_mem_ctx,
1781 : struct netr_SendToSamBase);
1782 17 : if (base_msg == NULL) {
1783 0 : status = NT_STATUS_NO_MEMORY;
1784 0 : goto error;
1785 : }
1786 :
1787 17 : base_msg->message_type = SendToSamResetBadPasswordCount;
1788 17 : base_msg->message_size = 16;
1789 17 : base_msg->message.reset_bad_password.guid = guid;
1790 17 : *send_to_sam = base_msg;
1791 : }
1792 : }
1793 :
1794 90138 : if (msg_mod->num_elements > 0) {
1795 2349 : unsigned int i;
1796 2349 : struct ldb_request *req;
1797 :
1798 : /*
1799 : * If it turns out we are going to update the DB, go
1800 : * back to the start, get a transaction and the
1801 : * current DB state and try again
1802 : */
1803 75068 : if (txn_active == false) {
1804 37352 : need_db_reread = true;
1805 37352 : goto get_transaction;
1806 : }
1807 :
1808 : /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1809 107117 : for (i=0;i<msg_mod->num_elements;i++) {
1810 69401 : msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1811 : }
1812 :
1813 37716 : ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
1814 : msg_mod,
1815 : NULL,
1816 : NULL,
1817 : ldb_op_default_callback,
1818 : NULL);
1819 37716 : if (ret != LDB_SUCCESS) {
1820 1 : status = NT_STATUS_INTERNAL_ERROR;
1821 1 : goto error;
1822 : }
1823 :
1824 37715 : ret = ldb_request_add_control(req,
1825 : DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1826 : false, NULL);
1827 37715 : if (ret != LDB_SUCCESS) {
1828 1 : TALLOC_FREE(req);
1829 1 : status = NT_STATUS_INTERNAL_ERROR;
1830 1 : goto error;
1831 : }
1832 : /*
1833 : * As we're in a transaction, make the ldb request directly
1834 : * to avoid the nested transaction that would result if we
1835 : * called dsdb_autotransaction_request
1836 : */
1837 37714 : ret = ldb_request(sam_ctx, req);
1838 37714 : if (ret == LDB_SUCCESS) {
1839 37713 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1840 : }
1841 37714 : TALLOC_FREE(req);
1842 37714 : if (ret != LDB_SUCCESS) {
1843 3 : status = NT_STATUS_INTERNAL_ERROR;
1844 3 : goto error;
1845 : }
1846 : }
1847 52781 : status = authsam_clear_bad_password_indicator(sam_ctx, mem_ctx, msg);
1848 52781 : if (!NT_STATUS_IS_OK(status)) {
1849 0 : goto error;
1850 : }
1851 :
1852 : /*
1853 : * Note that we may not have updated the user record, but
1854 : * committing the transaction in that case is still the correct
1855 : * thing to do.
1856 : * If the transaction was cancelled, this would be logged by
1857 : * the dsdb audit log as a failure. When in fact it is expected
1858 : * behaviour.
1859 : *
1860 : * Thankfully both TDB and LMDB seem to optimise for the empty
1861 : * transaction case
1862 : */
1863 52781 : exit:
1864 52781 : TALLOC_FREE(mem_ctx);
1865 :
1866 52781 : if (txn_active == false) {
1867 15070 : return status;
1868 : }
1869 :
1870 37711 : ret = ldb_transaction_commit(sam_ctx);
1871 37711 : if (ret != LDB_SUCCESS) {
1872 1 : DBG_ERR("Error (%d) %s, committing transaction,"
1873 : " while updating successful logon accounting"
1874 : " for (%s)\n",
1875 : ret,
1876 : ldb_errstring(sam_ctx),
1877 : ldb_dn_get_linearized(msg->dn));
1878 1 : return NT_STATUS_INTERNAL_ERROR;
1879 : }
1880 37710 : return status;
1881 :
1882 10 : error:
1883 10 : DBG_ERR("Failed to update badPwdCount, badPasswordTime or "
1884 : "set lockoutTime on %s: %s\n",
1885 : ldb_dn_get_linearized(msg->dn),
1886 : ldb_errstring(sam_ctx) != NULL ?
1887 : ldb_errstring(sam_ctx) :nt_errstr(status));
1888 10 : if (txn_active) {
1889 8 : ret = ldb_transaction_cancel(sam_ctx);
1890 8 : if (ret != LDB_SUCCESS) {
1891 1 : DBG_ERR("Error rolling back transaction,"
1892 : " while updating bad password count"
1893 : " on %s: %s\n",
1894 : ldb_dn_get_linearized(msg->dn),
1895 : ldb_errstring(sam_ctx));
1896 : }
1897 : }
1898 10 : TALLOC_FREE(mem_ctx);
1899 10 : return status;
1900 : }
|