2017-11-21 13:44:12 +03:00
/*
* Unix SMB / CIFS implementation .
* Group Policy Update event for winbindd
* Copyright ( C ) David Mulder 2017
*
* 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
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "param/param.h"
# include "param/loadparm.h"
# include "winbindd.h"
2021-01-03 23:53:49 +03:00
# include "lib/global_contexts.h"
2017-11-21 13:44:12 +03:00
/*
* gpupdate_interval ( )
* return Random integer between 5400 and 7200 , the group policy update
* interval in seconds
*
* Group Policy should be updated every 90 minutes in the background ,
2023-07-18 12:45:25 +03:00
* with a random offset between 0 and 30 minutes . This ensures multiple
2017-11-21 13:44:12 +03:00
* clients will not update at the same time .
*/
# define GPUPDATE_INTERVAL (90*60)
# define GPUPDATE_RAND_OFFSET (30*60)
static uint32_t gpupdate_interval ( void )
{
2018-04-10 22:13:37 +03:00
int rand_int_offset = generate_random ( ) % GPUPDATE_RAND_OFFSET ;
2017-11-21 13:44:12 +03:00
return GPUPDATE_INTERVAL + rand_int_offset ;
}
struct gpupdate_state {
TALLOC_CTX * ctx ;
struct loadparm_context * lp_ctx ;
} ;
2022-10-21 20:01:41 +03:00
static void gpupdate_cmd_done ( struct tevent_req * subreq ) ;
2017-11-21 13:44:12 +03:00
static void gpupdate_callback ( struct tevent_context * ev ,
struct tevent_timer * tim ,
struct timeval current_time ,
void * private_data )
{
struct tevent_timer * time_event ;
struct timeval schedule ;
struct tevent_req * req = NULL ;
struct gpupdate_state * data =
talloc_get_type_abort ( private_data , struct gpupdate_state ) ;
const char * const * gpupdate_cmd =
lpcfg_gpo_update_command ( data - > lp_ctx ) ;
2022-10-27 15:40:41 +03:00
const char * smbconf = lpcfg_configfile ( data - > lp_ctx ) ;
if ( smbconf = = NULL ) {
smbconf = lp_default_path ( ) ;
}
2017-11-21 13:44:12 +03:00
/* Execute gpupdate */
req = samba_runcmd_send ( data - > ctx , ev , timeval_zero ( ) , 2 , 0 ,
gpupdate_cmd ,
" -s " ,
smbconf ,
2018-05-07 18:48:32 +03:00
" --target=Computer " ,
2017-11-21 13:44:12 +03:00
" --machine-pass " ,
NULL ) ;
if ( req = = NULL ) {
DEBUG ( 0 , ( " Failed to execute the gpupdate command \n " ) ) ;
return ;
}
2022-10-21 20:01:41 +03:00
tevent_req_set_callback ( req , gpupdate_cmd_done , NULL ) ;
2017-11-21 13:44:12 +03:00
/* Schedule the next event */
schedule = tevent_timeval_current_ofs ( gpupdate_interval ( ) , 0 ) ;
time_event = tevent_add_timer ( ev , data - > ctx , schedule ,
gpupdate_callback , data ) ;
if ( time_event = = NULL ) {
DEBUG ( 0 , ( " Failed scheduling the next gpupdate event \n " ) ) ;
}
}
void gpupdate_init ( void )
{
struct tevent_timer * time_event ;
struct timeval schedule ;
2018-08-21 21:06:16 +03:00
TALLOC_CTX * ctx = talloc_new ( global_event_context ( ) ) ;
2017-11-21 13:44:12 +03:00
struct gpupdate_state * data = talloc ( ctx , struct gpupdate_state ) ;
struct loadparm_context * lp_ctx =
loadparm_init_s3 ( NULL , loadparm_s3_helpers ( ) ) ;
/*
* Check if gpupdate is enabled for winbind , if not
* return without scheduling any events .
*/
if ( ! lpcfg_apply_group_policies ( lp_ctx ) ) {
return ;
}
/*
* Execute the first event immediately , future events
* will execute on the gpupdate interval , which is every
* 90 to 120 minutes ( at random ) .
*/
schedule = tevent_timeval_current_ofs ( 0 , 0 ) ;
data - > ctx = ctx ;
data - > lp_ctx = lp_ctx ;
if ( data - > lp_ctx = = NULL ) {
smb_panic ( " Could not load smb.conf \n " ) ;
}
2018-08-21 21:06:16 +03:00
time_event = tevent_add_timer ( global_event_context ( ) , data - > ctx ,
2017-11-21 13:44:12 +03:00
schedule , gpupdate_callback , data ) ;
if ( time_event = = NULL ) {
DEBUG ( 0 , ( " Failed scheduling the gpupdate event \n " ) ) ;
}
}
2022-10-14 18:00:45 +03:00
void gpupdate_user_init ( const char * user )
{
struct tevent_req * req = NULL ;
TALLOC_CTX * ctx = talloc_new ( global_event_context ( ) ) ;
struct loadparm_context * lp_ctx =
loadparm_init_s3 ( NULL , loadparm_s3_helpers ( ) ) ;
const char * const * gpupdate_cmd = lpcfg_gpo_update_command ( lp_ctx ) ;
const char * smbconf = lpcfg_configfile ( lp_ctx ) ;
2022-10-26 21:37:01 +03:00
if ( smbconf = = NULL ) {
smbconf = lp_default_path ( ) ;
}
2022-10-14 18:00:45 +03:00
if ( ctx = = NULL ) {
DBG_ERR ( " talloc_new failed \n " ) ;
return ;
}
/*
* Check if gpupdate is enabled for winbind , if not
* return without applying user policy .
*/
if ( ! lpcfg_apply_group_policies ( lp_ctx ) ) {
return ;
}
/*
* Execute gpupdate for the user immediately .
* TODO : This should be scheduled to reapply every 90 to 120 minutes .
* Logoff will need to handle cancelling these events though , and
* multiple timers cannot be run for the same user , even if there are
* multiple active sessions .
*/
req = samba_runcmd_send ( ctx , global_event_context ( ) ,
timeval_zero ( ) , 2 , 0 ,
gpupdate_cmd ,
" -s " ,
smbconf ,
" --target=User " ,
" -U " ,
user ,
NULL ) ;
if ( req = = NULL ) {
DBG_ERR ( " Failed to execute the gpupdate command \n " ) ;
return ;
}
tevent_req_set_callback ( req , gpupdate_cmd_done , NULL ) ;
}
2022-10-21 20:01:41 +03:00
static void gpupdate_cmd_done ( struct tevent_req * subreq )
{
int sys_errno ;
int ret ;
ret = samba_runcmd_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " gpupdate failed with exit status %d \n " , sys_errno ) ;
}
}