2005-03-24 02:26:33 +03:00
/*
* Unix SMB / CIFS implementation .
* RPC Pipe client / server routines
2005-09-30 21:13:37 +04:00
*
2005-06-14 19:40:51 +04:00
* Copyright ( C ) Marcin Krzysztof Porwit 2005.
2005-09-30 21:13:37 +04:00
*
* Largely Rewritten ( Again ) by :
* Copyright ( C ) Gerald ( Jerry ) Carter 2005.
2005-03-24 02:26:33 +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
* the Free Software Foundation ; either version 2 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 , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_SRV
2005-09-30 21:13:37 +04:00
struct service_control_op {
2005-06-15 04:54:43 +04:00
const char * name ;
SERVICE_CONTROL_OPS * ops ;
2005-06-14 07:17:31 +04:00
} ;
2005-10-06 21:48:03 +04:00
# define SVCCTL_NUM_INTERNAL_SERVICES 4
/* handle external services */
2005-09-30 21:13:37 +04:00
extern SERVICE_CONTROL_OPS rcinit_svc_ops ;
2005-10-06 21:48:03 +04:00
/* builtin services (see service_db.c and services/svc_*.c */
extern SERVICE_CONTROL_OPS spoolss_svc_ops ;
2005-09-30 21:13:37 +04:00
extern SERVICE_CONTROL_OPS netlogon_svc_ops ;
extern SERVICE_CONTROL_OPS winreg_svc_ops ;
2005-10-06 21:48:03 +04:00
extern SERVICE_CONTROL_OPS wins_svc_ops ;
/* make sure this number patches the number of builtin
SERVICE_CONTROL_OPS structure listed above */
# define SVCCTL_NUM_INTERNAL_SERVICES 4
2005-03-24 02:26:33 +03:00
2005-09-30 21:13:37 +04:00
struct service_control_op * svcctl_ops ;
static struct generic_mapping scm_generic_map =
{ SC_MANAGER_READ_ACCESS , SC_MANAGER_WRITE_ACCESS , SC_MANAGER_EXECUTE_ACCESS , SC_MANAGER_ALL_ACCESS } ;
static struct generic_mapping svc_generic_map =
{ SERVICE_READ_ACCESS , SERVICE_WRITE_ACCESS , SERVICE_EXECUTE_ACCESS , SERVICE_ALL_ACCESS } ;
2005-06-15 00:11:59 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-09-30 21:13:37 +04:00
BOOL init_service_op_table ( void )
{
const char * * service_list = lp_svcctl_list ( ) ;
2005-10-06 21:48:03 +04:00
int num_services = SVCCTL_NUM_INTERNAL_SERVICES + str_list_count ( service_list ) ;
2005-09-30 21:13:37 +04:00
int i ;
if ( ! ( svcctl_ops = TALLOC_ARRAY ( NULL , struct service_control_op , num_services + 1 ) ) ) {
DEBUG ( 0 , ( " init_service_op_table: talloc() failed! \n " ) ) ;
return False ;
}
/* services listed in smb.conf get the rc.init interface */
2006-02-08 18:09:09 +03:00
for ( i = 0 ; service_list & & service_list [ i ] ; i + + ) {
2005-09-30 21:13:37 +04:00
svcctl_ops [ i ] . name = talloc_strdup ( svcctl_ops , service_list [ i ] ) ;
svcctl_ops [ i ] . ops = & rcinit_svc_ops ;
}
/* add builtin services */
svcctl_ops [ i ] . name = talloc_strdup ( svcctl_ops , " Spooler " ) ;
svcctl_ops [ i ] . ops = & spoolss_svc_ops ;
i + + ;
svcctl_ops [ i ] . name = talloc_strdup ( svcctl_ops , " NETLOGON " ) ;
svcctl_ops [ i ] . ops = & netlogon_svc_ops ;
i + + ;
svcctl_ops [ i ] . name = talloc_strdup ( svcctl_ops , " RemoteRegistry " ) ;
svcctl_ops [ i ] . ops = & winreg_svc_ops ;
i + + ;
2005-10-06 21:48:03 +04:00
svcctl_ops [ i ] . name = talloc_strdup ( svcctl_ops , " WINS " ) ;
svcctl_ops [ i ] . ops = & wins_svc_ops ;
i + + ;
2005-09-30 21:13:37 +04:00
/* NULL terminate the array */
svcctl_ops [ i ] . name = NULL ;
svcctl_ops [ i ] . ops = NULL ;
return True ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct service_control_op * find_service_by_name ( const char * name )
{
int i ;
for ( i = 0 ; svcctl_ops [ i ] . name ; i + + ) {
if ( strequal ( name , svcctl_ops [ i ] . name ) )
return & svcctl_ops [ i ] ;
}
return NULL ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-15 00:11:59 +04:00
static NTSTATUS svcctl_access_check ( SEC_DESC * sec_desc , NT_USER_TOKEN * token ,
uint32 access_desired , uint32 * access_granted )
{
NTSTATUS result ;
2005-09-14 16:49:24 +04:00
2005-09-16 18:47:21 +04:00
if ( geteuid ( ) = = sec_initial_uid ( ) ) {
2005-09-30 21:13:37 +04:00
DEBUG ( 5 , ( " svcctl_access_check: using root's token \n " ) ) ;
token = get_root_nt_token ( ) ;
2005-09-16 18:47:21 +04:00
}
2005-06-15 00:11:59 +04:00
se_access_check ( sec_desc , token , access_desired , access_granted , & result ) ;
2005-09-14 16:49:24 +04:00
2005-06-15 00:11:59 +04:00
return result ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static SEC_DESC * construct_scm_sd ( TALLOC_CTX * ctx )
{
SEC_ACE ace [ 2 ] ;
SEC_ACCESS mask ;
size_t i = 0 ;
SEC_DESC * sd ;
SEC_ACL * acl ;
2005-09-30 21:13:37 +04:00
size_t sd_size ;
2005-06-15 00:11:59 +04:00
/* basic access for Everyone */
init_sec_access ( & mask , SC_MANAGER_READ_ACCESS ) ;
init_sec_ace ( & ace [ i + + ] , & global_sid_World , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
/* Full Access 'BUILTIN\Administrators' */
init_sec_access ( & mask , SC_MANAGER_ALL_ACCESS ) ;
init_sec_ace ( & ace [ i + + ] , & global_sid_Builtin_Administrators , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
/* create the security descriptor */
if ( ! ( acl = make_sec_acl ( ctx , NT4_ACL_REVISION , i , ace ) ) )
return NULL ;
if ( ! ( sd = make_sec_desc ( ctx , SEC_DESC_REVISION , SEC_DESC_SELF_RELATIVE , NULL , NULL , NULL , acl , & sd_size ) ) )
return NULL ;
return sd ;
}
/******************************************************************
free ( ) function for REGISTRY_KEY
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void free_service_handle_info ( void * ptr )
{
2005-09-30 21:13:37 +04:00
TALLOC_FREE ( ptr ) ;
2005-06-15 00:11:59 +04:00
}
/******************************************************************
Find a registry key handle and return a SERVICE_INFO
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static SERVICE_INFO * find_service_info_by_hnd ( pipes_struct * p , POLICY_HND * hnd )
{
SERVICE_INFO * service_info = NULL ;
2005-12-03 09:46:46 +03:00
if ( ! find_policy_by_hnd ( p , hnd , ( void * * ) ( void * ) & service_info ) ) {
2005-06-15 00:11:59 +04:00
DEBUG ( 2 , ( " find_service_info_by_hnd: handle not found " ) ) ;
return NULL ;
2005-06-14 07:17:31 +04:00
}
2005-06-15 00:11:59 +04:00
return service_info ;
}
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/******************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-09-30 21:13:37 +04:00
static WERROR create_open_service_handle ( pipes_struct * p , POLICY_HND * handle , uint32 type ,
2005-06-15 00:11:59 +04:00
const char * service , uint32 access_granted )
{
SERVICE_INFO * info = NULL ;
2005-06-15 20:32:12 +04:00
WERROR result = WERR_OK ;
2005-09-30 21:13:37 +04:00
struct service_control_op * s_op ;
2005-06-15 00:11:59 +04:00
2005-09-30 21:13:37 +04:00
if ( ! ( info = TALLOC_ZERO_P ( NULL , SERVICE_INFO ) ) )
2005-06-15 00:11:59 +04:00
return WERR_NOMEM ;
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/* the Service Manager has a NULL name */
2005-09-30 21:13:37 +04:00
info - > type = SVC_HANDLE_IS_SCM ;
switch ( type ) {
case SVC_HANDLE_IS_SCM :
2005-06-15 00:11:59 +04:00
info - > type = SVC_HANDLE_IS_SCM ;
2005-09-30 21:13:37 +04:00
break ;
2005-06-15 04:54:43 +04:00
2005-09-30 21:13:37 +04:00
case SVC_HANDLE_IS_DBLOCK :
info - > type = SVC_HANDLE_IS_DBLOCK ;
break ;
case SVC_HANDLE_IS_SERVICE :
2005-06-15 00:11:59 +04:00
info - > type = SVC_HANDLE_IS_SERVICE ;
/* lookup the SERVICE_CONTROL_OPS */
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
if ( ! ( s_op = find_service_by_name ( service ) ) ) {
2005-06-15 20:32:12 +04:00
result = WERR_NO_SUCH_SERVICE ;
goto done ;
}
2005-09-30 21:13:37 +04:00
info - > ops = s_op - > ops ;
2005-06-15 20:32:12 +04:00
2005-09-30 21:13:37 +04:00
if ( ! ( info - > name = talloc_strdup ( info , s_op - > name ) ) ) {
2005-06-15 20:32:12 +04:00
result = WERR_NOMEM ;
goto done ;
2005-06-14 07:17:31 +04:00
}
2005-09-30 21:13:37 +04:00
break ;
default :
result = WERR_NO_SUCH_SERVICE ;
goto done ;
2005-06-15 00:11:59 +04:00
}
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
info - > access_granted = access_granted ;
/* store the SERVICE_INFO and create an open handle */
if ( ! create_policy_hnd ( p , handle , free_service_handle_info , info ) ) {
2005-06-15 20:32:12 +04:00
result = WERR_ACCESS_DENIED ;
goto done ;
2005-06-15 00:11:59 +04:00
}
2005-06-15 20:32:12 +04:00
done :
if ( ! W_ERROR_IS_OK ( result ) )
free_service_handle_info ( info ) ;
return result ;
2005-06-15 00:11:59 +04:00
}
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
WERROR _svcctl_open_scmanager ( pipes_struct * p , SVCCTL_Q_OPEN_SCMANAGER * q_u , SVCCTL_R_OPEN_SCMANAGER * r_u )
{
SEC_DESC * sec_desc ;
uint32 access_granted = 0 ;
NTSTATUS status ;
/* perform access checks */
if ( ! ( sec_desc = construct_scm_sd ( p - > mem_ctx ) ) )
return WERR_NOMEM ;
2005-09-30 21:13:37 +04:00
se_map_generic ( & q_u - > access , & scm_generic_map ) ;
2005-06-15 00:11:59 +04:00
status = svcctl_access_check ( sec_desc , p - > pipe_user . nt_user_token , q_u - > access , & access_granted ) ;
if ( ! NT_STATUS_IS_OK ( status ) )
return ntstatus_to_werror ( status ) ;
2005-09-30 21:13:37 +04:00
return create_open_service_handle ( p , & r_u - > handle , SVC_HANDLE_IS_SCM , NULL , access_granted ) ;
2005-06-15 00:11:59 +04:00
}
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
WERROR _svcctl_open_service ( pipes_struct * p , SVCCTL_Q_OPEN_SERVICE * q_u , SVCCTL_R_OPEN_SERVICE * r_u )
{
SEC_DESC * sec_desc ;
uint32 access_granted = 0 ;
NTSTATUS status ;
pstring service ;
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
rpcstr_pull ( service , q_u - > servicename . buffer , sizeof ( service ) , q_u - > servicename . uni_str_len * 2 , 0 ) ;
DEBUG ( 5 , ( " _svcctl_open_service: Attempting to open Service [%s], \n " , service ) ) ;
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/* based on my tests you can open a service if you have a valid scm handle */
2005-08-03 00:19:42 +04:00
if ( ! find_service_info_by_hnd ( p , & q_u - > handle ) )
2005-06-15 00:11:59 +04:00
return WERR_BADFID ;
2005-09-30 21:13:37 +04:00
/* perform access checks. Use the root token in order to ensure that we
retreive the security descriptor */
2005-06-15 00:11:59 +04:00
2005-09-30 21:13:37 +04:00
if ( ! ( sec_desc = svcctl_get_secdesc ( p - > mem_ctx , service , get_root_nt_token ( ) ) ) )
2005-06-15 00:11:59 +04:00
return WERR_NOMEM ;
2005-09-30 21:13:37 +04:00
se_map_generic ( & q_u - > access , & svc_generic_map ) ;
2005-06-15 00:11:59 +04:00
status = svcctl_access_check ( sec_desc , p - > pipe_user . nt_user_token , q_u - > access , & access_granted ) ;
if ( ! NT_STATUS_IS_OK ( status ) )
return ntstatus_to_werror ( status ) ;
2005-09-30 21:13:37 +04:00
return create_open_service_handle ( p , & r_u - > handle , SVC_HANDLE_IS_SERVICE , service , access_granted ) ;
2005-06-15 00:11:59 +04:00
}
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
WERROR _svcctl_close_service ( pipes_struct * p , SVCCTL_Q_CLOSE_SERVICE * q_u , SVCCTL_R_CLOSE_SERVICE * r_u )
{
return close_policy_hnd ( p , & q_u - > handle ) ? WERR_OK : WERR_BADFID ;
2005-06-14 07:17:31 +04:00
}
2005-06-15 00:11:59 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_get_display_name ( pipes_struct * p , SVCCTL_Q_GET_DISPLAY_NAME * q_u , SVCCTL_R_GET_DISPLAY_NAME * r_u )
2005-06-14 07:17:31 +04:00
{
2005-06-15 00:11:59 +04:00
fstring service ;
2005-09-30 21:13:37 +04:00
const char * display_name ;
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
/* can only use an SCM handle here */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SCM ) )
return WERR_BADFID ;
rpcstr_pull ( service , q_u - > servicename . buffer , sizeof ( service ) , q_u - > servicename . uni_str_len * 2 , 0 ) ;
2005-09-30 21:13:37 +04:00
display_name = svcctl_lookup_dispname ( service , p - > pipe_user . nt_user_token ) ;
init_svcctl_r_get_display_name ( r_u , display_name ) ;
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
return WERR_OK ;
2005-06-14 07:17:31 +04:00
}
2005-06-15 00:11:59 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
WERROR _svcctl_query_status ( pipes_struct * p , SVCCTL_Q_QUERY_STATUS * q_u , SVCCTL_R_QUERY_STATUS * r_u )
2005-06-14 07:17:31 +04:00
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
if ( ! ( info - > access_granted & SC_RIGHT_SVC_QUERY_STATUS ) )
return WERR_ACCESS_DENIED ;
2005-06-15 19:18:18 +04:00
/* try the service specific status call */
2005-09-30 21:13:37 +04:00
return info - > ops - > service_status ( info - > name , & r_u - > svc_status ) ;
2005-06-14 07:17:31 +04:00
}
2005-09-30 21:13:37 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
static int enumerate_status ( TALLOC_CTX * ctx , ENUM_SERVICES_STATUS * * status , NT_USER_TOKEN * token )
2005-06-14 07:17:31 +04:00
{
2005-09-30 21:13:37 +04:00
int num_services = 0 ;
int i ;
ENUM_SERVICES_STATUS * st ;
const char * display_name ;
/* just count */
while ( svcctl_ops [ num_services ] . name )
num_services + + ;
if ( ! ( st = TALLOC_ARRAY ( ctx , ENUM_SERVICES_STATUS , num_services ) ) ) {
DEBUG ( 0 , ( " enumerate_status: talloc() failed! \n " ) ) ;
return - 1 ;
2005-06-14 07:17:31 +04:00
}
2005-03-24 02:26:33 +03:00
2005-09-30 21:13:37 +04:00
for ( i = 0 ; i < num_services ; i + + ) {
init_unistr ( & st [ i ] . servicename , svcctl_ops [ i ] . name ) ;
display_name = svcctl_lookup_dispname ( svcctl_ops [ i ] . name , token ) ;
init_unistr ( & st [ i ] . displayname , display_name ) ;
svcctl_ops [ i ] . ops - > service_status ( svcctl_ops [ i ] . name , & st [ i ] . status ) ;
}
2005-03-24 02:26:33 +03:00
2005-09-30 21:13:37 +04:00
* status = st ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
return num_services ;
2005-06-14 07:17:31 +04:00
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_enum_services_status ( pipes_struct * p , SVCCTL_Q_ENUM_SERVICES_STATUS * q_u , SVCCTL_R_ENUM_SERVICES_STATUS * r_u )
{
ENUM_SERVICES_STATUS * services = NULL ;
2006-03-14 23:32:27 +03:00
int num_services ;
2005-06-14 07:17:31 +04:00
int i = 0 ;
2005-08-03 00:33:50 +04:00
size_t buffer_size = 0 ;
2005-06-14 07:17:31 +04:00
WERROR result = WERR_OK ;
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
2005-09-30 21:13:37 +04:00
NT_USER_TOKEN * token = p - > pipe_user . nt_user_token ;
2005-06-15 00:11:59 +04:00
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SCM ) )
return WERR_BADFID ;
2006-03-13 21:59:31 +03:00
if ( ! ( info - > access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE ) ) {
2005-06-15 00:11:59 +04:00
return WERR_ACCESS_DENIED ;
2006-03-13 21:59:31 +03:00
}
2005-06-14 07:17:31 +04:00
2006-03-13 21:59:31 +03:00
num_services = enumerate_status ( p - > mem_ctx , & services , token ) ;
2006-03-14 23:32:27 +03:00
if ( num_services = = - 1 ) {
2005-08-03 00:33:50 +04:00
return WERR_NOMEM ;
2006-03-13 21:59:31 +03:00
}
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
for ( i = 0 ; i < num_services ; i + + ) {
2005-08-03 00:33:50 +04:00
buffer_size + = svcctl_sizeof_enum_services_status ( & services [ i ] ) ;
2005-06-14 07:17:31 +04:00
}
2005-03-24 02:26:33 +03:00
buffer_size + = buffer_size % 4 ;
2005-06-14 07:17:31 +04:00
if ( buffer_size > q_u - > buffer_size ) {
2005-09-30 21:13:37 +04:00
num_services = 0 ;
2005-03-24 02:26:33 +03:00
result = WERR_MORE_DATA ;
}
2005-06-14 07:17:31 +04:00
rpcbuf_init ( & r_u - > buffer , q_u - > buffer_size , p - > mem_ctx ) ;
2005-03-24 02:26:33 +03:00
if ( W_ERROR_IS_OK ( result ) ) {
2005-09-30 21:13:37 +04:00
for ( i = 0 ; i < num_services ; i + + )
2005-03-24 02:26:33 +03:00
svcctl_io_enum_services_status ( " " , & services [ i ] , & r_u - > buffer , 0 ) ;
}
2005-06-14 07:17:31 +04:00
2005-03-24 02:26:33 +03:00
r_u - > needed = ( buffer_size > q_u - > buffer_size ) ? buffer_size : q_u - > buffer_size ;
2006-03-14 23:32:27 +03:00
r_u - > returned = ( uint32 ) num_services ;
2005-03-24 02:26:33 +03:00
if ( ! ( r_u - > resume = TALLOC_P ( p - > mem_ctx , uint32 ) ) )
return WERR_NOMEM ;
* r_u - > resume = 0x0 ;
return result ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_start_service ( pipes_struct * p , SVCCTL_Q_START_SERVICE * q_u , SVCCTL_R_START_SERVICE * r_u )
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
if ( ! ( info - > access_granted & SC_RIGHT_SVC_START ) )
return WERR_ACCESS_DENIED ;
2005-09-30 21:13:37 +04:00
return info - > ops - > start_service ( info - > name ) ;
2005-03-24 02:26:33 +03:00
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_control_service ( pipes_struct * p , SVCCTL_Q_CONTROL_SERVICE * q_u , SVCCTL_R_CONTROL_SERVICE * r_u )
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
/* perform access checks */
2005-09-30 21:13:37 +04:00
2005-06-15 00:11:59 +04:00
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
2005-09-30 21:13:37 +04:00
switch ( q_u - > control ) {
case SVCCTL_CONTROL_STOP :
if ( ! ( info - > access_granted & SC_RIGHT_SVC_STOP ) )
return WERR_ACCESS_DENIED ;
return info - > ops - > stop_service ( info - > name , & r_u - > svc_status ) ;
2005-06-15 00:11:59 +04:00
2005-09-30 21:13:37 +04:00
case SVCCTL_CONTROL_INTERROGATE :
if ( ! ( info - > access_granted & SC_RIGHT_SVC_QUERY_STATUS ) )
return WERR_ACCESS_DENIED ;
return info - > ops - > service_status ( info - > name , & r_u - > svc_status ) ;
}
/* default control action */
return WERR_ACCESS_DENIED ;
2005-03-24 02:26:33 +03:00
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_enum_dependent_services ( pipes_struct * p , SVCCTL_Q_ENUM_DEPENDENT_SERVICES * q_u , SVCCTL_R_ENUM_DEPENDENT_SERVICES * r_u )
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
2005-03-24 02:26:33 +03:00
2005-06-15 00:11:59 +04:00
if ( ! ( info - > access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS ) )
return WERR_ACCESS_DENIED ;
2005-03-24 02:26:33 +03:00
/* we have to set the outgoing buffer size to the same as the
incoming buffer size ( even in the case of failure */
rpcbuf_init ( & r_u - > buffer , q_u - > buffer_size , p - > mem_ctx ) ;
r_u - > needed = q_u - > buffer_size ;
/* no dependent services...basically a stub function */
r_u - > returned = 0 ;
return WERR_OK ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
WERROR _svcctl_query_service_status_ex ( pipes_struct * p , SVCCTL_Q_QUERY_SERVICE_STATUSEX * q_u , SVCCTL_R_QUERY_SERVICE_STATUSEX * r_u )
2005-03-24 02:26:33 +03:00
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
2005-09-30 21:13:37 +04:00
uint32 buffer_size ;
2005-06-15 00:11:59 +04:00
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
if ( ! ( info - > access_granted & SC_RIGHT_SVC_QUERY_STATUS ) )
return WERR_ACCESS_DENIED ;
2005-06-14 07:17:31 +04:00
/* we have to set the outgoing buffer size to the same as the
2005-09-30 21:13:37 +04:00
incoming buffer size ( even in the case of failure ) */
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
rpcbuf_init ( & r_u - > buffer , q_u - > buffer_size , p - > mem_ctx ) ;
r_u - > needed = q_u - > buffer_size ;
switch ( q_u - > level ) {
case SVC_STATUS_PROCESS_INFO :
{
SERVICE_STATUS_PROCESS svc_stat_proc ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
/* Get the status of the service.. */
info - > ops - > service_status ( info - > name , & svc_stat_proc . status ) ;
svc_stat_proc . process_id = sys_getpid ( ) ;
svc_stat_proc . service_flags = 0x0 ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
svcctl_io_service_status_process ( " " , & svc_stat_proc , & r_u - > buffer , 0 ) ;
buffer_size = sizeof ( SERVICE_STATUS_PROCESS ) ;
break ;
}
default :
return WERR_UNKNOWN_LEVEL ;
2005-06-14 07:17:31 +04:00
}
2005-03-24 02:26:33 +03:00
2005-09-30 21:13:37 +04:00
buffer_size + = buffer_size % 4 ;
r_u - > needed = ( buffer_size > q_u - > buffer_size ) ? buffer_size : q_u - > buffer_size ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
if ( buffer_size > q_u - > buffer_size )
return WERR_MORE_DATA ;
return WERR_OK ;
}
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
static WERROR fill_svc_config ( TALLOC_CTX * ctx , const char * name , SERVICE_CONFIG * config , NT_USER_TOKEN * token )
{
REGVAL_CTR * values ;
REGISTRY_VALUE * val ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
/* retrieve the registry values for this service */
if ( ! ( values = svcctl_fetch_regvalues ( name , token ) ) )
return WERR_REG_CORRUPT ;
/* now fill in the individual values */
config - > displayname = TALLOC_ZERO_P ( ctx , UNISTR2 ) ;
if ( ( val = regval_ctr_getvalue ( values , " DisplayName " ) ) ! = NULL )
init_unistr2 ( config - > displayname , regval_sz ( val ) , UNI_STR_TERMINATE ) ;
else
init_unistr2 ( config - > displayname , name , UNI_STR_TERMINATE ) ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
if ( ( val = regval_ctr_getvalue ( values , " ObjectName " ) ) ! = NULL ) {
config - > startname = TALLOC_ZERO_P ( ctx , UNISTR2 ) ;
init_unistr2 ( config - > startname , regval_sz ( val ) , UNI_STR_TERMINATE ) ;
}
if ( ( val = regval_ctr_getvalue ( values , " ImagePath " ) ) ! = NULL ) {
config - > executablepath = TALLOC_ZERO_P ( ctx , UNISTR2 ) ;
init_unistr2 ( config - > executablepath , regval_sz ( val ) , UNI_STR_TERMINATE ) ;
}
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
/* a few hard coded values */
/* loadordergroup and dependencies are empty */
config - > tag_id = 0x00000000 ; /* unassigned loadorder group */
config - > service_type = SVCCTL_WIN32_OWN_PROC ;
config - > error_control = SVCCTL_SVC_ERROR_NORMAL ;
2005-06-14 07:17:31 +04:00
2005-12-11 07:21:34 +03:00
/* set the start type. NetLogon and WINS are disabled to prevent
the client from showing the " Start " button ( if of course the services
are not running */
if ( strequal ( name , " NETLOGON " ) & & ( lp_servicenumber ( name ) = = - 1 ) )
config - > start_type = SVCCTL_DISABLED ;
else if ( strequal ( name , " WINS " ) & & ( ! lp_wins_support ( ) ) )
config - > start_type = SVCCTL_DISABLED ;
else
config - > start_type = SVCCTL_DEMAND_START ;
2005-09-30 21:13:37 +04:00
TALLOC_FREE ( values ) ;
2005-06-14 07:17:31 +04:00
return WERR_OK ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_query_service_config ( pipes_struct * p , SVCCTL_Q_QUERY_SERVICE_CONFIG * q_u , SVCCTL_R_QUERY_SERVICE_CONFIG * r_u )
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
2005-09-30 21:13:37 +04:00
uint32 buffer_size ;
WERROR wresult ;
2005-06-15 00:11:59 +04:00
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
if ( ! ( info - > access_granted & SC_RIGHT_SVC_QUERY_CONFIG ) )
return WERR_ACCESS_DENIED ;
2005-06-14 07:17:31 +04:00
2005-03-24 02:26:33 +03:00
/* we have to set the outgoing buffer size to the same as the
incoming buffer size ( even in the case of failure */
r_u - > needed = q_u - > buffer_size ;
2005-09-30 21:13:37 +04:00
wresult = fill_svc_config ( p - > mem_ctx , info - > name , & r_u - > config , p - > pipe_user . nt_user_token ) ;
if ( ! W_ERROR_IS_OK ( wresult ) )
return wresult ;
buffer_size = svcctl_sizeof_service_config ( & r_u - > config ) ;
r_u - > needed = ( buffer_size > q_u - > buffer_size ) ? buffer_size : q_u - > buffer_size ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
if ( buffer_size > q_u - > buffer_size ) {
ZERO_STRUCTP ( & r_u - > config ) ;
return WERR_INSUFFICIENT_BUFFER ;
2005-06-14 07:17:31 +04:00
}
2005-09-30 21:13:37 +04:00
2005-06-14 07:17:31 +04:00
return WERR_OK ;
2005-03-24 02:26:33 +03:00
}
2005-06-14 07:17:31 +04:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_query_service_config2 ( pipes_struct * p , SVCCTL_Q_QUERY_SERVICE_CONFIG2 * q_u , SVCCTL_R_QUERY_SERVICE_CONFIG2 * r_u )
{
2005-06-15 00:11:59 +04:00
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
2005-09-30 21:13:37 +04:00
uint32 buffer_size ;
2005-06-15 00:11:59 +04:00
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
if ( ! ( info - > access_granted & SC_RIGHT_SVC_QUERY_CONFIG ) )
return WERR_ACCESS_DENIED ;
2005-06-14 07:17:31 +04:00
/* we have to set the outgoing buffer size to the same as the
incoming buffer size ( even in the case of failure */
2005-03-24 02:26:33 +03:00
2005-09-30 21:13:37 +04:00
rpcbuf_init ( & r_u - > buffer , q_u - > buffer_size , p - > mem_ctx ) ;
r_u - > needed = q_u - > buffer_size ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
switch ( q_u - > level ) {
case SERVICE_CONFIG_DESCRIPTION :
{
SERVICE_DESCRIPTION desc_buf ;
const char * description ;
description = svcctl_lookup_description ( info - > name , p - > pipe_user . nt_user_token ) ;
ZERO_STRUCTP ( & desc_buf ) ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
init_service_description_buffer ( & desc_buf , description ) ;
svcctl_io_service_description ( " " , & desc_buf , & r_u - > buffer , 0 ) ;
buffer_size = svcctl_sizeof_service_description ( & desc_buf ) ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
break ;
2005-06-14 07:17:31 +04:00
}
2005-09-30 21:13:37 +04:00
break ;
case SERVICE_CONFIG_FAILURE_ACTIONS :
{
SERVICE_FAILURE_ACTIONS actions ;
/* nothing to say...just service the request */
ZERO_STRUCTP ( & actions ) ;
svcctl_io_service_fa ( " " , & actions , & r_u - > buffer , 0 ) ;
buffer_size = svcctl_sizeof_service_fa ( & actions ) ;
break ;
2005-06-14 07:17:31 +04:00
}
2005-09-30 21:13:37 +04:00
break ;
default :
return WERR_UNKNOWN_LEVEL ;
}
buffer_size + = buffer_size % 4 ;
r_u - > needed = ( buffer_size > q_u - > buffer_size ) ? buffer_size : q_u - > buffer_size ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
if ( buffer_size > q_u - > buffer_size )
return WERR_INSUFFICIENT_BUFFER ;
2005-06-14 07:17:31 +04:00
2005-09-30 21:13:37 +04:00
return WERR_OK ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_lock_service_db ( pipes_struct * p , SVCCTL_Q_LOCK_SERVICE_DB * q_u , SVCCTL_R_LOCK_SERVICE_DB * r_u )
{
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
/* perform access checks */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SCM ) )
return WERR_BADFID ;
if ( ! ( info - > access_granted & SC_RIGHT_MGR_LOCK ) )
return WERR_ACCESS_DENIED ;
/* Just open a handle. Doesn't actually lock anything */
return create_open_service_handle ( p , & r_u - > h_lock , SVC_HANDLE_IS_DBLOCK , NULL , 0 ) ;
;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_unlock_service_db ( pipes_struct * p , SVCCTL_Q_UNLOCK_SERVICE_DB * q_u , SVCCTL_R_UNLOCK_SERVICE_DB * r_u )
{
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > h_lock ) ;
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_DBLOCK ) )
return WERR_BADFID ;
return close_policy_hnd ( p , & q_u - > h_lock ) ? WERR_OK : WERR_BADFID ;
2005-06-14 07:17:31 +04:00
}
2006-01-13 23:24:50 +03:00
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_query_service_sec ( pipes_struct * p , SVCCTL_Q_QUERY_SERVICE_SEC * q_u , SVCCTL_R_QUERY_SERVICE_SEC * r_u )
{
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
SEC_DESC * sec_desc ;
/* only support the SCM and individual services */
if ( ! info | | ! ( info - > type & ( SVC_HANDLE_IS_SERVICE | SVC_HANDLE_IS_SCM ) ) )
return WERR_BADFID ;
/* check access reights (according to MSDN) */
if ( ! ( info - > access_granted & STD_RIGHT_READ_CONTROL_ACCESS ) )
return WERR_ACCESS_DENIED ;
/* TODO: handle something besides DACL_SECURITY_INFORMATION */
if ( ( q_u - > security_flags & DACL_SECURITY_INFORMATION ) ! = DACL_SECURITY_INFORMATION )
return WERR_INVALID_PARAM ;
/* lookup the security descriptor and marshall it up for a reply */
if ( ! ( sec_desc = svcctl_get_secdesc ( p - > mem_ctx , info - > name , get_root_nt_token ( ) ) ) )
return WERR_NOMEM ;
r_u - > needed = sec_desc_size ( sec_desc ) ;
if ( r_u - > needed > q_u - > buffer_size ) {
ZERO_STRUCTP ( & r_u - > buffer ) ;
return WERR_INSUFFICIENT_BUFFER ;
}
rpcbuf_init ( & r_u - > buffer , q_u - > buffer_size , p - > mem_ctx ) ;
if ( ! sec_io_desc ( " " , & sec_desc , & r_u - > buffer . prs , 0 ) )
return WERR_NOMEM ;
return WERR_OK ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR _svcctl_set_service_sec ( pipes_struct * p , SVCCTL_Q_SET_SERVICE_SEC * q_u , SVCCTL_R_SET_SERVICE_SEC * r_u )
{
SERVICE_INFO * info = find_service_info_by_hnd ( p , & q_u - > handle ) ;
SEC_DESC * sec_desc = NULL ;
uint32 required_access ;
if ( ! info | | ! ( info - > type & ( SVC_HANDLE_IS_SERVICE | SVC_HANDLE_IS_SCM ) ) )
return WERR_BADFID ;
2006-01-13 23:26:59 +03:00
/* can't set the security de4scriptor on the ServiceControlManager */
if ( info - > type = = SVC_HANDLE_IS_SCM )
return WERR_ACCESS_DENIED ;
2006-01-13 23:24:50 +03:00
/* check the access on the open handle */
switch ( q_u - > security_flags ) {
case DACL_SECURITY_INFORMATION :
required_access = STD_RIGHT_WRITE_DAC_ACCESS ;
break ;
case OWNER_SECURITY_INFORMATION :
case GROUP_SECURITY_INFORMATION :
required_access = STD_RIGHT_WRITE_OWNER_ACCESS ;
break ;
case SACL_SECURITY_INFORMATION :
return WERR_INVALID_PARAM ;
default :
return WERR_INVALID_PARAM ;
}
if ( ! ( info - > access_granted & required_access ) )
return WERR_ACCESS_DENIED ;
/* read the security descfriptor */
if ( ! sec_io_desc ( " " , & sec_desc , & q_u - > buffer . prs , 0 ) )
return WERR_NOMEM ;
/* store the new SD */
if ( ! svcctl_set_secdesc ( p - > mem_ctx , info - > name , sec_desc , p - > pipe_user . nt_user_token ) )
return WERR_ACCESS_DENIED ;
return WERR_OK ;
}