java - How to map Windows API CredWrite/CredRead in JNA? -


i'm trying map credwrite/credread in jna in order store thrid party credential used in java application in windows credential manager (os windows 10).

here're original signatures in c:

// https://msdn.microsoft.com/en-us/library/aa375187(v=vs.85).aspx bool credwrite(   _in_ pcredential credential,   _in_ dword       flags );  // https://msdn.microsoft.com/en-us/library/aa374804(v=vs.85).aspx bool credread(   _in_  lpctstr     targetname,   _in_  dword       type,   _in_  dword       flags,   _out_ pcredential *credential );  typedef struct _credential {   dword                 flags;   dword                 type;   lptstr                targetname;   lptstr                comment;   filetime              lastwritten;   dword                 credentialblobsize;   lpbyte                credentialblob;   dword                 persist;   dword                 attributecount;   pcredential_attribute attributes;   lptstr                targetalias;   lptstr                username; } credential, *pcredential;  typedef struct _credential_attribute {   lptstr keyword;   dword  flags;   dword  valuesize;   lpbyte value; } credential_attribute, *pcredential_attribute; 

here're maps in java:

wincrypt instance = (wincrypt) native.loadlibrary("advapi32", wincrypt.class, w32apioptions.default_options);  public boolean credwrite(         credential.byreference credential,         int flags         );  public boolean credread(         string targetname,         int type,         int flags,         pointerbyreference credential         );  public static class credential extends structure {     public int flags;     public int type;     public string targetname;     public string comment;     public filetime lastwritten;     public int credentialblobsize;     public byte[] credentialblob = new byte[128];     public int persist;     public int attributecount;     public credential_attribute.byreference attributes;     public string targetalias;     public string username;      public static class byreference extends credential implements structure.byreference {         public byreference() {         }          public byreference(pointer memory) {             super(memory);                      // line 55         }     }      public credential() {         super();     }      public credential(pointer memory) {         super(memory);          read();                                 // line 65     }      @override     protected list<string> getfieldorder() {         return arrays.aslist(new string[] {                 "flags",                 "type",                 "targetname",                 "comment",                 "lastwritten",                 "credentialblobsize",                 "credentialblob",                 "persist",                 "attributecount",                 "attributes",                 "targetalias",                 "username"         });     } }  public static class credential_attribute extends structure {     public string keyword;     public int flags;     public int valuesize;     public byte[] value = new byte[128];      public static class byreference extends credential_attribute implements structure.byreference {     }      @override     protected list<string> getfieldorder() {         return arrays.aslist(new string[] {                 "keyword",                 "flags",                 "valuesize",                 "value"         });     } } 

first tried write credential windows credential manager:

string password = "passwordtest"; int cbcreds = 1 + password.length();  credential.byreference credref = new credential.byreference(); credref.type = wincrypt.cred_type_generic; credref.targetname = "test/account"; credref.credentialblobsize = cbcreds; credref.credentialblob = password.getbytes(); credref.persist = wincrypt.cred_persist_local_machine; credref.username = "administrator";  boolean ok = wincrypt.instance.credwrite(credref, 0); int rc = kernel32.instance.getlasterror(); string errmsg = kernel32util.formatmessage(rc); system.out.println("credwrite() - ok: " + ok + ", errno: " + rc + ", errmsg: " + errmsg); 

output of try write:

credwrite() - ok: false, errno: 87, errmsg: parameter incorrect. 

then tried read existing credential windows credential manager:

pointerbyreference pref = new pointerbyreference(); boolean ok = wincrypt.instance.credread("build-apps", wincrypt.cred_type_domain_password, 0, pref); int rc = kernel32.instance.getlasterror(); string errmsg = kernel32util.formatmessage(rc); system.out.println("credread() - ok: " + ok + ", errno: " + rc + ", errmsg: " + errmsg); credential cred = new credential.byreference(pref.getpointer());        // line 44 

output of try read:

credread() - ok: true, errno: 0, errmsg: operation completed successfully. exception in thread "main" java.lang.illegalargumentexception: structure exceeds provided memory bounds     @ com.sun.jna.structure.ensureallocated(structure.java:366)     @ com.sun.jna.structure.ensureallocated(structure.java:346)     @ com.sun.jna.structure.read(structure.java:552)     @ com.abc.crypt.wincrypt$credential.<init>(wincrypt.java:65)     @ com.abc.crypt.wincrypt$credential$byreference.<init>(wincrypt.java:55)      @ com.abc.crypt.crypttest.main(crypttest.java:44) caused by: java.lang.indexoutofboundsexception: bounds exceeds available space : size=8, offset=200     @ com.sun.jna.memory.boundscheck(memory.java:203)     @ com.sun.jna.memory$sharedmemory.boundscheck(memory.java:87)     @ com.sun.jna.memory.share(memory.java:131)     @ com.sun.jna.structure.ensureallocated(structure.java:363)     ... 5 more 

so try write failed, try read succeeded failed create credential object based on output.

according webpage of credwrite api, errno 87 got in write test following error:

error_invalid_parameter

certain fields cannot changed in existing credential. error returned if field not match value in protected field of existing credential.

however value put in credential instance new credential rather existing 1 in windows credential manager.

any suggestion or idea on how fix/improve appreciated.

===================================

update after applying fix:

new credread:

public boolean credread(         string targetname,         int type,         int flags,         credential.byreference credential         ); 

test credread:

credential.byreference pref = new credential.byreference(); boolean ok = wincrypt.instance.credread("test/account", wincrypt.cred_type_generic, 0, pref); int rc = kernel32.instance.getlasterror(); string errmsg = kernel32util.formatmessage(rc); system.out.println("credread() - ok: " + ok + ", errno: " + rc + ", errmsg: " + errmsg); system.out.println(string.format("read username = '%s', password='%s' (%d bytes)\n",         pref.username, pref.credentialblob, pref.credentialblobsize)); 

result:

credread() - ok: true, errno: 0, errmsg: operation completed successfully. read username = 'null', password='null' (0 bytes) 

i checked how jna samples in contrib use byreference on out arg , doing in same way newing byreference , pass function.

credread.pcredential should credential.byreference. using pointerbyreference ends passing in pointer null value instead of expected pointer credential struct.

credental.credentialblob needs pointer or pointertype (probably memory if you're initializing block yourself). using inline byte array shifts entire structure array size, callee expecting pointer block of memory.

update

i think misread declaration of credread().

credread should continue use pointerbyreference. use pointerbyreference.getvalue() extract "returned" pointer value credread() in order create new credentials instance based on pointer. pointerbyreference.getpointer() gives address of memory allocated hold pointer value.

public boolean credwrite(     credential credential,     int flags     );  public boolean credread(     string targetname,     int type,     int flags,     pointerbyreference pref     );  pointerbyreference pref = new pointerbyreference() credread(name, type, flags, pref); creds = new credentials(pref.getvalue()) 

Comments

Popular posts from this blog

javascript - Slick Slider width recalculation -

jsf - PrimeFaces Datatable - What is f:facet actually doing? -

angular2 services - Angular 2 RC 4 Http post not firing -