2003-06-30 21:24:59 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-05-09 15:43:00 +04:00
2001-11-23 03:14:04 +03:00
Winbind daemon - pam auth funcions
2000-05-09 15:43:00 +04:00
Copyright ( C ) Andrew Tridgell 2000
2001-08-23 06:55:42 +04:00
Copyright ( C ) Tim Potter 2001
2002-02-05 12:40:36 +03:00
Copyright ( C ) Andrew Bartlett 2001 - 2002
2006-08-23 02:53:08 +04:00
Copyright ( C ) Guenther Deschner 2005
2007-09-21 16:24:43 +04:00
2000-05-09 15:43:00 +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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-05-09 15:43:00 +04:00
( at your option ) any later version .
2007-09-21 16:24:43 +04:00
2000-05-09 15:43:00 +04:00
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 .
2007-09-21 16:24:43 +04:00
2000-05-09 15:43:00 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-05-09 15:43:00 +04:00
*/
2003-11-12 04:51:10 +03:00
# include "includes.h"
2000-05-09 15:43:00 +04:00
# include "winbindd.h"
2018-03-10 17:31:11 +03:00
# include "libsmb/namequery.h"
2009-03-16 13:27:58 +03:00
# include "../libcli/auth/libcli_auth.h"
2011-01-18 15:56:26 +03:00
# include "../librpc/gen_ndr/ndr_samr_c.h"
2011-02-28 12:19:44 +03:00
# include "rpc_client/cli_pipe.h"
2010-05-18 20:25:50 +04:00
# include "rpc_client/cli_samr.h"
2010-05-05 03:39:16 +04:00
# include "../librpc/gen_ndr/ndr_netlogon.h"
2010-05-18 20:26:03 +04:00
# include "rpc_client/cli_netlogon.h"
2009-11-27 17:52:57 +03:00
# include "smb_krb5.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2010-08-03 01:12:16 +04:00
# include "../librpc/gen_ndr/krb5pac.h"
2011-03-22 18:50:02 +03:00
# include "passdb/machine_sid.h"
2011-03-25 04:28:05 +03:00
# include "auth.h"
2011-06-08 20:55:37 +04:00
# include "../lib/tsocket/tsocket.h"
2012-07-19 01:38:47 +04:00
# include "auth/kerberos/pac_utils.h"
# include "auth/gensec/gensec.h"
# include "librpc/crypto/gse_krb5.h"
2014-04-15 00:11:12 +04:00
# include "lib/afs/afs_funcs.h"
2016-11-29 18:41:27 +03:00
# include "libsmb/samlogon_cache.h"
2017-12-03 00:35:36 +03:00
# include "rpc_client/util_netlogon.h"
2019-01-28 05:31:46 +03:00
# include "param/param.h"
# include "messaging/messaging.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.h"
2019-11-08 17:40:01 +03:00
# include "lib/crypto/gnutls_helpers.h"
2009-11-26 20:21:28 +03:00
2019-11-18 12:28:59 +03:00
# include "lib/crypto/gnutls_helpers.h"
# include <gnutls/crypto.h>
2021-01-03 23:53:49 +03:00
# include "lib/global_contexts.h"
2019-11-18 12:28:59 +03:00
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2008-03-27 14:02:18 +03:00
# define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
2007-09-21 16:24:43 +04:00
static NTSTATUS append_info3_as_txt ( TALLOC_CTX * mem_ctx ,
2010-11-16 19:56:21 +03:00
struct winbindd_response * resp ,
2017-12-02 12:34:15 +03:00
uint16_t validation_level ,
union netr_Validation * validation )
2006-02-04 01:19:41 +03:00
{
2017-12-02 12:34:15 +03:00
struct netr_SamInfo3 * info3 = NULL ;
2018-01-11 11:37:22 +03:00
char * ex = NULL ;
2008-01-18 10:43:45 +03:00
uint32_t i ;
2018-01-11 11:37:22 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2017-12-02 12:34:15 +03:00
2018-01-11 11:37:22 +03:00
status = map_validation_to_info3 ( frame ,
2017-12-02 12:34:15 +03:00
validation_level ,
validation ,
& info3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-01-11 11:37:22 +03:00
goto out ;
2017-12-02 12:34:15 +03:00
}
2008-01-18 10:43:45 +03:00
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . logon_time =
2011-10-22 00:10:43 +04:00
nt_time_to_unix ( info3 - > base . logon_time ) ;
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . logoff_time =
2011-10-22 00:10:43 +04:00
nt_time_to_unix ( info3 - > base . logoff_time ) ;
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . kickoff_time =
2011-10-22 00:10:43 +04:00
nt_time_to_unix ( info3 - > base . kickoff_time ) ;
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . pass_last_set_time =
2008-02-17 04:08:12 +03:00
nt_time_to_unix ( info3 - > base . last_password_change ) ;
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . pass_can_change_time =
2008-02-17 04:08:12 +03:00
nt_time_to_unix ( info3 - > base . allow_password_change ) ;
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . pass_must_change_time =
2008-02-17 04:08:12 +03:00
nt_time_to_unix ( info3 - > base . force_password_change ) ;
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . logon_count = info3 - > base . logon_count ;
resp - > data . auth . info3 . bad_pw_count = info3 - > base . bad_password_count ;
2008-02-17 04:08:12 +03:00
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . user_rid = info3 - > base . rid ;
resp - > data . auth . info3 . group_rid = info3 - > base . primary_gid ;
sid_to_fstring ( resp - > data . auth . info3 . dom_sid , info3 - > base . domain_sid ) ;
2008-02-17 04:08:12 +03:00
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . num_groups = info3 - > base . groups . count ;
resp - > data . auth . info3 . user_flgs = info3 - > base . user_flags ;
2008-02-17 04:08:12 +03:00
2010-11-16 19:56:21 +03:00
resp - > data . auth . info3 . acct_flags = info3 - > base . acct_flags ;
resp - > data . auth . info3 . num_other_sids = info3 - > sidcount ;
2008-02-17 04:08:12 +03:00
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . user_name ,
2008-02-17 04:08:12 +03:00
info3 - > base . account_name . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . full_name ,
2008-02-17 04:08:12 +03:00
info3 - > base . full_name . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . logon_script ,
2008-02-17 04:08:12 +03:00
info3 - > base . logon_script . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . profile_path ,
2008-02-17 04:08:12 +03:00
info3 - > base . profile_path . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . home_dir ,
2008-02-17 04:08:12 +03:00
info3 - > base . home_directory . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . dir_drive ,
2008-02-17 04:08:12 +03:00
info3 - > base . home_drive . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . logon_srv ,
2008-02-17 04:08:12 +03:00
info3 - > base . logon_server . string ) ;
2010-11-16 19:56:21 +03:00
fstrcpy ( resp - > data . auth . info3 . logon_dom ,
2011-10-22 00:10:43 +04:00
info3 - > base . logon_domain . string ) ;
2006-02-04 01:19:41 +03:00
2017-12-02 12:34:28 +03:00
resp - > data . auth . validation_level = validation_level ;
if ( validation_level = = 6 ) {
fstrcpy ( resp - > data . auth . info6 . dns_domainname ,
validation - > sam6 - > dns_domainname . string ) ;
fstrcpy ( resp - > data . auth . info6 . principal_name ,
validation - > sam6 - > principal_name . string ) ;
}
2018-01-11 11:37:22 +03:00
ex = talloc_strdup ( frame , " " ) ;
2017-12-02 12:34:15 +03:00
if ( ex = = NULL ) {
2018-01-11 11:37:22 +03:00
status = NT_STATUS_NO_MEMORY ;
goto out ;
2017-12-02 12:34:15 +03:00
}
2008-01-18 10:43:45 +03:00
2008-02-17 04:08:12 +03:00
for ( i = 0 ; i < info3 - > base . groups . count ; i + + ) {
2008-01-18 10:43:45 +03:00
ex = talloc_asprintf_append_buffer ( ex , " 0x%08X:0x%08X \n " ,
2008-02-17 04:08:12 +03:00
info3 - > base . groups . rids [ i ] . rid ,
info3 - > base . groups . rids [ i ] . attributes ) ;
2017-12-02 12:34:15 +03:00
if ( ex = = NULL ) {
2018-01-11 11:37:22 +03:00
status = NT_STATUS_NO_MEMORY ;
goto out ;
2017-12-02 12:34:15 +03:00
}
2008-01-18 10:43:45 +03:00
}
2008-02-17 04:08:12 +03:00
for ( i = 0 ; i < info3 - > sidcount ; i + + ) {
2018-11-24 15:25:25 +03:00
struct dom_sid_buf sidbuf ;
2008-01-18 10:43:45 +03:00
2018-11-24 15:25:25 +03:00
ex = talloc_asprintf_append_buffer (
ex ,
" %s:0x%08X \n " ,
dom_sid_str_buf ( info3 - > sids [ i ] . sid , & sidbuf ) ,
info3 - > sids [ i ] . attributes ) ;
2017-12-02 12:34:15 +03:00
if ( ex = = NULL ) {
2018-01-11 11:37:22 +03:00
status = NT_STATUS_NO_MEMORY ;
goto out ;
2017-12-02 12:34:15 +03:00
}
2008-01-18 10:43:45 +03:00
}
2010-11-16 19:56:21 +03:00
resp - > length + = talloc_get_size ( ex ) ;
2018-01-11 11:37:22 +03:00
resp - > extra_data . data = talloc_move ( mem_ctx , & ex ) ;
2008-01-18 10:43:45 +03:00
2018-01-11 11:37:22 +03:00
status = NT_STATUS_OK ;
out :
TALLOC_FREE ( frame ) ;
return status ;
2006-02-04 01:19:41 +03:00
}
2002-08-17 21:00:51 +04:00
2007-09-21 16:24:43 +04:00
static NTSTATUS append_info3_as_ndr ( TALLOC_CTX * mem_ctx ,
2010-11-16 19:50:16 +03:00
struct winbindd_response * resp ,
2008-02-17 04:04:52 +03:00
struct netr_SamInfo3 * info3 )
2002-08-17 21:00:51 +04:00
{
2008-02-17 04:04:52 +03:00
DATA_BLOB blob ;
enum ndr_err_code ndr_err ;
2010-05-10 02:42:06 +04:00
ndr_err = ndr_push_struct_blob ( & blob , mem_ctx , info3 ,
2008-02-17 04:04:52 +03:00
( ndr_push_flags_fn_t ) ndr_push_netr_SamInfo3 ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( " append_info3_as_ndr: failed to append \n " ) ) ;
return ndr_map_error2ntstatus ( ndr_err ) ;
2002-08-17 21:00:51 +04:00
}
2010-11-16 19:50:16 +03:00
resp - > extra_data . data = blob . data ;
resp - > length + = blob . length ;
2008-02-17 04:04:52 +03:00
2002-08-17 21:00:51 +04:00
return NT_STATUS_OK ;
}
2007-08-20 19:53:56 +04:00
static NTSTATUS append_unix_username ( TALLOC_CTX * mem_ctx ,
2010-11-16 19:44:08 +03:00
struct winbindd_response * resp ,
2008-02-17 04:08:12 +03:00
const struct netr_SamInfo3 * info3 ,
2007-08-20 19:53:56 +04:00
const char * name_domain ,
const char * name_user )
{
/* We've been asked to return the unix username, per
' winbind use default domain ' settings and the like */
2018-05-08 12:18:56 +03:00
const char * nt_username , * nt_domain , * unix_username ;
2007-08-20 19:53:56 +04:00
2011-10-22 00:10:43 +04:00
nt_domain = talloc_strdup ( mem_ctx , info3 - > base . logon_domain . string ) ;
2008-02-17 04:08:12 +03:00
if ( ! nt_domain ) {
2007-08-20 19:53:56 +04:00
/* If the server didn't give us one, just use the one
* we sent them */
nt_domain = name_domain ;
}
2008-02-17 04:08:12 +03:00
nt_username = talloc_strdup ( mem_ctx , info3 - > base . account_name . string ) ;
if ( ! nt_username ) {
2007-08-20 19:53:56 +04:00
/* If the server didn't give us one, just use the one
* we sent them */
nt_username = name_user ;
}
2018-05-08 12:18:56 +03:00
unix_username = fill_domain_username_talloc ( mem_ctx ,
nt_domain ,
nt_username ,
true ) ;
if ( unix_username = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
fstrcpy ( resp - > data . auth . unix_username , unix_username ) ;
2007-08-20 19:53:56 +04:00
2010-11-16 19:44:08 +03:00
DEBUG ( 5 , ( " Setting unix username to [%s] \n " ,
resp - > data . auth . unix_username ) ) ;
2007-08-20 19:53:56 +04:00
return NT_STATUS_OK ;
}
static NTSTATUS append_afs_token ( TALLOC_CTX * mem_ctx ,
2010-11-16 19:52:31 +03:00
struct winbindd_response * resp ,
2008-02-17 04:08:12 +03:00
const struct netr_SamInfo3 * info3 ,
2007-08-20 19:53:56 +04:00
const char * name_domain ,
const char * name_user )
{
char * afsname = NULL ;
char * cell ;
2009-05-12 19:47:22 +04:00
char * token ;
2007-08-20 19:53:56 +04:00
afsname = talloc_strdup ( mem_ctx , lp_afs_username_map ( ) ) ;
if ( afsname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
afsname = talloc_string_sub ( mem_ctx ,
lp_afs_username_map ( ) ,
" %D " , name_domain ) ;
afsname = talloc_string_sub ( mem_ctx , afsname ,
" %u " , name_user ) ;
afsname = talloc_string_sub ( mem_ctx , afsname ,
" %U " , name_user ) ;
{
2010-05-21 05:25:01 +04:00
struct dom_sid user_sid ;
2018-10-26 09:25:14 +03:00
struct dom_sid_buf sidstr ;
2007-08-20 19:53:56 +04:00
2010-01-10 19:39:27 +03:00
sid_compose ( & user_sid , info3 - > base . domain_sid ,
info3 - > base . rid ) ;
2018-10-26 09:25:14 +03:00
afsname = talloc_string_sub (
mem_ctx ,
afsname ,
" %s " ,
dom_sid_str_buf ( & user_sid , & sidstr ) ) ;
2007-08-20 19:53:56 +04:00
}
if ( afsname = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-08-09 04:01:00 +04:00
if ( ! strlower_m ( afsname ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-08-20 19:53:56 +04:00
DEBUG ( 10 , ( " Generating token for user %s \n " , afsname ) ) ;
cell = strchr ( afsname , ' @ ' ) ;
if ( cell = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
* cell = ' \0 ' ;
cell + = 1 ;
2009-05-12 19:47:22 +04:00
token = afs_createtoken_str ( afsname , cell ) ;
if ( token = = NULL ) {
return NT_STATUS_OK ;
}
2010-11-16 19:52:31 +03:00
resp - > extra_data . data = talloc_strdup ( mem_ctx , token ) ;
if ( resp - > extra_data . data = = NULL ) {
2009-05-12 19:47:22 +04:00
return NT_STATUS_NO_MEMORY ;
2007-08-20 19:53:56 +04:00
}
2010-11-16 19:52:31 +03:00
resp - > length + = strlen ( ( const char * ) resp - > extra_data . data ) + 1 ;
2007-08-20 19:53:56 +04:00
return NT_STATUS_OK ;
}
2010-03-31 22:57:01 +04:00
static NTSTATUS check_info3_in_group ( struct netr_SamInfo3 * info3 ,
const char * group_sid )
2007-01-25 03:47:27 +03:00
/**
* Check whether a user belongs to a group or list of groups .
*
* @ param mem_ctx talloc memory context .
* @ param info3 user information , including group membership info .
* @ param group_sid One or more groups , separated by commas .
*
* @ return NT_STATUS_OK on success ,
* NT_STATUS_LOGON_FAILURE if the user does not belong ,
* or other NT_STATUS_IS_ERR ( status ) for other kinds of failure .
*/
2004-04-06 20:44:24 +04:00
{
2010-05-21 05:25:01 +04:00
struct dom_sid * require_membership_of_sid ;
2010-08-26 14:54:13 +04:00
uint32_t num_require_membership_of_sid ;
2007-12-08 04:32:32 +03:00
char * req_sid ;
2007-05-07 17:56:57 +04:00
const char * p ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2007-05-07 17:56:57 +04:00
size_t i ;
2010-08-26 14:04:11 +04:00
struct security_token * token ;
2009-09-27 14:47:24 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2007-05-07 17:56:57 +04:00
NTSTATUS status ;
2004-04-06 20:44:24 +04:00
/* Parse the 'required group' SID */
2007-12-08 04:32:32 +03:00
2004-04-06 20:44:24 +04:00
if ( ! group_sid | | ! group_sid [ 0 ] ) {
/* NO sid supplied, all users may access */
2012-07-17 23:38:31 +04:00
TALLOC_FREE ( frame ) ;
2004-04-06 20:44:24 +04:00
return NT_STATUS_OK ;
}
2007-01-25 03:47:27 +03:00
2010-08-26 14:04:11 +04:00
token = talloc_zero ( talloc_tos ( ) , struct security_token ) ;
2009-09-27 14:47:24 +04:00
if ( token = = NULL ) {
2007-05-07 17:56:57 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2009-09-27 14:47:24 +04:00
TALLOC_FREE ( frame ) ;
2007-05-07 17:56:57 +04:00
return NT_STATUS_NO_MEMORY ;
2007-01-25 03:47:27 +03:00
}
2007-05-07 17:56:57 +04:00
num_require_membership_of_sid = 0 ;
require_membership_of_sid = NULL ;
2007-01-25 03:47:27 +03:00
2007-05-07 17:56:57 +04:00
p = group_sid ;
2007-01-25 03:47:27 +03:00
2009-09-27 14:47:24 +04:00
while ( next_token_talloc ( talloc_tos ( ) , & p , & req_sid , " , " ) ) {
2007-05-07 17:56:57 +04:00
if ( ! string_to_sid ( & sid , req_sid ) ) {
DEBUG ( 0 , ( " check_info3_in_group: could not parse %s "
" as a SID! " , req_sid ) ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2007-05-07 17:56:57 +04:00
return NT_STATUS_INVALID_PARAMETER ;
}
2007-01-25 03:47:27 +03:00
2009-09-27 14:47:24 +04:00
status = add_sid_to_array ( talloc_tos ( ) , & sid ,
2008-01-09 02:11:31 +03:00
& require_membership_of_sid ,
& num_require_membership_of_sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-05-07 17:56:57 +04:00
DEBUG ( 0 , ( " add_sid_to_array failed \n " ) ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2008-01-09 02:11:31 +03:00
return status ;
2007-01-25 03:47:27 +03:00
}
}
2009-09-27 14:47:24 +04:00
status = sid_array_from_info3 ( talloc_tos ( ) , info3 ,
2010-08-31 03:32:52 +04:00
& token - > sids ,
2007-07-17 15:47:17 +04:00
& token - > num_sids ,
2012-07-21 04:12:09 +04:00
true ) ;
2007-07-17 15:47:17 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-09-27 14:47:24 +04:00
TALLOC_FREE ( frame ) ;
2007-07-17 15:47:17 +04:00
return status ;
2004-04-06 20:44:24 +04:00
}
2007-05-07 17:56:57 +04:00
if ( ! NT_STATUS_IS_OK ( status = add_aliases ( get_global_sam_sid ( ) ,
token ) )
| | ! NT_STATUS_IS_OK ( status = add_aliases ( & global_sid_Builtin ,
token ) ) ) {
DEBUG ( 3 , ( " could not add aliases: %s \n " ,
nt_errstr ( status ) ) ) ;
2009-09-27 14:47:24 +04:00
TALLOC_FREE ( frame ) ;
2007-05-07 17:56:57 +04:00
return status ;
}
2010-09-17 09:31:28 +04:00
security_token_debug ( DBGC_CLASS , 10 , token ) ;
2007-05-07 17:56:57 +04:00
for ( i = 0 ; i < num_require_membership_of_sid ; i + + ) {
2018-12-14 23:09:51 +03:00
struct dom_sid_buf buf ;
DEBUG ( 10 , ( " Checking SID %s \n " ,
dom_sid_str_buf ( & require_membership_of_sid [ i ] ,
& buf ) ) ) ;
2007-05-07 17:56:57 +04:00
if ( nt_token_check_sid ( & require_membership_of_sid [ i ] ,
token ) ) {
DEBUG ( 10 , ( " Access ok \n " ) ) ;
2009-09-27 14:47:24 +04:00
TALLOC_FREE ( frame ) ;
2007-05-07 17:56:57 +04:00
return NT_STATUS_OK ;
2004-04-06 20:44:24 +04:00
}
}
2008-08-19 03:18:24 +04:00
2004-04-06 20:44:24 +04:00
/* Do not distinguish this error from a wrong username/pw */
2009-09-27 14:47:24 +04:00
TALLOC_FREE ( frame ) ;
2004-04-06 20:44:24 +04:00
return NT_STATUS_LOGON_FAILURE ;
}
2009-09-27 13:49:11 +04:00
struct winbindd_domain * find_auth_domain ( uint8_t flags ,
const char * domain_name )
2005-06-09 02:10:34 +04:00
{
struct winbindd_domain * domain ;
if ( IS_DC ) {
domain = find_domain_from_name_noinit ( domain_name ) ;
if ( domain = = NULL ) {
2008-01-28 19:47:41 +03:00
DEBUG ( 3 , ( " Authentication for domain [%s] refused "
2008-08-19 03:18:24 +04:00
" as it is not a trusted domain \n " ,
2005-06-09 02:10:34 +04:00
domain_name ) ) ;
2018-01-15 14:06:50 +03:00
return NULL ;
2005-06-09 02:10:34 +04:00
}
2018-01-15 14:06:50 +03:00
if ( domain - > secure_channel_type ! = SEC_CHAN_NULL ) {
return domain ;
}
return domain - > routing_domain ;
2005-06-09 02:10:34 +04:00
}
2010-04-11 17:27:49 +04:00
if ( strequal ( domain_name , get_global_sam_name ( ) ) ) {
return find_domain_from_name_noinit ( domain_name ) ;
2005-06-09 02:10:34 +04:00
}
2019-07-19 18:10:09 +03:00
if ( lp_winbind_use_krb5_enterprise_principals ( ) ) {
/*
* If we use enterprise principals
* we always go trough our primary domain
* and follow the WRONG_REALM replies .
*/
flags & = ~ WBFLAG_PAM_CONTACT_TRUSTDOM ;
}
2006-08-23 02:53:08 +04:00
/* we can auth against trusted domains */
2009-09-27 13:49:11 +04:00
if ( flags & WBFLAG_PAM_CONTACT_TRUSTDOM ) {
2006-08-23 02:53:08 +04:00
domain = find_domain_from_name_noinit ( domain_name ) ;
if ( domain = = NULL ) {
2008-08-19 03:18:24 +04:00
DEBUG ( 3 , ( " Authentication for domain [%s] skipped "
" as it is not a trusted domain \n " ,
2006-08-23 02:53:08 +04:00
domain_name ) ) ;
} else {
2006-06-23 05:17:33 +04:00
return domain ;
2008-08-19 03:18:24 +04:00
}
2007-05-15 17:47:25 +04:00
}
2006-06-23 05:17:33 +04:00
2005-06-09 02:10:34 +04:00
return find_our_domain ( ) ;
}
2017-04-04 10:24:11 +03:00
static void fake_password_policy ( struct winbindd_response * r ,
const struct netr_SamBaseInfo * bi )
{
NTTIME min_password_age ;
NTTIME max_password_age ;
if ( bi - > allow_password_change > bi - > last_password_change ) {
min_password_age = bi - > allow_password_change -
bi - > last_password_change ;
} else {
min_password_age = 0 ;
}
if ( bi - > force_password_change > bi - > last_password_change ) {
max_password_age = bi - > force_password_change -
bi - > last_password_change ;
} else {
max_password_age = 0 ;
}
r - > data . auth . policy . min_length_password = 0 ;
r - > data . auth . policy . password_history = 0 ;
r - > data . auth . policy . password_properties = 0 ;
r - > data . auth . policy . expire =
nt_time_to_unix_abs ( & max_password_age ) ;
r - > data . auth . policy . min_passwordage =
nt_time_to_unix_abs ( & min_password_age ) ;
}
2008-08-19 20:31:10 +04:00
static void fill_in_password_policy ( struct winbindd_response * r ,
const struct samr_DomInfo1 * p )
{
r - > data . auth . policy . min_length_password =
p - > min_password_length ;
r - > data . auth . policy . password_history =
p - > password_history_length ;
r - > data . auth . policy . password_properties =
p - > password_properties ;
r - > data . auth . policy . expire =
2011-05-06 01:36:55 +04:00
nt_time_to_unix_abs ( ( const NTTIME * ) & ( p - > max_password_age ) ) ;
2008-08-19 20:31:10 +04:00
r - > data . auth . policy . min_passwordage =
2011-05-06 01:36:55 +04:00
nt_time_to_unix_abs ( ( const NTTIME * ) & ( p - > min_password_age ) ) ;
2008-08-19 20:31:10 +04:00
}
2006-02-04 01:19:41 +03:00
static NTSTATUS fillup_password_policy ( struct winbindd_domain * domain ,
2011-01-28 21:05:37 +03:00
struct winbindd_response * response )
2006-02-04 01:19:41 +03:00
{
2011-01-28 21:04:04 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
NTSTATUS status ;
2008-02-05 19:25:07 +03:00
struct samr_DomInfo1 password_policy ;
2006-02-04 01:19:41 +03:00
2007-05-07 00:16:12 +04:00
if ( ! winbindd_can_contact_domain ( domain ) ) {
DEBUG ( 5 , ( " fillup_password_policy: No inbound trust to "
2008-08-19 03:18:24 +04:00
" contact domain %s \n " , domain - > name ) ) ;
2011-01-28 21:04:04 +03:00
status = NT_STATUS_NOT_SUPPORTED ;
goto done ;
2008-08-19 03:18:24 +04:00
}
2007-05-07 00:16:12 +04:00
2016-10-08 02:31:40 +03:00
status = wb_cache_password_policy ( domain , talloc_tos ( ) ,
& password_policy ) ;
2006-02-04 01:19:41 +03:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2011-01-28 21:04:04 +03:00
goto done ;
2006-02-04 01:19:41 +03:00
}
2011-01-28 21:05:37 +03:00
fill_in_password_policy ( response , & password_policy ) ;
2006-02-04 01:19:41 +03:00
2011-01-28 21:04:04 +03:00
done :
TALLOC_FREE ( frame ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_OK ;
}
2008-08-19 03:18:24 +04:00
static NTSTATUS get_max_bad_attempts_from_lockout_policy ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2015-04-24 05:04:23 +03:00
uint16_t * lockout_threshold )
2006-02-04 01:19:41 +03:00
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2008-02-05 19:25:07 +03:00
struct samr_DomInfo12 lockout_policy ;
2006-02-04 01:19:41 +03:00
2008-02-05 19:25:07 +03:00
* lockout_threshold = 0 ;
2006-02-04 01:19:41 +03:00
2016-10-08 02:31:40 +03:00
status = wb_cache_lockout_policy ( domain , mem_ctx , & lockout_policy ) ;
2006-02-04 01:19:41 +03:00
if ( NT_STATUS_IS_ERR ( status ) ) {
return status ;
}
2008-02-05 19:25:07 +03:00
* lockout_threshold = lockout_policy . lockout_threshold ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_OK ;
}
2008-08-19 03:18:24 +04:00
static NTSTATUS get_pwd_properties ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2015-04-24 05:04:23 +03:00
uint32_t * password_properties )
2006-02-27 19:39:56 +03:00
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2008-02-05 19:25:07 +03:00
struct samr_DomInfo1 password_policy ;
2006-02-27 19:39:56 +03:00
* password_properties = 0 ;
2016-10-08 02:31:40 +03:00
status = wb_cache_password_policy ( domain , mem_ctx , & password_policy ) ;
2006-02-27 19:39:56 +03:00
if ( NT_STATUS_IS_ERR ( status ) ) {
return status ;
}
* password_properties = password_policy . password_properties ;
return NT_STATUS_OK ;
}
2006-02-04 01:19:41 +03:00
2006-09-04 13:29:50 +04:00
# ifdef HAVE_KRB5
2008-08-19 03:18:24 +04:00
static const char * generate_krb5_ccache ( TALLOC_CTX * mem_ctx ,
2006-02-04 01:19:41 +03:00
const char * type ,
uid_t uid ,
2010-09-10 17:07:28 +04:00
const char * * user_ccache_file )
2006-02-04 01:19:41 +03:00
{
2006-03-10 16:36:39 +03:00
/* accept FILE and WRFILE as krb5_cc_type from the client and then
2006-02-04 01:19:41 +03:00
* build the full ccname string based on the user ' s uid here -
* Guenther */
const char * gen_cc = NULL ;
2010-09-10 17:07:28 +04:00
if ( uid ! = - 1 ) {
if ( strequal ( type , " FILE " ) ) {
gen_cc = talloc_asprintf (
mem_ctx , " FILE:/tmp/krb5cc_%d " , uid ) ;
}
if ( strequal ( type , " WRFILE " ) ) {
gen_cc = talloc_asprintf (
mem_ctx , " WRFILE:/tmp/krb5cc_%d " , uid ) ;
}
2013-09-10 11:30:04 +04:00
if ( strequal ( type , " KEYRING " ) ) {
gen_cc = talloc_asprintf (
mem_ctx , " KEYRING:persistent:%d " , uid ) ;
}
2019-07-01 11:43:42 +03:00
if ( strequal ( type , " KCM " ) ) {
gen_cc = talloc_asprintf ( mem_ctx ,
" KCM:%d " ,
uid ) ;
}
2013-07-18 21:05:51 +04:00
if ( strnequal ( type , " FILE:/ " , 6 ) | |
strnequal ( type , " WRFILE:/ " , 8 ) | |
strnequal ( type , " DIR:/ " , 5 ) ) {
/* we allow only one "%u" substitution */
char * p ;
p = strchr ( type , ' % ' ) ;
if ( p ! = NULL ) {
p + + ;
if ( p ! = NULL & & * p = = ' u ' & & strchr ( p , ' % ' ) = = NULL ) {
2014-02-26 23:16:26 +04:00
char uid_str [ sizeof ( " 18446744073709551615 " ) ] ;
snprintf ( uid_str , sizeof ( uid_str ) , " %u " , uid ) ;
gen_cc = talloc_string_sub2 ( mem_ctx ,
type ,
" %u " ,
uid_str ,
/* remove_unsafe_characters */
false ,
/* replace_once */
true ,
/* allow_trailing_dollar */
false ) ;
2013-07-18 21:05:51 +04:00
}
}
}
2006-02-04 01:19:41 +03:00
}
2010-09-10 17:07:28 +04:00
* user_ccache_file = gen_cc ;
2006-02-04 01:19:41 +03:00
2010-09-10 17:07:28 +04:00
if ( gen_cc = = NULL ) {
gen_cc = talloc_strdup ( mem_ctx , " MEMORY:winbindd_pam_ccache " ) ;
}
2006-02-04 01:19:41 +03:00
if ( gen_cc = = NULL ) {
DEBUG ( 0 , ( " out of memory \n " ) ) ;
return NULL ;
}
2010-09-10 17:07:28 +04:00
DEBUG ( 10 , ( " using ccache: %s%s \n " , gen_cc ,
( * user_ccache_file = = NULL ) ? " (internal) " : " " ) ) ;
2006-02-04 01:19:41 +03:00
return gen_cc ;
}
2006-09-04 13:29:50 +04:00
# endif
2010-04-18 16:14:43 +04:00
uid_t get_uid_from_request ( struct winbindd_request * request )
2006-09-04 13:29:50 +04:00
{
2009-09-28 21:50:24 +04:00
uid_t uid ;
2006-09-04 13:29:50 +04:00
2010-04-18 16:14:43 +04:00
uid = request - > data . auth . uid ;
2006-09-04 13:29:50 +04:00
2016-03-09 15:43:09 +03:00
if ( uid = = ( uid_t ) - 1 ) {
2009-05-12 08:56:57 +04:00
DEBUG ( 1 , ( " invalid uid: '%u' \n " , ( unsigned int ) uid ) ) ;
2006-09-04 13:29:50 +04:00
return - 1 ;
}
return uid ;
}
2003-06-30 21:24:59 +04:00
/**********************************************************************
2006-02-04 01:19:41 +03:00
Authenticate a user with a clear text password using Kerberos and fill up
ccache if required
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-26 06:53:45 +04:00
2010-12-11 12:41:38 +03:00
static NTSTATUS winbindd_raw_kerberos_login ( TALLOC_CTX * mem_ctx ,
struct winbindd_domain * domain ,
const char * user ,
const char * pass ,
const char * krb5_cc_type ,
uid_t uid ,
2018-01-23 23:34:46 +03:00
struct netr_SamInfo6 * * info6 ,
2010-12-11 12:41:38 +03:00
fstring krb5ccname )
2006-02-04 01:19:41 +03:00
{
# ifdef HAVE_KRB5
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
krb5_error_code krb5_ret ;
const char * cc = NULL ;
const char * principal_s = NULL ;
const char * service = NULL ;
char * realm = NULL ;
2018-04-26 13:17:12 +03:00
fstring name_namespace , name_domain , name_user ;
2006-02-04 01:19:41 +03:00
time_t ticket_lifetime = 0 ;
time_t renewal_until = 0 ;
ADS_STRUCT * ads ;
time_t time_offset = 0 ;
2010-09-10 17:07:28 +04:00
const char * user_ccache_file ;
2010-05-06 06:45:14 +04:00
struct PAC_LOGON_INFO * logon_info = NULL ;
2018-01-23 23:34:46 +03:00
struct PAC_UPN_DNS_INFO * upn_dns_info = NULL ;
2014-02-21 21:56:04 +04:00
struct PAC_DATA * pac_data = NULL ;
2014-03-11 21:07:11 +04:00
struct PAC_DATA_CTR * pac_data_ctr = NULL ;
2014-01-17 17:29:03 +04:00
const char * local_service ;
2017-08-29 11:21:05 +03:00
uint32_t i ;
2018-01-23 23:34:46 +03:00
struct netr_SamInfo6 * info6_copy = NULL ;
2022-02-22 15:19:02 +03:00
char * canon_principal = NULL ;
char * canon_realm = NULL ;
2018-04-26 13:17:12 +03:00
bool ok ;
2006-02-04 01:19:41 +03:00
2018-01-23 23:34:46 +03:00
* info6 = NULL ;
2008-08-19 03:18:24 +04:00
2013-02-25 12:31:12 +04:00
if ( domain - > alt_name = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2008-08-19 03:18:24 +04:00
/* 1st step:
2006-02-04 01:19:41 +03:00
* prepare a krb5_cc_cache string for the user */
if ( uid = = - 1 ) {
DEBUG ( 0 , ( " no valid uid \n " ) ) ;
}
2010-12-11 12:41:38 +03:00
cc = generate_krb5_ccache ( mem_ctx ,
krb5_cc_type ,
2010-12-11 12:29:57 +03:00
uid ,
2010-09-10 17:07:28 +04:00
& user_ccache_file ) ;
2006-02-04 01:19:41 +03:00
if ( cc = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2008-08-19 03:18:24 +04:00
/* 2nd step:
2006-02-04 01:19:41 +03:00
* get kerberos properties */
2008-08-19 03:18:24 +04:00
2006-02-04 01:19:41 +03:00
if ( domain - > private_data ) {
ads = ( ADS_STRUCT * ) domain - > private_data ;
2008-08-19 03:18:24 +04:00
time_offset = ads - > auth . time_offset ;
2006-02-04 01:19:41 +03:00
}
2008-08-19 03:18:24 +04:00
/* 3rd step:
2006-02-04 01:19:41 +03:00
* do kerberos auth and setup ccache as the user */
2018-04-26 13:17:12 +03:00
ok = parse_domain_user ( user , name_namespace , name_domain , name_user ) ;
if ( ! ok ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2006-02-04 01:19:41 +03:00
2013-02-25 12:31:12 +04:00
realm = talloc_strdup ( mem_ctx , domain - > alt_name ) ;
if ( realm = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( realm ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2008-08-19 03:18:24 +04:00
2019-07-19 18:10:09 +03:00
if ( lp_winbind_use_krb5_enterprise_principals ( ) & &
name_namespace [ 0 ] ! = ' \0 ' )
{
principal_s = talloc_asprintf ( mem_ctx ,
" %s@%s@%s " ,
name_user ,
name_namespace ,
realm ) ;
} else {
principal_s = talloc_asprintf ( mem_ctx ,
" %s@%s " ,
name_user ,
realm ) ;
}
2006-02-04 01:19:41 +03:00
if ( principal_s = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2010-12-11 12:41:38 +03:00
service = talloc_asprintf ( mem_ctx , " %s/%s@%s " , KRB5_TGS_NAME , realm , realm ) ;
2006-02-04 01:19:41 +03:00
if ( service = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2014-01-17 17:29:03 +04:00
local_service = talloc_asprintf ( mem_ctx , " %s$@%s " ,
lp_netbios_name ( ) , lp_realm ( ) ) ;
if ( local_service = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2006-02-04 01:19:41 +03:00
/* if this is a user ccache, we need to act as the user to let the krb5
* library handle the chown , etc . */
2007-08-15 00:06:11 +04:00
/************************ ENTERING NON-ROOT **********************/
2006-02-04 01:19:41 +03:00
2010-09-10 17:07:28 +04:00
if ( user_ccache_file ! = NULL ) {
2006-05-12 02:47:28 +04:00
set_effective_uid ( uid ) ;
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " winbindd_raw_kerberos_login: uid is %d \n " , uid ) ) ;
}
2010-12-11 12:41:38 +03:00
result = kerberos_return_pac ( mem_ctx ,
2010-05-06 06:45:14 +04:00
principal_s ,
2010-12-11 12:41:38 +03:00
pass ,
2010-05-06 06:45:14 +04:00
time_offset ,
& ticket_lifetime ,
& renewal_until ,
cc ,
true ,
true ,
WINBINDD_PAM_AUTH_KRB5_RENEW_TIME ,
NULL ,
2014-01-17 17:29:03 +04:00
local_service ,
2022-02-22 15:19:02 +03:00
& canon_principal ,
& canon_realm ,
2014-03-11 21:07:11 +04:00
& pac_data_ctr ) ;
2010-09-10 17:07:28 +04:00
if ( user_ccache_file ! = NULL ) {
2006-05-12 02:47:28 +04:00
gain_root_privilege ( ) ;
2006-02-04 01:19:41 +03:00
}
2007-08-15 00:06:11 +04:00
/************************ RETURNED TO ROOT **********************/
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-03-29 13:40:42 +04:00
goto failed ;
2006-02-04 01:19:41 +03:00
}
2014-03-11 21:07:11 +04:00
if ( pac_data_ctr = = NULL ) {
goto failed ;
}
pac_data = pac_data_ctr - > pac_data ;
2014-02-21 21:56:04 +04:00
if ( pac_data = = NULL ) {
goto failed ;
}
for ( i = 0 ; i < pac_data - > num_buffers ; i + + ) {
2018-01-23 23:34:46 +03:00
if ( pac_data - > buffers [ i ] . type = = PAC_TYPE_LOGON_INFO ) {
logon_info = pac_data - > buffers [ i ] . info - > logon_info . info ;
2014-02-21 21:56:04 +04:00
continue ;
}
2018-01-23 23:34:46 +03:00
if ( pac_data - > buffers [ i ] . type = = PAC_TYPE_UPN_DNS_INFO ) {
upn_dns_info = & pac_data - > buffers [ i ] . info - > upn_dns_info ;
continue ;
2014-02-21 21:56:04 +04:00
}
}
2015-06-11 02:31:21 +03:00
if ( logon_info = = NULL ) {
DEBUG ( 10 , ( " Missing logon_info in ticket of %s \n " ,
principal_s ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
2010-05-06 06:45:14 +04:00
2007-08-15 00:06:11 +04:00
DEBUG ( 10 , ( " winbindd_raw_kerberos_login: winbindd validated ticket of %s \n " ,
principal_s ) ) ;
2006-02-04 01:19:41 +03:00
2018-01-23 23:34:46 +03:00
result = create_info6_from_pac ( mem_ctx , logon_info ,
upn_dns_info , & info6_copy ) ;
2015-06-10 15:13:25 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto failed ;
}
2006-02-04 01:19:41 +03:00
/* if we had a user's ccache then return that string for the pam
* environment */
2010-09-10 17:07:28 +04:00
if ( user_ccache_file ! = NULL ) {
2008-08-19 03:18:24 +04:00
2010-12-11 12:41:38 +03:00
fstrcpy ( krb5ccname , user_ccache_file ) ;
2006-02-04 01:19:41 +03:00
result = add_ccache_to_list ( principal_s ,
cc ,
service ,
2010-12-11 12:41:38 +03:00
user ,
2012-08-21 22:24:58 +04:00
pass ,
2006-09-08 04:19:32 +04:00
realm ,
2006-02-04 01:19:41 +03:00
uid ,
time ( NULL ) ,
ticket_lifetime ,
2008-08-19 03:18:24 +04:00
renewal_until ,
2022-02-22 15:19:02 +03:00
false ,
canon_principal ,
canon_realm ) ;
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2008-08-19 03:18:24 +04:00
DEBUG ( 10 , ( " winbindd_raw_kerberos_login: failed to add ccache to list: %s \n " ,
2006-02-04 01:19:41 +03:00
nt_errstr ( result ) ) ) ;
}
2007-02-22 16:35:01 +03:00
} else {
/* need to delete the memory cred cache, it is not used anymore */
krb5_ret = ads_kdestroy ( cc ) ;
if ( krb5_ret ) {
DEBUG ( 3 , ( " winbindd_raw_kerberos_login: "
" could not destroy krb5 credential cache: "
" %s \n " , error_message ( krb5_ret ) ) ) ;
}
2006-02-04 01:19:41 +03:00
}
2018-01-23 23:34:46 +03:00
* info6 = info6_copy ;
2007-08-15 00:26:35 +04:00
return NT_STATUS_OK ;
2006-03-29 13:40:42 +04:00
failed :
2013-07-11 15:44:53 +04:00
/*
* Do not delete an existing valid credential cache , if the user
* e . g . enters a wrong password
*/
if ( ( strequal ( krb5_cc_type , " FILE " ) | | strequal ( krb5_cc_type , " WRFILE " ) )
& & user_ccache_file ! = NULL ) {
return result ;
}
2006-03-29 13:40:42 +04:00
/* we could have created a new credential cache with a valid tgt in it
* but we werent able to get or verify the service ticket for this
* local host and therefor didn ' t get the PAC , we need to remove that
* cache entirely now */
krb5_ret = ads_kdestroy ( cc ) ;
if ( krb5_ret ) {
2006-05-02 23:15:14 +04:00
DEBUG ( 3 , ( " winbindd_raw_kerberos_login: "
2006-03-29 13:40:42 +04:00
" could not destroy krb5 credential cache: "
" %s \n " , error_message ( krb5_ret ) ) ) ;
}
2010-12-11 12:41:38 +03:00
if ( ! NT_STATUS_IS_OK ( remove_ccache ( user ) ) ) {
2006-05-02 23:15:14 +04:00
DEBUG ( 3 , ( " winbindd_raw_kerberos_login: "
2006-08-26 06:53:45 +04:00
" could not remove ccache for user %s \n " ,
2010-12-11 12:41:38 +03:00
user ) ) ;
2006-05-02 23:15:14 +04:00
}
2006-02-04 01:19:41 +03:00
return result ;
2007-08-15 00:26:35 +04:00
# else
2006-02-04 01:19:41 +03:00
return NT_STATUS_NOT_SUPPORTED ;
# endif /* HAVE_KRB5 */
}
2000-05-09 15:43:00 +04:00
2007-08-20 19:46:56 +04:00
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-09-27 13:51:07 +04:00
bool check_request_flags ( uint32_t flags )
2007-08-20 19:46:56 +04:00
{
uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
2008-01-18 10:43:45 +03:00
WBFLAG_PAM_INFO3_TEXT |
2007-08-20 19:46:56 +04:00
WBFLAG_PAM_INFO3_NDR ;
if ( ( ( flags & flags_edata ) = = WBFLAG_PAM_AFS_TOKEN ) | |
( ( flags & flags_edata ) = = WBFLAG_PAM_INFO3_NDR ) | |
2008-01-18 10:43:45 +03:00
( ( flags & flags_edata ) = = WBFLAG_PAM_INFO3_TEXT ) | |
2007-08-20 19:46:56 +04:00
! ( flags & flags_edata ) ) {
2008-08-19 20:03:13 +04:00
return true ;
2007-08-20 19:46:56 +04:00
}
2009-09-27 13:51:07 +04:00
DEBUG ( 1 , ( " check_request_flags: invalid request flags[0x%08X] \n " ,
flags ) ) ;
2007-08-20 19:46:56 +04:00
2008-08-19 20:03:13 +04:00
return false ;
2007-08-20 19:46:56 +04:00
}
2007-08-20 19:53:56 +04:00
/****************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-07-19 01:38:47 +04:00
NTSTATUS append_auth_data ( TALLOC_CTX * mem_ctx ,
struct winbindd_response * resp ,
uint32_t request_flags ,
2017-12-02 12:27:12 +03:00
uint16_t validation_level ,
union netr_Validation * validation ,
2012-07-19 01:38:47 +04:00
const char * name_domain ,
const char * name_user )
2007-08-20 19:53:56 +04:00
{
2017-12-02 12:27:12 +03:00
struct netr_SamInfo3 * info3 = NULL ;
2018-01-11 11:27:50 +03:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2007-08-20 19:53:56 +04:00
2017-12-02 12:27:12 +03:00
result = map_validation_to_info3 ( talloc_tos ( ) ,
validation_level ,
validation ,
& info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2018-01-11 11:27:50 +03:00
goto out ;
2017-12-02 12:27:12 +03:00
}
2010-11-16 19:07:33 +03:00
if ( request_flags & WBFLAG_PAM_USER_SESSION_KEY ) {
2010-11-16 19:58:10 +03:00
memcpy ( resp - > data . auth . user_session_key ,
2008-02-17 04:08:12 +03:00
info3 - > base . key . key ,
2010-11-16 19:58:10 +03:00
sizeof ( resp - > data . auth . user_session_key )
2007-08-20 19:53:56 +04:00
/* 16 */ ) ;
}
2010-11-16 19:07:33 +03:00
if ( request_flags & WBFLAG_PAM_LMKEY ) {
2010-11-16 19:58:10 +03:00
memcpy ( resp - > data . auth . first_8_lm_hash ,
2008-02-17 04:08:12 +03:00
info3 - > base . LMSessKey . key ,
2010-11-16 19:58:10 +03:00
sizeof ( resp - > data . auth . first_8_lm_hash )
2007-08-20 19:53:56 +04:00
/* 8 */ ) ;
}
2010-11-16 19:07:33 +03:00
if ( request_flags & WBFLAG_PAM_UNIX_NAME ) {
2010-11-16 19:58:10 +03:00
result = append_unix_username ( mem_ctx , resp ,
2010-11-16 19:44:08 +03:00
info3 , name_domain , name_user ) ;
2007-08-20 19:53:56 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2010-04-25 17:36:02 +04:00
DEBUG ( 10 , ( " Failed to append Unix Username: %s \n " ,
2007-08-20 19:53:56 +04:00
nt_errstr ( result ) ) ) ;
2018-01-11 11:27:50 +03:00
goto out ;
2007-08-20 19:53:56 +04:00
}
}
/* currently, anything from here on potentially overwrites extra_data. */
2010-11-16 19:07:33 +03:00
if ( request_flags & WBFLAG_PAM_INFO3_NDR ) {
2010-11-16 19:58:10 +03:00
result = append_info3_as_ndr ( mem_ctx , resp , info3 ) ;
2007-08-20 19:53:56 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " Failed to append INFO3 (NDR): %s \n " ,
nt_errstr ( result ) ) ) ;
2018-01-11 11:27:50 +03:00
goto out ;
2007-08-20 19:53:56 +04:00
}
}
2010-11-16 19:07:33 +03:00
if ( request_flags & WBFLAG_PAM_INFO3_TEXT ) {
2017-12-02 12:34:15 +03:00
result = append_info3_as_txt ( mem_ctx , resp ,
validation_level ,
validation ) ;
2007-08-20 19:53:56 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2010-04-25 17:36:02 +04:00
DEBUG ( 10 , ( " Failed to append INFO3 (TXT): %s \n " ,
2007-08-20 19:53:56 +04:00
nt_errstr ( result ) ) ) ;
2018-01-11 11:27:50 +03:00
goto out ;
2007-08-20 19:53:56 +04:00
}
}
2010-11-16 19:07:33 +03:00
if ( request_flags & WBFLAG_PAM_AFS_TOKEN ) {
2010-11-16 19:58:10 +03:00
result = append_afs_token ( mem_ctx , resp ,
2010-11-16 19:52:31 +03:00
info3 , name_domain , name_user ) ;
2007-08-20 19:53:56 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " Failed to append AFS token: %s \n " ,
nt_errstr ( result ) ) ) ;
2018-01-11 11:27:50 +03:00
goto out ;
2007-08-20 19:53:56 +04:00
}
}
2018-01-11 11:27:50 +03:00
result = NT_STATUS_OK ;
out :
2017-12-02 12:27:12 +03:00
TALLOC_FREE ( info3 ) ;
2018-01-11 11:27:50 +03:00
return result ;
2007-08-20 19:53:56 +04:00
}
2009-09-05 19:00:21 +04:00
static NTSTATUS winbindd_dual_pam_auth_cached ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state ,
struct netr_SamInfo3 * * info3 )
2000-05-09 15:43:00 +04:00
{
2006-02-04 01:19:41 +03:00
NTSTATUS result = NT_STATUS_LOGON_FAILURE ;
2015-04-24 05:04:23 +03:00
uint16_t max_allowed_bad_attempts ;
2018-04-26 13:17:12 +03:00
fstring name_namespace , name_domain , name_user ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType type ;
2006-02-04 01:19:41 +03:00
uchar new_nt_pass [ NT_HASH_LEN ] ;
2015-04-24 05:04:23 +03:00
const uint8_t * cached_nt_pass ;
const uint8_t * cached_salt ;
2008-02-17 04:08:12 +03:00
struct netr_SamInfo3 * my_info3 ;
2006-02-04 01:19:41 +03:00
time_t kickoff_time , must_change_time ;
2008-08-19 20:03:13 +04:00
bool password_good = false ;
2018-05-15 14:40:36 +03:00
bool ok ;
2007-05-15 17:46:26 +04:00
# ifdef HAVE_KRB5
struct winbindd_tdc_domain * tdc_domain = NULL ;
# endif
2006-02-04 01:19:41 +03:00
* info3 = NULL ;
ZERO_STRUCTP ( info3 ) ;
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached \n " ) ) ;
/* Parse domain and username */
2008-08-19 03:18:24 +04:00
2018-05-15 14:40:36 +03:00
ok = parse_domain_user ( state - > request - > data . auth . user ,
name_namespace ,
name_domain ,
name_user ) ;
if ( ! ok ) {
DBG_DEBUG ( " parse_domain_user failed \n " ) ;
return NT_STATUS_NO_SUCH_USER ;
}
2006-02-04 01:19:41 +03:00
2018-04-26 13:17:12 +03:00
if ( ! lookup_cached_name ( name_namespace ,
name_domain ,
2006-02-04 01:19:41 +03:00
name_user ,
& sid ,
& type ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached: no such user in the cache \n " ) ) ;
return NT_STATUS_NO_SUCH_USER ;
}
if ( type ! = SID_NAME_USER ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached: not a user (%s) \n " , sid_type_lookup ( type ) ) ) ;
return NT_STATUS_LOGON_FAILURE ;
}
2008-08-19 03:18:24 +04:00
result = winbindd_get_creds ( domain ,
state - > mem_ctx ,
& sid ,
& my_info3 ,
2006-08-20 07:53:42 +04:00
& cached_nt_pass ,
& cached_salt ) ;
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached: failed to get creds: %s \n " , nt_errstr ( result ) ) ) ;
return result ;
}
* info3 = my_info3 ;
2009-05-08 00:46:27 +04:00
E_md4hash ( state - > request - > data . auth . pass , new_nt_pass ) ;
2006-02-04 01:19:41 +03:00
2007-08-15 00:43:02 +04:00
dump_data_pw ( " new_nt_pass " , new_nt_pass , NT_HASH_LEN ) ;
dump_data_pw ( " cached_nt_pass " , cached_nt_pass , NT_HASH_LEN ) ;
2006-08-20 07:53:42 +04:00
if ( cached_salt ) {
2007-08-15 00:43:02 +04:00
dump_data_pw ( " cached_salt " , cached_salt , NT_HASH_LEN ) ;
2006-08-20 07:53:42 +04:00
}
2006-02-04 01:19:41 +03:00
2006-08-20 07:53:42 +04:00
if ( cached_salt ) {
/* In this case we didn't store the nt_hash itself,
but the MD5 combination of salt + nt_hash . */
uchar salted_hash [ NT_HASH_LEN ] ;
2019-11-18 12:28:59 +03:00
gnutls_hash_hd_t hash_hnd = NULL ;
int rc ;
rc = gnutls_hash_init ( & hash_hnd , GNUTLS_DIG_MD5 ) ;
if ( rc < 0 ) {
return gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ;
}
rc = gnutls_hash ( hash_hnd , cached_salt , 16 ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
return gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ;
}
rc = gnutls_hash ( hash_hnd , new_nt_pass , 16 ) ;
if ( rc < 0 ) {
gnutls_hash_deinit ( hash_hnd , NULL ) ;
return gnutls_error_to_ntstatus ( rc , NT_STATUS_HASH_NOT_SUPPORTED ) ;
}
gnutls_hash_deinit ( hash_hnd , salted_hash ) ;
2006-08-20 07:53:42 +04:00
2009-09-05 19:05:30 +04:00
password_good = ( memcmp ( cached_nt_pass , salted_hash ,
NT_HASH_LEN ) = = 0 ) ;
2006-08-20 07:53:42 +04:00
} else {
/* Old cached cred - direct store of nt_hash (bad bad bad !). */
2009-09-05 19:05:30 +04:00
password_good = ( memcmp ( cached_nt_pass , new_nt_pass ,
NT_HASH_LEN ) = = 0 ) ;
2006-08-20 07:53:42 +04:00
}
if ( password_good ) {
2006-02-04 01:19:41 +03:00
/* User *DOES* know the password, update logon_time and reset
* bad_pw_count */
2008-08-19 03:18:24 +04:00
2008-02-17 04:08:12 +03:00
my_info3 - > base . user_flags | = NETLOGON_CACHED_ACCOUNT ;
2008-08-19 03:18:24 +04:00
2008-02-17 04:08:12 +03:00
if ( my_info3 - > base . acct_flags & ACB_AUTOLOCK ) {
2006-02-04 01:19:41 +03:00
return NT_STATUS_ACCOUNT_LOCKED_OUT ;
}
2008-08-19 03:18:24 +04:00
2008-02-17 04:08:12 +03:00
if ( my_info3 - > base . acct_flags & ACB_DISABLED ) {
2006-02-04 01:19:41 +03:00
return NT_STATUS_ACCOUNT_DISABLED ;
}
2008-08-19 03:18:24 +04:00
2008-02-17 04:08:12 +03:00
if ( my_info3 - > base . acct_flags & ACB_WSTRUST ) {
2006-02-04 01:19:41 +03:00
return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ;
}
2008-08-19 03:18:24 +04:00
2008-02-17 04:08:12 +03:00
if ( my_info3 - > base . acct_flags & ACB_SVRTRUST ) {
2006-02-04 01:19:41 +03:00
return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ;
}
2008-08-19 03:18:24 +04:00
2008-02-17 04:08:12 +03:00
if ( my_info3 - > base . acct_flags & ACB_DOMTRUST ) {
2006-02-04 01:19:41 +03:00
return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ;
}
2006-02-22 23:40:24 +03:00
2008-02-17 04:08:12 +03:00
if ( ! ( my_info3 - > base . acct_flags & ACB_NORMAL ) ) {
2008-08-19 03:18:24 +04:00
DEBUG ( 0 , ( " winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x \n " ,
2008-02-17 04:08:12 +03:00
my_info3 - > base . acct_flags ) ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_LOGON_FAILURE ;
}
2007-02-13 18:56:09 +03:00
2011-10-22 00:10:43 +04:00
kickoff_time = nt_time_to_unix ( my_info3 - > base . kickoff_time ) ;
2006-02-04 01:19:41 +03:00
if ( kickoff_time ! = 0 & & time ( NULL ) > kickoff_time ) {
return NT_STATUS_ACCOUNT_EXPIRED ;
}
2008-02-17 04:08:12 +03:00
must_change_time = nt_time_to_unix ( my_info3 - > base . force_password_change ) ;
2006-02-04 01:19:41 +03:00
if ( must_change_time ! = 0 & & must_change_time < time ( NULL ) ) {
2007-01-11 18:41:02 +03:00
/* we allow grace logons when the password has expired */
2008-02-17 04:08:12 +03:00
my_info3 - > base . user_flags | = NETLOGON_GRACE_LOGON ;
2007-01-11 18:41:02 +03:00
/* return NT_STATUS_PASSWORD_EXPIRED; */
goto success ;
2006-02-04 01:19:41 +03:00
}
2008-08-19 03:18:24 +04:00
2006-09-08 12:47:07 +04:00
# ifdef HAVE_KRB5
2009-05-08 00:46:27 +04:00
if ( ( state - > request - > flags & WBFLAG_PAM_KRB5 ) & &
2007-05-15 17:46:26 +04:00
( ( tdc_domain = wcache_tdc_fetch_domain ( state - > mem_ctx , name_domain ) ) ! = NULL ) & &
2014-09-23 21:02:57 +04:00
( ( tdc_domain - > trust_type & LSA_TRUST_TYPE_UPLEVEL ) | |
2009-11-06 03:20:25 +03:00
/* used to cope with the case winbindd starting without network. */
! strequal ( tdc_domain - > domain_name , tdc_domain - > dns_name ) ) ) {
2006-09-08 04:19:32 +04:00
uid_t uid = - 1 ;
const char * cc = NULL ;
char * realm = NULL ;
const char * principal_s = NULL ;
const char * service = NULL ;
2010-09-10 17:07:28 +04:00
const char * user_ccache_file ;
2006-09-08 04:19:32 +04:00
2013-02-25 12:31:12 +04:00
if ( domain - > alt_name = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2011-01-28 21:07:40 +03:00
uid = get_uid_from_request ( state - > request ) ;
2006-09-08 04:19:32 +04:00
if ( uid = = - 1 ) {
DEBUG ( 0 , ( " winbindd_dual_pam_auth_cached: invalid uid \n " ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
cc = generate_krb5_ccache ( state - > mem_ctx ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . krb5_cc_type ,
state - > request - > data . auth . uid ,
2010-09-10 17:07:28 +04:00
& user_ccache_file ) ;
2006-09-08 04:19:32 +04:00
if ( cc = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2013-02-25 12:31:12 +04:00
realm = talloc_strdup ( state - > mem_ctx , domain - > alt_name ) ;
if ( realm = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( realm ) ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2006-09-08 04:19:32 +04:00
principal_s = talloc_asprintf ( state - > mem_ctx , " %s@%s " , name_user , realm ) ;
if ( principal_s = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
service = talloc_asprintf ( state - > mem_ctx , " %s/%s@%s " , KRB5_TGS_NAME , realm , realm ) ;
if ( service = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2010-09-10 17:07:28 +04:00
if ( user_ccache_file ! = NULL ) {
2006-09-08 04:19:32 +04:00
2010-09-10 17:07:28 +04:00
fstrcpy ( state - > response - > data . auth . krb5ccname ,
user_ccache_file ) ;
2006-09-08 04:19:32 +04:00
result = add_ccache_to_list ( principal_s ,
cc ,
service ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
2012-08-21 22:24:58 +04:00
state - > request - > data . auth . pass ,
2013-02-25 12:31:12 +04:00
realm ,
2006-09-08 04:19:32 +04:00
uid ,
time ( NULL ) ,
time ( NULL ) + lp_winbind_cache_time ( ) ,
time ( NULL ) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME ,
2022-02-22 15:19:02 +03:00
true ,
principal_s ,
realm ) ;
2006-09-08 04:19:32 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached: failed "
" to add ccache to list: %s \n " ,
nt_errstr ( result ) ) ) ;
}
}
}
2006-09-08 12:47:07 +04:00
# endif /* HAVE_KRB5 */
2007-01-11 18:41:02 +03:00
success :
/* FIXME: we possibly should handle logon hours as well (does xp when
* offline ? ) see auth / auth_sam . c : sam_account_ok for details */
2011-10-22 00:10:43 +04:00
unix_to_nt_time ( & my_info3 - > base . logon_time , time ( NULL ) ) ;
2008-02-17 04:08:12 +03:00
my_info3 - > base . bad_password_count = 0 ;
2007-01-11 18:41:02 +03:00
result = winbindd_update_creds_by_info3 ( domain ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
state - > request - > data . auth . pass ,
2007-01-11 18:41:02 +03:00
my_info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 1 , ( " winbindd_dual_pam_auth_cached: failed to update creds: %s \n " ,
nt_errstr ( result ) ) ) ;
return result ;
}
2006-02-04 01:19:41 +03:00
return NT_STATUS_OK ;
}
2011-05-25 18:49:41 +04:00
/* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
if ( domain - > online = = false ) {
goto failed ;
}
2006-02-04 01:19:41 +03:00
/* failure of this is not critical */
result = get_max_bad_attempts_from_lockout_policy ( domain , state - > mem_ctx , & max_allowed_bad_attempts ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
" Won't be able to honour account lockout policies \n " ) ) ;
}
/* increase counter */
2008-02-17 04:08:12 +03:00
my_info3 - > base . bad_password_count + + ;
2006-02-27 19:39:56 +03:00
if ( max_allowed_bad_attempts = = 0 ) {
goto failed ;
2006-02-04 01:19:41 +03:00
}
/* lockout user */
2008-02-17 04:08:12 +03:00
if ( my_info3 - > base . bad_password_count > = max_allowed_bad_attempts ) {
2006-02-04 01:19:41 +03:00
2015-04-24 05:04:23 +03:00
uint32_t password_properties ;
2006-02-27 19:39:56 +03:00
result = get_pwd_properties ( domain , state - > mem_ctx , & password_properties ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached: failed to get password properties. \n " ) ) ;
}
2010-05-18 00:04:24 +04:00
if ( ( my_info3 - > base . rid ! = DOMAIN_RID_ADMINISTRATOR ) | |
2008-01-17 12:24:34 +03:00
( password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS ) ) {
2008-02-17 04:08:12 +03:00
my_info3 - > base . acct_flags | = ACB_AUTOLOCK ;
2006-02-27 19:39:56 +03:00
}
2006-02-04 01:19:41 +03:00
}
2006-02-27 19:39:56 +03:00
failed :
2006-02-04 01:19:41 +03:00
result = winbindd_update_creds_by_info3 ( domain ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
2006-02-04 01:19:41 +03:00
NULL ,
my_info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2008-08-19 03:18:24 +04:00
DEBUG ( 0 , ( " winbindd_dual_pam_auth_cached: failed to update creds %s \n " ,
2006-02-04 01:19:41 +03:00
nt_errstr ( result ) ) ) ;
}
return NT_STATUS_LOGON_FAILURE ;
}
2009-09-05 19:00:21 +04:00
static NTSTATUS winbindd_dual_pam_auth_kerberos ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state ,
2018-01-23 23:34:46 +03:00
struct netr_SamInfo6 * * info6 )
2006-02-04 01:19:41 +03:00
{
struct winbindd_domain * contact_domain ;
2018-04-26 13:17:12 +03:00
fstring name_namespace , name_domain , name_user ;
2006-02-04 01:19:41 +03:00
NTSTATUS result ;
2018-04-26 13:17:12 +03:00
bool ok ;
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth_kerberos \n " ) ) ;
2008-08-19 03:18:24 +04:00
2006-02-04 01:19:41 +03:00
/* Parse domain and username */
2008-08-19 03:18:24 +04:00
2018-04-26 13:17:12 +03:00
ok = parse_domain_user ( state - > request - > data . auth . user ,
name_namespace ,
name_domain ,
name_user ) ;
if ( ! ok ) {
result = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
2006-02-04 01:19:41 +03:00
/* what domain should we contact? */
2008-08-19 03:18:24 +04:00
2019-07-19 18:10:09 +03:00
if ( lp_winbind_use_krb5_enterprise_principals ( ) ) {
contact_domain = find_auth_domain ( 0 , name_namespace ) ;
2006-02-04 01:19:41 +03:00
} else {
2018-04-26 13:17:12 +03:00
contact_domain = find_domain_from_name ( name_namespace ) ;
2019-07-19 18:10:09 +03:00
}
if ( contact_domain = = NULL ) {
DEBUG ( 3 , ( " Authentication for domain for [%s] -> [%s] \\ [%s] failed as %s is not a trusted domain \n " ,
state - > request - > data . auth . user , name_domain , name_user , name_namespace ) ) ;
result = NT_STATUS_NO_SUCH_USER ;
goto done ;
2006-02-04 01:19:41 +03:00
}
2008-08-19 03:18:24 +04:00
if ( contact_domain - > initialized & &
2006-06-23 00:07:08 +04:00
contact_domain - > active_directory ) {
goto try_login ;
}
if ( ! contact_domain - > initialized ) {
2014-05-26 03:58:38 +04:00
init_dc_connection ( contact_domain , false ) ;
2006-06-23 00:07:08 +04:00
}
2006-02-04 01:19:41 +03:00
if ( ! contact_domain - > active_directory ) {
2019-07-19 18:10:09 +03:00
DEBUG ( 3 , ( " krb5 auth requested but domain (%s) is not Active Directory \n " ,
contact_domain - > name ) ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_INVALID_LOGON_TYPE ;
}
2006-06-23 00:07:08 +04:00
try_login :
2010-12-11 12:41:38 +03:00
result = winbindd_raw_kerberos_login (
state - > mem_ctx , contact_domain ,
state - > request - > data . auth . user ,
state - > request - > data . auth . pass ,
state - > request - > data . auth . krb5_cc_type ,
get_uid_from_request ( state - > request ) ,
2018-01-23 23:34:46 +03:00
info6 , state - > response - > data . auth . krb5ccname ) ;
2006-02-04 01:19:41 +03:00
done :
return result ;
}
2010-04-11 17:27:49 +04:00
static NTSTATUS winbindd_dual_auth_passdb ( TALLOC_CTX * mem_ctx ,
2012-02-19 04:15:38 +04:00
uint32_t logon_parameters ,
2019-02-01 03:49:49 +03:00
const char * domain ,
const char * user ,
const uint64_t logon_id ,
2019-01-28 05:31:46 +03:00
const char * client_name ,
const int client_pid ,
2010-04-11 17:27:49 +04:00
const DATA_BLOB * challenge ,
const DATA_BLOB * lm_resp ,
const DATA_BLOB * nt_resp ,
2019-01-28 05:31:46 +03:00
const struct tsocket_address * remote ,
const struct tsocket_address * local ,
2016-06-02 19:13:40 +03:00
bool interactive ,
2017-03-17 11:42:38 +03:00
uint8_t * pauthoritative ,
2010-04-11 17:27:49 +04:00
struct netr_SamInfo3 * * pinfo3 )
{
2014-03-27 03:58:05 +04:00
struct auth_context * auth_context ;
struct auth_serversupplied_info * server_info ;
2010-04-11 17:27:49 +04:00
struct auth_usersupplied_info * user_info = NULL ;
2014-03-27 03:58:05 +04:00
struct netr_SamInfo3 * info3 ;
2010-04-11 17:27:49 +04:00
NTSTATUS status ;
2017-03-13 10:14:00 +03:00
bool ok ;
2014-03-27 00:17:15 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-06-08 20:55:37 +04:00
2017-03-17 11:42:38 +03:00
/*
* We are authoritative by default
*/
* pauthoritative = 1 ;
2014-03-27 00:17:15 +04:00
status = make_user_info ( frame , & user_info , user , user , domain , domain ,
2019-01-28 05:31:46 +03:00
lp_netbios_name ( ) , remote , local ,
2017-02-20 04:52:07 +03:00
" winbind " ,
lm_resp , nt_resp , NULL , NULL ,
2010-06-01 15:52:01 +04:00
NULL , AUTH_PASSWORD_RESPONSE ) ;
2010-04-11 17:27:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " make_user_info failed: %s \n " , nt_errstr ( status ) ) ) ;
2014-03-27 00:17:15 +04:00
TALLOC_FREE ( frame ) ;
2010-04-11 17:27:49 +04:00
return status ;
}
2014-03-27 03:58:05 +04:00
2012-02-19 04:15:38 +04:00
user_info - > logon_parameters = logon_parameters ;
2019-02-01 03:49:49 +03:00
user_info - > logon_id = logon_id ;
2019-01-28 05:31:46 +03:00
user_info - > auth_description = talloc_asprintf (
frame , " PASSDB, %s, %d " , client_name , client_pid ) ;
if ( user_info - > auth_description = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
2010-04-11 17:27:49 +04:00
2014-03-27 03:58:05 +04:00
/* We don't want to come back to winbindd or to do PAM account checks */
2017-03-21 10:31:29 +03:00
user_info - > flags | = USER_INFO_INFO3_AND_NO_AUTHZ ;
2014-03-27 03:58:05 +04:00
2016-06-02 19:13:40 +03:00
if ( interactive ) {
user_info - > flags | = USER_INFO_INTERACTIVE_LOGON ;
}
2017-03-17 11:18:41 +03:00
status = make_auth3_context_for_winbind ( frame , & auth_context ) ;
2014-03-27 03:58:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2017-03-17 11:18:41 +03:00
DBG_ERR ( " make_auth3_context_for_winbind failed: %s \n " ,
2017-02-27 16:35:59 +03:00
nt_errstr ( status ) ) ;
2014-03-27 03:58:05 +04:00
TALLOC_FREE ( frame ) ;
return status ;
}
2017-03-13 10:14:00 +03:00
ok = auth3_context_set_challenge ( auth_context ,
challenge - > data , " fixed " ) ;
if ( ! ok ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-03-27 03:58:05 +04:00
status = auth_check_ntlm_password ( mem_ctx ,
auth_context ,
user_info ,
2017-03-17 11:43:59 +03:00
& server_info ,
pauthoritative ) ;
2014-03-27 03:58:05 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return status ;
}
info3 = talloc_zero ( mem_ctx , struct netr_SamInfo3 ) ;
if ( info3 = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
status = serverinfo_to_SamInfo3 ( server_info , info3 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
TALLOC_FREE ( info3 ) ;
DEBUG ( 0 , ( " serverinfo_to_SamInfo3 failed: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
* pinfo3 = info3 ;
2021-04-13 16:42:37 +03:00
DBG_DEBUG ( " Authenticating user %s \\ %s returned %s \n " ,
domain ,
user ,
nt_errstr ( status ) ) ;
2014-03-27 00:17:15 +04:00
TALLOC_FREE ( frame ) ;
2010-11-27 20:56:41 +03:00
return status ;
2010-04-11 17:27:49 +04:00
}
2011-01-24 22:52:24 +03:00
static NTSTATUS winbind_samlogon_retry_loop ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
uint32_t logon_parameters ,
const char * username ,
2014-07-15 10:29:55 +04:00
const char * password ,
2011-01-24 22:52:24 +03:00
const char * domainname ,
const char * workstation ,
2019-02-01 03:49:49 +03:00
const uint64_t logon_id ,
2018-01-23 18:36:45 +03:00
bool plaintext_given ,
2011-01-24 22:52:24 +03:00
const uint8_t chal [ 8 ] ,
DATA_BLOB lm_response ,
DATA_BLOB nt_response ,
2014-07-15 10:29:55 +04:00
bool interactive ,
2017-01-28 23:20:59 +03:00
uint8_t * authoritative ,
uint32_t * flags ,
2017-12-12 01:26:38 +03:00
uint16_t * _validation_level ,
union netr_Validation * * _validation )
2011-01-24 22:52:24 +03:00
{
int attempts = 0 ;
2012-11-09 18:33:09 +04:00
int netr_attempts = 0 ;
2011-01-24 22:52:24 +03:00
bool retry = false ;
NTSTATUS result ;
2018-01-15 14:02:05 +03:00
enum netr_LogonInfoClass logon_type_i ;
enum netr_LogonInfoClass logon_type_n ;
2018-01-17 16:45:49 +03:00
uint16_t validation_level = UINT16_MAX ;
2017-12-01 01:35:40 +03:00
union netr_Validation * validation = NULL ;
winbindd_pam: add NT4 DC handling into winbind_samlogon_retry_loop()
Handle the case where a NT4 DC does not fill in the acct_flags in
the samlogon reply info3. Yes, in 2021, there are still admins
arround with real NT4 DCs.
NT4 DCs reject authentication with workstation accounts with
NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, even if
MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified.
We no longer call dcerpc_samr_QueryUserInfo(level=16)
to get the acct_flags, as we only ever got
ACB_NORMAL back (maybe with ACB_PWNOEXP in addition),
which is easy to calculate on our own.
This was removed in commit (for 4.15.0rc1):
commit 73528f26eea24033a7093e5591b8f89ad2b8644e
Author: Ralph Boehme <slow@samba.org>
AuthorDate: Mon Jan 11 14:59:46 2021 +0100
Commit: Jeremy Allison <jra@samba.org>
CommitDate: Thu Jan 21 22:56:20 2021 +0000
winbind: remove legacy flags fallback
Some very old NT4 DCs might have not returned the account flags filled in. This
shouldn't be a problem anymore. Additionally, on a typical domain member server,
this request is (and can only be) send to the primary domain, so this will not
work with accounts from trusted domains.
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Jan 21 22:56:20 UTC 2021 on sn-devel-184
It means one more caller of the problematic cm_connect_sam()
function is removed! SAMR connections may not be allowed for
machine accounts with modern AD DCs.
For network logons NT4 DCs also skip the
account_name, so we have to fallback to the
one given by the client. We have code to cope
with that deeply hidden inside of netsamlogon_cache_store().
Up to Samba 4.7 netsamlogon_cache_store() operated on the
info3 structure that was passed to the caller of winbind_dual_SamLogon()
and pass propagated up to auth_winbind in smbd.
But for Samba 4.8 the following commit:
commit f153c95176b7759e10996b24b66d9917945372ed
Author: Ralph Boehme <slow@samba.org>
Date: Mon Dec 11 16:25:35 2017 +0100
winbindd: let winbind_dual_SamLogon return validation
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
actually changed the situation and only a temporary info3 structure
was passed into netsamlogon_cache_store(), which means
account_name was NULL and get propagated as "" into auth_winbind
in smbd, where getpwnam() is no longer possible and every
smb access gets NT_STATUS_LOGON_FAILURE.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14772
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Tue Aug 3 11:10:27 UTC 2021 on sn-devel-184
2021-08-02 15:17:47 +03:00
TALLOC_CTX * base_ctx = NULL ;
struct netr_SamBaseInfo * base_info = NULL ;
2011-01-24 22:52:24 +03:00
do {
struct rpc_pipe_client * netlogon_pipe ;
2018-02-02 17:24:00 +03:00
struct netlogon_creds_cli_context * netlogon_creds_ctx = NULL ;
2011-01-24 22:52:24 +03:00
retry = false ;
2018-02-02 17:24:00 +03:00
result = cm_connect_netlogon_secure ( domain , & netlogon_pipe ,
& netlogon_creds_ctx ) ;
2011-01-24 22:52:24 +03:00
2017-03-02 13:28:18 +03:00
if ( NT_STATUS_EQUAL ( result ,
NT_STATUS_CANT_ACCESS_DOMAIN_INFO ) ) {
/*
* This means we don ' t have a trust account .
*/
* authoritative = 0 ;
result = NT_STATUS_NO_SUCH_USER ;
break ;
}
2011-01-24 22:52:24 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2012-11-09 18:33:09 +04:00
DEBUG ( 3 , ( " Could not open handle to NETLOGON pipe "
" (error: %s, attempts: %d) \n " ,
nt_errstr ( result ) , netr_attempts ) ) ;
/* After the first retry always close the connection */
if ( netr_attempts > 0 ) {
DEBUG ( 3 , ( " This is again a problem for this "
" particular call, forcing the close "
" of this connection \n " ) ) ;
2014-09-23 21:35:21 +04:00
invalidate_cm_connection ( domain ) ;
2012-11-09 18:33:09 +04:00
}
/* After the second retry failover to the next DC */
if ( netr_attempts > 1 ) {
/*
* If the netlogon server is not reachable then
* it is possible that the DC is rebuilding
* sysvol and shutdown netlogon for that time .
* We should failover to the next dc .
*/
DEBUG ( 3 , ( " This is the third problem for this "
" particular call, adding DC to the "
2017-04-04 03:21:34 +03:00
" negative cache list: %s %s \n " , domain - > name , domain - > dcname ) ) ;
2012-11-09 18:33:09 +04:00
add_failed_connection_entry ( domain - > name ,
domain - > dcname ,
result ) ;
saf_delete ( domain - > name ) ;
}
/* Only allow 3 retries */
if ( netr_attempts < 3 ) {
DEBUG ( 3 , ( " The connection to netlogon "
" failed, retrying \n " ) ) ;
netr_attempts + + ;
retry = true ;
continue ;
2012-02-25 04:13:10 +04:00
}
2011-01-24 22:52:24 +03:00
return result ;
}
2018-01-15 14:02:05 +03:00
logon_type_i = NetlogonInteractiveInformation ;
logon_type_n = NetlogonNetworkInformation ;
if ( domain - > domain_trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST ) {
logon_type_i = NetlogonInteractiveTransitiveInformation ;
logon_type_n = NetlogonNetworkTransitiveInformation ;
}
if ( domain - > domain_trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE ) {
logon_type_i = NetlogonInteractiveTransitiveInformation ;
logon_type_n = NetlogonNetworkTransitiveInformation ;
}
if ( domain - > domain_trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE ) {
logon_type_i = NetlogonInteractiveInformation ;
logon_type_n = NetlogonNetworkInformation ;
}
if ( domain - > domain_trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN ) {
logon_type_i = NetlogonInteractiveInformation ;
logon_type_n = NetlogonNetworkInformation ;
}
2012-11-09 18:33:09 +04:00
netr_attempts = 0 ;
2018-02-02 17:24:00 +03:00
if ( plaintext_given ) {
2017-12-01 09:59:50 +03:00
result = rpccli_netlogon_password_logon (
2018-02-02 17:24:00 +03:00
netlogon_creds_ctx ,
2017-12-01 09:59:50 +03:00
netlogon_pipe - > binding_handle ,
mem_ctx ,
logon_parameters ,
domainname ,
username ,
password ,
workstation ,
2019-02-01 03:49:49 +03:00
logon_id ,
2018-01-15 14:02:05 +03:00
logon_type_i ,
2017-12-01 09:59:50 +03:00
authoritative ,
flags ,
2017-12-01 01:35:40 +03:00
& validation_level ,
& validation ) ;
2018-01-23 18:36:45 +03:00
} else if ( interactive ) {
result = rpccli_netlogon_interactive_logon (
2018-02-02 17:24:00 +03:00
netlogon_creds_ctx ,
2018-01-23 18:36:45 +03:00
netlogon_pipe - > binding_handle ,
mem_ctx ,
logon_parameters ,
username ,
domainname ,
workstation ,
2019-02-01 03:49:49 +03:00
logon_id ,
2018-01-23 18:36:45 +03:00
lm_response ,
nt_response ,
logon_type_i ,
authoritative ,
flags ,
& validation_level ,
& validation ) ;
2014-07-15 10:29:55 +04:00
} else {
2017-12-01 09:59:50 +03:00
result = rpccli_netlogon_network_logon (
2018-02-02 17:24:00 +03:00
netlogon_creds_ctx ,
2017-12-01 09:59:50 +03:00
netlogon_pipe - > binding_handle ,
mem_ctx ,
logon_parameters ,
username ,
domainname ,
workstation ,
2019-02-01 03:49:49 +03:00
logon_id ,
2017-12-01 09:59:50 +03:00
chal ,
lm_response ,
nt_response ,
2018-01-15 14:02:05 +03:00
logon_type_n ,
2017-12-01 09:59:50 +03:00
authoritative ,
flags ,
2017-12-01 01:35:40 +03:00
& validation_level ,
& validation ) ;
2014-07-15 10:29:55 +04:00
}
2011-01-07 19:28:29 +03:00
/*
* we increment this after the " feature negotiation "
* for can_do_samlogon_ex and can_do_validation6
*/
attempts + = 1 ;
2011-01-24 22:52:24 +03:00
/* We have to try a second time as cm_connect_netlogon
might not yet have noticed that the DC has killed
our connection . */
if ( ! rpccli_is_connected ( netlogon_pipe ) ) {
retry = true ;
continue ;
}
/* if we get access denied, a possible cause was that we had
2017-12-21 20:14:38 +03:00
an open connection to the DC , but someone changed our
2011-01-24 22:52:24 +03:00
machine account password out from underneath us using ' net
rpc changetrustpw ' */
if ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED ) ) {
2015-10-11 03:58:59 +03:00
DEBUG ( 1 , ( " winbind_samlogon_retry_loop: sam_logon returned "
" ACCESS_DENIED. Maybe the DC has Restrict "
" NTLM set or the trust account "
2011-01-24 22:52:24 +03:00
" password was changed and we didn't know it. "
" Killing connections to domain %s \n " ,
domainname ) ) ;
2014-09-23 21:35:21 +04:00
invalidate_cm_connection ( domain ) ;
2011-01-24 22:52:24 +03:00
retry = true ;
}
2013-07-27 13:30:13 +04:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ) ) {
/*
* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
* ( no Ex ) . This happens against old Samba
* DCs , if LogonSamLogonEx ( ) fails with an error
* e . g . NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD .
*
* The server will log something like this :
* api_net_sam_logon_ex : Failed to marshall NET_R_SAM_LOGON_EX .
*
* This sets the whole connection into a fault_state mode
* and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE .
*
* This also happens to our retry with LogonSamLogonWithFlags ( )
* and LogonSamLogon ( ) .
*
* In order to recover from this situation , we need to
* drop the connection .
*/
2014-09-23 21:35:21 +04:00
invalidate_cm_connection ( domain ) ;
2013-07-27 13:30:13 +04:00
result = NT_STATUS_LOGON_FAILURE ;
break ;
}
2011-01-24 22:52:24 +03:00
} while ( ( attempts < 2 ) & & retry ) ;
2012-02-25 04:13:10 +04:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_IO_TIMEOUT ) ) {
DEBUG ( 3 , ( " winbind_samlogon_retry_loop: sam_network_logon(ex) "
2017-04-04 03:21:34 +03:00
" returned NT_STATUS_IO_TIMEOUT after the retry. "
2012-02-25 04:13:10 +04:00
" Killing connections to domain %s \n " ,
domainname ) ) ;
2014-09-23 21:35:21 +04:00
invalidate_cm_connection ( domain ) ;
2012-02-25 04:13:10 +04:00
}
2017-12-01 01:35:40 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
winbindd_pam: add NT4 DC handling into winbind_samlogon_retry_loop()
Handle the case where a NT4 DC does not fill in the acct_flags in
the samlogon reply info3. Yes, in 2021, there are still admins
arround with real NT4 DCs.
NT4 DCs reject authentication with workstation accounts with
NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, even if
MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified.
We no longer call dcerpc_samr_QueryUserInfo(level=16)
to get the acct_flags, as we only ever got
ACB_NORMAL back (maybe with ACB_PWNOEXP in addition),
which is easy to calculate on our own.
This was removed in commit (for 4.15.0rc1):
commit 73528f26eea24033a7093e5591b8f89ad2b8644e
Author: Ralph Boehme <slow@samba.org>
AuthorDate: Mon Jan 11 14:59:46 2021 +0100
Commit: Jeremy Allison <jra@samba.org>
CommitDate: Thu Jan 21 22:56:20 2021 +0000
winbind: remove legacy flags fallback
Some very old NT4 DCs might have not returned the account flags filled in. This
shouldn't be a problem anymore. Additionally, on a typical domain member server,
this request is (and can only be) send to the primary domain, so this will not
work with accounts from trusted domains.
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Jan 21 22:56:20 UTC 2021 on sn-devel-184
It means one more caller of the problematic cm_connect_sam()
function is removed! SAMR connections may not be allowed for
machine accounts with modern AD DCs.
For network logons NT4 DCs also skip the
account_name, so we have to fallback to the
one given by the client. We have code to cope
with that deeply hidden inside of netsamlogon_cache_store().
Up to Samba 4.7 netsamlogon_cache_store() operated on the
info3 structure that was passed to the caller of winbind_dual_SamLogon()
and pass propagated up to auth_winbind in smbd.
But for Samba 4.8 the following commit:
commit f153c95176b7759e10996b24b66d9917945372ed
Author: Ralph Boehme <slow@samba.org>
Date: Mon Dec 11 16:25:35 2017 +0100
winbindd: let winbind_dual_SamLogon return validation
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
actually changed the situation and only a temporary info3 structure
was passed into netsamlogon_cache_store(), which means
account_name was NULL and get propagated as "" into auth_winbind
in smbd, where getpwnam() is no longer possible and every
smb access gets NT_STATUS_LOGON_FAILURE.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14772
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Tue Aug 3 11:10:27 UTC 2021 on sn-devel-184
2021-08-02 15:17:47 +03:00
switch ( validation_level ) {
case 3 :
base_ctx = validation - > sam3 ;
base_info = & validation - > sam3 - > base ;
break ;
case 6 :
base_ctx = validation - > sam6 ;
base_info = & validation - > sam6 - > base ;
break ;
default :
smb_panic ( __location__ ) ;
}
if ( base_info - > acct_flags = = 0 | | base_info - > account_name . string = = NULL ) {
struct dom_sid user_sid ;
struct dom_sid_buf sid_buf ;
const char * acct_flags_src = " server " ;
const char * acct_name_src = " server " ;
/*
* Handle the case where a NT4 DC does not fill in the acct_flags in
* the samlogon reply info3 . Yes , in 2021 , there are still admins
* arround with real NT4 DCs .
*
* We used to call dcerpc_samr_QueryUserInfo ( level = 16 ) to fetch
* acct_flags , but as NT4 DCs reject authentication with workstation
* accounts with NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT , even if
* MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified , we only ever got
* ACB_NORMAL back ( maybe with ACB_PWNOEXP in addition ) .
*
* For network logons NT4 DCs also skip the
* account_name , so we have to fallback to the
* one given by the client .
*/
if ( base_info - > acct_flags = = 0 ) {
base_info - > acct_flags = ACB_NORMAL ;
if ( base_info - > force_password_change = = NTTIME_MAX ) {
base_info - > acct_flags | = ACB_PWNOEXP ;
}
acct_flags_src = " calculated " ;
}
if ( base_info - > account_name . string = = NULL ) {
base_info - > account_name . string = talloc_strdup ( base_ctx ,
username ) ;
if ( base_info - > account_name . string = = NULL ) {
TALLOC_FREE ( validation ) ;
return NT_STATUS_NO_MEMORY ;
}
acct_name_src = " client " ;
}
sid_compose ( & user_sid , base_info - > domain_sid , base_info - > rid ) ;
DBG_DEBUG ( " Fallback to %s_acct_flags[0x%x] %s_acct_name[%s] for %s \n " ,
acct_flags_src ,
base_info - > acct_flags ,
acct_name_src ,
base_info - > account_name . string ,
dom_sid_str_buf ( & user_sid , & sid_buf ) ) ;
}
2017-12-12 01:26:38 +03:00
* _validation_level = validation_level ;
* _validation = validation ;
2017-12-01 01:35:40 +03:00
return NT_STATUS_OK ;
2011-01-24 22:52:24 +03:00
}
2008-07-04 09:53:42 +04:00
2020-01-03 17:39:34 +03:00
static NTSTATUS nt_dual_auth_passdb ( TALLOC_CTX * mem_ctx ,
fstring name_user ,
fstring name_domain ,
const char * pass ,
uint64_t logon_id ,
const char * client_name ,
const int client_pid ,
const struct tsocket_address * remote ,
const struct tsocket_address * local ,
uint8_t * authoritative ,
struct netr_SamInfo3 * * info3 )
{
unsigned char local_nt_response [ 24 ] ;
uchar chal [ 8 ] ;
DATA_BLOB chal_blob ;
DATA_BLOB lm_resp ;
DATA_BLOB nt_resp ;
/* do password magic */
generate_random_buffer ( chal , sizeof ( chal ) ) ;
chal_blob = data_blob_const ( chal , sizeof ( chal ) ) ;
if ( lp_client_ntlmv2_auth ( ) ) {
DATA_BLOB server_chal ;
DATA_BLOB names_blob ;
server_chal = data_blob_const ( chal , 8 ) ;
/* note that the 'workgroup' here is for the local
machine . The ' server name ' must match the
' workstation ' passed to the actual SamLogon call .
*/
names_blob = NTLMv2_generate_names_blob ( mem_ctx ,
lp_netbios_name ( ) ,
lp_workgroup ( ) ) ;
if ( ! SMBNTLMv2encrypt ( mem_ctx , name_user , name_domain ,
pass , & server_chal , & names_blob ,
& lm_resp , & nt_resp , NULL , NULL ) ) {
data_blob_free ( & names_blob ) ;
DEBUG ( 0 , ( " SMBNTLMv2encrypt() failed! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
data_blob_free ( & names_blob ) ;
} else {
int rc ;
lm_resp = data_blob_null ;
rc = SMBNTencrypt ( pass , chal , local_nt_response ) ;
if ( rc ! = 0 ) {
DEBUG ( 0 , ( " SMBNTencrypt() failed! \n " ) ) ;
return gnutls_error_to_ntstatus ( rc ,
NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ) ;
}
nt_resp = data_blob_talloc ( mem_ctx , local_nt_response ,
sizeof ( local_nt_response ) ) ;
}
return winbindd_dual_auth_passdb ( talloc_tos ( ) , 0 , name_domain ,
name_user , logon_id , client_name ,
client_pid , & chal_blob , & lm_resp ,
& nt_resp , remote , local ,
true , /* interactive */
authoritative , info3 ) ;
}
2017-12-01 10:26:59 +03:00
static NTSTATUS winbindd_dual_pam_auth_samlogon (
TALLOC_CTX * mem_ctx ,
struct winbindd_domain * domain ,
const char * user ,
const char * pass ,
2019-02-01 03:49:49 +03:00
uint64_t logon_id ,
2019-01-28 05:31:46 +03:00
const char * client_name ,
const int client_pid ,
2017-12-01 10:26:59 +03:00
uint32_t request_flags ,
2019-01-28 05:31:46 +03:00
const struct tsocket_address * remote ,
const struct tsocket_address * local ,
2017-12-11 17:54:36 +03:00
uint16_t * _validation_level ,
union netr_Validation * * _validation )
2006-02-04 01:19:41 +03:00
{
2018-04-26 13:17:12 +03:00
fstring name_namespace , name_domain , name_user ;
2006-02-04 01:19:41 +03:00
NTSTATUS result ;
2021-10-04 18:29:34 +03:00
uint8_t authoritative = 1 ;
2017-01-28 23:20:59 +03:00
uint32_t flags = 0 ;
2020-01-03 14:42:03 +03:00
uint16_t validation_level = 0 ;
2017-12-12 01:26:38 +03:00
union netr_Validation * validation = NULL ;
2018-04-26 13:17:12 +03:00
bool ok ;
2002-08-17 21:00:51 +04:00
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth_samlogon \n " ) ) ;
2008-08-19 03:18:24 +04:00
2000-05-09 15:43:00 +04:00
/* Parse domain and username */
2008-08-19 03:18:24 +04:00
2018-04-26 13:17:12 +03:00
ok = parse_domain_user ( user , name_namespace , name_domain , name_user ) ;
if ( ! ok ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2000-05-09 15:43:00 +04:00
2017-04-03 01:19:48 +03:00
/*
* We check against domain - > name instead of
* name_domain , as find_auth_domain ( ) - >
* find_domain_from_name_noinit ( ) already decided
* that we are in a child for the correct domain .
*
* name_domain can also be lp_realm ( )
* we need to check against domain - > name .
*/
if ( strequal ( domain - > name , get_global_sam_name ( ) ) ) {
2017-12-11 17:54:36 +03:00
struct netr_SamInfo3 * info3 = NULL ;
2008-08-19 03:18:24 +04:00
2020-01-03 17:39:34 +03:00
result = nt_dual_auth_passdb ( mem_ctx , name_user , name_domain ,
pass , logon_id , client_name ,
client_pid , remote , local ,
& authoritative , & info3 ) ;
2014-06-30 04:04:03 +04:00
2017-12-01 12:32:41 +03:00
/*
2017-03-17 11:42:38 +03:00
* We need to try the remote NETLOGON server if this is
2017-02-21 02:14:12 +03:00
* not authoritative ( for example on the RODC ) .
2014-06-30 04:04:03 +04:00
*/
2017-03-17 11:42:38 +03:00
if ( authoritative ! = 0 ) {
2021-01-11 16:59:46 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
result = map_info3_to_validation ( mem_ctx ,
info3 ,
& validation_level ,
& validation ) ;
TALLOC_FREE ( info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
2018-01-11 11:23:05 +03:00
}
2014-06-30 04:04:03 +04:00
goto done ;
}
2010-04-11 17:27:49 +04:00
}
2003-06-30 21:24:59 +04:00
/* check authentication loop */
2011-01-24 22:52:24 +03:00
result = winbind_samlogon_retry_loop ( domain ,
2010-12-11 13:54:18 +03:00
mem_ctx ,
2011-01-24 22:52:24 +03:00
0 ,
name_user ,
2014-07-15 10:29:55 +04:00
pass ,
2011-01-24 22:52:24 +03:00
name_domain ,
2011-06-09 09:31:03 +04:00
lp_netbios_name ( ) ,
2019-02-01 03:49:49 +03:00
logon_id ,
2018-01-23 18:36:45 +03:00
true , /* plaintext_given */
2017-02-21 02:14:12 +03:00
NULL ,
data_blob_null , data_blob_null ,
2014-07-15 10:29:55 +04:00
true , /* interactive */
2017-01-28 23:20:59 +03:00
& authoritative ,
& flags ,
2017-12-12 01:26:38 +03:00
& validation_level ,
& validation ) ;
2011-01-24 22:52:24 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2021-01-11 16:59:46 +03:00
return result ;
2007-02-13 18:56:09 +03:00
}
2006-02-04 01:19:41 +03:00
done :
2021-01-11 16:59:46 +03:00
* _validation_level = validation_level ;
* _validation = validation ;
return NT_STATUS_OK ;
2006-02-04 01:19:41 +03:00
}
2019-01-28 05:31:46 +03:00
/*
* @ brief build a tsocket_address for the remote address of the supplied socket
*
*/
static struct tsocket_address * get_remote_address ( TALLOC_CTX * mem_ctx , int sock )
{
struct sockaddr_storage st = { 0 } ;
struct sockaddr * sar = ( struct sockaddr * ) & st ;
socklen_t sa_len = sizeof ( st ) ;
struct tsocket_address * remote = NULL ;
int ret = 0 ;
ret = getpeername ( sock , sar , & sa_len ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " getpeername failed - %s " , strerror ( errno ) ) ;
return NULL ;
}
ret = tsocket_address_bsd_from_sockaddr ( mem_ctx , sar , sa_len , & remote ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " tsocket_address_bsd_from_sockaddr failed - %s " ,
strerror ( errno ) ) ;
return NULL ;
}
return remote ;
}
/*
* @ brief build a tsocket_address for the local address of the supplied socket
*
*/
static struct tsocket_address * get_local_address ( TALLOC_CTX * mem_ctx , int sock )
{
struct sockaddr_storage st = { 0 } ;
struct sockaddr * sar = ( struct sockaddr * ) & st ;
socklen_t sa_len = sizeof ( st ) ;
struct tsocket_address * local = NULL ;
int ret = 0 ;
ret = getsockname ( sock , sar , & sa_len ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " getsockname failed - %s " , strerror ( errno ) ) ;
return NULL ;
}
ret = tsocket_address_bsd_from_sockaddr ( mem_ctx , sar , sa_len , & local ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " tsocket_address_bsd_from_sockaddr failed - %s " ,
strerror ( errno ) ) ;
return NULL ;
}
return local ;
}
/*
* @ brief generate an authentication message in the logs .
*
*/
static void log_authentication (
TALLOC_CTX * mem_ctx ,
const struct winbindd_domain * domain ,
const struct winbindd_cli_state * state ,
const struct timeval start_time ,
const uint64_t logon_id ,
const char * command ,
const char * user_name ,
const char * domain_name ,
const char * workstation ,
const DATA_BLOB lm_resp ,
const DATA_BLOB nt_resp ,
const struct tsocket_address * remote ,
const struct tsocket_address * local ,
NTSTATUS result )
{
struct auth_usersupplied_info * ui = NULL ;
struct dom_sid * sid = NULL ;
struct loadparm_context * lp_ctx = NULL ;
struct imessaging_context * msg_ctx = NULL ;
ui = talloc_zero ( mem_ctx , struct auth_usersupplied_info ) ;
ui - > logon_id = logon_id ;
ui - > service_description = " winbind " ;
ui - > password . response . nt . length = nt_resp . length ;
ui - > password . response . nt . data = nt_resp . data ;
ui - > password . response . lanman . length = lm_resp . length ;
ui - > password . response . lanman . data = lm_resp . data ;
if ( nt_resp . length = = 0 & & lm_resp . length = = 0 ) {
ui - > password_state = AUTH_PASSWORD_PLAIN ;
} else {
ui - > password_state = AUTH_PASSWORD_RESPONSE ;
}
/*
* In the event of a failure ui - > auth_description will be null ,
* the logging code handles this correctly so it can be ignored .
*/
ui - > auth_description = talloc_asprintf (
ui ,
" %s, %s, %d " ,
command ,
state - > request - > client_name ,
state - > pid ) ;
if ( ui - > auth_description = = NULL ) {
DBG_ERR ( " OOM Unable to create auth_description " ) ;
}
ui - > client . account_name = user_name ;
ui - > client . domain_name = domain_name ;
ui - > workstation_name = workstation ;
ui - > remote_host = remote ;
ui - > local_host = local ;
sid = dom_sid_parse_talloc (
ui , state - > response - > data . auth . info3 . dom_sid ) ;
if ( sid ! = NULL ) {
sid_append_rid ( sid , state - > response - > data . auth . info3 . user_rid ) ;
}
if ( lp_auth_event_notification ( ) ) {
lp_ctx = loadparm_init_s3 ( ui , loadparm_s3_helpers ( ) ) ;
msg_ctx = imessaging_client_init (
ui , lp_ctx , global_event_context ( ) ) ;
}
log_authentication_event (
msg_ctx ,
lp_ctx ,
& start_time ,
ui ,
result ,
state - > response - > data . auth . info3 . logon_dom ,
state - > response - > data . auth . info3 . user_name ,
sid ) ;
TALLOC_FREE ( ui ) ;
}
2006-02-04 01:19:41 +03:00
enum winbindd_result winbindd_dual_pam_auth ( struct winbindd_domain * domain ,
2008-08-19 03:18:24 +04:00
struct winbindd_cli_state * state )
2006-02-04 01:19:41 +03:00
{
NTSTATUS result = NT_STATUS_LOGON_FAILURE ;
2008-08-19 03:18:24 +04:00
NTSTATUS krb5_result = NT_STATUS_OK ;
2018-04-26 13:17:12 +03:00
fstring name_namespace , name_domain , name_user ;
2008-09-16 00:50:15 +04:00
char * mapped_user ;
fstring domain_user ;
2018-01-17 16:42:31 +03:00
uint16_t validation_level = UINT16_MAX ;
2017-12-02 12:27:12 +03:00
union netr_Validation * validation = NULL ;
2008-09-16 00:50:15 +04:00
NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL ;
2018-04-26 13:17:12 +03:00
bool ok ;
2019-02-01 03:49:49 +03:00
uint64_t logon_id = 0 ;
2019-01-28 05:31:46 +03:00
const struct timeval start_time = timeval_current ( ) ;
const struct tsocket_address * remote = NULL ;
const struct tsocket_address * local = NULL ;
2008-02-17 04:08:12 +03:00
2006-02-04 01:19:41 +03:00
/* Ensure null termination */
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user [ sizeof ( state - > request - > data . auth . user ) - 1 ] = ' \0 ' ;
2006-02-04 01:19:41 +03:00
/* Ensure null termination */
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . pass [ sizeof ( state - > request - > data . auth . pass ) - 1 ] = ' \0 ' ;
2006-02-04 01:19:41 +03:00
2019-02-01 03:49:49 +03:00
/*
* Generate a logon_id for this session .
*/
logon_id = generate_random_u64 ( ) ;
2019-01-28 05:31:46 +03:00
remote = get_remote_address ( state - > mem_ctx , state - > sock ) ;
local = get_local_address ( state - > mem_ctx , state - > sock ) ;
2006-02-04 01:19:41 +03:00
DEBUG ( 3 , ( " [%5lu]: dual pam auth %s \n " , ( unsigned long ) state - > pid ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ) ) ;
2006-02-04 01:19:41 +03:00
/* Parse domain and username */
2008-08-19 03:18:24 +04:00
2008-09-16 00:50:15 +04:00
name_map_status = normalize_name_unmap ( state - > mem_ctx ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
2008-09-16 00:50:15 +04:00
& mapped_user ) ;
2007-03-16 20:54:10 +03:00
2019-08-29 22:58:27 +03:00
/* If the name normalization didn't actually do anything,
2008-09-16 00:50:15 +04:00
just use the original name */
if ( ! NT_STATUS_IS_OK ( name_map_status ) & &
! NT_STATUS_EQUAL ( name_map_status , NT_STATUS_FILE_RENAMED ) )
{
2009-05-08 00:46:27 +04:00
mapped_user = state - > request - > data . auth . user ;
2008-09-16 00:50:15 +04:00
}
2018-04-26 13:17:12 +03:00
ok = parse_domain_user ( mapped_user ,
name_namespace ,
name_domain ,
name_user ) ;
if ( ! ok ) {
result = NT_STATUS_INVALID_PARAMETER ;
goto process_result ;
}
2008-09-16 00:50:15 +04:00
2009-05-08 00:46:27 +04:00
if ( mapped_user ! = state - > request - > data . auth . user ) {
2010-07-30 00:47:27 +04:00
fstr_sprintf ( domain_user , " %s%c%s " , name_domain ,
* lp_winbind_separator ( ) ,
name_user ) ;
2011-05-04 00:10:01 +04:00
strlcpy ( state - > request - > data . auth . user , domain_user ,
sizeof ( state - > request - > data . auth . user ) ) ;
2008-09-16 00:50:15 +04:00
}
2006-02-04 01:19:41 +03:00
2010-09-08 17:29:32 +04:00
if ( ! domain - > online ) {
2006-12-15 09:06:15 +03:00
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ;
if ( domain - > startup ) {
/* Logons are very important to users. If we're offline and
we get a request within the first 30 seconds of startup ,
try very hard to find a DC and go online . */
DEBUG ( 10 , ( " winbindd_dual_pam_auth: domain: %s offline and auth "
" request in startup mode. \n " , domain - > name ) ) ;
winbindd_flush_negative_conn_cache ( domain ) ;
2014-05-26 03:58:38 +04:00
result = init_dc_connection ( domain , false ) ;
2006-12-15 09:06:15 +03:00
}
2006-09-15 18:05:28 +04:00
}
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth: domain: %s last was %s \n " , domain - > name , domain - > online ? " online " : " offline " ) ) ;
/* Check for Kerberos authentication */
2009-05-08 00:46:27 +04:00
if ( domain - > online & & ( state - > request - > flags & WBFLAG_PAM_KRB5 ) ) {
2018-01-23 23:34:46 +03:00
struct netr_SamInfo6 * info6 = NULL ;
2008-08-19 03:18:24 +04:00
2018-01-23 23:34:46 +03:00
result = winbindd_dual_pam_auth_kerberos ( domain , state , & info6 ) ;
2007-05-07 00:33:33 +04:00
/* save for later */
krb5_result = result ;
2008-08-19 03:18:24 +04:00
2006-02-04 01:19:41 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_kerberos succeeded \n " ) ) ;
2017-12-02 12:27:12 +03:00
2018-01-23 23:34:46 +03:00
result = map_info6_to_validation ( state - > mem_ctx ,
info6 ,
2017-12-02 12:27:12 +03:00
& validation_level ,
& validation ) ;
2018-01-23 23:34:46 +03:00
TALLOC_FREE ( info6 ) ;
2017-12-02 12:27:12 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2018-01-23 23:34:46 +03:00
DBG_ERR ( " map_info6_to_validation failed \n " ) ;
2017-12-02 12:27:12 +03:00
goto done ;
}
2006-02-04 01:19:41 +03:00
goto process_result ;
}
2017-12-01 13:40:47 +03:00
DBG_DEBUG ( " winbindd_dual_pam_auth_kerberos failed: %s \n " ,
nt_errstr ( result ) ) ;
2006-04-25 12:42:34 +04:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NO_LOGON_SERVERS ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_IO_TIMEOUT ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth_kerberos setting domain to offline \n " ) ) ;
2007-05-07 01:26:01 +04:00
set_domain_offline ( domain ) ;
2008-08-19 03:18:24 +04:00
goto cached_logon ;
2006-02-04 01:19:41 +03:00
}
2006-03-17 01:17:03 +03:00
/* there are quite some NT_STATUS errors where there is no
* point in retrying with a samlogon , we explictly have to take
* care not to increase the bad logon counter on the DC */
if ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCOUNT_DISABLED ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_ACCOUNT_EXPIRED ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_ACCOUNT_LOCKED_OUT ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_INVALID_LOGON_HOURS ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_INVALID_WORKSTATION ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_LOGON_FAILURE ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_NO_SUCH_USER ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_PASSWORD_EXPIRED ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_PASSWORD_MUST_CHANGE ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_WRONG_PASSWORD ) ) {
2010-02-17 21:00:01 +03:00
goto done ;
2006-03-17 01:17:03 +03:00
}
2008-08-19 03:18:24 +04:00
2009-05-08 00:46:27 +04:00
if ( state - > request - > flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5 ) {
2006-02-04 01:19:41 +03:00
DEBUG ( 3 , ( " falling back to samlogon \n " ) ) ;
goto sam_logon ;
} else {
goto cached_logon ;
}
}
sam_logon :
/* Check for Samlogon authentication */
if ( domain - > online ) {
2017-12-11 17:54:36 +03:00
struct netr_SamBaseInfo * base_info = NULL ;
2010-12-11 13:54:18 +03:00
result = winbindd_dual_pam_auth_samlogon (
state - > mem_ctx , domain ,
state - > request - > data . auth . user ,
state - > request - > data . auth . pass ,
2019-02-01 03:49:49 +03:00
logon_id ,
2019-01-28 05:31:46 +03:00
state - > request - > client_name ,
state - > pid ,
2010-12-11 13:54:18 +03:00
state - > request - > flags ,
2019-01-28 05:31:46 +03:00
remote ,
local ,
2017-12-11 17:54:36 +03:00
& validation_level ,
& validation ) ;
2008-08-19 03:18:24 +04:00
2006-02-04 01:19:41 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " winbindd_dual_pam_auth_samlogon succeeded \n " ) ) ;
2017-12-11 17:54:36 +03:00
switch ( validation_level ) {
case 3 :
base_info = & validation - > sam3 - > base ;
break ;
case 6 :
base_info = & validation - > sam6 - > base ;
break ;
default :
DBG_ERR ( " Bad validation level %d \n " ,
validation_level ) ;
result = NT_STATUS_INTERNAL_ERROR ;
goto done ;
}
2007-05-07 00:33:33 +04:00
/* add the Krb5 err if we have one */
if ( NT_STATUS_EQUAL ( krb5_result , NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
2017-12-11 17:54:36 +03:00
base_info - > user_flags | = LOGON_KRB5_FAIL_CLOCK_SKEW ;
}
2006-02-04 01:19:41 +03:00
goto process_result ;
2008-08-19 03:18:24 +04:00
}
2007-05-07 01:26:01 +04:00
2008-08-19 03:18:24 +04:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth_samlogon failed: %s \n " ,
2007-05-07 01:26:01 +04:00
nt_errstr ( result ) ) ) ;
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NO_LOGON_SERVERS ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_IO_TIMEOUT ) | |
2008-08-19 03:18:24 +04:00
NT_STATUS_EQUAL ( result , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) )
2007-05-07 01:26:01 +04:00
{
DEBUG ( 10 , ( " winbindd_dual_pam_auth_samlogon setting domain to offline \n " ) ) ;
set_domain_offline ( domain ) ;
2008-08-19 03:18:24 +04:00
goto cached_logon ;
2007-05-07 01:26:01 +04:00
}
2017-07-12 15:32:02 +03:00
if ( domain - > online ) {
/* We're still online - fail. */
goto done ;
}
2006-02-04 01:19:41 +03:00
}
cached_logon :
/* Check for Cached logons */
2009-05-08 00:46:27 +04:00
if ( ! domain - > online & & ( state - > request - > flags & WBFLAG_PAM_CACHED_LOGIN ) & &
2006-02-04 01:19:41 +03:00
lp_winbind_offline_logon ( ) ) {
2017-12-02 12:27:12 +03:00
struct netr_SamInfo3 * info3 = NULL ;
2008-08-19 03:18:24 +04:00
2006-02-04 01:19:41 +03:00
result = winbindd_dual_pam_auth_cached ( domain , state , & info3 ) ;
2018-01-09 20:57:53 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached failed: %s \n " , nt_errstr ( result ) ) ) ;
goto done ;
}
2018-01-09 20:57:53 +03:00
DEBUG ( 10 , ( " winbindd_dual_pam_auth_cached succeeded \n " ) ) ;
2017-12-02 12:27:12 +03:00
result = map_info3_to_validation ( state - > mem_ctx ,
info3 ,
& validation_level ,
& validation ) ;
TALLOC_FREE ( info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DBG_ERR ( " map_info3_to_validation failed \n " ) ;
goto done ;
}
2006-02-04 01:19:41 +03:00
}
process_result :
2003-07-03 20:23:11 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
2010-05-21 05:25:01 +04:00
struct dom_sid user_sid ;
2017-12-02 12:27:12 +03:00
TALLOC_CTX * base_ctx = NULL ;
struct netr_SamBaseInfo * base_info = NULL ;
struct netr_SamInfo3 * info3 = NULL ;
2006-02-07 20:55:17 +03:00
2017-12-02 12:27:12 +03:00
switch ( validation_level ) {
case 3 :
base_ctx = validation - > sam3 ;
base_info = & validation - > sam3 - > base ;
break ;
case 6 :
base_ctx = validation - > sam6 ;
base_info = & validation - > sam6 - > base ;
break ;
default :
2006-03-13 04:08:27 +03:00
result = NT_STATUS_INTERNAL_ERROR ;
goto done ;
}
2017-12-02 12:27:12 +03:00
sid_compose ( & user_sid , base_info - > domain_sid , base_info - > rid ) ;
2010-12-11 16:27:54 +03:00
2017-12-02 12:27:12 +03:00
if ( base_info - > full_name . string = = NULL ) {
2014-07-07 19:16:32 +04:00
struct netr_SamInfo3 * cached_info3 ;
cached_info3 = netsamlogon_cache_get ( state - > mem_ctx ,
& user_sid ) ;
if ( cached_info3 ! = NULL & &
cached_info3 - > base . full_name . string ! = NULL ) {
2017-12-02 12:27:12 +03:00
base_info - > full_name . string = talloc_strdup (
base_ctx ,
cached_info3 - > base . full_name . string ) ;
if ( base_info - > full_name . string = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2014-07-07 19:16:32 +04:00
} else {
2015-07-27 00:02:57 +03:00
/* this might fail so we don't check the return code */
2014-07-07 19:16:32 +04:00
wcache_query_user_fullname ( domain ,
2017-12-02 12:27:12 +03:00
base_ctx ,
2014-07-07 19:16:32 +04:00
& user_sid ,
2017-12-02 12:27:12 +03:00
& base_info - > full_name . string ) ;
2014-07-07 19:16:32 +04:00
}
}
2017-12-02 12:27:12 +03:00
result = map_validation_to_info3 ( talloc_tos ( ) ,
validation_level ,
validation ,
& info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2010-12-11 16:27:54 +03:00
wcache_invalidate_samlogon ( find_domain_from_name ( name_domain ) ,
& user_sid ) ;
2008-08-28 04:29:10 +04:00
netsamlogon_cache_store ( name_user , info3 ) ;
2005-11-10 23:28:23 +03:00
2007-05-07 01:26:01 +04:00
/* save name_to_sid info as early as possible (only if
this is our primary domain so we don ' t invalidate
the cache entry by storing the seq_num for the wrong
domain ) . */
2008-08-19 03:18:24 +04:00
if ( domain - > primary ) {
cache_name2sid ( domain , name_domain , name_user ,
2007-05-07 01:26:01 +04:00
SID_NAME_USER , & user_sid ) ;
}
2008-08-19 03:18:24 +04:00
2004-04-06 20:44:24 +04:00
/* Check if the user is in the right group */
2009-09-27 14:47:24 +04:00
result = check_info3_in_group (
info3 ,
state - > request - > data . auth . require_membership_of_sid ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2004-04-06 20:44:24 +04:00
DEBUG ( 3 , ( " User %s is not in the required group (%s), so plaintext authentication is rejected \n " ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
state - > request - > data . auth . require_membership_of_sid ) ) ;
2006-02-04 01:19:41 +03:00
goto done ;
2004-04-06 20:44:24 +04:00
}
2021-01-11 18:50:31 +03:00
if ( ! is_allowed_domain ( info3 - > base . logon_domain . string ) ) {
DBG_NOTICE ( " Authentication failed for user [%s] "
" from firewalled domain [%s] \n " ,
info3 - > base . account_name . string ,
info3 - > base . logon_domain . string ) ;
result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED ;
goto done ;
}
2010-11-16 19:58:10 +03:00
result = append_auth_data ( state - > mem_ctx , state - > response ,
2017-12-02 12:27:12 +03:00
state - > request - > flags ,
validation_level ,
validation ,
2010-11-16 19:07:33 +03:00
name_domain , name_user ) ;
2007-08-20 19:53:56 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
2006-02-04 01:19:41 +03:00
}
2005-09-30 21:13:37 +04:00
2010-09-09 06:01:11 +04:00
if ( ( state - > request - > flags & WBFLAG_PAM_CACHED_LOGIN )
& & lp_winbind_offline_logon ( ) ) {
2006-08-26 06:53:45 +04:00
2010-09-09 06:01:11 +04:00
result = winbindd_store_creds ( domain ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
state - > request - > data . auth . pass ,
2010-09-09 03:58:21 +04:00
info3 ) ;
2006-02-04 01:19:41 +03:00
}
2009-05-08 00:46:27 +04:00
if ( state - > request - > flags & WBFLAG_PAM_GET_PWD_POLICY ) {
2017-04-04 10:24:11 +03:00
/*
* WBFLAG_PAM_GET_PWD_POLICY is not used within
* any Samba caller anymore .
*
* We just fake this based on the effective values
* for the user , for legacy callers .
*/
fake_password_policy ( state - > response , & info3 - > base ) ;
2006-08-26 06:53:45 +04:00
}
2006-09-05 09:28:31 +04:00
2008-08-19 03:18:24 +04:00
result = NT_STATUS_OK ;
2006-09-05 09:28:31 +04:00
}
2006-02-04 01:19:41 +03:00
done :
2003-04-07 11:32:51 +04:00
/* give us a more useful (more correct?) error code */
2005-09-30 21:13:37 +04:00
if ( ( NT_STATUS_EQUAL ( result , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) | |
2006-02-04 01:19:41 +03:00
( NT_STATUS_EQUAL ( result , NT_STATUS_UNSUCCESSFUL ) ) ) ) {
2003-04-07 11:32:51 +04:00
result = NT_STATUS_NO_LOGON_SERVERS ;
}
2008-08-19 03:18:24 +04:00
2021-10-04 18:29:34 +03:00
/*
* Here we don ' t alter
* state - > response - > data . auth . authoritative based
* on the servers response
* as we don ' t want a fallback to the local sam
* for interactive PAM logons
*/
2009-06-14 14:41:46 +04:00
set_auth_errors ( state - > response , result ) ;
2002-02-05 12:40:36 +03:00
2008-08-19 03:18:24 +04:00
DEBUG ( NT_STATUS_IS_OK ( result ) ? 5 : 2 , ( " Plain-text authentication for user %s returned %s (PAM: %d) \n " ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ,
2009-06-14 14:41:46 +04:00
state - > response - > data . auth . nt_status_string ,
state - > response - > data . auth . pam_error ) ) ;
2002-02-05 12:40:36 +03:00
2019-01-28 05:31:46 +03:00
/*
* Log the winbind pam authentication , the logon_id will tie this to
* any of the logons invoked from this request .
*/
log_authentication (
state - > mem_ctx ,
domain ,
state ,
start_time ,
logon_id ,
" PAM_AUTH " ,
name_user ,
name_domain ,
NULL ,
data_blob_null ,
data_blob_null ,
remote ,
local ,
result ) ;
2001-09-04 11:13:01 +04:00
return NT_STATUS_IS_OK ( result ) ? WINBINDD_OK : WINBINDD_ERROR ;
2001-08-22 06:48:16 +04:00
}
2003-06-30 21:24:59 +04:00
2014-05-08 08:49:13 +04:00
NTSTATUS winbind_dual_SamLogon ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
2018-01-23 19:37:54 +03:00
bool interactive ,
2014-05-08 08:49:13 +04:00
uint32_t logon_parameters ,
const char * name_user ,
const char * name_domain ,
const char * workstation ,
2019-02-01 03:49:49 +03:00
const uint64_t logon_id ,
2019-01-28 05:31:46 +03:00
const char * client_name ,
const int client_pid ,
2014-05-08 08:49:13 +04:00
const uint8_t chal [ 8 ] ,
DATA_BLOB lm_response ,
DATA_BLOB nt_response ,
2019-01-28 05:31:46 +03:00
const struct tsocket_address * remote ,
const struct tsocket_address * local ,
2017-01-28 23:20:59 +03:00
uint8_t * authoritative ,
2017-04-12 05:12:32 +03:00
bool skip_sam ,
2017-01-28 23:20:59 +03:00
uint32_t * flags ,
2017-12-11 18:25:35 +03:00
uint16_t * _validation_level ,
union netr_Validation * * _validation )
2014-05-08 08:49:13 +04:00
{
2018-05-16 13:10:29 +03:00
uint16_t validation_level = 0 ;
2017-12-12 01:26:38 +03:00
union netr_Validation * validation = NULL ;
2014-05-08 08:49:13 +04:00
NTSTATUS result ;
2017-04-03 01:19:48 +03:00
/*
* We check against domain - > name instead of
* name_domain , as find_auth_domain ( ) - >
* find_domain_from_name_noinit ( ) already decided
* that we are in a child for the correct domain .
*
* name_domain can also be lp_realm ( )
* we need to check against domain - > name .
*/
2017-04-12 05:12:32 +03:00
if ( ! skip_sam & & strequal ( domain - > name , get_global_sam_name ( ) ) ) {
2014-05-08 08:49:13 +04:00
DATA_BLOB chal_blob = data_blob_const (
chal , 8 ) ;
2017-12-11 18:25:35 +03:00
struct netr_SamInfo3 * info3 = NULL ;
2014-05-08 08:49:13 +04:00
result = winbindd_dual_auth_passdb (
2017-12-11 18:25:35 +03:00
talloc_tos ( ) ,
2014-05-08 08:49:13 +04:00
logon_parameters ,
name_domain , name_user ,
2019-02-01 03:49:49 +03:00
logon_id ,
2019-01-28 05:31:46 +03:00
client_name ,
client_pid ,
2016-06-02 19:13:40 +03:00
& chal_blob , & lm_response , & nt_response ,
2019-01-28 05:31:46 +03:00
remote ,
local ,
2018-01-23 19:37:54 +03:00
interactive ,
2017-03-17 11:42:38 +03:00
authoritative ,
2017-12-11 18:25:35 +03:00
& info3 ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
result = map_info3_to_validation ( mem_ctx ,
info3 ,
& validation_level ,
& validation ) ;
TALLOC_FREE ( info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
}
2014-06-30 04:04:03 +04:00
2017-12-02 01:11:44 +03:00
/*
2017-03-17 11:42:38 +03:00
* We need to try the remote NETLOGON server if this is
* not authoritative .
2014-06-30 04:04:03 +04:00
*/
2017-03-17 11:42:38 +03:00
if ( * authoritative ! = 0 ) {
2017-01-28 23:20:59 +03:00
* flags = 0 ;
2014-06-30 04:04:03 +04:00
goto process_result ;
}
2014-05-08 08:49:13 +04:00
}
result = winbind_samlogon_retry_loop ( domain ,
mem_ctx ,
logon_parameters ,
name_user ,
2014-07-15 10:29:55 +04:00
NULL , /* password */
2014-05-08 08:49:13 +04:00
name_domain ,
/* Bug #3248 - found by Stefan Burkei. */
workstation , /* We carefully set this above so use it... */
2019-02-01 03:49:49 +03:00
logon_id ,
2018-01-23 18:36:45 +03:00
false , /* plaintext_given */
2014-05-08 08:49:13 +04:00
chal ,
lm_response ,
nt_response ,
2018-01-23 19:37:54 +03:00
interactive ,
2017-01-28 23:20:59 +03:00
authoritative ,
flags ,
2017-12-12 01:26:38 +03:00
& validation_level ,
& validation ) ;
2014-05-08 08:49:13 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
process_result :
if ( NT_STATUS_IS_OK ( result ) ) {
struct dom_sid user_sid ;
2017-12-11 18:25:35 +03:00
TALLOC_CTX * base_ctx = NULL ;
struct netr_SamBaseInfo * base_info = NULL ;
struct netr_SamInfo3 * info3 = NULL ;
switch ( validation_level ) {
case 3 :
base_ctx = validation - > sam3 ;
base_info = & validation - > sam3 - > base ;
break ;
case 6 :
base_ctx = validation - > sam6 ;
base_info = & validation - > sam6 - > base ;
break ;
default :
result = NT_STATUS_INTERNAL_ERROR ;
goto done ;
}
2014-05-08 08:49:13 +04:00
2017-12-11 18:25:35 +03:00
sid_compose ( & user_sid , base_info - > domain_sid , base_info - > rid ) ;
2014-07-07 19:16:32 +04:00
2017-12-11 18:25:35 +03:00
if ( base_info - > full_name . string = = NULL ) {
2014-07-07 19:16:32 +04:00
struct netr_SamInfo3 * cached_info3 ;
cached_info3 = netsamlogon_cache_get ( mem_ctx ,
& user_sid ) ;
if ( cached_info3 ! = NULL & &
2017-12-11 18:25:35 +03:00
cached_info3 - > base . full_name . string ! = NULL )
{
base_info - > full_name . string = talloc_strdup (
base_ctx ,
cached_info3 - > base . full_name . string ) ;
2014-07-07 19:16:32 +04:00
} else {
2015-07-27 00:02:57 +03:00
/* this might fail so we don't check the return code */
2014-07-07 19:16:32 +04:00
wcache_query_user_fullname ( domain ,
2017-12-11 18:25:35 +03:00
base_ctx ,
2014-07-07 19:16:32 +04:00
& user_sid ,
2017-12-11 18:25:35 +03:00
& base_info - > full_name . string ) ;
2014-07-07 19:16:32 +04:00
}
}
2017-12-11 18:25:35 +03:00
result = map_validation_to_info3 ( talloc_tos ( ) ,
validation_level ,
validation ,
& info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2014-05-08 08:49:13 +04:00
wcache_invalidate_samlogon ( find_domain_from_name ( name_domain ) ,
& user_sid ) ;
2017-12-11 18:25:35 +03:00
netsamlogon_cache_store ( name_user , info3 ) ;
TALLOC_FREE ( info3 ) ;
2014-05-08 08:49:13 +04:00
}
done :
/* give us a more useful (more correct?) error code */
if ( ( NT_STATUS_EQUAL ( result , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) | |
( NT_STATUS_EQUAL ( result , NT_STATUS_UNSUCCESSFUL ) ) ) ) {
result = NT_STATUS_NO_LOGON_SERVERS ;
}
DEBUG ( NT_STATUS_IS_OK ( result ) ? 5 : 2 ,
( " NTLM CRAP authentication for user [%s] \\ [%s] returned %s \n " ,
name_domain ,
name_user ,
nt_errstr ( result ) ) ) ;
2017-12-11 18:25:35 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
* _validation_level = validation_level ;
* _validation = validation ;
return NT_STATUS_OK ;
2014-05-08 08:49:13 +04:00
}
2005-06-09 02:10:34 +04:00
enum winbindd_result winbindd_dual_pam_auth_crap ( struct winbindd_domain * domain ,
2008-08-19 03:18:24 +04:00
struct winbindd_cli_state * state )
2005-06-09 02:10:34 +04:00
{
NTSTATUS result ;
2004-10-01 07:28:39 +04:00
const char * name_user = NULL ;
2004-01-05 07:10:28 +03:00
const char * name_domain = NULL ;
2002-11-13 02:20:50 +03:00
const char * workstation ;
2019-02-01 03:49:49 +03:00
uint64_t logon_id = 0 ;
2021-10-04 18:29:34 +03:00
uint8_t authoritative = 1 ;
2017-06-08 18:10:12 +03:00
uint32_t flags = 0 ;
2017-12-11 18:25:35 +03:00
uint16_t validation_level ;
union netr_Validation * validation = NULL ;
2019-07-31 12:40:20 +03:00
DATA_BLOB lm_resp = { 0 } , nt_resp = { 0 } ;
2019-01-28 05:31:46 +03:00
const struct timeval start_time = timeval_current ( ) ;
const struct tsocket_address * remote = NULL ;
const struct tsocket_address * local = NULL ;
2002-01-01 07:50:45 +03:00
2005-06-09 02:10:34 +04:00
/* This is child-only, so no check for privileged access is needed
anymore */
2003-03-24 12:54:13 +03:00
2002-08-17 21:00:51 +04:00
/* Ensure null termination */
2009-05-08 00:46:27 +04:00
state - > request - > data . auth_crap . user [ sizeof ( state - > request - > data . auth_crap . user ) - 1 ] = 0 ;
state - > request - > data . auth_crap . domain [ sizeof ( state - > request - > data . auth_crap . domain ) - 1 ] = 0 ;
2001-08-22 06:48:16 +04:00
2009-05-08 00:46:27 +04:00
name_user = state - > request - > data . auth_crap . user ;
2010-09-09 05:07:31 +04:00
name_domain = state - > request - > data . auth_crap . domain ;
2010-09-09 05:09:07 +04:00
workstation = state - > request - > data . auth_crap . workstation ;
2019-02-01 03:49:49 +03:00
logon_id = generate_random_u64 ( ) ;
2019-01-28 05:31:46 +03:00
remote = get_remote_address ( state - > mem_ctx , state - > sock ) ;
local = get_local_address ( state - > mem_ctx , state - > sock ) ;
2002-01-18 05:37:55 +03:00
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " [%5lu]: pam auth crap domain: %s user: %s \n " , ( unsigned long ) state - > pid ,
2004-01-05 07:10:28 +03:00
name_domain , name_user ) ) ;
2008-08-19 03:18:24 +04:00
2009-05-08 00:46:27 +04:00
if ( state - > request - > data . auth_crap . lm_resp_len > sizeof ( state - > request - > data . auth_crap . lm_resp )
| | state - > request - > data . auth_crap . nt_resp_len > sizeof ( state - > request - > data . auth_crap . nt_resp ) ) {
if ( ! ( state - > request - > flags & WBFLAG_BIG_NTLMV2_BLOB ) | |
state - > request - > extra_len ! = state - > request - > data . auth_crap . nt_resp_len ) {
2008-11-07 11:13:26 +03:00
DEBUG ( 0 , ( " winbindd_pam_auth_crap: invalid password length %u/%u \n " ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth_crap . lm_resp_len ,
state - > request - > data . auth_crap . nt_resp_len ) ) ;
2008-11-07 11:13:26 +03:00
result = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
2002-01-18 05:37:55 +03:00
}
2009-05-08 00:46:27 +04:00
lm_resp = data_blob_talloc ( state - > mem_ctx , state - > request - > data . auth_crap . lm_resp ,
state - > request - > data . auth_crap . lm_resp_len ) ;
2008-11-07 11:13:26 +03:00
2009-05-08 00:46:27 +04:00
if ( state - > request - > flags & WBFLAG_BIG_NTLMV2_BLOB ) {
2008-11-07 11:13:26 +03:00
nt_resp = data_blob_talloc ( state - > mem_ctx ,
2009-05-08 00:46:27 +04:00
state - > request - > extra_data . data ,
state - > request - > data . auth_crap . nt_resp_len ) ;
2008-11-07 11:13:26 +03:00
} else {
nt_resp = data_blob_talloc ( state - > mem_ctx ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth_crap . nt_resp ,
state - > request - > data . auth_crap . nt_resp_len ) ;
2008-11-07 11:13:26 +03:00
}
2004-01-05 07:10:28 +03:00
2014-05-08 08:49:13 +04:00
result = winbind_dual_SamLogon ( domain ,
state - > mem_ctx ,
2018-01-23 19:37:54 +03:00
false , /* interactive */
2014-05-08 08:49:13 +04:00
state - > request - > data . auth_crap . logon_parameters ,
name_user ,
name_domain ,
/* Bug #3248 - found by Stefan Burkei. */
workstation , /* We carefully set this above so use it... */
2019-02-01 03:49:49 +03:00
logon_id ,
2019-01-28 05:31:46 +03:00
state - > request - > client_name ,
state - > request - > pid ,
2014-05-08 08:49:13 +04:00
state - > request - > data . auth_crap . chal ,
lm_resp ,
nt_resp ,
2019-01-28 05:31:46 +03:00
remote ,
local ,
2017-01-28 23:20:59 +03:00
& authoritative ,
2017-04-12 05:12:32 +03:00
false ,
2017-01-28 23:20:59 +03:00
& flags ,
2017-12-11 18:25:35 +03:00
& validation_level ,
& validation ) ;
2011-01-24 22:52:24 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2001-10-05 04:20:06 +04:00
2002-02-05 12:40:36 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
2017-12-11 18:25:35 +03:00
struct netr_SamInfo3 * info3 = NULL ;
result = map_validation_to_info3 ( state - > mem_ctx ,
validation_level ,
validation ,
& info3 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2005-11-10 23:28:23 +03:00
2017-12-11 18:25:35 +03:00
/* Check if the user is in the right group */
2009-09-27 14:47:24 +04:00
result = check_info3_in_group (
info3 ,
state - > request - > data . auth_crap . require_membership_of_sid ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2007-05-07 15:04:38 +04:00
DEBUG ( 3 , ( " User %s is not in the required group (%s), so "
" crap authentication is rejected \n " ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth_crap . user ,
state - > request - > data . auth_crap . require_membership_of_sid ) ) ;
2004-04-06 20:44:24 +04:00
goto done ;
}
2021-01-11 19:10:19 +03:00
if ( ! is_allowed_domain ( info3 - > base . logon_domain . string ) ) {
DBG_NOTICE ( " Authentication failed for user [%s] "
" from firewalled domain [%s] \n " ,
info3 - > base . account_name . string ,
info3 - > base . logon_domain . string ) ;
result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED ;
goto done ;
}
2010-11-16 19:58:10 +03:00
result = append_auth_data ( state - > mem_ctx , state - > response ,
2017-12-02 12:27:12 +03:00
state - > request - > flags ,
validation_level ,
validation ,
2010-11-16 19:07:33 +03:00
name_domain , name_user ) ;
2007-08-20 19:53:56 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
2002-08-17 21:00:51 +04:00
}
2002-02-05 12:40:36 +03:00
}
2002-01-01 07:50:45 +03:00
done :
2005-09-30 21:13:37 +04:00
2009-05-08 00:46:27 +04:00
if ( state - > request - > flags & WBFLAG_PAM_NT_STATUS_SQUASH ) {
2004-04-06 20:44:24 +04:00
result = nt_status_squash ( result ) ;
}
2005-09-30 21:13:37 +04:00
2009-06-14 14:41:46 +04:00
set_auth_errors ( state - > response , result ) ;
2021-10-04 18:29:34 +03:00
state - > response - > data . auth . authoritative = authoritative ;
2019-01-28 05:31:46 +03:00
/*
* Log the winbind pam authentication , the logon_id will tie this to
* any of the logons invoked from this request .
*/
log_authentication (
state - > mem_ctx ,
domain ,
state ,
start_time ,
logon_id ,
" NTLM_AUTH " ,
name_user ,
name_domain ,
workstation ,
lm_resp ,
nt_resp ,
remote ,
local ,
result ) ;
2002-02-05 12:40:36 +03:00
2001-09-04 11:13:01 +04:00
return NT_STATUS_IS_OK ( result ) ? WINBINDD_OK : WINBINDD_ERROR ;
2000-05-09 15:43:00 +04:00
}
2006-12-19 20:35:47 +03:00
enum winbindd_result winbindd_dual_pam_chauthtok ( struct winbindd_domain * contact_domain ,
struct winbindd_cli_state * state )
{
char * oldpass ;
char * newpass = NULL ;
2009-03-19 00:49:41 +03:00
struct policy_handle dom_pol ;
2010-07-06 19:02:33 +04:00
struct rpc_pipe_client * cli = NULL ;
2008-08-19 20:03:13 +04:00
bool got_info = false ;
2008-02-05 22:14:54 +03:00
struct samr_DomInfo1 * info = NULL ;
2009-09-26 00:44:00 +04:00
struct userPwdChangeFailureInformation * reject = NULL ;
2006-12-19 20:35:47 +03:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2018-04-26 13:17:12 +03:00
fstring namespace , domain , user ;
2011-01-18 15:56:26 +03:00
struct dcerpc_binding_handle * b = NULL ;
2018-04-26 13:17:12 +03:00
bool ok ;
2006-12-19 20:35:47 +03:00
2010-07-06 19:02:33 +04:00
ZERO_STRUCT ( dom_pol ) ;
2006-12-19 20:35:47 +03:00
DEBUG ( 3 , ( " [%5lu]: dual pam chauthtok %s \n " , ( unsigned long ) state - > pid ,
2009-05-08 00:46:27 +04:00
state - > request - > data . auth . user ) ) ;
2006-12-19 20:35:47 +03:00
2018-04-26 13:17:12 +03:00
ok = parse_domain_user ( state - > request - > data . chauthtok . user ,
namespace ,
domain ,
user ) ;
if ( ! ok ) {
2002-02-05 12:40:36 +03:00
goto done ;
}
2001-05-07 08:32:40 +04:00
2021-01-11 19:59:48 +03:00
if ( ! is_allowed_domain ( domain ) ) {
DBG_NOTICE ( " Authentication failed for user [%s] "
" from firewalled domain [%s] \n " ,
user , domain ) ;
result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED ;
goto done ;
}
2002-01-30 06:23:40 +03:00
/* Change password */
2009-05-08 00:46:27 +04:00
oldpass = state - > request - > data . chauthtok . oldpass ;
newpass = state - > request - > data . chauthtok . newpass ;
2001-05-07 08:32:40 +04:00
2006-05-02 23:22:39 +04:00
/* Initialize reject reason */
2009-06-14 14:41:46 +04:00
state - > response - > data . auth . reject_reason = Undefined ;
2006-05-02 23:22:39 +04:00
2002-01-30 06:23:40 +03:00
/* Get sam handle */
2001-05-07 08:32:40 +04:00
2014-05-26 03:58:38 +04:00
result = cm_connect_sam ( contact_domain , state - > mem_ctx , true , & cli ,
2005-06-09 02:10:34 +04:00
& dom_pol ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2002-02-05 12:40:36 +03:00
DEBUG ( 1 , ( " could not get SAM handle on DC for %s \n " , domain ) ) ;
goto done ;
}
2001-05-07 08:32:40 +04:00
2011-01-18 15:56:26 +03:00
b = cli - > binding_handle ;
2008-06-25 23:49:57 +04:00
result = rpccli_samr_chgpasswd_user3 ( cli , state - > mem_ctx ,
user ,
newpass ,
oldpass ,
& info ,
& reject ) ;
2006-02-04 01:19:41 +03:00
2007-01-19 17:54:05 +03:00
/* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2006-02-04 01:19:41 +03:00
2007-01-19 17:54:05 +03:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_PASSWORD_RESTRICTION ) ) {
2008-08-19 20:31:10 +04:00
2009-06-14 14:41:46 +04:00
fill_in_password_policy ( state - > response , info ) ;
2008-02-05 22:14:54 +03:00
2009-06-14 14:41:46 +04:00
state - > response - > data . auth . reject_reason =
2009-09-26 00:44:00 +04:00
reject - > extendedFailureReason ;
2006-02-04 01:19:41 +03:00
2008-08-19 20:03:13 +04:00
got_info = true ;
2007-01-19 17:54:05 +03:00
}
2006-03-17 17:18:05 +03:00
2008-11-13 19:19:11 +03:00
/* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
* return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
* returns with 4 byte error code ( NT_STATUS_NOT_SUPPORTED ) which is too
* short to comply with the samr_ChangePasswordUser3 idl - gd */
2008-06-25 12:35:59 +04:00
/* only fallback when the chgpasswd_user3 call is not supported */
2011-04-24 02:00:40 +04:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_NOT_SUPPORTED ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_BUFFER_TOO_SMALL ) | |
NT_STATUS_EQUAL ( result , NT_STATUS_NOT_IMPLEMENTED ) ) {
2006-02-04 01:19:41 +03:00
2008-06-25 23:49:57 +04:00
DEBUG ( 10 , ( " Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2 \n " ,
2006-02-04 01:19:41 +03:00
nt_errstr ( result ) ) ) ;
2008-08-19 03:18:24 +04:00
2008-06-25 12:35:59 +04:00
result = rpccli_samr_chgpasswd_user2 ( cli , state - > mem_ctx , user , newpass , oldpass ) ;
2007-01-19 17:54:05 +03:00
/* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
Map to the same status code as Windows 2003. */
if ( NT_STATUS_EQUAL ( NT_STATUS_ACCOUNT_RESTRICTION , result ) ) {
2008-08-19 03:18:24 +04:00
result = NT_STATUS_PASSWORD_RESTRICTION ;
2007-01-19 17:54:05 +03:00
}
2006-02-04 01:19:41 +03:00
}
2008-08-19 03:18:24 +04:00
done :
2006-02-04 01:19:41 +03:00
2010-09-11 20:24:54 +04:00
if ( NT_STATUS_IS_OK ( result )
& & ( state - > request - > flags & WBFLAG_PAM_CACHED_LOGIN )
& & lp_winbind_offline_logon ( ) ) {
result = winbindd_update_creds_by_name ( contact_domain , user ,
newpass ) ;
/* Again, this happens when we login from gdm or xdm
* and the password expires , * BUT * cached crendentials
* doesn ' t exist . winbindd_update_creds_by_name ( )
* returns NT_STATUS_NO_SUCH_USER .
* This is not a failure .
* - - - BoYang
* */
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NO_SUCH_USER ) ) {
result = NT_STATUS_OK ;
}
2008-07-07 22:26:16 +04:00
2010-09-11 20:24:54 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " Failed to store creds: %s \n " ,
nt_errstr ( result ) ) ) ;
goto process_result ;
2006-02-04 01:19:41 +03:00
}
2008-07-07 22:26:16 +04:00
}
2006-02-04 01:19:41 +03:00
2006-03-13 03:05:47 +03:00
if ( ! NT_STATUS_IS_OK ( result ) & & ! got_info & & contact_domain ) {
2006-02-04 01:19:41 +03:00
NTSTATUS policy_ret ;
2008-08-19 03:18:24 +04:00
2011-01-28 21:05:37 +03:00
policy_ret = fillup_password_policy (
contact_domain , state - > response ) ;
2006-02-04 01:19:41 +03:00
/* failure of this is non critical, it will just provide no
* additional information to the client why the change has
* failed - Guenther */
if ( ! NT_STATUS_IS_OK ( policy_ret ) ) {
DEBUG ( 10 , ( " Failed to get password policies: %s \n " , nt_errstr ( policy_ret ) ) ) ;
goto process_result ;
}
}
process_result :
2002-02-05 12:40:36 +03:00
2010-07-06 19:02:33 +04:00
if ( strequal ( contact_domain - > name , get_global_sam_name ( ) ) ) {
/* FIXME: internal rpc pipe does not cache handles yet */
2011-01-18 15:56:26 +03:00
if ( b ) {
2010-07-06 19:02:33 +04:00
if ( is_valid_policy_hnd ( & dom_pol ) ) {
2011-01-18 15:56:26 +03:00
NTSTATUS _result ;
dcerpc_samr_Close ( b , state - > mem_ctx , & dom_pol , & _result ) ;
2010-07-06 19:02:33 +04:00
}
TALLOC_FREE ( cli ) ;
}
}
2009-06-14 14:41:46 +04:00
set_auth_errors ( state - > response , result ) ;
2002-02-05 12:40:36 +03:00
2008-08-19 03:18:24 +04:00
DEBUG ( NT_STATUS_IS_OK ( result ) ? 5 : 2 ,
( " Password change for user [%s] \\ [%s] returned %s (PAM: %d) \n " ,
2002-10-26 06:20:59 +04:00
domain ,
user ,
2009-06-14 14:41:46 +04:00
state - > response - > data . auth . nt_status_string ,
state - > response - > data . auth . pam_error ) ) ;
2002-10-26 06:20:59 +04:00
2006-12-19 20:35:47 +03:00
return NT_STATUS_IS_OK ( result ) ? WINBINDD_OK : WINBINDD_ERROR ;
2001-05-07 08:32:40 +04:00
}
2006-02-04 01:19:41 +03:00
enum winbindd_result winbindd_dual_pam_logoff ( struct winbindd_domain * domain ,
2008-08-19 03:18:24 +04:00
struct winbindd_cli_state * state )
2006-02-04 01:19:41 +03:00
{
NTSTATUS result = NT_STATUS_NOT_SUPPORTED ;
DEBUG ( 3 , ( " [%5lu]: pam dual logoff %s \n " , ( unsigned long ) state - > pid ,
2009-05-08 00:46:27 +04:00
state - > request - > data . logoff . user ) ) ;
2006-02-04 01:19:41 +03:00
2009-05-08 00:46:27 +04:00
if ( ! ( state - > request - > flags & WBFLAG_PAM_KRB5 ) ) {
2006-02-04 01:19:41 +03:00
result = NT_STATUS_OK ;
goto process_result ;
}
2009-05-08 00:46:27 +04:00
if ( state - > request - > data . logoff . krb5ccname [ 0 ] = = ' \0 ' ) {
2006-09-06 14:59:39 +04:00
result = NT_STATUS_OK ;
goto process_result ;
}
2006-02-04 01:19:41 +03:00
# ifdef HAVE_KRB5
2008-08-19 03:18:24 +04:00
2016-03-09 15:43:09 +03:00
if ( state - > request - > data . logoff . uid = = ( uid_t ) - 1 ) {
2006-02-04 01:19:41 +03:00
DEBUG ( 0 , ( " winbindd_pam_logoff: invalid uid \n " ) ) ;
goto process_result ;
}
2006-08-26 06:53:45 +04:00
/* what we need here is to find the corresponding krb5 ccache name *we*
2007-02-26 12:53:35 +03:00
* created for a given username and destroy it */
2009-05-08 00:46:27 +04:00
if ( ! ccache_entry_exists ( state - > request - > data . logoff . user ) ) {
2007-02-26 12:53:35 +03:00
result = NT_STATUS_OK ;
DEBUG ( 10 , ( " winbindd_pam_logoff: no entry found. \n " ) ) ;
goto process_result ;
}
2009-05-08 00:46:27 +04:00
if ( ! ccache_entry_identical ( state - > request - > data . logoff . user ,
state - > request - > data . logoff . uid ,
state - > request - > data . logoff . krb5ccname ) ) {
2006-08-26 06:53:45 +04:00
DEBUG ( 0 , ( " winbindd_pam_logoff: cached entry differs. \n " ) ) ;
2006-02-04 01:19:41 +03:00
goto process_result ;
}
2009-05-08 00:46:27 +04:00
result = remove_ccache ( state - > request - > data . logoff . user ) ;
2006-12-14 19:34:24 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 0 , ( " winbindd_pam_logoff: failed to remove ccache: %s \n " ,
nt_errstr ( result ) ) ) ;
goto process_result ;
2006-02-04 01:19:41 +03:00
}
2012-08-21 22:24:58 +04:00
/*
* Remove any mlock ' ed memory creds in the child
* we might be using for krb5 ticket renewal .
*/
winbindd_delete_memory_creds ( state - > request - > data . logoff . user ) ;
2006-02-04 01:19:41 +03:00
# else
result = NT_STATUS_NOT_SUPPORTED ;
# endif
process_result :
2006-08-26 06:53:45 +04:00
2009-06-14 14:41:46 +04:00
set_auth_errors ( state - > response , result ) ;
2006-02-04 01:19:41 +03:00
return NT_STATUS_IS_OK ( result ) ? WINBINDD_OK : WINBINDD_ERROR ;
}
2006-07-13 13:29:25 +04:00
/* Change user password with auth crap*/
enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap ( struct winbindd_domain * domainSt , struct winbindd_cli_state * state )
{
NTSTATUS result ;
DATA_BLOB new_nt_password ;
DATA_BLOB old_nt_hash_enc ;
DATA_BLOB new_lm_password ;
DATA_BLOB old_lm_hash_enc ;
2018-04-26 13:17:12 +03:00
fstring namespace , domain , user ;
2009-03-19 00:49:41 +03:00
struct policy_handle dom_pol ;
2006-07-13 13:29:25 +04:00
struct winbindd_domain * contact_domain = domainSt ;
2010-07-06 19:02:33 +04:00
struct rpc_pipe_client * cli = NULL ;
2011-01-18 15:56:26 +03:00
struct dcerpc_binding_handle * b = NULL ;
2010-07-06 19:02:33 +04:00
ZERO_STRUCT ( dom_pol ) ;
2006-07-13 13:29:25 +04:00
/* Ensure null termination */
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . user [
sizeof ( state - > request - > data . chng_pswd_auth_crap . user ) - 1 ] = 0 ;
state - > request - > data . chng_pswd_auth_crap . domain [
sizeof ( state - > request - > data . chng_pswd_auth_crap . domain ) - 1 ] = 0 ;
2018-04-26 13:17:12 +03:00
domain [ 0 ] = ' \0 ' ;
namespace [ 0 ] = ' \0 ' ;
user [ 0 ] = ' \0 ' ;
2008-08-19 03:18:24 +04:00
2006-07-13 13:29:25 +04:00
DEBUG ( 3 , ( " [%5lu]: pam change pswd auth crap domain: %s user: %s \n " ,
( unsigned long ) state - > pid ,
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . domain ,
state - > request - > data . chng_pswd_auth_crap . user ) ) ;
2006-09-20 11:18:30 +04:00
if ( lp_winbind_offline_logon ( ) ) {
DEBUG ( 0 , ( " Refusing password change as winbind offline logons are enabled. " ) ) ;
DEBUGADD ( 0 , ( " Changing passwords here would risk inconsistent logons \n " ) ) ;
result = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
2009-05-08 00:46:27 +04:00
if ( * state - > request - > data . chng_pswd_auth_crap . domain ) {
fstrcpy ( domain , state - > request - > data . chng_pswd_auth_crap . domain ) ;
2006-07-13 13:29:25 +04:00
} else {
2018-04-26 13:17:12 +03:00
bool ok ;
ok = parse_domain_user ( state - > request - > data . chng_pswd_auth_crap . user ,
namespace ,
domain ,
user ) ;
if ( ! ok ) {
result = NT_STATUS_INVALID_PARAMETER ;
goto done ;
}
2006-07-13 13:29:25 +04:00
if ( ! * domain ) {
DEBUG ( 3 , ( " no domain specified with username (%s) - "
" failing auth \n " ,
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . user ) ) ;
2006-07-13 13:29:25 +04:00
result = NT_STATUS_NO_SUCH_USER ;
goto done ;
}
}
if ( ! * domain & & lp_winbind_use_default_domain ( ) ) {
2011-05-06 01:36:55 +04:00
fstrcpy ( domain , lp_workgroup ( ) ) ;
2006-07-13 13:29:25 +04:00
}
2021-01-11 19:19:05 +03:00
if ( ! is_allowed_domain ( domain ) ) {
DBG_NOTICE ( " Authentication failed for user [%s] "
" from firewalled domain [%s] \n " ,
state - > request - > data . chng_pswd_auth_crap . user ,
domain ) ;
result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED ;
goto done ;
}
2006-07-13 13:29:25 +04:00
if ( ! * user ) {
2009-05-08 00:46:27 +04:00
fstrcpy ( user , state - > request - > data . chng_pswd_auth_crap . user ) ;
2006-07-13 13:29:25 +04:00
}
DEBUG ( 3 , ( " [%5lu]: pam auth crap domain: %s user: %s \n " ,
( unsigned long ) state - > pid , domain , user ) ) ;
2008-08-19 03:18:24 +04:00
2006-07-13 13:29:25 +04:00
/* Change password */
2010-04-20 22:37:35 +04:00
new_nt_password = data_blob_const (
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . new_nt_pswd ,
state - > request - > data . chng_pswd_auth_crap . new_nt_pswd_len ) ;
2006-07-13 13:29:25 +04:00
2010-04-20 22:37:35 +04:00
old_nt_hash_enc = data_blob_const (
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . old_nt_hash_enc ,
state - > request - > data . chng_pswd_auth_crap . old_nt_hash_enc_len ) ;
2006-07-13 13:29:25 +04:00
2009-05-08 00:46:27 +04:00
if ( state - > request - > data . chng_pswd_auth_crap . new_lm_pswd_len > 0 ) {
2010-04-20 22:37:35 +04:00
new_lm_password = data_blob_const (
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . new_lm_pswd ,
state - > request - > data . chng_pswd_auth_crap . new_lm_pswd_len ) ;
2006-07-13 13:29:25 +04:00
2010-04-20 22:37:35 +04:00
old_lm_hash_enc = data_blob_const (
2009-05-08 00:46:27 +04:00
state - > request - > data . chng_pswd_auth_crap . old_lm_hash_enc ,
state - > request - > data . chng_pswd_auth_crap . old_lm_hash_enc_len ) ;
2006-07-13 13:29:25 +04:00
} else {
2012-04-19 17:38:25 +04:00
new_lm_password = data_blob_null ;
old_lm_hash_enc = data_blob_null ;
2006-07-13 13:29:25 +04:00
}
/* Get sam handle */
2014-05-26 03:58:38 +04:00
result = cm_connect_sam ( contact_domain , state - > mem_ctx , true , & cli , & dom_pol ) ;
2006-07-13 13:29:25 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 1 , ( " could not get SAM handle on DC for %s \n " , domain ) ) ;
goto done ;
}
2011-01-18 15:56:26 +03:00
b = cli - > binding_handle ;
2006-07-13 13:29:25 +04:00
result = rpccli_samr_chng_pswd_auth_crap (
cli , state - > mem_ctx , user , new_nt_password , old_nt_hash_enc ,
new_lm_password , old_lm_hash_enc ) ;
2008-08-19 03:18:24 +04:00
done :
2008-08-19 20:31:35 +04:00
2010-07-06 19:02:33 +04:00
if ( strequal ( contact_domain - > name , get_global_sam_name ( ) ) ) {
/* FIXME: internal rpc pipe does not cache handles yet */
2011-01-18 15:56:26 +03:00
if ( b ) {
2010-07-06 19:02:33 +04:00
if ( is_valid_policy_hnd ( & dom_pol ) ) {
2011-01-18 15:56:26 +03:00
NTSTATUS _result ;
dcerpc_samr_Close ( b , state - > mem_ctx , & dom_pol , & _result ) ;
2010-07-06 19:02:33 +04:00
}
TALLOC_FREE ( cli ) ;
}
}
2009-06-14 14:41:46 +04:00
set_auth_errors ( state - > response , result ) ;
2006-07-13 13:29:25 +04:00
2008-08-19 03:18:24 +04:00
DEBUG ( NT_STATUS_IS_OK ( result ) ? 5 : 2 ,
( " Password change for user [%s] \\ [%s] returned %s (PAM: %d) \n " ,
2006-07-13 13:29:25 +04:00
domain , user ,
2009-06-14 14:41:46 +04:00
state - > response - > data . auth . nt_status_string ,
state - > response - > data . auth . pam_error ) ) ;
2006-07-13 13:29:25 +04:00
return NT_STATUS_IS_OK ( result ) ? WINBINDD_OK : WINBINDD_ERROR ;
}
2012-07-19 01:38:47 +04:00
# ifdef HAVE_KRB5
static NTSTATUS extract_pac_vrfy_sigs ( TALLOC_CTX * mem_ctx , DATA_BLOB pac_blob ,
2018-01-24 01:02:26 +03:00
struct PAC_DATA * * p_pac_data )
2012-07-19 01:38:47 +04:00
{
krb5_context krbctx = NULL ;
krb5_error_code k5ret ;
krb5_keytab keytab ;
krb5_kt_cursor cursor ;
krb5_keytab_entry entry ;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
ZERO_STRUCT ( entry ) ;
ZERO_STRUCT ( cursor ) ;
2018-12-05 13:46:46 +03:00
k5ret = smb_krb5_init_context_common ( & krbctx ) ;
2012-07-19 01:38:47 +04:00
if ( k5ret ) {
2018-12-05 13:46:46 +03:00
DBG_ERR ( " kerberos init context failed (%s) \n " ,
error_message ( k5ret ) ) ;
2012-07-19 01:38:47 +04:00
status = krb5_to_nt_status ( k5ret ) ;
goto out ;
}
k5ret = gse_krb5_get_server_keytab ( krbctx , & keytab ) ;
if ( k5ret ) {
DEBUG ( 1 , ( " Failed to get keytab: %s \n " ,
error_message ( k5ret ) ) ) ;
status = krb5_to_nt_status ( k5ret ) ;
goto out_free ;
}
k5ret = krb5_kt_start_seq_get ( krbctx , keytab , & cursor ) ;
if ( k5ret ) {
DEBUG ( 1 , ( " Failed to start seq: %s \n " ,
error_message ( k5ret ) ) ) ;
status = krb5_to_nt_status ( k5ret ) ;
goto out_keytab ;
}
k5ret = krb5_kt_next_entry ( krbctx , keytab , & entry , & cursor ) ;
while ( k5ret = = 0 ) {
2018-01-24 01:02:26 +03:00
status = kerberos_decode_pac ( mem_ctx ,
pac_blob ,
krbctx ,
NULL , /* krbtgt_keyblock */
KRB5_KT_KEY ( & entry ) , /* service_keyblock */
NULL , /* client_principal */
0 , /* tgs_authtime */
p_pac_data ) ;
2012-07-19 01:38:47 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
break ;
}
k5ret = smb_krb5_kt_free_entry ( krbctx , & entry ) ;
k5ret = krb5_kt_next_entry ( krbctx , keytab , & entry , & cursor ) ;
}
k5ret = krb5_kt_end_seq_get ( krbctx , keytab , & cursor ) ;
if ( k5ret ) {
DEBUG ( 1 , ( " Failed to end seq: %s \n " ,
error_message ( k5ret ) ) ) ;
}
out_keytab :
k5ret = krb5_kt_close ( krbctx , keytab ) ;
if ( k5ret ) {
DEBUG ( 1 , ( " Failed to close keytab: %s \n " ,
error_message ( k5ret ) ) ) ;
}
out_free :
krb5_free_context ( krbctx ) ;
out :
return status ;
}
2018-02-09 10:38:18 +03:00
NTSTATUS winbindd_pam_auth_pac_verify ( struct winbindd_cli_state * state ,
bool * p_is_trusted ,
uint16_t * p_validation_level ,
union netr_Validation * * p_validation )
2012-07-19 01:38:47 +04:00
{
struct winbindd_request * req = state - > request ;
DATA_BLOB pac_blob ;
2018-01-24 01:02:26 +03:00
struct PAC_DATA * pac_data = NULL ;
2012-07-19 01:38:47 +04:00
struct PAC_LOGON_INFO * logon_info = NULL ;
2018-01-24 01:02:26 +03:00
struct PAC_UPN_DNS_INFO * upn_dns_info = NULL ;
struct netr_SamInfo6 * info6 = NULL ;
uint16_t validation_level = 0 ;
union netr_Validation * validation = NULL ;
2014-06-17 10:27:35 +04:00
struct netr_SamInfo3 * info3_copy = NULL ;
2012-07-19 01:38:47 +04:00
NTSTATUS result ;
2018-01-24 01:02:26 +03:00
bool is_trusted = false ;
uint32_t i ;
2012-07-19 01:38:47 +04:00
2018-02-09 10:38:18 +03:00
* p_is_trusted = false ;
* p_validation_level = 0 ;
* p_validation = NULL ;
2012-07-19 01:38:47 +04:00
pac_blob = data_blob_const ( req - > extra_data . data , req - > extra_len ) ;
2018-01-24 01:02:26 +03:00
result = extract_pac_vrfy_sigs ( state - > mem_ctx , pac_blob , & pac_data ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
is_trusted = true ;
}
if ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED ) ) {
/* Try without signature verification */
result = kerberos_decode_pac ( state - > mem_ctx ,
pac_blob ,
NULL , /* krb5_context */
NULL , /* krbtgt_keyblock */
NULL , /* service_keyblock */
NULL , /* client_principal */
0 , /* tgs_authtime */
& pac_data ) ;
}
if ( ! NT_STATUS_IS_OK ( result ) ) {
2012-07-19 01:38:47 +04:00
DEBUG ( 1 , ( " Error during PAC signature verification: %s \n " ,
nt_errstr ( result ) ) ) ;
return result ;
}
2018-01-24 01:02:26 +03:00
for ( i = 0 ; i < pac_data - > num_buffers ; i + + ) {
if ( pac_data - > buffers [ i ] . type = = PAC_TYPE_LOGON_INFO ) {
logon_info = pac_data - > buffers [ i ] . info - > logon_info . info ;
continue ;
}
if ( pac_data - > buffers [ i ] . type = = PAC_TYPE_UPN_DNS_INFO ) {
upn_dns_info = & pac_data - > buffers [ i ] . info - > upn_dns_info ;
continue ;
}
}
result = create_info6_from_pac ( state - > mem_ctx ,
logon_info ,
upn_dns_info ,
& info6 ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
2021-01-14 12:42:53 +03:00
if ( ! is_allowed_domain ( info6 - > base . logon_domain . string ) ) {
DBG_NOTICE ( " Authentication failed for user [%s] "
" from firewalled domain [%s] \n " ,
info6 - > base . account_name . string ,
info6 - > base . logon_domain . string ) ;
return NT_STATUS_AUTHENTICATION_FIREWALL_FAILED ;
}
2018-01-24 01:02:26 +03:00
result = map_info6_to_validation ( state - > mem_ctx ,
info6 ,
& validation_level ,
& validation ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
result = map_validation_to_info3 ( state - > mem_ctx ,
validation_level ,
validation ,
& info3_copy ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
if ( is_trusted ) {
2016-09-28 01:04:49 +03:00
/*
* Signature verification succeeded , we can
* trust the PAC and prime the netsamlogon
* and name2sid caches . DO NOT DO THIS
* in the signature verification failed
* code path .
*/
struct winbindd_domain * domain = NULL ;
2014-06-17 10:27:35 +04:00
netsamlogon_cache_store ( NULL , info3_copy ) ;
2012-07-19 01:38:47 +04:00
2016-09-28 01:04:49 +03:00
/*
* We ' re in the parent here , so find the child
* pointer from the PAC domain name .
*/
2017-06-07 20:33:24 +03:00
domain = find_lookup_domain_from_name (
2016-09-28 01:04:49 +03:00
info3_copy - > base . logon_domain . string ) ;
if ( domain & & domain - > primary ) {
struct dom_sid user_sid ;
2018-12-14 23:09:51 +03:00
struct dom_sid_buf buf ;
2016-09-28 01:04:49 +03:00
sid_compose ( & user_sid ,
info3_copy - > base . domain_sid ,
info3_copy - > base . rid ) ;
2016-09-28 21:26:04 +03:00
cache_name2sid_trusted ( domain ,
2016-09-28 01:04:49 +03:00
info3_copy - > base . logon_domain . string ,
info3_copy - > base . account_name . string ,
SID_NAME_USER ,
& user_sid ) ;
2017-12-18 22:54:40 +03:00
DBG_INFO ( " PAC for user %s \\ %s SID %s primed cache \n " ,
2016-09-28 01:04:49 +03:00
info3_copy - > base . logon_domain . string ,
info3_copy - > base . account_name . string ,
2018-12-14 23:09:51 +03:00
dom_sid_str_buf ( & user_sid , & buf ) ) ;
2016-09-28 01:04:49 +03:00
}
2012-07-19 01:38:47 +04:00
}
2018-02-09 10:38:18 +03:00
* p_is_trusted = is_trusted ;
* p_validation_level = validation_level ;
* p_validation = validation ;
2012-07-19 01:38:47 +04:00
return NT_STATUS_OK ;
}
# else /* HAVE_KRB5 */
2018-02-09 10:38:18 +03:00
NTSTATUS winbindd_pam_auth_pac_verify ( struct winbindd_cli_state * state ,
bool * p_is_trusted ,
uint16_t * p_validation_level ,
union netr_Validation * * p_validation ) ;
2012-07-19 01:38:47 +04:00
{
2018-02-09 10:38:18 +03:00
* p_is_trusted = false ;
* p_validation_level = 0 ;
* p_validation = NULL ;
2012-07-19 01:38:47 +04:00
return NT_STATUS_NO_SUCH_USER ;
}
# endif /* HAVE_KRB5 */