WMI query on remote machine

457 views
Skip to first unread message

Anantharaman Gopalakrishnan

unread,
Oct 17, 2018, 3:04:26 AM10/17/18
to Java Native Access
Hi,

I am trying to write a Java program which uses JNA (5.0.0) to execute WMI query on remote machine (Provided username/password).

I am trying to port this WMI example. I have modified this CPP code here for my testing purpose (directly provided username/password) and it works fine.

But, in my java code, when executing the query using ExecQuery, I am getting the error code 0x80070005.


import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.COM.COMException;
import com.sun.jna.platform.win32.COM.COMUtils;
import com.sun.jna.platform.win32.COM.Wbemcli;
import com.sun.jna.platform.win32.OleAuto;
import com.sun.jna.platform.win32.WTypes.BSTR;
import com.sun.jna.platform.win32.WTypes.LPOLESTR;
import com.sun.jna.platform.win32.WinError;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.ptr.PointerByReference;

public class TestOshiRemote {
public static void main(String[] args) throws Exception {
String machineName = "machineName";
String userNameWithDomain = "\\administrator";
String pass = "Password";

String namespace = "\\\\" + machineName + "\\ROOT\\CIMV2";

BSTR username = OleAuto.INSTANCE.SysAllocString(userNameWithDomain);
BSTR password = OleAuto.INSTANCE.SysAllocString(pass);

BSTR WQL = OleAuto.INSTANCE.SysAllocString("WQL");

// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
HRESULT hres = Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_MULTITHREADED);
switch (hres.intValue()) {
// Successful local initialization
case COMUtils.S_OK:
break;
// COM was already initialized
case COMUtils.S_FALSE:
case WinError.RPC_E_CHANGED_MODE:
break;
// Any other results is an error
default:
throw new COMException("Failed to initialize COM library. : " + hres.intValue());
}

// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = Ole32.INSTANCE.CoInitializeSecurity(null, -1, null, null, Ole32.RPC_C_AUTHN_LEVEL_DEFAULT, Ole32.RPC_C_IMP_LEVEL_IMPERSONATE, null, Ole32.EOAC_NONE, null);
// If security already initialized we get RPC_E_TOO_LATE
// This can be safely ignored
if (COMUtils.FAILED(hres) && hres.intValue() != WinError.RPC_E_TOO_LATE) {
Ole32.INSTANCE.CoUninitialize();
throw new COMException("Failed to initialize security. : " + hres.intValue());
}

PointerByReference pSvc = new PointerByReference();
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
Wbemcli.IWbemLocator loc = Wbemcli.IWbemLocator.create();

// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
// Connect to the namespace with the current user and obtain pointer
// pSvc to make IWbemServices calls.
BSTR namespaceStr = OleAuto.INSTANCE.SysAllocString(namespace);
hres = loc.ConnectServer(namespaceStr, username, password, null, 0, null, null, pSvc);
OleAuto.INSTANCE.SysFreeString(namespaceStr);
// Release the locator. If successful, pSvc contains connection
// information
loc.Release();
if (COMUtils.FAILED(hres)) {
throw new COMException(String.format("Could not connect to namespace %s.", namespace) + " : " + hres.intValue());
}

String user = userNameWithDomain.substring(userNameWithDomain.indexOf("\\") + 1);
String domainName = userNameWithDomain.substring(0, userNameWithDomain.indexOf("\\"));
COAUTHIDENTITY auth = COAUTHIDENTITY.newAuth(user, domainName, pass);
// http://chert.cs.ksu.edu/students/sam/java_com2.htm
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------

// IntByReference intByReference = new IntByReference(-1);
// PointerByReference pointerByReference = new PointerByReference(intByReference.getPointer());

// hres = Ole32.INSTANCE.CoSetProxyBlanket(pSvc.getValue(), Ole32.RPC_C_AUTHN_WINNT, Ole32.RPC_C_AUTHZ_NONE, null, Ole32.RPC_C_AUTHN_LEVEL_CALL, Ole32.RPC_C_IMP_LEVEL_IMPERSONATE, null, Ole32.EOAC_NONE);

// Pointer pAuth = new Pointer(0);
// Pointer.nativeValue(pAuth, -1);

// Pointer pAuth = Pointer.createConstant(-1);
Pointer pAuth = new Pointer(-1);
Pointer.nativeValue(pAuth, -1);
LPOLESTR COLE_DEFAULT_PRINCIPAL = new LPOLESTR(pAuth);
hres = Ole32.INSTANCE.CoSetProxyBlanket(pSvc.getValue(), Ole32.RPC_C_AUTHN_DEFAULT, Ole32.RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, Ole32.RPC_C_AUTHN_LEVEL_PKT_PRIVACY, Ole32.RPC_C_IMP_LEVEL_IMPERSONATE, auth, Ole32.EOAC_NONE);
if (COMUtils.FAILED(hres)) {
new Wbemcli.IWbemServices(pSvc.getValue()).Release();
throw new COMException("Could not set proxy blanket: " + hres.intValue());
}
Wbemcli.IWbemServices svc = new Wbemcli.IWbemServices(pSvc.getValue());

String query = "SELECT BuildNumber,Caption,OSArchitecture,Version FROM Win32_OperatingSystem";

PointerByReference pEnumerator = new PointerByReference();
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// Send the query. The flags allow us to return immediately and begin
// enumerating in the forward direction as results come in.
BSTR queryStr = OleAuto.INSTANCE.SysAllocString(query);
hres = svc.ExecQuery(WQL, queryStr, Wbemcli.WBEM_FLAG_FORWARD_ONLY | Wbemcli.WBEM_FLAG_RETURN_IMMEDIATELY, null, pEnumerator);
OleAuto.INSTANCE.SysFreeString(queryStr);
if (COMUtils.FAILED(hres)) {
svc.Release();
throw new COMException(String.format("Query '%s' failed.", query) + " : " + hres.intValue());
}
Wbemcli.IEnumWbemClassObject obj = new Wbemcli.IEnumWbemClassObject(pEnumerator.getValue());

System.out.println("Done");
}
}


