2008-02-17 01:47:01 +01:00
/*
2005-11-10 20:28:23 +00: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 19:38:48 +01:00
Copyright ( C ) Guenther Deschner 2008.
2008-02-17 01:47:01 +01:00
2005-11-10 20:28:23 +00: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 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-11-10 20:28:23 +00:00
( at your option ) any later version .
2008-02-17 01:47:01 +01:00
2005-11-10 20:28:23 +00: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 01:47:01 +01:00
2005-11-10 20:28:23 +00:00
You should have received a copy of the GNU General Public License
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-11-10 20:28:23 +00:00
*/
2016-11-29 15:59:21 +00:00
# include "replace.h"
2016-11-29 15:41:27 +00:00
# include "samlogon_cache.h"
2011-02-25 23:20:06 +01:00
# include "system/filesys.h"
2016-11-29 15:59:21 +00:00
# include "system/time.h"
# include "lib/util/debug.h"
# include "lib/util/talloc_stack.h"
# include "source3/lib/util_path.h"
2008-10-20 19:21:10 +02:00
# include "librpc/gen_ndr/ndr_krb5pac.h"
2010-10-12 15:27:50 +11:00
# include "../libcli/security/security.h"
2011-05-05 11:25:29 +02:00
# include "util_tdb.h"
2005-11-10 20:28:23 +00:00
# define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
static TDB_CONTEXT * netsamlogon_tdb = NULL ;
/***********************************************************************
open the tdb
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-17 01:47:01 +01:00
2007-10-18 17:40:25 -07:00
bool netsamlogon_cache_init ( void )
2005-11-10 20:28:23 +00:00
{
2009-12-04 16:34:08 +01:00
bool first_try = true ;
2014-10-06 18:21:17 +02:00
char * path = NULL ;
2009-12-04 16:34:08 +01:00
int ret ;
struct tdb_context * tdb ;
if ( netsamlogon_tdb ) {
return true ;
}
path = cache_path ( NETSAMLOGON_TDB ) ;
2014-10-06 18:21:17 +02:00
if ( path = = NULL ) {
return false ;
}
2009-12-04 16:34:08 +01:00
again :
2010-09-27 05:46:07 -07:00
tdb = tdb_open_log ( path , 0 , TDB_DEFAULT | TDB_INCOMPATIBLE_HASH ,
2009-12-04 16:34:08 +01: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 18:21:17 +02:00
talloc_free ( path ) ;
2009-12-04 16:34:08 +01:00
return true ;
clear :
if ( ! first_try ) {
2014-10-06 18:21:17 +02:00
talloc_free ( path ) ;
2009-12-04 16:34:08 +01:00
return false ;
}
first_try = false ;
2011-04-19 12:06:05 +09:30
DEBUG ( 0 , ( " retry after truncate for '%s' \n " , path ) ) ;
2016-04-05 16:47:39 +02:00
ret = truncate ( path , 0 ) ;
if ( ret = = - 1 ) {
DBG_ERR ( " truncate failed: %s \n " , strerror ( errno ) ) ;
talloc_free ( path ) ;
return false ;
}
2011-04-19 12:06:05 +09:30
goto again ;
2005-11-10 20:28:23 +00:00
}
/***********************************************************************
Clear cache getpwnam and getgroups entries from the winbindd cache
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-17 01:47:01 +01:00
2010-12-11 14:19:50 +01:00
void netsamlogon_clear_cached_user ( const struct dom_sid * user_sid )
2005-11-10 20:28:23 +00:00
{
2016-11-29 15:52:29 +00:00
char keystr [ DOM_SID_STR_BUFLEN ] ;
2005-11-10 20:28:23 +00:00
2008-08-27 17:28:34 -07:00
if ( ! netsamlogon_cache_init ( ) ) {
DEBUG ( 0 , ( " netsamlogon_clear_cached_user: cannot open "
" %s for write! \n " ,
NETSAMLOGON_TDB ) ) ;
return ;
}
2005-11-10 20:28:23 +00:00
2008-08-27 17:28:34 -07:00
/* Prepare key as DOMAIN-SID/USER-RID string */
2016-11-29 15:52:29 +00:00
dom_sid_string_buf ( user_sid , keystr , sizeof ( keystr ) ) ;
2005-11-10 20:28:23 +00:00
2008-08-27 17:28:34 -07:00
DEBUG ( 10 , ( " netsamlogon_clear_cached_user: SID [%s] \n " , keystr ) ) ;
2005-11-10 20:28:23 +00:00
2008-08-27 17:28:34 -07:00
tdb_delete_bystring ( netsamlogon_tdb , keystr ) ;
2005-11-10 20:28:23 +00:00
}
/***********************************************************************
2008-02-17 01:47:01 +01:00
Store a netr_SamInfo3 structure in a tdb for later user
2005-11-10 20:28:23 +00:00
username should be in UTF - 8 format
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-17 01:47:01 +01:00
bool netsamlogon_cache_store ( const char * username , struct netr_SamInfo3 * info3 )
2005-11-10 20:28:23 +00:00
{
2016-12-01 20:46:47 +00:00
uint8_t dummy = 0 ;
TDB_DATA data = { . dptr = & dummy , . dsize = sizeof ( dummy ) } ;
2016-11-29 15:52:29 +00:00
char keystr [ DOM_SID_STR_BUFLEN ] ;
2008-02-17 01:47:01 +01:00
bool result = false ;
2010-05-21 11:25:01 +10:00
struct dom_sid user_sid ;
2014-07-09 13:36:06 +02:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2008-02-17 01:47:01 +01:00
DATA_BLOB blob ;
enum ndr_err_code ndr_err ;
struct netsamlogoncache_entry r ;
2016-12-01 20:46:47 +00:00
int ret ;
2008-02-17 01:47:01 +01:00
if ( ! info3 ) {
return false ;
}
2005-11-10 20:28:23 +00:00
if ( ! netsamlogon_cache_init ( ) ) {
2008-02-17 01:47:01 +01:00
DEBUG ( 0 , ( " netsamlogon_cache_store: cannot open %s for write! \n " ,
NETSAMLOGON_TDB ) ) ;
return false ;
2005-11-10 20:28:23 +00:00
}
2016-12-01 20:46:47 +00: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 .
*/
dom_sid_string_buf ( info3 - > base . domain_sid , keystr , sizeof ( keystr ) ) ;
ret = tdb_store_bystring ( netsamlogon_tdb , keystr , data , TDB_INSERT ) ;
if ( ( ret = = - 1 ) & & ( tdb_error ( netsamlogon_tdb ) ! = TDB_ERR_EXISTS ) ) {
DBG_WARNING ( " Could not store domain marker for %s: %s \n " ,
keystr , tdb_errorstr ( netsamlogon_tdb ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return false ;
}
2010-01-10 17:39:27 +01:00
sid_compose ( & user_sid , info3 - > base . domain_sid , info3 - > base . rid ) ;
2005-11-10 20:28:23 +00:00
/* Prepare key as DOMAIN-SID/USER-RID string */
2016-11-29 15:52:29 +00:00
dom_sid_string_buf ( & user_sid , keystr , sizeof ( keystr ) ) ;
2005-11-10 20:28:23 +00:00
DEBUG ( 10 , ( " netsamlogon_cache_store: SID [%s] \n " , keystr ) ) ;
2008-02-17 01:47:01 +01:00
/* Prepare data */
2014-07-03 16:17:46 +02: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 ) ;
}
}
2005-11-10 20:28:23 +00: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 01:47:01 +01:00
if ( ! info3 - > base . account_name . string ) {
2008-03-25 22:35:20 +01:00
info3 - > base . account_name . string = talloc_strdup ( info3 , username ) ;
2005-11-10 20:28:23 +00:00
}
2008-02-17 01:47:01 +01:00
2016-11-29 16:11:59 +00:00
r . timestamp = time ( NULL ) ;
2008-02-17 01:47:01 +01:00
r . info3 = * info3 ;
2011-02-03 02:23:21 +01:00
/* avoid storing secret information */
ZERO_STRUCT ( r . info3 . base . key ) ;
ZERO_STRUCT ( r . info3 . base . LMSessKey ) ;
2008-02-17 01:47:01 +01:00
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( netsamlogoncache_entry , & r ) ;
2005-11-11 03:03:41 +00:00
}
2014-07-09 13:36:06 +02:00
ndr_err = ndr_push_struct_blob ( & blob , tmp_ctx , & r ,
2008-02-17 01:47:01 +01:00
( ndr_push_flags_fn_t ) ndr_push_netsamlogoncache_entry ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( " netsamlogon_cache_store: failed to push entry to cache \n " ) ) ;
2014-07-09 13:36:06 +02:00
TALLOC_FREE ( tmp_ctx ) ;
2008-02-17 01:47:01 +01:00
return false ;
2005-12-03 06:46:46 +00:00
}
2005-11-10 20:28:23 +00:00
2008-02-17 01:47:01 +01:00
data . dsize = blob . length ;
data . dptr = blob . data ;
2011-06-20 18:40:31 +09:30
if ( tdb_store_bystring ( netsamlogon_tdb , keystr , data , TDB_REPLACE ) = = 0 ) {
2008-02-17 01:47:01 +01:00
result = true ;
2005-11-10 20:28:23 +00:00
}
2005-11-11 03:03:41 +00:00
2014-07-09 13:36:06 +02:00
TALLOC_FREE ( tmp_ctx ) ;
2008-02-17 01:47:01 +01:00
2005-11-10 20:28:23 +00:00
return result ;
}
/***********************************************************************
2008-02-17 01:47:01 +01:00
Retrieves a netr_SamInfo3 structure from a tdb . Caller must
2016-11-29 16:01:58 +00:00
free the user_info struct ( talloced memory )
2005-11-10 20:28:23 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 11:25:01 +10:00
struct netr_SamInfo3 * netsamlogon_cache_get ( TALLOC_CTX * mem_ctx , const struct dom_sid * user_sid )
2005-11-10 20:28:23 +00:00
{
2008-02-17 01:47:01 +01:00
struct netr_SamInfo3 * info3 = NULL ;
TDB_DATA data ;
2016-11-29 15:52:29 +00:00
char keystr [ DOM_SID_STR_BUFLEN ] ;
2008-02-17 01:47:01 +01:00
enum ndr_err_code ndr_err ;
DATA_BLOB blob ;
struct netsamlogoncache_entry r ;
2005-11-10 20:28:23 +00:00
if ( ! netsamlogon_cache_init ( ) ) {
2008-02-17 01:47:01 +01:00
DEBUG ( 0 , ( " netsamlogon_cache_get: cannot open %s for write! \n " ,
NETSAMLOGON_TDB ) ) ;
2011-12-20 10:25:05 +01:00
return NULL ;
2005-11-10 20:28:23 +00:00
}
/* Prepare key as DOMAIN-SID/USER-RID string */
2016-11-29 15:52:29 +00:00
dom_sid_string_buf ( user_sid , keystr , sizeof ( keystr ) ) ;
2005-11-10 20:28:23 +00:00
DEBUG ( 10 , ( " netsamlogon_cache_get: SID [%s] \n " , keystr ) ) ;
2007-03-27 09:30:40 +00:00
data = tdb_fetch_bystring ( netsamlogon_tdb , keystr ) ;
2007-05-03 12:29:32 +00:00
2008-02-17 01:47:01 +01:00
if ( ! data . dptr ) {
return NULL ;
}
2007-05-03 12:29:32 +00:00
2011-06-07 11:44:43 +10:00
info3 = talloc_zero ( mem_ctx , struct netr_SamInfo3 ) ;
2008-02-17 01:47:01 +01:00
if ( ! info3 ) {
goto done ;
}
2008-04-21 10:25:28 +02:00
blob = data_blob_const ( data . dptr , data . dsize ) ;
2008-02-17 01:47:01 +01:00
2017-08-03 17:03:26 +02:00
ndr_err = ndr_pull_struct_blob_all (
& blob , mem_ctx , & r ,
( ndr_pull_flags_fn_t ) ndr_pull_netsamlogoncache_entry ) ;
2005-11-10 20:28:23 +00:00
2008-02-17 01:47:01 +01:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 0 , ( " netsamlogon_cache_get: failed to pull entry from cache \n " ) ) ;
2014-12-12 11:39:25 +01:00
tdb_delete_bystring ( netsamlogon_tdb , keystr ) ;
2008-02-28 23:15:11 +01:00
TALLOC_FREE ( info3 ) ;
2008-02-17 01:47:01 +01:00
goto done ;
}
2014-12-12 11:41:14 +01:00
if ( DEBUGLEVEL > = 10 ) {
NDR_PRINT_DEBUG ( netsamlogoncache_entry , & r ) ;
}
2008-02-23 10:50:12 +01:00
info3 = ( struct netr_SamInfo3 * ) talloc_memdup ( mem_ctx , & r . info3 ,
sizeof ( r . info3 ) ) ;
2008-02-17 01:47:01 +01:00
done :
SAFE_FREE ( data . dptr ) ;
return info3 ;
2005-11-10 20:28:23 +00:00
}
2016-12-05 14:38:14 +00:00
bool netsamlogon_cache_have ( const struct dom_sid * sid )
2005-11-10 20:28:23 +00:00
{
2016-12-01 20:45:35 +00:00
char keystr [ DOM_SID_STR_BUFLEN ] ;
bool ok ;
2005-11-10 20:28:23 +00:00
2016-12-01 20:45:35 +00:00
if ( ! netsamlogon_cache_init ( ) ) {
DBG_WARNING ( " Cannot open %s \n " , NETSAMLOGON_TDB ) ;
2016-11-29 15:20:14 +00:00
return false ;
}
2005-11-10 20:28:23 +00:00
2016-12-05 14:38:14 +00:00
dom_sid_string_buf ( sid , keystr , sizeof ( keystr ) ) ;
2005-11-10 20:28:23 +00:00
2016-12-01 20:45:35 +00:00
ok = tdb_exists ( netsamlogon_tdb , string_term_tdb_data ( keystr ) ) ;
return ok ;
2005-11-10 20:28:23 +00:00
}
2017-06-27 17:34:34 +02: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 ;
}