Monday 7 November 2011

Tomcat CPU Hog Monitoring service

Have you ever been in this kind of trouble? You use Tomcat as the servlet container. In general your web service runs smoothly, however it has CPU hog issue randomly on the production server of your customer. You are told it is not a load issue (CPU is expected high when there is a huge demand for your service, it can only be solved by load balancing) which means your Java coding may have a bug or bad design. The problem is, you are unable to reproduce this issue in your environment, and even your customer can’t reproduce it on purpose.


Anyway, the issue does happen, but no pattern at all. You are under a big pressure to sort it out quickly, what can you do?


Struggled and frustrated? Don’t worry, NanoFish comes to rescue!


Please check this PDF version for the details. You can download the binary and source code, I wish they are helpful.

Tuesday 25 October 2011

Test Radius Challenge Response in NTRadPing

If you lack of the Challenge-Response (CR) VPN device, instead you can use NTRadPing to check or show DualShield Radius Server CR feature.

Basically, you need to create a radius logon procedure with two logon steps in DualShield.

With NTRadPing, in the second step, add the State attribute returned from the first step login. Please check the PDF version for the details.

Monday 24 October 2011

Reset DualShield sa Password

In some situations, you may need to reset sa password. For instance, you forget the sa password of DualShield and have no other administratative accounts to login.

You are stuck, aren't you? Luckily, DualShield recently provided a running mode called safe mode in which you can reset the sa password.

Windows Version

Add -Ddual.safe.mode=true in Java Options which can be shown by "tomcat6w.exe //ES//dualshield"

Linux Version

Edit the file "/etc/init.d/dualshield", add "-Ddual.safe.mode=true \" just below the line "-Djava.io.tmpdir=$TMP_DIR \"

Please check this PDF version for the details.

Monday 26 September 2011

WinDBG remote debugging with SSH port forwarding

When I tried to apply my “tunnel” onto Java remote debugging, I found someone got a better approachSSH port forwarding.

It is very cool, so I’d like to try it on WinDBG.

If the machine with public IP has Linux OS installed, it is very easy to start a SSH daemon. However I got one machine which has windows 2003 installed, so I have to find a Windows version sshd (SSH deamon). I think that freeSSHd is the best one among the free editions.

As the port 22 (default SSH port) on my server is taken by another process, I use 9000 instead, and listen on “All interfaces”. Next, go to the tab “Tunnelling”, check on both “local port forwarding” option and “remote port forwarding”.

We are going to use WinDBG to do the remote debugging, certainly it is done on Windows system, so we need a windows version SSH client. I prefer a CLI version of SSH client, so I choose plink.exe (from the popular putty site).

Which parameters do we need in the SSH client? If you are new to SSH, please have a look of the hyperlinks in this document. However, I believe it is much easier to understand them with an example, so let’s give the instructions first.

On the client machine where the application you want to debug is running on, run debugger server (dbgsrv.exe), specify the port as 1012 (you can use any free one).

dbgsrv –t tcp:port=1012

Check the tab Processes in Task Manager to make sure the debug server is running. Also, open a notepad as the application we are going to debug.

Next, on the same client machine, run

plink –P 9000 -R 9001:localhost:1012 nanoart@sshserver -N

Or, you can run the following command on the relay machine instead.

plink –P 9000 -R 9001:[ip of client machine]:1012 nanoart@sshserver -N

This is very useful when you are debugging GINA or credential provider which prevent you running a user-mode application.

At this stage, we’d better to have some explanations on the plink command.

The parameter -R specifies a remote port forwarding. It asks SSH server to start a listener process on the remote machine (SSH server) with port 9001. Thus the remote machine can accept connections and forwarding them back over SSH back to the machine that started the SSH port forward session, and then from there onto the client machine. Because my SSH sever is not running on the default port 22, I have to specify it with the parameter –P. The last parameter –N means “don't start a shell/command”, this is optional. Of course, you need to provide a SSH login account (“nanoart” in this example).

On developer’s machine, run this command,

plink –P 9000 -L 1012:localhost:9001 nanoart@sshserver –N

The parameter -L means local port forwarding. It results in a process listening on a port (here 1012) on the developer’s machine . This process/port will accept connections and forward them via the remote authenticated SSH (sshd) process to another host:port combination (here it is localhost:9001).

Note: The localhost might appear at first sight a little confusing, but don't forget host:port pair is relative to SSH server in local port forwarding. If localhost is used, it is the SSH server itself. However it is relative to the initiating end of this SSH connection, i.e. the workstation in the case of remote port forwarding.

Now, the route is tunnelled between the developer’s machine and the client’s machine.

On the developer’s machine, we can run

windbg –premote tcp:port=1012, server=localhost

It is worth mentioning that you may need to switch the order of port forwarding (first local port forwarding, then remote port forwarding), otherwise it may not work if you are using the freeSSHd as the SSH server.

In WinDBG, we can see all the processes of the client’s machine at the remote site.

Also, we can attach to the sample process “notepad.exe”.

Bravo, the remote debugging with SSH port forwarding succeeded! Finally I can forget the dbengprx.exe issue.

Please read the full version which has some figures to help you understand it easily.

The foible of Apple PackageMaker

Using PackageMaker GUI, I created a package script which has a Postinstall action "Open File". The package (built with GUI) worked as expected, it did launch the installed application of mine after the installtion. However, I got a warning when I tried to build the same script with PackageMaker command line.

/Developer/usr/bin/packagemaker --doc makedma.pmdoc --out dmgsource/Installer.pkg
2011-09-26 11:59:59.533 packagemaker[212:903] Warning: unknown or deprecated action

In addition, the command line built package did not launch the installed application.

It sounds like no answer so far, as someone asked the same question on stackoverflow.

The command line PackageMaker is just one job in my shell script which builds xcode projects at the top and creates a dmg file at the end, so this foible caused some trouble to me.

I just wonder if it is another strategy from Apple - leave some glitches on purpose so that some people can make a good living on that? You know what I mean.

Wednesday 21 September 2011

Remote Debugging with Visual Studio 2008

I accidentally found that the port(4015 as the default) of MSVC(Visual Studio 2008) remote debugging monitor(msvsmon.exe) is only for the authentication, the debug data is transfered through other ports which are created by the authetication process.

This mechanism makes it impossible to do the remote debugging over firewall(s). Please see my experiment in details.

Sunday 18 September 2011

Tunnel implementation

In order to make WinDBG remote debugging work through firewall(s), I decided to write my own repeater, instead of using its dbengprx.exe, which doesn’t work with “Two Firewalls”(see my previous blog).

With Boost ASIO, implementing the prototype is not a big job. The instructions to use the tunnel are as following.

First, run dbgsrv.exe at the debuggee’s side.

Second, run tunnel.exe on the server with a public IP address. It has two listening ports, 9000 and 9001.

Third, at the debuggee’s side, run tunnel outward (public IP) 9001 (dbgsrv ip) 1012. Unlike “dbgsrv.exe”, many other debugger servers(like msvsmon.exe) do not have the feature “clicon”, so I made my tunnel be able to relay the traffic between the public server and the dbgsrv machine. As you can see, the connection direction is outward relative to the relay server itself.

You can run the above outward direction tunnel on the same machine where dbgsrv is running, however it is very useful to run it on another machine when you are debugging GINA or credential provider which makes impossible run a cmd application, because you haven’t logged in.