import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WTypes.LPOLESTR;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.win32.W32APIOptions;

public interface Ole32 extends com.sun.jna.platform.win32.Ole32 {
Ole32 INSTANCE = Native.load("Ole32", Ole32.class, W32APIOptions.DEFAULT_OPTIONS);

int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 0x06;

int RPC_C_AUTHN_DEFAULT = 0xFFFFFFFF;
int RPC_C_AUTHZ_DEFAULT = 0xffffffff;

HRESULT CoSetProxyBlanket(Pointer pProxy, int dwAuthnSvc, int dwAuthzSvc, LPOLESTR pServerPrincName, int dwAuthnLevel, int dwImpLevel, COAUTHIDENTITY pAuthInfo, int dwCapabilities);
}



import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;

@Structure.FieldOrder({"User", "UserLength", "Domain", "DomainLength", "Password", "PasswordLength", "Flags"})
public class COAUTHIDENTITY extends Structure {
public Pointer User;
public int UserLength;
public Pointer Domain;
public int DomainLength;
public Pointer Password;
public int PasswordLength;
public int Flags;

public static COAUTHIDENTITY newAuth(String uname, String domainName, String pass) {
COAUTHIDENTITY auth = new COAUTHIDENTITY();
auth.User = new Memory(Native.WCHAR_SIZE * (uname.length() + 1));
auth.User.setWideString(0, uname);
auth.UserLength = uname.length();

auth.Password = new Memory(Native.WCHAR_SIZE * (pass.length() + 1));
auth.Password.setWideString(0, pass);
auth.PasswordLength = pass.length();

auth.Domain = new Memory(Native.WCHAR_SIZE * (domainName.length() + 1));
auth.Domain.setWideString(0, domainName);
auth.DomainLength = domainName.length();

auth.Flags = 1;

return auth;
}
}



Error occurs in line 

hres = svc.ExecQuery(WQL, queryStr, Wbemcli.WBEM_FLAG_FORWARD_ONLY | Wbemcli.WBEM_FLAG_RETURN_IMMEDIATELY, null, pEnumerator);

For the provided credentials, my version of C++ code is working fine. Also, I can use power-shell & WMIC to retrieve the data. 

I am using oshi library as my inspiration.

Any help regarding this would be greatly appreciated.

Thanks & Regards,
Anantharaman.

Matthias Bläsing

unread,
Oct 17, 2018, 3:32:30 AM10/17/18
to jna-...@googlegroups.com
Hi Anantharaman,

Am Mittwoch, den 17.10.2018, 00:04 -0700 schrieb Anantharaman Gopalakrishnan:
> public static COAUTHIDENTITY newAuth(String uname, String domainName, String pass) {
> COAUTHIDENTITY auth = new COAUTHIDENTITY();
> auth.User = new Memory(Native.WCHAR_SIZE * (uname.length() + 1));
> auth.User.setWideString(0, uname);
> auth.UserLength = uname.length();
>
> auth.Password = new Memory(Native.WCHAR_SIZE * (pass.length() + 1));
> auth.Password.setWideString(0, pass);
> auth.PasswordLength = pass.length();
>
> auth.Domain = new Memory(Native.WCHAR_SIZE * (domainName.length() + 1));
> auth.Domain.setWideString(0, domainName);
> auth.DomainLength = domainName.length();
>
> auth.Flags = 1;
>
> return auth;
> }

The usage of `auth.Flags` does not match the C++ version. The C++
Version sets:

authIdent.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

According to:

https://docs.microsoft.com/en-us/windows/desktop/api/wtypesbase/ns-wtypesbase-_coauthidentity

The values are:

SEC_WINNT_AUTH_IDENTITY_ANSI 0x1
SEC_WINNT_AUTH_IDENTITY_UNICODE 0x2

So it should read (literal or I would advise creating named constants):

auth.Flags = 0x2;

If that fails, please create a project (preferable maven) that
recreates the problem and add a desccription what is needed to execute
it.

Greetings

Matthias


Anantharaman Gopalakrishnan

unread,
Oct 22, 2018, 3:19:31 AM10/22/18
to Java Native Access
Hi Matthias,

Sorry for replying late.

Your suggestion helped me a lot. Thanks.

Thanks & Regards,
Anantharaman G.
Reply all
Reply to author
Forward
0 new messages