2008-02-17 03:47:01 +03:00
/*
2005-11-10 23:28:23 +03:00
Unix SMB / CIFS implementation .
Net_sam_logon info3 helpers
Copyright ( C ) Alexander Bokovoy 2002.
Copyright ( C ) Andrew Bartlett 2002.
Copyright ( C ) Gerald Carter 2003.
Copyright ( C ) Tim Potter 2003.
2008-02-27 21:38:48 +03:00
Copyright ( C ) Guenther Deschner 2008.
2008-02-17 03:47:01 +03:00
2005-11-10 23:28:23 +03: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
2005-11-10 23:28:23 +03:00
( at your option ) any later version .
2008-02-17 03:47:01 +03:00
2005-11-10 23:28:23 +03: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 .
2008-02-17 03:47:01 +03:00
2005-11-10 23:28:23 +03: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/>.
2005-11-10 23:28:23 +03:00
*/
2016-11-29 18:59:21 +03:00
# include "replace.h"
2016-11-29 18:41:27 +03:00
# include "samlogon_cache.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2016-11-29 18:59:21 +03:00
# include "system/time.h"
# include "lib/util/debug.h"
# include "lib/util/talloc_stack.h"
2019-02-06 18:05:48 +03:00
# include "lib/util/memory.h" /* for SAFE_FREE() */
2016-11-29 18:59:21 +03:00
# include "source3/lib/util_path.h"
2008-10-20 21:21:10 +04:00
# include "librpc/gen_ndr/ndr_krb5pac.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2005-11-10 23:28:23 +03:00
# define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
static TDB_CONTEXT * netsamlogon_tdb = NULL ;
/***********************************************************************
open the tdb
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-17 03:47:01 +03:00
2007-10-19 04:40:25 +04:00
bool netsamlogon_cache_init ( void )
2005-11-10 23:28:23 +03:00
{
2009-12-04 18:34:08 +03:00
bool first_try = true ;
2014-10-06 20:21:17 +04:00
char * path = NULL ;
2009-12-04 18:34:08 +03:00
int ret ;
struct tdb_context * tdb ;
if ( netsamlogon_tdb ) {
return true ;
}
2018-08-16 11:51:44 +03:00
path = cache_path ( talloc_tos ( ) , NETSAMLOGON_TDB ) ;
2014-10-06 20:21:17 +04:00
if ( path = = NULL ) {
return false ;
}
2009-12-04 18:34:08 +03:00
again :
2010-09-27 16:46:07 +04:00
tdb = tdb_open_log ( path , 0 , TDB_DEFAULT | TDB_INCOMPATIBLE_HASH ,
2009-12-04 18:34:08 +03:00
O_RDWR | O_CREAT , 0600 ) ;
if ( tdb = = NULL ) {
DEBUG ( 0 , ( " tdb_open_log('%s') - failed \n " , path ) ) ;
goto clear ;
}
ret = tdb_check ( tdb , NULL , NULL ) ;
if ( ret ! = 0 ) {
tdb_close ( tdb ) ;
DEBUG ( 0 , ( " tdb_check('%s') - failed \n " , path ) ) ;
goto clear ;
}
netsamlogon_tdb = tdb ;
2014-10-06 20:21:17 +04:00
talloc_free ( path ) ;
2009-12-04 18:34:08 +03:00
return true ;
clear :
if ( ! first_try ) {
2014-10-06 20:21:17 +04:00
talloc_free ( path ) ;
2009-12-04 18:34:08 +03:00
return false ;
}
first_try = false ;
2011-04-19 06:36:05 +04:00
DEBUG ( 0 , ( " retry after truncate for '%s' \n " , path ) ) ;
2016-04-05 17:47:39 +03:00
ret = truncate ( path , 0 ) ;
if ( ret = = - 1 ) {
DBG_ERR ( " truncate failed: %s \n " , strerror ( errno ) ) ;
talloc_free ( path ) ;
return false ;
}
2011-04-19 06:36:05 +04:00
goto again ;
2005-11-10 23:28:23 +03:00
}
/***********************************************************************
Clear cache getpwnam and getgroups entries from the winbindd cache
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-17 03:47:01 +03:00
2010-12-11 16:19:50 +03:00
void netsamlogon_clear_cached_user ( const struct dom_sid * user_sid )
2005-11-10 23:28:23 +03:00
{
2018-10-26 09:25:14 +03:00
struct dom_sid_buf keystr ;
2005-11-10 23:28:23 +03:00
2008-08-28 04:28:34 +04:00
if ( ! netsamlogon_cache_init ( ) ) {
DEBUG ( 0 , ( " netsamlogon_clear_cached_user: cannot open "
" %s for write! \n " ,
NETSAMLOGON_TDB ) ) ;
return ;
}
2005-11-10 23:28:23 +03:00
2008-08-28 04:28:34 +04:00
/* Prepare key as DOMAIN-SID/USER-RID string */
2018-10-26 09:25:14 +03:00
dom_sid_str_buf ( user_sid , & keystr ) ;
2005-11-10 23:28:23 +03:00
2018-10-26 09:25:14 +03:00
DBG_DEBUG ( " SID [%s] \n " , keystr . buf ) ;
2005-11-10 23:28:23 +03:00
2018-10-26 09:25:14 +03:00
tdb_delete_bystring ( netsamlogon_tdb , keystr . buf ) ;
2005-11-10 23:28:23 +03:00
}
/***********************************************************************
2008-02-17 03:47:01 +03:00
Store a netr_SamInfo3 structure in a tdb for later user
2005-11-10 23:28:23 +03:00
username should be in UTF - 8 format
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-17 03:47:01 +03:00
bool netsamlogon_cache_store ( const char * username , struct netr_SamInfo3 * info3 )
2005-11-10 23:28:23 +03:00
{
2016-12-01 23:46:47 +03:00
uint8_t dummy = 0 ;
TDB_DATA data = { . dptr = & dummy , . dsize = sizeof ( dummy ) } ;
2018-10-26 09:25:14 +03:00
struct dom_sid_buf keystr ;
2008-02-17 03:47:01 +03:00
bool result = false ;
2010-05-21 05:25:01 +04:00
struct dom_sid user_sid ;
2014-07-09 15:36:06 +04:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2008-02-17 03:47:01 +03:00
DATA_BLOB blob ;
enum ndr_err_code ndr_err ;
struct netsamlogoncache_entry r ;
2016-12-01 23:46:47 +03:00
int ret ;
2008-02-17 03:47:01 +03:00
if ( ! info3 ) {
2018-10-13 11:55:00 +03:00
goto fail ;
2008-02-17 03:47:01 +03:00
}
2005-11-10 23:28:23 +03:00
if ( ! netsamlogon_cache_init ( ) ) {
2022-06-11 18:44:30 +03:00
D_WARNING ( " netsamlogon_cache_store: cannot open %s for write! \n " ,
NETSAMLOGON_TDB ) ;
2018-10-13 11:55:00 +03:00
goto fail ;
2005-11-10 23:28:23 +03:00
}
2016-12-01 23:46:47 +03:00
/*
* First write a record with just the domain sid for
* netsamlogon_cache_domain_known . Use TDB_INSERT to avoid
* overwriting potentially other data . We ' re just interested
* in the existence of that record .
*/
2018-10-26 09:25:14 +03:00
dom_sid_str_buf ( info3 - > base . domain_sid , & keystr ) ;
2016-12-01 23:46:47 +03:00
2018-10-26 09:25:14 +03:00
ret = tdb_store_bystring ( netsamlogon_tdb , keystr . buf , data , TDB_INSERT ) ;
2016-12-01 23:46:47 +03:00
if ( ( ret = = - 1 ) & & ( tdb_error ( netsamlogon_tdb ) ! = TDB_ERR_EXISTS ) ) {
2022-06-11 18:44:30 +03:00
D_WARNING ( " Could not store domain marker for %s: %s \n " ,
2018-10-26 09:25:14 +03:00
keystr . buf , tdb_errorstr ( netsamlogon_tdb ) ) ;
2018-10-13 11:55:00 +03:00
goto fail ;
2016-12-01 23:46:47 +03:00
}
2010-01-10 19:39:27 +03:00
sid_compose ( & user_sid , info3 - > base . domain_sid , info3 - > base . rid ) ;
2005-11-10 23:28:23 +03:00
/* Prepare key as DOMAIN-SID/USER-RID string */
2018-10-26 09:25:14 +03:00
dom_sid_str_buf ( & user_sid , & keystr ) ;
2005-11-10 23:28:23 +03:00
2018-10-26 09:25:14 +03:00
DBG_DEBUG ( " SID [%s] \n " , keystr . buf ) ;
2008-02-17 03:47:01 +03:00
/* Prepare data */
2014-07-03 18:17:46 +04:00
if ( info3 - > base . full_name . string = = NULL ) {
struct netr_SamInfo3 * cached_info3 ;
const char * full_name = NULL ;
cached_info3 = netsamlogon_cache_get ( tmp_ctx , & user_sid ) ;
if ( cached_info3 ! = NULL ) {
full_name = cached_info3 - > base . full_name . string ;
}
if ( full_name ! = NULL ) {
info3 - > base . full_name . string = talloc_strdup ( info3 , full_name ) ;
2018-10-13 11:57:13 +03:00
if ( info3 - > base . full_name . string = = NULL ) {
goto fail ;
}
2014-07-03 18:17:46 +04:00
}
}
2005-11-10 23:28:23 +03:00
/* only Samba fills in the username, not sure why NT doesn't */
/* so we fill it in since winbindd_getpwnam() makes use of it */
2008-02-17 03:47:01 +03:00
if ( ! info3 - > base . account_name . string ) {
2008-03-26 00:35:20 +03:00
info3 - > base . account_name . string = talloc_strdup ( info3 , username ) ;
2018-10-13 11:57:13 +03:00
if ( info3 - > base . account_name . string = = NULL ) {
goto fail ;
}
2005-11-10 23:28:23 +03:00
}
2008-02-17 03:47:01 +03:00
2016-11-29 19:11:59 +03:00
r . timestamp = time ( NULL ) ;
2008-02-17 03:47:01 +03:00
r . info3 = * info3 ;
2011-02-03 04:23:21 +03:00
/* avoid storing secret information */
ZERO_STRUCT ( r . info3 . base . key ) ;
ZERO_STRUCT ( r . info3 . base . LMSessKey ) ;
2008-02-17 03:47:01 +03:00
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( netsamlogoncache_entry , & r ) ;
2005-11-11 06:03:41 +03:00
}
2014-07-09 15:36:06 +04:00
ndr_err = ndr_push_struct_blob ( & blob , tmp_ctx , & r ,
2008-02-17 03:47:01 +03:00
( ndr_push_flags_fn_t ) ndr_push_netsamlogoncache_entry ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2018-10-13 11:58:32 +03:00
DBG_WARNING ( " failed to push entry to cache: %s \n " ,
ndr_errstr ( ndr_err ) ) ;
2018-10-13 11:55:00 +03:00
goto fail ;
2005-12-03 09:46:46 +03:00
}
2005-11-10 23:28:23 +03:00
2008-02-17 03:47:01 +03:00
data . dsize = blob . length ;
data . dptr = blob . data ;
2018-10-26 09:25:14 +03:00
if ( tdb_store_bystring ( netsamlogon_tdb , keystr . buf , data , TDB_REPLACE ) = = 0 ) {
2008-02-17 03:47:01 +03:00
result = true ;
2005-11-10 23:28:23 +03:00
}
2005-11-11 06:03:41 +03:00
2018-10-13 11:55:00 +03:00
fail :
2014-07-09 15:36:06 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2005-11-10 23:28:23 +03:00
return result ;
}
/***********************************************************************
2008-02-17 03:47:01 +03:00
Retrieves a netr_SamInfo3 structure from a tdb . Caller must
2016-11-29 19:01:58 +03:00
free the user_info struct ( talloced memory )
2005-11-10 23:28:23 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
struct netr_SamInfo3 * netsamlogon_cache_get ( TALLOC_CTX * mem_ctx , const struct dom_sid * user_sid )
2005-11-10 23:28:23 +03:00
{
2008-02-17 03:47:01 +03:00
struct netr_SamInfo3 * info3 = NULL ;
TDB_DATA data ;
2018-10-26 09:25:14 +03:00
struct dom_sid_buf keystr ;
2008-02-17 03:47:01 +03:00
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
struct netsamlogoncache_entry r ;
2005-11-10 23:28:23 +03:00
if ( ! netsamlogon_cache_init ( ) ) {
2008-02-17 03:47:01 +03:00
DEBUG ( 0 , ( " netsamlogon_cache_get: cannot open %s for write! \n " ,
NETSAMLOGON_TDB ) ) ;
2011-12-20 13:25:05 +04:00
return NULL ;
2005-11-10 23:28:23 +03:00
}
/* Prepare key as DOMAIN-SID/USER-RID string */
2018-10-26 09:25:14 +03:00
dom_sid_str_buf ( user_sid , & keystr ) ;
DBG_DEBUG ( " SID [%s] \n " , keystr . buf ) ;
data = tdb_fetch_bystring ( netsamlogon_tdb , keystr . buf ) ;
2007-05-03 16:29:32 +04:00
2008-02-17 03:47:01 +03:00
if ( ! data . dptr ) {
2022-06-11 18:44:30 +03:00
D_DEBUG ( " tdb fetch for %s is empty \n " , keystr . buf ) ;
2008-02-17 03:47:01 +03:00
return NULL ;
}
2007-05-03 16:29:32 +04:00
2011-06-07 05:44:43 +04:00
info3 = talloc_zero ( mem_ctx , struct netr_SamInfo3 ) ;
2008-02-17 03:47:01 +03:00
if ( ! info3 ) {
goto done ;
}
2008-04-21 12:25:28 +04:00
blob = data_blob_const ( data . dptr , data . dsize ) ;
2008-02-17 03:47:01 +03:00
2017-08-03 18:03:26 +03:00
ndr_err = ndr_pull_struct_blob_all (
& blob , mem_ctx , & r ,
( ndr_pull_flags_fn_t ) ndr_pull_netsamlogoncache_entry ) ;
2005-11-10 23:28:23 +03:00
2008-02-17 03:47:01 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2022-06-11 18:44:30 +03:00
D_WARNING ( " netsamlogon_cache_get: failed to pull entry from cache \n " ) ;
2018-10-26 09:25:14 +03:00
tdb_delete_bystring ( netsamlogon_tdb , keystr . buf ) ;
2008-02-29 01:15:11 +03:00
TALLOC_FREE ( info3 ) ;
2008-02-17 03:47:01 +03:00
goto done ;
}
2022-06-11 18:44:30 +03:00
NDR_PRINT_DEBUG_LEVEL ( DBGLVL_DEBUG , netsamlogoncache_entry , & r ) ;
2014-12-12 13:41:14 +03:00
2008-02-23 12:50:12 +03:00
info3 = ( struct netr_SamInfo3 * ) talloc_memdup ( mem_ctx , & r . info3 ,
sizeof ( r . info3 ) ) ;
2008-02-17 03:47:01 +03:00
done :
SAFE_FREE ( data . dptr ) ;
return info3 ;
2005-11-10 23:28:23 +03:00
}
2016-12-05 17:38:14 +03:00
bool netsamlogon_cache_have ( const struct dom_sid * sid )
2005-11-10 23:28:23 +03:00
{
2018-10-26 09:25:14 +03:00
struct dom_sid_buf keystr ;
2016-12-01 23:45:35 +03:00
bool ok ;
2005-11-10 23:28:23 +03:00
2016-12-01 23:45:35 +03:00
if ( ! netsamlogon_cache_init ( ) ) {
DBG_WARNING ( " Cannot open %s \n " , NETSAMLOGON_TDB ) ;
2016-11-29 18:20:14 +03:00
return false ;
}
2005-11-10 23:28:23 +03:00
2018-10-26 09:25:14 +03:00
dom_sid_str_buf ( sid , & keystr ) ;
2005-11-10 23:28:23 +03:00
2018-10-26 09:25:14 +03:00
ok = tdb_exists ( netsamlogon_tdb , string_term_tdb_data ( keystr . buf ) ) ;
2016-12-01 23:45:35 +03:00
return ok ;
2005-11-10 23:28:23 +03:00
}
2017-06-27 18:34:34 +03:00
struct netsamlog_cache_forall_state {
TALLOC_CTX * mem_ctx ;
int ( * cb ) ( const char * sid_str ,
time_t when_cached ,
struct netr_SamInfo3 * ,
void * private_data ) ;
void * private_data ;
} ;
static int netsamlog_cache_traverse_cb ( struct tdb_context * tdb ,
TDB_DATA key ,
TDB_DATA data ,
void * private_data )
{
struct netsamlog_cache_forall_state * state =
( struct netsamlog_cache_forall_state * ) private_data ;
TALLOC_CTX * mem_ctx = NULL ;
DATA_BLOB blob ;
const char * sid_str = NULL ;
struct dom_sid sid ;
struct netsamlogoncache_entry r ;
enum ndr_err_code ndr_err ;
int ret ;
bool ok ;
if ( key . dsize = = 0 ) {
return 0 ;
}
if ( key . dptr [ key . dsize - 1 ] ! = ' \0 ' ) {
return 0 ;
}
if ( data . dptr = = NULL ) {
return 0 ;
}
sid_str = ( char * ) key . dptr ;
ok = string_to_sid ( & sid , sid_str ) ;
if ( ! ok ) {
DBG_ERR ( " String to SID failed for %s \n " , sid_str ) ;
return - 1 ;
}
if ( sid . num_auths ! = 5 ) {
return 0 ;
}
mem_ctx = talloc_new ( state - > mem_ctx ) ;
if ( mem_ctx = = NULL ) {
return - 1 ;
}
blob = data_blob_const ( data . dptr , data . dsize ) ;
ndr_err = ndr_pull_struct_blob (
& blob , state - > mem_ctx , & r ,
( ndr_pull_flags_fn_t ) ndr_pull_netsamlogoncache_entry ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_ERR ( " failed to pull entry from cache \n " ) ;
return - 1 ;
}
ret = state - > cb ( sid_str , r . timestamp , & r . info3 , state - > private_data ) ;
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
int netsamlog_cache_for_all ( int ( * cb ) ( const char * sid_str ,
time_t when_cached ,
struct netr_SamInfo3 * ,
void * private_data ) ,
void * private_data )
{
int ret ;
TALLOC_CTX * mem_ctx = NULL ;
struct netsamlog_cache_forall_state state ;
if ( ! netsamlogon_cache_init ( ) ) {
DBG_ERR ( " Cannot open %s \n " , NETSAMLOGON_TDB ) ;
return - 1 ;
}
mem_ctx = talloc_init ( " netsamlog_cache_for_all " ) ;
if ( mem_ctx = = NULL ) {
return - 1 ;
}
state = ( struct netsamlog_cache_forall_state ) {
. mem_ctx = mem_ctx ,
. cb = cb ,
. private_data = private_data ,
} ;
ret = tdb_traverse_read ( netsamlogon_tdb ,
netsamlog_cache_traverse_cb ,
& state ) ;
TALLOC_FREE ( state . mem_ctx ) ;
return ret ;
}