Finally, run windbg.exe at the debugger side, but the server parameter should be public IP:9000, instead of debuggee IP:1012

  • dbgsrv.exe -t tcp:port=1012
  • tunnel inward 9000 9001
  • tunnel outward (public IP) 9001 (dbgsrv ip) 1012
  • windbg -premote tcp:server=(public ip),port=9000

I did a test, it worked. I could attached the process which I wanted to debug.

Please read the PDF version for the details. You can also download the source code, I would be very happy if you can improve it and make it as a mature product.

Saturday 17 September 2011

My WinDBG remote debugging trial on "Two Firewall" scenario

You can do remote debugging with WinDBG, basically use the following instructions(with the displaying order).

  • At debuggee side, run dbgsrv.exe –t tcp:port=1012,password=longjump
  • At debugger side, run windbg –premote tcp:port=1012,server=debuggee’s ip,password=longjump

Pretty easy, isn’t it? Well, you probably know the question I am going to ask, what about the situation when the debuggee is behind a firewall?

As a matter of fact, the debugger himself is generally behind the firewall as well. As a developer, you might be able to persuade your network administrator to modify the firewall settings for your debug purpose, but it’s simply not practical to ask your client to change his firewall, so the forwarded connection to the Debuggee is unfeasible.

MS documentation provides an example titled “Two Firewalls” which sounds exactly what I wanted. Actually there is a bit difference, it is about kernel debugging while I only wanted to debug the user mode application. Anyway, it has a backward connection between the repeater and the debuggee, it is called “smart client” in WinDBG. I decided to have a go. Please read my full story here.

Monday 12 September 2011

Use Twitter to send out OTP in DualShield

Apart from the classical SMS and SMTP channels, DualShield can utilize Twitter to send OTP out. Obviously, you need to configure the Twitter Gateway. Deepnet provided a tool to generate the necessary keys, which is now obselete. You can use Twitter web service to get those keys, please read this pdf for the details.

Wednesday 3 August 2011

Troubleshoot Java CPU Hog

I am not scared of the CPU hog in the application which is developed with c(c++). Using WinDBG, you can track down the processor hog by its detailed instructions. What about Java application, especially the webapp you developed and it is hosted by TOMCAT? Recently,I was asked to have a look of tomcat high CPU problem, it forced me to learn some JAVA debug and profile skill. Fortunately, with JDK 1.6, it is possible to use java.lang.management.ManagementFactory.getThreadMXBean() to pin down the offensive thread, then print out its StackTrace.


Please save the following code(updated) to a file called "cpusage.jsp", and place it into the subfolder tomcat\webapps\ROOT. Once you notice a hign CPU of tomcat service, then launch the browser and visit http://localhost:8080/cpusage.jsp(you may need to change the port). Refresh the page after 2-3 seconds, it will list all active threads, and you can click the hyperlink to see the StackTrace of the related thread. Please read the pdf version to see a detailed demo.





<%@ page import="java.lang.management.*, java.util.*" %>
<%!
Map cpuTimes = new HashMap();
Map cpuTimeFetch = new HashMap();
%>
<%
out.println("<h1><center>Tomcat CPU Profiler</center></h1>");

long cpus = Runtime.getRuntime().availableProcessors();
out.print("<p>The number of processors available to JVM = " + cpus + "</p>");
ThreadMXBean threads = ManagementFactory.getThreadMXBean();
long now = System.currentTimeMillis();
ThreadInfo[] t = threads.dumpAllThreads(false, false);

out.print("<p>Currently it has " + t.length + " threads, below only the active(CPU percentage > 0) threads are listed.</p>");
out.print("<p>The data format is: (thread index) | (thread name) (cpu percentage)</p>");

for (int i = 0; i < t.length; i++)
{
long id = t[i].getThreadId();
Long idid = new Long(id);
long current = 0;
if (cpuTimes.get(idid) != null)
{
long prev = ((Long) cpuTimes.get(idid)).longValue();
current = threads.getThreadCpuTime(t[i].getThreadId());
long catchTime = ((Long) cpuTimeFetch.get(idid)).longValue();
double percent = (current - prev) / ((now - catchTime) * cpus * 10000);
if (percent > 0 && prev > 0)
{
out.println("<li>" + i + " | <a href=cpusage.jsp?ti=" + i +">"+ t[i].getThreadName() + "</a>     " + percent);
}
}
cpuTimes.put(idid, new Long(current));
cpuTimeFetch.put(idid, new Long(now));
}

if (request.getParameter("ti") != null)
{
int index = Integer.parseInt(request.getParameter("ti"));

StackTraceElement[] stackElements = t[index].getStackTrace();

out.println("<p>The stack for thread <i>" + t[index].getThreadName() + "</i> :</p>");
out.println("<table><tr><td>Line number</td><td>Full class name</td><td>Method name</td></tr>");

for (int lcv = 0; lcv < stackElements.length; lcv++)
{
out.println("<tr>");
out.println("<td>" + stackElements[lcv].getLineNumber() + "</td>");
String className = stackElements[lcv].getClassName();
out.println("<td>" + className + "</td>");
out.println("<td>" + stackElements[lcv].getMethodName() + "</td>");
out.println("</tr>");

}
out.println("</table>");
}

%>

Wednesday 27 July 2011

DualShield - manually switch protocol

You can select HTTP/SSL protocol when you install DualShield. Probably you install the trial version with HTTP, after trial you want to move it to production environment which needs SSL. Compared to reinstallation, it is a bit hassle to do the switch manually, but it is possible.


Please open the following files to make the change(http -> https)



C:\Program Files\DualShield\config\appsso-metadata.xml (4 hits)
Line 5: entityID="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn2:$deepnet.dualserver.ssoport">
Line 7: <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
Line 20: Location="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn2:$deepnet.dualserver.ssoport/appsso/login"/>
Line 24: Location="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn2:$deepnet.dualserver.ssoport/appsso/logout" />
C:\Program Files\DualShield\config\appsso.properties (2 hits)
Line 4: dasProvisioningUri=$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn:$deepnet.dualserver.provport/das5/xmlrpc
Line 21: management_protocol=$deepnet.dualserver.protocol
C:\Program Files\DualShield\config\ManagementConsole.xml (3 hits)
Line 9: protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
Line 13: Location="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn:$deepnet.dualserver.manageport/dmc/logout" />
Line 17: Location="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn:$deepnet.dualserver.manageport/dmc/" />
C:\Program Files\DualShield\config\SelfServiceConsole.xml (3 hits)
Line 9: protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
Line 13: Location="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn2:$deepnet.dualserver.slfsrvport/dss/logout" />
Line 17: Location="$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn2:$deepnet.dualserver.slfsrvport/dss/" />
C:\Program Files\DualShield\manconsole.url (1 hits)
Line 2: URL=$deepnet.dualserver.protocol://$deepnet.dualserver.fqdn:$deepnet.dualserver.manageport/dmc

