diff --git a/dlls/wbemprox/Makefile.in b/dlls/wbemprox/Makefile.in index 35706932238..b5127cb68de 100644 --- a/dlls/wbemprox/Makefile.in +++ b/dlls/wbemprox/Makefile.in @@ -9,6 +9,7 @@ C_SRCS = \ qualifier.c \ query.c \ reg.c \ + security.c \ service.c \ services.c \ table.c \ diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c index 21451728dc7..2a431f2f720 100644 --- a/dlls/wbemprox/builtin.c +++ b/dlls/wbemprox/builtin.c @@ -493,6 +493,10 @@ static const struct column col_stdregprov[] = { method_enumvaluesW, CIM_FLAG_ARRAY|COL_FLAG_METHOD }, { method_getstringvalueW, CIM_FLAG_ARRAY|COL_FLAG_METHOD } }; +static const struct column col_systemsecurity[] = +{ + { method_getsdW, CIM_FLAG_ARRAY|COL_FLAG_METHOD }, +}; static const struct column col_videocontroller[] = { { prop_adapterdactypeW, CIM_STRING }, @@ -800,6 +804,10 @@ struct record_stdregprov class_method *enumvalues; class_method *getstringvalue; }; +struct record_systemsecurity +{ + class_method *getsd; +}; struct record_videocontroller { const WCHAR *adapter_dactype; @@ -846,7 +854,9 @@ static const struct record_param data_param[] = { class_stdregprovW, method_getstringvalueW, 1, param_subkeynameW, CIM_STRING }, { class_stdregprovW, method_getstringvalueW, 1, param_valuenameW, CIM_STRING }, { class_stdregprovW, method_getstringvalueW, -1, param_returnvalueW, CIM_UINT32, VT_I4 }, - { class_stdregprovW, method_getstringvalueW, -1, param_valueW, CIM_STRING } + { class_stdregprovW, method_getstringvalueW, -1, param_valueW, CIM_STRING }, + { class_systemsecurityW, method_getsdW, -1, param_returnvalueW, CIM_UINT32, VT_I4 }, + { class_systemsecurityW, method_getsdW, -1, param_sdW, CIM_UINT8|CIM_FLAG_ARRAY }, }; #define FLAVOR_ID (WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE | WBEM_FLAVOR_NOT_OVERRIDABLE |\ @@ -869,6 +879,10 @@ static const struct record_stdregprov data_stdregprov[] = { { reg_enum_key, reg_enum_values, reg_get_stringvalue } }; +static const struct record_systemsecurity data_systemsecurity[] = +{ + { security_get_sd } +}; /* check if row matches condition and update status */ static BOOL match_row( const struct table *table, UINT row, const struct expr *cond, enum fill_status *status ) @@ -2416,6 +2430,7 @@ static struct table builtin_classes[] = { class_serviceW, SIZEOF(col_service), col_service, 0, 0, NULL, fill_service }, { class_sounddeviceW, SIZEOF(col_sounddevice), col_sounddevice, SIZEOF(data_sounddevice), 0, (BYTE *)data_sounddevice }, { class_stdregprovW, SIZEOF(col_stdregprov), col_stdregprov, SIZEOF(data_stdregprov), 0, (BYTE *)data_stdregprov }, + { class_systemsecurityW, SIZEOF(col_systemsecurity), col_systemsecurity, SIZEOF(data_systemsecurity), 0, (BYTE *)data_systemsecurity }, { class_videocontrollerW, SIZEOF(col_videocontroller), col_videocontroller, 0, 0, NULL, fill_videocontroller } }; diff --git a/dlls/wbemprox/query.c b/dlls/wbemprox/query.c index b3a3eb9e64d..7ae9a0f1884 100644 --- a/dlls/wbemprox/query.c +++ b/dlls/wbemprox/query.c @@ -664,6 +664,8 @@ VARTYPE to_vartype( CIMTYPE type ) case CIM_BOOLEAN: return VT_BOOL; case CIM_STRING: case CIM_DATETIME: return VT_BSTR; + case CIM_SINT8: return VT_I1; + case CIM_UINT8: return VT_UI1; case CIM_SINT16: return VT_I2; case CIM_UINT16: return VT_UI2; case CIM_SINT32: return VT_I4; @@ -724,6 +726,12 @@ void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret ) case VT_BSTR: V_BSTR( ret ) = val_ptr; break; + case VT_I1: + V_I1( ret ) = val; + break; + case VT_UI1: + V_UI1( ret ) = val; + break; case VT_I2: V_I2( ret ) = val; break; @@ -788,6 +796,12 @@ HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VAR else vartype = VT_NULL; break; + case CIM_SINT8: + if (!vartype) vartype = VT_I1; + break; + case CIM_UINT8: + if (!vartype) vartype = VT_UI1; + break; case CIM_SINT16: if (!vartype) vartype = VT_I2; break; @@ -826,6 +840,8 @@ static CIMTYPE to_cimtype( VARTYPE type ) { case VT_BOOL: return CIM_BOOLEAN; case VT_BSTR: return CIM_STRING; + case VT_I1: return CIM_SINT8; + case VT_UI1: return CIM_UINT8; case VT_I2: return CIM_SINT16; case VT_UI2: return CIM_UINT16; case VT_I4: return CIM_SINT32; diff --git a/dlls/wbemprox/security.c b/dlls/wbemprox/security.c new file mode 100644 index 00000000000..b2e29be5df1 --- /dev/null +++ b/dlls/wbemprox/security.c @@ -0,0 +1,182 @@ +/* + * __SystemSecurity implementation + * + * Copyright 2014 Vincent Povirk for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "config.h" +#include + +#include "windef.h" +#include "winbase.h" +#include "wbemcli.h" +#include "iads.h" + +#include "wine/debug.h" +#include "wbemprox_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wbemprox); + +static HRESULT to_byte_array( void *data, DWORD size, VARIANT *var ) +{ + SAFEARRAY *sa; + void *sadata; + HRESULT hr; + + if (!(sa = SafeArrayCreateVector( VT_UI1, 0, size ))) return E_OUTOFMEMORY; + + hr = SafeArrayAccessData( sa, &sadata ); + + if (SUCCEEDED(hr)) + { + memcpy( sadata, data, size ); + + SafeArrayUnaccessData( sa ); + } + else + { + SafeArrayDestroy( sa ); + return hr; + } + + set_variant( VT_UI1|VT_ARRAY, 0, sa, var ); + return S_OK; +} + +static HRESULT get_sd( SECURITY_DESCRIPTOR **sd, DWORD *size ) +{ + BYTE sid_admin_buffer[SECURITY_MAX_SID_SIZE]; + SID *sid_admin = (SID*)sid_admin_buffer; + BYTE sid_network_buffer[SECURITY_MAX_SID_SIZE]; + SID *sid_network = (SID*)sid_network_buffer; + BYTE sid_local_buffer[SECURITY_MAX_SID_SIZE]; + SID *sid_local = (SID*)sid_local_buffer; + BYTE sid_users_buffer[SECURITY_MAX_SID_SIZE]; + SID *sid_users = (SID*)sid_users_buffer; + BYTE acl_buffer[sizeof(ACL) + 4 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + SECURITY_MAX_SID_SIZE)]; + ACL *acl = (ACL*)acl_buffer; + DWORD sid_size; + SECURITY_DESCRIPTOR absolute_sd; + HRESULT hr = S_OK; + + sid_size = sizeof(sid_admin_buffer); + CreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, sid_admin, &sid_size ); + + sid_size = sizeof(sid_network_buffer); + CreateWellKnownSid( WinNetworkServiceSid, NULL, sid_network, &sid_size ); + + sid_size = sizeof(sid_local_buffer); + CreateWellKnownSid( WinLocalServiceSid, NULL, sid_local, &sid_size ); + + sid_size = sizeof(sid_users_buffer); + CreateWellKnownSid( WinAuthenticatedUserSid, NULL, sid_users, &sid_size ); + + InitializeAcl( acl, sizeof(acl_buffer), ACL_REVISION ); + + AddAccessAllowedAceEx( acl, ACL_REVISION, CONTAINER_INHERIT_ACE|INHERITED_ACE, + ADS_RIGHT_DS_CREATE_CHILD|ADS_RIGHT_DS_DELETE_CHILD|ADS_RIGHT_ACTRL_DS_LIST|ADS_RIGHT_DS_SELF| + ADS_RIGHT_DS_READ_PROP|ADS_RIGHT_DS_WRITE_PROP|READ_CONTROL|WRITE_DAC, + sid_admin ); + + AddAccessAllowedAceEx( acl, ACL_REVISION, CONTAINER_INHERIT_ACE|INHERITED_ACE, + ADS_RIGHT_DS_CREATE_CHILD|ADS_RIGHT_DS_DELETE_CHILD|ADS_RIGHT_DS_READ_PROP, + sid_network ); + + AddAccessAllowedAceEx( acl, ACL_REVISION, CONTAINER_INHERIT_ACE|INHERITED_ACE, + ADS_RIGHT_DS_CREATE_CHILD|ADS_RIGHT_DS_DELETE_CHILD|ADS_RIGHT_DS_READ_PROP, + sid_local ); + + AddAccessAllowedAceEx( acl, ACL_REVISION, CONTAINER_INHERIT_ACE|INHERITED_ACE, + ADS_RIGHT_DS_CREATE_CHILD|ADS_RIGHT_DS_DELETE_CHILD|ADS_RIGHT_DS_READ_PROP, + sid_users ); + + InitializeSecurityDescriptor( &absolute_sd, SECURITY_DESCRIPTOR_REVISION ); + + SetSecurityDescriptorOwner( &absolute_sd, sid_admin, TRUE ); + SetSecurityDescriptorGroup( &absolute_sd, sid_admin, TRUE ); + SetSecurityDescriptorDacl( &absolute_sd, TRUE, acl, TRUE ); + + *size = GetSecurityDescriptorLength( &absolute_sd ); + + *sd = HeapAlloc( GetProcessHeap(), 0, *size ); + if (!*sd) + hr = E_OUTOFMEMORY; + + if (SUCCEEDED(hr)) + { + if (!MakeSelfRelativeSD(&absolute_sd, *sd, size)) + hr = E_FAIL; + } + + return hr; +} + +HRESULT security_get_sd( IWbemClassObject *obj, IWbemClassObject *in, IWbemClassObject **out ) +{ + VARIANT var_sd, retval; + IWbemClassObject *sig, *out_params = NULL; + HRESULT hr, ret; + SECURITY_DESCRIPTOR *sd; + DWORD sd_size; + + TRACE("%p, %p\n", in, out); + + hr = create_signature( class_systemsecurityW, method_getsdW, PARAM_OUT, &sig ); + + if (SUCCEEDED(hr)) + { + hr = IWbemClassObject_SpawnInstance( sig, 0, &out_params ); + + IWbemClassObject_Release( sig ); + } + + if (SUCCEEDED(hr)) + { + ret = get_sd( &sd, &sd_size ); + + if (SUCCEEDED(ret)) + { + VariantInit( &var_sd ); + + hr = to_byte_array( sd, sd_size, &var_sd ); + + if (SUCCEEDED(hr)) + hr = IWbemClassObject_Put( out_params, param_sdW, 0, &var_sd, CIM_UINT8|CIM_FLAG_ARRAY ); + + HeapFree( GetProcessHeap(), 0, sd ); + VariantClear( &var_sd ); + } + + if (SUCCEEDED(hr)) + { + set_variant( VT_UI4, ret, NULL, &retval ); + hr = IWbemClassObject_Put( out_params, param_returnvalueW, 0, &retval, CIM_UINT32 ); + } + + if (SUCCEEDED(hr) && out) + { + *out = out_params; + IWbemClassObject_AddRef( out_params ); + } + + IWbemClassObject_Release( out_params ); + } + + return hr; +} diff --git a/dlls/wbemprox/table.c b/dlls/wbemprox/table.c index 7a5b1c18012..0c57f2618ca 100644 --- a/dlls/wbemprox/table.c +++ b/dlls/wbemprox/table.c @@ -52,6 +52,9 @@ UINT get_type_size( CIMTYPE type ) { case CIM_BOOLEAN: return sizeof(int); + case CIM_SINT8: + case CIM_UINT8: + return sizeof(INT8); case CIM_SINT16: case CIM_UINT16: return sizeof(INT16); @@ -111,6 +114,12 @@ HRESULT get_value( const struct table *table, UINT row, UINT column, LONGLONG *v case CIM_STRING: *val = (INT_PTR)*(const WCHAR **)ptr; break; + case CIM_SINT8: + *val = *(const INT8 *)ptr; + break; + case CIM_UINT8: + *val = *(const UINT8 *)ptr; + break; case CIM_SINT16: *val = *(const INT16 *)ptr; break; @@ -215,6 +224,12 @@ HRESULT set_value( const struct table *table, UINT row, UINT column, LONGLONG va case CIM_STRING: *(WCHAR **)ptr = (WCHAR *)(INT_PTR)val; break; + case CIM_SINT8: + *(INT8 *)ptr = val; + break; + case CIM_UINT8: + *(UINT8 *)ptr = val; + break; case CIM_SINT16: *(INT16 *)ptr = val; break; diff --git a/dlls/wbemprox/tests/Makefile.in b/dlls/wbemprox/tests/Makefile.in index 86ab0c9871d..565edd0a289 100644 --- a/dlls/wbemprox/tests/Makefile.in +++ b/dlls/wbemprox/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = wbemprox.dll -IMPORTS = uuid oleaut32 ole32 user32 +IMPORTS = uuid oleaut32 ole32 user32 advapi32 C_SRCS = \ query.c \ diff --git a/dlls/wbemprox/tests/query.c b/dlls/wbemprox/tests/query.c index d244dad3109..467a63cd3b2 100644 --- a/dlls/wbemprox/tests/query.c +++ b/dlls/wbemprox/tests/query.c @@ -21,6 +21,7 @@ #include #include "windows.h" #include "ocidl.h" +#include "sddl.h" #include "initguid.h" #include "objidl.h" #include "wbemcli.h" @@ -650,6 +651,83 @@ static void test_GetNames( IWbemServices *services ) SysFreeString( wql ); } +static void test_SystemSecurity( IWbemServices *services ) +{ + static const WCHAR systemsecurityW[] = {'_','_','S','y','s','t','e','m','S','e','c','u','r','i','t','y',0}; + static const WCHAR getsdW[] = {'G','e','t','S','D',0}; + static const WCHAR returnvalueW[] = {'R','e','t','u','r','n','V','a','l','u','e',0}; + static const WCHAR sdW[] = {'S','D',0}; + BSTR class = SysAllocString( systemsecurityW ), method; + IWbemClassObject *reg, *out; + VARIANT retval, var_sd; + void *data; + SECURITY_DESCRIPTOR_RELATIVE *sd; + CIMTYPE type; + HRESULT hr; + BYTE sid_admin_buffer[SECURITY_MAX_SID_SIZE]; + SID *sid_admin = (SID*)sid_admin_buffer; + DWORD sid_size; + BOOL ret; + + hr = IWbemServices_GetObject( services, class, 0, NULL, ®, NULL ); + if (hr != S_OK) + { + win_skip( "__SystemSecurity not available\n" ); + return; + } + + sid_size = sizeof(sid_admin_buffer); + ret = CreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, sid_admin, &sid_size ); + ok( ret, "CreateWellKnownSid failed\n" ); + + out = NULL; + method = SysAllocString( getsdW ); + hr = IWbemServices_ExecMethod( services, class, method, 0, NULL, NULL, &out, NULL ); + ok( hr == S_OK || hr == WBEM_E_ACCESS_DENIED, "failed to execute method %08x\n", hr ); + SysFreeString( method ); + + if (SUCCEEDED(hr)) + { + type = 0xdeadbeef; + VariantInit( &retval ); + hr = IWbemClassObject_Get( out, returnvalueW, 0, &retval, &type, NULL ); + ok( hr == S_OK, "failed to get return value %08x\n", hr ); + ok( V_VT( &retval ) == VT_I4, "unexpected variant type 0x%x\n", V_VT( &retval ) ); + ok( !V_I4( &retval ), "unexpected error %u\n", V_UI4( &retval ) ); + ok( type == CIM_UINT32, "unexpected type 0x%x\n", type ); + + type = 0xdeadbeef; + VariantInit( &var_sd ); + hr = IWbemClassObject_Get( out, sdW, 0, &var_sd, &type, NULL ); + ok( hr == S_OK, "failed to get names %08x\n", hr ); + ok( V_VT( &var_sd ) == (VT_UI1|VT_ARRAY), "unexpected variant type 0x%x\n", V_VT( &var_sd ) ); + ok( type == (CIM_UINT8|CIM_FLAG_ARRAY), "unexpected type 0x%x\n", type ); + + hr = SafeArrayAccessData( V_ARRAY( &var_sd ), &data ); + ok( hr == S_OK, "SafeArrayAccessData failed %x\n", hr ); + if (SUCCEEDED(hr)) + { + sd = data; + + ok( (sd->Control & SE_SELF_RELATIVE) == SE_SELF_RELATIVE, "relative flag unset\n" ); + ok( sd->Owner != 0, "no owner SID\n"); + ok( sd->Group != 0, "no owner SID\n"); + ok( EqualSid( (PSID)((LPBYTE)sd + sd->Owner), sid_admin ), "unexpected owner SID\n" ); + ok( EqualSid( (PSID)((LPBYTE)sd + sd->Group), sid_admin ), "unexpected group SID\n" ); + + hr = SafeArrayUnaccessData( V_ARRAY( &var_sd ) ); + ok( hr == S_OK, "SafeArrayUnaccessData failed %x\n", hr ); + } + + VariantClear( &var_sd ); + IWbemClassObject_Release( out ); + } + else if (hr == WBEM_E_ACCESS_DENIED) + win_skip( "insufficient privs to test __SystemSecurity\n" ); + + SysFreeString( class ); +} + START_TEST(query) { static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0}; @@ -682,6 +760,7 @@ START_TEST(query) test_notification_query_async( services ); test_query_async( services ); test_GetNames( services ); + test_SystemSecurity( services ); SysFreeString( path ); IWbemServices_Release( services ); diff --git a/dlls/wbemprox/wbemprox_private.h b/dlls/wbemprox/wbemprox_private.h index 2721f67bcfe..c6a5e905867 100644 --- a/dlls/wbemprox/wbemprox_private.h +++ b/dlls/wbemprox/wbemprox_private.h @@ -224,6 +224,7 @@ HRESULT service_pause_service(IWbemClassObject *, IWbemClassObject *, IWbemClass HRESULT service_resume_service(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN; HRESULT service_start_service(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN; HRESULT service_stop_service(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN; +HRESULT security_get_sd(IWbemClassObject *, IWbemClassObject *, IWbemClassObject **) DECLSPEC_HIDDEN; static void *heap_alloc( size_t len ) __WINE_ALLOC_SIZE(1); static inline void *heap_alloc( size_t len ) @@ -259,12 +260,14 @@ static inline WCHAR *heap_strdupW( const WCHAR *src ) static const WCHAR class_processW[] = {'W','i','n','3','2','_','P','r','o','c','e','s','s',0}; static const WCHAR class_serviceW[] = {'W','i','n','3','2','_','S','e','r','v','i','c','e',0}; static const WCHAR class_stdregprovW[] = {'S','t','d','R','e','g','P','r','o','v',0}; +static const WCHAR class_systemsecurityW[] = {'_','_','S','y','s','t','e','m','S','e','c','u','r','i','t','y',0}; static const WCHAR prop_nameW[] = {'N','a','m','e',0}; static const WCHAR method_enumkeyW[] = {'E','n','u','m','K','e','y',0}; static const WCHAR method_enumvaluesW[] = {'E','n','u','m','V','a','l','u','e','s',0}; static const WCHAR method_getownerW[] = {'G','e','t','O','w','n','e','r',0}; +static const WCHAR method_getsdW[] = {'G','e','t','S','D',0}; static const WCHAR method_getstringvalueW[] = {'G','e','t','S','t','r','i','n','g','V','a','l','u','e',0}; static const WCHAR method_pauseserviceW[] = {'P','a','u','s','e','S','e','r','v','i','c','e',0}; static const WCHAR method_resumeserviceW[] = {'R','e','s','u','m','e','S','e','r','v','i','c','e',0}; @@ -275,6 +278,7 @@ static const WCHAR param_defkeyW[] = {'h','D','e','f','K','e','y',0}; static const WCHAR param_domainW[] = {'D','o','m','a','i','n',0}; static const WCHAR param_namesW[] = {'s','N','a','m','e','s',0}; static const WCHAR param_returnvalueW[] = {'R','e','t','u','r','n','V','a','l','u','e',0}; +static const WCHAR param_sdW[] = {'S','D',0}; static const WCHAR param_subkeynameW[] = {'s','S','u','b','K','e','y','N','a','m','e',0}; static const WCHAR param_typesW[] = {'T','y','p','e','s',0}; static const WCHAR param_userW[] = {'U','s','e','r',0};