WORK IN PROGRESS
This page is currently being created or overworked. Please don't treat it as a finished document.
Some initial words (You can skip this if you only want the facts )
In this tutorial I want to create a Java Program that is able to access a remote Windows machines Service Registry and for example start and stop services on that.
Access will be done during DCE/RPC calls transported using SMB named pipes. In contrast to allmost all other techniques this has the smallest configuration impact on the targeted machine. All you have to have configured are the "File and Printer Sharing" and have the administrative Shares enabled. In most cases Windows is allready configured correctly.
There seem to be several Java libraries that offer services in the DCE/RPC sector. The one I liked most was JCIFS, which seems to be the base of most, but not all of the other solutions.
While doing the basic stuff with JCIFS was pretty easy, finding out how to do DCE/RPC calls was allmost impossible. Unfortunately JCIFS allready had stuff for a lot of DCE/RPC services, but how to use them was explained nowhere and nither Google nor the Mailinglist was able or willing to explain how to do it. So I had to look how JCIFS did stuff internally. So the source was with me, but it turned out it was more the dark side of the source.
The svcctl service I wanted to acces didn't have any implementation in JCIFS so I had to create my own. Luckily this code can be generated automatically from so-called IDL (http://en.wikipedia.org/wiki/Microsoft_Interface_Definition_Language) files. This interface definition was a well protected secret of Microsoft. The guys at the Samba project did quite a good job of reverse engineering this. Luckily Microsoft had to publish the specification in 2002 in order to avoid major trouble with the European Union (http://www.theregister.co.uk/2002/03/19/why_microsofts_eu_concession/).
Based upon this IDL it is possible to generate the code for communicating with MS services automatically. One implementation of such a compiler is MIDLC (http://jcifs.samba.org/src/) which is available from the JCIFS site. It seems that this is actually only used occasionally as I couldn't manage to get it running on a non-liunux machine and it did seem to have quite some quirks. I assume this was used to generate the Stubs used in JCIFS and hasn't been used or implroved for a long time (2006).
Next unfortunate thing is that midlc allready comes with a set of idl files. From having a look at them the svcctl.idl seems to be implemented as far as the Samba guys managed to do this (Not all service functions are available). Unfortunately the ones I was looking for were missing (CreateServiceW, DeleteServiceW, StopServiceW, ...).
So If you now think: "Hey ... so I'll get the official IDL file from Microsoft and use that" (http://msdn.microsoft.com/en-us/library/cc245860(v=prot.10).aspx) ... well what should I say ... the formats are different and therefore you can't use them out of the box. But they will be helpfull in extending the existing file.
So far, so good ... Now I used midlc on a linux machine to generate the stubs for communicating with SVCCTL. I used the default files first because I had to learn how do do these calls first and I didn't want to get stuck, just because my IDL was wrong.
Unfortunateley I wasted about 5 full days on this and finally abandoned my quest ... at least for a little while. Finding out how to do stuff with a completely undocumented API based upon untested code following an undocumented protocol by looking a binary WireShark dumps of a tool called PSExec (http://technet.microsoft.com/de-de/sysinternals/bb897553) was a total nightmare and I was on the brink of going insane on it.
I even offered JCIFS professionals a bounty (not the chocolate bar) for providing me with a solution, but not a single "professional" even answered ... "Hail to the glory of open-source!!!!".
Luckily my employee stumbled over Alfresco JLan (http://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/root/projects/alfresco-jlan/) and discovered that it could do a lot more than simply copy files from one server to another. It actually came with a full implementation of the SVCCTL Service. This allowed to build the Software I was trying to build for so long. It took quite some time to figgure out how to build such an application with the library that was available from Alfresco, but we managed to get it going.
The general functionality was implemented pretty fast after that and we sarted implementing some logic that sent quite large amounts of data over Named Pipes using JLan. This is where we began having trouble. Errors complaning about the size of data packets keept on occuring, ruining the data-transfer. We avoided this by breaking everything down to really small pieces of data, but I was never really satisfied with this and it didn't look as if there was any support available from anywhere . So this was only a Proof-Of-Concept solution.
Then one day I had the Idea to use a stripped-down minimal implementation of a JLan program and to have a look at what it does in WireShark and to try to replicate what JLan did in JCIFS. With this approach it took another two days and I was actually able to start a Windows service on a remote machine using JCIFS.
The rest of this tutorial will explain in detail the steps needed to do this. Hopefully this document might save the sanity of the one or the other developer also going nuts on something similar
Generating the Stub
Ok ... so before we can start coding we have to generate the stub code, that we will use do encode/decode the DCE/RPC requests. This is done using the midlc tool (http://jcifs.samba.org/src/midlc-0.6.1.tar.gz). Download it to a linux machine and build it:
You can leave away the "make install" documented in the README.txt as this failled to execute and isn't really needed.
Now you have the "midlc" binary and can start generating code. So if you simply execute the "midlc" binary, it will present you the options:
Of course everybody knows what the "-v", "-d", "-s" and "-Dmacro" oprions are ... well ... I couln't really find any form of documentation that explained them. But it seemed that I didn't need them in order to get my code generated.
The important options are "-t", which controls for which library the code is generated for:
- "jcifs": Generates code to be used with jcifs ... who would have thought about that!
- "java": Generates code to be used with jarapac (http://sourceforge.net/projects/jarapac/) which seems to be yet another dead project in the DCE/RPC area.
- "samba": Generates "segmentation faults"
- "c": Generates an whole bunch of C code and header files. As we will be using Java I didn't really waste a second on this.
The other option that seemed obvious was "-o" this controls the name of the output file. So if you set that option to "myCoolFile", then midlc will generate myCoolFile.java" (or an unnamed segmentation fault or "myCoolFile.c" and "myCoolFile.h").
Inside the midlc package there is a directory "idl" which contains several IDL files for different Windows services. The one I was interested in was "idl/svcctl.idl", so I used that one to generate the initial stub:
The resulting "svcctl.java" was now the starting point of my JCIFS-based SVCCTL client.