Also, comment out all connectors with http protocol, and uncomment the SSL connectors in the Tomcat configuration file server.xml.


 
C:\Program Files\DualShield\tomcat\conf\server.xml (18 hits)
Line 99: <Connector port="$deepnet.dualserver.provport" protocol="HTTP/1.1"
Line 105: <Connector protocol="HTTP/1.1" SSLEnabled="true"
Line 114: <Connector protocol="HTTP/1.1" SSLEnabled="true"
Line 120: <Connector protocol="HTTP/1.1" SSLEnabled="true"
Line 127: <!-- A "Connector" using the shared thread pool-->
Line 129: <Connector executor="tomcatThreadPool"
Line 134: <!-- Define a SSL HTTP/1.1 Connector on port 8443
Line 139: <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
Line 144: <!-- Define an AJP 1.3 Connector on port 8009 -->
Line 145: <!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
Line 213: <Connector port="$deepnet.dualserver.ssoport" protocol="HTTP/1.1"
Line 217: <Connector port="$deepnet.dualserver.ssomanport" protocol="HTTP/1.1"
Line 222: <Connector protocol="HTTP/1.1" SSLEnabled="true"
Line 228: <Connector protocol="HTTP/1.1" SSLEnabled="true"
Line 293: <Connector port="$deepnet.dualserver.slfsrvport" protocol="HTTP/1.1"
Line 299: <Connector protocol="HTTP/1.1" SSLEnabled="true"
Line 365: <Connector port="$deepnet.dualserver.manageport" protocol="HTTP/1.1"
Line 371: <Connector protocol="HTTP/1.1" SSLEnabled="true"

Thursday 21 July 2011

CryptoKey Registration

With Fiddler, you can see the detailed steps(registerDevice, getPolicy, getPublicKey, backupCredential) of CryptoKey Registration.


Note: "Management+Console" is a domain where the token is registered to.



POST http://192.168.222.9:8088/das5/service/Management+Console HTTP/1.1
Content-Type: text/xml
User-Agent: deepnet xmlrpc 1.0
Host: 192.168.222.9:8088
Content-Length: 555
Connection: Keep-Alive

<?xml version="1.0"?>
<methodCall><methodName>das.registerDevice</methodName>
<params><param><value><struct><member><name>loginName</name><value>mine</value></member></struct></value></param><param><value><struct><member><name>password</name><value>password</value></member></struct></value></param><param><value><struct><member><name>name</name><value>CryptoKey</value></member></struct></value></param><param><value><struct><member><name>serial</name><value>070007A9080865D813EF</value></member></struct></value></param></params></methodCall>

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml
Content-Length: 359
Date: Thu, 21 Jul 2011 09:47:33 GMT

<?xml version="1.0" encoding="ISO-8859-1"?>
<methodResponse>
<params>
<param>
<value><array><data><value><string>OK</string></value><value><string>Succeeded</string></value><value><struct><member><name>serial</name><value><string>070007A9080865D813EF</string></value></member></struct></value></data></array></value>
</param>
</params>
</methodResponse>



POST http://192.168.222.9:8088/das5/service/Management+Console HTTP/1.1
Content-Type: text/xml
User-Agent: deepnet xmlrpc 1.0
Host: 192.168.222.9:8088
Content-Length: 319
Connection: Keep-Alive

<?xml version="1.0"?>
<methodCall><methodName>das.getPolicy</methodName>
<params><param><value><struct><member><name>loginName</name><value>mine</value></member></struct></value></param><param><value><struct><member><name>name</name><value>CryptoKey</value></member></struct></value></param></params></methodCall>

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml
Content-Length: 2233
Date: Thu, 21 Jul 2011 09:47:33 GMT

<?xml version="1.0" encoding="ISO-8859-1"?>
<methodResponse>
<params>
<param>
<value><array><data><value><string>OK</string></value><value><struct><member><name>tokenLimit</name><value><i4>0</i4></value></member><member><name>activate</name><value><string>0</string></value></member><member><name>messageChannel</name><value><string>SMS</string></value></member><member><name>enforcePasswordPolicy</name><value><boolean>0</boolean></value></member><member><name>enforceAntivirusPolicy</name><value><boolean>0</boolean></value></member><member><name>enforceSecurityPolicy</name><value><boolean>0</boolean></value></member><member><name>enforceAntivirus</name><value><boolean>0</boolean></value></member><member><name>enforceAntivirusRT</name><value><boolean>0</boolean></value></member><member><name>passwordRecovery</name><value><string>0</string></value></member><member><name>passwordMinLen</name><value><i4>1</i4></value></member><member><name>passwordMinUpper</name><value><i4>1</i4></value></member><member><name>passwordMinLower</name><value><i4>1</i4></value></member><member><name>passwordMinNumber</name><value><i4>1</i4></value></member><member><name>passwordMinSymbol</name><value><i4>1</i4></value></member><member><name>passwordLifeTime</name><value><i4>30</i4></value></member><member><name>passwordHistory</name><value><i4>30</i4></value></member><member><name>passwordHint</name><value><boolean>1</boolean></value></member><member><name>infectedActionRealtime</name><value><string>DISINFECT</string></value></member><member><name>suspiciousActionRealtime</name><value><string>PROMPT</string></value></member><member><name>infectedActionOndemand</name><value><string>DISINFECT</string></value></member><member><name>suspiciousActionOndemand</name><value><string>PROMPT</string></value></member><member><name>antivirusAgeLock</name><value><i4>1</i4></value></member><member><name>lockdownPerm</name><value><i4>5</i4></value></member><member><name>lockdownNotify</name><value><i4>3</i4></value></member><member><name>autoLockup</name><value><i4>10</i4></value></member><member><name>autoReminder</name><value><i4>60</i4></value></member></struct></value></data></array></value>
</param>
</params>
</methodResponse>



POST http://192.168.222.9:8088/das5/service/Management+Console HTTP/1.1
Content-Type: text/xml
User-Agent: deepnet xmlrpc 1.0
Host: 192.168.222.9:8088
Content-Length: 335
Connection: Keep-Alive

<?xml version="1.0"?>
<methodCall><methodName>das.getPublicKey</methodName>
<params><param><value><struct><member><name>loginName</name><value>mine</value></member></struct></value></param><param><value><struct><member><name>serial</name><value>070007A9080865D813EF</value></member></struct></value></param></params></methodCall>

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml
Content-Length: 451
Date: Thu, 21 Jul 2011 09:47:33 GMT

<?xml version="1.0" encoding="ISO-8859-1"?>
<methodResponse>
<params>
<param>
<value><array><data><value><string>OK</string></value><value><base64>
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCRSGBQZG3qnuIvUsmvAdUHj8KeLqyn5VDz
LvP018RJN8AiyUAJj9N6AW4j2OggFU1RK+WCW0iWdgwUwpGQn/EHWuNKNVBy8gQubiR1bzj3
zsO335QCg9GJpk/ykB2g/ytVhRxwb/9LQJ4S5DguuO6CQzNxcx0yqbjSE0ezsPrn8wIDAQAB

</base64></value></data></array></value>
</param>
</params>
</methodResponse>



POST http://192.168.222.9:8088/das5/service/Management+Console HTTP/1.1
Content-Type: text/xml
User-Agent: deepnet xmlrpc 1.0
Host: 192.168.222.9:8088
Content-Length: 560
Connection: Keep-Alive

