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

Generated by: LCOV version 1.14