cardif_windows_wmi.c

来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 2,302 行 · 第 1/5 页

C
2,302
字号
	}

	hr =  CoInitializeSecurity(
	    NULL,                      // Security descriptor    
	    -1,                        // COM negotiates authentication service
	    NULL,                      // Authentication services
		NULL,                      // Reserved
	    RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication level for proxies
	    RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation level for proxies
	    NULL,                        // Authentication info
	    EOAC_NONE,                   // Additional capabilities of the client or server
	    NULL);                       // Reserved

	if (hr != S_OK && hr != RPC_E_TOO_LATE)
	{
		debug_printf(DEBUG_NORMAL, "Failed to initialize COM security. Error code = 0x%02x\n", hr);
		CoUninitialize();
		return -1;
	}

	hr = CoCreateInstance(&CLSID_WbemLocator, 0, 
        CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *) &wmiLoc);
 
    if (FAILED(hr))
    {
        debug_printf(DEBUG_NORMAL, "Failed to create IWbemLocator object. Err code = 0x%02x\n", hr);
        CoUninitialize();
        return -1;
    }

	if (cardif_windows_wmi_connect() != 0) return -1;
	if (cardif_windows_wmi_event_connect() != 0) return -1;

	return 0;
}

/**
 * \brief Clean up the WMI connection(s) that we were using.
 *
 * \retval 0 on success
 **/
int cardif_windows_wmi_deinit()
{
	cardif_windows_wmi_event_disconnect();
	cardif_windows_wmi_disconnect();
	cardif_windows_wmi_async_cleanup();

	if(wmiLoc != NULL)
		IWbemLocator_Release(wmiLoc);   

    CoUninitialize();

	return 0;
}

/**
 * \brief Establish a connection to WMI to get interface events.
 *
 * This should only be called when the program starts up.
 *
 * \retval 0 on success
 * \retval -1 on error
 **/
int cardif_windows_wmi_event_connect()
{
	HRESULT hr;

  // Connect to the root\default namespace with the current user.
    hr = IWbemLocator_ConnectServer(wmiLoc,
            L"ROOT\\WMI", 
            NULL, NULL, 0, 0, 0, 0, &wmiEvents);

    if (FAILED(hr))
    {
        debug_printf(DEBUG_NORMAL, "Could not connect. Error code = 0x%04x\n", hr);
        return -1;    
    }

    debug_printf(DEBUG_INT, "Connected to WMI\n");

    hr = CoSetProxyBlanket(
       (IUnknown *)wmiEvents,                        // Indicates the proxy to set
       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
       NULL,                        // Server principal name 
       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
       NULL,                        // client identity
       EOAC_NONE                    // proxy capabilities 
    );

    if (FAILED(hr))
    {
        debug_printf(DEBUG_NORMAL, "Could not set proxy blanket. Error code = 0x%04x\n", hr);
        return -1;
    }

	if (cardif_windows_wmi_event_setup_disconnect() != 0)
	{
		debug_printf(DEBUG_NORMAL, "Can't establish listener for media disconnect events.\n");
	}

	if (cardif_windows_wmi_event_setup_connect() != 0)
	{
		debug_printf(DEBUG_NORMAL, "Can't establish listener for media connect events.\n");
	}

	if (cardif_windows_wmi_event_setup_media_specific() != 0)
	{
		debug_printf(DEBUG_NORMAL, "Can't establish listener for media specific events.\n");
	}

	if (cardif_windows_wmi_event_setup_insert() != 0)
	{
		debug_printf(DEBUG_NORMAL, "Can't establish listener for card insertion events.\n");
	}

	if (cardif_windows_wmi_event_setup_remove() != 0)
	{
		debug_printf(DEBUG_NORMAL, "Can't establish listener for card removal events!\n");
	}

	return 0;
}

/**
 * \brief Establish a connection to WMI for future requests.
 *
 *  In general, this will only be called when the program starts up.
 *
 * \retval 0 on success
 * \retval -1 on error
 **/
int cardif_windows_wmi_connect()
{
	HRESULT hr;

  // Connect to the root\default namespace with the current user.
    hr = IWbemLocator_ConnectServer(wmiLoc,
            L"ROOT\\CIMV2", 
            NULL, NULL, 0, 0, 0, 0, &wmiSvc);

    if (FAILED(hr))
    {
		error_prequeue_add("Unable to connect to WMI.  The supplicant will be unable to establish a connection.");
        debug_printf(DEBUG_NORMAL, "Could not connect. Error code = 0x%02x\n", hr);
        return -1;
    }

    debug_printf(DEBUG_INT, "Connected to CIMV2\n");

    hr = CoSetProxyBlanket(
       (IUnknown *)wmiSvc,                        // Indicates the proxy to set
       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
       NULL,                        // Server principal name 
       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
       NULL,                        // client identity
       EOAC_NONE                    // proxy capabilities 
    );

    if (FAILED(hr))
    {
        debug_printf(DEBUG_NORMAL, "Could not set proxy blanket. Error code = 0x%02x\n", hr);
        return -1;
    }

	WMIConnected = TRUE;

	return XENONE;
}