<?xml version="1.0"?>
<methodCall><methodName>das.backupCredential</methodName>
<params><param><value><struct><member><name>loginName</name><value>mine</value></member></struct></value></param><param><value><struct><member><name>serial</name><value>070007A9080865D813EF</value></member></struct></value></param><param><value><base64>Cgcg657W6JTLdkrwMivIkbDTyZ5KlH04umjZkGl/6agE8UVUcVijkh3fMe9hsVf0QMWwohDi
Gi5zHeGyZrGVFfX8dL3lBH1JkBuu2aED9ag6a+J0x6bLoa5iieu/nFYc8V3uUXS15mgTbox1
kCbgVlXuRRAAbiNRZMaQLKe46zc=</base64></value></param></params></methodCall>

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml
Content-Length: 239
Date: Thu, 21 Jul 2011 09:47:33 GMT

<?xml version="1.0" encoding="ISO-8859-1"?>
<methodResponse>
<params>
<param>
<value><array><data><value><string>OK</string></value><value><string>Succeeded</string></value></data></array></value>
</param>
</params>
</methodResponse>

Wednesday 6 July 2011

Server Agent Discovery

Deepnet Windows logon client uses broadcasting technique to locate where the server agent is. In the situation which the broadcasting doesn't work, you may need to modify the registry to specify the server address(IP and port).



HKEY_LOCAL_MACHINE\\SOFTWARE\\Deepnet Security\\Windows Logon

String value: DCAgents=x.x.x.x:port1,y.y.y.y:port2

Note: it is out of date.

DualShield Ports

Deepnet DualShield system involves quite a few ports, you may forget them after the installation. Don't worry, there is a summary file you can review them, it is located at the folder $INSTALL_PATH\Uninstaller, the file name is called "InstallSummary.htm"


For your convenience, here is the summary of a typical installation.



Installation Path
C:\Program Files\Deepnet DualShield
Server Configuration
Server FQDN: dualshield.deepnetsecurity.local
Use SSL: false
Certificate Path:
Administration Port: 8070
Authentication Port: 8071
Provisioning Port: 8072
Management Console Port: 8073
SSO Logon Port: 8074
SSO Management Port: 8075
Self Service Port: 8076

Database Connection
Use the existing database: false
Database Type: mysql
Database Name: dualshield
SQL Server: localhost
SQL Port: 3306
User Name: root
Password: ********

Agent Registration Data

DualShield Management Console allows you to register an agent manually. All fields are self-explained except the last one - Agent Registration Data.


For SSO agent(it is very rare to register this kind of agent), you have to fill it with the correct info



-----BEGIN DUAL AGENT CONFIGURATION-----
bWFuYWdlUHJvdG9jb2w9aHR0cCxtYW5hZ2VQb3J0PTgwNzU=
-----END DUAL AGENT CONFIGURATION-----

Are you curious to know what it means? do base64 decode, the result is



-----BEGIN DUAL AGENT CONFIGURATION-----
manageProtocol=http,managePort=8075
-----END DUAL AGENT CONFIGURATION-----

Friday 24 June 2011

Use "IP Modem" in Deepnet DualShield

With DualShield, you try to use GPRS Modem to send SMS and may face one of the following situations.



  • You installed a 64bit version DualShield, and it is hard for you to find a 64bit driver of your modem working on a 64bit OS.

  • You installed DualShield on a virtual machine, and the host (like ESXi) can’t pass though your modem device.


Fortunately, there is a workaround, assume you have a physical machine which can install the modem driver.


On the above image, we label the PC to which the modem is physically connected as “Remote PC [Server]”. After installing the modem driver on this PC, check “Device Manager” to see if the modem device is available.


Also check what the COM port is.


Now run “Pira CZ Remote COM Port” (a freeware application which can be downloaded from http://www.pira.cz/eng/piracom.htm, not sure if it has service version. If not, you can use some utility to turn it to a service anyway), make sure select the correct COM port. You can use the default “Server Port” (=23).


Now your modem is converted to an IP modem which can be accessed from another machine (Local PC [Client] labelled in the first image), then how?
You need another software “HW VSP3 - Virtual Serial Port” which can be downloaded from http://www.hw-group.com/products/hw_vsp/index_en.html, it has 64 bit support.


It will create a virtual COM port on this PC which maps to IP and port provided by piracom we set it at the first stage.


Once connected, DualShield can use this like a local COM port.


What if you are using linux OS? You can use remserial or socat.


For your convenience, here are the commands respectively,



Give access to a RS232 device over a network.
// remserial command
remserial -d -p 23 -s "9600 raw" /dev/ttyS0 &
// socat command
socat tcp-l:23,reuseaddr,fork file:/dev/ttyS0,nonblock,raw,echo=0,waitlock=/var/run/tty

Connect a Linux program that needs a serial port to a remote serial port.
// remserial command
remserial -d -r 192.168.222.124 -p 23 -l /dev/remserial1 /dev/ptmx &
// socat command
socat pty,link=/dev/netcom0,raw tcp: 192.168.222.124:23 &

The PDF version can be accessed from here.


Reference


Pira CZ Remote COM Port

HW VSP3 - Virtual Serial Port

Remserial
Socat

Thursday 23 June 2011

JDBC connection string for failover

In its HA manual, Deepnet suggests a few HA scenarios, but it doesn’t cover the following usage.


You may have a mirrored SQL database, and it can be automatic failover, but it has no VIP (virtual IP). Also you want to run a DualShield instance only. How can DualShield benefit from the existing SQL failover feature?


Well, DualShield Authentication Sever utilizes JDBC driver to connect its SQL database, you can achieve it by adding the second server into the JDBC connection string.


Let us look at an example in MySQL. The original one in the file server.xml



<Resource driverClassName="com.mysql.jdbc.Driver" maxActive="1000" maxIdle="2" maxWait="5000" name="jdbc/DasDS" password="changeit" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/dualshield?useUnicode=true& characterEncoding=UTF-8" username="root" validationQuery="Select 1"/>

The new string which supports HA,



<Resource driverClassName="com.mysql.jdbc.Driver" maxActive="1000" maxIdle="2" maxWait="5000" name="jdbc/DasDS" password="changeit" type="javax.sql.DataSource" url="jdbc:mysql://localhost,192.168.124.201:3306/dualshield?useUnicode=true&failOverReadOnly=false&characterEncoding=UTF-8" username="root" validationQuery="Select 1"/>

As you can see, we appended the second server after the original one “localhost”, separated with comma.
Don’t forget to set the HA property “failOverReadOnly=false”(its default value = true), otherwise you will get an error “Connection is read-only. Queries leading to data modification are not allowed”.


MS SQL and ORACE have the similar failover settings in their JDBC connection strings. In MS SQL, it is called “failoverPartner”.


The PDF version is available from here


Reference


Driver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J

Using Database Mirroring (JDBC)

Java – JDBC – Microsoft Drivers

Wednesday 22 June 2011

2X with Deepnet

I thought it's going to be very straightforward to use deepnet authentication in 2X. However, when I tried to do logon from 2X client, I was stuck by a strange error.


Code[01/0000000C] Account for user \\deepnetsecurity\username not found.


I was confused as this user truely existed in Deepnet application. It could be confirmed by looking through deepnet web-based management console. Also the function "Verify Deepnet user account names" provided by 2X didn't complain anything.


At the end, I turned to seek the help from Deepnet Support, they told me, in this case, the option "Use Principal Name" in application settings must be checked.


You can check the PDF version which has a few figures to help you better understand what I said.

Tuesday 21 June 2011

GPRS modem with DualShield(linux version)

Now Deepnet DualShield linux version can send SMS OTP by GPRS modem. You may need to tweak a little to make it work with your particular modem, especially it is USB modem, according to SMSLib Troubleshooting


In my case(using ZTE MF100 USB Modem in Ubuntu 11.04 32bit), it has a port as "/dev/ttyUSB2".



mingfa@water:/dev$ ls -l ttyUSB2
crw-rw---- 1 root dialout 188, 2 2011-06-21 16:01 ttyUSB2

As DualShield is running under a user called "dualshield", you need to add this user into the group "dialout" which the modem belongs to.



sudo useradd -G dialout dualshield

In addition, I have to add the parameter "-Dsmslib.serial.polling \" in the file /etc/init.d/dualshield, otherwise I got a no response exception.



case "$1" in
start)
# Start DualShield
$DAEMON_HOME/bin/jsvc \
-jvm server \
-user $TOMCAT_USER \
-home $JRE_HOME \
-Dcatalina.home=$CATALINA_HOME \
-Dcatalina.tmpdir=$CATALINA_TEMP \
-Djava.io.tmpdir=$TMP_DIR \
-Djava.library.path=$JRE_HOME/bin \
-Dsmslib.serial.polling \

