LCOV - code coverage report
Current view: top level - source4/auth - sam.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 327 465 70.3 %
Date: 2021-09-23 10:06:22 Functions: 12 12 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             : 
      35             : #undef DBGC_CLASS
      36             : #define DBGC_CLASS DBGC_AUTH
      37             : 
      38             : #define KRBTGT_ATTRS                            \
      39             :         /* required for the krb5 kdc */         \
      40             :         "objectClass",                                \
      41             :         "sAMAccountName",                     \
      42             :         "userPrincipalName",                  \
      43             :         "servicePrincipalName",                       \
      44             :         "msDS-KeyVersionNumber",              \
      45             :         "msDS-SecondaryKrbTgtNumber",         \
      46             :         "msDS-SupportedEncryptionTypes",      \
      47             :         "supplementalCredentials",            \
      48             :         "msDS-AllowedToDelegateTo",           \
      49             :                                                 \
      50             :         /* passwords */                         \
      51             :         "dBCSPwd",                            \
      52             :         "unicodePwd",                         \
      53             :                                                 \
      54             :         "userAccountControl",                 \
      55             :         "msDS-User-Account-Control-Computed", \
      56             :         "objectSid",                          \
      57             :                                                 \
      58             :         "pwdLastSet",                         \
      59             :         "msDS-UserPasswordExpiryTimeComputed",        \
      60             :         "accountExpires"
      61             : 
      62             : const char *krbtgt_attrs[] = {
      63             :         KRBTGT_ATTRS, NULL
      64             : };
      65             : 
      66             : const char *server_attrs[] = {
      67             :         KRBTGT_ATTRS, NULL
      68             : };
      69             : 
      70             : const char *user_attrs[] = {
      71             :         /*
      72             :          * This ordering (having msDS-ResultantPSO first) is
      73             :          * important.  By processing this attribute first it is
      74             :          * available in the operational module for the other PSO
      75             :          * attribute calcuations to use.
      76             :          */
      77             :         "msDS-ResultantPSO",
      78             : 
      79             :         KRBTGT_ATTRS,
      80             : 
      81             :         "logonHours",
      82             : 
      83             :         /*
      84             :          * To allow us to zero the badPwdCount and lockoutTime on
      85             :          * successful logon, without database churn
      86             :          */
      87             :         "lockoutTime",
      88             : 
      89             :         /*
      90             :          * Needed for SendToSAM requests
      91             :          */
      92             :         "objectGUID",
      93             : 
      94             :         /* check 'allowed workstations' */
      95             :         "userWorkstations",
      96             : 
      97             :         /* required for user_info_dc, not access control: */
      98             :         "displayName",
      99             :         "scriptPath",
     100             :         "profilePath",
     101             :         "homeDirectory",
     102             :         "homeDrive",
     103             :         "lastLogon",
     104             :         "lastLogonTimestamp",
     105             :         "lastLogoff",
     106             :         "accountExpires",
     107             :         "badPwdCount",
     108             :         "logonCount",
     109             :         "primaryGroupID",
     110             :         "memberOf",
     111             :         "badPasswordTime",
     112             :         "lmPwdHistory",
     113             :         "ntPwdHistory",
     114             :         NULL,
     115             : };
     116             : 
     117             : /****************************************************************************
     118             :  Check if a user is allowed to logon at this time. Note this is the
     119             :  servers local time, as logon hours are just specified as a weekly
     120             :  bitmask.
     121             : ****************************************************************************/
     122             :                                                                                                               
     123       44562 : static bool logon_hours_ok(struct ldb_message *msg, const char *name_for_logs)
     124             : {
     125             :         /* In logon hours first bit is Sunday from 12AM to 1AM */
     126             :         const struct ldb_val *hours;
     127             :         struct tm *utctime;
     128             :         time_t lasttime;
     129             :         const char *asct;
     130             :         uint8_t bitmask, bitpos;
     131             : 
     132       44562 :         hours = ldb_msg_find_ldb_val(msg, "logonHours");
     133       44562 :         if (!hours) {
     134       44560 :                 DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
     135       42816 :                 return true;
     136             :         }
     137             : 
     138           2 :         if (hours->length != 168/8) {
     139           0 :                 DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
     140           0 :                 return true;            
     141             :         }
     142             : 
     143           2 :         lasttime = time(NULL);
     144           2 :         utctime = gmtime(&lasttime);
     145           2 :         if (!utctime) {
     146           0 :                 DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
     147             :                         name_for_logs));
     148           0 :                 return false;
     149             :         }
     150             : 
     151             :         /* find the corresponding byte and bit */
     152           2 :         bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
     153           2 :         bitmask = 1 << (bitpos % 8);
     154             : 
     155           2 :         if (! (hours->data[bitpos/8] & bitmask)) {
     156           0 :                 struct tm *t = localtime(&lasttime);
     157           0 :                 if (!t) {
     158           0 :                         asct = "INVALID TIME";
     159             :                 } else {
     160           0 :                         asct = asctime(t);
     161           0 :                         if (!asct) {
     162           0 :                                 asct = "INVALID TIME";
     163             :                         }
     164             :                 }
     165             :                 
     166           0 :                 DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
     167             :                           "logon at this time (%s).\n",
     168             :                           name_for_logs, asct ));
     169           0 :                 return false;
     170             :         }
     171             : 
     172           2 :         asct = asctime(utctime);
     173           2 :         DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
     174             :                 name_for_logs, asct ? asct : "UNKNOWN TIME" ));
     175             : 
     176           2 :         return true;
     177             : }
     178             : 
     179             : /****************************************************************************
     180             :  Do a specific test for a SAM_ACCOUNT being valid for this connection
     181             :  (ie not disabled, expired and the like).
     182             : ****************************************************************************/
     183       45342 : _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
     184             :                                      struct ldb_context *sam_ctx,
     185             :                                      uint32_t logon_parameters,
     186             :                                      struct ldb_dn *domain_dn,
     187             :                                      struct ldb_message *msg,
     188             :                                      const char *logon_workstation,
     189             :                                      const char *name_for_logs,
     190             :                                      bool allow_domain_trust,
     191             :                                      bool password_change)
     192             : {
     193             :         uint16_t acct_flags;
     194             :         const char *workstation_list;
     195             :         NTTIME acct_expiry;
     196             :         NTTIME must_change_time;
     197       45342 :         struct timeval tv_now = timeval_current();
     198       45342 :         NTTIME now = timeval_to_nttime(&tv_now);
     199             : 
     200       45342 :         DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
     201             : 
     202       45342 :         acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
     203             :         
     204       45342 :         acct_expiry = samdb_result_account_expires(msg);
     205             : 
     206             :         /* Check for when we must change this password, taking the
     207             :          * userAccountControl flags into account */
     208       45342 :         must_change_time = samdb_result_nttime(msg,
     209             :                         "msDS-UserPasswordExpiryTimeComputed", 0);
     210             : 
     211       45342 :         workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL);
     212             : 
     213             :         /* Quit if the account was disabled. */
     214       45342 :         if (acct_flags & ACB_DISABLED) {
     215         426 :                 DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
     216         426 :                 return NT_STATUS_ACCOUNT_DISABLED;
     217             :         }
     218             : 
     219             :         /* Quit if the account was locked out. */
     220       44916 :         if (acct_flags & ACB_AUTOLOCK) {
     221           0 :                 DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
     222           0 :                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
     223             :         }
     224             : 
     225             :         /* Test account expire time */
     226       44916 :         if (now > acct_expiry) {
     227           0 :                 DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
     228           0 :                 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n", 
     229             :                          nt_time_string(mem_ctx, acct_expiry)));
     230           0 :                 return NT_STATUS_ACCOUNT_EXPIRED;
     231             :         }
     232             : 
     233             :         /* check for immediate expiry "must change at next logon" (but not if this is a password change request) */
     234       44916 :         if ((must_change_time == 0) && !password_change) {
     235          11 :                 DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n",
     236             :                          name_for_logs));
     237          11 :                 return NT_STATUS_PASSWORD_MUST_CHANGE;
     238             :         }
     239             : 
     240             :         /* check for expired password (but not if this is a password change request) */
     241       44905 :         if ((must_change_time < now) && !password_change) {
     242           0 :                 DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n",
     243             :                          name_for_logs));
     244           0 :                 DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n",
     245             :                          nt_time_string(mem_ctx, must_change_time)));
     246           0 :                 return NT_STATUS_PASSWORD_EXPIRED;
     247             :         }
     248             : 
     249             :         /* Test workstation. Workstation list is comma separated. */
     250       44905 :         if (logon_workstation && workstation_list && *workstation_list) {
     251         343 :                 bool invalid_ws = true;
     252             :                 int i;
     253         343 :                 char **workstations = str_list_make(mem_ctx, workstation_list, ",");
     254             : 
     255         686 :                 for (i = 0; workstations && workstations[i]; i++) {
     256         343 :                         DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
     257             :                                   workstations[i], logon_workstation));
     258             : 
     259         343 :                         if (strequal(workstations[i], logon_workstation)) {
     260           0 :                                 invalid_ws = false;
     261           0 :                                 break;
     262             :                         }
     263             :                 }
     264             : 
     265         343 :                 talloc_free(workstations);
     266             : 
     267         343 :                 if (invalid_ws) {
     268         343 :                         return NT_STATUS_INVALID_WORKSTATION;
     269             :                 }
     270             :         }
     271             :         
     272       44562 :         if (!logon_hours_ok(msg, name_for_logs)) {
     273           0 :                 return NT_STATUS_INVALID_LOGON_HOURS;
     274             :         }
     275             :         
     276       44562 :         if (!allow_domain_trust) {
     277       18219 :                 if (acct_flags & ACB_DOMTRUST) {
     278           0 :                         DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
     279           0 :                         return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
     280             :                 }
     281             :         }
     282       44562 :         if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
     283       10098 :                 if (acct_flags & ACB_SVRTRUST) {
     284           0 :                         DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
     285           0 :                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
     286             :                 }
     287             :         }
     288       44562 :         if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
     289             :                 /* TODO: this fails with current solaris client. We
     290             :                    need to work with Gordon to work out why */
     291        9072 :                 if (acct_flags & ACB_WSTRUST) {
     292         342 :                         DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
     293         342 :                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
     294             :                 }
     295             :         }
     296             : 
     297       44220 :         return NT_STATUS_OK;
     298             : }
     299             : 
     300       85167 : static NTSTATUS authsam_domain_group_filter(TALLOC_CTX *mem_ctx,
     301             :                                             char **_filter)
     302             : {
     303       85167 :         char *filter = NULL;
     304             : 
     305       85167 :         *_filter = NULL;
     306             : 
     307       85167 :         filter = talloc_strdup(mem_ctx, "(&(objectClass=group)");
     308       85167 :         if (filter == NULL) {
     309           0 :                 return NT_STATUS_NO_MEMORY;
     310             :         }
     311             : 
     312             :         /*
     313             :          * Skip all builtin groups, they're added later.
     314             :          */
     315       85167 :         filter = talloc_asprintf_append_buffer(filter,
     316             :                                 "(!(groupType:1.2.840.113556.1.4.803:=%u))",
     317             :                                 GROUP_TYPE_BUILTIN_LOCAL_GROUP);
     318       85167 :         if (filter == NULL) {
     319           0 :                 return NT_STATUS_NO_MEMORY;
     320             :         }
     321             :         /*
     322             :          * Only include security groups.
     323             :          */
     324       85167 :         filter = talloc_asprintf_append_buffer(filter,
     325             :                                 "(groupType:1.2.840.113556.1.4.803:=%u))",
     326             :                                 GROUP_TYPE_SECURITY_ENABLED);
     327       85167 :         if (filter == NULL) {
     328           0 :                 return NT_STATUS_NO_MEMORY;
     329             :         }
     330             : 
     331       85167 :         *_filter = filter;
     332       85167 :         return NT_STATUS_OK;
     333             : }
     334             : 
     335       45047 : _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx,
     336             :                                            struct ldb_context *sam_ctx,
     337             :                                            const char *netbios_name,
     338             :                                            const char *domain_name,
     339             :                                            const char *dns_domain_name,
     340             :                                            struct ldb_dn *domain_dn, 
     341             :                                            struct ldb_message *msg,
     342             :                                            DATA_BLOB user_sess_key,
     343             :                                            DATA_BLOB lm_sess_key,
     344             :                                            struct auth_user_info_dc **_user_info_dc)
     345             : {
     346             :         NTSTATUS status;
     347             :         struct auth_user_info_dc *user_info_dc;
     348             :         struct auth_user_info *info;
     349       45047 :         const char *str = NULL;
     350       45047 :         char *filter = NULL;
     351             :         /* SIDs for the account and his primary group */
     352             :         struct dom_sid *account_sid;
     353             :         struct dom_sid_buf buf;
     354             :         const char *primary_group_dn;
     355             :         DATA_BLOB primary_group_blob;
     356             :         /* SID structures for the expanded group memberships */
     357       45047 :         struct dom_sid *sids = NULL;
     358       45047 :         unsigned int num_sids = 0, i;
     359             :         struct dom_sid *domain_sid;
     360             :         TALLOC_CTX *tmp_ctx;
     361             :         struct ldb_message_element *el;
     362             : 
     363       45047 :         user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
     364       45047 :         NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
     365             : 
     366       45047 :         tmp_ctx = talloc_new(user_info_dc);
     367       45047 :         if (tmp_ctx == NULL) {
     368           0 :                 TALLOC_FREE(user_info_dc);
     369           0 :                 return NT_STATUS_NO_MEMORY;
     370             :         }
     371             : 
     372       45047 :         sids = talloc_array(user_info_dc, struct dom_sid, 2);
     373       45047 :         if (sids == NULL) {
     374           0 :                 TALLOC_FREE(user_info_dc);
     375           0 :                 return NT_STATUS_NO_MEMORY;
     376             :         }
     377             : 
     378       45047 :         num_sids = 2;
     379             : 
     380       45047 :         account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
     381       45047 :         if (account_sid == NULL) {
     382           0 :                 TALLOC_FREE(user_info_dc);
     383           0 :                 return NT_STATUS_NO_MEMORY;
     384             :         }
     385             : 
     386       45047 :         status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
     387       45047 :         if (!NT_STATUS_IS_OK(status)) {
     388           0 :                 talloc_free(user_info_dc);
     389           0 :                 return status;
     390             :         }
     391             : 
     392       45047 :         sids[PRIMARY_USER_SID_INDEX] = *account_sid;
     393       45047 :         sids[PRIMARY_GROUP_SID_INDEX] = *domain_sid;
     394       45047 :         sid_append_rid(&sids[PRIMARY_GROUP_SID_INDEX], ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0));
     395             : 
     396             :         /*
     397             :          * Filter out builtin groups from this token. We will search
     398             :          * for builtin groups later, and not include them in the PAC
     399             :          * or SamLogon validation info.
     400             :          */
     401       45047 :         status = authsam_domain_group_filter(tmp_ctx, &filter);
     402       45047 :         if (!NT_STATUS_IS_OK(status)) {
     403           0 :                 TALLOC_FREE(user_info_dc);
     404           0 :                 return status;
     405             :         }
     406             : 
     407       86024 :         primary_group_dn = talloc_asprintf(
     408             :                 tmp_ctx,
     409             :                 "<SID=%s>",
     410       45047 :                 dom_sid_str_buf(&sids[PRIMARY_GROUP_SID_INDEX], &buf));
     411       45047 :         if (primary_group_dn == NULL) {
     412           0 :                 TALLOC_FREE(user_info_dc);
     413           0 :                 return NT_STATUS_NO_MEMORY;
     414             :         }
     415             : 
     416       45047 :         primary_group_blob = data_blob_string_const(primary_group_dn);
     417             : 
     418             :         /* Expands the primary group - this function takes in
     419             :          * memberOf-like values, so we fake one up with the
     420             :          * <SID=S-...> format of DN and then let it expand
     421             :          * them, as long as they meet the filter - so only
     422             :          * domain groups, not builtin groups
     423             :          *
     424             :          * The primary group is still treated specially, so we set the
     425             :          * 'only childs' flag to true
     426             :          */
     427       45047 :         status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
     428             :                                            user_info_dc, &sids, &num_sids);
     429       45047 :         if (!NT_STATUS_IS_OK(status)) {
     430           0 :                 talloc_free(user_info_dc);
     431           0 :                 return status;
     432             :         }
     433             : 
     434             :         /* Expands the additional groups */
     435       45047 :         el = ldb_msg_find_element(msg, "memberOf");
     436      200034 :         for (i = 0; el && i < el->num_values; i++) {
     437             :                 /* This function takes in memberOf values and expands
     438             :                  * them, as long as they meet the filter - so only
     439             :                  * domain groups, not builtin groups */
     440      154987 :                 status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
     441             :                                                    user_info_dc, &sids, &num_sids);
     442      154987 :                 if (!NT_STATUS_IS_OK(status)) {
     443           0 :                         talloc_free(user_info_dc);
     444           0 :                         return status;
     445             :                 }
     446             :         }
     447             : 
     448       45047 :         user_info_dc->sids = sids;
     449       45047 :         user_info_dc->num_sids = num_sids;
     450             : 
     451       45047 :         user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info);
     452       45047 :         NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info);
     453             : 
     454       45047 :         info->account_name = talloc_steal(info,
     455             :                 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
     456             : 
     457       45047 :         info->user_principal_name = talloc_steal(info,
     458             :                 ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL));
     459       45047 :         if (info->user_principal_name == NULL && dns_domain_name != NULL) {
     460       38474 :                 info->user_principal_name = talloc_asprintf(info, "%s@%s",
     461             :                                         info->account_name,
     462             :                                         dns_domain_name);
     463       38474 :                 if (info->user_principal_name == NULL) {
     464           0 :                         TALLOC_FREE(user_info_dc);
     465           0 :                         return NT_STATUS_NO_MEMORY;
     466             :                 }
     467       38474 :                 info->user_principal_constructed = true;
     468             :         }
     469             : 
     470       45047 :         info->domain_name = talloc_strdup(info, domain_name);
     471       45047 :         if (info->domain_name == NULL) {
     472           0 :                 TALLOC_FREE(user_info_dc);
     473           0 :                 return NT_STATUS_NO_MEMORY;
     474             :         }
     475             : 
     476       45047 :         if (dns_domain_name != NULL) {
     477       44951 :                 info->dns_domain_name = talloc_strdup(info, dns_domain_name);
     478       44951 :                 if (info->dns_domain_name == NULL) {
     479           0 :                         TALLOC_FREE(user_info_dc);
     480           0 :                         return NT_STATUS_NO_MEMORY;
     481             :                 }
     482             :         }
     483             : 
     484       45047 :         str = ldb_msg_find_attr_as_string(msg, "displayName", "");
     485       45047 :         info->full_name = talloc_strdup(info, str);
     486       45047 :         if (info->full_name == NULL) {
     487           0 :                 TALLOC_FREE(user_info_dc);
     488           0 :                 return NT_STATUS_NO_MEMORY;
     489             :         }
     490             : 
     491       45047 :         str = ldb_msg_find_attr_as_string(msg, "scriptPath", "");
     492       45047 :         info->logon_script = talloc_strdup(info, str);
     493       45047 :         if (info->logon_script == NULL) {
     494           0 :                 TALLOC_FREE(user_info_dc);
     495           0 :                 return NT_STATUS_NO_MEMORY;
     496             :         }
     497             : 
     498       45047 :         str = ldb_msg_find_attr_as_string(msg, "profilePath", "");
     499       45047 :         info->profile_path = talloc_strdup(info, str);
     500       45047 :         if (info->profile_path == NULL) {
     501           0 :                 TALLOC_FREE(user_info_dc);
     502           0 :                 return NT_STATUS_NO_MEMORY;
     503             :         }
     504             : 
     505       45047 :         str = ldb_msg_find_attr_as_string(msg, "homeDirectory", "");
     506       45047 :         info->home_directory = talloc_strdup(info, str);
     507       45047 :         if (info->home_directory == NULL) {
     508           0 :                 TALLOC_FREE(user_info_dc);
     509           0 :                 return NT_STATUS_NO_MEMORY;
     510             :         }
     511             : 
     512       45047 :         str = ldb_msg_find_attr_as_string(msg, "homeDrive", "");
     513       45047 :         info->home_drive = talloc_strdup(info, str);
     514       45047 :         if (info->home_drive == NULL) {
     515           0 :                 TALLOC_FREE(user_info_dc);
     516           0 :                 return NT_STATUS_NO_MEMORY;
     517             :         }
     518             : 
     519       45047 :         info->logon_server = talloc_strdup(info, netbios_name);
     520       45047 :         if (info->logon_server == NULL) {
     521           0 :                 TALLOC_FREE(user_info_dc);
     522           0 :                 return NT_STATUS_NO_MEMORY;
     523             :         }
     524             : 
     525       45047 :         info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
     526       45047 :         info->last_logoff = samdb_result_last_logoff(msg);
     527       45047 :         info->acct_expiry = samdb_result_account_expires(msg);
     528       45047 :         info->last_password_change = samdb_result_nttime(msg,
     529             :                 "pwdLastSet", 0);
     530             :         info->allow_password_change
     531       45047 :                 = samdb_result_allow_password_change(sam_ctx, mem_ctx, 
     532             :                         domain_dn, msg, "pwdLastSet");
     533       45047 :         info->force_password_change = samdb_result_nttime(msg,
     534             :                 "msDS-UserPasswordExpiryTimeComputed", 0);
     535       45047 :         info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0);
     536       45047 :         info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount",
     537             :                 0);
     538             : 
     539       45047 :         info->acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
     540             : 
     541       45047 :         user_info_dc->user_session_key = data_blob_talloc(user_info_dc,
     542             :                                                          user_sess_key.data,
     543             :                                                          user_sess_key.length);
     544       45047 :         if (user_sess_key.data) {
     545       16845 :                 if (user_info_dc->user_session_key.data == NULL) {
     546           0 :                         TALLOC_FREE(user_info_dc);
     547           0 :                         return NT_STATUS_NO_MEMORY;
     548             :                 }
     549             :         }
     550       45047 :         user_info_dc->lm_session_key = data_blob_talloc(user_info_dc,
     551             :                                                        lm_sess_key.data,
     552             :                                                        lm_sess_key.length);
     553       45047 :         if (lm_sess_key.data) {
     554       16086 :                 if (user_info_dc->lm_session_key.data == NULL) {
     555           0 :                         TALLOC_FREE(user_info_dc);
     556           0 :                         return NT_STATUS_NO_MEMORY;
     557             :                 }
     558             :         }
     559             : 
     560       45047 :         if (info->acct_flags & ACB_SVRTRUST) {
     561             :                 /* the SID_NT_ENTERPRISE_DCS SID gets added into the
     562             :                    PAC */
     563        3979 :                 user_info_dc->sids = talloc_realloc(user_info_dc,
     564             :                                                    user_info_dc->sids,
     565             :                                                    struct dom_sid,
     566             :                                                    user_info_dc->num_sids+1);
     567        3979 :                 if (user_info_dc->sids == NULL) {
     568           0 :                         TALLOC_FREE(user_info_dc);
     569           0 :                         return NT_STATUS_NO_MEMORY;
     570             :                 }
     571        3979 :                 user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs;
     572        3979 :                 user_info_dc->num_sids++;
     573             :         }
     574             : 
     575       45047 :         if ((info->acct_flags & (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) ==
     576             :             (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) {
     577             :                 /* the DOMAIN_RID_ENTERPRISE_READONLY_DCS PAC */
     578         859 :                 user_info_dc->sids = talloc_realloc(user_info_dc,
     579             :                                                    user_info_dc->sids,
     580             :                                                    struct dom_sid,
     581             :                                                    user_info_dc->num_sids+1);
     582         859 :                 if (user_info_dc->sids == NULL) {
     583           0 :                         TALLOC_FREE(user_info_dc);
     584           0 :                         return NT_STATUS_NO_MEMORY;
     585             :                 }
     586         859 :                 user_info_dc->sids[user_info_dc->num_sids] = *domain_sid;
     587         859 :                 sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids],
     588             :                             DOMAIN_RID_ENTERPRISE_READONLY_DCS);
     589         859 :                 user_info_dc->num_sids++;
     590             :         }
     591             : 
     592       45047 :         info->authenticated = true;
     593             : 
     594       45047 :         talloc_free(tmp_ctx);
     595       45047 :         *_user_info_dc = user_info_dc;
     596             : 
     597       45047 :         return NT_STATUS_OK;
     598             : }
     599             : 
     600       40120 : _PUBLIC_ NTSTATUS authsam_update_user_info_dc(TALLOC_CTX *mem_ctx,
     601             :                         struct ldb_context *sam_ctx,
     602             :                         struct auth_user_info_dc *user_info_dc)
     603             : {
     604       40120 :         char *filter = NULL;
     605             :         NTSTATUS status;
     606             :         uint32_t i;
     607       40120 :         uint32_t n = 0;
     608             : 
     609             :         /*
     610             :          * This function exists to expand group memberships
     611             :          * in the local domain (forest), as the token
     612             :          * may come from a different domain.
     613             :          */
     614             : 
     615             :         /*
     616             :          * Filter out builtin groups from this token. We will search
     617             :          * for builtin groups later.
     618             :          */
     619       40120 :         status = authsam_domain_group_filter(mem_ctx, &filter);
     620       40120 :         if (!NT_STATUS_IS_OK(status)) {
     621           0 :                 TALLOC_FREE(user_info_dc);
     622           0 :                 return status;
     623             :         }
     624             : 
     625             :         /*
     626             :          * We loop only over the existing number of
     627             :          * sids.
     628             :          */
     629       40120 :         n = user_info_dc->num_sids;
     630      279377 :         for (i = 0; i < n; i++) {
     631      239257 :                 struct dom_sid *sid = &user_info_dc->sids[i];
     632             :                 struct dom_sid_buf sid_buf;
     633             :                 char dn_str[sizeof(sid_buf.buf)*2];
     634      239257 :                 DATA_BLOB dn_blob = data_blob_null;
     635             : 
     636      245501 :                 snprintf(dn_str,
     637             :                         sizeof(dn_str),
     638             :                         "<SID=%s>",
     639             :                         dom_sid_str_buf(sid, &sid_buf));
     640      239257 :                 dn_blob = data_blob_string_const(dn_str);
     641             : 
     642             :                 /*
     643             :                  * We already have the SID in the token, so set
     644             :                  * 'only childs' flag to true and add all
     645             :                  * groups which match the filter.
     646             :                  */
     647      239257 :                 status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
     648             :                                                    true, filter,
     649             :                                                    user_info_dc,
     650             :                                                    &user_info_dc->sids,
     651      239257 :                                                    &user_info_dc->num_sids);
     652      239257 :                 if (!NT_STATUS_IS_OK(status)) {
     653           0 :                         return status;
     654             :                 }
     655             :         }
     656             : 
     657       40120 :         return NT_STATUS_OK;
     658             : }
     659             : 
     660       90630 : NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
     661             :                                    TALLOC_CTX *mem_ctx, const char *principal,
     662             :                                    const char **attrs,
     663             :                                    struct ldb_dn **domain_dn,
     664             :                                    struct ldb_message **msg)
     665             : {                          
     666             :         struct ldb_dn *user_dn;
     667             :         NTSTATUS nt_status;
     668       90630 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     669             :         int ret;
     670             : 
     671       90630 :         if (!tmp_ctx) {
     672           0 :                 return NT_STATUS_NO_MEMORY;
     673             :         }
     674             : 
     675       90630 :         nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, 
     676             :                                               &user_dn, domain_dn);
     677       90630 :         if (!NT_STATUS_IS_OK(nt_status)) {
     678        5367 :                 talloc_free(tmp_ctx);
     679        5367 :                 return nt_status;
     680             :         }
     681             :         
     682             :         /* pull the user attributes */
     683       85263 :         ret = dsdb_search_one(sam_ctx, tmp_ctx, msg, user_dn,
     684             :                               LDB_SCOPE_BASE, attrs,
     685             :                               DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
     686             :                               "(objectClass=*)");
     687       85263 :         if (ret != LDB_SUCCESS) {
     688           0 :                 talloc_free(tmp_ctx);
     689           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     690             :         }
     691       85263 :         talloc_steal(mem_ctx, *msg);
     692       85263 :         talloc_steal(mem_ctx, *domain_dn);
     693       85263 :         talloc_free(tmp_ctx);
     694             :         
     695       85263 :         return NT_STATUS_OK;
     696             : }
     697             : 
     698             : /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
     699             : 
     700             :  Supply either a principal or a DN
     701             : */
     702         158 : NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
     703             :                                            struct loadparm_context *lp_ctx,
     704             :                                            struct ldb_context *sam_ctx,
     705             :                                            const char *principal,
     706             :                                            struct ldb_dn *user_dn,
     707             :                                            struct auth_user_info_dc **user_info_dc)
     708             : {
     709             :         NTSTATUS nt_status;
     710         158 :         DATA_BLOB user_sess_key = data_blob(NULL, 0);
     711         158 :         DATA_BLOB lm_sess_key = data_blob(NULL, 0);
     712             : 
     713             :         struct ldb_message *msg;
     714             :         struct ldb_dn *domain_dn;
     715             : 
     716         158 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     717         158 :         if (!tmp_ctx) {
     718           0 :                 return NT_STATUS_NO_MEMORY;
     719             :         }
     720             : 
     721         158 :         if (principal) {
     722           0 :                 nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
     723             :                                                       user_attrs, &domain_dn, &msg);
     724           0 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     725           0 :                         talloc_free(tmp_ctx);
     726           0 :                         return nt_status;
     727             :                 }
     728         158 :         } else if (user_dn) {
     729             :                 struct dom_sid *user_sid, *domain_sid;
     730             :                 int ret;
     731             :                 /* pull the user attributes */
     732         158 :                 ret = dsdb_search_one(sam_ctx, tmp_ctx, &msg, user_dn,
     733             :                                       LDB_SCOPE_BASE, user_attrs,
     734             :                                       DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
     735             :                                       "(objectClass=*)");
     736         158 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     737           0 :                         talloc_free(tmp_ctx);
     738           0 :                         return NT_STATUS_NO_SUCH_USER;
     739         158 :                 } else if (ret != LDB_SUCCESS) {
     740           0 :                         talloc_free(tmp_ctx);
     741           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     742             :                 }
     743             : 
     744         158 :                 user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
     745             : 
     746         158 :                 nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
     747         158 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     748           0 :                         return nt_status;
     749             :                 }
     750             : 
     751         158 :                 domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
     752             :                                           "(&(objectSid=%s)(objectClass=domain))",
     753             :                                             ldap_encode_ndr_dom_sid(tmp_ctx, domain_sid));
     754         158 :                 if (!domain_dn) {
     755             :                         struct dom_sid_buf buf;
     756           0 :                         DEBUG(3, ("authsam_get_user_info_dc_principal: Failed to find domain with: SID %s\n",
     757             :                                   dom_sid_str_buf(domain_sid, &buf)));
     758           0 :                         return NT_STATUS_NO_SUCH_USER;
     759             :                 }
     760             : 
     761             :         } else {
     762           0 :                 return NT_STATUS_INVALID_PARAMETER;
     763             :         }
     764             : 
     765         158 :         nt_status = authsam_make_user_info_dc(tmp_ctx, sam_ctx,
     766             :                                              lpcfg_netbios_name(lp_ctx),
     767             :                                              lpcfg_sam_name(lp_ctx),
     768             :                                              lpcfg_sam_dnsname(lp_ctx),
     769             :                                              domain_dn,
     770             :                                              msg,
     771             :                                              user_sess_key, lm_sess_key,
     772             :                                              user_info_dc);
     773         158 :         if (!NT_STATUS_IS_OK(nt_status)) {
     774           0 :                 talloc_free(tmp_ctx);
     775           0 :                 return nt_status;
     776             :         }
     777             : 
     778         158 :         talloc_steal(mem_ctx, *user_info_dc);
     779         158 :         talloc_free(tmp_ctx);
     780             : 
     781         158 :         return NT_STATUS_OK;
     782             : }
     783             : 
     784             : /*
     785             :  * Returns the details for the Password Settings Object (PSO), if one applies
     786             :  * the user.
     787             :  */
     788        3005 : static int authsam_get_user_pso(struct ldb_context *sam_ctx,
     789             :                                 TALLOC_CTX *mem_ctx,
     790             :                                 struct ldb_message *user_msg,
     791             :                                 struct ldb_message **pso_msg)
     792             : {
     793        3005 :         const char *attrs[] = { "msDS-LockoutThreshold",
     794             :                                 "msDS-LockoutObservationWindow",
     795             :                                 NULL };
     796        3005 :         struct ldb_dn *pso_dn = NULL;
     797        3005 :         struct ldb_result *res = NULL;
     798             :         int ret;
     799             : 
     800             :         /* check if the user has a PSO that applies to it */
     801        3005 :         pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
     802             :                                          "msDS-ResultantPSO");
     803             : 
     804        3005 :         if (pso_dn != NULL) {
     805          25 :                 ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
     806          25 :                 if (ret != LDB_SUCCESS) {
     807           0 :                         return ret;
     808             :                 }
     809             : 
     810          25 :                 *pso_msg = res->msgs[0];
     811             :         }
     812             : 
     813        3005 :         return LDB_SUCCESS;
     814             : }
     815             : 
     816        3005 : NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
     817             :                                       struct ldb_message *msg,
     818             :                                       struct ldb_dn *domain_dn)
     819             : {
     820        3005 :         const char *attrs[] = { "lockoutThreshold",
     821             :                                 "lockOutObservationWindow",
     822             :                                 "lockoutDuration",
     823             :                                 "pwdProperties",
     824             :                                 NULL };
     825             :         int ret;
     826             :         NTSTATUS status;
     827             :         struct ldb_result *domain_res;
     828        3005 :         struct ldb_message *msg_mod = NULL;
     829        3005 :         struct ldb_message *pso_msg = NULL;
     830             :         TALLOC_CTX *mem_ctx;
     831             : 
     832        3005 :         mem_ctx = talloc_new(msg);
     833        3005 :         if (mem_ctx == NULL) {
     834           0 :                 return NT_STATUS_NO_MEMORY;
     835             :         }
     836             : 
     837        3005 :         ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
     838        3005 :         if (ret != LDB_SUCCESS) {
     839           0 :                 TALLOC_FREE(mem_ctx);
     840           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     841             :         }
     842             : 
     843        3005 :         ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
     844        3005 :         if (ret != LDB_SUCCESS) {
     845             : 
     846             :                 /*
     847             :                  * fallback to using the domain defaults so that we still
     848             :                  * record the bad password attempt
     849             :                  */
     850           0 :                 DBG_ERR("Error (%d) checking PSO for %s",
     851             :                         ret, ldb_dn_get_linearized(msg->dn));
     852             :         }
     853             : 
     854        5859 :         status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
     855        3005 :                                            msg, domain_res->msgs[0], pso_msg,
     856             :                                            &msg_mod);
     857        3005 :         if (!NT_STATUS_IS_OK(status)) {
     858           0 :                 TALLOC_FREE(mem_ctx);
     859           0 :                 return status;
     860             :         }
     861             : 
     862        3005 :         if (msg_mod != NULL) {
     863             :                 struct ldb_request *req;
     864             : 
     865         509 :                 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
     866             :                                         msg_mod,
     867             :                                         NULL,
     868             :                                         NULL,
     869             :                                         ldb_op_default_callback,
     870             :                                         NULL);
     871         509 :                 if (ret != LDB_SUCCESS) {
     872           0 :                         goto done;
     873             :                 }
     874             : 
     875         509 :                 ret = ldb_request_add_control(req,
     876             :                                               DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
     877             :                                               false, NULL);
     878         509 :                 if (ret != LDB_SUCCESS) {
     879           0 :                         talloc_free(req);
     880           0 :                         goto done;
     881             :                 }
     882             : 
     883         509 :                 ret = dsdb_autotransaction_request(sam_ctx, req);
     884         509 :                 talloc_free(req);
     885             :         }
     886             : 
     887        5350 : done:
     888        3005 :         if (ret != LDB_SUCCESS) {
     889           0 :                 DBG_ERR("Failed to update badPwdCount, badPasswordTime or "
     890             :                         "set lockoutTime on %s: %s\n",
     891             :                         ldb_dn_get_linearized(msg->dn),
     892             :                         ldb_errstring(sam_ctx));
     893           0 :                 TALLOC_FREE(mem_ctx);
     894           0 :                 return NT_STATUS_INTERNAL_ERROR;
     895             :         }
     896             : 
     897        3005 :         TALLOC_FREE(mem_ctx);
     898        3005 :         return NT_STATUS_OK;
     899             : }
     900             : 
     901             : 
     902       42855 : static NTSTATUS authsam_update_lastlogon_timestamp(struct ldb_context *sam_ctx,
     903             :                                             struct ldb_message *msg_mod,
     904             :                                             struct ldb_dn *domain_dn,
     905             :                                             NTTIME old_timestamp,
     906             :                                             NTTIME now)
     907             : {
     908             :         /*
     909             :          * We only set lastLogonTimestamp if the current value is older than
     910             :          * now - msDS-LogonTimeSyncInterval days.
     911             :          *
     912             :          * msDS-LogonTimeSyncInterval is an int32_t number of days, while
     913             :          * lastLogonTimestamp is in the 64 bit 100ns NTTIME format.
     914             :          *
     915             :          * The docs say: "the initial update, after the domain functional
     916             :          * level is raised to DS_BEHAVIOR_WIN2003 or higher, is calculated as
     917             :          * 14 days minus a random percentage of 5 days", but we aren't doing
     918             :          * that. The blogosphere seems to think that this randomised update
     919             :          * happens everytime, but [MS-ADA1] doesn't agree.
     920             :          *
     921             :          * Dochelp referred us to the following blog post:
     922             :          * http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
     923             :          *
     924             :          * en msDS-LogonTimeSyncInterval is zero, the lastLogonTimestamp is
     925             :          * not changed.
     926             :          */
     927             :         static const char *attrs[] = { "msDS-LogonTimeSyncInterval",
     928             :                                         NULL };
     929             :         int ret;
     930       42855 :         struct ldb_result *domain_res = NULL;
     931       42855 :         TALLOC_CTX *mem_ctx = NULL;
     932             :         int32_t sync_interval;
     933             :         NTTIME sync_interval_nt;
     934             : 
     935       42855 :         mem_ctx = talloc_new(msg_mod);
     936       42855 :         if (mem_ctx == NULL) {
     937           0 :                 return NT_STATUS_NO_MEMORY;
     938             :         }
     939             : 
     940       42855 :         ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
     941             :                              0);
     942       42855 :         if (ret != LDB_SUCCESS || domain_res->count != 1) {
     943           0 :                 TALLOC_FREE(mem_ctx);
     944           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     945             :         }
     946             : 
     947       42855 :         sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
     948             :                                                  "msDS-LogonTimeSyncInterval",
     949             :                                                  14);
     950       42855 :         DEBUG(5, ("sync interval is %d\n", sync_interval));
     951       42855 :         if (sync_interval == 0){
     952             :                 /*
     953             :                  * Setting msDS-LogonTimeSyncInterval to zero is how you ask
     954             :                  * that nothing happens here.
     955             :                  */
     956           0 :                 TALLOC_FREE(mem_ctx);
     957           0 :                 return NT_STATUS_OK;
     958             :         }
     959       42855 :         else if (sync_interval >= 5){
     960             :                 /*
     961             :                  * Subtract "a random percentage of 5" days. Presumably this
     962             :                  * percentage is between 0 and 100, and modulus is accurate
     963             :                  * enough.
     964             :                  */
     965       42855 :                 uint32_t r = generate_random() % 6;
     966       42855 :                 sync_interval -= r;
     967       42855 :                 DEBUG(5, ("randomised sync interval is %d (-%d)\n", sync_interval, r));
     968             :         }
     969             :         /* In the case where sync_interval < 5 there is no randomisation */
     970             : 
     971       42855 :         sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
     972             : 
     973       42855 :         DEBUG(5, ("old timestamp is %lld, threshold %lld, diff %lld\n",
     974             :                   (long long int)old_timestamp,
     975             :                   (long long int)(now - sync_interval_nt),
     976             :                   (long long int)(old_timestamp - now + sync_interval_nt)));
     977             : 
     978       42855 :         if (old_timestamp > now){
     979           0 :                 DEBUG(0, ("lastLogonTimestamp is in the future! (%lld > %lld)\n",
     980             :                           (long long int)old_timestamp, (long long int)now));
     981             :                 /* then what? */
     982             : 
     983       42855 :         } else if (old_timestamp < now - sync_interval_nt){
     984        5119 :                 DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
     985             :                           (long long int)now));
     986             : 
     987             :                 /* The time has come to update lastLogonTimestamp */
     988        5119 :                 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
     989             :                                           "lastLogonTimestamp", now);
     990             : 
     991        5119 :                 if (ret != LDB_SUCCESS) {
     992           0 :                         TALLOC_FREE(mem_ctx);
     993           0 :                         return NT_STATUS_NO_MEMORY;
     994             :                 }
     995             :         }
     996       42855 :         TALLOC_FREE(mem_ctx);
     997       42855 :         return NT_STATUS_OK;
     998             : }
     999             : 
    1000             : /****************************************************************************
    1001             :  Look for the specified user in the sam, return ldb result structures
    1002             : ****************************************************************************/
    1003             : 
    1004       22844 : NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
    1005             :                                          const char *account_name,
    1006             :                                          struct ldb_dn *domain_dn,
    1007             :                                          struct ldb_message **ret_msg)
    1008             : {
    1009             :         int ret;
    1010             : 
    1011             :         /* pull the user attributes */
    1012       22844 :         ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
    1013             :                               user_attrs,
    1014             :                               DSDB_SEARCH_SHOW_EXTENDED_DN,
    1015             :                               "(&(sAMAccountName=%s)(objectclass=user))",
    1016             :                               ldb_binary_encode_string(mem_ctx, account_name));
    1017       22844 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    1018         858 :                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n",
    1019             :                          account_name, ldb_dn_get_linearized(domain_dn)));
    1020         858 :                 return NT_STATUS_NO_SUCH_USER;
    1021             :         }
    1022       21986 :         if (ret != LDB_SUCCESS) {
    1023           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1024             :         }
    1025             : 
    1026       21986 :         return NT_STATUS_OK;
    1027             : }
    1028             : 
    1029             : 
    1030             : /* Reset the badPwdCount to zero and update the lastLogon time. */
    1031       44343 : NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
    1032             :                                           const struct ldb_message *msg,
    1033             :                                           struct ldb_dn *domain_dn,
    1034             :                                           bool interactive_or_kerberos,
    1035             :                                           struct netr_SendToSamBase **send_to_sam)
    1036             : {
    1037             :         int ret;
    1038             :         NTSTATUS status;
    1039             :         int badPwdCount;
    1040             :         int dbBadPwdCount;
    1041             :         int64_t lockoutTime;
    1042             :         struct ldb_message *msg_mod;
    1043             :         TALLOC_CTX *mem_ctx;
    1044             :         struct timeval tv_now;
    1045             :         NTTIME now;
    1046             :         NTTIME lastLogonTimestamp;
    1047       44343 :         bool am_rodc = false;
    1048             : 
    1049       44343 :         mem_ctx = talloc_new(msg);
    1050       44343 :         if (mem_ctx == NULL) {
    1051           0 :                 return NT_STATUS_NO_MEMORY;
    1052             :         }
    1053             : 
    1054       44343 :         lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
    1055       44343 :         dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
    1056       44343 :         if (interactive_or_kerberos) {
    1057       26035 :                 badPwdCount = dbBadPwdCount;
    1058             :         } else {
    1059       17718 :                 badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
    1060             :                                                                  domain_dn, msg);
    1061             :         }
    1062       44343 :         lastLogonTimestamp =
    1063       44343 :                 ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
    1064             : 
    1065       44343 :         DEBUG(5, ("lastLogonTimestamp is %lld\n",
    1066             :                   (long long int)lastLogonTimestamp));
    1067             : 
    1068       44343 :         msg_mod = ldb_msg_new(mem_ctx);
    1069       44343 :         if (msg_mod == NULL) {
    1070           0 :                 TALLOC_FREE(mem_ctx);
    1071           0 :                 return NT_STATUS_NO_MEMORY;
    1072             :         }
    1073       44343 :         msg_mod->dn = msg->dn;
    1074             : 
    1075       44343 :         if (lockoutTime != 0) {
    1076             :                 /*
    1077             :                  * This implies "badPwdCount" = 0, see samldb_lockout_time()
    1078             :                  */
    1079          36 :                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
    1080          36 :                 if (ret != LDB_SUCCESS) {
    1081           0 :                         TALLOC_FREE(mem_ctx);
    1082           0 :                         return NT_STATUS_NO_MEMORY;
    1083             :                 }
    1084       44307 :         } else if (badPwdCount != 0) {
    1085         224 :                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
    1086         224 :                 if (ret != LDB_SUCCESS) {
    1087           0 :                         TALLOC_FREE(mem_ctx);
    1088           0 :                         return NT_STATUS_NO_MEMORY;
    1089             :                 }
    1090             :         }
    1091             : 
    1092       44343 :         tv_now = timeval_current();
    1093       44343 :         now = timeval_to_nttime(&tv_now);
    1094             : 
    1095       45497 :         if (interactive_or_kerberos ||
    1096        1266 :             (badPwdCount != 0 && lockoutTime == 0)) {
    1097       26737 :                 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
    1098             :                                           "lastLogon", now);
    1099       26737 :                 if (ret != LDB_SUCCESS) {
    1100           0 :                         TALLOC_FREE(mem_ctx);
    1101           0 :                         return NT_STATUS_NO_MEMORY;
    1102             :                 }
    1103             :         }
    1104             : 
    1105       44343 :         if (interactive_or_kerberos) {
    1106             :                 int logonCount;
    1107             : 
    1108       26625 :                 logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
    1109             : 
    1110       26625 :                 logonCount += 1;
    1111             : 
    1112       26625 :                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
    1113             :                                         "logonCount", logonCount);
    1114       26625 :                 if (ret != LDB_SUCCESS) {
    1115           0 :                         TALLOC_FREE(mem_ctx);
    1116           0 :                         return NT_STATUS_NO_MEMORY;
    1117             :                 }
    1118             :         } else {
    1119             :                 /* Set an unset logonCount to 0 on first successful login */
    1120       17718 :                 if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
    1121          16 :                         ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
    1122             :                                                 "logonCount", 0);
    1123          16 :                         if (ret != LDB_SUCCESS) {
    1124           0 :                                 TALLOC_FREE(mem_ctx);
    1125           0 :                                 return NT_STATUS_NO_MEMORY;
    1126             :                         }
    1127             :                 }
    1128             :         }
    1129             : 
    1130       44343 :         ret = samdb_rodc(sam_ctx, &am_rodc);
    1131       44343 :         if (ret != LDB_SUCCESS) {
    1132           0 :                 TALLOC_FREE(mem_ctx);
    1133           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1134             :         }
    1135             : 
    1136       44343 :         if (!am_rodc) {
    1137       42855 :                 status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
    1138             :                                                             lastLogonTimestamp, now);
    1139       42855 :                 if (!NT_STATUS_IS_OK(status)) {
    1140           0 :                         TALLOC_FREE(mem_ctx);
    1141           0 :                         return NT_STATUS_NO_MEMORY;
    1142             :                 }
    1143             :         } else {
    1144             :                 /* Perform the (async) SendToSAM calls for MS-SAMS */
    1145        1488 :                 if (dbBadPwdCount != 0 && send_to_sam != NULL) {
    1146             :                         struct netr_SendToSamBase *base_msg;
    1147          17 :                         struct GUID guid = samdb_result_guid(msg, "objectGUID");
    1148          17 :                         base_msg = talloc_zero(msg, struct netr_SendToSamBase);
    1149             : 
    1150          17 :                         base_msg->message_type = SendToSamResetBadPasswordCount;
    1151          17 :                         base_msg->message_size = 16;
    1152          17 :                         base_msg->message.reset_bad_password.guid = guid;
    1153          17 :                         *send_to_sam = base_msg;
    1154             :                 }
    1155             :         }
    1156             : 
    1157       44343 :         if (msg_mod->num_elements > 0) {
    1158             :                 unsigned int i;
    1159             :                 struct ldb_request *req;
    1160             : 
    1161             :                 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
    1162       88921 :                 for (i=0;i<msg_mod->num_elements;i++) {
    1163       58757 :                         msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    1164             :                 }
    1165             : 
    1166       30754 :                 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
    1167             :                                         msg_mod,
    1168             :                                         NULL,
    1169             :                                         NULL,
    1170             :                                         ldb_op_default_callback,
    1171             :                                         NULL);
    1172       30754 :                 if (ret != LDB_SUCCESS) {
    1173           0 :                         goto done;
    1174             :                 }
    1175             : 
    1176       30754 :                 ret = ldb_request_add_control(req,
    1177             :                                               DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
    1178             :                                               false, NULL);
    1179       30754 :                 if (ret != LDB_SUCCESS) {
    1180           0 :                         talloc_free(req);
    1181           0 :                         goto done;
    1182             :                 }
    1183             : 
    1184       30754 :                 ret = dsdb_autotransaction_request(sam_ctx, req);
    1185       30754 :                 talloc_free(req);
    1186             :         }
    1187             : 
    1188       53901 : done:
    1189       44343 :         if (ret != LDB_SUCCESS) {
    1190           0 :                 DEBUG(0, ("Failed to set badPwdCount and lockoutTime "
    1191             :                           "to 0 and/or  lastlogon to now (%lld) "
    1192             :                           "%s: %s\n", (long long int)now,
    1193             :                           ldb_dn_get_linearized(msg_mod->dn),
    1194             :                           ldb_errstring(sam_ctx)));
    1195           0 :                 TALLOC_FREE(mem_ctx);
    1196           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1197             :         }
    1198             : 
    1199       44343 :         TALLOC_FREE(mem_ctx);
    1200       44343 :         return NT_STATUS_OK;
    1201             : }

Generated by: LCOV version 1.13