/**
 * \brief Disconnect from the WMI event service when we are done with it.
 *
 * This should be called when the program shuts down.
 *
 * \retval 0 on success
 **/
int cardif_windows_wmi_event_disconnect()
{
	if (pConnectEvent != NULL) IWbemClassObject_Release(pConnectEvent);
	if (pDisconnectEvent != NULL) IWbemClassObject_Release(pDisconnectEvent);
	if (pMediaSpecificEvent != NULL) IWbemClassObject_Release(pMediaSpecificEvent);
	if (pInsertEvent != NULL) IWbemClassObject_Release(pInsertEvent);
	if (pRemoveEvent != NULL) IWbemClassObject_Release(pRemoveEvent);

	if (wmiEvents != NULL) IWbemServices_Release(wmiEvents);

	WMIConnected = FALSE;

	return XENONE;
}

/**
 * \brief Disconnect from the WMI service when we are done with it.  
 *
 *  In general, this will only be called when the program has been asked to shut down.
 *
 * \retval XENONE on success
 **/
int cardif_windows_wmi_disconnect()
{

	if (wmiSvc != NULL)
		IWbemServices_Release(wmiSvc);


	return XENONE;
}

///< \todo Move to_unicode to xsup_common.
// This function is found in mschapv2.c, but we need it here, so
// prototype it, and let the linker figure it out. ;)
char *to_unicode(char *);

/**
 * \brief Determine a device index given the context for a device.
 *
 * @param[in] ctx   A pointer to the context for the interface we need to find the 
 *                  index of.
 *
 * \todo  Find the proper way to convert unicode strings.
 *
 * \retval 0 on success
 * \retval -1 on error
 **/
int cardif_windows_wmi_get_idx(context *ctx, char **description)
{
	char *matchstr = NULL;
	char *unimstr = NULL;
	HRESULT hr;
	IEnumWbemClassObject* pEnumerator = NULL;
	IWbemClassObject *pclsObj = NULL;
	int index = -1;
	ULONG uReturn = 0;
	VARIANT vtProp;
	struct win_sock_data *sockData = NULL;

	if (ctx == NULL) return -1;

	// First, we need to find the goop that follows the \DEVICE\ in the
	// interface name.
	matchstr = strstr(ctx->intName, "{");
	if (matchstr == NULL) return -1;      // It isn't there!?  This is BAD!

	if (wmiSvc == NULL)
	{
		debug_printf(DEBUG_NORMAL, "WMI Service is not available!\n");
		return -1;
	}

	// Request information about ALL of the interfaces known to Windows.
    hr = IWbemServices_ExecQuery(wmiSvc,
        L"WQL", 
        L"SELECT * FROM Win32_NetworkAdapterConfiguration",
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
        NULL,
        &pEnumerator);
    
    if (FAILED(hr))
    {
        printf("Query for known interfaces failed. Error code = 0x%02x\n", hr);
        return -1;
    }

	// Then, search through them, looking for 'matchstr'.
	unimstr = to_unicode(matchstr);
	debug_printf(DEBUG_INT, "Searching for interface matching '%ws'.\n", unimstr);
    while (pEnumerator)
    {
        hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, 
            &pclsObj, &uReturn);

        if(0 == uReturn)
        {
            break;
        }

		hr = IWbemClassObject_Get(pclsObj, L"SettingID", 0, &vtProp, 0, 0);
		if (FAILED(hr))
		{
			debug_printf(DEBUG_NORMAL, "Unable to obtain the 'SettingID' from the return "
					"results!\n");
			FREE(unimstr);
		    IWbemClassObject_Release(pEnumerator);
		    IWbemClassObject_Release(pclsObj);
			return -1;
		}

		if (wcscmp((wchar_t *)unimstr, vtProp.bstrVal) == 0)
		{
			debug_printf(DEBUG_INT, "Found interface.\n");

			// Clean up, so we can get the index.
			VariantClear(&vtProp);

			hr = IWbemClassObject_Get(pclsObj, L"Index", 0, &vtProp, 0, 0);
			if (FAILED(hr))
			{
				debug_printf(DEBUG_NORMAL, "Unable to obtain the Index for the desired "
						"interface!\n");
				FREE(unimstr);
				IWbemClassObject_Release(pEnumerator);
				IWbemClassObject_Release(pclsObj);
				return -1;
			}

			// Otherwise, we now know the index.
			debug_printf(DEBUG_INT, "Interface is at WMI index %d.\n", vtProp.intVal);
			sockData = (struct win_sock_data *)ctx->sockData;

			if (sockData == NULL)
			{
				debug_printf(DEBUG_NORMAL, "sockData for context '%s' is invalid!?\n",
							ctx->intName);
				FREE(unimstr);
				IWbemClassObject_Release(pEnumerator);
				IWbemClassObject_Release(pclsObj);
				VariantClear(&vtProp);
				return -1;
			}
	
			sockData->wmiIntIdx = vtProp.intVal;
			VariantClear(&vtProp);

			hr = IWbemClassObject_Get(pclsObj, L"Caption", 0, &vtProp, 0, 0);
			if (FAILED(hr))
			{
				debug_printf(DEBUG_NORMAL, "Unable to obtain the Index for the desired "
						"interface!\n");
				FREE(unimstr);
				IWbemClassObject_Release(pEnumerator);
				IWbemClassObject_Release(pclsObj);
				return -1;
			}
			
			// Store a copy of the caption for later use, if needed.
			sockData->caption = _wcsdup(vtProp.bstrVal);

			VariantClear(&vtProp);

			debug_printf(DEBUG_INT, "Interface Caption : %ws\n", sockData->caption);

			if (description != NULL)
			{
				hr = IWbemClassObject_Get(pclsObj, L"Description", 0, &vtProp, 0, 0);
				if (FAILED(hr))
				{
					debug_printf(DEBUG_NORMAL, "Unable to obtain the Index for the desired "
							"interface!\n");
					FREE(unimstr);
					IWbemClassObject_Release(pEnumerator);
					IWbemClassObject_Release(pclsObj);
					return -1;
				}
			
				(*description) = uni_to_ascii(vtProp.bstrVal);
				VariantClear(&vtProp);
			}

			IWbemClassObject_Release(pclsObj);
			break;
		}
		else
		{
			VariantClear(&vtProp);
			IWbemClassObject_Release(pclsObj);
		}
	}

	IWbemClassObject_Release(pEnumerator);

    FREE(unimstr);

	return XENONE;
}

