📄 srv_svcctl_nt.c
字号:
/* * Unix SMB/CIFS implementation. * RPC Pipe client / server routines * * 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 * 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 02139, USA. */#include "includes.h"#undef DBGC_CLASS#define DBGC_CLASS DBGC_RPC_SRVstruct service_control_op { const char *name; SERVICE_CONTROL_OPS *ops;};#define SVCCTL_NUM_INTERNAL_SERVICES 4/* handle external services */extern SERVICE_CONTROL_OPS rcinit_svc_ops;/* builtin services (see service_db.c and services/svc_*.c */extern SERVICE_CONTROL_OPS spoolss_svc_ops;extern SERVICE_CONTROL_OPS netlogon_svc_ops;extern SERVICE_CONTROL_OPS winreg_svc_ops;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 4struct 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 = SVCCTL_NUM_INTERNAL_SERVICES + 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 && 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++; svcctl_ops[i].name = talloc_strdup( svcctl_ops, "WINS" ); svcctl_ops[i].ops = &wins_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: using root's token\n")); token = get_root_nt_token(); } 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; size_t 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;}/****************************************************************** free() function for REGISTRY_KEY *****************************************************************/ static void free_service_handle_info(void *ptr){ TALLOC_FREE( ptr );}/****************************************************************** 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 **)(void *)&service_info) ) { DEBUG(2,("find_service_info_by_hnd: handle not found")); return NULL; } return service_info;}/****************************************************************** *****************************************************************/ 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 = TALLOC_ZERO_P( NULL, SERVICE_INFO )) ) return WERR_NOMEM; /* the Service Manager has a NULL name */ info->type = SVC_HANDLE_IS_SCM; switch ( type ) { case SVC_HANDLE_IS_SCM: info->type = SVC_HANDLE_IS_SCM; 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 */ if ( !(s_op = find_service_by_name( service )) ) { result = WERR_NO_SUCH_SERVICE; goto done; } info->ops = s_op->ops; 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; /* store the SERVICE_INFO and create an open handle */ if ( !create_policy_hnd( p, handle, free_service_handle_info, info ) ) { result = WERR_ACCESS_DENIED; goto done; } done: if ( !W_ERROR_IS_OK(result) ) free_service_handle_info( info ); return result;}/****************************************************************************************************************************************/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; 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, SVC_HANDLE_IS_SCM, NULL, access_granted );}/****************************************************************************************************************************************/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; 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)); /* based on my tests you can open a service if you have a valid scm handle */ if ( !find_service_info_by_hnd( p, &q_u->handle ) ) return WERR_BADFID; /* perform access checks. Use the root token in order to ensure that we retreive the security descriptor */ 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 ); return create_open_service_handle( p, &r_u->handle, SVC_HANDLE_IS_SERVICE, service, access_granted );}/****************************************************************************************************************************************/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;}/****************************************************************************************************************************************/WERROR _svcctl_get_display_name(pipes_struct *p, SVCCTL_Q_GET_DISPLAY_NAME *q_u, SVCCTL_R_GET_DISPLAY_NAME *r_u){ fstring service; const char *display_name; 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); 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;}/****************************************************************************************************************************************/WERROR _svcctl_query_status(pipes_struct *p, SVCCTL_Q_QUERY_STATUS *q_u, SVCCTL_R_QUERY_STATUS *r_u){ 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; /* try the service specific status call */ return info->ops->service_status( info->name, &r_u->svc_status );}/****************************************************************************************************************************************/static int enumerate_status( TALLOC_CTX *ctx, ENUM_SERVICES_STATUS **status, NT_USER_TOKEN *token ){ 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; } 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 ); } *status = st; return num_services;}/****************************************************************************************************************************************/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_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 */ if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) return WERR_BADFID; if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) ) return WERR_ACCESS_DENIED; if ( (num_services = enumerate_status( p->mem_ctx, &services, token )) == -1 ) return WERR_NOMEM; 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 ) { num_services = 0; result = WERR_MORE_DATA; } rpcbuf_init(&r_u->buffer, q_u->buffer_size, p->mem_ctx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -