LCOV - code coverage report
Current view: top level - source4/auth - sam.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 651 800 81.4 %
Date: 2024-01-11 09:59:51 Functions: 20 20 100.0 %

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

Generated by: LCOV version 1.14