+Sun Jan 25 14:31:31 EST 2009
+jcifs-1.3.3
+
+If a jcifs.netbios.wins property is not supplied, the default
+jcifs.resolveOrder is now LMHOSTS,DNS,BCAST whereas previously it was
+LMHOSTS,BCAST,DNS. This is much more likely to eliminate annoying 6
+second timeouts waiting for BCAST queries to timeout.
+
+An "Invalid parameter" error would occur if the RC4 Cipher was not
+available for NTLMv2. The logic has been adjusted so that the correct
+error is thrown. Note that RC4 is only available in Java 1.5 update 7 and
+later. Thus JCIFS 1.3 requires that version or NTLMv2 must be disabled.
+
+The NTLMSSP classes could try to load Cp850 which is not available in
+the standard JRE. This has been fixed.
+
+Added setLength method to NdrBuffer class.
+
Mon Dec 22 13:30:39 EST 2008
jcifs-1.3.2
<project name="jcifs" default="usage" basedir=".">
- <property name="version" value="1.3.2"/>
- <property name="reldate" value="Dec 22, 2008"/>
+ <property name="version" value="1.3.3"/>
+ <property name="reldate" value="Jan 25, 2009"/>
<target name="usage">
<echo>
#!/bin/sh
-JAVA_HOME=/usr/local/java6
+#JAVA_HOME=/usr/local/java6
+JAVA_HOME=/usr/local/java
CLASSPATH=../build:.
-PROPERTIES=../user1.prp
+PROPERTIES=../../user2.prp
RUN="${JAVA_HOME}/bin/java -cp ${CLASSPATH} -Djcifs.properties=${PROPERTIES}"
#SERVER=dc1.w.net
#DIR=test
# Domain-based DFS
-#SHARE=root2
-#DIR=link2/test
+SERVER=w.net
+SHARE=root2
+DIR=link2/test
# smb://fs1.w.net/DFSStandaloneRoot/DFSStandaloneLink/test/
# smb://dc1.w.net/root2/link2/test/
# smb://dc1.w.net/tmp/test/
# smb://dc3.x.net/tmp/test/
# Stand-alone DFS
-SERVER=dc3.x.net
-SHARE=tmp
-DIR=test
+#SERVER=dc3.x.net
+#SHARE=tmp
+#DIR=test
WRITE_DIR=${DIR}/
SRC_DIR=${DIR}/Junk
if( nbns == null ) {
resolveOrder = new int[3];
resolveOrder[0] = RESOLVER_LMHOSTS;
- resolveOrder[1] = RESOLVER_BCAST;
- resolveOrder[2] = RESOLVER_DNS;
+ resolveOrder[1] = RESOLVER_DNS;
+ resolveOrder[2] = RESOLVER_BCAST;
} else {
resolveOrder = new int[4];
resolveOrder[0] = RESOLVER_LMHOSTS;
resolveOrder[1] = RESOLVER_WINS;
- resolveOrder[2] = RESOLVER_BCAST;
- resolveOrder[3] = RESOLVER_DNS;
+ resolveOrder[2] = RESOLVER_DNS;
+ resolveOrder[3] = RESOLVER_BCAST;
}
} else {
int[] tmp = new int[4];
DcerpcBinding binding;
int max_xmit, max_recv;
+ public DcerpcBind() {
+ }
DcerpcBind(DcerpcBinding binding, DcerpcHandle handle) {
this.binding = binding;
max_xmit = handle.max_xmit;
private int error;
private Throwable rootCause;
- DcerpcException(String msg) {
- super(msg);
- }
DcerpcException(int error) {
super(getMessageByDcerpcError(error));
this.error = error;
}
- DcerpcException(String msg, Throwable rootCause) {
+ public DcerpcException(String msg) {
+ super(msg);
+ }
+ public DcerpcException(String msg, Throwable rootCause) {
super(msg);
this.rootCause = rootCause;
}
protected int max_xmit = 4280;
protected int max_recv = max_xmit;
protected int state = 0;
+ protected DcerpcSecurityProvider securityProvider = null;
private static int call_id = 1;
public static DcerpcHandle getHandle(String url,
throw new DcerpcException("DCERPC transport not supported: " + url);
}
+ public void bind() throws DcerpcException, IOException {
+ try {
+ state = 1;
+ DcerpcMessage bind = new DcerpcBind(binding, this);
+ sendrecv(bind);
+ } catch (IOException ioe) {
+ state = 0;
+ throw ioe;
+ }
+ }
public void sendrecv(DcerpcMessage msg) throws DcerpcException, IOException {
byte[] stub, frag;
NdrBuffer buf, fbuf;
DcerpcException de;
if (state == 0) {
- state = 1;
- DcerpcMessage bind = new DcerpcBind(binding, this);
- sendrecv(bind);
+ bind();
}
isDirect = msg instanceof DcerpcBind;
msg.encode(buf);
+ if (securityProvider != null) {
+ buf.setIndex(0);
+ securityProvider.wrap(buf);
+ }
+
tot = buf.getLength();
off = 0;
+
while (off < tot) {
msg.call_id = call_id++;
doReceiveFragment(stub, isDirect);
buf.reset();
+ buf.setIndex(8);
+ buf.setLength(buf.dec_ndr_short());
+
+ if (securityProvider != null)
+ securityProvider.unwrap(buf);
+
+ buf.setIndex(0);
+
msg.decode_header(buf);
off = 24;
doReceiveFragment(frag, isDirect);
fbuf.reset();
+ fbuf.setIndex(8);
+ fbuf.setLength(fbuf.dec_ndr_short());
+
+ if (securityProvider != null)
+ securityProvider.unwrap(fbuf);
+
+ fbuf.reset();
msg.decode_header(fbuf);
stub_frag_len = msg.length - 24;
throw de;
}
+ public void setDcerpcSecurityProvider(DcerpcSecurityProvider securityProvider)
+ {
+ this.securityProvider = securityProvider;
+ }
public String getServer() {
if (this instanceof DcerpcPipeHandle)
return ((DcerpcPipeHandle)this).pipe.getServer();
buf.enc_ndr_long(call_id);
}
void decode_header(NdrBuffer buf) throws NdrException {
- buf.dec_ndr_small(); /* RPC version */
- buf.dec_ndr_small(); /* minor version */
+ /* RPC major / minor version */
+ if (buf.dec_ndr_small() != 5 || buf.dec_ndr_small() != 0)
+ throw new NdrException("DCERPC version not supported");
ptype = buf.dec_ndr_small();
flags = buf.dec_ndr_small();
if (buf.dec_ndr_long() != 0x00000010) /* Little-endian / ASCII / IEEE */
public void decode(NdrBuffer buf) throws NdrException {
decode_header(buf);
- if (ptype != 12 && ptype != 2 && ptype != 3)
+ if (ptype != 12 && ptype != 2 && ptype != 3 && ptype != 13)
throw new NdrException("Unexpected ptype: " + ptype);
if (ptype == 2 || ptype == 3) { /* Response or Fault */
buf.dec_ndr_short(); /* context id */
buf.dec_ndr_short(); /* cancel count */
}
- if (ptype == 3) { /* Fault */
+ if (ptype == 3 || ptype == 13) { /* Fault */
result = buf.dec_ndr_long();
} else { /* Bind_ack or Response */
decode_out(buf);
--- /dev/null
+/* jcifs msrpc client library in Java
+ * Copyright (C) 2009 "Michael B. Allen" <jcifs at samba dot org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package jcifs.dcerpc;
+
+import jcifs.dcerpc.ndr.NdrBuffer;
+
+public interface DcerpcSecurityProvider
+{
+ void wrap(NdrBuffer outgoing) throws DcerpcException;
+ void unwrap(NdrBuffer incoming) throws DcerpcException;
+}
public int getLength() {
return deferred.length;
}
+ public void setLength(int length) {
+ deferred.length = length;
+ }
public void advance(int n) {
index += n;
if ((index - start) > deferred.length) {
(byte) 'S', (byte) 'S', (byte) 'P', (byte) 0
};
- private static final String OEM_ENCODING = Config.getProperty("jcifs.encoding", "Cp850");
+ private static final String OEM_ENCODING = Config.DEFAULT_OEM_ENCODING;
private int flags;
RANDOM.nextBytes(clientChallenge);
java.util.Arrays.fill(clientChallenge, 8, 24, (byte)0x00);
+// NTLMv1 w/ NTLM2 session sec and key exch all been verified with a debug build of smbclient
+
byte[] responseKeyNT = NtlmPasswordAuthentication.nTOWFv1(password);
byte[] ntlm2Response = NtlmPasswordAuthentication.getNTLM2Response(responseKeyNT,
type2.getChallenge(),
MD4 md4 = new MD4();
md4.update(responseKeyNT);
- HMACT64 hmac = new HMACT64(md4.digest());
+ byte[] userSessionKey = md4.digest();
+
+ HMACT64 hmac = new HMACT64(userSessionKey);
hmac.update(sessionNonce);
- byte[] userSessionKey = hmac.digest(); // NTLM2 session key
+ byte[] ntlm2SessionKey = hmac.digest();
if ((getFlags() & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0) {
masterKey = new byte[16];
byte[] exchangedKey = new byte[16];
try {
Cipher rc4 = Cipher.getInstance("RC4");
- rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(userSessionKey, "RC4"));
+ rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(ntlm2SessionKey, "RC4"));
rc4.update(masterKey, 0, 16, exchangedKey, 0);
} catch (GeneralSecurityException gse) {
throw new RuntimeException("", gse);
setSessionKey(exchangedKey);
} else {
- masterKey = userSessionKey;
+ masterKey = ntlm2SessionKey;
setSessionKey(masterKey);
}
}
setNTResponse(getNTLMv2Response(type2, responseKeyNT, clientChallenge2));
if ((getFlags() & NTLMSSP_NEGOTIATE_SIGN) == NTLMSSP_NEGOTIATE_SIGN) {
- masterKey = new byte[16];
- RANDOM.nextBytes(masterKey);
-
HMACT64 hmac = new HMACT64(responseKeyNT);
hmac.update(ntResponse, 0, 16); // only first 16 bytes of ntResponse
byte[] userSessionKey = hmac.digest();
- /* TODO: don't do this if NTLMSSP_NEGOTIATE_KEY_EXCH not set
- */
- byte[] exchangedKey = new byte[16];
- try {
- Cipher rc4 = Cipher.getInstance("RC4");
- rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(userSessionKey, "RC4"));
- rc4.update(masterKey, 0, 16, exchangedKey, 0);
- } catch (GeneralSecurityException gse) {
- throw new RuntimeException("", gse);
- }
+ if ((getFlags() & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0) {
+ masterKey = new byte[16];
+ RANDOM.nextBytes(masterKey);
+
+ byte[] exchangedKey = new byte[16];
+ try {
+ Cipher rc4 = Cipher.getInstance("RC4");
+ rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(userSessionKey, "RC4"));
+ rc4.update(masterKey, 0, 16, exchangedKey, 0);
+ } catch (GeneralSecurityException gse) {
+ throw new RuntimeException("", gse);
+ }
- setSessionKey(exchangedKey);
+ setSessionKey(exchangedKey);
+ } else {
+ masterKey = userSessionKey;
+ setSessionKey(masterKey);
+ }
}
break;
int workstationOffset = readULong(material, 48);
int flags;
String charset;
+ byte[] _sessionKey = null;
if (lmResponseOffset == 52 || ntResponseOffset == 52 ||
domainOffset == 52 || userOffset == 52 ||
workstationOffset == 52) {
flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_OEM;
charset = getOEMEncoding();
} else {
- setSessionKey(readSecurityBuffer(material, 52));
+ _sessionKey = readSecurityBuffer(material, 52);
flags = readULong(material, 60);
charset = ((flags & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
"UnicodeLittleUnmarked" : getOEMEncoding();
}
+ setSessionKey(_sessionKey);
setFlags(flags);
setLMResponse(lmResponse);
setNTResponse(ntResponse);
state++;
break;
} catch (Exception e) {
- throw new SmbException(e.getMessage());
+ throw new SmbException(e.getMessage(), e);
}
default:
throw new SmbException("Invalid state");
static String DEFAULT_PASSWORD;
static final String BLANK = "";
+ public static final NtlmPasswordAuthentication ANONYMOUS = new NtlmPasswordAuthentication("", "", "");
+
static void initDefaults() {
if (DEFAULT_DOMAIN != null) return;
DEFAULT_DOMAIN = Config.getProperty("jcifs.smb.client.domain", "?");
if (cred instanceof NtlmPasswordAuthentication) {
NtlmPasswordAuthentication auth = (NtlmPasswordAuthentication)cred;
- if (session.transport.server.encryptedPasswords) {
+ if (auth == NtlmPasswordAuthentication.ANONYMOUS) {
+ lmHash = new byte[0];
+ ntHash = new byte[0];
+ } else if (session.transport.server.encryptedPasswords) {
lmHash = auth.getAnsiHash( session.transport.server.encryptionKey );
ntHash = auth.getUnicodeHash( session.transport.server.encryptionKey );
// prohibit HTTP auth attempts for the null session
import java.util.Enumeration;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.io.IOException;
import jcifs.Config;
import jcifs.UniAddress;
import jcifs.netbios.NbtAddress;
do {
switch (state) {
case 10: /* NTLM */
- if ((transport.capabilities & SmbConstants.CAP_EXTENDED_SECURITY) == SmbConstants.CAP_EXTENDED_SECURITY) {
+ if (auth == NtlmPasswordAuthentication.ANONYMOUS)
+ transport.capabilities &= ~SmbConstants.CAP_EXTENDED_SECURITY;
+
+ if (transport.hasCapability(SmbConstants.CAP_EXTENDED_SECURITY)) {
state = 20; /* NTLMSSP */
break;
}
break;
}
- token = nctx.initSecContext(token, 0, token.length);
+ try {
+ token = nctx.initSecContext(token, 0, token.length);
+ } catch (SmbException se) {
+ /* We must close the transport or the server will be expecting a
+ * Type3Message. Otherwise, when we send a Type1Message it will return
+ * "Invalid parameter".
+ */
+ try { transport.disconnect(true); } catch (IOException ioe) {}
+ uid = 0;
+ throw se;
+ }
+
if (token != null) {
request = new SmbComSessionSetupAndX(this, null, token);
response = new SmbComSessionSetupAndXResponse(null);