......

Monday 6 June 2011

token association with a user in batch mode

You can use CSV file to associate(map) a token to a user in a batch.



In DualShield(v5x)



"domain","loginName","manufacturerCode","productCode","serial"
mydomain,kates,DN,SE,10008000
mydomain,johnnya,DN,SE,10008001

In DUAP(v3x)



LoginName,UserName,Mobile,Description,Email,FromLDAP,AuthMethod,TokenDeviceID
kates,Kate Smith,07912345678,,kate.smith@company.com,,SafeID,10008000
johnnya,johnny Allen, 07912387654,,johnny.allen@company.com,,SafeID,10008001

Wednesday 16 March 2011

Upgrade seed file

In DualShield, you may encounter a problem when importing a Deepnet token seed file which came with its previous version v3.x, as they changed the format of token seed file. If the file only contains a few tokens, you can modify it manually, however it is very hard labour if it contains hundred tokens.


Here is the utility to convert from v3x format to v5x format, also the source code, it utilizes pugixml to manipulate the xml file.


The command to run this utility is, seedupgrade infile outfile.




V3x Format



<tokenList>
<tokenInfo>
<method>PocketID</method>
<device>
<manufacturer>Deepnet Security</manufacturer>
<vendor>Deepnet Security</vendor>
<model>CB</model>
<serial>71358472</serial>
</device>
<token><![CDATA[<data>
<deviceID>71358472</deviceID>
<type>CB</type>
<counter>0</counter>
<digits>6</digits>
<secret enc="HEX">08E49538328BAE830E0DB14A82341100BC23B840</secret>
<description>71358472</description>
</data>
]]></token>
</tokenInfo>
</tokenList>



V5x Format



<?xml version="1.0"?>
<data>
<header>
<manufacturerCode>DN</manufacturerCode>
<productCode>ST</productCode>
<encode>HEX</encode>
<encrypt>NONE</encrypt>
</header>
<tokens>
<token>
<serial>71358472</serial>
<seed>08E49538328BAE830E0DB14A82341100BC23B840</seed>
</token>
</tokens>
</data>

Add an additional SMS provider

Deepnet Authentication Server(since v3.4x) has a good design on the support of SMS provider. It is very flexible to do the customization - In theory, you can add any SMS provider you like. It is a very good feature, as the domestic SMS providers are always cheaper than the world famous one like ClickAtell.


Then how? It seems Deepnet has no document to describe the procedures. I can fully understand it, as the template heavily depends on a particular SMS provider. First of all, you have to get the API document of your SMS provider, make sure what protocol they are using, HTTP, SMTP, or SMPP etc.


Next, study the built-in SMS provider templates. You can find them in the folder "$INSTALL_PATH/Tomcat/conf/dgs" ("$INSTALL_PATH/smsproviders" if you are using v5.x).


Congratulations if your provider operates as same as one of the built-in SMS providers, you are lucky.


Assume you are going to use "txtmail.co.nz" as your SMS provider in Deepnet, then copy the built-in provider "gin.xml", and save the new file as txtmail.xml, open the file "txtmail.xml" and change the provider name etc. At the end, the file content shoull look like the following



<?xml version="1.0" encoding="UTF-8"?>
<provider name="txtmail">
<sms>
<smtp>
<email>${to}@txtmail.co.nz</email>
<format>text</format>
<from>${from}</from>
<subject>${subject}</subject>
<body><![CDATA[${text}]]></body>
</smtp>
</sms>
</provider>

Finally, Add an entry in the file "sms_providers.xml",
<provider name="TXTMail" file="txtmail.xml" />


Access the management console of Deepnet, you should see the newly added provider in SMS Gateway Settings.


Here is another example, it has not been tested yet though. mollie.nl can send SMS via HTTP.


The syntax of sending the request is,

http://www.mollie.nl/xml/sms/?username=[username] &password=[password]&originator=[originator]&recipients=[recipient(s)]&message=[message]


And the response looks like the following


<?xml version="1.0" ?>
<response>
<item type="sms">
<recipients>1</recipients>
<success>true</success>
<resultcode>10</resultcode>
<resultmessage>Message successfully sent.</resultmessage>
</item>
</response>


As it is a HTTP protocol, you can refer to the built-in ClickAtell. The response is XML format, so you can use xmlPath to extract the result, otherwise, you may need a regular expression which is complicated. However you can find the regular expression example in the built-in templates. The final mollie template would be




<provider name="Mollie">
<sms>
<http>
<method>GET</method>
<url>http://www.mollie.nl/xml/sms/</url>
<query>username=${userName}&password=${password}&originator=${from}&recipients=${to}&message=${body}</query>
<variables>
<variable name="flash"/>
<variable name="dlr_url"/>
</variables>
<mappings>
<mapping name="replace_sms" type="boolean">
<true>1</true>
<false>0</false>
</mapping>
</mappings>
<response type="http_body" regexp="true" format="xml">
<pattern success="true" xmlPath="//response/item/success">true</pattern>
</response>
</http>
<smtp>
<email>${to}@mobiel.mollie.nl</email>
<format>text</format>
<from>${from}</from>
<subject>username=${userName}&password=${password}&sender=${subject}</subject>
<body><![CDATA[${text}]]></body>
</smtp>
</sms>
</provider>

mollie.nl also supports SMTP. It is quite interesting to see how it does the authentication - credentials in Subject!

Monday 14 March 2011

changes log nsis plug-in

I tried to use CustomLicense plugin to load the changes log in my update installer, it never worked with NSIS 2.46 (the exported function LoadFile was never called, confirmed by adding a MessageBox in this function). The size of the plugin dll also puzzled me, it is just 4K (4096 bytes, no more, no less).


Couldn't figure out why, so I build it myslef, using "exdll.h" instead of "pluginapi.h". My DLL is much bigger(44K), it works though.

Thursday 10 March 2011

Learning ISA

In this document, we try to use two options(web publishing and server publishing rule) to publish the same MS SharePoint(WSS30) site. It also tries to show how to setup filewall rule to allow ftp (from ISA machine to outside) and RDP(outside to ISA machine).

Friday 18 February 2011

LDAP + OTP over CHAP

