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