2005-03-24 02:26:33 +03:00
/*
* Unix SMB / CIFS implementation .
* RPC Pipe client / server routines
2005-06-14 19:40:51 +04:00
* Copyright ( C ) Gerald ( Jerry ) Carter 2005 ,
* Copyright ( C ) Marcin Krzysztof Porwit 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 .
*/
2005-06-14 07:17:31 +04:00
/* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */
2005-03-24 02:26:33 +03:00
# include "includes.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_SRV
2005-06-14 07:17:31 +04:00
# define SERVICEDB_VERSION_V1 1 /* Will there be more? */
# define INTERNAL_SERVICES_LIST "NETLOGON Spooler"
/* */
/* scripts will execute from the following libdir, if they are in the enable svcctl=<list of scripts> */
/* these should likely be symbolic links. Note that information about them will be extracted from the files themselves */
/* using the LSB standard keynames for various information */
# define SVCCTL_SCRIPT_DIR " / svcctl / "
2005-06-15 04:54:43 +04:00
struct service_control_op_table {
const char * name ;
SERVICE_CONTROL_OPS * ops ;
2005-06-14 07:17:31 +04:00
} ;
2005-06-15 04:54:43 +04:00
extern SERVICE_CONTROL_OPS spoolss_svc_ops ;
2005-03-24 02:26:33 +03:00
2005-06-15 04:54:43 +04:00
struct service_control_op_table svcctl_ops [ ] = {
{ " Spooler " , & spoolss_svc_ops } ,
{ " NETLOGON " , NULL } ,
{ NULL , 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 ;
/* maybe add privilege checks in here later */
se_access_check ( sec_desc , token , access_desired , access_granted , & result ) ;
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 ;
uint32 sd_size ;
/* 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 ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static SEC_DESC * construct_service_sd ( TALLOC_CTX * ctx )
{
SEC_ACE ace [ 4 ] ;
SEC_ACCESS mask ;
size_t i = 0 ;
SEC_DESC * sd ;
SEC_ACL * acl ;
uint32 sd_size ;
/* basic access for Everyone */
init_sec_access ( & mask , SERVICE_READ_ACCESS ) ;
init_sec_ace ( & ace [ i + + ] , & global_sid_World , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
init_sec_access ( & mask , SERVICE_EXECUTE_ACCESS ) ;
init_sec_ace ( & ace [ i + + ] , & global_sid_Builtin_Power_Users , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
init_sec_access ( & mask , SERVICE_ALL_ACCESS ) ;
init_sec_ace ( & ace [ i + + ] , & global_sid_Builtin_Server_Operators , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
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 )
{
SERVICE_INFO * info = ( SERVICE_INFO * ) ptr ;
SAFE_FREE ( info - > name ) ;
SAFE_FREE ( info ) ;
}
/******************************************************************
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 ;
if ( ! find_policy_by_hnd ( p , hnd , ( void * * ) & service_info ) ) {
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
/******************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static WERROR create_open_service_handle ( pipes_struct * p , POLICY_HND * handle ,
const char * service , uint32 access_granted )
{
SERVICE_INFO * info = NULL ;
2005-06-15 20:32:12 +04:00
WERROR result = WERR_OK ;
2005-06-15 00:11:59 +04:00
if ( ! ( info = SMB_MALLOC_P ( SERVICE_INFO ) ) )
return WERR_NOMEM ;
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
ZERO_STRUCTP ( info ) ;
/* the Service Manager has a NULL name */
if ( ! service ) {
info - > type = SVC_HANDLE_IS_SCM ;
} else {
2005-06-15 04:54:43 +04:00
int i ;
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-06-15 00:11:59 +04:00
for ( i = 0 ; svcctl_ops [ i ] . name ; i + + ) {
2005-06-15 20:32:12 +04:00
if ( strequal ( svcctl_ops [ i ] . name , service ) ) {
2005-06-15 04:54:43 +04:00
info - > ops = svcctl_ops [ i ] . ops ;
2005-06-15 20:32:12 +04:00
break ;
}
}
if ( ! svcctl_ops [ i ] . name ) {
result = WERR_NO_SUCH_SERVICE ;
goto done ;
}
if ( ! ( info - > name = SMB_STRDUP ( service ) ) ) {
result = WERR_NOMEM ;
goto done ;
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
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 ;
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 ) ;
return create_open_service_handle ( p , & r_u - > handle , NULL , access_granted ) ;
}
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 ;
SERVICE_INFO * scm_info ;
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 */
if ( ! ( scm_info = find_service_info_by_hnd ( p , & q_u - > handle ) ) )
return WERR_BADFID ;
/* perform access checks */
if ( ! ( sec_desc = construct_service_sd ( p - > mem_ctx ) ) )
return WERR_NOMEM ;
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 ) ;
#if 0 /* FIXME!!! */
if ( ! get_service_info ( service_tdb , service , info ) ) {
return WERR_NO_SUCH_SERVICE ;
# endif
return create_open_service_handle ( p , & r_u - > handle , service , access_granted ) ;
}
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 ;
fstring displayname ;
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-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
/* need a tdb lookup here or something */
fstrcpy ( displayname , " FIX ME! " ) ;
2005-06-14 07:17:31 +04:00
2005-06-15 00:11:59 +04:00
init_svcctl_r_get_display_name ( r_u , displayname ) ;
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 */
if ( info - > ops )
return info - > ops - > service_status ( & r_u - > svc_status ) ;
/* default action for now */
2005-06-15 00:11:59 +04:00
r_u - > svc_status . type = 0x0020 ;
r_u - > svc_status . state = 0x0004 ;
r_u - > svc_status . controls_accepted = 0x0005 ;
return WERR_OK ;
2005-06-14 07:17:31 +04:00
}
2005-06-15 00:11:59 +04:00
/*********************************************************************
TODO - for internal services , do similar to external services , except
we have to call the right status routine . . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-01 23:58:16 +04:00
static WERROR enum_internal_services ( TALLOC_CTX * tcx , ENUM_SERVICES_STATUS * * svc_ptr , int existing_services , uint32 * added )
2005-06-14 07:17:31 +04:00
{
int num_services = 2 ;
int i = 0 ;
ENUM_SERVICES_STATUS * services = NULL ;
if ( ! svc_ptr | | ! ( * svc_ptr ) )
2005-03-24 02:26:33 +03:00
return WERR_NOMEM ;
2005-06-14 07:17:31 +04:00
services = * svc_ptr ;
#if 0
/* *svc_ptr has the pointer to the array if there is one already. NULL if not. */
if ( ( existing_services > 0 ) & & svc_ptr & & * svc_ptr ) { /* reallocate vs. allocate */
2005-06-15 00:11:59 +04:00
DEBUG ( 8 , ( " enum_internal_services: REALLOCing %d services \n " , num_services ) ) ;
2005-06-14 07:17:31 +04:00
services = TALLOC_REALLOC_ARRAY ( tcx , * svc_ptr , ENUM_SERVICES_STATUS , existing_services + num_services ) ;
if ( ! rsvcs )
return WERR_NOMEM ;
* svc_ptr = services ;
} else {
if ( ! ( services = TALLOC_ARRAY ( tcx , ENUM_SERVICES_STATUS , num_services ) ) )
return WERR_NOMEM ;
}
# endif
if ( existing_services > 0 ) {
i + = existing_services ;
}
2005-06-15 00:11:59 +04:00
DEBUG ( 8 , ( " enum_internal_services: Creating %d services, starting index %d \n " , num_services , existing_services ) ) ;
2005-03-24 02:26:33 +03:00
init_unistr ( & services [ i ] . servicename , " Spooler " ) ;
2005-06-14 07:17:31 +04:00
init_unistr ( & services [ i ] . displayname , " Print Spooler " ) ;
2005-03-24 02:26:33 +03:00
services [ i ] . status . type = 0x110 ;
services [ i ] . status . controls_accepted = 0x0 ;
services [ i ] . status . win32_exit_code = 0x0 ;
services [ i ] . status . service_exit_code = 0x0 ;
services [ i ] . status . check_point = 0x0 ;
services [ i ] . status . wait_hint = 0x0 ;
if ( ! lp_disable_spoolss ( ) )
services [ i ] . status . state = SVCCTL_RUNNING ;
else
services [ i ] . status . state = SVCCTL_STOPPED ;
i + + ;
2005-06-14 07:17:31 +04:00
init_unistr ( & services [ i ] . servicename , " NETLOGON " ) ;
2005-03-24 02:26:33 +03:00
init_unistr ( & services [ i ] . displayname , " Net Logon " ) ;
services [ i ] . status . type = 0x20 ;
services [ i ] . status . controls_accepted = 0x0 ;
services [ i ] . status . win32_exit_code = 0x0 ;
services [ i ] . status . service_exit_code = 0x0 ;
services [ i ] . status . check_point = 0x0 ;
services [ i ] . status . wait_hint = 0x0 ;
if ( lp_servicenumber ( " NETLOGON " ) ! = - 1 )
services [ i ] . status . state = SVCCTL_RUNNING ;
else
services [ i ] . status . state = SVCCTL_STOPPED ;
2005-06-14 07:17:31 +04:00
* added = num_services ;
return WERR_OK ;
}
/********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 ;
uint32 num_int_services = 0 ;
uint32 num_ext_services = 0 ;
int i = 0 ;
size_t buffer_size ;
WERROR result = WERR_OK ;
2005-06-15 00:11:59 +04:00
WERROR ext_result = WERR_OK ;
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_ENUMERATE_SERVICE ) )
return WERR_ACCESS_DENIED ;
2005-06-14 07:17:31 +04:00
/* num_services = str_list_count( lp_enable_svcctl() ); */
/* here's where we'll read the db of external services */
/* _svcctl_read_LSB_data(NULL,NULL); */
/* init_svcctl_db(); */
2005-03-24 02:26:33 +03:00
2005-06-16 04:46:43 +04:00
/* num_int_services = num_internal_services(); */
2005-06-14 07:17:31 +04:00
2005-06-16 04:46:43 +04:00
/* num_ext_services = num_external_services(); */
2005-06-14 07:17:31 +04:00
if ( ! ( services = TALLOC_ARRAY ( p - > mem_ctx , ENUM_SERVICES_STATUS , num_int_services + num_ext_services ) ) )
return WERR_NOMEM ;
2005-06-15 00:11:59 +04:00
result = enum_internal_services ( p - > mem_ctx , & services , 0 , & num_int_services ) ;
2005-06-14 07:17:31 +04:00
if ( W_ERROR_IS_OK ( result ) ) {
DEBUG ( 8 , ( " _svcctl_enum_services_status: Got %d internal services \n " , num_int_services ) ) ;
}
2005-06-16 04:46:43 +04:00
/* ext_result=enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services); */
2005-06-14 07:17:31 +04:00
if ( W_ERROR_IS_OK ( ext_result ) ) {
DEBUG ( 8 , ( " _svcctl_enum_services_status: Got %d external services \n " , num_ext_services ) ) ;
}
DEBUG ( 8 , ( " _svcctl_enum_services_status: total of %d services \n " , num_int_services + num_ext_services ) ) ;
2005-03-24 02:26:33 +03:00
buffer_size = 0 ;
2005-06-14 07:17:31 +04:00
for ( i = 0 ; i < num_int_services + num_ext_services ; i + + ) {
buffer_size + = svcctl_sizeof_enum_services_status ( & services [ i ] ) ;
}
/* */
2005-03-24 02:26:33 +03:00
buffer_size + = buffer_size % 4 ;
2005-06-14 07:17:31 +04:00
DEBUG ( 8 , ( " _svcctl_enum_services_status: buffer size passed %d, we need %d \n " ,
q_u - > buffer_size , buffer_size ) ) ;
if ( buffer_size > q_u - > buffer_size ) {
num_int_services = 0 ;
num_ext_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-06-14 07:17:31 +04:00
for ( i = 0 ; i < num_int_services + num_ext_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 ;
2005-06-14 07:17:31 +04:00
r_u - > returned = num_int_services + num_ext_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-06-15 07:10:36 +04:00
return info - > ops - > start_service ( ) ;
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 */
/* we only support stop so don't get complicated */
if ( ! info | | ( info - > type ! = SVC_HANDLE_IS_SERVICE ) )
return WERR_BADFID ;
if ( q_u - > control ! = SVCCTL_CONTROL_STOP )
return WERR_ACCESS_DENIED ;
if ( ! ( info - > access_granted & SC_RIGHT_SVC_STOP ) )
return WERR_ACCESS_DENIED ;
2005-06-15 07:10:36 +04:00
return info - > ops - > stop_service ( & r_u - > svc_status ) ;
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-14 07:17:31 +04:00
SERVICE_STATUS_PROCESS ssp ;
POLICY_HND * handle ;
2005-06-14 19:40:51 +04:00
SERVICE_INFO * service_info ;
2005-06-14 07:17:31 +04:00
pstring command ;
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-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 */
r_u - > needed = q_u - > buffer_size ;
/* need to find the service name by the handle that is open */
handle = & ( q_u - > handle ) ;
/* get rid of the easy errors */
if ( q_u - > info_level ! = SVC_STATUS_PROCESS_INFO ) {
DEBUG ( 10 , ( " _svcctl_query_service_status_ex : Invalid information level specified \n " ) ) ;
return WERR_UNKNOWN_LEVEL ;
}
service_info = find_service_info_by_hnd ( p , handle ) ;
if ( ! service_info ) {
DEBUG ( 10 , ( " _svcctl_query_service_status_ex : Can't find the service for the handle \n " ) ) ;
return WERR_BADFID ;
}
2005-03-24 02:26:33 +03:00
2005-06-14 07:17:31 +04:00
if ( r_u - > needed < ( sizeof ( SERVICE_STATUS_PROCESS ) + sizeof ( uint32 ) + sizeof ( uint32 ) ) ) {
DEBUG ( 10 , ( " _svcctl_query_service_status_ex : buffer size of [%d] is too small. \n " , r_u - > needed ) ) ;
return WERR_INSUFFICIENT_BUFFER ;
}
ZERO_STRUCT ( ssp ) ;
2005-06-14 19:40:51 +04:00
#if 0
2005-06-14 07:17:31 +04:00
if ( ! strwicmp ( service_info - > servicetype , " EXTERNAL " ) )
ssp . type = SVCCTL_WIN32_OWN_PROC ;
else
ssp . type = SVCCTL_WIN32_SHARED_PROC ;
2005-06-14 19:40:51 +04:00
# endif
2005-06-14 07:17:31 +04:00
/* Get the status of the service.. */
memset ( command , 0 , sizeof ( command ) ) ;
2005-06-14 19:40:51 +04:00
#if 0
slprintf ( command , sizeof ( command ) - 1 , " %s%s%s %s " , dyn_LIBDIR , SVCCTL_SCRIPT_DIR , service_info - > filename , " status " ) ;
2005-06-14 07:17:31 +04:00
DEBUG ( 10 , ( " _svcctl_query_service_status_ex: status command is [%s] \n " , command ) ) ;
/* TODO - wrap in privilege check */
ret = smbrun ( command , & fd ) ;
DEBUGADD ( 10 , ( " returned [%d] \n " , ret ) ) ;
close ( fd ) ;
if ( ret ! = 0 )
DEBUG ( 10 , ( " _svcctl_query_service_status_ex: Command returned [%d] \n " , ret ) ) ;
/* SET all service_stats bits here... */
if ( ret = = 0 ) {
ssp . state = SVCCTL_RUNNING ;
ssp . controls_accepted = SVCCTL_CONTROL_SHUTDOWN | SVCCTL_CONTROL_STOP ;
} else {
ssp . state = SVCCTL_STOPPED ;
ssp . controls_accepted = 0 ;
}
2005-06-14 19:40:51 +04:00
# endif
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 )
{
POLICY_HND * handle ;
2005-06-14 19:40:51 +04:00
SERVICE_INFO * service_info ;
2005-06-14 07:17:31 +04:00
uint32 needed_size ;
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_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-06-14 07:17:31 +04:00
/* need to find the service name by the handle that is open */
handle = & ( q_u - > handle ) ;
service_info = find_service_info_by_hnd ( p , handle ) ;
#if 0
if ( q_u - > buffer_size < sizeof ( Service_info ) ) {
/* have to report need more... */
/* TODO worst case -- should actualy calc what we need here. */
r_u - > needed = sizeof ( Service_info ) + sizeof ( pstring ) * 5 ;
DEBUG ( 10 , ( " _svcctl_query_service_config: NOT ENOUGH BUFFER ALLOCATED FOR RETURN DATA -- provided %d wanted %d \n " ,
q_u - > buffer_size , r_u - > needed ) ) ;
return WERR_INSUFFICIENT_BUFFER ;
}
# endif
if ( ! service_info ) {
DEBUG ( 10 , ( " _svcctl_query_service_config : Can't find the service for the handle \n " ) ) ;
return WERR_BADFID ;
}
#if 0
if ( ! ( service_config = ( SERVICE_CONFIG * ) TALLOC_ZERO_P ( p - > mem_ctx , SERVICE_CONFIG ) ) )
return WERR_NOMEM ;
# endif
r_u - > config . service_type = SVCCTL_WIN32_OWN_PROC ;
r_u - > config . start_type = SVCCTL_DEMAND_START ;
r_u - > config . error_control = SVCCTL_SVC_ERROR_IGNORE ;
r_u - > config . tag_id = 0x00000000 ;
/* Init the strings */
r_u - > config . executablepath = TALLOC_ZERO_P ( p - > mem_ctx , UNISTR2 ) ;
r_u - > config . loadordergroup = TALLOC_ZERO_P ( p - > mem_ctx , UNISTR2 ) ;
r_u - > config . dependencies = TALLOC_ZERO_P ( p - > mem_ctx , UNISTR2 ) ;
r_u - > config . startname = TALLOC_ZERO_P ( p - > mem_ctx , UNISTR2 ) ;
r_u - > config . displayname = TALLOC_ZERO_P ( p - > mem_ctx , UNISTR2 ) ;
2005-06-14 19:40:51 +04:00
#if 0
2005-06-14 07:17:31 +04:00
pstrcpy ( fullpathinfo , dyn_LIBDIR ) ;
pstrcat ( fullpathinfo , SVCCTL_SCRIPT_DIR ) ;
pstrcat ( fullpathinfo , service_info - > filename ) ;
/* Get and calculate the size of the fields. Note that we're still building the fields in the "too-small buffer case"
even though we throw it away . */
2005-03-24 02:26:33 +03:00
2005-06-14 07:17:31 +04:00
DEBUG ( 10 , ( " _svcctl_query_service_config: fullpath info [%s] \n " , fullpathinfo ) ) ;
init_unistr2 ( r_u - > config . executablepath , fullpathinfo , UNI_STR_TERMINATE ) ;
init_unistr2 ( r_u - > config . loadordergroup , " " , UNI_STR_TERMINATE ) ;
init_unistr2 ( r_u - > config . dependencies , service_info - > dependencies , UNI_STR_TERMINATE ) ;
2005-03-24 02:26:33 +03:00
2005-06-14 07:17:31 +04:00
/* TODO - if someone really cares, perhaps "LocalSystem" should be changed to something else here... */
init_unistr2 ( r_u - > config . startname , " LocalSystem " , UNI_STR_TERMINATE ) ;
init_unistr2 ( r_u - > config . displayname , service_info - > servicename , UNI_STR_TERMINATE ) ;
2005-06-14 19:40:51 +04:00
# endif
2005-06-14 07:17:31 +04:00
needed_size = 0x04 + sizeof ( SERVICE_CONFIG ) + 2 * (
r_u - > config . executablepath - > uni_str_len +
r_u - > config . loadordergroup - > uni_str_len +
r_u - > config . dependencies - > uni_str_len +
r_u - > config . startname - > uni_str_len +
r_u - > config . displayname - > uni_str_len ) ;
DEBUG ( 10 , ( " _svcctl_query_service_config: ****** need to have a buffer of [%d], [%d] for struct \n " , needed_size ,
sizeof ( SERVICE_CONFIG ) ) ) ;
DEBUG ( 10 , ( " \t size of executable path : %d \n " , r_u - > config . executablepath - > uni_str_len ) ) ;
DEBUG ( 10 , ( " \t size of loadordergroup : %d \n " , r_u - > config . loadordergroup - > uni_str_len ) ) ;
DEBUG ( 10 , ( " \t size of dependencies : %d \n " , r_u - > config . dependencies - > uni_str_len ) ) ;
DEBUG ( 10 , ( " \t size of startname : %d \n " , r_u - > config . startname - > uni_str_len ) ) ;
DEBUG ( 10 , ( " \t size of displayname : %d \n " , r_u - > config . displayname - > uni_str_len ) ) ;
if ( q_u - > buffer_size < needed_size ) {
/* have to report need more...*/
r_u - > needed = needed_size ;
DEBUG ( 10 , ( " _svcctl_query_service_config: ****** zeroing strings for return \n " ) ) ;
memset ( & r_u - > config , 0 , sizeof ( SERVICE_CONFIG ) ) ;
DEBUG ( 10 , ( " _svcctl_query_service_config: Not enouh buffer provided for return -- provided %d wanted %d \n " ,
q_u - > buffer_size , needed_size ) ) ;
return WERR_INSUFFICIENT_BUFFER ;
}
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 )
{
POLICY_HND * handle ;
2005-06-14 19:40:51 +04:00
SERVICE_INFO * service_info ;
uint32 level ;
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_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-06-14 07:17:31 +04:00
r_u - > needed = q_u - > buffer_size ;
r_u - > description = NULL ;
r_u - > returned = q_u - > buffer_size ;
r_u - > offset = 4 ;
handle = & ( q_u - > handle ) ;
service_info = find_service_info_by_hnd ( p , handle ) ;
if ( ! service_info ) {
DEBUG ( 10 , ( " _svcctl_query_service_config2 : Can't find the service for the handle \n " ) ) ;
return WERR_BADFID ;
}
/*
TODO - perhaps move the RPC_DATA_BLOB into the R_QUERY_SERVICE_CONFIG structure , and to the processing in here , vs
in the * r_query_config2 marshalling routine . . .
*/
level = q_u - > info_level ;
2005-06-14 19:40:51 +04:00
#if 0
2005-06-14 07:17:31 +04:00
if ( SERVICE_CONFIG_DESCRIPTION = = level ) {
if ( service_info & & service_info - > shortdescription ) {
/* length of the string, plus the terminator... */
string_buffer_size = strlen ( service_info - > shortdescription ) + 1 ;
DEBUG ( 10 , ( " _svcctl_query_service_config: copying the description [%s] length [%d] \n " ,
service_info - > shortdescription , string_buffer_size ) ) ;
if ( q_u - > buffer_size > = ( ( string_buffer_size ) * 2 + 4 ) ) {
r_u - > description = TALLOC_ZERO_P ( p - > mem_ctx , UNISTR2 ) ;
if ( ! r_u - > description ) return WERR_NOMEM ;
init_unistr2 ( r_u - > description , service_info - > shortdescription , UNI_STR_TERMINATE ) ;
}
}
else {
string_buffer_size = 0 ;
}
DEBUG ( 10 , ( " _svcctl_query_service_config2: buffer needed is [%x], return buffer size is [%x] \n " ,
string_buffer_size , q_u - > buffer_size ) ) ;
if ( ( ( string_buffer_size ) * 2 + 4 ) > q_u - > buffer_size ) {
r_u - > needed = ( string_buffer_size + 1 ) * 2 + 4 ;
DEBUG ( 10 , ( " _svcctl_query_service_config2: INSUFFICIENT BUFFER \n " ) ) ;
return WERR_INSUFFICIENT_BUFFER ;
}
DEBUG ( 10 , ( " _svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x] \n " ,
r_u - > needed , q_u - > buffer_size ) ) ;
return WERR_OK ;
}
2005-06-14 19:40:51 +04:00
# endif
2005-06-14 07:17:31 +04:00
return WERR_ACCESS_DENIED ;
}