Many peope wish they can use LDAP Password + OTP in RADIUS authentication to enhance their security. MSCHAP(CHAP) is defacto the common protocol used in RADIUS, as PAP is denounced due to its plain text transmission across the Internet. However it is technically impossible for LDAP + OTP over CHAP. Why? you will certainly ask the same question as I did when I first dealt with it. Basically, you can regard CHAP as a hash algorithm like the popular MD5 or SHA1. In mathematics,


HASH(StaticPass + OTP) != HASH(StaticPass) + HASH(OTP)


At VPN client side, you input StaticPass + OTP, at VPN server side, the server receives HASH(StaticPass + OTP). If the server has no plain text of StaticPass, then it is impossible for the server to decide if there is a match. Unfortunately LDAP password is not available as a plain text. According to MS, the password itself is actually a LM hash. As a result, none of any two factor authentiction service providers can support LDAP + OTP over CHAP. If you know any vendors who claim they support this, please let me know.


Here is the summary of Deepnet Radius Authentication. X = supported.


In the situation where StaticPass token doesn't physically exist in Deepent database, LDAP password is used instead.
































MSCHAP2(CHAP)PAP
StaticPass
X
OTP
X1
X
StaticPass + OTP
X
StaticPass >> OTP
X


If a StaticPass token exists, the password can be retrieved in Deepnet.

































MSCHAP2(CHAP)PAP
StaticPass
X
X
OTP
X1
X
StaticPass + OTP
X1
X
StaticPass >> OTP
X1
X

Note: 1 All OTP tokens except vasco token.

Wednesday 16 February 2011

Passing Username

Deepnet IIS solution adds an additional login page, that means the user has to type his username twice which is inconvenience. Is there any way to pass the username typed on the first login (deepnet) page down to the second login(the original) page?


The answer is YES. Let's take Microsoft Remote Web Workplace in SBS as an example, find the related file "logon.aspx", locate the line



<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" ></TD>


change it to



<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" value='<%=Request.Cookies["DasUserName"] == null ? string.Empty : Request.Cookies["DasUserName"].Value%>' ></TD>


As you can see, the value attribute is added: value='<%=Request.Cookies["DasUserName"] == null ? string.Empty : Request.Cookies["DasUserName"].Value%>'


If the object is run at server (runat="server"), then you should change it to be like



<td align=right class=linkText><%=loadResString("L_LOGON_USER_NAME")%></td>
<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" runat="server"></TD>
<td class="linkText"></td>
<script type="text/javascript">
<!-- //
var cookie = GetDASCookie('DasUserName');
document.getElementById('<%=txtUserName.ClientID%>').value = cookie.split('=')[1];
//-->
</script>



Furthermore, in order to prevent the field from editing, you can add readonly attribute.



<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" readonly="readonly" value='<%=Request.Cookies["DasUserName"] == null ? string.Empty : Request.Cookies["DasUserName"].Value%>' runat="server"></TD>

Deepnet mandate option on ActiveSync

Somehow the mandate option in Deepnet IIS solution doesn't work on ActiveSync protection. Once you add the deepnet protection on ActiveSync node, then each mobile device which synchronizes with Exchange server will need two-factor authentication, no matter you check on/off the mandate option.


In testing phase, It's quite likely that you want one or two devices to be protected with Deepnet 2-factor authentication while the others still work with the original one factor(Windows username/password).


Well, how to achieve this purpose? Here it is the workaround.


After assigning the event filter(see the related user guide from Deepnet), edit its content. The following python script will function as non-mandate option on deepnet ActiveSync protection.



"""
This is a trigger script used by DAS

# return integer:
# zero: continue trigger chain
# nonzero: quit chain

# return boolean
# False: continue trigger chain
# True: quit chain

# return dictionary
# dict['noContinue']
# dict['noLog']
# dict['newReturnVal']
#
"""
#import socket
import sys
import java.util.Hashtable

def Log(msg):
return
# HOST = '192.168.111.168' # The remote host
# PORT = 7000 # The same port as used by the server
# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# s.connect((HOST, PORT))
# s.send(str(msg) +'\r\n')
# s.close()

class Trigger:
def __init__(self):
pass

def execute(self, *args, **dict):

try:
if filter_context is None:
return 0
except:
return 0

Log('------------------------')
#Log(filter_context['DasAPI'].hello()[0])
Log(filter_context['appID'])
Log(filter_context['resultCode'])

for i in filter_context.keys():
#Log(i)
#Log(filter_context[i])
Log(i + ': ' + str(filter_context[i]))

if not filter_context.containsKey('method'):
return 0

if filter_context['method'].lower()!='devicepass':
return 0

Log('DevicePass found')

# if user account not found, try to import it from LDAP
if filter_context['resultCode']=='E-USERID-NOT-FOUND' or filter_context['resultCode']=='E-LOGINNAME-NOT-FOUND':
# bRet = self.importAccount()

# if bRet==True:
# bRet = self.createToken()
# if bRet==True:
# return self.changeReturn('E-TOKEN-INACTIVE')
return self.changeReturn('TRUE')

if filter_context['resultCode']=='E-TOKEN-NOT-FOUND' or filter_context['resultCode']=='E-METHOD-NOT-FOUND':
bRet = self.createToken()
if bRet==True:
return self.changeReturn('E-TOKEN-INACTIVE')

return 0

def importAccount(self):
try:
result = filter_context['DasAPI'].importAccount(
filter_context['appID'], filter_context['loginName'])
Log( 'importAccount: ' + str(result) )
if result[0]=='OK':
self.newUserID = str(result[1])
return True
return False
except:
Log(sys.exc_info()[0])
return False

def createToken(self):
try:
tokenInfo = java.util.Hashtable()
tokenInfo['credential'] = filter_context['credential']
tokenInfo['method'] = filter_context['method']
tokenInfo['description'] = 'created by trigger'
userID = filter_context['userID']
if userID=='':
userID = self.newUserID

result = filter_context['DasAPI'].createToken(
filter_context['appID'],
userID, tokenInfo, False)
Log( 'createToken: ' + str(result) )
if result[0]=='OK':
return True
return False
except:
Log(sys.exc_info()[0])
return False;


def changeReturn(self, val):
r={'newReturnVal':val}
return r


def main():
trigger = Trigger()
return trigger.execute()

if __name__ == '__main__':
main()

If you compare it with the original python script, you will see the difference.



#original
if filter_context['resultCode']=='E-USERID-NOT-FOUND' or filter_context['resultCode']=='E-LOGINNAME-NOT-FOUND':
bRet = self.importAccount()

if bRet==True:
bRet = self.createToken()
if bRet==True:
return self.changeReturn('E-TOKEN-INACTIVE')
return 0

#new
if filter_context['resultCode']=='E-USERID-NOT-FOUND' or filter_context['resultCode']=='E-LOGINNAME-NOT-FOUND':
# bRet = self.importAccount()

# if bRet==True:
# bRet = self.createToken()
# if bRet==True:
# return self.changeReturn('E-TOKEN-INACTIVE')
return self.changeReturn('TRUE')


Monday 7 February 2011

Experiment of SMSLib on GPRS Modem in Ubuntu

