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