2006-04-27 23:50:13 +04:00
/*
Unix SMB / CIFS implementation .
Password and authentication handling
2010-12-21 14:35:13 +03:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2001 - 2010
2006-04-27 23:50:13 +04:00
Copyright ( C ) Gerald Carter 2003
Copyright ( C ) Stefan Metzmacher 2005
2009-07-17 05:28:58 +04:00
Copyright ( C ) Matthias Dieter Wallnöfer 2009
2006-04-27 23:50:13 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-04-27 23:50:13 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-04-27 23:50:13 +04:00
*/
# include "includes.h"
# include "system/time.h"
# include "auth/auth.h"
2007-11-16 22:12:00 +03:00
# include <ldb.h>
2006-04-27 23:50:13 +04:00
# include "dsdb/samdb/samdb.h"
# include "libcli/security/security.h"
2008-10-20 20:59:51 +04:00
# include "auth/auth_sam.h"
2010-02-16 07:49:29 +03:00
# include "dsdb/common/util.h"
2010-12-22 09:17:07 +03:00
# include "libcli/ldap/ldap_ndr.h"
# include "param/param.h"
2006-04-27 23:50:13 +04:00
2009-07-16 11:37:36 +04:00
# define KRBTGT_ATTRS \
/* required for the krb5 kdc */ \
" objectClass " , \
" sAMAccountName " , \
" userPrincipalName " , \
" servicePrincipalName " , \
" msDS-KeyVersionNumber " , \
2010-09-29 06:07:43 +04:00
" msDS-SecondaryKrbTgtNumber " , \
2010-06-24 04:03:29 +04:00
" msDS-SupportedEncryptionTypes " , \
2009-07-16 11:37:36 +04:00
" supplementalCredentials " , \
2011-04-27 13:41:49 +04:00
" msDS-AllowedToDelegateTo " , \
2009-07-16 11:37:36 +04:00
\
/* passwords */ \
" dBCSPwd " , \
" unicodePwd " , \
\
2013-10-29 08:30:18 +04:00
" userAccountControl " , \
" msDS-User-Account-Control-Computed " , \
2009-07-16 11:37:36 +04:00
" objectSid " , \
\
" pwdLastSet " , \
2010-09-29 06:07:43 +04:00
" accountExpires "
2009-07-16 11:37:36 +04:00
const char * krbtgt_attrs [ ] = {
2010-09-29 06:07:43 +04:00
KRBTGT_ATTRS , NULL
2009-07-16 11:37:36 +04:00
} ;
2006-04-27 23:50:13 +04:00
2009-07-16 11:37:36 +04:00
const char * server_attrs [ ] = {
2010-09-29 06:07:43 +04:00
KRBTGT_ATTRS , NULL
2009-07-16 11:37:36 +04:00
} ;
2006-04-27 23:50:13 +04:00
2009-07-16 11:37:36 +04:00
const char * user_attrs [ ] = {
KRBTGT_ATTRS ,
2006-04-27 23:50:13 +04:00
2007-07-27 10:31:12 +04:00
" logonHours " ,
2006-04-27 23:50:13 +04:00
2013-11-11 02:35:12 +04:00
/*
* To allow us to zero the badPwdCount and lockoutTime on
* successful logon , without database churn
*/
" lockoutTime " ,
2006-04-27 23:50:13 +04:00
/* check 'allowed workstations' */
" userWorkstations " ,
2011-02-08 08:53:13 +03:00
/* required for user_info_dc, not access control: */
2006-04-27 23:50:13 +04:00
" displayName " ,
" scriptPath " ,
" profilePath " ,
" homeDirectory " ,
" homeDrive " ,
" lastLogon " ,
" lastLogoff " ,
" accountExpires " ,
" badPwdCount " ,
" logonCount " ,
" primaryGroupID " ,
2009-06-04 08:07:35 +04:00
" memberOf " ,
2013-11-06 01:39:42 +04:00
" badPasswordTime " ,
2006-04-27 23:50:13 +04:00
NULL ,
} ;
2007-07-27 10:31:12 +04:00
/****************************************************************************
Check if a user is allowed to logon at this time . Note this is the
servers local time , as logon hours are just specified as a weekly
bitmask .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-07 02:16:19 +04:00
static bool logon_hours_ok ( struct ldb_message * msg , const char * name_for_logs )
2007-07-27 10:31:12 +04:00
{
/* In logon hours first bit is Sunday from 12AM to 1AM */
const struct ldb_val * hours ;
struct tm * utctime ;
time_t lasttime ;
const char * asct ;
uint8_t bitmask , bitpos ;
hours = ldb_msg_find_ldb_val ( msg , " logonHours " ) ;
if ( ! hours ) {
DEBUG ( 5 , ( " logon_hours_ok: No hours restrictions for user %s \n " , name_for_logs ) ) ;
2007-10-07 02:16:19 +04:00
return true ;
2007-07-27 10:31:12 +04:00
}
if ( hours - > length ! = 168 / 8 ) {
DEBUG ( 5 , ( " logon_hours_ok: malformed logon hours restrictions for user %s \n " , name_for_logs ) ) ;
2007-10-07 02:16:19 +04:00
return true ;
2007-07-27 10:31:12 +04:00
}
lasttime = time ( NULL ) ;
utctime = gmtime ( & lasttime ) ;
if ( ! utctime ) {
DEBUG ( 1 , ( " logon_hours_ok: failed to get gmtime. Failing logon for user %s \n " ,
name_for_logs ) ) ;
2007-10-07 02:16:19 +04:00
return false ;
2007-07-27 10:31:12 +04:00
}
/* find the corresponding byte and bit */
bitpos = ( utctime - > tm_wday * 24 + utctime - > tm_hour ) % 168 ;
bitmask = 1 < < ( bitpos % 8 ) ;
if ( ! ( hours - > data [ bitpos / 8 ] & bitmask ) ) {
struct tm * t = localtime ( & lasttime ) ;
if ( ! t ) {
asct = " INVALID TIME " ;
} else {
asct = asctime ( t ) ;
if ( ! asct ) {
asct = " INVALID TIME " ;
}
}
DEBUG ( 1 , ( " logon_hours_ok: Account for user %s not allowed to "
" logon at this time (%s). \n " ,
name_for_logs , asct ) ) ;
2007-10-07 02:16:19 +04:00
return false ;
2007-07-27 10:31:12 +04:00
}
asct = asctime ( utctime ) ;
DEBUG ( 5 , ( " logon_hours_ok: user %s allowed to logon at this time (%s) \n " ,
name_for_logs , asct ? asct : " UNKNOWN TIME " ) ) ;
2007-10-07 02:16:19 +04:00
return true ;
2007-07-27 10:31:12 +04:00
}
2006-04-27 23:50:13 +04:00
/****************************************************************************
2010-02-21 09:33:28 +03:00
Do a specific test for a SAM_ACCOUNT being valid for this connection
2006-04-27 23:50:13 +04:00
( ie not disabled , expired and the like ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
_PUBLIC_ NTSTATUS authsam_account_ok ( TALLOC_CTX * mem_ctx ,
2009-05-26 06:31:39 +04:00
struct ldb_context * sam_ctx ,
uint32_t logon_parameters ,
struct ldb_dn * domain_dn ,
struct ldb_message * msg ,
const char * logon_workstation ,
const char * name_for_logs ,
2009-06-18 05:08:46 +04:00
bool allow_domain_trust ,
bool password_change )
2006-04-27 23:50:13 +04:00
{
uint16_t acct_flags ;
const char * workstation_list ;
NTTIME acct_expiry ;
NTTIME must_change_time ;
2014-03-31 15:35:25 +04:00
struct timeval tv_now = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv_now ) ;
2006-04-27 23:50:13 +04:00
DEBUG ( 4 , ( " authsam_account_ok: Checking SMB password for user %s \n " , name_for_logs ) ) ;
2013-10-29 08:30:18 +04:00
acct_flags = samdb_result_acct_flags ( msg , " msDS-User-Account-Control-Computed " ) ;
2006-04-27 23:50:13 +04:00
2008-03-25 07:25:13 +03:00
acct_expiry = samdb_result_account_expires ( msg ) ;
2008-02-29 00:47:42 +03:00
/* Check for when we must change this password, taking the
* userAccountControl flags into account */
2006-04-27 23:50:13 +04:00
must_change_time = samdb_result_force_password_change ( sam_ctx , mem_ctx ,
domain_dn , msg ) ;
2010-10-14 11:41:42 +04:00
workstation_list = ldb_msg_find_attr_as_string ( msg , " userWorkstations " , NULL ) ;
2006-04-27 23:50:13 +04:00
/* Quit if the account was disabled. */
if ( acct_flags & ACB_DISABLED ) {
2010-08-31 06:28:55 +04:00
DEBUG ( 2 , ( " authsam_account_ok: Account for user '%s' was disabled. \n " , name_for_logs ) ) ;
2006-04-27 23:50:13 +04:00
return NT_STATUS_ACCOUNT_DISABLED ;
}
/* Quit if the account was locked out. */
if ( acct_flags & ACB_AUTOLOCK ) {
2010-08-31 06:28:55 +04:00
DEBUG ( 2 , ( " authsam_account_ok: Account for user %s was locked out. \n " , name_for_logs ) ) ;
2006-04-27 23:50:13 +04:00
return NT_STATUS_ACCOUNT_LOCKED_OUT ;
}
/* Test account expire time */
if ( now > acct_expiry ) {
2010-08-31 06:28:55 +04:00
DEBUG ( 2 , ( " authsam_account_ok: Account for user '%s' has expired. \n " , name_for_logs ) ) ;
2006-04-27 23:50:13 +04:00
DEBUG ( 3 , ( " authsam_account_ok: Account expired at '%s'. \n " ,
nt_time_string ( mem_ctx , acct_expiry ) ) ) ;
return NT_STATUS_ACCOUNT_EXPIRED ;
}
2009-06-18 05:08:46 +04:00
/* check for immediate expiry "must change at next logon" (but not if this is a password change request) */
if ( ( must_change_time = = 0 ) & & ! password_change ) {
2010-08-31 06:28:55 +04:00
DEBUG ( 2 , ( " sam_account_ok: Account for user '%s' password must change!. \n " ,
2008-02-28 00:50:00 +03:00
name_for_logs ) ) ;
return NT_STATUS_PASSWORD_MUST_CHANGE ;
}
2006-04-27 23:50:13 +04:00
2009-06-18 05:08:46 +04:00
/* check for expired password (but not if this is a password change request) */
if ( ( must_change_time < now ) & & ! password_change ) {
2010-08-31 06:28:55 +04:00
DEBUG ( 2 , ( " sam_account_ok: Account for user '%s' password expired!. \n " ,
2008-02-28 00:50:00 +03:00
name_for_logs ) ) ;
2010-08-31 06:28:55 +04:00
DEBUG ( 2 , ( " sam_account_ok: Password expired at '%s' unix time. \n " ,
2008-02-28 00:50:00 +03:00
nt_time_string ( mem_ctx , must_change_time ) ) ) ;
return NT_STATUS_PASSWORD_EXPIRED ;
2006-04-27 23:50:13 +04:00
}
/* Test workstation. Workstation list is comma separated. */
if ( logon_workstation & & workstation_list & & * workstation_list ) {
2007-10-07 02:16:19 +04:00
bool invalid_ws = true ;
2006-04-27 23:50:13 +04:00
int i ;
2014-02-26 23:16:26 +04:00
char * * workstations = str_list_make ( mem_ctx , workstation_list , " , " ) ;
2006-04-27 23:50:13 +04:00
for ( i = 0 ; workstations & & workstations [ i ] ; i + + ) {
DEBUG ( 10 , ( " sam_account_ok: checking for workstation match '%s' and '%s' \n " ,
workstations [ i ] , logon_workstation ) ) ;
2007-07-30 12:58:39 +04:00
if ( strequal ( workstations [ i ] , logon_workstation ) ) {
2007-10-07 02:16:19 +04:00
invalid_ws = false ;
2006-04-27 23:50:13 +04:00
break ;
}
}
talloc_free ( workstations ) ;
if ( invalid_ws ) {
return NT_STATUS_INVALID_WORKSTATION ;
}
}
2007-07-27 10:31:12 +04:00
if ( ! logon_hours_ok ( msg , name_for_logs ) ) {
return NT_STATUS_INVALID_LOGON_HOURS ;
}
2008-12-04 17:09:21 +03:00
if ( ! allow_domain_trust ) {
if ( acct_flags & ACB_DOMTRUST ) {
DEBUG ( 2 , ( " sam_account_ok: Domain trust account %s denied by server \n " , name_for_logs ) ) ;
return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ;
}
2006-04-27 23:50:13 +04:00
}
if ( ! ( logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT ) ) {
if ( acct_flags & ACB_SVRTRUST ) {
DEBUG ( 2 , ( " sam_account_ok: Server trust account %s denied by server \n " , name_for_logs ) ) ;
return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ;
}
}
if ( ! ( logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT ) ) {
2009-09-18 02:15:58 +04:00
/* TODO: this fails with current solaris client. We
need to work with Gordon to work out why */
2006-04-27 23:50:13 +04:00
if ( acct_flags & ACB_WSTRUST ) {
DEBUG ( 4 , ( " sam_account_ok: Wksta trust account %s denied by server \n " , name_for_logs ) ) ;
return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ;
}
}
return NT_STATUS_OK ;
}
2011-02-08 08:53:13 +03:00
_PUBLIC_ NTSTATUS authsam_make_user_info_dc ( TALLOC_CTX * mem_ctx ,
2009-07-17 05:28:58 +04:00
struct ldb_context * sam_ctx ,
2007-12-03 17:53:17 +03:00
const char * netbios_name ,
2009-05-26 06:31:39 +04:00
const char * domain_name ,
struct ldb_dn * domain_dn ,
2007-12-03 17:53:17 +03:00
struct ldb_message * msg ,
2009-08-18 01:39:41 +04:00
DATA_BLOB user_sess_key ,
DATA_BLOB lm_sess_key ,
2011-02-08 08:53:13 +03:00
struct auth_user_info_dc * * _user_info_dc )
2006-04-27 23:50:13 +04:00
{
2009-07-17 05:28:58 +04:00
NTSTATUS status ;
2011-02-08 08:53:13 +03:00
struct auth_user_info_dc * user_info_dc ;
struct auth_user_info * info ;
2010-04-13 16:11:26 +04:00
const char * str , * filter ;
2009-08-18 01:39:41 +04:00
/* SIDs for the account and his primary group */
2006-04-27 23:50:13 +04:00
struct dom_sid * account_sid ;
2010-04-13 16:11:26 +04:00
const char * primary_group_string ;
const char * primary_group_dn ;
DATA_BLOB primary_group_blob ;
2009-08-18 01:39:41 +04:00
/* SID structures for the expanded group memberships */
2011-01-20 15:39:37 +03:00
struct dom_sid * sids = NULL ;
unsigned int num_sids = 0 , i ;
2010-04-13 16:11:26 +04:00
struct dom_sid * domain_sid ;
TALLOC_CTX * tmp_ctx ;
struct ldb_message_element * el ;
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
user_info_dc = talloc ( mem_ctx , struct auth_user_info_dc ) ;
NT_STATUS_HAVE_NO_MEMORY ( user_info_dc ) ;
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
tmp_ctx = talloc_new ( user_info_dc ) ;
2014-02-13 08:51:11 +04:00
if ( user_info_dc = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-04-13 16:11:26 +04:00
2011-02-08 08:53:13 +03:00
sids = talloc_array ( user_info_dc , struct dom_sid , 2 ) ;
2014-02-13 08:51:11 +04:00
if ( sids = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2011-01-20 15:39:37 +03:00
num_sids = 2 ;
2011-02-08 08:53:13 +03:00
account_sid = samdb_result_dom_sid ( user_info_dc , msg , " objectSid " ) ;
2014-02-13 08:51:11 +04:00
if ( account_sid = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2010-04-13 16:11:26 +04:00
status = dom_sid_split_rid ( tmp_ctx , account_sid , & domain_sid , NULL ) ;
2009-07-17 05:28:58 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-08 08:53:13 +03:00
talloc_free ( user_info_dc ) ;
2009-07-17 05:28:58 +04:00
return status ;
}
2011-01-20 15:39:37 +03:00
sids [ PRIMARY_USER_SID_INDEX ] = * account_sid ;
sids [ PRIMARY_GROUP_SID_INDEX ] = * domain_sid ;
sid_append_rid ( & sids [ PRIMARY_GROUP_SID_INDEX ] , ldb_msg_find_attr_as_uint ( msg , " primaryGroupID " , ~ 0 ) ) ;
2010-04-13 16:11:26 +04:00
/* Filter out builtin groups from this token. We will search
* for builtin groups later , and not include them in the PAC
* on SamLogon validation info */
filter = talloc_asprintf ( tmp_ctx , " (&(objectClass=group)(!(groupType:1.2.840.113556.1.4.803:=%u))(groupType:1.2.840.113556.1.4.803:=%u)) " , GROUP_TYPE_BUILTIN_LOCAL_GROUP , GROUP_TYPE_SECURITY_ENABLED ) ;
2014-02-13 08:51:11 +04:00
if ( filter = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-04-13 16:11:26 +04:00
2011-01-20 15:39:37 +03:00
primary_group_string = dom_sid_string ( tmp_ctx , & sids [ PRIMARY_GROUP_SID_INDEX ] ) ;
2014-02-13 08:51:11 +04:00
if ( primary_group_string = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-04-13 16:11:26 +04:00
primary_group_dn = talloc_asprintf ( tmp_ctx , " <SID=%s> " , primary_group_string ) ;
2014-02-13 08:51:11 +04:00
if ( primary_group_dn = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-04-13 16:11:26 +04:00
primary_group_blob = data_blob_string_const ( primary_group_dn ) ;
/* Expands the primary group - this function takes in
* memberOf - like values , so we fake one up with the
* < SID = S - . . . > format of DN and then let it expand
* them , as long as they meet the filter - so only
* domain groups , not builtin groups
*
* The primary group is still treated specially , so we set the
* ' only childs ' flag to true
*/
2010-12-21 14:35:13 +03:00
status = dsdb_expand_nested_groups ( sam_ctx , & primary_group_blob , true , filter ,
2011-02-08 08:53:13 +03:00
user_info_dc , & sids , & num_sids ) ;
2009-08-18 01:39:41 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-08 08:53:13 +03:00
talloc_free ( user_info_dc ) ;
2009-08-18 01:39:41 +04:00
return status ;
}
2006-04-27 23:50:13 +04:00
2010-04-13 16:11:26 +04:00
/* Expands the additional groups */
el = ldb_msg_find_element ( msg , " memberOf " ) ;
for ( i = 0 ; el & & i < el - > num_values ; i + + ) {
/* This function takes in memberOf values and expands
* them , as long as they meet the filter - so only
* domain groups , not builtin groups */
2010-12-21 14:35:13 +03:00
status = dsdb_expand_nested_groups ( sam_ctx , & el - > values [ i ] , false , filter ,
2011-02-08 08:53:13 +03:00
user_info_dc , & sids , & num_sids ) ;
2010-04-13 16:11:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-02-08 08:53:13 +03:00
talloc_free ( user_info_dc ) ;
2010-04-13 16:11:26 +04:00
return status ;
2006-04-27 23:50:13 +04:00
}
2010-04-13 16:11:26 +04:00
}
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
user_info_dc - > sids = sids ;
user_info_dc - > num_sids = num_sids ;
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
user_info_dc - > info = info = talloc_zero ( user_info_dc , struct auth_user_info ) ;
NT_STATUS_HAVE_NO_MEMORY ( user_info_dc - > info ) ;
info - > account_name = talloc_steal ( info ,
2010-10-14 11:41:42 +04:00
ldb_msg_find_attr_as_string ( msg , " sAMAccountName " , NULL ) ) ;
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
info - > domain_name = talloc_strdup ( info , domain_name ) ;
2014-02-13 09:08:56 +04:00
if ( info - > domain_name = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2010-10-14 11:41:42 +04:00
str = ldb_msg_find_attr_as_string ( msg , " displayName " , " " ) ;
2011-02-08 08:53:13 +03:00
info - > full_name = talloc_strdup ( info , str ) ;
2014-02-13 08:51:11 +04:00
if ( info - > full_name = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2010-10-14 11:41:42 +04:00
str = ldb_msg_find_attr_as_string ( msg , " scriptPath " , " " ) ;
2011-02-08 08:53:13 +03:00
info - > logon_script = talloc_strdup ( info , str ) ;
2014-02-13 09:08:56 +04:00
if ( info - > logon_script = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2010-10-14 11:41:42 +04:00
str = ldb_msg_find_attr_as_string ( msg , " profilePath " , " " ) ;
2011-02-08 08:53:13 +03:00
info - > profile_path = talloc_strdup ( info , str ) ;
2014-02-13 09:08:56 +04:00
if ( info - > profile_path = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2010-10-14 11:41:42 +04:00
str = ldb_msg_find_attr_as_string ( msg , " homeDirectory " , " " ) ;
2011-02-08 08:53:13 +03:00
info - > home_directory = talloc_strdup ( info , str ) ;
2014-02-13 09:08:56 +04:00
if ( info - > home_directory = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2010-10-14 11:41:42 +04:00
str = ldb_msg_find_attr_as_string ( msg , " homeDrive " , " " ) ;
2011-02-08 08:53:13 +03:00
info - > home_drive = talloc_strdup ( info , str ) ;
2014-02-13 08:51:11 +04:00
if ( info - > home_drive = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
info - > logon_server = talloc_strdup ( info , netbios_name ) ;
2014-02-13 09:08:56 +04:00
if ( info - > logon_server = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
info - > last_logon = samdb_result_nttime ( msg , " lastLogon " , 0 ) ;
info - > last_logoff = samdb_result_last_logoff ( msg ) ;
info - > acct_expiry = samdb_result_account_expires ( msg ) ;
info - > last_password_change = samdb_result_nttime ( msg ,
2009-08-18 01:39:41 +04:00
" pwdLastSet " , 0 ) ;
2011-02-08 08:53:13 +03:00
info - > allow_password_change
2006-04-27 23:50:13 +04:00
= samdb_result_allow_password_change ( sam_ctx , mem_ctx ,
2009-08-18 01:39:41 +04:00
domain_dn , msg , " pwdLastSet " ) ;
2011-02-08 08:53:13 +03:00
info - > force_password_change
2009-08-18 01:39:41 +04:00
= samdb_result_force_password_change ( sam_ctx , mem_ctx ,
domain_dn , msg ) ;
2011-02-08 08:53:13 +03:00
info - > logon_count = ldb_msg_find_attr_as_uint ( msg , " logonCount " , 0 ) ;
info - > bad_password_count = ldb_msg_find_attr_as_uint ( msg , " badPwdCount " ,
2009-08-18 01:39:41 +04:00
0 ) ;
2006-04-27 23:50:13 +04:00
2013-10-29 08:30:18 +04:00
info - > acct_flags = samdb_result_acct_flags ( msg , " msDS-User-Account-Control-Computed " ) ;
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
user_info_dc - > user_session_key = data_blob_talloc ( user_info_dc ,
2010-01-05 22:11:29 +03:00
user_sess_key . data ,
user_sess_key . length ) ;
if ( user_sess_key . data ) {
2014-02-13 09:08:56 +04:00
if ( user_info_dc - > user_session_key . data = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-01-05 22:11:29 +03:00
}
2011-02-08 08:53:13 +03:00
user_info_dc - > lm_session_key = data_blob_talloc ( user_info_dc ,
2010-01-05 22:11:29 +03:00
lm_sess_key . data ,
lm_sess_key . length ) ;
if ( lm_sess_key . data ) {
2014-02-13 09:08:56 +04:00
if ( user_info_dc - > lm_session_key . data = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-01-05 22:11:29 +03:00
}
2006-04-27 23:50:13 +04:00
2011-02-08 08:53:13 +03:00
if ( info - > acct_flags & ACB_SVRTRUST ) {
2010-09-26 06:14:42 +04:00
/* the SID_NT_ENTERPRISE_DCS SID gets added into the
PAC */
2011-02-08 08:53:13 +03:00
user_info_dc - > sids = talloc_realloc ( user_info_dc ,
user_info_dc - > sids ,
2011-01-20 15:39:37 +03:00
struct dom_sid ,
2011-02-08 08:53:13 +03:00
user_info_dc - > num_sids + 1 ) ;
2014-02-13 08:51:11 +04:00
if ( user_info_dc - > sids = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2011-02-08 08:53:13 +03:00
user_info_dc - > sids [ user_info_dc - > num_sids ] = global_sid_Enterprise_DCs ;
user_info_dc - > num_sids + + ;
2010-09-26 06:14:42 +04:00
}
2011-02-08 08:53:13 +03:00
if ( ( info - > acct_flags & ( ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST ) ) = =
2010-09-29 10:19:26 +04:00
( ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST ) ) {
/* the DOMAIN_RID_ENTERPRISE_READONLY_DCS PAC */
2011-02-08 08:53:13 +03:00
user_info_dc - > sids = talloc_realloc ( user_info_dc ,
user_info_dc - > sids ,
2011-01-20 15:39:37 +03:00
struct dom_sid ,
2011-02-08 08:53:13 +03:00
user_info_dc - > num_sids + 1 ) ;
2014-02-13 08:51:11 +04:00
if ( user_info_dc - > sids = = NULL ) {
TALLOC_FREE ( user_info_dc ) ;
return NT_STATUS_NO_MEMORY ;
}
2011-02-08 08:53:13 +03:00
user_info_dc - > sids [ user_info_dc - > num_sids ] = * domain_sid ;
sid_append_rid ( & user_info_dc - > sids [ user_info_dc - > num_sids ] ,
2011-01-20 15:39:37 +03:00
DOMAIN_RID_ENTERPRISE_READONLY_DCS ) ;
2011-02-08 08:53:13 +03:00
user_info_dc - > num_sids + + ;
2010-09-29 10:19:26 +04:00
}
2011-02-08 08:53:13 +03:00
info - > authenticated = true ;
2006-04-27 23:50:13 +04:00
2010-04-13 16:11:26 +04:00
talloc_free ( tmp_ctx ) ;
2011-02-08 08:53:13 +03:00
* _user_info_dc = user_info_dc ;
2006-04-27 23:50:13 +04:00
return NT_STATUS_OK ;
}
2008-04-02 06:53:27 +04:00
NTSTATUS sam_get_results_principal ( struct ldb_context * sam_ctx ,
2006-04-27 23:50:13 +04:00
TALLOC_CTX * mem_ctx , const char * principal ,
2009-07-28 08:05:19 +04:00
const char * * attrs ,
2009-05-26 06:31:39 +04:00
struct ldb_dn * * domain_dn ,
2009-06-04 08:07:35 +04:00
struct ldb_message * * msg )
2006-04-27 23:50:13 +04:00
{
2009-05-26 06:31:39 +04:00
struct ldb_dn * user_dn ;
2006-04-27 23:50:13 +04:00
NTSTATUS nt_status ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
int ret ;
if ( ! tmp_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
2009-07-28 08:05:19 +04:00
nt_status = crack_user_principal_name ( sam_ctx , tmp_ctx , principal ,
& user_dn , domain_dn ) ;
2006-04-27 23:50:13 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return nt_status ;
}
/* pull the user attributes */
2010-02-16 07:49:29 +03:00
ret = dsdb_search_one ( sam_ctx , tmp_ctx , msg , user_dn ,
2011-09-29 11:43:25 +04:00
LDB_SCOPE_BASE , attrs ,
DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG ,
" (objectClass=*) " ) ;
2009-06-04 08:07:35 +04:00
if ( ret ! = LDB_SUCCESS ) {
2006-04-27 23:50:13 +04:00
talloc_free ( tmp_ctx ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
2009-06-04 08:07:35 +04:00
talloc_steal ( mem_ctx , * msg ) ;
2009-05-26 06:31:39 +04:00
talloc_steal ( mem_ctx , * domain_dn ) ;
2006-04-27 23:50:13 +04:00
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2010-12-22 09:17:07 +03:00
/* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
Supply either a principal or a DN
*/
2011-02-08 08:53:13 +03:00
NTSTATUS authsam_get_user_info_dc_principal ( TALLOC_CTX * mem_ctx ,
2010-12-22 09:17:07 +03:00
struct loadparm_context * lp_ctx ,
struct ldb_context * sam_ctx ,
const char * principal ,
struct ldb_dn * user_dn ,
2011-02-08 08:53:13 +03:00
struct auth_user_info_dc * * user_info_dc )
2010-12-22 09:17:07 +03:00
{
NTSTATUS nt_status ;
DATA_BLOB user_sess_key = data_blob ( NULL , 0 ) ;
DATA_BLOB lm_sess_key = data_blob ( NULL , 0 ) ;
struct ldb_message * msg ;
struct ldb_dn * domain_dn ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
if ( principal ) {
nt_status = sam_get_results_principal ( sam_ctx , tmp_ctx , principal ,
user_attrs , & domain_dn , & msg ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return nt_status ;
}
} else if ( user_dn ) {
struct dom_sid * user_sid , * domain_sid ;
int ret ;
/* pull the user attributes */
ret = dsdb_search_one ( sam_ctx , tmp_ctx , & msg , user_dn ,
2011-09-29 11:43:25 +04:00
LDB_SCOPE_BASE , user_attrs ,
DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG ,
" (objectClass=*) " ) ;
2010-12-22 09:17:07 +03:00
if ( ret = = LDB_ERR_NO_SUCH_OBJECT ) {
talloc_free ( tmp_ctx ) ;
return NT_STATUS_NO_SUCH_USER ;
} else if ( ret ! = LDB_SUCCESS ) {
talloc_free ( tmp_ctx ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
user_sid = samdb_result_dom_sid ( msg , msg , " objectSid " ) ;
nt_status = dom_sid_split_rid ( tmp_ctx , user_sid , & domain_sid , NULL ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return nt_status ;
}
domain_dn = samdb_search_dn ( sam_ctx , mem_ctx , NULL ,
" (&(objectSid=%s)(objectClass=domain)) " ,
ldap_encode_ndr_dom_sid ( tmp_ctx , domain_sid ) ) ;
if ( ! domain_dn ) {
2011-02-08 08:53:13 +03:00
DEBUG ( 3 , ( " authsam_get_user_info_dc_principal: Failed to find domain with: SID %s \n " ,
2010-12-22 09:17:07 +03:00
dom_sid_string ( tmp_ctx , domain_sid ) ) ) ;
return NT_STATUS_NO_SUCH_USER ;
}
} else {
return NT_STATUS_INVALID_PARAMETER ;
}
2011-02-08 08:53:13 +03:00
nt_status = authsam_make_user_info_dc ( tmp_ctx , sam_ctx ,
2010-12-22 09:17:07 +03:00
lpcfg_netbios_name ( lp_ctx ) ,
lpcfg_workgroup ( lp_ctx ) ,
domain_dn ,
msg ,
user_sess_key , lm_sess_key ,
2011-02-08 08:53:13 +03:00
user_info_dc ) ;
2010-12-22 09:17:07 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return nt_status ;
}
2011-02-08 08:53:13 +03:00
talloc_steal ( mem_ctx , * user_info_dc ) ;
2010-12-22 09:17:07 +03:00
talloc_free ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2013-11-06 01:39:42 +04:00
NTSTATUS authsam_update_bad_pwd_count ( struct ldb_context * sam_ctx ,
struct ldb_message * msg ,
struct ldb_dn * domain_dn )
{
const char * attrs [ ] = { " lockoutThreshold " ,
" lockOutObservationWindow " ,
" lockoutDuration " ,
" pwdProperties " ,
NULL } ;
int ret , badPwdCount ;
int64_t lockoutThreshold , lockOutObservationWindow , badPasswordTime ;
struct dom_sid * sid ;
struct ldb_result * domain_res ;
struct ldb_message * msg_mod ;
struct timeval tv_now = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv_now ) ;
NTSTATUS status ;
uint32_t pwdProperties , rid = 0 ;
TALLOC_CTX * mem_ctx ;
mem_ctx = talloc_new ( msg ) ;
if ( mem_ctx = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
sid = samdb_result_dom_sid ( mem_ctx , msg , " objectSid " ) ;
ret = dsdb_search_dn ( sam_ctx , mem_ctx , & domain_res , domain_dn , attrs , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
pwdProperties = ldb_msg_find_attr_as_uint ( domain_res - > msgs [ 0 ] ,
" pwdProperties " , - 1 ) ;
if ( sid & & ! ( pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS ) ) {
status = dom_sid_split_rid ( NULL , sid , NULL , & rid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* This can ' t happen anyway , but always try
* and update the badPwdCount on failure
*/
rid = 0 ;
}
}
/*
* Work out if we are doing password lockout on the domain .
* Also , the built in administrator account is exempt :
* http : //msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
*/
lockoutThreshold = ldb_msg_find_attr_as_int ( domain_res - > msgs [ 0 ] ,
" lockoutThreshold " , 0 ) ;
if ( lockoutThreshold = = 0 | | ( rid = = DOMAIN_RID_ADMINISTRATOR ) ) {
DEBUG ( 5 , ( " Not updating badPwdCount on %s after wrong password \n " ,
ldb_dn_get_linearized ( msg - > dn ) ) ) ;
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_OK ;
}
lockOutObservationWindow = ldb_msg_find_attr_as_int64 ( domain_res - > msgs [ 0 ] ,
" lockOutObservationWindow " , 0 ) ;
badPasswordTime = ldb_msg_find_attr_as_int64 ( msg , " badPasswordTime " , 0 ) ;
msg_mod = ldb_msg_new ( mem_ctx ) ;
if ( msg_mod = = NULL ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
msg_mod - > dn = msg - > dn ;
if ( badPasswordTime - lockOutObservationWindow > = now ) {
badPwdCount = ldb_msg_find_attr_as_int ( msg , " badPwdCount " , 0 ) ;
} else {
badPwdCount = 0 ;
}
badPwdCount + + ;
ret = samdb_msg_add_int ( sam_ctx , msg_mod , msg_mod , " badPwdCount " , badPwdCount ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
ret = samdb_msg_add_int64 ( sam_ctx , msg_mod , msg_mod , " badPasswordTime " , now ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
if ( badPwdCount > = lockoutThreshold ) {
ret = samdb_msg_add_int64 ( sam_ctx , msg_mod , msg_mod , " lockoutTime " , now ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
DEBUG ( 5 , ( " Locked out user %s after %d wrong passwords \n " ,
ldb_dn_get_linearized ( msg - > dn ) , badPwdCount ) ) ;
}
ret = dsdb_replace ( sam_ctx , msg_mod , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to upate badPwdCount, badPasswordTime or set lockoutTime on %s: %s \n " ,
ldb_dn_get_linearized ( msg_mod - > dn ) , ldb_errstring ( sam_ctx ) ) ) ;
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
DEBUG ( 5 , ( " Updated badPwdCount on %s after %d wrong passwords \n " ,
ldb_dn_get_linearized ( msg - > dn ) , badPwdCount ) ) ;
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_OK ;
}
2013-11-11 02:35:12 +04:00
NTSTATUS authsam_zero_bad_pwd_count ( struct ldb_context * sam_ctx ,
const struct ldb_message * msg )
{
int ret ;
int badPwdCount ;
int64_t lockoutTime ;
struct ldb_message * msg_mod ;
TALLOC_CTX * mem_ctx ;
lockoutTime = ldb_msg_find_attr_as_int64 ( msg , " lockoutTime " , 0 ) ;
badPwdCount = ldb_msg_find_attr_as_int ( msg , " badPwdCount " , 0 ) ;
if ( lockoutTime = = 0 & & badPwdCount = = 0 ) {
return NT_STATUS_OK ;
}
mem_ctx = talloc_new ( msg ) ;
if ( mem_ctx = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
msg_mod = ldb_msg_new ( mem_ctx ) ;
if ( msg_mod = = NULL ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
msg_mod - > dn = msg - > dn ;
if ( lockoutTime ! = 0 ) {
/*
* This implies " badPwdCount " = 0 , see samldb_lockout_time ( )
*/
ret = samdb_msg_add_int ( sam_ctx , msg_mod , msg_mod , " lockoutTime " , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
} else {
ret = samdb_msg_add_int ( sam_ctx , msg_mod , msg_mod , " badPwdCount " , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
}
ret = dsdb_replace ( sam_ctx , msg_mod , 0 ) ;
if ( ret ! = LDB_SUCCESS ) {
DEBUG ( 0 , ( " Failed to set badPwdCount and lockoutTime to 0 on %s: %s \n " ,
ldb_dn_get_linearized ( msg_mod - > dn ) , ldb_errstring ( sam_ctx ) ) ) ;
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
TALLOC_FREE ( mem_ctx ) ;
return NT_STATUS_OK ;
}