From: Felix Schumacher Date: Wed, 6 Aug 2008 14:38:37 +0000 (+0200) Subject: jcifs-1.2.10b from tgz X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=633741a9b66a138f8de2cbc66d3dda677611b100;p=jcifs_without_docs.git jcifs-1.2.10b from tgz Tue Nov 14 12:32:23 EST 2006 jcifs-1.2.10b released / MSRPC Support, Long Unicode Share Name Enumeration and Critical Bugfixes This release contains the following new functionality and fixes: * Long Unicode Share Enumeration - The SmbFile.list* methods will now try to use MSRPC to enumerate shares if the target is a server. If the operation should fail for any reason, the client will fall back to trying the older RAP method. This should permit enumerating shares with names that use charsets other than the negotiated OEM "ASCII" encoding, share names that are longer than 12 characters, and arbirarily large lists of shares. * MSRPC Support - MSRPC support has been integrated into JCIFS directly. It should now be possible to add new RPCs (AT jobs, SID/group name resolution, service management, regedit, etc) relatively easily with little knowledge of MSRPC protocols. Look at the jcifs/dcerpc/msrpc/MsrpcShareEnum.java class for an example and ask the mailing list for further instructions. * Apr 24 bugfix - A NullPointerException caused by an error in logic has been fixed. * May 10 bugfix - The client will now detect if the JRE supports Cp850 and set the default jcifs.encoding to US-ASCII if it does not. This will eliminate some NullPointerExceptions that were occuring as a result. * A small update about keep-alives has been added to the NTLM HTTP Authentication document. * Jun 21 bugfix - CLOSE-WAIT sockets left over by read errors have been fixed. * Jul 19 bugfix - Errors caused by using UnicodeLittle as opposed to UnicodeLittleUnmarked have been fixed by ensuring UnicodeLittleUnmarked is used throughout the codebase. * Oct 3 bugfix - Invalid state errors from Transport classes have been fixed. It should be safe to interrupt() JCIFS operations now. * Oct 20 bugfix - Uncontrolled looping due to invalid Transport logic has been fixed. * Oct 25 bugfix - Logic has been added to make domain controller lookups more robust. * Oct 27 bugfix - Failure when using SmbFile.renameTo() with jcifs.smb.client.ssnLimit=1 has been fixed. * Oct 31 bugfix - Endless looping when all WINS servers in a list are unavailable has been fixed. Note the openFlags used with SmbFile, SmbNamedPipe, and various streams classes have been tweaked. They are now the following: Flags for SmbFile{In,Out}putStream are: bits meaning 0-15 open flags (e.g. O_RDWR) 16-31 lower 16 bits of access mask shifted up 16 bits Flags for SmbNamedPipe are: bits meaning 0-7 open flags (e.g. O_RDWR) 8-15 pipe type (e.g. PIPE_TYPE_CALL) 16-31 lower 16 bits of access mask shifted up 16 bits --- diff --git a/README.txt b/README.txt index 12f21c8..db54b75 100644 --- a/README.txt +++ b/README.txt @@ -1,3 +1,60 @@ +Tue Nov 14 12:32:23 EST 2006 +jcifs-1.2.10b released / MSRPC Support, Long Unicode Share Name + Enumeration and Critical Bugfixes + +This release contains the following new functionality and fixes: + + * Long Unicode Share Enumeration - The SmbFile.list* methods will now + try to use MSRPC to enumerate shares if the target is a server. If + the operation should fail for any reason, the client will fall + back to trying the older RAP method. This should permit enumerating + shares with names that use charsets other than the negotiated OEM + "ASCII" encoding, share names that are longer than 12 characters, + and arbirarily large lists of shares. + * MSRPC Support - MSRPC support has been integrated into JCIFS + directly. It should now be possible to add new RPCs (AT jobs, + SID/group name resolution, service management, regedit, etc) + relatively easily with little knowledge of MSRPC protocols. Look at + the jcifs/dcerpc/msrpc/MsrpcShareEnum.java class for an example and + ask the mailing list for further instructions. + * Apr 24 bugfix - A NullPointerException caused by an error in logic + has been fixed. + * May 10 bugfix - The client will now detect if the JRE supports Cp850 + and set the default jcifs.encoding to US-ASCII if it does not. This + will eliminate some NullPointerExceptions that were occuring as + a result. + * A small update about keep-alives has been added to the NTLM HTTP + Authentication document. + * Jun 21 bugfix - CLOSE-WAIT sockets left over by read errors have + been fixed. + * Jul 19 bugfix - Errors caused by using UnicodeLittle as + opposed to UnicodeLittleUnmarked have been fixed by ensuring + UnicodeLittleUnmarked is used throughout the codebase. + * Oct 3 bugfix - Invalid state errors from Transport classes have + been fixed. It should be safe to interrupt() JCIFS operations now. + * Oct 20 bugfix - Uncontrolled looping due to invalid Transport + logic has been fixed. + * Oct 25 bugfix - Logic has been added to make domain controller + lookups more robust. + * Oct 27 bugfix - Failure when using SmbFile.renameTo() with + jcifs.smb.client.ssnLimit=1 has been fixed. + * Oct 31 bugfix - Endless looping when all WINS servers in a list + are unavailable has been fixed. + +Note the openFlags used with SmbFile, SmbNamedPipe, and various streams +classes have been tweaked. They are now the following: + + Flags for SmbFile{In,Out}putStream are: + bits meaning + 0-15 open flags (e.g. O_RDWR) + 16-31 lower 16 bits of access mask shifted up 16 bits + + Flags for SmbNamedPipe are: + bits meaning + 0-7 open flags (e.g. O_RDWR) + 8-15 pipe type (e.g. PIPE_TYPE_CALL) + 16-31 lower 16 bits of access mask shifted up 16 bits + Tue Apr 4 15:44:43 EDT 2006 jcifs-1.2.9 released / Java 1.5 Compiler Issue diff --git a/build.xml b/build.xml index 0c8dfdb..5f3f346 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - - + + diff --git a/examples/InterruptTest.java b/examples/InterruptTest.java new file mode 100644 index 0000000..1105b4d --- /dev/null +++ b/examples/InterruptTest.java @@ -0,0 +1,50 @@ +import jcifs.util.transport.TransportException; +import jcifs.smb.*; + +public class InterruptTest extends Thread { + + String url; + + public InterruptTest(String url) { + this.url = url; + } + public void run() { + for (int i = 0; i < 10; i++) { + try { + SmbFileInputStream in = new SmbFileInputStream(url); + + byte[] b = new byte[10]; + while(in.read( b ) > 0) { + ; + } + + in.close(); + } catch(SmbException se) { + Throwable t = se.getRootCause(); + if (t instanceof TransportException) { + TransportException te = (TransportException)t; + t = te.getRootCause(); + if (t instanceof InterruptedException) { + System.out.println("interrupted ok"); + continue; + } + } + se.printStackTrace(); + try { Thread.sleep(500); } catch(InterruptedException ie) {} + } catch(Exception e) { + e.printStackTrace(); + break; + } + } + } + + public static void main( String argv[] ) throws Exception { + InterruptTest it = new InterruptTest(argv[0]); + it.start(); + for (int i = 0; i < 10; i++) { + Thread.sleep(200); + it.interrupt(); + } + } +} + diff --git a/examples/Makefile b/examples/Makefile index 4888a83..1051bdf 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,7 +3,7 @@ CLASSPATH=../build:. .SUFFIXES: .java .class -CLASSFILES=AllocInfo.class Append.class AuthListFiles.class CallNamedPipe.class CopyTo.class CreateFile.class Delete.class Equals.class Exists.class FileInfo.class FileOps.class FilterFiles.class Format.class GetDate.class GetDfsPath.class Get.class GetType.class GetURL.class GrowWrite.class HttpURL.class Interleave.class IsDir.class Length.class ListFiles.class List.class ListTypes.class Mkdir.class NodeStatus.class OpenExclusive.class PeekNamedPipe.class PipeTalk.class Put.class Query.class RenameTo.class SetAttrs.class SetTime.class SlowRead.class SlowWrite.class SmbCrawler.class SmbShell.class SmbTableFile.class SmbTableFileRecord.class T2Crawler.class TestRandomAccess.class TestSmbURL.class TestUnicode.class ThreadedNbtQuery.class ThreadedSmbCrawler.class ThreadedUniQuery.class Torture1.class Torture2.class TortureTest5.class TransactNamedPipe.class URLTest.class VerifyGuest.class VerifyIO.class VerifyReads.class +CLASSFILES=InterruptedTest.class AllocInfo.class Append.class AuthListFiles.class CallNamedPipe.class CopyTo.class CreateFile.class Delete.class Equals.class Exists.class FileInfo.class FileOps.class FilterFiles.class Format.class GetDate.class GetDfsPath.class Get.class GetType.class GetURL.class GrowWrite.class HttpURL.class Interleave.class IsDir.class Length.class ListFiles.class List.class ListTypes.class Mkdir.class NodeStatus.class OpenExclusive.class PeekNamedPipe.class PipeTalk.class Put.class Query.class RenameTo.class SetAttrs.class SetTime.class SlowRead.class SlowWrite.class SmbCrawler.class SmbShell.class SmbTableFile.class SmbTableFileRecord.class T2Crawler.class TestRandomAccess.class TestSmbURL.class TestUnicode.class ThreadedNbtQuery.class ThreadedSmbCrawler.class ThreadedUniQuery.class Torture1.class Torture2.class TortureTest5.class TransactNamedPipe.class URLTest.class VerifyGuest.class VerifyIO.class VerifyReads.class all: ${CLASSFILES} diff --git a/examples/T2Crawler.java b/examples/T2Crawler.java index c325e36..cd06f54 100644 --- a/examples/T2Crawler.java +++ b/examples/T2Crawler.java @@ -118,7 +118,12 @@ public class T2Crawler { } } for( i = 0; i < l.length; i++ ) { - l[i].canRead(); + try { + l[i].canRead(); + } catch(Exception ex) { + System.err.println( l[i] ); + ex.printStackTrace(); + } } } catch( Exception ex ) { System.err.println( l[i] ); diff --git a/examples/U2.java b/examples/U2.java new file mode 100644 index 0000000..63a25ff --- /dev/null +++ b/examples/U2.java @@ -0,0 +1,10 @@ +import jcifs.dcerpc.*; +import jcifs.util.*; + +public class U2 { + + public static void main( String[] argv ) throws Exception { + UUID uuid = new UUID(argv[0]); + System.out.println(uuid.toString()); + } +} diff --git a/examples/run1.sh b/examples/run1.sh index 010f5ad..286eef3 100644 --- a/examples/run1.sh +++ b/examples/run1.sh @@ -5,8 +5,8 @@ CLASSPATH=../build:. PROPERTIES=../../miallen.prp RUN="${JAVA_HOME}/bin/java -cp ${CLASSPATH} -Djcifs.properties=${PROPERTIES}" -SERVER=xp1 -SHARE=temp +SERVER=xp3 +SHARE=tmp WRITE_DIR=test/ SRC_DIR=test/Junk FILE1=test/Junk/10883563.doc @@ -14,6 +14,7 @@ FILE1=test/Junk/10883563.doc URL_SHARE=smb://${SERVER}/${SHARE}/ URL_WRITE_DIR=${URL_SHARE}${WRITE_DIR} +[ "$1" = "InterruptTest" ] && $RUN InterruptTest ${URL_WRITE_DIR}Append.txt [ "$1" = "AllocInfo" ] && $RUN AllocInfo ${URL_SHARE} [ "$1" = "Append" ] && $RUN Append ${URL_WRITE_DIR}Append.txt [ "$1" = "AuthListFiles" ] && $RUN AuthListFiles smb://bogus\@${SERVER}/${SHARE}/ diff --git a/examples/runtests.sh b/examples/runtests.sh index d79cae1..98ad6f8 100644 --- a/examples/runtests.sh +++ b/examples/runtests.sh @@ -5,8 +5,8 @@ CLASSPATH=../build:. PROPERTIES=../../miallen.prp RUN="${JAVA_HOME}/bin/java -cp ${CLASSPATH} -Djcifs.properties=${PROPERTIES}" -SERVER=xp1 -SHARE=temp +SERVER=xp3 +SHARE=tmp WRITE_DIR=test/ SRC_DIR=test/Junk FILE1=test/Junk/10883563.doc @@ -16,8 +16,9 @@ URL_WRITE_DIR=${URL_SHARE}${WRITE_DIR} set -x +$RUN InterruptTest ${URL_WRITE_DIR}Append.txt $RUN AllocInfo ${URL_SHARE} -#$RUN Append ${URL_WRITE_DIR}Append.txt +$RUN Append ${URL_WRITE_DIR}Append.txt $RUN AuthListFiles smb://bogus\@${SERVER}/${SHARE}/ $RUN CopyTo ${URL_SHARE}${SRC_DIR}/ ${URL_SHARE}${WRITE_DIR}CopyTo/ $RUN CreateFile ${URL_WRITE_DIR}CreateFile.txt diff --git a/src/jcifs/Config.java b/src/jcifs/Config.java index bf70a10..dd22499 100644 --- a/src/jcifs/Config.java +++ b/src/jcifs/Config.java @@ -51,6 +51,7 @@ public class Config { private static Properties prp = new Properties(); private static LogStream log; + public static String DEFAULT_OEM_ENCODING = "Cp850"; static { String filename; @@ -74,7 +75,17 @@ public class Config { LogStream.setLevel( level ); } - if( log.level > 2 ) { + try { + "".getBytes(DEFAULT_OEM_ENCODING); + } catch (UnsupportedEncodingException uee) { + if (log.level >= 2) { + log.println("WARNING: The default OEM encoding " + DEFAULT_OEM_ENCODING + + " does not appear to be supported by this JRE. The default encoding will be US-ASCII."); + } + DEFAULT_OEM_ENCODING = "US-ASCII"; + } + + if (log.level >= 4) { try { prp.store( log, "JCIFS PROPERTIES" ); } catch( IOException ioe ) { diff --git a/src/jcifs/dcerpc/DcerpcBind.java b/src/jcifs/dcerpc/DcerpcBind.java new file mode 100644 index 0000000..5e792a9 --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcBind.java @@ -0,0 +1,87 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.*; + +public class DcerpcBind extends DcerpcMessage { + + static final String[] result_message = { + "0", + "DCERPC_BIND_ERR_ABSTRACT_SYNTAX_NOT_SUPPORTED", + "DCERPC_BIND_ERR_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED", + "DCERPC_BIND_ERR_LOCAL_LIMIT_EXCEEDED" + }; + + static String getResultMessage(int result) { + return result < 4 ? + result_message[result] : + "0x" + jcifs.util.Hexdump.toHexString(result, 4); + } + public DcerpcException getResult() { + if (result != 0) + return new DcerpcException(getResultMessage(result)); + return null; + } + + DcerpcBinding binding; + int max_xmit, max_recv; + + DcerpcBind(DcerpcBinding binding, DcerpcHandle handle) { + this.binding = binding; + max_xmit = handle.max_xmit; + max_recv = handle.max_recv; + ptype = 11; + flags = DCERPC_FIRST_FRAG | DCERPC_LAST_FRAG; + } + + public int getOpnum() { + return 0; + } + public void encode_in(NdrBuffer buf) throws NdrException { + buf.enc_ndr_short(max_xmit); + buf.enc_ndr_short(max_recv); + buf.enc_ndr_long(0); /* assoc. group */ + buf.enc_ndr_small(1); /* num context items */ + buf.enc_ndr_small(0); /* reserved */ + buf.enc_ndr_short(0); /* reserved2 */ + buf.enc_ndr_short(0); /* context id */ + buf.enc_ndr_small(1); /* number of items */ + buf.enc_ndr_small(0); /* reserved */ + binding.uuid.encode(buf); + buf.enc_ndr_short(binding.major); + buf.enc_ndr_short(binding.minor); + DCERPC_UUID_SYNTAX_NDR.encode(buf); + buf.enc_ndr_long(2); /* syntax version */ + } + public void decode_out(NdrBuffer buf) throws NdrException { + buf.dec_ndr_short(); /* max transmit frag size */ + buf.dec_ndr_short(); /* max receive frag size */ + buf.dec_ndr_long(); /* assoc. group */ + int n = buf.dec_ndr_short(); /* secondary addr len */ + buf.advance(n); /* secondary addr */ + buf.align(4); + buf.dec_ndr_small(); /* num results */ + buf.align(4); + result = buf.dec_ndr_short(); + buf.dec_ndr_short(); + buf.advance(20); /* transfer syntax / version */ + } +} diff --git a/src/jcifs/dcerpc/DcerpcBinding.java b/src/jcifs/dcerpc/DcerpcBinding.java new file mode 100644 index 0000000..8329d47 --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcBinding.java @@ -0,0 +1,89 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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 java.util.HashMap; +import java.util.Iterator; + +import jcifs.dcerpc.msrpc.*; + +class DcerpcBinding { + + private static HashMap INTERFACES; + + static { + INTERFACES = new HashMap(); + INTERFACES.put("srvsvc", srvsvc.getSyntax()); + } + + String proto; + String server; + String endpoint = null; + HashMap options = null; + UUID uuid = null; + int major; + int minor; + + DcerpcBinding(String proto, String server) { + this.proto = proto; + this.server = server; + } + + void setOption(String key, Object val) throws DcerpcException { + if (key.equals("endpoint")) { + endpoint = val.toString().toLowerCase(); + if (endpoint.startsWith("\\pipe\\")) { + String iface = (String)INTERFACES.get(endpoint.substring(6)); + if (iface != null) { + int c, p; + c = iface.indexOf(':'); + p = iface.indexOf('.', c + 1); + uuid = new UUID(iface.substring(0, c)); + major = Integer.parseInt(iface.substring(c + 1, p)); + minor = Integer.parseInt(iface.substring(p + 1)); + return; + } + } + throw new DcerpcException("Bad endpoint: " + endpoint); + } + if (options == null) + options = new HashMap(); + options.put(key, val); + } + Object getOption(String key) { + if (key.equals("endpoint")) + return endpoint; + return options.get(key); + } + + public String toString() { + String ret = proto + ":" + server + "[" + endpoint; + if (options != null) { + Iterator iter = options.keySet().iterator(); + while (iter.hasNext()) { + Object key = iter.next(); + Object val = options.get(key); + ret += "," + key + "=" + val; + } + } + ret += "]"; + return ret; + } +} diff --git a/src/jcifs/dcerpc/DcerpcConstants.java b/src/jcifs/dcerpc/DcerpcConstants.java new file mode 100644 index 0000000..540849b --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcConstants.java @@ -0,0 +1,34 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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; + +public interface DcerpcConstants { + + public static final UUID DCERPC_UUID_SYNTAX_NDR = new UUID("8a885d04-1ceb-11c9-9fe8-08002b104860"); + + public static final int DCERPC_FIRST_FRAG = 0x01; /* First fragment */ + public static final int DCERPC_LAST_FRAG = 0x02; /* Last fragment */ + public static final int DCERPC_PENDING_CANCEL = 0x04; /* Cancel was pending at sender */ + public static final int DCERPC_RESERVED_1 = 0x08; + public static final int DCERPC_CONC_MPX = 0x10; /* supports concurrent multiplexing */ + public static final int DCERPC_DID_NOT_EXECUTE = 0x20; + public static final int DCERPC_MAYBE = 0x40; /* `maybe' call semantics requested */ + public static final int DCERPC_OBJECT_UUID = 0x80; /* if true, a non-nil object UUID */ +} diff --git a/src/jcifs/dcerpc/DcerpcError.java b/src/jcifs/dcerpc/DcerpcError.java new file mode 100644 index 0000000..83011d0 --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcError.java @@ -0,0 +1,58 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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; + +public interface DcerpcError { + + public static final int DCERPC_FAULT_OTHER = 0x00000001; + public static final int DCERPC_FAULT_ACCESS_DENIED = 0x00000005; + public static final int DCERPC_FAULT_CANT_PERFORM = 0x000006D8; + public static final int DCERPC_FAULT_NDR = 0x000006F7; + public static final int DCERPC_FAULT_INVALID_TAG = 0x1C000006; + public static final int DCERPC_FAULT_CONTEXT_MISMATCH = 0x1C00001A; + public static final int DCERPC_FAULT_OP_RNG_ERROR = 0x1C010002; + public static final int DCERPC_FAULT_UNK_IF = 0x1C010003; + public static final int DCERPC_FAULT_PROTO_ERROR = 0x1c01000b; + + static final int[] DCERPC_FAULT_CODES = { + DCERPC_FAULT_OTHER, + DCERPC_FAULT_ACCESS_DENIED, + DCERPC_FAULT_CANT_PERFORM, + DCERPC_FAULT_NDR, + DCERPC_FAULT_INVALID_TAG, + DCERPC_FAULT_CONTEXT_MISMATCH, + DCERPC_FAULT_OP_RNG_ERROR, + DCERPC_FAULT_UNK_IF, + DCERPC_FAULT_PROTO_ERROR + }; + + static final String[] DCERPC_FAULT_MESSAGES = { + "DCERPC_FAULT_OTHER", + "DCERPC_FAULT_ACCESS_DENIED", + "DCERPC_FAULT_CANT_PERFORM", + "DCERPC_FAULT_NDR", + "DCERPC_FAULT_INVALID_TAG", + "DCERPC_FAULT_CONTEXT_MISMATCH", + "DCERPC_FAULT_OP_RNG_ERROR", + "DCERPC_FAULT_UNK_IF", + "DCERPC_FAULT_PROTO_ERROR" + }; +} + diff --git a/src/jcifs/dcerpc/DcerpcException.java b/src/jcifs/dcerpc/DcerpcException.java new file mode 100644 index 0000000..d8a2b7a --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcException.java @@ -0,0 +1,77 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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 java.io.*; + +import jcifs.util.Hexdump; +import jcifs.smb.WinError; + +public class DcerpcException extends IOException implements DcerpcError, WinError { + + static String getMessageByDcerpcError(int errcode) { + int min = 0; + int max = DCERPC_FAULT_CODES.length; + + while (max >= min) { + int mid = (min + max) / 2; + + if (errcode > DCERPC_FAULT_CODES[mid]) { + min = mid + 1; + } else if (errcode < DCERPC_FAULT_CODES[mid]) { + max = mid - 1; + } else { + return DCERPC_FAULT_MESSAGES[mid]; + } + } + + return "0x" + Hexdump.toHexString(errcode, 8); + } + + 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) { + super(msg); + this.rootCause = rootCause; + } + public int getErrorCode() { + return error; + } + public Throwable getRootCause() { + return rootCause; + } + public String toString() { + if (rootCause != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + rootCause.printStackTrace(pw); + return super.toString() + "\n" + sw; + } + return super.toString(); + } +} diff --git a/src/jcifs/dcerpc/DcerpcHandle.java b/src/jcifs/dcerpc/DcerpcHandle.java new file mode 100644 index 0000000..b5df2c3 --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcHandle.java @@ -0,0 +1,187 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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 java.io.*; +import java.net.*; + +import jcifs.smb.NtlmPasswordAuthentication; +import jcifs.util.Hexdump; +import jcifs.dcerpc.ndr.NdrBuffer; + +public abstract class DcerpcHandle implements DcerpcConstants { + + /* Bindings are in the form: + * proto:\\server[key1=val1,key2=val2] + * or + * proto:server[key1=val1,key2=val2] + * or + * proto:[key1=val1,key2=val2] + * + * If a key is absent it is assumed to be 'endpoint'. Thus the + * following are equivalent: + * proto:\\ts0.win.net[endpoint=\pipe\srvsvc] + * proto:ts0.win.net[\pipe\srvsvc] + * + * If the server is absent it is set to "127.0.0.1" + */ + protected static DcerpcBinding parseBinding(String str) throws DcerpcException { + int state, mark, si; + char[] arr = str.toCharArray(); + String proto = null, key = null; + DcerpcBinding binding = null; + + state = mark = si = 0; + do { + char ch = arr[si]; + + switch (state) { + case 0: + if (ch == ':') { + proto = str.substring(mark, si); + mark = si + 1; + state = 1; + } + break; + case 1: + if (ch == '\\') { + mark = si + 1; + break; + } + state = 2; + case 2: + if (ch == '[') { + String server = str.substring(mark, si).trim(); + if (server.length() == 0) + server = "127.0.0.1"; + binding = new DcerpcBinding(proto, str.substring(mark, si)); + mark = si + 1; + state = 5; + } + break; + case 5: + if (ch == '=') { + key = str.substring(mark, si).trim(); + mark = si + 1; + } else if (ch == ',' || ch == ']') { + String val = str.substring(mark, si).trim(); + if (key == null) + key = "endpoint"; + binding.setOption(key, val); + key = null; + } + break; + default: + si = arr.length; + } + + si++; + } while (si < arr.length); + + if (binding == null || binding.endpoint == null) + throw new DcerpcException("Invalid binding URL: " + str); + + return binding; + } + + protected DcerpcBinding binding; + protected int max_xmit = 4280; + protected int max_recv = max_xmit; + protected int state = 0; + private static int call_id = 0; + + public static DcerpcHandle getHandle(String url, + NtlmPasswordAuthentication auth) + throws UnknownHostException, MalformedURLException, DcerpcException { + if (url.startsWith("ncacn_np:")) { + return new DcerpcPipeHandle(url, auth); + } + throw new DcerpcException("DCERPC transport not supported: " + url); + } + + public void sendrecv(DcerpcMessage msg) throws DcerpcException, IOException { + byte[] frag, stub; + NdrBuffer buf; + boolean isLast; + DcerpcException de; + int off = 24; + + if (state == 0) { + state = 1; + DcerpcMessage bind = new DcerpcBind(binding, this); + sendrecv(bind); + } + + stub = frag = new byte[max_recv]; + buf = new NdrBuffer(frag, 0); + + msg.encode(buf); + + // assumes 1 fragment for now + msg.call_id = call_id++; + doSendFragment(frag, 0, buf.getLength()); + + doReceiveFragment(frag); + buf.reset(); + msg.decode_header(buf); + + if (msg.ptype == 2 && msg.isFlagSet(DCERPC_LAST_FRAG) == false) { + msg.alloc_hint = buf.dec_ndr_long(); + if (msg.alloc_hint > (stub.length - 24)) { + stub = new byte[msg.alloc_hint]; + System.arraycopy(frag, 0, stub, 0, msg.length); + } + off = msg.length; + } + + while (msg.isFlagSet(DCERPC_LAST_FRAG) == false) { + int stub_frag_len; + + doReceiveFragment(frag); + buf.reset(); + msg.decode_header(buf); + stub_frag_len = msg.length - 24; + + if ((off + stub_frag_len) > stub.length) { + // shouldn't happen if alloc_hint is correct or greater + byte[] tmp = new byte[off + stub_frag_len]; + System.arraycopy(stub, 0, tmp, 0, off); + stub = tmp; + } + + System.arraycopy(frag, 24, stub, off, stub_frag_len); + off += stub_frag_len; + } + + buf = new NdrBuffer(stub, 0); + + msg.decode(buf); + + if ((de = msg.getResult()) != null) + throw de; + } + public String toString() { + return binding.toString(); + } + + protected abstract void doSendFragment(byte[] buf, int off, int length) throws IOException; + protected abstract void doReceiveFragment(byte[] buf) throws IOException; + public abstract void close() throws IOException; +} diff --git a/src/jcifs/dcerpc/DcerpcMessage.java b/src/jcifs/dcerpc/DcerpcMessage.java new file mode 100644 index 0000000..83df082 --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcMessage.java @@ -0,0 +1,111 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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 java.io.IOException; +import jcifs.dcerpc.ndr.*; + +public abstract class DcerpcMessage extends NdrObject implements DcerpcConstants { + + protected int ptype = -1; + protected int flags = 0; + protected int length = 0; + protected int call_id = 0; + protected int alloc_hint = 0; + protected int result = 0; + + public boolean isFlagSet(int flag) { + return (flags & flag) == flag; + } + public DcerpcException getResult() { + if (result != 0) + return new DcerpcException(result); + return null; + } + + void encode_header(NdrBuffer buf) { + buf.enc_ndr_small(5); /* RPC version */ + buf.enc_ndr_small(0); /* minor version */ + buf.enc_ndr_small(ptype); + buf.enc_ndr_small(flags); + buf.enc_ndr_long(0x00000010); /* Little-endian / ASCII / IEEE */ + buf.enc_ndr_short(length); + buf.enc_ndr_short(0); /* length of auth_value */ + 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 */ + ptype = buf.dec_ndr_small(); + flags = buf.dec_ndr_small(); + if (buf.dec_ndr_long() != 0x00000010) /* Little-endian / ASCII / IEEE */ + throw new NdrException("Data representation not supported"); + length = buf.dec_ndr_short(); + if (buf.dec_ndr_short() != 0) + throw new NdrException("DCERPC authentication not supported"); + call_id = buf.dec_ndr_long(); + } + public void encode(NdrBuffer buf) throws NdrException { + int start = buf.getIndex(); + int alloc_hint_index = 0; + + buf.advance(16); /* momentarily skip header */ + if (ptype == 0) { /* Request */ + alloc_hint_index = buf.getIndex(); + buf.enc_ndr_long(0); /* momentarily skip alloc hint */ + buf.enc_ndr_short(0); /* context id */ + buf.enc_ndr_short(getOpnum()); + } + + encode_in(buf); + length = buf.getIndex() - start; + + if (ptype == 0) { + buf.setIndex(alloc_hint_index); + alloc_hint = length - alloc_hint_index; + buf.enc_ndr_long(alloc_hint); + } + + buf.setIndex(start); + encode_header(buf); + buf.setIndex(start + length); + } + public void decode(NdrBuffer buf) throws NdrException { + decode_header(buf); + + if (ptype != 12 && ptype != 2 && ptype != 3) + throw new NdrException("Unexpected ptype: " + ptype); + + if (ptype == 2 || ptype == 3) { /* Response or Fault */ + alloc_hint = buf.dec_ndr_long(); + buf.dec_ndr_short(); /* context id */ + buf.dec_ndr_short(); /* cancel count */ + } + if (ptype == 3) { /* Fault */ + result = buf.dec_ndr_long(); + } else { /* Bind_ack or Response */ + decode_out(buf); + } + } + + public abstract int getOpnum(); + public abstract void encode_in(NdrBuffer buf) throws NdrException; + public abstract void decode_out(NdrBuffer buf) throws NdrException; +} diff --git a/src/jcifs/dcerpc/DcerpcPipeHandle.java b/src/jcifs/dcerpc/DcerpcPipeHandle.java new file mode 100644 index 0000000..7d7a824 --- /dev/null +++ b/src/jcifs/dcerpc/DcerpcPipeHandle.java @@ -0,0 +1,83 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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 java.net.*; +import java.io.*; + +import jcifs.dcerpc.ndr.NdrBuffer; +import jcifs.smb.*; +import jcifs.util.*; + +public class DcerpcPipeHandle extends DcerpcHandle { + + SmbNamedPipe pipe; + SmbFileInputStream in; + OutputStream out = null; + boolean isStart = true; + + public DcerpcPipeHandle(String url, + NtlmPasswordAuthentication auth) + throws UnknownHostException, MalformedURLException, DcerpcException { + binding = DcerpcHandle.parseBinding(url); + url = "smb://" + binding.server + "/IPC$/" + binding.endpoint.substring(6); + pipe = new SmbNamedPipe(url, + /* This 0x20000 bit is going to get chopped! */ + (0x2019F << 16) | SmbNamedPipe.PIPE_TYPE_RDWR | SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT, + auth); + } + + protected void doSendFragment(byte[] buf, int off, int length) throws IOException { + in = (SmbFileInputStream)pipe.getNamedPipeInputStream(); + out = pipe.getNamedPipeOutputStream(); + out.write(buf, 0, length); + } + protected void doReceiveFragment(byte[] buf) throws IOException { + int off, flags, length; + + if (buf.length < max_recv) + throw new IllegalArgumentException("buffer too small"); + + if (isStart) { // start of new frag, do trans + off = in.read(buf, 0, 1024); + } else { + off = in.readDirect(buf, 0, buf.length); + } + + if (buf[0] != 5 && buf[1] != 0) + throw new IOException("Unexpected DCERPC PDU header"); + + flags = buf[3] & 0xFF; + // next read is start of new frag + isStart = (flags & DCERPC_LAST_FRAG) == DCERPC_LAST_FRAG; + + length = Encdec.dec_uint16le(buf, 8); + if (length > max_recv) + throw new IOException("Unexpected fragment length: " + length); + + while (off < length) { + off += in.readDirect(buf, off, length - off); + } + } + public void close() throws IOException { + out.close(); + } +} + diff --git a/src/jcifs/dcerpc/UUID.java b/src/jcifs/dcerpc/UUID.java new file mode 100644 index 0000000..b36e566 --- /dev/null +++ b/src/jcifs/dcerpc/UUID.java @@ -0,0 +1,96 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.util.*; + +public class UUID extends rpc.uuid_t { + + public static int hex_to_bin(char[] arr, int offset, int length) { + int value = 0; + int ai, count; + + count = 0; + for (ai = offset; ai < arr.length && count < length; ai++) { + value <<= 4; + switch (arr[ai]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + value += arr[ai] - '0'; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + value += 10 + (arr[ai] - 'A'); + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + value += 10 + (arr[ai] - 'a'); + break; + default: + throw new IllegalArgumentException(new String(arr, offset, length)); + } + count++; + } + + return value; + } + static final char[] HEXCHARS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + public static String bin_to_hex(int value, int length) { + char[] arr = new char[length]; + int ai = arr.length; + while (ai-- > 0) { + arr[ai] = HEXCHARS[value & 0xF]; + value >>>= 4; + } + return new String(arr); + } + private static byte B(int i) { return (byte)(i & 0xFF); } + private static short S(int i) { return (short)(i & 0xFFFF); } + + public UUID(String str) { + char[] arr = str.toCharArray(); + time_low = hex_to_bin(arr, 0, 8); + time_mid = S(hex_to_bin(arr, 9, 4)); + time_hi_and_version = S(hex_to_bin(arr, 14, 4)); + clock_seq_hi_and_reserved = B(hex_to_bin(arr, 19, 2)); + clock_seq_low = B(hex_to_bin(arr, 21, 2)); + node = new byte[6]; + node[0] = B(hex_to_bin(arr, 24, 2)); + node[1] = B(hex_to_bin(arr, 26, 2)); + node[2] = B(hex_to_bin(arr, 28, 2)); + node[3] = B(hex_to_bin(arr, 30, 2)); + node[4] = B(hex_to_bin(arr, 32, 2)); + node[5] = B(hex_to_bin(arr, 34, 2)); + } + + public String toString() { + return bin_to_hex(time_low, 8) + '-' + + bin_to_hex(time_mid, 4) + '-' + + bin_to_hex(time_hi_and_version, 4) + '-' + + bin_to_hex(clock_seq_hi_and_reserved, 2) + + bin_to_hex(clock_seq_low, 2) + '-' + + bin_to_hex(node[0], 2) + + bin_to_hex(node[1], 2) + + bin_to_hex(node[2], 2) + + bin_to_hex(node[3], 2) + + bin_to_hex(node[4], 2) + + bin_to_hex(node[5], 2); + } +} diff --git a/src/jcifs/dcerpc/msrpc/MsrpcShareEnum.java b/src/jcifs/dcerpc/msrpc/MsrpcShareEnum.java new file mode 100644 index 0000000..040e872 --- /dev/null +++ b/src/jcifs/dcerpc/msrpc/MsrpcShareEnum.java @@ -0,0 +1,92 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.msrpc; + +import jcifs.smb.*; +import jcifs.util.Hexdump; + +public class MsrpcShareEnum extends srvsvc.ShareEnumAll { + + class MsrpcShareInfo1 implements FileEntry { + + String netname; + int type; + String remark; + + MsrpcShareInfo1(srvsvc.ShareInfo1 info1) { + this.netname = info1.netname; + this.type = info1.type; + this.remark = info1.remark; + } + + public String getName() { + return netname; + } + public int getType() { + /* 0x80000000 means hidden but SmbFile.isHidden() checks for $ at end + */ + switch(type & 0xFFFF) { + case 1: + return SmbFile.TYPE_PRINTER; + case 3: + return SmbFile.TYPE_NAMED_PIPE; + } + return SmbFile.TYPE_SHARE; + } + public int getAttributes() { + return SmbFile.ATTR_READONLY | SmbFile.ATTR_DIRECTORY; + } + public long createTime() { + return 0L; + } + public long lastModified() { + return 0L; + } + public long length() { + return 0L; + } + + public String toString() { + return new String( "MsrpcShareInfo1[" + + "netName=" + netname + + ",type=0x" + Hexdump.toHexString( type, 8 ) + + ",remark=" + remark + "]" ); + } + } + + public MsrpcShareEnum(String server) { + super("\\\\" + server, 1, new srvsvc.ShareInfoCtr1(), -1, 0, 0); + ptype = 0; + flags = DCERPC_FIRST_FRAG | DCERPC_LAST_FRAG; + } + + public FileEntry[] getEntries() { + /* The ShareInfo1 class does not implement the FileEntry + * interface (because it is generated from IDL). Therefore + * we must create an array of objects that do. + */ + srvsvc.ShareInfoCtr1 ctr = (srvsvc.ShareInfoCtr1)info; + MsrpcShareInfo1[] entries = new MsrpcShareInfo1[ctr.count]; + for (int i = 0; i < ctr.count; i++) { + entries[i] = new MsrpcShareInfo1(ctr.array[i]); + } + return entries; + } +} diff --git a/src/jcifs/dcerpc/msrpc/srvsvc.idl b/src/jcifs/dcerpc/msrpc/srvsvc.idl new file mode 100644 index 0000000..7f28ee2 --- /dev/null +++ b/src/jcifs/dcerpc/msrpc/srvsvc.idl @@ -0,0 +1,76 @@ +[ + uuid(4b324fc8-1670-01d3-1278-5a47bf6ee188), + version(3.0) +] +interface srvsvc +{ + import "rpc.idl"; + + typedef struct { + [string] wchar_t *netname; + } ShareInfo0; + + typedef struct { + int count; + [size_is(count)] ShareInfo0 *array; + } ShareInfoCtr0; + + typedef struct { + [string] wchar_t *netname; + int type; + [string] wchar_t *remark; + } ShareInfo1; + + typedef struct { + int count; + [size_is(count)] ShareInfo1 *array; + } ShareInfoCtr1; + + typedef [switch_type(int)] union { + [case(0)] ShareInfoCtr0 *info0; + [case(1)] ShareInfoCtr1 *info1; + } ShareCtr; + + [op(0x0f)] + int ShareEnumAll([in,string,unique] wchar_t *servername, + [in,out] int *level, + [in,out,switch_is(*level)] ShareCtr *info, + [in] unsigned long prefmaxlen, + [out] unsigned long *totalentries, + [in,out] unsigned long *resume_handle); + + typedef struct { + unsigned long platform_id; + [string] wchar_t *name; + } ServerInfo100; + + typedef [switch_type(int)] union { + [case(0)] ServerInfo100 *info0; + } ServerInfo; + + [op(0x15)] + int ServerGetInfo([in,string,unique] wchar_t *servername, + [in] int level, + [out,switch_is(level)] ServerInfo *info); + + typedef struct { + uint32_t elapsedt; + uint32_t msecs; + uint32_t hours; + uint32_t mins; + uint32_t secs; + uint32_t hunds; + uint32_t timezone; + uint32_t tinterval; + uint32_t day; + uint32_t month; + uint32_t year; + uint32_t weekday; + } TimeOfDayInfo; + + [op(0x1c)] + int RemoteTOD([in,string,unique] wchar_t *servername, + [out,unique] TimeOfDayInfo *info); +} + + diff --git a/src/jcifs/dcerpc/msrpc/srvsvc.java b/src/jcifs/dcerpc/msrpc/srvsvc.java new file mode 100644 index 0000000..179e1b6 --- /dev/null +++ b/src/jcifs/dcerpc/msrpc/srvsvc.java @@ -0,0 +1,380 @@ +package jcifs.dcerpc.msrpc; + +import jcifs.dcerpc.*; +import jcifs.dcerpc.ndr.*; + +public class srvsvc { + + public static String getSyntax() { + return "4b324fc8-1670-01d3-1278-5a47bf6ee188:3.0"; + } + + public static class ShareInfo0 extends NdrObject { + + public String netname; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_referent(netname, 1); + + if (netname != null) { + _dst = _dst.deferred; + _dst.enc_ndr_string(netname); + + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + int _netnamep = _src.dec_ndr_long(); + + if (_netnamep != 0) { + _src = _src.deferred; + netname = _src.dec_ndr_string(); + + } + } + } + public static class ShareInfoCtr0 extends NdrObject { + + public int count; + public ShareInfo0[] array; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_long(count); + _dst.enc_ndr_referent(array, 1); + + if (array != null) { + _dst = _dst.deferred; + int _arrays = count; + _dst.enc_ndr_long(_arrays); + int _arrayi = _dst.index; + _dst.advance(4 * _arrays); + + _dst = _dst.derive(_arrayi); + for (int _i = 0; _i < _arrays; _i++) { + array[_i].encode(_dst); + } + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + count = (int)_src.dec_ndr_long(); + int _arrayp = _src.dec_ndr_long(); + + if (_arrayp != 0) { + _src = _src.deferred; + int _arrays = _src.dec_ndr_long(); + int _arrayi = _src.index; + _src.advance(4 * _arrays); + + if (array == null) { + if (_arrays < 0 || _arrays > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + array = new ShareInfo0[_arrays]; + } + _src = _src.derive(_arrayi); + for (int _i = 0; _i < _arrays; _i++) { + if (array[_i] == null) { + array[_i] = new ShareInfo0(); + } + array[_i].decode(_src); + } + } + } + } + public static class ShareInfo1 extends NdrObject { + + public String netname; + public int type; + public String remark; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_referent(netname, 1); + _dst.enc_ndr_long(type); + _dst.enc_ndr_referent(remark, 1); + + if (netname != null) { + _dst = _dst.deferred; + _dst.enc_ndr_string(netname); + + } + if (remark != null) { + _dst = _dst.deferred; + _dst.enc_ndr_string(remark); + + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + int _netnamep = _src.dec_ndr_long(); + type = (int)_src.dec_ndr_long(); + int _remarkp = _src.dec_ndr_long(); + + if (_netnamep != 0) { + _src = _src.deferred; + netname = _src.dec_ndr_string(); + + } + if (_remarkp != 0) { + _src = _src.deferred; + remark = _src.dec_ndr_string(); + + } + } + } + public static class ShareInfoCtr1 extends NdrObject { + + public int count; + public ShareInfo1[] array; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_long(count); + _dst.enc_ndr_referent(array, 1); + + if (array != null) { + _dst = _dst.deferred; + int _arrays = count; + _dst.enc_ndr_long(_arrays); + int _arrayi = _dst.index; + _dst.advance(12 * _arrays); + + _dst = _dst.derive(_arrayi); + for (int _i = 0; _i < _arrays; _i++) { + array[_i].encode(_dst); + } + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + count = (int)_src.dec_ndr_long(); + int _arrayp = _src.dec_ndr_long(); + + if (_arrayp != 0) { + _src = _src.deferred; + int _arrays = _src.dec_ndr_long(); + int _arrayi = _src.index; + _src.advance(12 * _arrays); + + if (array == null) { + if (_arrays < 0 || _arrays > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + array = new ShareInfo1[_arrays]; + } + _src = _src.derive(_arrayi); + for (int _i = 0; _i < _arrays; _i++) { + if (array[_i] == null) { + array[_i] = new ShareInfo1(); + } + array[_i].decode(_src); + } + } + } + } + public static class ShareEnumAll extends DcerpcMessage { + + public int getOpnum() { return 0x0f; } + + public int retval; + public String servername; + public int level; + public NdrObject info; + public int prefmaxlen; + public int totalentries; + public int resume_handle; + + public ShareEnumAll(String servername, + int level, + NdrObject info, + int prefmaxlen, + int totalentries, + int resume_handle) { + this.servername = servername; + this.level = level; + this.info = info; + this.prefmaxlen = prefmaxlen; + this.totalentries = totalentries; + this.resume_handle = resume_handle; + } + + public void encode_in(NdrBuffer _dst) throws NdrException { + _dst.enc_ndr_referent(servername, 1); + if (servername != null) { + _dst.enc_ndr_string(servername); + + } + _dst.enc_ndr_long(level); + int _descr = level; + _dst.enc_ndr_long(_descr); + _dst.enc_ndr_referent(info, 1); + if (info != null) { + _dst = _dst.deferred; + info.encode(_dst); + + } + _dst.enc_ndr_long(prefmaxlen); + _dst.enc_ndr_long(resume_handle); + } + public void decode_out(NdrBuffer _src) throws NdrException { + level = (int)_src.dec_ndr_long(); + _src.dec_ndr_long(); /* union discriminant */ + int _infop = _src.dec_ndr_long(); + if (_infop != 0) { + if (info == null) { /* YOYOYO */ + info = new ShareInfoCtr0(); + } + _src = _src.deferred; + info.decode(_src); + + } + totalentries = (int)_src.dec_ndr_long(); + resume_handle = (int)_src.dec_ndr_long(); + retval = (int)_src.dec_ndr_long(); + } + } + public static class ServerInfo100 extends NdrObject { + + public int platform_id; + public String name; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_long(platform_id); + _dst.enc_ndr_referent(name, 1); + + if (name != null) { + _dst = _dst.deferred; + _dst.enc_ndr_string(name); + + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + platform_id = (int)_src.dec_ndr_long(); + int _namep = _src.dec_ndr_long(); + + if (_namep != 0) { + _src = _src.deferred; + name = _src.dec_ndr_string(); + + } + } + } + public static class ServerGetInfo extends DcerpcMessage { + + public int getOpnum() { return 0x15; } + + public int retval; + public String servername; + public int level; + public NdrObject info; + + public ServerGetInfo(String servername, int level, NdrObject info) { + this.servername = servername; + this.level = level; + this.info = info; + } + + public void encode_in(NdrBuffer _dst) throws NdrException { + _dst.enc_ndr_referent(servername, 1); + if (servername != null) { + _dst.enc_ndr_string(servername); + + } + _dst.enc_ndr_long(level); + } + public void decode_out(NdrBuffer _src) throws NdrException { + _src.dec_ndr_long(); /* union discriminant */ + int _infop = _src.dec_ndr_long(); + if (_infop != 0) { + if (info == null) { /* YOYOYO */ + info = new ServerInfo100(); + } + _src = _src.deferred; + info.decode(_src); + + } + retval = (int)_src.dec_ndr_long(); + } + } + public static class TimeOfDayInfo extends NdrObject { + + public int elapsedt; + public int msecs; + public int hours; + public int mins; + public int secs; + public int hunds; + public int timezone; + public int tinterval; + public int day; + public int month; + public int year; + public int weekday; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_long(elapsedt); + _dst.enc_ndr_long(msecs); + _dst.enc_ndr_long(hours); + _dst.enc_ndr_long(mins); + _dst.enc_ndr_long(secs); + _dst.enc_ndr_long(hunds); + _dst.enc_ndr_long(timezone); + _dst.enc_ndr_long(tinterval); + _dst.enc_ndr_long(day); + _dst.enc_ndr_long(month); + _dst.enc_ndr_long(year); + _dst.enc_ndr_long(weekday); + + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + elapsedt = (int)_src.dec_ndr_long(); + msecs = (int)_src.dec_ndr_long(); + hours = (int)_src.dec_ndr_long(); + mins = (int)_src.dec_ndr_long(); + secs = (int)_src.dec_ndr_long(); + hunds = (int)_src.dec_ndr_long(); + timezone = (int)_src.dec_ndr_long(); + tinterval = (int)_src.dec_ndr_long(); + day = (int)_src.dec_ndr_long(); + month = (int)_src.dec_ndr_long(); + year = (int)_src.dec_ndr_long(); + weekday = (int)_src.dec_ndr_long(); + + } + } + public static class RemoteTOD extends DcerpcMessage { + + public int getOpnum() { return 0x1c; } + + public int retval; + public String servername; + public TimeOfDayInfo info; + + public RemoteTOD(String servername, TimeOfDayInfo info) { + this.servername = servername; + this.info = info; + } + + public void encode_in(NdrBuffer _dst) throws NdrException { + _dst.enc_ndr_referent(servername, 1); + if (servername != null) { + _dst.enc_ndr_string(servername); + + } + } + public void decode_out(NdrBuffer _src) throws NdrException { + int _infop = _src.dec_ndr_long(); + if (_infop != 0) { + if (info == null) { /* YOYOYO */ + info = new TimeOfDayInfo(); + } + info.decode(_src); + + } + retval = (int)_src.dec_ndr_long(); + } + } +} diff --git a/src/jcifs/dcerpc/ndr/NdrBuffer.java b/src/jcifs/dcerpc/ndr/NdrBuffer.java new file mode 100644 index 0000000..b08e1f4 --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrBuffer.java @@ -0,0 +1,228 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import jcifs.util.Encdec; + +public class NdrBuffer { + int referent; + HashMap referents; + + static class Entry { + int referent; + Object obj; + } + + public byte[] buf; + public int start; + public int index; + public int length; + public NdrBuffer deferred; + + public NdrBuffer(byte[] buf, int start) { + this.buf = buf; + this.start = index = start; + length = 0; + deferred = this; + } + + public NdrBuffer derive(int idx) { + NdrBuffer nb = new NdrBuffer(buf, start); + nb.index = idx; + nb.deferred = deferred; + return nb; + } + + + + public void reset() { + this.index = start; + length = 0; + deferred = this; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } + public int getCapacity() { + return buf.length - start; + } + public int getTailSpace() { + return buf.length - index; + } + public byte[] getBuffer() { + return buf; + } + public int align(int boundary, byte value) { + int n = align(boundary); + int i = n; + while (i > 0) { + buf[index - i] = value; + i--; + } + return n; + } + public void writeOctetArray(byte[] b, int i, int l) { + System.arraycopy(b, i, buf, index, l); + advance(l); + } + public void readOctetArray(byte[] b, int i, int l) { + System.arraycopy(buf, index, b, i, l); + advance(l); + } + + + public int getLength() { + return deferred.length; + } + public void advance(int n) { + index += n; + if ((index - start) > deferred.length) { + deferred.length = index - start; + } + } + public int align(int boundary) { + int m = boundary - 1; + int i = index - start; + int n = ((i + m) & ~m) - i; + advance(n); + return n; + } + public void enc_ndr_small(int s) { + buf[index] = (byte)(s & 0xFF); + advance(1); + } + public int dec_ndr_small() { + int val = buf[index] & 0xFF; + advance(1); + return val; + } + public void enc_ndr_short(int s) { + align(2); + Encdec.enc_uint16le((short)s, buf, index); + advance(2); + } + public int dec_ndr_short() { + align(2); + int val = Encdec.dec_uint16le(buf, index); + advance(2); + return val; + } + public void enc_ndr_long(int l) { + align(4); + Encdec.enc_uint32le(l, buf, index); + advance(4); + } + public int dec_ndr_long() { + align(4); + int val = Encdec.dec_uint32le(buf, index); + advance(4); + return val; + } + public void enc_ndr_hyper(long h) { + align(8); + Encdec.enc_uint64le(h, buf, index); + advance(8); + } + public long dec_ndr_hyper() { + align(8); + long val = Encdec.dec_uint64le(buf, index); + advance(8); + return val; + } + /* float */ + /* double */ + public void enc_ndr_string(String s) { + align(4); + int i = index; + int len = s.length(); + Encdec.enc_uint32le(len + 1, buf, i); i += 4; + Encdec.enc_uint32le(0, buf, i); i += 4; + Encdec.enc_uint32le(len + 1, buf, i); i += 4; + try { + System.arraycopy(s.getBytes("UnicodeLittleUnmarked"), 0, buf, i, len * 2); + } catch( UnsupportedEncodingException uee ) { + } + i += len * 2; + buf[i++] = (byte)'\0'; + buf[i++] = (byte)'\0'; + advance(i - index); + } + public String dec_ndr_string() throws NdrException { + align(4); + int i = index; + String val = null; + int len = Encdec.dec_uint32le(buf, i); + i += 12; + if (len != 0) { + len--; + int size = len * 2; + try { + if (size < 0 || size > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + val = new String(buf, i, size, "UnicodeLittleUnmarked"); + i += size + 2; + } catch( UnsupportedEncodingException uee ) { + } + } + advance(i - index); + return val; + } + private int getDceReferent(Object obj) { + Entry e; + + if (referents == null) { + referents = new HashMap(); + referent = 1; + } + + if ((e = (Entry)referents.get(obj)) == null) { + e = new Entry(); + e.referent = referent++; + e.obj = obj; + referents.put(obj, e); + } + + return e.referent; + } + public void enc_ndr_referent(Object obj, int type) { + if (obj == null) { + enc_ndr_long(0); + return; + } + switch (type) { + case 1: /* unique */ + case 3: /* ref */ + enc_ndr_long(System.identityHashCode(obj)); + return; + case 2: /* ptr */ + enc_ndr_long(getDceReferent(obj)); + return; + } + } + + public String toString() { + return "start=" + start + ",index=" + index + ",length=" + getLength(); + } +} + diff --git a/src/jcifs/dcerpc/ndr/NdrException.java b/src/jcifs/dcerpc/ndr/NdrException.java new file mode 100644 index 0000000..8be4410 --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrException.java @@ -0,0 +1,32 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +import java.io.IOException; + +public class NdrException extends IOException { + + public static final String NO_NULL_REF = "ref pointer cannot be null"; + public static final String INVALID_CONFORMANCE = "invalid array conformance"; + + public NdrException( String msg ) { + super( msg ); + } +} diff --git a/src/jcifs/dcerpc/ndr/NdrHyper.java b/src/jcifs/dcerpc/ndr/NdrHyper.java new file mode 100644 index 0000000..43c581c --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrHyper.java @@ -0,0 +1,37 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +public class NdrHyper extends NdrObject { + + public long value; + + public NdrHyper(long value) { + this.value = value; + } + + public void encode(NdrBuffer dst) throws NdrException { + dst.enc_ndr_hyper(value); + } + public void decode(NdrBuffer src) throws NdrException { + value = src.dec_ndr_hyper(); + } +} + diff --git a/src/jcifs/dcerpc/ndr/NdrLong.java b/src/jcifs/dcerpc/ndr/NdrLong.java new file mode 100644 index 0000000..0b929d1 --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrLong.java @@ -0,0 +1,37 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +public class NdrLong extends NdrObject { + + public int value; + + public NdrLong(int value) { + this.value = value; + } + + public void encode(NdrBuffer dst) throws NdrException { + dst.enc_ndr_long(value); + } + public void decode(NdrBuffer src) throws NdrException { + value = src.dec_ndr_long(); + } +} + diff --git a/src/jcifs/dcerpc/ndr/NdrObject.java b/src/jcifs/dcerpc/ndr/NdrObject.java new file mode 100644 index 0000000..b2c0372 --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrObject.java @@ -0,0 +1,27 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +public abstract class NdrObject { + + public abstract void encode(NdrBuffer dst) throws NdrException; + public abstract void decode(NdrBuffer src) throws NdrException; +} + diff --git a/src/jcifs/dcerpc/ndr/NdrShort.java b/src/jcifs/dcerpc/ndr/NdrShort.java new file mode 100644 index 0000000..e710232 --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrShort.java @@ -0,0 +1,37 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +public class NdrShort extends NdrObject { + + public int value; + + public NdrShort(int value) { + this.value = value & 0xFF; + } + + public void encode(NdrBuffer dst) throws NdrException { + dst.enc_ndr_short(value); + } + public void decode(NdrBuffer src) throws NdrException { + value = src.dec_ndr_short(); + } +} + diff --git a/src/jcifs/dcerpc/ndr/NdrSmall.java b/src/jcifs/dcerpc/ndr/NdrSmall.java new file mode 100644 index 0000000..42ede46 --- /dev/null +++ b/src/jcifs/dcerpc/ndr/NdrSmall.java @@ -0,0 +1,37 @@ +/* jcifs msrpc client library in Java + * Copyright (C) 2006 "Michael B. Allen" + * "Eric Glass" + * + * 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.ndr; + +public class NdrSmall extends NdrObject { + + public int value; + + public NdrSmall(int value) { + this.value = value & 0xFF; + } + + public void encode(NdrBuffer dst) throws NdrException { + dst.enc_ndr_small(value); + } + public void decode(NdrBuffer src) throws NdrException { + value = src.dec_ndr_small(); + } +} + diff --git a/src/jcifs/dcerpc/rpc.idl b/src/jcifs/dcerpc/rpc.idl new file mode 100644 index 0000000..02aff63 --- /dev/null +++ b/src/jcifs/dcerpc/rpc.idl @@ -0,0 +1,63 @@ +interface rpc +{ + /* base types */ + + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + + /* dce */ + + typedef struct { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; + } uuid_t; + + /* win32 stuff */ + + typedef struct { + uint32_t type; + uuid_t uuid; + } policy_handle; + + /* + * typedef struct _UNICODE_STRING + * USHORT Length; + * USHORT MaximumLength; + * [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer; + * } UNICODE_STRING; + */ + + typedef struct { + uint16_t length; + uint16_t maximum_length; + [length_is(length / 2),size_is(maximum_length / 2)] uint16_t *buffer; + } unicode_string; + + /* + * typedef struct _SID_IDENTIFIER_AUTHORITY { + * UCHAR Value[6]; + * } SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY; + * + * #define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} + * + * typedef struct _SID { + * UCHAR Revision; + * UCHAR SubAuthorityCount; + * SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + * [size_is(SubAuthorityCount)] ULONG SubAuthority[*]; + * } SID, *PSID; + */ + + typedef struct { + uint8_t revision; + uint8_t sub_authority_count; + uint8_t identifier_authority[6]; + [size_is(sub_authority_count)] uint32_t sub_authority[*]; + } sid_t; +} + diff --git a/src/jcifs/dcerpc/rpc.java b/src/jcifs/dcerpc/rpc.java new file mode 100644 index 0000000..cc2fc02 --- /dev/null +++ b/src/jcifs/dcerpc/rpc.java @@ -0,0 +1,212 @@ +package jcifs.dcerpc; + +import jcifs.dcerpc.ndr.*; +import jcifs.util.*; + +public class rpc { + + public static class uuid_t extends NdrObject { + + public int time_low; + public short time_mid; + public short time_hi_and_version; + public byte clock_seq_hi_and_reserved; + public byte clock_seq_low; + public byte[] node; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_long(time_low); + _dst.enc_ndr_short(time_mid); + _dst.enc_ndr_short(time_hi_and_version); + _dst.enc_ndr_small(clock_seq_hi_and_reserved); + _dst.enc_ndr_small(clock_seq_low); + int _nodes = 6; + int _nodei = _dst.index; + _dst.advance(1 * _nodes); + + _dst = _dst.derive(_nodei); + for (int _i = 0; _i < _nodes; _i++) { + _dst.enc_ndr_small(node[_i]); + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + time_low = (int)_src.dec_ndr_long(); + time_mid = (short)_src.dec_ndr_short(); + time_hi_and_version = (short)_src.dec_ndr_short(); + clock_seq_hi_and_reserved = (byte)_src.dec_ndr_small(); + clock_seq_low = (byte)_src.dec_ndr_small(); + int _nodes = 6; + int _nodei = _src.index; + _src.advance(1 * _nodes); + + if (node == null) { + if (_nodes < 0 || _nodes > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + node = new byte[_nodes]; + } + _src = _src.derive(_nodei); + for (int _i = 0; _i < _nodes; _i++) { + node[_i] = (byte)_src.dec_ndr_small(); + } + } + } + public static class policy_handle extends NdrObject { + + public int type; + public uuid_t uuid; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_long(type); + _dst.enc_ndr_long(uuid.time_low); + _dst.enc_ndr_short(uuid.time_mid); + _dst.enc_ndr_short(uuid.time_hi_and_version); + _dst.enc_ndr_small(uuid.clock_seq_hi_and_reserved); + _dst.enc_ndr_small(uuid.clock_seq_low); + int _uuid_nodes = 6; + int _uuid_nodei = _dst.index; + _dst.advance(1 * _uuid_nodes); + + _dst = _dst.derive(_uuid_nodei); + for (int _i = 0; _i < _uuid_nodes; _i++) { + _dst.enc_ndr_small(uuid.node[_i]); + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + type = (int)_src.dec_ndr_long(); + _src.align(4); + if (uuid == null) { + uuid = new uuid_t(); + } + uuid.time_low = (int)_src.dec_ndr_long(); + uuid.time_mid = (short)_src.dec_ndr_short(); + uuid.time_hi_and_version = (short)_src.dec_ndr_short(); + uuid.clock_seq_hi_and_reserved = (byte)_src.dec_ndr_small(); + uuid.clock_seq_low = (byte)_src.dec_ndr_small(); + int _uuid_nodes = 6; + int _uuid_nodei = _src.index; + _src.advance(1 * _uuid_nodes); + + if (uuid.node == null) { + if (_uuid_nodes < 0 || _uuid_nodes > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + uuid.node = new byte[_uuid_nodes]; + } + _src = _src.derive(_uuid_nodei); + for (int _i = 0; _i < _uuid_nodes; _i++) { + uuid.node[_i] = (byte)_src.dec_ndr_small(); + } + } + } + public static class unicode_string extends NdrObject { + + public short length; + public short maximum_length; + public short[] buffer; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + _dst.enc_ndr_short(length); + _dst.enc_ndr_short(maximum_length); + _dst.enc_ndr_referent(buffer, 1); + + if (buffer != null) { + _dst = _dst.deferred; + int _bufferl = length / 2; + int _buffers = maximum_length / 2; + _dst.enc_ndr_long(_buffers); + _dst.enc_ndr_long(0); + _dst.enc_ndr_long(_bufferl); + int _bufferi = _dst.index; + _dst.advance(2 * _bufferl); + + _dst = _dst.derive(_bufferi); + for (int _i = 0; _i < _bufferl; _i++) { + _dst.enc_ndr_short(buffer[_i]); + } + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + length = (short)_src.dec_ndr_short(); + maximum_length = (short)_src.dec_ndr_short(); + int _bufferp = _src.dec_ndr_long(); + + if (_bufferp != 0) { + _src = _src.deferred; + int _buffers = _src.dec_ndr_long(); + _src.dec_ndr_long(); + int _bufferl = _src.dec_ndr_long(); + int _bufferi = _src.index; + _src.advance(2 * _bufferl); + + if (buffer == null) { + if (_buffers < 0 || _buffers > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + buffer = new short[_buffers]; + } + _src = _src.derive(_bufferi); + for (int _i = 0; _i < _bufferl; _i++) { + buffer[_i] = (short)_src.dec_ndr_short(); + } + } + } + } + public static class sid_t extends NdrObject { + + public byte revision; + public byte sub_authority_count; + public byte[] identifier_authority; + public int[] sub_authority; + + public void encode(NdrBuffer _dst) throws NdrException { + _dst.align(4); + int _sub_authoritys = sub_authority_count; + _dst.enc_ndr_long(_sub_authoritys); + _dst.enc_ndr_small(revision); + _dst.enc_ndr_small(sub_authority_count); + int _identifier_authoritys = 6; + int _identifier_authorityi = _dst.index; + _dst.advance(1 * _identifier_authoritys); + int _sub_authorityi = _dst.index; + _dst.advance(4 * _sub_authoritys); + + _dst = _dst.derive(_identifier_authorityi); + for (int _i = 0; _i < _identifier_authoritys; _i++) { + _dst.enc_ndr_small(identifier_authority[_i]); + } + _dst = _dst.derive(_sub_authorityi); + for (int _i = 0; _i < _sub_authoritys; _i++) { + _dst.enc_ndr_long(sub_authority[_i]); + } + } + public void decode(NdrBuffer _src) throws NdrException { + _src.align(4); + int _sub_authoritys = _src.dec_ndr_long(); + revision = (byte)_src.dec_ndr_small(); + sub_authority_count = (byte)_src.dec_ndr_small(); + int _identifier_authoritys = 6; + int _identifier_authorityi = _src.index; + _src.advance(1 * _identifier_authoritys); + int _sub_authorityi = _src.index; + _src.advance(4 * _sub_authoritys); + + if (identifier_authority == null) { + if (_identifier_authoritys < 0 || _identifier_authoritys > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + identifier_authority = new byte[_identifier_authoritys]; + } + _src = _src.derive(_identifier_authorityi); + for (int _i = 0; _i < _identifier_authoritys; _i++) { + identifier_authority[_i] = (byte)_src.dec_ndr_small(); + } + if (sub_authority == null) { + if (_sub_authoritys < 0 || _sub_authoritys > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE ); + sub_authority = new int[_sub_authoritys]; + } + _src = _src.derive(_sub_authorityi); + for (int _i = 0; _i < _sub_authoritys; _i++) { + sub_authority[_i] = (int)_src.dec_ndr_long(); + } + } + } +} diff --git a/src/jcifs/netbios/NameServiceClient.java b/src/jcifs/netbios/NameServiceClient.java index 9bd690d..dbc72f9 100644 --- a/src/jcifs/netbios/NameServiceClient.java +++ b/src/jcifs/netbios/NameServiceClient.java @@ -18,10 +18,7 @@ package jcifs.netbios; -import java.net.InetAddress; -import java.net.DatagramSocket; -import java.net.DatagramPacket; -import java.net.UnknownHostException; +import java.net.*; import java.io.IOException; import java.io.InterruptedIOException; import java.util.HashMap; @@ -203,19 +200,21 @@ class NameServiceClient implements Runnable { response.notify(); } } + } catch(SocketTimeoutException ste) { } catch( Exception ex ) { if( log.level > 2 ) ex.printStackTrace( log ); + } finally { tryClose(); } } void send( NameServicePacket request, NameServicePacket response, int timeout ) throws IOException { Integer nid = null; - int count = 0; + int max = NbtAddress.NBNS.length; synchronized( response ) { - do { + while (max-- > 0) { try { synchronized( LOCK ) { request.nameTrnId = getNextNameTrnId(); @@ -237,24 +236,25 @@ class NameServiceClient implements Runnable { response.wait( timeout ); + if (response.received) + return; + } catch( InterruptedException ie ) { } finally { responseTable.remove( nid ); } - if( !response.received && - NbtAddress.NBNS.length > 1 && - NbtAddress.isWINS( request.addr )) { + if (NbtAddress.isWINS( request.addr ) == false) + break; + /* Message was sent to WINS but * failed to receive response. * Try a different WINS server. */ - request.addr = NbtAddress.switchWINS(); - if( count == 0 ) { - count = NbtAddress.NBNS.length - 1; - } - } - } while( count-- > 0 ); + if (request.addr == NbtAddress.getWINSAddress()) + NbtAddress.switchWINS(); + request.addr = NbtAddress.getWINSAddress(); + } } } diff --git a/src/jcifs/smb/FileEntry.java b/src/jcifs/smb/FileEntry.java index a659707..489e6a7 100644 --- a/src/jcifs/smb/FileEntry.java +++ b/src/jcifs/smb/FileEntry.java @@ -1,6 +1,6 @@ package jcifs.smb; -interface FileEntry { +public interface FileEntry { String getName(); int getType(); diff --git a/src/jcifs/smb/NetServerEnum2Response.java b/src/jcifs/smb/NetServerEnum2Response.java index b0c1378..637db55 100644 --- a/src/jcifs/smb/NetServerEnum2Response.java +++ b/src/jcifs/smb/NetServerEnum2Response.java @@ -113,7 +113,7 @@ class NetServerEnum2Response extends SmbComTransactionResponse { off = start + off; e.commentOrMasterBrowser = readString( buffer, off, 48, false ); - if( log.level > 3 ) + if( log.level >= 4 ) log.println( e ); } lastName = numEntries == 0 ? null : e.name; diff --git a/src/jcifs/smb/NetShareEnumResponse.java b/src/jcifs/smb/NetShareEnumResponse.java index b8514eb..23c5ed4 100644 --- a/src/jcifs/smb/NetShareEnumResponse.java +++ b/src/jcifs/smb/NetShareEnumResponse.java @@ -112,7 +112,7 @@ class NetShareEnumResponse extends SmbComTransactionResponse { off = start + off; e.remark = readString( buffer, off, 128, false ); - if( log.level > 2 ) + if (log.level >= 4) log.println( e ); } diff --git a/src/jcifs/smb/NtlmPasswordAuthentication.java b/src/jcifs/smb/NtlmPasswordAuthentication.java index 72b1fc9..e550fe0 100644 --- a/src/jcifs/smb/NtlmPasswordAuthentication.java +++ b/src/jcifs/smb/NtlmPasswordAuthentication.java @@ -89,7 +89,7 @@ public final class NtlmPasswordAuthentication implements Principal, Serializable try { passwordBytes = password.toUpperCase().getBytes( ServerMessageBlock.OEM_ENCODING ); } catch( UnsupportedEncodingException uee ) { - return null; + throw new RuntimeException("Try setting jcifs.encoding=US-ASCII", uee); } int passwordLength = passwordBytes.length; diff --git a/src/jcifs/smb/ServerMessageBlock.java b/src/jcifs/smb/ServerMessageBlock.java index d90ce5c..83e6550 100644 --- a/src/jcifs/smb/ServerMessageBlock.java +++ b/src/jcifs/smb/ServerMessageBlock.java @@ -248,7 +248,7 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); throw new RuntimeException( "zero termination not found" ); } } - str = new String( src, srcIndex, len, "UnicodeLittle" ); + str = new String( src, srcIndex, len, "UnicodeLittleUnmarked" ); } else { while( src[srcIndex + len] != (byte)0x00 ) { len++; @@ -313,7 +313,7 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); if( wordCount != 0 ) { int n; if(( n = readParameterWordsWireFormat( buffer, bufferIndex )) != wordCount * 2 ) { - if( log.level > 2 ) { + if( log.level >= 5 ) { log.println( "wordCount * 2=" + ( wordCount * 2 ) + " but readParameterWordsWireFormat returned " + n ); } @@ -327,7 +327,7 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); if( byteCount != 0 ) { int n; if(( n = readBytesWireFormat( buffer, bufferIndex )) != byteCount ) { - if( log.level > 2 ) { + if( log.level >= 5 ) { log.println( "byteCount=" + byteCount + " but readBytesWireFormat returned " + n ); } diff --git a/src/jcifs/smb/SigningDigest.java b/src/jcifs/smb/SigningDigest.java index 12c47dc..1fdee9b 100644 --- a/src/jcifs/smb/SigningDigest.java +++ b/src/jcifs/smb/SigningDigest.java @@ -58,14 +58,14 @@ public class SigningDigest { } catch( Exception ex ) { throw new SmbException( "", ex ); } - if( log.level > 3 ) { + if( log.level >= 4 ) { log.println( "LM_COMPATIBILITY=" + LM_COMPATIBILITY ); Hexdump.hexdump( log, macSigningKey, 0, macSigningKey.length ); } } public void update( byte[] input, int offset, int len ) { - if( log.level > 3 ) { + if( log.level >= 4 ) { log.println( "update: " + updates + " " + offset + ":" + len ); Hexdump.hexdump( log, input, offset, Math.min( len, 256 )); log.flush(); @@ -81,7 +81,7 @@ public class SigningDigest { b = digest.digest(); - if( log.level > 3 ) { + if( log.level >= 4 ) { log.println( "digest: " ); Hexdump.hexdump( log, b, 0, b.length ); log.flush(); @@ -154,7 +154,7 @@ public class SigningDigest { byte[] signature = digest(); for (int i = 0; i < 8; i++) { if (signature[i] != data[offset + ServerMessageBlock.SIGNATURE_OFFSET + i]) { - if( log.level > 2 ) { + if( log.level >= 2 ) { log.println( "signature verification failure" ); Hexdump.hexdump( log, signature, 0, 8 ); Hexdump.hexdump( log, data, diff --git a/src/jcifs/smb/SmbComNegotiateResponse.java b/src/jcifs/smb/SmbComNegotiateResponse.java index e78ba24..d846e60 100644 --- a/src/jcifs/smb/SmbComNegotiateResponse.java +++ b/src/jcifs/smb/SmbComNegotiateResponse.java @@ -82,7 +82,7 @@ class SmbComNegotiateResponse extends ServerMessageBlock { } } server.oemDomainName = new String( buffer, bufferIndex, - len, "UnicodeLittle" ); + len, "UnicodeLittleUnmarked" ); } else { while( buffer[bufferIndex + len] != (byte)0x00 ) { len++; diff --git a/src/jcifs/smb/SmbComNtTransactionResponse.java b/src/jcifs/smb/SmbComNtTransactionResponse.java index 2238456..15bfa96 100644 --- a/src/jcifs/smb/SmbComNtTransactionResponse.java +++ b/src/jcifs/smb/SmbComNtTransactionResponse.java @@ -53,7 +53,7 @@ abstract class SmbComNtTransactionResponse extends SmbComTransactionResponse { setupCount = buffer[bufferIndex] & 0xFF; bufferIndex += 2; if( setupCount != 0 ) { - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "setupCount is not zero: " + setupCount ); } diff --git a/src/jcifs/smb/SmbConstants.java b/src/jcifs/smb/SmbConstants.java index 1dde3f0..80a816e 100644 --- a/src/jcifs/smb/SmbConstants.java +++ b/src/jcifs/smb/SmbConstants.java @@ -124,7 +124,7 @@ interface SmbConstants { static final TimeZone TZ = TimeZone.getDefault(); static final boolean USE_BATCHING = Config.getBoolean( "jcifs.smb.client.useBatching", true ); - static final String OEM_ENCODING = Config.getProperty( "jcifs.encoding", "Cp850" ); + static final String OEM_ENCODING = Config.getProperty( "jcifs.encoding", Config.DEFAULT_OEM_ENCODING ); static final int DEFAULT_FLAGS2 = FLAGS2_LONG_FILENAMES | FLAGS2_EXTENDED_ATTRIBUTES | diff --git a/src/jcifs/smb/SmbFile.java b/src/jcifs/smb/SmbFile.java index 161abfb..54fbf9d 100644 --- a/src/jcifs/smb/SmbFile.java +++ b/src/jcifs/smb/SmbFile.java @@ -31,6 +31,8 @@ import jcifs.Config; import jcifs.util.LogStream; import jcifs.UniAddress; import jcifs.netbios.NbtAddress; +import jcifs.dcerpc.*; +import jcifs.dcerpc.msrpc.MsrpcShareEnum; import java.util.Date; @@ -270,6 +272,14 @@ public class SmbFile extends URLConnection implements SmbConstants { static final int O_RDWR = 0x03; static final int O_APPEND = 0x04; + // Open Function Encoding + // create if the file does not exist + static final int O_CREAT = 0x0010; + // fail if the file exists + static final int O_EXCL = 0x0020; + // truncate if the file exists + static final int O_TRUNC = 0x0040; + // share access /** * When specified as the shareAccess constructor parameter, @@ -300,14 +310,6 @@ public class SmbFile extends URLConnection implements SmbConstants { */ public static final int FILE_SHARE_DELETE = 0x04; - // Open Function Encoding - // create if the file does not exist - static final int O_CREAT = 0x0010; - // fail if the file exists - static final int O_EXCL = 0x0001; - // truncate if the file exists - static final int O_TRUNC = 0x0002; - // file attribute encoding /** * A file with this bit on as returned by getAttributes() or set @@ -357,6 +359,7 @@ public class SmbFile extends URLConnection implements SmbConstants { static long attrExpirationPeriod; static { + try { Class.forName( "jcifs.Config" ); } catch( ClassNotFoundException cnfe ) { @@ -673,8 +676,8 @@ public class SmbFile extends URLConnection implements SmbConstants { trans = SmbTransport.getSmbTransport( addr, url.getPort() ); tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null ); - if (log.level > 2) - System.out.println( dr ); + if (log.level >= 3) + log.println( dr ); dfsReferral = dr; request.path = getDfsUncPath0(); @@ -815,7 +818,7 @@ public class SmbFile extends URLConnection implements SmbConstants { connect0(); - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "open0: " + unc ); /* @@ -851,7 +854,7 @@ public class SmbFile extends URLConnection implements SmbConstants { } void close( int f, long lastWriteTime ) throws SmbException { - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "close: " + f ); /* @@ -1170,7 +1173,7 @@ public class SmbFile extends URLConnection implements SmbConstants { path = dfsReferral.nodepath + path.substring( dfsReferral.path.length() ); } - if( log.level > 2 ) + if (log.level >= 3) log.println( "queryPath: " + path ); /* normally we'd check the negotiatedCapabilities for CAP_NT_SMBS @@ -1555,8 +1558,20 @@ public class SmbFile extends URLConnection implements SmbConstants { ArrayList list = new ArrayList(); try { - if( url.getHost().length() == 0 || share == null ) { - doNetEnum( list, false, wildcard, searchAttributes, fnf, ff ); + int hostlen = url.getHost().length(); + if( hostlen == 0 || share == null ) { + boolean done = false; + if (hostlen != 0 && getType() == TYPE_SERVER) { + try { + doMsrpcEnum(list, false, wildcard, searchAttributes, fnf, ff); + done = true; + } catch(IOException ioe) { + if (log.level >= 3) + ioe.printStackTrace(log); + } + } + if (!done) + doNetEnum( list, false, wildcard, searchAttributes, fnf, ff ); } else { doFindFirstNext( list, false, wildcard, searchAttributes, fnf, ff ); } @@ -1581,8 +1596,20 @@ public class SmbFile extends URLConnection implements SmbConstants { } try { - if( url.getHost().length() == 0 || share == null ) { - doNetEnum( list, true, wildcard, searchAttributes, fnf, ff ); + int hostlen = url.getHost().length(); + if( hostlen == 0 || share == null ) { + boolean done = false; + if (hostlen != 0 && getType() == TYPE_SERVER) { + try { + doMsrpcEnum(list, true, wildcard, searchAttributes, fnf, ff); + done = true; + } catch(IOException ioe) { + if (log.level >= 3) + ioe.printStackTrace(log); + } + } + if (!done) + doNetEnum( list, true, wildcard, searchAttributes, fnf, ff ); } else { doFindFirstNext( list, true, wildcard, searchAttributes, fnf, ff ); } @@ -1594,6 +1621,63 @@ public class SmbFile extends URLConnection implements SmbConstants { return (SmbFile[])list.toArray(new SmbFile[list.size()]); } + void doMsrpcEnum( ArrayList list, + boolean files, + String wildcard, + int searchAttributes, + SmbFilenameFilter fnf, + SmbFileFilter ff ) throws IOException, + UnknownHostException, + MalformedURLException { + String p = url.getPath(); + MsrpcShareEnum rpc; + DcerpcHandle handle; + + if( p.lastIndexOf( '/' ) != ( p.length() - 1 )) { + throw new SmbException( url.toString() + " directory must end with '/'" ); + } + if (getType() != TYPE_SERVER) + throw new SmbException( "The requested list operations is invalid: " + url.toString() ); + + rpc = new MsrpcShareEnum(url.getHost()); + handle = DcerpcHandle.getHandle("ncacn_np:" + url.getHost() + "[\\PIPE\\srvsvc]", auth); + + try { + boolean more = false; + do { + handle.sendrecv(rpc); + + FileEntry[] entries = rpc.getEntries(); + for( int i = 0; i < entries.length; i++ ) { + FileEntry e = entries[i]; + String name = e.getName(); + if( fnf != null && fnf.accept( this, name ) == false ) { + continue; + } + if( name.length() > 0 ) { + SmbFile f = new SmbFile( this, name, + e.getType(), + ATTR_READONLY | ATTR_DIRECTORY, 0L, 0L, 0L ); + if( ff != null && ff.accept( f ) == false ) { + continue; + } + if( files ) { + list.add( f ); + } else { + list.add( name ); + } + } + } + } while(more); + } finally { + try { + handle.close(); + } catch(IOException ioe) { + if (log.level >= 4) + ioe.printStackTrace(log); + } + } + } void doNetEnum( ArrayList list, boolean files, String wildcard, @@ -1690,7 +1774,7 @@ public class SmbFile extends URLConnection implements SmbConstants { req = new Trans2FindFirst2( path, wildcard, searchAttributes ); resp = new Trans2FindFirst2Response(); - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "doFindFirstNext: " + req.path ); send( req, resp ); @@ -1774,11 +1858,11 @@ public class SmbFile extends URLConnection implements SmbConstants { exists(); dest.exists(); } - if( tree != dest.tree ) { + if (!tree.equals(dest.tree)) { throw new SmbException( "Invalid operation for workgroups, servers, or shares" ); } - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "renameTo: " + unc + " -> " + dest.unc ); attrExpiration = sizeExpiration = 0; @@ -1913,61 +1997,62 @@ public class SmbFile extends URLConnection implements SmbConstants { } else { int off; -try { - open( SmbFile.O_RDONLY, 0, ATTR_NORMAL, 0 ); try { - dest.open( SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC, - FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, - attributes, 0 ); - } catch( SmbAuthException sae ) { - if(( dest.attributes & ATTR_READONLY ) != 0 ) { - /* Remove READONLY and try again - */ - dest.setPathInformation( dest.attributes & ~ATTR_READONLY, 0L, 0L ); + open( SmbFile.O_RDONLY, 0, ATTR_NORMAL, 0 ); + try { dest.open( SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC, FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, attributes, 0 ); - } else { - throw sae; + } catch( SmbAuthException sae ) { + if(( dest.attributes & ATTR_READONLY ) != 0 ) { + /* Remove READONLY and try again + */ + dest.setPathInformation( dest.attributes & ~ATTR_READONLY, 0L, 0L ); + dest.open( SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC, + FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, + attributes, 0 ); + } else { + throw sae; + } } - } - - i = off = 0; - for( ;; ) { - req.setParam( fid, off, bsize ); - resp.setParam( b[i], 0 ); - send( req, resp ); - - synchronized( w ) { - while( !w.ready ) { - try { - w.wait(); - } catch( InterruptedException ie ) { - throw new SmbException( dest.url.toString(), ie ); + + i = off = 0; + for( ;; ) { + req.setParam( fid, off, bsize ); + resp.setParam( b[i], 0 ); + send( req, resp ); + + synchronized( w ) { + while( !w.ready ) { + try { + w.wait(); + } catch( InterruptedException ie ) { + throw new SmbException( dest.url.toString(), ie ); + } } + if( w.e != null ) { + throw w.e; + } + if( resp.dataLength <= 0 ) { + break; + } + w.write( b[i], resp.dataLength, dest, off ); } - if( w.e != null ) { - throw w.e; - } - if( resp.dataLength <= 0 ) { - break; - } - w.write( b[i], resp.dataLength, dest, off ); + + i = i == 1 ? 0 : 1; + off += resp.dataLength; } - - i = i == 1 ? 0 : 1; - off += resp.dataLength; + + dest.send( new Trans2SetFileInformation( + dest.fid, attributes, createTime, lastModified ), + new Trans2SetFileInformationResponse() ); + dest.close( 0L ); + } catch( Exception ex ) { + if( log.level > 1 ) + ex.printStackTrace( log ); + } finally { + close(); } - - dest.send( new Trans2SetFileInformation( - dest.fid, attributes, createTime, lastModified ), - new Trans2SetFileInformationResponse() ); - dest.close( 0L ); - close(); -} catch( Exception ex ) { - if( log.level > 1 ) - ex.printStackTrace( log ); -} } } /** @@ -2051,8 +2136,11 @@ try { bsize = Math.min( t1.rcv_buf_size - 70, t1.snd_buf_size - 70 ); b = new byte[2][bsize]; - copyTo0( dest, b, bsize, w, req, resp ); - w.write( null, -1, null, 0 ); + try { + copyTo0( dest, b, bsize, w, req, resp ); + } finally { + w.write( null, -1, null, 0 ); + } } /** @@ -2101,7 +2189,7 @@ try { * Delete or Delete Directory Request / Response */ - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "delete: " + fileName ); if(( attributes & ATTR_DIRECTORY ) != 0 ) { @@ -2231,7 +2319,7 @@ try { * Create Directory Request / Response */ - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "mkdir: " + path ); send( new SmbComCreateDirectory( path ), blank_resp() ); diff --git a/src/jcifs/smb/SmbFileInputStream.java b/src/jcifs/smb/SmbFileInputStream.java index eb9dfc7..0e06adf 100644 --- a/src/jcifs/smb/SmbFileInputStream.java +++ b/src/jcifs/smb/SmbFileInputStream.java @@ -31,7 +31,7 @@ import java.io.IOException; public class SmbFileInputStream extends InputStream { private long fp; - private int readSize, openFlags; + private int readSize, openFlags, access; private byte[] tmp = new byte[1]; SmbFile file; @@ -64,9 +64,10 @@ public class SmbFileInputStream extends InputStream { SmbFileInputStream( SmbFile file, int openFlags ) throws SmbException, MalformedURLException, UnknownHostException { this.file = file; - this.openFlags = openFlags; + this.openFlags = openFlags & 0xFFFF; + this.access = (openFlags >>> 16) & 0xFFFF; if (file.type != SmbFile.TYPE_NAMED_PIPE) { - file.open( openFlags, 0, SmbFile.ATTR_NORMAL, 0 ); + file.open( openFlags, access, SmbFile.ATTR_NORMAL, 0 ); this.openFlags &= ~(SmbFile.O_CREAT | SmbFile.O_TRUNC); } else { file.connect0(); @@ -117,6 +118,9 @@ public class SmbFileInputStream extends InputStream { */ public int read( byte[] b, int off, int len ) throws IOException { + return readDirect(b, off, len); + } + public int readDirect( byte[] b, int off, int len ) throws IOException { if( len <= 0 ) { return 0; } @@ -126,13 +130,13 @@ public class SmbFileInputStream extends InputStream { throw new IOException( "Bad file descriptor" ); } // ensure file is open - file.open( openFlags, 0, SmbFile.ATTR_NORMAL, 0 ); + file.open( openFlags, access, SmbFile.ATTR_NORMAL, 0 ); /* * Read AndX Request / Response */ - if( file.log.level > 2 ) + if( file.log.level >= 4 ) file.log.println( "read: fid=" + file.fid + ",off=" + off + ",len=" + len ); SmbComReadAndXResponse response = new SmbComReadAndXResponse( b, off ); @@ -145,7 +149,7 @@ public class SmbFileInputStream extends InputStream { do { r = len > readSize ? readSize : len; - if( file.log.level > 2 ) + if( file.log.level >= 4 ) file.log.println( "read: len=" + len + ",r=" + r + ",fp=" + fp ); try { diff --git a/src/jcifs/smb/SmbFileOutputStream.java b/src/jcifs/smb/SmbFileOutputStream.java index b15385e..cfe9934 100644 --- a/src/jcifs/smb/SmbFileOutputStream.java +++ b/src/jcifs/smb/SmbFileOutputStream.java @@ -33,7 +33,7 @@ public class SmbFileOutputStream extends OutputStream { private SmbFile file; private boolean append, useNTSmbs; - private int openFlags, writeSize; + private int openFlags, access, writeSize; private long fp; private byte[] tmp = new byte[1]; private SmbComWriteAndX reqx; @@ -124,9 +124,12 @@ write, and/or delete the file while the jCIFS user has the file open. this.file = file; this.append = append; this.openFlags = openFlags; + this.access = (openFlags >>> 16) & 0xFFFF; if( append ) { try { fp = file.length(); + } catch( SmbAuthException sae ) { + throw sae; } catch( SmbException se ) { fp = 0L; } @@ -136,7 +139,7 @@ write, and/or delete the file while the jCIFS user has the file open. file.send( new TransWaitNamedPipe( "\\pipe" + file.unc ), new TransWaitNamedPipeResponse() ); } - file.open( openFlags, SmbConstants.FILE_WRITE_DATA, SmbFile.ATTR_NORMAL, 0 ); + file.open( openFlags, access | SmbConstants.FILE_WRITE_DATA, SmbFile.ATTR_NORMAL, 0 ); this.openFlags &= ~(SmbFile.O_CREAT | SmbFile.O_TRUNC); /* in case close and reopen */ writeSize = file.tree.session.transport.snd_buf_size - 70; @@ -206,13 +209,13 @@ write, and/or delete the file while the jCIFS user has the file open. file.send( new TransWaitNamedPipe( "\\pipe" + file.unc ), new TransWaitNamedPipeResponse() ); } - file.open( openFlags, SmbConstants.FILE_WRITE_DATA, SmbFile.ATTR_NORMAL, 0 ); + file.open( openFlags, access | SmbConstants.FILE_WRITE_DATA, SmbFile.ATTR_NORMAL, 0 ); if( append ) { fp = file.length(); } } - if( file.log.level > 2 ) + if( file.log.level >= 4 ) file.log.println( "write: fid=" + file.fid + ",off=" + off + ",len=" + len ); int w; @@ -234,3 +237,4 @@ write, and/or delete the file while the jCIFS user has the file open. } while( len > 0 ); } } + diff --git a/src/jcifs/smb/SmbNamedPipe.java b/src/jcifs/smb/SmbNamedPipe.java index 5de24a6..8b0363a 100644 --- a/src/jcifs/smb/SmbNamedPipe.java +++ b/src/jcifs/smb/SmbNamedPipe.java @@ -108,15 +108,15 @@ public class SmbNamedPipe extends SmbFile { * Pipe operations should behave like the CallNamedPipe Win32 Named Pipe function. */ - public static final int PIPE_TYPE_CALL = 0x01; + public static final int PIPE_TYPE_CALL = 0x0100; /** * Pipe operations should behave like the TransactNamedPipe Win32 Named Pipe function. */ - public static final int PIPE_TYPE_TRANSACT = 0x02; + public static final int PIPE_TYPE_TRANSACT = 0x0200; - public static final int PIPE_TYPE_DCE_TRANSACT = 0x02 | 0x04; + public static final int PIPE_TYPE_DCE_TRANSACT = 0x0200 | 0x0400; InputStream pipeIn; OutputStream pipeOut; @@ -165,8 +165,8 @@ public class SmbNamedPipe extends SmbFile { ( pipeType & PIPE_TYPE_TRANSACT ) == PIPE_TYPE_TRANSACT ) { pipeIn = new TransactNamedPipeInputStream( this ); } else { - pipeIn = new SmbFileInputStream( this, - ( pipeType & 0xFF0000 ) | SmbFile.O_EXCL ); + pipeIn = new SmbFileInputStream(this, + (pipeType & 0xFFFF00FF) | SmbFile.O_EXCL); } } return pipeIn; @@ -186,8 +186,8 @@ public class SmbNamedPipe extends SmbFile { ( pipeType & PIPE_TYPE_TRANSACT ) == PIPE_TYPE_TRANSACT ) { pipeOut = new TransactNamedPipeOutputStream( this ); } else { - pipeOut = new SmbFileOutputStream( this, false, - ( pipeType & 0xFF0000 ) | SmbFile.O_EXCL ); + pipeOut = new SmbFileOutputStream(this, false, + (pipeType & 0xFFFF00FF) | SmbFile.O_EXCL ); } } return pipeOut; diff --git a/src/jcifs/smb/SmbSession.java b/src/jcifs/smb/SmbSession.java index 581363a..1dca19a 100644 --- a/src/jcifs/smb/SmbSession.java +++ b/src/jcifs/smb/SmbSession.java @@ -72,7 +72,7 @@ public final class SmbSession { SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 ); if (USERNAME == null) { trans.connect(); - if (SmbTransport.log.level > 2) + if (SmbTransport.log.level >= 3) SmbTransport.log.println( "Default credentials (jcifs.smb.client.username/password)" + " not specified. SMB signing may not work propertly." + @@ -90,6 +90,9 @@ public final class SmbSession { } synchronized (DOMAIN) { long now = System.currentTimeMillis(); +int retry = 1; + +do { if (dc_list_expiration < now) { dc_list_expiration = now + CACHE_POLICY * 1000L; NbtAddress[] list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null ); @@ -97,7 +100,7 @@ public final class SmbSession { dc_list = list; } else { /* keep using the old list */ dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */ - if (SmbTransport.log.level > 1) { + if (SmbTransport.log.level >= 2) { SmbTransport.log.println( "Failed to retrieve DC list from WINS" ); } } @@ -110,7 +113,7 @@ public final class SmbSession { try { return interrogate( dc_list[i] ); } catch (SmbException se) { - if (SmbTransport.log.level > 1) { + if (SmbTransport.log.level >= 2) { SmbTransport.log.println( "Failed validate DC: " + dc_list[i] ); if (SmbTransport.log.level > 2) se.printStackTrace( SmbTransport.log ); @@ -120,6 +123,11 @@ public final class SmbSession { } } +/* No DCs found, for retieval of list by expiring it and retry. + */ + dc_list_expiration = 0; +} while (retry-- > 0); + dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */ } @@ -245,7 +253,7 @@ synchronized( transport() ) { * Session Setup And X Request / Response */ - if( transport.log.level > 3 ) + if( transport.log.level >= 4 ) transport.log.println( "sessionSetup: accountName=" + auth.username + ",primaryDomain=" + auth.domain ); SmbComSessionSetupAndX request = new SmbComSessionSetupAndX( this, andx ); diff --git a/src/jcifs/smb/SmbTransport.java b/src/jcifs/smb/SmbTransport.java index 71dfea7..88206de 100644 --- a/src/jcifs/smb/SmbTransport.java +++ b/src/jcifs/smb/SmbTransport.java @@ -187,11 +187,12 @@ public class SmbTransport extends Transport implements SmbConstants { NbtAddress.getLocalName() ); out.write( sbuf, 0, ssp.writeWireFormat( sbuf, 0 )); if (readn( in, sbuf, 0, 4 ) < 4) { + try { socket.close(); } catch(IOException ioe) {}; throw new SmbException( "EOF during NetBIOS session request" ); } switch( sbuf[0] & 0xFF ) { case SessionServicePacket.POSITIVE_SESSION_RESPONSE: - if( log.level > 2 ) + if( log.level >= 4 ) log.println( "session established ok with " + address ); return; case SessionServicePacket.NEGATIVE_SESSION_RESPONSE: @@ -252,9 +253,9 @@ public class SmbTransport extends Transport implements SmbConstants { int n = NEGOTIATE_REQUEST.encode( sbuf, 4 ); Encdec.enc_uint32be( n & 0xFFFF, sbuf, 0 ); /* 4 byte ssn msg header */ - if (log.level > 3) { + if (log.level >= 4) { log.println( NEGOTIATE_REQUEST ); - if (log.level > 5) { + if (log.level >= 6) { Hexdump.hexdump( log, sbuf, 4, n ); } } @@ -273,9 +274,9 @@ public class SmbTransport extends Transport implements SmbConstants { readn( in, sbuf, 4 + 32, size - 32 ); resp.decode( sbuf, 4 ); - if (log.level > 3) { + if (log.level >= 4) { log.println( resp ); - if (log.level > 5) { + if (log.level >= 6) { Hexdump.hexdump( log, sbuf, 4, n ); } } @@ -354,7 +355,7 @@ public class SmbTransport extends Transport implements SmbConstants { /* read smb header */ if ((n = readn( in, sbuf, 4, 32 )) < 32) return null; - if (log.level > 2) { + if (log.level >= 4) { log.println( "New data read: " + this ); jcifs.util.Hexdump.hexdump( log, sbuf, 4, 32 ); } @@ -401,12 +402,12 @@ public class SmbTransport extends Transport implements SmbConstants { ServerMessageBlock smb = (ServerMessageBlock)request; int n = smb.encode( BUF, 4 ); Encdec.enc_uint32be( n & 0xFFFF, BUF, 0 ); /* 4 byte session message header */ - if (log.level > 3) { + if (log.level >= 4) { do { log.println( smb ); } while (smb instanceof AndXServerMessageBlock && (smb = ((AndXServerMessageBlock)smb).andx) != null); - if (log.level > 5) { + if (log.level >= 6) { Hexdump.hexdump( log, BUF, 4, n ); } } @@ -464,9 +465,9 @@ public class SmbTransport extends Transport implements SmbConstants { digest.verify( BUF, 4, resp ); } - if (log.level > 3) { + if (log.level >= 4) { log.println( response ); - if (log.level > 5) { + if (log.level >= 6) { Hexdump.hexdump( log, BUF, 4, size ); } } diff --git a/src/jcifs/smb/SmbTree.java b/src/jcifs/smb/SmbTree.java index a39670a..131a557 100644 --- a/src/jcifs/smb/SmbTree.java +++ b/src/jcifs/smb/SmbTree.java @@ -49,6 +49,13 @@ class SmbTree { ( service == null || service.startsWith( "??" ) || this.service.equalsIgnoreCase( service )); } + public boolean equals(Object obj) { + if (obj instanceof SmbTree) { + SmbTree tree = (SmbTree)obj; + return matches(tree.share, tree.service); + } + return false; + } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { if( response != null ) { @@ -137,7 +144,7 @@ synchronized(transport) { * Tree Connect And X Request / Response */ - if( session.transport.log.level > 2 ) + if( session.transport.log.level >= 4 ) session.transport.log.println( "treeConnect: unc=" + unc + ",service=" + service ); SmbComTreeConnectAndXResponse response = diff --git a/src/jcifs/smb/Trans2FindFirst2Response.java b/src/jcifs/smb/Trans2FindFirst2Response.java index a9e7ce4..588a0e2 100644 --- a/src/jcifs/smb/Trans2FindFirst2Response.java +++ b/src/jcifs/smb/Trans2FindFirst2Response.java @@ -105,7 +105,7 @@ class Trans2FindFirst2Response extends SmbComTransactionResponse { try { if( useUnicode ) { // should Unicode alignment be corrected for here? - str = new String( src, srcIndex, len, "UnicodeLittle" ); + str = new String( src, srcIndex, len, "UnicodeLittleUnmarked" ); } else { /* On NT without Unicode the fileNameLength diff --git a/src/jcifs/smb/TransCallNamedPipe.java b/src/jcifs/smb/TransCallNamedPipe.java index 6a838e1..73b7348 100644 --- a/src/jcifs/smb/TransCallNamedPipe.java +++ b/src/jcifs/smb/TransCallNamedPipe.java @@ -53,7 +53,7 @@ class TransCallNamedPipe extends SmbComTransaction { } int writeDataWireFormat( byte[] dst, int dstIndex ) { if(( dst.length - dstIndex ) < pipeDataLen ) { - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "TransCallNamedPipe data too long for buffer" ); return 0; } diff --git a/src/jcifs/smb/TransTransactNamedPipe.java b/src/jcifs/smb/TransTransactNamedPipe.java index b0f1358..d67189a 100644 --- a/src/jcifs/smb/TransTransactNamedPipe.java +++ b/src/jcifs/smb/TransTransactNamedPipe.java @@ -52,7 +52,7 @@ class TransTransactNamedPipe extends SmbComTransaction { } int writeDataWireFormat( byte[] dst, int dstIndex ) { if(( dst.length - dstIndex ) < pipeDataLen ) { - if( log.level > 2 ) + if( log.level >= 3 ) log.println( "TransTransactNamedPipe data too long for buffer" ); return 0; } diff --git a/src/jcifs/smb/TransactNamedPipeInputStream.java b/src/jcifs/smb/TransactNamedPipeInputStream.java index 3581feb..c0fdfe0 100644 --- a/src/jcifs/smb/TransactNamedPipeInputStream.java +++ b/src/jcifs/smb/TransactNamedPipeInputStream.java @@ -35,7 +35,7 @@ class TransactNamedPipeInputStream extends SmbFileInputStream { TransactNamedPipeInputStream( SmbNamedPipe pipe ) throws SmbException, MalformedURLException, UnknownHostException { - super( pipe, ( pipe.pipeType & 0xFFFF0000 ) | SmbFile.O_EXCL ); + super( pipe, ( pipe.pipeType & 0xFFFF00FF ) | SmbFile.O_EXCL ); this.dcePipe = ( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT ) != SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT; lock = new Object(); } @@ -89,7 +89,7 @@ class TransactNamedPipeInputStream extends SmbFileInputStream { return result; } public int available() throws IOException { - if( file.log.level > 2 ) + if( file.log.level >= 3 ) file.log.println( "Named Pipe available() does not apply to TRANSACT Named Pipes" ); return 0; } diff --git a/src/jcifs/smb/TransactNamedPipeOutputStream.java b/src/jcifs/smb/TransactNamedPipeOutputStream.java index 3b38129..f94375e 100644 --- a/src/jcifs/smb/TransactNamedPipeOutputStream.java +++ b/src/jcifs/smb/TransactNamedPipeOutputStream.java @@ -49,15 +49,17 @@ class TransactNamedPipeOutputStream extends OutputStream { len = 0; } - if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_CALL ) == - SmbNamedPipe.PIPE_TYPE_CALL ) { + if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_CALL ) == SmbNamedPipe.PIPE_TYPE_CALL ) { pipe.send( new TransWaitNamedPipe( path ), new TransWaitNamedPipeResponse() ); pipe.send( new TransCallNamedPipe( path, b, off, len ), new TransCallNamedPipeResponse( pipe )); } else if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_TRANSACT ) == SmbNamedPipe.PIPE_TYPE_TRANSACT ) { - pipe.open(SmbFile.O_EXCL, pipe.pipeType & 0xFFFF0000, SmbFile.ATTR_NORMAL, 0 ); + pipe.open((pipe.pipeType & 0xFF) | SmbFile.O_EXCL, + pipe.pipeType >>> 16, + SmbFile.ATTR_NORMAL, + 0); TransTransactNamedPipe req = new TransTransactNamedPipe( pipe.fid, b, off, len ); if (dcePipe) { req.maxDataCount = 1024; @@ -66,3 +68,4 @@ class TransactNamedPipeOutputStream extends OutputStream { } } } + diff --git a/src/jcifs/util/transport/Transport.java b/src/jcifs/util/transport/Transport.java index c31268b..bcc06be 100644 --- a/src/jcifs/util/transport/Transport.java +++ b/src/jcifs/util/transport/Transport.java @@ -103,7 +103,7 @@ public abstract class Transport implements Runnable { synchronized (response_map) { Response response = (Response)response_map.get( key ); if (response == null) { - if (log.level > 2) + if (log.level >= 4) log.println( "Invalid key, skipping message" ); doSkip(); } else { @@ -114,14 +114,14 @@ public abstract class Transport implements Runnable { } } catch( Exception ex ) { String msg = ex.getMessage(); - boolean hard = true; + boolean timeout = msg != null && msg.equals( "Read timed out" ); + /* If just a timeout, try to disconnect gracefully + */ + boolean hard = timeout == false; - if (log.level > 2) + if (!timeout && log.level >= 3) ex.printStackTrace( log ); - if (msg != null && msg.equals( "Read timed out" )) { - hard = false; - } try { disconnect( hard ); } catch( IOException ioe ) { @@ -147,46 +147,56 @@ public abstract class Transport implements Runnable { protected abstract void doDisconnect( boolean hard ) throws IOException; public synchronized void connect( long timeout ) throws TransportException { - switch (state) { - case 0: - break; - case 3: - return; // already connected - case 4: - state = 0; - throw new TransportException( "Connection in error", te ); - default: - throw new TransportException( "Invalid state: " + state ); - } + try { + switch (state) { + case 0: + break; + case 3: + return; // already connected + case 4: + state = 0; + throw new TransportException( "Connection in error", te ); + default: + state = 0; + throw new TransportException( "Invalid state: " + state ); + } - state = 1; - te = null; - thread = new Thread( this, name ); - thread.setDaemon( true ); + state = 1; + te = null; + thread = new Thread( this, name ); + thread.setDaemon( true ); - synchronized (thread) { - thread.start(); - try { + synchronized (thread) { + thread.start(); thread.wait( timeout ); /* wait for doConnect */ - } catch( InterruptedException ie ) { - throw new TransportException( ie ); - } - switch (state) { - case 1: /* doConnect never returned */ - state = 0; - thread = null; - throw new TransportException( "Connection timeout" ); - case 2: - if (te != null) { /* doConnect throw Exception */ - state = 4; /* error */ + switch (state) { + case 1: /* doConnect never returned */ + state = 0; thread = null; - throw te; - } - state = 3; /* Success! */ - return; - default: - te = new TransportException( "Invalid state: " + state ); + throw new TransportException( "Connection timeout" ); + case 2: + if (te != null) { /* doConnect throw Exception */ + state = 4; /* error */ + thread = null; + throw te; + } + state = 3; /* Success! */ + return; + } + } + } catch( InterruptedException ie ) { + state = 0; + thread = null; + throw new TransportException( ie ); + } finally { + /* This guarantees that we leave in a valid state + */ + if (state != 0 && state != 3) { + if (log.level >= 1) + log.println("Invalid state: " + state); + state = 0; + thread = null; } } } @@ -196,17 +206,20 @@ public abstract class Transport implements Runnable { switch (state) { case 0: /* not connected - just return */ return; + case 2: + hard = true; case 3: /* connected - go ahead and disconnect */ if (response_map.size() != 0 && !hard) { break; /* outstanding requests */ } doDisconnect( hard ); + default: + if (log.level >= 1) + log.println("Invalid state: " + state); case 4: /* in error - reset the transport */ thread = null; state = 0; break; - default: - throw new TransportException( "Invalid state: " + state ); } } }