static GdkPixbuf* dn_data_url_to_pixbuf(const NPVariant *data_url) { GdkPixbuf *pixbuf = NULL; GInputStream *stream; gsize len; gchar *buffer, *data; GError *err = NULL; buffer = variant_to_string (data_url); if (buffer == NULL) return NULL; g_debug ("%s(\"%s\")", G_STRFUNC, buffer); if (!g_str_has_prefix (buffer, "data:image/png;base64,")) goto out; /* skip the mime type prefix */ data = buffer + 22; g_base64_decode_inplace (data, &len); stream = g_memory_input_stream_new_from_data (data, len, NULL); pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &err); if (err != NULL) { g_debug ("%s error: %s", G_STRFUNC, err->message); g_error_free (err); } out: g_free (buffer); return pixbuf; }
static NPVariant dn_show_notification (NPObject *object, const NPVariant *args, uint32_t argc) { NPVariant result; gchar *summary, *body = NULL; GdkPixbuf *image = NULL; gboolean shown; BOOLEAN_TO_NPVARIANT (FALSE, result); g_debug ("%s()", G_STRFUNC); if (G_UNLIKELY (argc < 1 || !NPVARIANT_IS_STRING(args[0]))) return result; summary = variant_to_string (&args[0]); if (G_UNLIKELY (summary == NULL)) return result; if (argc >= 2) body = variant_to_string (&args[1]); if (argc >= 3) image = dn_data_url_to_pixbuf(&args[2]); g_debug ("%s(\"%s\", \"%s\", %s)", G_STRFUNC, summary, body, image != NULL ? "<image>" : NULL); NotifyNotification *notification = notify_notification_new (summary, body, NULL); if (image != NULL) notify_notification_set_image_from_pixbuf (notification, image); shown = notify_notification_show (notification, NULL); /*TODO: notify_notification_set_image_from_pixbuf() */ BOOLEAN_TO_NPVARIANT (shown, result); g_free (summary); if (body != NULL) g_free (body); if (image != NULL) g_object_unref (image); return result; }
variant do_debug(variant i, variant s) { if(get_core_debug_level_env()>=variant_as_int(i) && (is_core_debug_group(DEBUG_GROUP_ALL) || is_core_debug_group(core_debug_group))) { printf("%s \n",variant_to_string(s)); }; return VARIANT_EMPTY(); }
/*! * @brief Convert a variant type to a string and write it to the given buffer. * @param v The variant to convert. * @param buffer Pointer to the buffer to write the value to. * @param bufferSize size of the buffer. * @returns Pointer to the next location in the buffer. * @remarks This attempts to "flatten" a variant, including array types. The implementation is * not 100% complete, but is good enough for the sake of this requirement. Only arrays * of BSTR are currenty supported, more types can be added later if needed. Arbitrary * array depth has been attempted, but no tests have yet found a nested array in the * result set. There's probably bugs in that bit. */ char* variant_to_string(_variant_t& v, char* buffer, DWORD bufferSize) { dprintf("[WMI] preparing to parse variant of type %u (%x), buffer size %u", v.vt, v.vt, bufferSize); switch (v.vt) { case VT_EMPTY: strncpy_s(buffer, bufferSize, "(EMPTY)", bufferSize - 1); break; case VT_NULL: strncpy_s(buffer, bufferSize, "(NULL)", bufferSize - 1); break; case VT_BOOL: strncpy_s(buffer, bufferSize, v.boolVal == VARIANT_TRUE ? "true" : "false", bufferSize - 1); break; case VT_I1: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId8, (CHAR)v); break; case VT_I2: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId16, (SHORT)v); break; case VT_INT: case VT_I4: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId32, (INT)v); break; case VT_INT_PTR: case VT_I8: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId64, (INT_PTR)v); break; case VT_UI1: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu8, (BYTE)v); break; case VT_UI2: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu16, (SHORT)v); break; case VT_UINT: case VT_UI4: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu32, (UINT)v); break; case VT_UINT_PTR: case VT_UI8: _snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu64, (UINT_PTR)v); break; case VT_BSTR: case VT_LPSTR: case VT_LPWSTR: // not sure if this is correct strncpy_s(buffer, bufferSize, (char*)(_bstr_t)v.bstrVal, bufferSize - 1); break; // TODO more types, such as floats, dates, etc. default: if ((v.vt & VT_ARRAY) == VT_ARRAY) { // nested array type, great. dprintf("[WMI] array type found!"); LPSAFEARRAY array = v.parray; HRESULT hResult; if (FAILED(hResult = SafeArrayLock(array))) { dprintf("[WMI] Failed to get array dimension: %x", hResult); break; } dprintf("[WMI] Field name array locked."); LONG* indices = NULL; LONG* bounds = NULL; do { VARTYPE varType; SafeArrayGetVartype(array, &varType); dprintf("[WMI] Array type %u (%x)", (ULONG)varType, (ULONG)varType); dprintf("[WMI] Array dimensions: %u", SafeArrayGetDim(array)); LONG iterations = 1; LONG dim = SafeArrayGetDim(array); indices = (LONG*)malloc(dim * sizeof(LONG)); bounds = (LONG*)malloc(dim * sizeof(LONG) * 2); memset(indices, 0, dim * sizeof(LONG)); memset(bounds, 0, dim * sizeof(LONG) * 2); for (LONG i = 0; i < dim; ++i) { LONG* lBound = bounds + i * 2; LONG* uBound = lBound + 1; if (FAILED(hResult = SafeArrayGetLBound(array, i + 1, lBound)) || FAILED(hResult = SafeArrayGetUBound(array, i + 1, uBound))) { dprintf("[WMI] Failed to get array dimensions: %x", hResult); break; } dprintf("[WMI] Array bounds: %u to %u", *lBound, *uBound); iterations *= *uBound - *lBound; indices[i] = *lBound; } dprintf("[WMI] Array requires %u iterations", iterations); // we're going to wrap our array elements in brackets, and separate with pipes // because we need some kind of array visualisation and this is the best I could // come up with at this time of night. Each dimension nests in a new set of brackets while (iterations-- > 0) { for (LONG i = 0; i < dim; ++i) { if (indices[i] == 0) { // save space for the closing bracket as well bufferSize -= 2; *buffer++ = '{'; dprintf("[WMI] opening bracket for dimension %u", i); } else if(*(buffer - 1) != '|') { --bufferSize; *buffer++ = '|'; } } dprintf("[WMI] extracting value for iteration %u", iterations); switch (varType) { case VT_BSTR: BSTR val; if (SUCCEEDED(SafeArrayGetElement(array, indices, (void*)&val))) { dprintf("[WMI] Value extracted for iteration %u", iterations); char* newBuf = variant_to_string(_variant_t(val), buffer, bufferSize); bufferSize -= (LONG)(newBuf - buffer + 1); buffer = newBuf; dprintf("[WMI] Value added", iterations); } break; default: dprintf("[WMI] Unsupported nested array type %u", (LONG)varType); break; } ++indices[dim - 1]; for (LONG i = dim - 1; i >= 0; --i) { if (indices[i] == bounds[i * 2 + 1]) { dprintf("[WMI] closing bracket for dimension %u", i); *buffer++ = '}'; indices[i] = bounds[i * 2]; if (i > 0) { ++indices[i - 1]; } } } } } while (0); if (indices) { free(indices); } if (bounds) { free(bounds); } SafeArrayUnlock(array); } else { dprintf("[WMI] Unhandled type: %u (%x)", v.vt, v.vt); } // ignore the buffer for other types break; } // return wherever we go to. return buffer + strlen(buffer); }
/*! * @brief Perform a WMI query. * @param lpwRoot Name of the root object that is to be queried against. * @param lpwQuery The filter to use when reading objects (LDAP style). * @param response The response \c Packet to add the results to. */ DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response) { HRESULT hResult; dprintf("[WMI] Initialising COM"); if ((hResult = CoInitializeEx(NULL, COINIT_MULTITHREADED)) == S_OK) { dprintf("[WMI] COM initialised"); IWbemLocator* pLocator = NULL; IWbemServices* pServices = NULL; IEnumWbemClassObject* pEnumerator = NULL; IWbemClassObject* pSuperClass = NULL; IWbemClassObject* pObj = NULL; Tlv* valueTlvs = NULL; char* values = NULL; VARIANT** fields = NULL; do { if (FAILED(hResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))) { dprintf("[WMI] Failed to initialize security: %x", hResult); break; } dprintf("[WMI] Security initialised"); if (FAILED(hResult = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator)))) { dprintf("[WMI] Failed to create WbemLocator: %x", hResult); break; } dprintf("[WMI] WbemLocator created."); if (FAILED(hResult = pLocator->ConnectServer(_bstr_t(lpwRoot), NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pServices))) { dprintf("[WMI] Failed to create WbemServices at %S: %x", lpwRoot, hResult); break; } dprintf("[WMI] WbemServices created."); if (FAILED(hResult = pServices->ExecQuery(L"WQL", lpwQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator))) { dprintf("[WMI] Failed to create Enumerator for query %S: %x", lpwQuery, hResult); break; } dprintf("[WMI] Enumerated created."); ULONG numFound; if (FAILED(hResult = pEnumerator->Next(ENUM_TIMEOUT, 1, &pObj, &numFound))) { dprintf("[WMI] Failed to get the first query element: %x", lpwQuery, hResult); break; } dprintf("[WMI] First result read. hr=%x p=%p", hResult, pObj); if (hResult == WBEM_S_FALSE) { // this is not an error dprintf("[WMI] No results found!"); break; } // get the names of the fields out of the first object before doing anything else. LPSAFEARRAY pFieldArray = NULL; if (FAILED(hResult = pObj->GetNames(NULL, WBEM_FLAG_ALWAYS, NULL, &pFieldArray))) { dprintf("[WMI] Failed to get field names: %x", hResult); break; } dprintf("[WMI] Field Names extracted. hr=%x p=%p", hResult, pFieldArray); // lock the array if (FAILED(hResult = SafeArrayLock(pFieldArray))) { dprintf("[WMI] Failed to get array dimension: %x", hResult); break; } dprintf("[WMI] Field name array locked."); do { dprintf("[WMI] Array dimensions: %u", SafeArrayGetDim(pFieldArray)); // this array is just one dimension, let's get the bounds of the first dimension LONG lBound, uBound; if (FAILED(hResult = SafeArrayGetLBound(pFieldArray, 1, &lBound)) || FAILED(hResult = SafeArrayGetUBound(pFieldArray, 1, &uBound))) { dprintf("[WMI] Failed to get array dimensions: %x", hResult); break; } dprintf("[WMI] Bounds: %u to %u", lBound, uBound); LONG fieldCount = uBound - lBound - SYSTEM_FIELD_COUNT - 1; dprintf("[WMI] Query results in %u fields", fieldCount); fields = (VARIANT**)malloc(fieldCount * sizeof(VARIANT**)); valueTlvs = (Tlv*)malloc(fieldCount * sizeof(Tlv)); values = (char*)malloc(fieldCount * FIELD_SIZE); memset(fields, 0, fieldCount * sizeof(VARIANT**)); memset(valueTlvs, 0, fieldCount * sizeof(Tlv)); memset(values, 0, fieldCount * FIELD_SIZE); for (LONG i = 0; i < fieldCount; ++i) { LONG indices[1] = { i + SYSTEM_FIELD_COUNT }; char* fieldName = values + (i * FIELD_SIZE); SafeArrayPtrOfIndex(pFieldArray, indices, (void**)&fields[i]); _bstr_t bstr(fields[i]->bstrVal); strncpy_s(fieldName, FIELD_SIZE, (const char*)bstr, FIELD_SIZE - 1); valueTlvs[i].header.type = TLV_TYPE_EXT_WMI_FIELD; valueTlvs[i].header.length = (UINT)strlen(fieldName) + 1; valueTlvs[i].buffer = (PUCHAR)fieldName; dprintf("[WMI] Added header field: %s", fieldName); } dprintf("[WMI] added all field headers"); // add the field names to the packet packet_add_tlv_group(response, TLV_TYPE_EXT_WMI_FIELDS, valueTlvs, fieldCount); dprintf("[WMI] processing values..."); // with that horrible pain out of the way, let's actually grab the data do { if (FAILED(hResult)) { dprintf("[WMI] Loop exited via %x", hResult); break; } memset(valueTlvs, 0, fieldCount * sizeof(Tlv)); memset(values, 0, fieldCount * FIELD_SIZE); for (LONG i = 0; i < fieldCount; ++i) { char* value = values + (i * FIELD_SIZE); valueTlvs[i].header.type = TLV_TYPE_EXT_WMI_VALUE; valueTlvs[i].buffer = (PUCHAR)value; VARIANT varValue; VariantInit(&varValue); _bstr_t field(fields[i]->bstrVal); dprintf("[WMI] Extracting value for %s", (char*)field); if (SUCCEEDED(pObj->Get(field, 0, &varValue, NULL, NULL))) { variant_to_string(_variant_t(varValue), value, FIELD_SIZE); } valueTlvs[i].header.length = (UINT)strlen(value) + 1; dprintf("[WMI] Added value for %s: %s", (char*)_bstr_t(fields[i]->bstrVal), value); } // add the field values to the packet packet_add_tlv_group(response, TLV_TYPE_EXT_WMI_VALUES, valueTlvs, fieldCount); pObj->Release(); pObj = NULL; } while ((hResult = pEnumerator->Next(ENUM_TIMEOUT, 1, &pObj, &numFound)) != WBEM_S_FALSE); } while (0); SafeArrayUnlock(pFieldArray); } while (0); if (fields) { free(fields); } if (values) { free(values); } if (valueTlvs) { free(valueTlvs); } if (pObj) { pObj->Release(); } if (pEnumerator) { pEnumerator->Release(); } if (pServices) { pServices->Release(); } if (pLocator) { pLocator->Release(); } CoUninitialize(); if (SUCCEEDED(hResult)) { hResult = S_OK; dprintf("[WMI] Things appeard to go well!"); } } else { dprintf("[WMI] Failed to initialize COM"); } if (FAILED(hResult)) { // if we failed, we're going to convert the error to a string, add it and still return success, but we'll // also include the hresult. char errorMessage[1024]; memset(errorMessage, 0, 1024); _com_error comError(hResult); _snprintf_s(errorMessage, 1024, 1023, "%s (0x%x)", comError.ErrorMessage(), hResult); dprintf("[WMI] returning error -> %s", errorMessage); packet_add_tlv_string(response, TLV_TYPE_EXT_WMI_ERROR, errorMessage); hResult = S_OK; } return (DWORD)hResult; }