I spent a lot of time on this GPRS 609 MODEM. Somehow this device I purchased on Ebay is faulty, or it isn't powerful enough in my area. Anyway it doesn't work very well. Basically, it can connect with "cu -l /dev/ttyUSB0", but sometimes it had no echo even I tried "AT+ATE1". The command AT+CMGS almost failed with error 33825, altough I did manage to send SMS twice. However, SMSLib SendMessage never succeeded. Interestingly enough, all other commands(listed below) were OK on the condition that the echo was fine.


Finally, I gave up the lame duck(I am afraid say so), as my friend offered me his Motorola V3 mobile phone which can be taken as a GPRS modem. Life became much easier with this mobile phone. Almost everything was straightforward.



With Ubuntu 10.10 32bit guest OS in Vmware Workstation,

dmesg shows this device is recognized as ttyACM0, no additional driver needed.



[ 233.820553] usb 2-1: new full speed USB device using uhci_hcd and address 3
[ 234.057913] usb 2-1: configuration #1 chosen from 2 choices
[ 234.284872] cdc_acm 2-1:1.0: ttyACM0: USB ACM device
[ 234.297306] usbcore: registered new interface driver cdc_acm
[ 234.297901] cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters


No hassle at all when using AT commands to send SMS. However, the tricks suggested by SMSLib Troubleshooting are applied during SMSLib tests. In details, the parameter -Dsmslib.serial.polling is used for no response exception. A symbolic link (sudo ln -s /dev/ttyACM0 /dev/ttyS20) is created for NoSuchPortException, but I haven't tried the alternative - gnu.io.rxtx.SerialPorts.



/*
* Register ports specified in the file "gnu.io.rxtx.properties"
* Key system properties:
* gnu.io.rxtx.SerialPorts
* gnu.io.rxtx.ParallelPorts
*
* The file gnu.io.rxtx.properties must reside in the java extension dir
*
* Example: /usr/local/java/jre/lib/ext/gnu.io.rxtx.properties
*
* The file contains the following key properties:
*
* gnu.io.rxtx.SerialPorts=/dev/ttyS0:/dev/ttyS1:
* gnu.io.rxtx.ParallelPorts=/dev/lp0:
*
*/

In addition, I chose the RXTX library distribution from CloudHopper's web site. Also I installed Sun Java, as I know the folder structure of Sun Java better than built-in Open JDK on Ubuntu. The command to run this jar is,


 /opt/java/bin/java -Dsmslib.serial.polling -Djava.library.path=/opt/java/bin -jar smslearn.jar


The modified java source code of SendMessage example.




// SendMessage.java - Sample application.
//
// This application shows you the basic procedure for sending messages.
// You will find how to send synchronous and asynchronous messages.
//
// For asynchronous dispatch, the example application sets a callback
// notification, to see what's happened with messages.

package com.deepnet.smslearn;

import org.smslib.AGateway;
import org.smslib.IOutboundMessageNotification;
import org.smslib.Library;
import org.smslib.OutboundMessage;
import org.smslib.Service;
import org.smslib.modem.SerialModemGateway;