/**
 *  \brief  Do a WQL request against WMI, and get the value at index 0 of the
 *          resulting array.
 *
 *  @param[in] ctx   The context for the interface we want to get data about.
 *  @param[in] prop   A wchar_t pointer that contains the property to be queried.
 *
 *  \retval NULL on error
 *  \retval ptr to result
 **/
wchar_t *cardif_windows_wmi_get_array_idx0(context *ctx, wchar_t *prop)
{
	struct win_sock_data *sockData = NULL;
	HRESULT hr;
	wchar_t *adapt_select = NULL;
	VARIANT vtProp;
	IWbemClassObject *pclsObj = NULL;
	IEnumWbemClassObject *pEnumerator = NULL;
	ULONG uReturn;
	BSTR HUGEP *pbstr = NULL;
	wchar_t *retval = NULL;

	if (ctx == NULL) return NULL;

	sockData = (struct win_sock_data *)ctx->sockData;
	if (sockData == NULL)
	{
		debug_printf(DEBUG_NORMAL, "Couldn't get socket data for context '%s'!?\n", 
			ctx->intName);
		return NULL;
	}

	if (sockData->wmiIntIdx == INVALID_WMI_IDX)
	{
		// We don't know the index, so locate it.
		if (cardif_windows_wmi_get_idx(ctx, NULL) != XENONE)
		{
			debug_printf(DEBUG_NORMAL, "Couldn't determine WMI interface index in %s()!\n",
					__FUNCTION__);
			return NULL;
		}
	}

	// We should know everything we need to locate the IP address for this interface.
	// Request information about ALL of the interfaces known to Windows.
	adapt_select = Malloc(512);
	if (adapt_select == NULL)
	{
		debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store adapter select string!\n");
		return NULL;
	}

	swprintf(adapt_select, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index = %d", sockData->wmiIntIdx);

    hr = IWbemServices_ExecQuery(wmiSvc,
        L"WQL", adapt_select,
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
        NULL,
        &pEnumerator);

	if (FAILED(hr))
	{
		debug_printf(DEBUG_NORMAL, "Failed to locate the WMI configuration block for interface "
				"'%s'!\n", ctx->intName);
                FREE(adapt_select);
		return NULL;
	}
        FREE(adapt_select);

    hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, 
         &pclsObj, &uReturn);

    if(0 == uReturn)
    {
		debug_printf(DEBUG_NORMAL, "Couldn't build enumerator needed to get array data!\n");
        // Clean up and return nothing.
		IWbemClassObject_Release(pEnumerator);
		return NULL;
    }

	// We should have a pointer to what we need to know now.  So, get the data.
	hr = IWbemClassObject_Get(pclsObj, prop, 0, &vtProp, 0, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?