diff options
author | Gerald Carter <jerry@samba.org> | 2005-09-30 17:13:37 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:04:48 -0500 |
commit | 54abd2aa66069e6baf7769c496f46d9dba18db39 (patch) | |
tree | 9cf8e88168011797319ba9e9866749201b1eac1e /source3/rpc_server/srv_svcctl_nt.c | |
parent | 4a2cc231d22a82ed21771a72508f15d21ed63227 (diff) | |
download | samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.gz samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.bz2 samba-54abd2aa66069e6baf7769c496f46d9dba18db39.zip |
r10656: BIG merge from trunk. Features not copied over
* \PIPE\unixinfo
* winbindd's {group,alias}membership new functions
* winbindd's lookupsids() functionality
* swat (trunk changes to be reverted as per discussion with Deryck)
(This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3)
Diffstat (limited to 'source3/rpc_server/srv_svcctl_nt.c')
-rw-r--r-- | source3/rpc_server/srv_svcctl_nt.c | 694 |
1 files changed, 307 insertions, 387 deletions
diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c index 538b97a2b1..e8df2acb22 100644 --- a/source3/rpc_server/srv_svcctl_nt.c +++ b/source3/rpc_server/srv_svcctl_nt.c @@ -1,8 +1,11 @@ /* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines - * Copyright (C) Gerald (Jerry) Carter 2005, + * * Copyright (C) Marcin Krzysztof Porwit 2005. + * + * Largely Rewritten (Again) by: + * Copyright (C) Gerald (Jerry) Carter 2005. * * 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 @@ -19,51 +22,97 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* TODO - Do the OpenService service name matching case-independently, or at least make it an option. */ - - #include "includes.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV -#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/" - - -struct service_control_op_table { +struct service_control_op { const char *name; SERVICE_CONTROL_OPS *ops; }; extern SERVICE_CONTROL_OPS spoolss_svc_ops; +extern SERVICE_CONTROL_OPS rcinit_svc_ops; +extern SERVICE_CONTROL_OPS netlogon_svc_ops; +extern SERVICE_CONTROL_OPS winreg_svc_ops; -struct service_control_op_table svcctl_ops[] = { - { "Spooler", &spoolss_svc_ops }, - { "NETLOGON", NULL }, - { NULL, NULL } -}; +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 }; /******************************************************************** ********************************************************************/ +BOOL init_service_op_table( void ) +{ + const char **service_list = lp_svcctl_list(); + int num_services = 3 + str_list_count( service_list ); + 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 */ + + for ( i=0; service_list[i]; i++ ) { + 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++; + + /* 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; +} +/******************************************************************** +********************************************************************/ + static NTSTATUS svcctl_access_check( SEC_DESC *sec_desc, NT_USER_TOKEN *token, uint32 access_desired, uint32 *access_granted ) { NTSTATUS result; if ( geteuid() == sec_initial_uid() ) { - DEBUG(5,("svcctl_access_check: access check bypassed for 'root'\n")); - *access_granted = access_desired; - return NT_STATUS_OK; + DEBUG(5,("svcctl_access_check: using root's token\n")); + token = get_root_nt_token(); } se_access_check( sec_desc, token, access_desired, access_granted, &result ); @@ -81,7 +130,7 @@ static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx ) size_t i = 0; SEC_DESC *sd; SEC_ACL *acl; - uint32 sd_size; + size_t sd_size; /* basic access for Everyone */ @@ -105,51 +154,13 @@ static SEC_DESC* construct_scm_sd( TALLOC_CTX *ctx ) 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); + TALLOC_FREE( ptr ); } /****************************************************************** @@ -171,44 +182,50 @@ static SERVICE_INFO *find_service_info_by_hnd(pipes_struct *p, POLICY_HND *hnd) /****************************************************************** *****************************************************************/ -static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, +static WERROR create_open_service_handle( pipes_struct *p, POLICY_HND *handle, uint32 type, const char *service, uint32 access_granted ) { SERVICE_INFO *info = NULL; WERROR result = WERR_OK; + struct service_control_op *s_op; - if ( !(info = SMB_MALLOC_P( SERVICE_INFO )) ) + if ( !(info = TALLOC_ZERO_P( NULL, SERVICE_INFO )) ) return WERR_NOMEM; - ZERO_STRUCTP( info ); - /* the Service Manager has a NULL name */ - if ( !service ) { + info->type = SVC_HANDLE_IS_SCM; + + switch ( type ) { + case SVC_HANDLE_IS_SCM: info->type = SVC_HANDLE_IS_SCM; - } else { - int i; + break; + case SVC_HANDLE_IS_DBLOCK: + info->type = SVC_HANDLE_IS_DBLOCK; + break; + + case SVC_HANDLE_IS_SERVICE: info->type = SVC_HANDLE_IS_SERVICE; /* lookup the SERVICE_CONTROL_OPS */ - for ( i=0; svcctl_ops[i].name; i++ ) { - if ( strequal( svcctl_ops[i].name, service ) ) { - info->ops = svcctl_ops[i].ops; - break; - } - } - - if ( !svcctl_ops[i].name ) { + if ( !(s_op = find_service_by_name( service )) ) { result = WERR_NO_SUCH_SERVICE; goto done; } + + info->ops = s_op->ops; - if ( !(info->name = SMB_STRDUP( service )) ) { + if ( !(info->name = talloc_strdup( info, s_op->name )) ) { result = WERR_NOMEM; goto done; } + break; + + default: + result = WERR_NO_SUCH_SERVICE; + goto done; } info->access_granted = access_granted; @@ -241,11 +258,12 @@ WERROR _svcctl_open_scmanager(pipes_struct *p, SVCCTL_Q_OPEN_SCMANAGER *q_u, SVC if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) ) return WERR_NOMEM; + se_map_generic( &q_u->access, &scm_generic_map ); 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 ); + return create_open_service_handle( p, &r_u->handle, SVC_HANDLE_IS_SCM, NULL, access_granted ); } /******************************************************************** @@ -268,21 +286,18 @@ WERROR _svcctl_open_service(pipes_struct *p, SVCCTL_Q_OPEN_SERVICE *q_u, SVCCTL_ if ( !find_service_info_by_hnd( p, &q_u->handle ) ) return WERR_BADFID; - /* perform access checks */ + /* perform access checks. Use the root token in order to ensure that we + retreive the security descriptor */ - if ( !(sec_desc = construct_service_sd( p->mem_ctx )) ) + if ( !(sec_desc = svcctl_get_secdesc( p->mem_ctx, service, get_root_nt_token() )) ) return WERR_NOMEM; + se_map_generic( &q_u->access, &svc_generic_map ); 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 ); + return create_open_service_handle( p, &r_u->handle, SVC_HANDLE_IS_SERVICE, service, access_granted ); } /******************************************************************** @@ -299,7 +314,7 @@ WERROR _svcctl_close_service(pipes_struct *p, SVCCTL_Q_CLOSE_SERVICE *q_u, SVCCT WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u) { fstring service; - fstring displayname; + const char *display_name; SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle ); /* can only use an SCM handle here */ @@ -308,12 +323,9 @@ WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, return WERR_BADFID; rpcstr_pull(service, q_u->servicename.buffer, sizeof(service), q_u->servicename.uni_str_len*2, 0); - - /* need a tdb lookup here or something */ - fstrcpy( displayname, "FIX ME!" ); - - init_svcctl_r_get_display_name( r_u, displayname ); + display_name = svcctl_lookup_dispname( service, p->pipe_user.nt_user_token ); + init_svcctl_r_get_display_name( r_u, display_name ); return WERR_OK; } @@ -335,87 +347,40 @@ WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_ /* try the service specific status call */ - if ( info->ops ) - return info->ops->service_status( &r_u->svc_status ); - - /* default action for now */ - - r_u->svc_status.type = 0x0020; - r_u->svc_status.state = 0x0004; - r_u->svc_status.controls_accepted = 0x0005; - - return WERR_OK; + return info->ops->service_status( info->name, &r_u->svc_status ); } +/******************************************************************** +********************************************************************/ -/********************************************************************* - TODO - for internal services, do similar to external services, except - we have to call the right status routine... -**********************************************************************/ - -static WERROR enum_internal_services(TALLOC_CTX *ctx,ENUM_SERVICES_STATUS **svc_ptr, int existing_services, uint32 *added) +static int enumerate_status( TALLOC_CTX *ctx, ENUM_SERVICES_STATUS **status, NT_USER_TOKEN *token ) { - int num_services = 2; - int i = 0; - ENUM_SERVICES_STATUS *services=NULL; - - if (!svc_ptr || !(*svc_ptr)) - return WERR_NOMEM; - - services = *svc_ptr; - - if ( (existing_services > 0) && svc_ptr && *svc_ptr ) { - ENUM_SERVICES_STATUS *tmp_services = NULL; - uint32 total_svc = existing_services + num_services; - - if ( !(tmp_services = TALLOC_REALLOC_ARRAY( ctx, services, ENUM_SERVICES_STATUS, total_svc )) ) - return WERR_NOMEM; - - services = tmp_services; - i += existing_services; - } - else { - if ( !(services = TALLOC_ARRAY( ctx, ENUM_SERVICES_STATUS, num_services )) ) - return WERR_NOMEM; + 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; } - - DEBUG(8,("enum_internal_services: Creating %d services, starting index %d\n", - num_services, existing_services)); - - init_unistr( &services[i].servicename, "Spooler" ); - init_unistr( &services[i].displayname, "Print Spooler" ); - - 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++; - init_unistr( &services[i].servicename, "NETLOGON" ); - init_unistr( &services[i].displayname, "Net Logon" ); + 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 ); + } - 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; - - *added = num_services; - *svc_ptr = services; + *status = st; - return WERR_OK; + return num_services; } /******************************************************************** @@ -424,11 +389,12 @@ static WERROR enum_internal_services(TALLOC_CTX *ctx,ENUM_SERVICES_STATUS **svc_ 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, num_ext_services, total_services; + uint32 num_services; int i = 0; size_t buffer_size = 0; WERROR result = WERR_OK; SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle ); + NT_USER_TOKEN *token = p->pipe_user.nt_user_token; /* perform access checks */ @@ -438,50 +404,29 @@ WERROR _svcctl_enum_services_status(pipes_struct *p, SVCCTL_Q_ENUM_SERVICES_STAT if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) ) return WERR_ACCESS_DENIED; - num_int_services = 0; - num_ext_services = 0; - - /* 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(); */ - - if ( !(services = TALLOC_ARRAY(p->mem_ctx, ENUM_SERVICES_STATUS, num_int_services+num_ext_services )) ) + if ( (num_services = enumerate_status( p->mem_ctx, &services, token )) == -1 ) return WERR_NOMEM; - if ( W_ERROR_IS_OK(enum_internal_services(p->mem_ctx, &services, 0, &num_int_services)) ) - DEBUG(8,("_svcctl_enum_services_status: Got %d internal services\n", num_int_services)); - -#if 0 - if ( W_ERROR_IS_OK(enum_external_services(p->mem_ctx, &services, num_int_services, &num_ext_services)) ) - DEBUG(8,("_svcctl_enum_services_status: Got %d external services\n", num_ext_services)); -#endif - - total_services = num_int_services + num_ext_services; - - DEBUG(8,("_svcctl_enum_services_status: total of %d services\n", total_services )); - - for ( i=0; i<total_services; i++ ) { + for ( i=0; i<num_services; i++ ) { buffer_size += svcctl_sizeof_enum_services_status(&services[i]); } buffer_size += buffer_size % 4; if (buffer_size > q_u->buffer_size ) { - total_services = 0; + num_services = 0; result = WERR_MORE_DATA; } rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx); if ( W_ERROR_IS_OK(result) ) { - for ( i=0; i<num_int_services+num_ext_services; i++ ) + for ( i=0; i<num_services; i++ ) svcctl_io_enum_services_status( "", &services[i], &r_u->buffer, 0 ); } r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size; - r_u->returned = total_services; + r_u->returned = num_services; if ( !(r_u->resume = TALLOC_P( p->mem_ctx, uint32 )) ) return WERR_NOMEM; @@ -506,7 +451,7 @@ WERROR _svcctl_start_service(pipes_struct *p, SVCCTL_Q_START_SERVICE *q_u, SVCCT if ( !(info->access_granted & SC_RIGHT_SVC_START) ) return WERR_ACCESS_DENIED; - return info->ops->start_service(); + return info->ops->start_service( info->name ); } /******************************************************************** @@ -517,18 +462,27 @@ WERROR _svcctl_control_service(pipes_struct *p, SVCCTL_Q_CONTROL_SERVICE *q_u, S 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; + 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 ); - return info->ops->stop_service( &r_u->svc_status ); + 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; } /******************************************************************** @@ -564,11 +518,8 @@ WERROR _svcctl_enum_dependent_services( pipes_struct *p, SVCCTL_Q_ENUM_DEPENDENT WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_STATUSEX *q_u, SVCCTL_R_QUERY_SERVICE_STATUSEX *r_u ) { - SERVICE_STATUS_PROCESS ssp; - POLICY_HND *handle; - SERVICE_INFO *service_info; - pstring command; SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle ); + uint32 buffer_size; /* perform access checks */ @@ -579,68 +530,80 @@ WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_ return WERR_ACCESS_DENIED; /* 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); + 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; + + switch ( q_u->level ) { + case SVC_STATUS_PROCESS_INFO: + { + SERVICE_STATUS_PROCESS svc_stat_proc; - /* get rid of the easy errors */ + /* 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; - 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; + svcctl_io_service_status_process( "", &svc_stat_proc, &r_u->buffer, 0 ); + buffer_size = sizeof(SERVICE_STATUS_PROCESS); + break; + } + + default: + 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; - } - 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); - -#if 0 - if (!strwicmp(service_info->servicetype,"EXTERNAL")) - ssp.type = SVCCTL_WIN32_OWN_PROC; - else - ssp.type = SVCCTL_WIN32_SHARED_PROC; -#endif + buffer_size += buffer_size % 4; + r_u->needed = (buffer_size > q_u->buffer_size) ? buffer_size : q_u->buffer_size; - /* Get the status of the service.. */ + if (buffer_size > q_u->buffer_size ) + return WERR_MORE_DATA; + + return WERR_OK; +} - memset(command, 0, sizeof(command)); +/******************************************************************** +********************************************************************/ -#if 0 - slprintf(command, sizeof(command)-1, "%s%s%s %s", dyn_LIBDIR, SVCCTL_SCRIPT_DIR, service_info->filename, "status"); +static WERROR fill_svc_config( TALLOC_CTX *ctx, const char *name, SERVICE_CONFIG *config, NT_USER_TOKEN *token ) +{ + REGVAL_CTR *values; + REGISTRY_VALUE *val; - DEBUG(10, ("_svcctl_query_service_status_ex: status command is [%s]\n", command)); + /* 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 ); - /* TODO - wrap in privilege check */ + 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 ); + } - 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)); + /* 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->start_type = SVCCTL_DEMAND_START; + config->error_control = SVCCTL_SVC_ERROR_NORMAL; - /* 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; - } -#endif + TALLOC_FREE( values ); return WERR_OK; } @@ -650,10 +613,9 @@ WERROR _svcctl_query_service_status_ex( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_ 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; - SERVICE_INFO *service_info; - uint32 needed_size; SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle ); + uint32 buffer_size; + WERROR wresult; /* perform access checks */ @@ -667,89 +629,19 @@ WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CON incoming buffer size (even in the case of failure */ r_u->needed = q_u->buffer_size; + + 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; - /* 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); - -#if 0 - 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. */ - - 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); - - /* 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); -#endif - - 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, ("\tsize of executable path : %d\n",r_u->config.executablepath->uni_str_len)); - DEBUG(10, ("\tsize of loadordergroup : %d\n", r_u->config.loadordergroup->uni_str_len)); - DEBUG(10, ("\tsize of dependencies : %d\n", r_u->config.dependencies->uni_str_len)); - DEBUG(10, ("\tsize of startname : %d\n", r_u->config.startname->uni_str_len)); - DEBUG(10, ("\tsize 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; + if (buffer_size > q_u->buffer_size ) { + ZERO_STRUCTP( &r_u->config ); + return WERR_INSUFFICIENT_BUFFER; } - + return WERR_OK; } @@ -758,9 +650,8 @@ WERROR _svcctl_query_service_config( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CON 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; - SERVICE_INFO *service_info; SERVICE_INFO *info = find_service_info_by_hnd( p, &q_u->handle ); + uint32 buffer_size; /* perform access checks */ @@ -773,55 +664,84 @@ WERROR _svcctl_query_service_config2( pipes_struct *p, SVCCTL_Q_QUERY_SERVICE_CO /* 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; - r_u->description = NULL; - r_u->returned = q_u->buffer_size; - r_u->offset = 4; + rpcbuf_init( &r_u->buffer, q_u->buffer_size, p->mem_ctx ); + r_u->needed = q_u->buffer_size; - handle = &(q_u->handle); + 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 ); - service_info = find_service_info_by_hnd(p, handle); + 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 ); - 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... - */ - -#if 0 - if (SERVICE_CONFIG_DESCRIPTION == q_u->info_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); - } + break; } - 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; + 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; } - DEBUG(10, ("_svcctl_query_service_config2: returning ok, needed is [%x], buffer size is [%x]\n", - r_u->needed,q_u->buffer_size)); + 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; - return WERR_OK; - } -#endif + if (buffer_size > q_u->buffer_size ) + return WERR_INSUFFICIENT_BUFFER; - return WERR_ACCESS_DENIED; + 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; } |