public class SendMessage
{
public void doIt(String device, String speed, String phone, String message) throws Exception
{
OutboundNotification outboundNotification = new OutboundNotification();
System.out.println("Example: Send message from a serial gsm modem.");
System.out.println(Library.getLibraryDescription());
System.out.println("Version: " + Library.getLibraryVersion());
SerialModemGateway gateway = new SerialModemGateway("modem.ttyS20", device, Integer.parseInt(speed), "NoSuchPortException", "V3");
gateway.setInbound(true);
gateway.setOutbound(true);
// gateway.setSimPin("0000");
// Explicit SMSC address set is required for some modems.
// Below is for VODAFONE GREECE - be sure to set your own!
// gateway.setSmscNumber("+306942190000");
Service.getInstance().setOutboundMessageNotification(outboundNotification);
Service.getInstance().addGateway(gateway);
Service.getInstance().startService();
System.out.println();
System.out.println("Modem Information:");
System.out.println(" Manufacturer: " + gateway.getManufacturer());
System.out.println(" Model: " + gateway.getModel());
System.out.println(" Serial No: " + gateway.getSerialNo());
System.out.println(" SIM IMSI: " + gateway.getImsi());
System.out.println(" Signal Level: " + gateway.getSignalLevel() + " dBm");
System.out.println(" Battery Level: " + gateway.getBatteryLevel() + "%");
System.out.println();
// Send a message synchronously.
OutboundMessage msg = new OutboundMessage(phone, message);
Service.getInstance().sendMessage(msg);
System.out.println(msg);
// Or, send out a WAP SI message.
//OutboundWapSIMessage wapMsg = new OutboundWapSIMessage("+306974000000", new URL("http://www.smslib.org/"), "Visit SMSLib now!");
//Service.getInstance().sendMessage(wapMsg);
//System.out.println(wapMsg);
// You can also queue some asynchronous messages to see how the callbacks
// are called...
//msg = new OutboundMessage("+309999999999", "Wrong number!");
//srv.queueMessage(msg, gateway.getGatewayId());
//msg = new OutboundMessage("+308888888888", "Wrong number!");
//srv.queueMessage(msg, gateway.getGatewayId());
// System.out.println("Now Sleeping - Hit to terminate.");
// System.in.read();
Service.getInstance().stopService();
}

public class OutboundNotification implements IOutboundMessageNotification
{
public void process(AGateway gateway, OutboundMessage msg)
{
System.out.println("Outbound handler called from Gateway: " + gateway.getGatewayId());
System.out.println(msg);
}
}

public static void main(String args[])
{
if(args.length < 4)
{
System.out.println("Usage:smslearn device speed phone message");
return;
}

SendMessage app = new SendMessage();
try
{
app.doIt(args[0],args[1],args[2],args[3]);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}



Basic AT commands


you can try minicom instead.



$ cu -l /dev/ttyACM0
Connected.

//Phone activity status +CPAS. 0 Ready, 1 Unavailable,2 Unknown,3 Ringing,4 Call in progress,5 Asleep
at+cpas
+CPAS: 0

//Request manufacturer identification +CGMI
at+cgmi
+CGMI: "Motorola CE, Copyright 2004"

//Request model identification +CGMM
at+cgmm
+CGMM: "GSM900","GSM1800","GSM1900","GSM850","MODEL=V3"

//Request revision identification +CGMR
at+cgmr
+CGMR: "R374_G_0E.42.10R_A"

//Request product serial number identification +CGSN
at+cgsn
+CGSN: IMEI354759009930994

//AT+ATE1 : enable echo;

//Service Centre Address +CSCA
at+csca?
+CSCA: "+447973100973",145

//Report Mobile Equipment error +CMEE
AT+CMEE=1 //Report Mobile Equipment extend error. 0 = Disable, 1 = result code and use numeric values, 2 = result code and use verbose value

//Message Format +CMGF
AT+CMGF? // Query current format
AT+CMGF=1 // 0 = PDU mode (default), 1 = text mode

//Enter PIN +CPIN
at+cpin?
+CPIN: READY

//Send Message +CMGS
AT+CMGS="+31638740161"
Hello World !
+CMGS: 62
//Replace the above phone number with your own cell phone number. The modem will respond with: >
//You can now type the message text and send the message using the - key combination:
//After some seconds the modem will respond with the message ID of the message, indicating that the message was sent correctly:
//The message will arrive on the mobile phone shortly.


It is worth writing here how to exit cu: type '~' first, once you see computer name, then type '.'.




Reference



Send SMS using AT commands

USB Tri-band GPRS Modem / Cell Phone Radio (GSM 900/1800/1900Mhz)

Modify PL2303 PID & VID

Monday 31 January 2011

LDAP Connection Errors

When using LDAP connection to import the external identity source(user names) in Deepnet Authentication Server, you must specify the correct user DN string and its password in order to connect LDAP server successfully. Otherwise you will get some errors like "AcceptSecurityContext error, data 525(or 52e etc)".



I often use two utilities to confirm the user DN string, dsquery and ADSIEdit.



Dsquery is a command-line tool that is built into Windows Server 2008. It is available if you have the Active Directory Domain Services (AD DS) server role installed. To use dsquery, you must run the dsquery command from an elevated command prompt. To open an elevated command prompt, click Start, right-click Command Prompt, and then click Run as administrator. On Windows 2003, you may need to install Support Tools on the domain controller to use dsquery.


Here is an example. the command "dsquery user" is executed on domain controller.



C:\>dsquery user
"CN=Administrator,CN=Users,DC=nanoart,DC=local"
"CN=Guest,CN=Users,DC=nanoart,DC=local"
"CN=SUPPORT_388945a0,CN=Users,DC=nanoart,DC=local"
"CN=krbtgt,CN=Users,DC=nanoart,DC=local"

Alternatively, we can use ADSIEdit. I prefer to run it on domain controller as well, although it can run on another machine, but you must know how to login.





References



LDAP Troubleshooting

Common Active Directory LDAP bind errors

Saturday 22 January 2011

Redundant cluster settings

First of all, let us look at the content of server.xml file which is located at the folder "C:\Program Files\Deepnet Authentication Server\Tomcat\conf". There are 3 occurrences of Cluster.



<Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster" clusterLogName="clusterlog" clusterName="localhost" manager.className="org.apache.catalina.cluster.session.DeltaManager" manager.expireSessionsOnShutdown="false" manager.notifyListenersOnReplication="false" manager.notifySessionListenersOnReplication="false" manager.sendAllSessions="false" manager.sendAllSessionsSize="500" manager.sendAllSessionsWaitTime="20" manager.sendClusterDomainOnly="true">
<Membership className="org.apache.catalina.cluster.mcast.McastService" mcastAddr="228.1.1.4" mcastClusterDomain="das_cluster" mcastDropTime="30000" mcastFrequency="1000" mcastPort="24282" recoveryEnabled="true"/>
<Sender className="org.apache.catalina.cluster.tcp.ReplicationTransmitter" doProcessingStats="true" doTransmitterProcessingStats="true" doWaitAckStats="true" keepAliveMaxRequestCount="-1" keepAliveTimeout="80000" queueCheckLock="true" queueDoStats="true" queueTimeWait="true" recoverCounter="6" recoverTimeout="5000" replicationMode="fastasyncqueue"/>
<Receiver className="org.apache.catalina.cluster.tcp.ReplicationListener" compress="false" sendAck="true" tcpListenAddress="x.x.x.x" tcpListenPort="4000" tcpSelectorTimeout="100" tcpThreadCount="6"/>
<Valve className="org.apache.catalina.cluster.tcp.ReplicationValve" filter=".*\.gif;.*\.js;.*\.css;.*\.png;.*\.jpeg;.*\.jpg;.*\.htm;.*\.html;.*\.txt;" primaryIndicator="true"/>
<Valve className="org.apache.catalina.cluster.session.JvmRouteBinderValve"/>
<ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
<ClusterListener className="org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener"/>
</Cluster>

What will this result in? With some traffic monitor, you will see a lot of connection attempts to IP "228.1.1.4" configured in server.xml (see above). Suspicious and scary, isn't it? I am not comfortable with that, although this address doesn't exist on Internet.


According to Deepnet Support, this tech(multicast) was adopted at the very beginning for deepnet authentication server cluster configuration, but they abandoned it as another approach was used to implement the cluster/load balancing.


So these settings are redundant, why not remove them!



  • backup the file server.xml;
  • open the file server.xml with your favourite editor;
  • locate these pairs <Cluster ..>....</Cluster>, delete them;
  • save the file;
  • restart deepnet service "das";

Now it is nice and clean. Happy!

Monday 10 January 2011

Deepnet ActiveSync solution doesn't work on some Android devices.

You may have some problems to add Deepnet ActiveSync protection onto Android phone device. Here is the effective remedy.



1, go to the folder "C:\Program Files\Deepnet Security\IIS" on your Exchange server where Deepnet IIS agent is installed;

2, open the file "config.xml" with your favourite editor;

3, locate <serv desc="Microsoft Server ActiveSync" code="sas">, which is around line 64;



<serv desc="Microsoft Server ActiveSync" code="sas">
<requests>

4, insert the following after <requests>;



<req match="Microsoft-Server-ActiveSync/Android" source="${_url}">
<params>
<par name="UserName" value="User={.*?}&" source="${_url}"/>
<par name="DeviceID" value="/{android.+}/*.*$" source="${_url}"/>
</params>
<variables>
<var name="x-deviceID" value="$$encrypt(<uuid>${DeviceID}</uuid>)"/>
</variables>
<actions>
<condition property="${_Authenticator}" value="devicePass" op="iquals">

<condition property="${UserName}" value="" op="equals">
<act type="assign" var="UserName" value="${_authuser}"/>
</condition>


<condition property="${UserName}" value="" op="notequals">

<act type="xmlrpc">
<methodCall>
<methodName>das.login</methodName>
<params>
<param>
<value><string>${_appId}</string></value>
</param>
<param>
<value><string>${UserName}</string></value>
</param>
<param>
<value><string><![CDATA[<?xml version="1.0"?>
<credential>
<method>${_Authenticator}</method>
<token>
<deviceID>${DeviceID}</deviceID>
</token>
<credentialData>
<devicePrint>
${x-deviceID}
</devicePrint>
</credentialData>
</credential>]]></string></value>
</param>
<param>
<value><string>${_clientip}</string></value>
</param>
<param>
<value><string></string></value>
</param>
<param>
<value><boolean>0</boolean></value>
</param>
</params>
</methodCall>
</act>
</condition>
</condition>
</actions>
<errors page="/dasweb/sas/error.aspx?errcode=$$urlencode(${_return})&username=$$urlencode(${UserName})&appid=$$urlencode(${_appId})&method=$$urlencode(${_Authenticator})">
<err code="E-METHOD-NOT-FOUND" page="/dasweb/sas/method_not_found.aspx?errcode=$$urlencode(${_return})&username=$$urlencode(${UserName})&appid=$$urlencode(${_appId})&method=$$urlencode(${_Authenticator})"/>
<err code="E-TOKEN-INACTIVE" page="/dasweb/sas/token_inactive.aspx?errcode=$$urlencode(${_return})&username=$$urlencode(${UserName})&appid=$$urlencode(${_appId})&method=$$urlencode(${_Authenticator})&deviceid=$$urlencode(${DeviceID})"/>
<err code="E-CONNECT-DAS" page="/dasweb/sas/connect_das_error.aspx?errcode=$$urlencode(${_return})&das=$$urlencode(${_das})"/>
</errors>
</req>

For your convenience, the working configuration file can be downloaded from here. Simply replace the original one, then restart IIS service.