2016-12-20 19:41:22 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Cloudbase Solutions Srl
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include "wmi.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <tchar.h>
|
|
|
|
#include "openvswitch/vlog.h"
|
2017-01-30 07:42:31 +00:00
|
|
|
#include "util.h"
|
2016-12-20 19:41:22 +00:00
|
|
|
|
|
|
|
VLOG_DEFINE_THIS_MODULE(wmi);
|
|
|
|
|
|
|
|
/* WMI Job values. */
|
|
|
|
enum job_status
|
|
|
|
{
|
|
|
|
job_starting = 3,
|
|
|
|
job_running = 4,
|
|
|
|
job_completed = 7,
|
|
|
|
job_wait = 4096
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *
|
|
|
|
sanitize_port_name(char *name)
|
|
|
|
{
|
|
|
|
char *p1, *p2;
|
|
|
|
p1 = p2 = name;
|
|
|
|
|
|
|
|
while (*p1) {
|
|
|
|
if ((*p1) == '\'' || (*p1) == '\"') {
|
|
|
|
p1++;
|
|
|
|
} else {
|
|
|
|
*p2 = *p1;
|
|
|
|
p2++;
|
|
|
|
p1++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*p2 = '\0';
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function will output the appropriate message for a given HRESULT.*/
|
|
|
|
static void
|
|
|
|
get_hres_error(HRESULT hres)
|
|
|
|
{
|
|
|
|
char *error_msg = NULL;
|
|
|
|
|
|
|
|
if (FACILITY_WINDOWS == HRESULT_FACILITY(hres)) {
|
|
|
|
hres = HRESULT_CODE(hres);
|
|
|
|
}
|
|
|
|
|
|
|
|
VLOG_ERR("%s", ovs_format_message(hres));
|
|
|
|
}
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
check_return_value(HRESULT hres)
|
|
|
|
{
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
get_hres_error(hres);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT
|
|
|
|
get_variant_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
|
|
|
|
VARIANT *value)
|
|
|
|
{
|
|
|
|
HRESULT hres;
|
|
|
|
|
|
|
|
VariantInit(value);
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, field_name, 0, value, 0, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
VariantClear(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function retrieves the uint16_t value from a given class object with
|
|
|
|
* the field name field_name. */
|
|
|
|
static HRESULT
|
|
|
|
get_uint16_t_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
|
|
|
|
uint16_t *value)
|
|
|
|
{
|
|
|
|
VARIANT vt_prop;
|
|
|
|
HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
|
|
|
|
*value = V_UI2(&vt_prop);
|
|
|
|
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function retrieves the unsigned int values from a given class object
|
|
|
|
* with the field name field_name. */
|
|
|
|
static HRESULT
|
|
|
|
get_uint_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
|
|
|
|
unsigned int *value)
|
|
|
|
{
|
|
|
|
VARIANT vt_prop;
|
|
|
|
HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
|
|
|
|
*value = V_UI4(&vt_prop);
|
|
|
|
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function retrieves the unsigned short value from a given class object
|
|
|
|
* with the field name field_name. */
|
|
|
|
static HRESULT
|
|
|
|
get_ushort_value(IWbemClassObject *pcls_obj, wchar_t *field_name,
|
|
|
|
unsigned short *value)
|
|
|
|
{
|
|
|
|
VARIANT vt_prop;
|
|
|
|
HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
|
|
|
|
*value = V_UI2(&vt_prop);
|
|
|
|
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function retrieves the BSTR value from a given class object with
|
|
|
|
* the field name field_name, to a preallocated destination dest and with the
|
|
|
|
* maximum length max_dest_lgth. */
|
|
|
|
static HRESULT
|
|
|
|
get_str_value(IWbemClassObject *pcls_obj, wchar_t *field_name, wchar_t *dest,
|
|
|
|
int max_dest_lgth)
|
|
|
|
{
|
|
|
|
VARIANT vt_prop;
|
|
|
|
HRESULT hres = get_variant_value(pcls_obj, field_name, &vt_prop);
|
|
|
|
|
|
|
|
if (wcscpy_s(dest, max_dest_lgth, vt_prop.bstrVal)) {
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
VLOG_WARN("get_str_value, wcscpy_s failed :%s", ovs_strerror(errno));
|
|
|
|
return WBEM_E_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function waits for a WMI job to finish and retrieves the error code
|
|
|
|
* if the job failed */
|
|
|
|
static HRESULT
|
|
|
|
wait_for_job(IWbemServices *psvc, wchar_t *job_path)
|
|
|
|
{
|
|
|
|
IWbemClassObject *pcls_obj = NULL;
|
|
|
|
HRESULT retval = 0;
|
|
|
|
uint16_t job_state = 0;
|
|
|
|
uint16_t error = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
if(!check_return_value(psvc->lpVtbl->GetObject(psvc, job_path, 0, NULL,
|
|
|
|
&pcls_obj, NULL))) {
|
|
|
|
retval = WBEM_E_FAILED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = get_uint16_t_value(pcls_obj, L"JobState", &job_state);
|
|
|
|
if (FAILED(retval)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (job_state == job_starting || job_state == job_running) {
|
|
|
|
Sleep(200);
|
|
|
|
} else if (job_state == job_completed) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/* Error occurred. */
|
|
|
|
retval = get_uint16_t_value(pcls_obj, L"ErrorCode", &error);
|
|
|
|
if (FAILED(retval)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
VLOG_WARN("Job failed with error: %d", error);
|
|
|
|
retval = WBEM_E_FAILED;;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pcls_obj != NULL) {
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
}
|
|
|
|
} while(TRUE);
|
|
|
|
|
|
|
|
if (pcls_obj != NULL) {
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function will initialize DCOM retrieving the WMI locator's ploc and
|
|
|
|
* the context associated to it. */
|
|
|
|
static boolean
|
|
|
|
initialize_wmi(IWbemLocator **ploc, IWbemContext **pcontext)
|
|
|
|
{
|
|
|
|
HRESULT hres = 0;
|
|
|
|
|
|
|
|
/* Initialize COM. */
|
|
|
|
hres = CoInitialize(NULL);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize COM security. */
|
|
|
|
hres = CoInitializeSecurity(NULL,
|
|
|
|
-1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
RPC_C_AUTHN_LEVEL_DEFAULT,
|
|
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
|
|
NULL,
|
|
|
|
EOAC_NONE,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill context. */
|
|
|
|
hres = CoCreateInstance(&CLSID_WbemContext,
|
|
|
|
NULL,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
&IID_IWbemContext,
|
|
|
|
(void**)pcontext);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fill_context(*pcontext);
|
|
|
|
|
|
|
|
/* Initialize locator's (ploc) to WMI. */
|
|
|
|
hres = CoCreateInstance(&CLSID_WbemLocator,
|
|
|
|
NULL,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
&IID_IWbemLocator,
|
|
|
|
(LPVOID *)ploc);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function connects the WMI locator's ploc to a given WMI provider
|
|
|
|
* defined in server and also sets the required security levels for a local
|
|
|
|
* connection to it. */
|
|
|
|
static boolean
|
|
|
|
connect_set_security(IWbemLocator *ploc, IWbemContext *pcontext,
|
|
|
|
wchar_t *server, IWbemServices **psvc)
|
|
|
|
{
|
|
|
|
HRESULT hres = 0;
|
|
|
|
|
|
|
|
/* Connect to server. */
|
|
|
|
hres = ploc->lpVtbl->ConnectServer(ploc,
|
|
|
|
server,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
pcontext,
|
|
|
|
psvc);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set security levels. */
|
|
|
|
hres = CoSetProxyBlanket((IUnknown *) *psvc,
|
|
|
|
RPC_C_AUTHN_WINNT,
|
|
|
|
RPC_C_AUTHZ_NONE,
|
|
|
|
NULL,
|
|
|
|
RPC_C_AUTHN_LEVEL_CALL,
|
|
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
|
|
NULL,
|
|
|
|
EOAC_NONE);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function retrieves the first class object of a given enumeration
|
|
|
|
* outputted by a query and fails if it could not retrieve the object or there
|
|
|
|
* was no object to retrieve */
|
|
|
|
static boolean
|
|
|
|
get_first_element(IEnumWbemClassObject *penumerate,
|
|
|
|
IWbemClassObject **pcls_obj)
|
|
|
|
{
|
|
|
|
unsigned long retval = 0;
|
|
|
|
|
|
|
|
if (penumerate == NULL) {
|
|
|
|
VLOG_WARN("Enumeration Class Object is NULL. Cannot get the first"
|
|
|
|
"object");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT hres = penumerate->lpVtbl->Next(penumerate, WBEM_INFINITE, 1,
|
|
|
|
pcls_obj, &retval);
|
|
|
|
|
|
|
|
|
|
|
|
if (!check_return_value(hres) || retval == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is a wrapper that transforms a char * into a wchar_t * */
|
|
|
|
static boolean
|
|
|
|
tranform_wide(char *name, wchar_t *wide_name)
|
|
|
|
{
|
|
|
|
unsigned long size = strlen(name) + 1;
|
|
|
|
long long ret = 0;
|
|
|
|
|
|
|
|
if (wide_name == NULL) {
|
|
|
|
VLOG_WARN("Provided wide string is NULL");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = mbstowcs(wide_name, name, size);
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
VLOG_WARN("Invalid multibyte character is encountered");
|
|
|
|
return false;
|
|
|
|
} else if (ret == size) {
|
|
|
|
VLOG_WARN("Returned wide string not NULL terminated");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
#define WMI_QUERY_COUNT 2048
|
|
|
|
|
2016-12-20 19:41:22 +00:00
|
|
|
/* This function will delete a switch internal port with a given name as input
|
|
|
|
* executing "RemoveResourceSettings" as per documentation:
|
|
|
|
* https://msdn.microsoft.com/en-us/library/hh850277%28v=vs.85%29.aspx
|
|
|
|
* allocating the data and populating the needed fields to execute the
|
|
|
|
* method */
|
|
|
|
boolean
|
|
|
|
delete_wmi_port(char *name)
|
|
|
|
{
|
|
|
|
HRESULT hres = 0;
|
|
|
|
boolean retval = true;
|
|
|
|
|
|
|
|
IWbemLocator *ploc = NULL;
|
|
|
|
IWbemServices *psvc = NULL;
|
|
|
|
IWbemContext *pcontext = NULL;
|
|
|
|
IWbemClassObject *pclass_instance = NULL;
|
|
|
|
IWbemClassObject *pinput_params = NULL;
|
|
|
|
IWbemClassObject *pcls_obj = NULL;
|
|
|
|
IWbemClassObject *pout_params = NULL;
|
|
|
|
IEnumWbemClassObject *penumerate = NULL;
|
|
|
|
|
|
|
|
sanitize_port_name(name);
|
|
|
|
VARIANT vt_prop;
|
|
|
|
VARIANT variant_array;
|
|
|
|
wchar_t *wide_name = NULL;
|
|
|
|
VariantInit(&vt_prop);
|
|
|
|
VariantInit(&variant_array);
|
|
|
|
|
|
|
|
LONG count[1];
|
|
|
|
SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 1);
|
|
|
|
if (psa == NULL) {
|
|
|
|
VLOG_WARN("Could not allocate memory for a SAFEARRAY");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!initialize_wmi(&ploc, &pcontext)) {
|
|
|
|
VLOG_WARN("Could not initialize DCOM");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!connect_set_security(ploc, pcontext, L"Root\\Virtualization\\v2",
|
|
|
|
&psvc)) {
|
|
|
|
VLOG_WARN("Could not connect and set security for virtualization");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Get the port with the element name equal to the name input. */
|
2017-01-26 23:56:04 -08:00
|
|
|
wchar_t internal_port_query[WMI_QUERY_COUNT] = L"SELECT * from "
|
2016-12-20 19:41:22 +00:00
|
|
|
L"Msvm_EthernetPortAllocationSettingData WHERE ElementName = \"" ;
|
|
|
|
|
|
|
|
wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t));
|
|
|
|
if (wide_name == NULL) {
|
|
|
|
VLOG_WARN("Could not allocate memory for wide string");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tranform_wide(name, wide_name)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, wide_name);
|
2016-12-20 19:41:22 +00:00
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"\"");
|
2016-12-20 19:41:22 +00:00
|
|
|
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
internal_port_query,
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the element path on the switch which will be deleted. */
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
/* Get the class object and the parameters it can have. */
|
|
|
|
hres = psvc->lpVtbl->GetObject(psvc,
|
|
|
|
L"Msvm_VirtualEthernetSwitchManagementService", 0, NULL, &pcls_obj,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->GetMethod(pcls_obj, L"RemoveResourceSettings", 0,
|
|
|
|
&pinput_params, NULL);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0,
|
|
|
|
&pclass_instance);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
count[0] = 0;
|
|
|
|
|
|
|
|
hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
VariantInit(&vt_prop);
|
|
|
|
variant_array.vt = VT_ARRAY | VT_BSTR;
|
|
|
|
variant_array.parray = psa;
|
|
|
|
|
|
|
|
hres = pclass_instance->lpVtbl->Put(pclass_instance, L"ResourceSettings", 0,
|
|
|
|
&variant_array, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the object of the Msvm_VirtualEthernetSwitchManagementService which
|
|
|
|
* we need to invoke the port deletion. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
L"SELECT * FROM "
|
|
|
|
L"Msvm_VirtualEthernetSwitchManagementService",
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
/* Invoke the delete port method. */
|
|
|
|
hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal,
|
|
|
|
L"RemoveResourceSettings", 0,
|
|
|
|
pcontext, pclass_instance, &pout_params,
|
|
|
|
NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
VariantInit(&vt_prop);
|
|
|
|
|
|
|
|
hres = pout_params->lpVtbl->Get(pout_params, L"ReturnValue", 0,
|
|
|
|
&vt_prop, NULL, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int retvalue = 0;
|
|
|
|
hres = get_uint_value(pout_params, L"ReturnValue", &retvalue);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retvalue != 0 && retvalue != job_wait) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retvalue == job_wait) {
|
|
|
|
WCHAR job_path[2048];
|
|
|
|
hres = get_str_value(pout_params, L"Job", job_path,
|
|
|
|
sizeof(job_path) / sizeof(WCHAR));
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
hres = wait_for_job(psvc, job_path);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
|
|
|
|
if (pcontext != NULL) {
|
|
|
|
pcontext->lpVtbl->Release(pcontext);
|
|
|
|
pcontext = NULL;
|
|
|
|
}
|
|
|
|
if (psa != NULL) {
|
|
|
|
SafeArrayDestroy(psa);
|
|
|
|
psa = NULL;
|
|
|
|
}
|
|
|
|
if (pcls_obj != NULL) {
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
}
|
|
|
|
if (wide_name != NULL) {
|
|
|
|
free(wide_name);
|
|
|
|
wide_name = NULL;
|
|
|
|
}
|
|
|
|
if (!retval) {
|
|
|
|
get_hres_error(hres);
|
|
|
|
}
|
|
|
|
if (pinput_params != NULL) {
|
|
|
|
pinput_params->lpVtbl->Release(pinput_params);
|
|
|
|
pinput_params = NULL;
|
|
|
|
}
|
|
|
|
if (pout_params != NULL) {
|
|
|
|
pout_params->lpVtbl->Release(pout_params);
|
|
|
|
pout_params = NULL;
|
|
|
|
}
|
|
|
|
if (psvc != NULL) {
|
|
|
|
psvc->lpVtbl->Release(psvc);
|
|
|
|
psvc = NULL;
|
|
|
|
}
|
|
|
|
if (ploc != NULL) {
|
|
|
|
ploc->lpVtbl->Release(ploc);
|
|
|
|
ploc = NULL;
|
|
|
|
}
|
|
|
|
if (pclass_instance != NULL) {
|
|
|
|
pclass_instance->lpVtbl->Release(pclass_instance);
|
|
|
|
pclass_instance = NULL;
|
|
|
|
}
|
|
|
|
if (penumerate != NULL) {
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CoUninitialize();
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
|
2016-12-20 19:41:22 +00:00
|
|
|
/* This function will create an internal port on the switch given a given name
|
|
|
|
* executing the method AddResourceSettings as per documentation:
|
|
|
|
* https://msdn.microsoft.com/en-us/library/hh850019%28v=vs.85%29.aspx.
|
|
|
|
* It will verify if the port is already defined, in which case it will use
|
|
|
|
* the specific port, and if the forwarding extension "Open vSwitch Extension"
|
|
|
|
* is enabled and running only on a single switch.
|
|
|
|
* After the port is created and bound to the switch we will disable the
|
|
|
|
* created net adapter and rename it to match the OVS bridge name .*/
|
|
|
|
boolean
|
|
|
|
create_wmi_port(char *name) {
|
|
|
|
HRESULT hres = 0;
|
|
|
|
boolean retval = true;
|
|
|
|
|
|
|
|
BSTR text_object_string = NULL;
|
|
|
|
|
|
|
|
IWbemLocator *ploc = NULL;
|
|
|
|
IWbemContext *pcontext = NULL;
|
|
|
|
IWbemServices *psvc = NULL;
|
|
|
|
IEnumWbemClassObject *penumerate = NULL;
|
|
|
|
IWbemClassObject *default_settings_data = NULL;
|
|
|
|
IWbemClassObject *default_system = NULL;
|
|
|
|
IWbemClassObject *pcls_obj = NULL;
|
|
|
|
IWbemClassObject *pclass = NULL;
|
|
|
|
IWbemClassObject *pinput_params = NULL;
|
|
|
|
IWbemClassObject *pclass_instance = NULL;
|
|
|
|
IWbemObjectTextSrc *text_object = NULL;
|
|
|
|
IWbemClassObject *pout_params = NULL;
|
|
|
|
|
|
|
|
wchar_t *wide_name = NULL;
|
|
|
|
VARIANT vt_prop;
|
|
|
|
VARIANT switch_setting_path;
|
|
|
|
VARIANT new_name;
|
|
|
|
SAFEARRAY *psa = SafeArrayCreateVector(VT_BSTR, 0, 1);
|
|
|
|
VARIANT variant_array;
|
|
|
|
LONG count[1];
|
|
|
|
|
|
|
|
VariantInit(&vt_prop);
|
|
|
|
VariantInit(&switch_setting_path);
|
|
|
|
sanitize_port_name(name);
|
|
|
|
|
|
|
|
if (psa == NULL) {
|
|
|
|
VLOG_WARN("Could not allocate memory for a SAFEARRAY");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!initialize_wmi(&ploc, &pcontext)) {
|
|
|
|
VLOG_WARN("Could not initialize DCOM");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!connect_set_security(ploc, pcontext, L"Root\\Virtualization\\v2",
|
|
|
|
&psvc)) {
|
|
|
|
VLOG_WARN("Could not connect and set security for virtualization");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the element already exists on the switch. */
|
2017-01-26 23:56:04 -08:00
|
|
|
wchar_t internal_port_query[WMI_QUERY_COUNT] = L"SELECT * FROM "
|
2016-12-20 19:41:22 +00:00
|
|
|
L"Msvm_InternalEthernetPort WHERE ElementName = \"";
|
|
|
|
|
|
|
|
wide_name = malloc((strlen(name) + 1) * sizeof(wchar_t));
|
|
|
|
if (wide_name == NULL) {
|
|
|
|
VLOG_WARN("Could not allocate memory for wide string");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tranform_wide(name, wide_name)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, wide_name);
|
|
|
|
|
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"\"");
|
2016-12-20 19:41:22 +00:00
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
internal_port_query,
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("Port with name: %s already defined on the switch", name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
/* Check if the extension is enabled and running. Also check if the
|
|
|
|
* the extension is enabled on more than one switch. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
L"SELECT * "
|
|
|
|
L"FROM Msvm_EthernetSwitchExtension "
|
|
|
|
L"WHERE "
|
|
|
|
L"ElementName=\"Open vSwitch Extension\" "
|
|
|
|
L"AND EnabledState=2 "
|
|
|
|
L"AND HealthState=5",
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("Open vSwitch Extension is not enabled on any switch");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscpy_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
L"SELECT * FROM Msvm_VirtualEthernetSwitch WHERE Name = \"");
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"SystemName", 0,
|
|
|
|
&vt_prop, 0, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
vt_prop.bstrVal);
|
|
|
|
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
if (get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("The extension is activated on more than one switch, "
|
|
|
|
"aborting operation. Please activate the extension on a "
|
|
|
|
"single switch");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
if (pcls_obj != NULL) {
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the switch object on which the extension is activated. */
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"\"");
|
2016-12-20 19:41:22 +00:00
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
internal_port_query,
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("Could not get the switch object on which the extension is"
|
|
|
|
"activated");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"ElementName", 0, &vt_prop, 0, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscpy_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
L"SELECT * FROM Msvm_VirtualEthernetSwitchSettingData WHERE "
|
|
|
|
L"ElementName = \"");
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
vt_prop.bstrVal);
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"Name", 0, &vt_prop, 0, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
/* Should be enough to give the InstanceID, from msdn documentation:
|
|
|
|
* Uniquely identifies an instance of this class. This property is
|
|
|
|
* inherited from CIM_SettingData and is always
|
|
|
|
* set to "Microsoft:GUID\DeviceSpecificData". */
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
L"\" AND InstanceID = \"Microsoft:");
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
vt_prop.bstrVal);
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
L"\"");
|
|
|
|
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
|
|
|
|
/* Retrieve the Msvm_VirtualEthernetSwitchSettingData pinned to the switch
|
|
|
|
* object on which the extension is activated. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
internal_port_query,
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("Could not get the first "
|
|
|
|
"Msvm_VirtualEthernetSwitchSettingData object");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &switch_setting_path,
|
|
|
|
0, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
/* Retrieve a default allocation port. This object will be later filled
|
|
|
|
* with optional data to create an switch internal port. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
L"SELECT * FROM "
|
|
|
|
L"Msvm_EthernetPortAllocationSettingData "
|
|
|
|
L"WHERE InstanceID LIKE '%%%%\\\\Default' "
|
|
|
|
L"AND ResourceSubType = "
|
|
|
|
L"'Microsoft:Hyper-V:Ethernet Connection'",
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &default_settings_data)) {
|
|
|
|
VLOG_WARN("Could not retrieve default allocation port object");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
/* Retrieve the default computer system on which the port allocation will
|
|
|
|
* be hosted.
|
|
|
|
* Instead of querying using Description, we can query using InstallDate.
|
|
|
|
* From MSDN documentation regarding InstallDate:
|
|
|
|
* The date and time the virtual machine configuration was created for
|
|
|
|
* a virtual machine, or Null, for a management operating system. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
L"SELECT * FROM Msvm_ComputerSystem WHERE "
|
|
|
|
L"InstallDate is NULL",
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &default_system)) {
|
|
|
|
VLOG_WARN("Could not retrieve default computer system object");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = default_system->lpVtbl->Get(default_system, L"__PATH",
|
|
|
|
0, &vt_prop, 0, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
count[0] = 0;
|
|
|
|
hres = SafeArrayPutElement(psa, count, vt_prop.bstrVal);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
variant_array.vt = VT_ARRAY | VT_BSTR;
|
|
|
|
variant_array.parray = psa;
|
|
|
|
hres = default_settings_data->lpVtbl->Put(default_settings_data,
|
|
|
|
L"HostResource", 0,
|
|
|
|
&variant_array, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = psvc->lpVtbl->GetObject(psvc,
|
|
|
|
L"Msvm_VirtualEthernetSwitchManagementService",
|
|
|
|
0, NULL, &pclass, NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = pclass->lpVtbl->GetMethod(pclass, L"AddResourceSettings", 0,
|
|
|
|
&pinput_params, NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0,
|
|
|
|
&pclass_instance);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the switch setting path retrieved above in the affected
|
|
|
|
* configuration field of the class instance. */
|
|
|
|
hres = pclass_instance->lpVtbl->Put(pclass_instance,
|
|
|
|
L"AffectedConfiguration", 0,
|
|
|
|
&switch_setting_path, 0);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the port name in the ElementName field of the default allocation
|
|
|
|
* data. */
|
|
|
|
vt_prop.vt = VT_BSTR;
|
|
|
|
vt_prop.bstrVal = SysAllocString(wide_name);
|
|
|
|
hres = default_settings_data->lpVtbl->Put(default_settings_data,
|
|
|
|
L"ElementName", 0,
|
|
|
|
&vt_prop, 0);
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Retrieve and store the serialized data of the modified default switch
|
|
|
|
* settings data. */
|
|
|
|
hres = CoCreateInstance(&CLSID_WbemObjectTextSrc,
|
|
|
|
NULL,
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
&IID_IWbemObjectTextSrc,
|
|
|
|
(void**)&text_object);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = text_object->lpVtbl->GetText(text_object, 0,
|
|
|
|
default_settings_data,
|
|
|
|
WMI_OBJ_TEXT_WMI_DTD_2_0,
|
|
|
|
pcontext,
|
|
|
|
&text_object_string);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
hres = SafeArrayDestroy(psa);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
VLOG_WARN("Could not clear the data of the array");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
psa = SafeArrayCreateVector(VT_BSTR, 0, 1);
|
|
|
|
|
|
|
|
if (psa == NULL) {
|
|
|
|
VLOG_WARN("Could not allocate memory for a SAFEARRAY");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
count[0] = 0;
|
|
|
|
variant_array.parray = psa;
|
|
|
|
hres = SafeArrayPutElement(psa, count, text_object_string);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
hres = pclass_instance->lpVtbl->Put(pclass_instance, L"ResourceSettings",
|
|
|
|
0, &variant_array, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the object of the switch service. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
L"SELECT * FROM "
|
|
|
|
L"Msvm_VirtualEthernetSwitchManagementService",
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("Could not get the object of the switch service");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
|
|
|
|
hres = pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
/* Try to add the port to the switch. */
|
|
|
|
hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal,
|
|
|
|
L"AddResourceSettings", 0,
|
|
|
|
pcontext, pclass_instance, &pout_params,
|
|
|
|
NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int retvalue = 0;
|
|
|
|
hres = get_uint_value(pout_params, L"ReturnValue", &retvalue);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retvalue != 0 && retvalue != job_wait) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retvalue == job_wait) {
|
|
|
|
WCHAR job_path[2048];
|
|
|
|
hres = get_str_value(pout_params, L"Job", job_path,
|
|
|
|
sizeof(job_path) / sizeof(WCHAR));
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
hres = wait_for_job(psvc, job_path);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pclass->lpVtbl->Release(pclass);
|
|
|
|
pclass = NULL;
|
|
|
|
pclass_instance->lpVtbl->Release(pclass_instance);
|
|
|
|
pclass_instance = NULL;
|
|
|
|
pinput_params->lpVtbl->Release(pinput_params);
|
|
|
|
pinput_params = NULL;
|
|
|
|
psvc->lpVtbl->Release(psvc);
|
|
|
|
psvc = NULL;
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
|
|
|
|
if (!connect_set_security(ploc, pcontext, L"Root\\StandardCimv2",
|
|
|
|
&psvc)) {
|
|
|
|
VLOG_WARN("Could not connect and set security for CIM");
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscpy_s(internal_port_query, WMI_QUERY_COUNT,
|
2016-12-20 19:41:22 +00:00
|
|
|
L"SELECT * FROM MSFT_NetAdapter WHERE Name LIKE '%%");
|
2017-01-26 23:56:04 -08:00
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, wide_name);
|
|
|
|
wcscat_s(internal_port_query, WMI_QUERY_COUNT, L"%%'");
|
2016-12-20 19:41:22 +00:00
|
|
|
|
|
|
|
/* Get the object with the port name equal to name on the CIM. */
|
|
|
|
hres = psvc->lpVtbl->ExecQuery(psvc,
|
|
|
|
L"WQL",
|
|
|
|
internal_port_query,
|
|
|
|
WBEM_FLAG_FORWARD_ONLY |
|
|
|
|
WBEM_FLAG_RETURN_IMMEDIATELY,
|
|
|
|
NULL,
|
|
|
|
&penumerate);
|
|
|
|
|
|
|
|
if (!get_first_element(penumerate, &pcls_obj)) {
|
|
|
|
VLOG_WARN("Element name: %s not found in CIM", name);
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
pcls_obj->lpVtbl->Get(pcls_obj, L"__PATH", 0, &vt_prop, 0, 0);
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
|
|
|
|
/* Disable the adapter with port name equal with name. */
|
|
|
|
hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Disable", 0,
|
|
|
|
pcontext, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = psvc->lpVtbl->GetObject(psvc, L"MSFT_NetAdapter", 0, NULL, &pclass,
|
|
|
|
NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = pclass->lpVtbl->GetMethod(pclass, L"Rename", 0, &pinput_params,
|
|
|
|
NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hres = pinput_params->lpVtbl->SpawnInstance(pinput_params, 0,
|
|
|
|
&pclass_instance);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
VariantInit(&new_name);
|
|
|
|
new_name.vt = VT_BSTR;
|
|
|
|
new_name.bstrVal = wide_name;
|
|
|
|
hres = pclass_instance->lpVtbl->Put(pclass_instance, L"NewName", 0,
|
|
|
|
&new_name, 0);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
hres = psvc->lpVtbl->ExecMethod(psvc, vt_prop.bstrVal, L"Rename", 0,
|
|
|
|
pcontext, pclass_instance, NULL, NULL);
|
|
|
|
if (FAILED(hres)) {
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (text_object_string != NULL) {
|
|
|
|
SysFreeString(text_object_string);
|
|
|
|
text_object_string = NULL;
|
|
|
|
}
|
|
|
|
if (psa != NULL) {
|
|
|
|
SafeArrayDestroy(psa);
|
|
|
|
psa = NULL;
|
|
|
|
}
|
|
|
|
if (ploc != NULL) {
|
|
|
|
ploc->lpVtbl->Release(ploc);
|
|
|
|
ploc = NULL;
|
|
|
|
}
|
|
|
|
if (pcontext != NULL) {
|
|
|
|
pcontext->lpVtbl->Release(pcontext);
|
|
|
|
pcontext = NULL;
|
|
|
|
}
|
|
|
|
if (psvc != NULL) {
|
|
|
|
psvc->lpVtbl->Release(psvc);
|
|
|
|
psvc = NULL;
|
|
|
|
}
|
|
|
|
if (penumerate != NULL) {
|
|
|
|
penumerate->lpVtbl->Release(penumerate);
|
|
|
|
penumerate = NULL;
|
|
|
|
}
|
|
|
|
if (default_settings_data != NULL) {
|
|
|
|
default_settings_data->lpVtbl->Release(default_settings_data);
|
|
|
|
default_settings_data = NULL;
|
|
|
|
}
|
|
|
|
if (default_system != NULL) {
|
|
|
|
default_system->lpVtbl->Release(default_system);
|
|
|
|
default_system = NULL;
|
|
|
|
}
|
|
|
|
if (pcls_obj != NULL) {
|
|
|
|
pcls_obj->lpVtbl->Release(pcls_obj);
|
|
|
|
pcls_obj = NULL;
|
|
|
|
}
|
|
|
|
if (pclass != NULL) {
|
|
|
|
pclass->lpVtbl->Release(pclass);
|
|
|
|
pclass = NULL;
|
|
|
|
}
|
|
|
|
if (pinput_params != NULL) {
|
|
|
|
pinput_params->lpVtbl->Release(pinput_params);
|
|
|
|
pinput_params = NULL;
|
|
|
|
}
|
|
|
|
if (pclass_instance != NULL) {
|
|
|
|
pclass_instance->lpVtbl->Release(pclass_instance);
|
|
|
|
pclass_instance = NULL;
|
|
|
|
}
|
|
|
|
if (text_object != NULL) {
|
|
|
|
text_object->lpVtbl->Release(text_object);
|
|
|
|
text_object = NULL;
|
|
|
|
}
|
|
|
|
if (pout_params != NULL) {
|
|
|
|
pout_params->lpVtbl->Release(pout_params);
|
|
|
|
pout_params = NULL;
|
|
|
|
}
|
|
|
|
if (wide_name != NULL) {
|
|
|
|
free(wide_name);
|
|
|
|
wide_name = NULL;
|
|
|
|
}
|
|
|
|
VariantClear(&vt_prop);
|
|
|
|
VariantClear(&switch_setting_path);
|
|
|
|
|
|
|
|
if (!retval) {
|
|
|
|
get_hres_error(hres);
|
|
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
return retval;
|
|
|
|
}
|