diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 00000000..846342af
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,33 @@
+image: java:8-jdk
+
+stages:
+ - build
+ - test
+ - deploy
+
+before_script:
+# - echo `pwd` # debug
+# - echo "$CI_BUILD_NAME, $CI_BUILD_REF_NAME $CI_BUILD_STAGE" # debug
+ - export GRADLE_USER_HOME=`pwd`/.gradle
+
+cache:
+ paths:
+ - .gradle/wrapper
+ - .gradle/caches
+
+build:
+ stage: build
+ script:
+ - ./gradlew assemble
+ artifacts:
+ paths:
+ - build/libs/*.jar
+ expire_in: 1 week
+ only:
+ - master
+
+test:
+ stage: test
+ script:
+ - ./gradlew check
+
diff --git a/src/it/java/SmbjTest.java b/src/it/java/SmbjTest.java
index 5836db49..1201bbea 100644
--- a/src/it/java/SmbjTest.java
+++ b/src/it/java/SmbjTest.java
@@ -338,7 +338,6 @@ public void testRpc() throws IOException, SMBApiException, URISyntaxException {
}
}
-
//@Test
public void manualTestNotify() throws IOException {
diff --git a/src/it/resources/logback-test.xml b/src/it/resources/logback-test.xml
index a12690b5..6054f851 100644
--- a/src/it/resources/logback-test.xml
+++ b/src/it/resources/logback-test.xml
@@ -28,6 +28,6 @@
-
+
diff --git a/src/main/java/com/hierynomus/msdtyp/ACL.java b/src/main/java/com/hierynomus/msdtyp/ACL.java
index 1359bd0a..e7726e8d 100644
--- a/src/main/java/com/hierynomus/msdtyp/ACL.java
+++ b/src/main/java/com/hierynomus/msdtyp/ACL.java
@@ -15,12 +15,11 @@
*/
package com.hierynomus.msdtyp;
+import java.util.Arrays;
import com.hierynomus.msdtyp.ace.ACE;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.Arrays;
-
/**
* [MS-DTYP].pdf 2.4.5 ACL
*/
@@ -84,11 +83,11 @@ public int getAclSize() {
@Override
public String toString() {
return "ACL{" +
- "revision=" + revision +
- ", aceCount=" + aceCount +
- ", sidIdentifierAuthority=" + Arrays.toString(sidIdentifierAuthority) +
- ", subAuthorities=" + Arrays.toString(subAuthorities) +
- ", aces=" + Arrays.toString(aces) +
- '}';
+ "revision=" + revision +
+ ", aceCount=" + aceCount +
+ ", sidIdentifierAuthority=" + Arrays.toString(sidIdentifierAuthority) +
+ ", subAuthorities=" + Arrays.toString(subAuthorities) +
+ ", aces=" + Arrays.toString(aces) +
+ '}';
}
}
diff --git a/src/main/java/com/hierynomus/msdtyp/AccessMask.java b/src/main/java/com/hierynomus/msdtyp/AccessMask.java
index 92a91cbe..06bc3b3f 100644
--- a/src/main/java/com/hierynomus/msdtyp/AccessMask.java
+++ b/src/main/java/com/hierynomus/msdtyp/AccessMask.java
@@ -19,7 +19,7 @@
/**
* MS-DTYP 2.4.3 ACCESS_MASK
- *
+ *
* Its ok to find multiple names pointing to the same values, Since the
* same access mask when applied to File, Folder or other object are just
* named/called differently.
diff --git a/src/main/java/com/hierynomus/msdtyp/MsDataTypes.java b/src/main/java/com/hierynomus/msdtyp/MsDataTypes.java
index eea46258..9c19f20e 100644
--- a/src/main/java/com/hierynomus/msdtyp/MsDataTypes.java
+++ b/src/main/java/com/hierynomus/msdtyp/MsDataTypes.java
@@ -15,11 +15,10 @@
*/
package com.hierynomus.msdtyp;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import com.hierynomus.protocol.commons.buffer.Endian;
-
import java.util.Date;
import java.util.UUID;
+import com.hierynomus.protocol.commons.buffer.Buffer;
+import com.hierynomus.protocol.commons.buffer.Endian;
/**
* Utility class that can read and write data types from the [MS-DTYP].pdf specification document from buffers.
@@ -28,7 +27,8 @@ public class MsDataTypes {
public static final int NANO100_TO_MILLI = 10000;
public static final long WINDOWS_TO_UNIX_EPOCH = 0x19DB1DED53E8000L;
- private MsDataTypes() {}
+ private MsDataTypes() {
+ }
/**
* [MS-DTYP].pdf 2.3.4.2 GUID Packet representation
diff --git a/src/main/java/com/hierynomus/msdtyp/SID.java b/src/main/java/com/hierynomus/msdtyp/SID.java
index e491a59c..8086f778 100644
--- a/src/main/java/com/hierynomus/msdtyp/SID.java
+++ b/src/main/java/com/hierynomus/msdtyp/SID.java
@@ -20,6 +20,8 @@
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
+import java.util.Arrays;
+
/**
* [MS-DTYP].pdf 2.4.2 SecurityIdentifier SID
*/
@@ -134,4 +136,29 @@ public byte[] getSidIdentifierAuthority() {
public long[] getSubAuthorities() {
return subAuthorities;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ SID sid = (SID) o;
+
+ if (revision != sid.revision)
+ return false;
+ if (!Arrays.equals(sidIdentifierAuthority, sid.sidIdentifierAuthority))
+ return false;
+ return Arrays.equals(subAuthorities, sid.subAuthorities);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) revision;
+ result = 31 * result + Arrays.hashCode(sidIdentifierAuthority);
+ result = 31 * result + Arrays.hashCode(subAuthorities);
+ return result;
+ }
}
diff --git a/src/main/java/com/hierynomus/msdtyp/SecurityDescriptor.java b/src/main/java/com/hierynomus/msdtyp/SecurityDescriptor.java
index 9672de91..2b1de454 100644
--- a/src/main/java/com/hierynomus/msdtyp/SecurityDescriptor.java
+++ b/src/main/java/com/hierynomus/msdtyp/SecurityDescriptor.java
@@ -15,12 +15,11 @@
*/
package com.hierynomus.msdtyp;
+import java.util.EnumSet;
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
/**
* [MS-DTYP].pdf 2.4.6 SecurityDescriptor
*/
@@ -35,7 +34,7 @@ public class SecurityDescriptor {
public SecurityDescriptor() {
}
-// public SecurityDescriptor(EnumSet control, SID ownerSid, SID groupSid, ACL sacl, ACL dacl) {
+ // public SecurityDescriptor(EnumSet control, SID ownerSid, SID groupSid, ACL sacl, ACL dacl) {
// this.control = control;
// this.ownerSid = ownerSid;
// this.groupSid = groupSid;
@@ -120,12 +119,12 @@ public ACL getDacl() {
@Override
public String toString() {
return "SecurityDescriptor{" +
- "control=" + control +
- ", ownerSid=" + ownerSid +
- ", groupSid=" + groupSid +
- ", sacl=" + sacl +
- ", dacl=" + dacl +
- '}';
+ "control=" + control +
+ ", ownerSid=" + ownerSid +
+ ", groupSid=" + groupSid +
+ ", sacl=" + sacl +
+ ", dacl=" + dacl +
+ '}';
}
// SecurityDescriptor Control bits
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/ACE.java b/src/main/java/com/hierynomus/msdtyp/ace/ACE.java
index 04194468..8bc29d7f 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/ACE.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/ACE.java
@@ -117,10 +117,10 @@ public static ACE factory(SMBBuffer buffer) throws Buffer.BufferException {
@Override
public String toString() {
return "ACE{" +
- "aceHeader=" + aceHeader +
- ", accessMask=" + EnumWithValue.EnumUtils.toEnumSet(accessMask, AccessMask.class) +
- ", sid=" + sid +
- '}';
+ "aceHeader=" + aceHeader +
+ ", accessMask=" + EnumWithValue.EnumUtils.toEnumSet(accessMask, AccessMask.class) +
+ ", sid=" + sid +
+ '}';
}
protected abstract void readMessage(SMBBuffer buffer) throws Buffer.BufferException;
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/AceHeader.java b/src/main/java/com/hierynomus/msdtyp/ace/AceHeader.java
index feedc873..ef611589 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/AceHeader.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/AceHeader.java
@@ -15,12 +15,11 @@
*/
package com.hierynomus.msdtyp.ace;
+import java.util.EnumSet;
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toEnumSet;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.valueOf;
@@ -73,9 +72,9 @@ public EnumSet getAceFlags() {
@Override
public String toString() {
return "AceHeader{" +
- "aceType=" + aceType +
- ", aceFlags=" + aceFlags +
- ", aceSize=" + aceSize +
- '}';
+ "aceType=" + aceType +
+ ", aceFlags=" + aceFlags +
+ ", aceSize=" + aceSize +
+ '}';
}
}
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/AceType1.java b/src/main/java/com/hierynomus/msdtyp/ace/AceType1.java
index ee1265de..cb6e9fc9 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/AceType1.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/AceType1.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.msdtyp.ace;
+import java.util.EnumSet;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msdtyp.SID;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toLong;
// Type 1 - Header/Mask/SID (ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_MANDATORY_LABEL_ACE,
@@ -30,9 +29,10 @@ class AceType1 extends ACE {
AceType1() {
}
+
AceType1(AceType aceType, EnumSet aceFlags, EnumSet accessMask, SID sid) {
super(new AceHeader(aceType, aceFlags, ACE.HEADER_STRUCTURE_SIZE + 4 + sid.byteCount()),
- toLong(accessMask), sid);
+ toLong(accessMask), sid);
}
@Override
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/AceType2.java b/src/main/java/com/hierynomus/msdtyp/ace/AceType2.java
index 08e04c10..ecd461f0 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/AceType2.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/AceType2.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.msdtyp.ace;
+import java.util.EnumSet;
+import java.util.UUID;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.msdtyp.SID;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-import java.util.UUID;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toEnumSet;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toLong;
@@ -35,9 +34,9 @@ class AceType2 extends ACE {
private UUID inheritedObjectType;
AceType2(AceType aceType, EnumSet aceFlags, EnumSet accessMask,
- EnumSet flags, UUID objectType, UUID inheritedObjectType, SID sid) {
+ EnumSet flags, UUID objectType, UUID inheritedObjectType, SID sid) {
super(new AceHeader(aceType, aceFlags, ACE.HEADER_STRUCTURE_SIZE + 4 + 4 + 16 + 16 + sid.byteCount()),
- toLong(accessMask), sid);
+ toLong(accessMask), sid);
this.flags = flags;
this.objectType = objectType;
this.inheritedObjectType = inheritedObjectType;
@@ -83,9 +82,9 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
@Override
public String toString() {
return "AceType2{" +
- "flags=" + flags +
- ", objectType=" + objectType +
- ", inheritedObjectType=" + inheritedObjectType +
- "} " + super.toString();
+ "flags=" + flags +
+ ", objectType=" + objectType +
+ ", inheritedObjectType=" + inheritedObjectType +
+ "} " + super.toString();
}
}
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/AceType3.java b/src/main/java/com/hierynomus/msdtyp/ace/AceType3.java
index 9076958a..c43febe5 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/AceType3.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/AceType3.java
@@ -15,14 +15,13 @@
*/
package com.hierynomus.msdtyp.ace;
+import java.util.Arrays;
+import java.util.EnumSet;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msdtyp.SID;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.Arrays;
-import java.util.EnumSet;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toLong;
// Type 3 - Header/Mask/SID/ApplicationData
@@ -35,10 +34,10 @@ class AceType3 extends ACE {
}
AceType3(AceType aceType, EnumSet aceFlags, EnumSet accessMask, SID sid, byte[]
- applicationData) {
+ applicationData) {
super(new AceHeader(aceType, aceFlags, ACE.HEADER_STRUCTURE_SIZE + 4 + 4 + sid.byteCount() +
- applicationData.length),
- toLong(accessMask), sid);
+ applicationData.length),
+ toLong(accessMask), sid);
this.applicationData = applicationData;
}
@@ -59,7 +58,7 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
@Override
public String toString() {
return "AceType3{" +
- "applicationData=" + Arrays.toString(applicationData) +
- "} " + super.toString();
+ "applicationData=" + Arrays.toString(applicationData) +
+ "} " + super.toString();
}
}
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/AceType4.java b/src/main/java/com/hierynomus/msdtyp/ace/AceType4.java
index 9149c020..26467866 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/AceType4.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/AceType4.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.msdtyp.ace;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.UUID;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msdtyp.SID;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.UUID;
-
// Type 4 - Header/Mask/Flags/ObjectType/InheritedObjectType/Sid/ApplicationData
// ACCESS_ALLOWED_CALLBACK_OBJECT_ACE, ACCESS_DENIED_CALLBACK_OBJECT_ACE, SYSTEM_AUDIT_OBJECT_ACE,
// SYSTEM_AUDIT_CALLBACK_OBJECT_ACE,
@@ -35,8 +34,8 @@ class AceType4 extends AceType2 {
}
AceType4(AceType aceType, EnumSet aceFlags, EnumSet accessMask,
- EnumSet flags, UUID objectType, UUID inheritedObjectType, SID sid, byte[]
- applicationData) {
+ EnumSet flags, UUID objectType, UUID inheritedObjectType, SID sid, byte[]
+ applicationData) {
super(aceType, aceFlags, accessMask, flags, objectType, inheritedObjectType, sid);
aceHeader.setAceSize(aceHeader.getAceSize() + applicationData.length);
this.applicationData = applicationData;
@@ -58,7 +57,7 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
@Override
public String toString() {
return "AceType4{" +
- "applicationData=" + Arrays.toString(applicationData) +
- "} " + super.toString();
+ "applicationData=" + Arrays.toString(applicationData) +
+ "} " + super.toString();
}
}
diff --git a/src/main/java/com/hierynomus/msdtyp/ace/AceTypes.java b/src/main/java/com/hierynomus/msdtyp/ace/AceTypes.java
index 15eafa88..9d71dac7 100644
--- a/src/main/java/com/hierynomus/msdtyp/ace/AceTypes.java
+++ b/src/main/java/com/hierynomus/msdtyp/ace/AceTypes.java
@@ -15,20 +15,34 @@
*/
package com.hierynomus.msdtyp.ace;
-import com.hierynomus.msdtyp.AccessMask;
-import com.hierynomus.msdtyp.SID;
-
import java.util.EnumSet;
import java.util.UUID;
+import com.hierynomus.msdtyp.AccessMask;
+import com.hierynomus.msdtyp.SID;
-import static com.hierynomus.msdtyp.ace.AceType.*;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_ALLOWED_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_ALLOWED_CALLBACK_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_ALLOWED_OBJECT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_DENIED_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_DENIED_CALLBACK_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.ACCESS_DENIED_OBJECT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_AUDIT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_AUDIT_CALLBACK_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_AUDIT_OBJECT_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_MANDATORY_LABEL_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE;
+import static com.hierynomus.msdtyp.ace.AceType.SYSTEM_SCOPED_POLICY_ID_ACE_TYPE;
/**
* Factory methods for the different AceType objects.
*/
public class AceTypes {
- private AceTypes() {}
+ private AceTypes() {
+ }
/**
* [MS-DTYP].pdf 2.4.4.2 ACCESS_ALLOWED_ACE
@@ -89,8 +103,8 @@ public static ACE accessAllowedCallbackObjectAce(EnumSet aceFlags, Enu
* [MS-DTYP].pdf 2.4.4.9 ACCESS_DENIED_CALLBACK_OBJECT_ACE
*/
public static ACE accessDeniedCallbackObjectAce(EnumSet aceFlags, EnumSet accessMask,
- EnumSet flags, UUID objectType, UUID inheritedObjectType,
- SID sid, byte[] applicationData) {
+ EnumSet flags, UUID objectType, UUID inheritedObjectType,
+ SID sid, byte[] applicationData) {
return new AceType4(ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE, aceFlags, accessMask, flags, objectType, inheritedObjectType, sid, applicationData);
}
diff --git a/src/main/java/com/hierynomus/mserref/NtStatus.java b/src/main/java/com/hierynomus/mserref/NtStatus.java
index 9ace152c..5a6e5587 100644
--- a/src/main/java/com/hierynomus/mserref/NtStatus.java
+++ b/src/main/java/com/hierynomus/mserref/NtStatus.java
@@ -19,7 +19,7 @@
/**
* [MS-ERREF].pdf 2.3.1 NTSTATUS values
- *
+ *
* Subset of the possible values which are useful for SMB2 communication
*/
public enum NtStatus implements EnumWithValue {
@@ -28,6 +28,8 @@ public enum NtStatus implements EnumWithValue {
STATUS_PENDING(0x00000103L),
STATUS_BUFFER_OVERFLOW(0x80000005L),
STATUS_END_OF_FILE(0xC0000011L),
+ STATUS_SHARING_VIOLATION(0xC0000043L),
+ STATUS_DELETE_PENDING(0xC0000056L),
STATUS_FILE_IS_A_DIRECTORY(0xC00000BAL),
STATUS_NETWORK_NAME_DELETED(0xC00000C9L),
STATUS_INVALID_PARAMETER(0xC000000DL),
@@ -39,8 +41,13 @@ public enum NtStatus implements EnumWithValue {
STATUS_OBJECT_PATH_NOT_FOUND(0xC000003AL),
STATUS_LOGON_FAILURE(0xC000006DL),
STATUS_PASSWORD_EXPIRED(0xC0000071L),
+ STATUS_DISK_FULL(0xC000007FL),
STATUS_INSUFFICIENT_RESOURCES(0xC000009AL),
+ STATUS_PIPE_NOT_AVAILABLE(0xC00000ACL),
+ STATUS_INVALID_PIPE_STATE(0xC00000ADL),
+ STATUS_PIPE_BUSY(0xC00000AEL),
STATUS_NOT_SUPPORTED(0xC00000BBL),
+ STATUS_BAD_NETWORK_PATH(0xC00000BEL),
STATUS_BAD_NETWORK_NAME(0xC00000CCL),
STATUS_REQUEST_NOT_ACCEPTED(0xC00000D0L),
STATUS_NET_WRITE_FAULT(0xC00000D2L),
@@ -66,10 +73,12 @@ public enum NtStatus implements EnumWithValue {
STATUS_CONNECTION_DISCONNECTED(0xC000020CL),
STATUS_CONNECTION_RESET(0xC000020DL),
STATUS_NOT_FOUND(0xC0000225L),
+ STATUS_PATH_NOT_COVERED(0xC0000257L),
STATUS_RETRY(0xC000022DL),
STATUS_DFS_UNAVAILABLE(0xC000026DL),
STATUS_FILE_ENCRYPTED(0xC0000293L),
STATUS_NETWORK_SESSION_EXPIRED(0xC000035CL),
+ STATUS_NO_MORE_FILES(0x80000006L),
UNKNOWN(0xFFFFFFFFL);
private long value;
diff --git a/src/main/java/com/hierynomus/msfscc/fileinformation/FileInfo.java b/src/main/java/com/hierynomus/msfscc/fileinformation/FileInfo.java
index abf34611..9cf996cd 100644
--- a/src/main/java/com/hierynomus/msfscc/fileinformation/FileInfo.java
+++ b/src/main/java/com/hierynomus/msfscc/fileinformation/FileInfo.java
@@ -58,9 +58,9 @@ public long getAccessMask() {
@Override
public String toString() {
return "FileInfo{" +
- "fileName='" + fileName + '\'' +
- "fileSize='" + fileSize + '\'' +
- ", fileAttributes=" + EnumWithValue.EnumUtils.toEnumSet(fileAttributes, FileAttributes.class) +
- '}';
+ "fileName='" + fileName + '\'' +
+ "fileSize='" + fileSize + '\'' +
+ ", fileAttributes=" + EnumWithValue.EnumUtils.toEnumSet(fileAttributes, FileAttributes.class) +
+ '}';
}
}
diff --git a/src/main/java/com/hierynomus/msfscc/fileinformation/FileInformationFactory.java b/src/main/java/com/hierynomus/msfscc/fileinformation/FileInformationFactory.java
index fc618457..abbd3c49 100644
--- a/src/main/java/com/hierynomus/msfscc/fileinformation/FileInformationFactory.java
+++ b/src/main/java/com/hierynomus/msfscc/fileinformation/FileInformationFactory.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.msfscc.fileinformation;
-import com.hierynomus.msdtyp.MsDataTypes;
-import com.hierynomus.msfscc.FileInformationClass;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import com.hierynomus.protocol.commons.buffer.Endian;
-
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import com.hierynomus.msdtyp.MsDataTypes;
+import com.hierynomus.msfscc.FileInformationClass;
+import com.hierynomus.protocol.commons.buffer.Buffer;
+import com.hierynomus.protocol.commons.buffer.Endian;
public class FileInformationFactory {
@@ -44,9 +43,7 @@ public static byte[] getRenameInfo(boolean replaceIfExists, String newName) {
* MS-FSCC 2.4.11 FileDispositionInformation for SMB2
*/
public static byte[] getFileDispositionInfo(boolean deleteOnClose) {
- Buffer.PlainBuffer fileDispBuf = new Buffer.PlainBuffer(Endian.LE);
- fileDispBuf.putByte((byte) (deleteOnClose ? 1 : 0));
- return fileDispBuf.getCompactData();
+ return deleteOnClose ? new byte[]{1} : new byte[]{0};
}
/**
@@ -58,16 +55,16 @@ public static byte[] getFileDispositionInfo(boolean deleteOnClose) {
* @throws Buffer.BufferException
*/
public static List parseFileInformationList(
- byte[] data, FileInformationClass fileInformationClass)
- throws Buffer.BufferException {
+ byte[] data, FileInformationClass fileInformationClass)
+ throws Buffer.BufferException {
Buffer.PlainBuffer buffer = new Buffer.PlainBuffer(data, Endian.LE);
List _fileInfoList = new ArrayList<>();
int offsetStart = 0;
int nextEntryOffset = offsetStart;
long fileIndex = 0;
- do {
- nextEntryOffset = (int)buffer.readUInt32();
+ do {
+ nextEntryOffset = (int) buffer.readUInt32();
fileIndex = buffer.readUInt32();
FileInfo fileInfo = null;
switch (fileInformationClass) {
@@ -92,7 +89,7 @@ public static List parseFileInformationList(
/**
* [MS-SMB2] 2.2.38 SMB2 QUERY_INFO Response, SMB2_0_INFO_FILE/FileAllInformation
- *
+ *
* [MS-FSCC] 2.4.2 FileAllInformation
*/
public static FileInfo parseFileAllInformation(Buffer.PlainBuffer buffer) throws Buffer.BufferException {
diff --git a/src/main/java/com/hierynomus/mssmb2/SMB2CreateDisposition.java b/src/main/java/com/hierynomus/mssmb2/SMB2CreateDisposition.java
index 6b2b0029..b522a1b2 100644
--- a/src/main/java/com/hierynomus/mssmb2/SMB2CreateDisposition.java
+++ b/src/main/java/com/hierynomus/mssmb2/SMB2CreateDisposition.java
@@ -25,17 +25,29 @@
* For other files, this field MUST contain one of the following values.
*/
public enum SMB2CreateDisposition implements EnumWithValue {
- /** If the file already exists, supersede it. Otherwise, create the file. This value SHOULD NOT be used for a printer object. */
+ /**
+ * If the file already exists, supersede it. Otherwise, create the file. This value SHOULD NOT be used for a printer object.
+ */
FILE_SUPERSEDE(0x00000000L),
- /** If the file already exists, return success; otherwise, fail the operation. MUST NOT be used for a printer object. */
+ /**
+ * If the file already exists, return success; otherwise, fail the operation. MUST NOT be used for a printer object.
+ */
FILE_OPEN(0x00000001L),
- /** If the file already exists, fail the operation; otherwise, create the file. */
+ /**
+ * If the file already exists, fail the operation; otherwise, create the file.
+ */
FILE_CREATE(0x00000002L),
- /** Open the file if it already exists; otherwise, create the file. This value SHOULD NOT be used for a printer object. */
+ /**
+ * Open the file if it already exists; otherwise, create the file. This value SHOULD NOT be used for a printer object.
+ */
FILE_OPEN_IF(0x00000003L),
- /** Overwrite the file if it already exists; otherwise, fail the operation. MUST NOT be used for a printer object. */
+ /**
+ * Overwrite the file if it already exists; otherwise, fail the operation. MUST NOT be used for a printer object.
+ */
FILE_OVERWRITE(0x00000004L),
- /** Overwrite the file if it already exists; otherwise, create the file. This value SHOULD NOT be used for a printer object. */
+ /**
+ * Overwrite the file if it already exists; otherwise, create the file. This value SHOULD NOT be used for a printer object.
+ */
FILE_OVERWRITE_IF(0x00000005L);
private long value;
diff --git a/src/main/java/com/hierynomus/mssmb2/SMB2Dialect.java b/src/main/java/com/hierynomus/mssmb2/SMB2Dialect.java
index 80e929c4..2a69fdd6 100644
--- a/src/main/java/com/hierynomus/mssmb2/SMB2Dialect.java
+++ b/src/main/java/com/hierynomus/mssmb2/SMB2Dialect.java
@@ -42,6 +42,7 @@ public boolean isSmb3x() {
/**
* Whether any of the dialects in the set is an SMB 3.x dialect.
+ *
* @param dialects The supported dialects enumset.
* @return true if there is (at least) one SMB 3.x dialect in the set.
*/
diff --git a/src/main/java/com/hierynomus/mssmb2/SMB2FileId.java b/src/main/java/com/hierynomus/mssmb2/SMB2FileId.java
index e94053b8..b141e359 100644
--- a/src/main/java/com/hierynomus/mssmb2/SMB2FileId.java
+++ b/src/main/java/com/hierynomus/mssmb2/SMB2FileId.java
@@ -39,13 +39,13 @@ public void write(SMBBuffer buffer) {
}
public static SMB2FileId read(SMBBuffer buffer) throws Buffer.BufferException {
- return new SMB2FileId(buffer.readRawBytes(8),buffer.readRawBytes(8));
+ return new SMB2FileId(buffer.readRawBytes(8), buffer.readRawBytes(8));
}
@Override
public String toString() {
return "SMB2FileId{" +
- "persistentHandle=" + ByteArrayUtils.printHex(persistentHandle) +
- '}';
+ "persistentHandle=" + ByteArrayUtils.printHex(persistentHandle) +
+ '}';
}
}
diff --git a/src/main/java/com/hierynomus/mssmb2/SMB2Header.java b/src/main/java/com/hierynomus/mssmb2/SMB2Header.java
index 2ade7a9c..ec9141fa 100644
--- a/src/main/java/com/hierynomus/mssmb2/SMB2Header.java
+++ b/src/main/java/com/hierynomus/mssmb2/SMB2Header.java
@@ -21,13 +21,14 @@
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.isSet;
-import static com.hierynomus.smbj.connection.NegotiatedProtocol.SINGLE_CREDIT_PAYLOAD_SIZE;
/**
* [MS-SMB2].pdf 2.2.1 SMB2 Packet Header
*/
public class SMB2Header {
public static final int STRUCTURE_SIZE = 64;
+ public static final int SIGNATURE_OFFSET = 48;
+ public static final int SIGNATURE_SIZE = 16;
private SMB2Dialect dialect;
private int creditCharge = 1;
@@ -63,12 +64,12 @@ public void writeTo(SMBBuffer buffer) {
buffer.putUInt32(treeId); // TreeId (4 bytes)
}
buffer.putLong(sessionId); // SessionId (8 bytes)
- buffer.putRawBytes(new byte[] {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}); // Signature (16 bytes)
+ buffer.putRawBytes(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}); // Signature (16 bytes)
}
private void writeChannelSequenceReserved(SMBBuffer buffer) {
if (dialect.isSmb3x()) {
- buffer.putRawBytes(new byte[] {0x0, 0x0}); // ChannelSequence (2 bytes)
+ buffer.putRawBytes(new byte[]{0x0, 0x0}); // ChannelSequence (2 bytes)
buffer.putReserved(2); // Reserved (2 bytes)
throw new UnsupportedOperationException("SMB 3.x not yet implemented");
} else {
@@ -78,7 +79,7 @@ private void writeChannelSequenceReserved(SMBBuffer buffer) {
/**
* [MS-SMB2].pdf 3.2.4.1.2 Requesting Credits from the Server
- *
+ *
* We should at least request the number of credits this request consumes, but we can request more (by calling {@link #setCreditRequest(int)}).
*/
private void writeCreditRequest(SMBBuffer buffer) {
@@ -137,6 +138,10 @@ public void setDialect(SMB2Dialect dialect) {
this.dialect = dialect;
}
+ public boolean isFlagSet(SMB2MessageFlag flag) {
+ return isSet(this.flags, flag);
+ }
+
public void setFlag(SMB2MessageFlag flag) {
this.flags |= flag.getValue();
}
@@ -205,4 +210,23 @@ public void setNextCommandOffset(long nextCommandOffset) {
public void setCreditCharge(int creditCharge) {
this.creditCharge = creditCharge;
}
+
+ public String toString() {
+ return String.format(
+ "dialect=%s, creditCharge=%s, creditRequest=%s, creditResponse=%s, message=%s, messageId=%s, asyncId=%s, sessionId=%s, treeId=%s, status=%s, statusCode=%s, flags=%s, nextCommandOffset=%s",
+ dialect,
+ creditCharge,
+ creditRequest,
+ creditResponse,
+ message,
+ messageId,
+ asyncId,
+ sessionId,
+ treeId,
+ status,
+ statusCode,
+ flags,
+ nextCommandOffset);
+
+ }
}
diff --git a/src/main/java/com/hierynomus/mssmb2/SMB2Packet.java b/src/main/java/com/hierynomus/mssmb2/SMB2Packet.java
index 53b9fad5..2bf98c9d 100644
--- a/src/main/java/com/hierynomus/mssmb2/SMB2Packet.java
+++ b/src/main/java/com/hierynomus/mssmb2/SMB2Packet.java
@@ -22,6 +22,7 @@
public class SMB2Packet implements Packet {
protected final SMB2Header header = new SMB2Header();
protected int structureSize;
+ SMBBuffer buffer;
public SMB2Packet() {
}
@@ -54,6 +55,10 @@ public int getStructureSize() {
return structureSize;
}
+ public SMBBuffer getBuffer() {
+ return buffer;
+ }
+
public final void write(SMBBuffer buffer) {
header.writeTo(buffer);
writeTo(buffer);
@@ -61,6 +66,7 @@ public final void write(SMBBuffer buffer) {
/**
* Write the message fields into the buffer, as specified in the [MS-SMB2].pdf specification.
+ *
* @param buffer
*/
protected void writeTo(SMBBuffer buffer) {
@@ -68,6 +74,7 @@ protected void writeTo(SMBBuffer buffer) {
}
public final SMB2Packet read(SMBBuffer buffer) throws Buffer.BufferException {
+ this.buffer = buffer; // remember the buffer we read it from
header.readFrom(buffer);
readMessage(buffer);
return this;
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyRequest.java
index 14562fef..f45dbead 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyRequest.java
@@ -15,12 +15,11 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
import com.hierynomus.mssmb2.*;
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
/**
* [MS-SMB2].pdf 2.2.35 SMB2 CHANGE_NOTIFY Request
*
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponse.java
index b9a17246..a62499d1 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponse.java
@@ -15,6 +15,9 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.msfscc.FileNotifyAction;
import com.hierynomus.mssmb2.SMB2Packet;
@@ -22,14 +25,11 @@
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* [MS-SMB2].pdf 2.2.36 SMB2 CHANGE_NOTIFY Response
*
-\ */
+ * \
+ */
public class SMB2ChangeNotifyResponse extends SMB2Packet {
List fileNotifyInfoList = new ArrayList<>();
@@ -49,7 +49,7 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
}
private List readFileNotifyInfo(SMBBuffer buffer, int outputBufferOffset, int outBufferLength)
- throws Buffer.BufferException {
+ throws Buffer.BufferException {
List notifyInfoList = new ArrayList<>();
buffer.rpos(outputBufferOffset);
int currentPos = buffer.rpos();
@@ -57,11 +57,11 @@ private List readFileNotifyInfo(SMBBuffer buffer, int outputBuff
long fileNameLen = 0;
String fileName = null;
- do {
- nextEntryOffset = (int)buffer.readUInt32();
+ do {
+ nextEntryOffset = (int) buffer.readUInt32();
FileNotifyAction action = EnumWithValue.EnumUtils.valueOf(buffer.readUInt32(), FileNotifyAction.class, null);
fileNameLen = buffer.readUInt32();
- fileName = buffer.readString(StandardCharsets.UTF_16LE, (int)fileNameLen/2);
+ fileName = buffer.readString(StandardCharsets.UTF_16LE, (int) fileNameLen / 2);
notifyInfoList.add(new FileNotifyInfo(action, fileName));
currentPos += nextEntryOffset;
buffer.rpos(currentPos);
@@ -94,9 +94,9 @@ public String getFileName() {
@Override
public String toString() {
return "FileNotifyInfo{" +
- "action=" + action +
- ", fileName='" + fileName + '\'' +
- '}';
+ "action=" + action +
+ ", fileName='" + fileName + '\'' +
+ '}';
}
}
}
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2Close.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2Close.java
index 420ff7a4..cfe6cfbc 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2Close.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2Close.java
@@ -15,6 +15,7 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.Date;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.mssmb2.SMB2Dialect;
@@ -24,8 +25,6 @@
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.Date;
-
/**
* [MS-SMB2].pdf 2.2.15 SMB2 CLOSE Request / 2.2.16 SMB2 CLOSE Response
*/
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateRequest.java
index f92068f5..c9c4ff63 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateRequest.java
@@ -15,12 +15,11 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
import com.hierynomus.msfscc.FileAttributes;
import com.hierynomus.mssmb2.*;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.ensureNotNull;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toLong;
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateResponse.java
index edf5624e..b1703d49 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2CreateResponse.java
@@ -15,6 +15,8 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.Date;
+import java.util.EnumSet;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.msfscc.FileAttributes;
@@ -23,14 +25,10 @@
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.Date;
-import java.util.EnumSet;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toEnumSet;
/**
* [MS-SMB2].pdf 2.2.14 SMB2 CREATE Response
- *
*/
public class SMB2CreateResponse extends SMB2Packet {
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2IoctlResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2IoctlResponse.java
index 3a40f6c2..31bb50a5 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2IoctlResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2IoctlResponse.java
@@ -26,7 +26,8 @@
/**
* [MS-SMB2].pdf 2.2.32 SMB2 IOCTL Response
*
-\ */
+ * \
+ */
public class SMB2IoctlResponse extends SMB2Packet {
private SMB2IoctlRequest.ControlCode controlCode;
@@ -50,9 +51,9 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
fileId = SMB2FileId.read(buffer); // FileId (16 bytes)
int inputOffset = buffer.readUInt32AsInt(); // Input Offset (4 bytes)
- int inputCount = buffer.readUInt32AsInt(); // Input Count (4 bytes)
+ int inputCount = buffer.readUInt32AsInt(); // Input Count (4 bytes)
int outputOffset = buffer.readUInt32AsInt(); // Input Offset (4 bytes)
- int outputCount = buffer.readUInt32AsInt(); // Input Count (4 bytes)
+ int outputCount = buffer.readUInt32AsInt(); // Input Count (4 bytes)
buffer.skip(4); // Flags (4 bytes)
buffer.skip(4); // Reserved2 (4 bytes)
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateRequest.java
index 07c450de..507099f5 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateRequest.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
+import java.util.UUID;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.mssmb2.SMB2MessageCommandCode;
import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-import java.util.UUID;
-
/**
* [MS-SMB2].pdf 2.2.3 SMB2 Negotiate
*/
@@ -34,6 +33,7 @@ public class SMB2NegotiateRequest extends SMB2Packet {
/**
* Request constructor.
+ *
* @param dialects
* @param clientGuid
*/
@@ -45,6 +45,7 @@ public SMB2NegotiateRequest(EnumSet dialects, UUID clientGuid) {
/**
* The Request packet
+ *
* @param buffer
*/
@Override
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateResponse.java
index f34230f8..ca0ca82c 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2NegotiateResponse.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.Date;
+import java.util.UUID;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.Date;
-import java.util.UUID;
-
/**
* [MS-SMB2].pdf 2.2.4 SMB2 Negotiate Response
*/
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryRequest.java
index 3a9ad8e1..24971714 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryRequest.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
import com.hierynomus.msfscc.FileInformationClass;
import com.hierynomus.mssmb2.*;
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
/**
* [MS-SMB2].pdf 2.2.33 SMB2 QUERY DIRECTORY Request
*
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoRequest.java
index ba92c570..395e5b61 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoRequest.java
@@ -15,6 +15,7 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
import com.hierynomus.msdtyp.SecurityInformation;
import com.hierynomus.msfscc.FileInformationClass;
import com.hierynomus.msfscc.FileSysemInformationClass;
@@ -22,8 +23,6 @@
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
/**
* [MS-SMB2].pdf 2.2.37 SMB2 QUERY_INFO Request
*/
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoResponse.java
index 4d670a9b..b09a3e6c 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2QueryInfoResponse.java
@@ -23,7 +23,8 @@
/**
* [MS-SMB2].pdf 2.2.38 SMB2 QUERY_INFO Response
*
-\ */
+ * \
+ */
public class SMB2QueryInfoResponse extends SMB2Packet {
byte[] outputBuffer;
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadRequest.java
index 0bc7549c..3a2b9487 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadRequest.java
@@ -23,7 +23,6 @@
/**
* [MS-SMB2].pdf 2.2.19 SMB2 READ Request
- *
*/
public class SMB2ReadRequest extends SMB2MultiCreditPacket {
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadResponse.java
index c0c8eccd..1430aa4f 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ReadResponse.java
@@ -22,7 +22,6 @@
/**
* [MS-SMB2].pdf 2.2.20 SMB2 READ Response
- *
*/
public class SMB2ReadResponse extends SMB2Packet {
@@ -30,7 +29,7 @@ public class SMB2ReadResponse extends SMB2Packet {
private byte[] data;
public SMB2ReadResponse() {
- super();
+ super();
}
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ResponseMessageFactory.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ResponseMessageFactory.java
index 15ae9cba..8d73eabd 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2ResponseMessageFactory.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2ResponseMessageFactory.java
@@ -26,7 +26,7 @@ public class SMB2ResponseMessageFactory {
public static SMB2Packet read(SMBBuffer buffer) throws Buffer.BufferException {
// Check we see a valid header start
- Check.ensureEquals(buffer.readRawBytes(4), new byte[] {(byte) 0xFE, 'S', 'M', 'B'}, "Could not find SMB2 Packet header");
+ Check.ensureEquals(buffer.readRawBytes(4), new byte[]{(byte) 0xFE, 'S', 'M', 'B'}, "Could not find SMB2 Packet header");
// Skip until Command
buffer.skip(8);
SMB2MessageCommandCode command = SMB2MessageCommandCode.lookup(buffer.readUInt16());
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2SessionSetup.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2SessionSetup.java
index d498dbce..49be7c5b 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2SessionSetup.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2SessionSetup.java
@@ -15,6 +15,7 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.mssmb2.SMB2Header;
@@ -23,9 +24,6 @@
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-
-import java.util.EnumSet;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toEnumSet;
@@ -48,7 +46,7 @@ public SMB2SessionSetup() {
public SMB2SessionSetup(SMB2Dialect negotiatedDialect, EnumSet securityMode) {
super(25, negotiatedDialect, SMB2MessageCommandCode.SMB2_SESSION_SETUP);
this.negotiatedDialect = negotiatedDialect;
- this.securityMode = (byte)EnumWithValue.EnumUtils.toLong(securityMode);
+ this.securityMode = (byte) EnumWithValue.EnumUtils.toLong(securityMode);
}
@Override
@@ -59,9 +57,11 @@ protected void writeTo(SMBBuffer buffer) {
buffer.putUInt32(clientCapabilities & 0x01); // Capabilities (4 bytes) (only last byte can be set)
buffer.putReserved4(); // Channel (4 bytes)
buffer.putUInt16(SMB2Header.STRUCTURE_SIZE + 25 - 1); // SecurityBufferOffset (2 bytes) (header structure size + Session setup structure size - 1)
- buffer.putUInt16(securityBuffer.length); // SecurityBufferLength (2 bytes)
+ buffer.putUInt16((securityBuffer != null) ? securityBuffer.length : 0); // SecurityBufferLength (2 bytes)
buffer.putUInt64(previousSessionId); // PreviousSessionId (8 bytes)
- buffer.putRawBytes(securityBuffer); // SecurityBuffer (variable)
+ if (securityBuffer != null) {
+ buffer.putRawBytes(securityBuffer); // SecurityBuffer (variable)
+ }
}
@Override
@@ -71,7 +71,7 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
int securityBufferOffset = buffer.readUInt16(); // SecurityBufferOffset (2 bytes)
int securityBufferLength = buffer.readUInt16(); // SecurityBufferLength (2 bytes)
if (getHeader().getStatus() == NtStatus.STATUS_SUCCESS ||
- getHeader().getStatus() == NtStatus.STATUS_MORE_PROCESSING_REQUIRED) {
+ getHeader().getStatus() == NtStatus.STATUS_MORE_PROCESSING_REQUIRED) {
securityBuffer = readSecurityBuffer(buffer, securityBufferOffset, securityBufferLength); // SecurityBuffer (variable)
}
}
@@ -81,8 +81,10 @@ private byte[] readSecurityBuffer(SMBBuffer buffer, int securityBufferOffset, in
// Just to be sure, we should already be there.
buffer.rpos(securityBufferOffset);
return buffer.readRawBytes(securityBufferLength);
+ } else {
+ return new byte[0];
+// throw new SMBRuntimeException("The SMB2 Session Setup response should contain a positive length security buffer");
}
- throw new SMBRuntimeException("The SMB2 Session Setup response should contain a positive length security buffer");
}
private void putFlags(SMBBuffer buffer) {
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2SetInfoRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2SetInfoRequest.java
index 164d3d9c..9b234f4b 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2SetInfoRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2SetInfoRequest.java
@@ -33,10 +33,10 @@ public class SMB2SetInfoRequest extends SMB2Packet {
private final SecurityInformation securityInformation;
public SMB2SetInfoRequest(
- SMB2Dialect negotiatedDialect, long sessionId, long treeId,
- SMB2InfoType infoType, SMB2FileId fileId,
- FileInformationClass fileInfoClass,
- SecurityInformation securityInformation, byte[] buffer
+ SMB2Dialect negotiatedDialect, long sessionId, long treeId,
+ SMB2InfoType infoType, SMB2FileId fileId,
+ FileInformationClass fileInfoClass,
+ SecurityInformation securityInformation, byte[] buffer
) {
super(33, negotiatedDialect, SMB2MessageCommandCode.SMB2_SET_INFO, sessionId, treeId);
this.fileId = fileId;
@@ -47,7 +47,6 @@ public SMB2SetInfoRequest(
}
/**
- *
* @param smbBuffer
*/
@Override
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponse.java
index b4db2ac5..68d35950 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponse.java
@@ -15,19 +15,18 @@
*/
package com.hierynomus.mssmb2.messages;
+import java.util.EnumSet;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.mssmb2.SMB2ShareCapabilities;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smbj.common.SMBBuffer;
-import java.util.EnumSet;
-
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toEnumSet;
/**
* [MS-SMB2].pdf 2.2.10 SMB2 TREE_CONNECT Response
- *
+ *
* TODO
*/
public class SMB2TreeConnectResponse extends SMB2Packet {
@@ -38,7 +37,7 @@ public class SMB2TreeConnectResponse extends SMB2Packet {
private long maximalAccess;
public SMB2TreeConnectResponse() {
- super();
+ super();
}
@@ -56,6 +55,7 @@ protected void readMessage(SMBBuffer buffer) throws Buffer.BufferException {
/**
* Whether the ShareType returned is SMB2_SHARE_TYPE_DISK (0x01)
+ *
* @return true if the ShareType returned is SMB2_SHARE_TYPE_DISK (0x01)
*/
public boolean isDiskShare() {
@@ -64,6 +64,7 @@ public boolean isDiskShare() {
/**
* Whether the ShareType returned is SMB2_SHARE_TYPE_PIPE (0x02)
+ *
* @return true if the ShareType returned is SMB2_SHARE_TYPE_PIPE (0x02)
*/
public boolean isNamedPipe() {
@@ -72,6 +73,7 @@ public boolean isNamedPipe() {
/**
* Whether the ShareType returned is SMB2_SHARE_TYPE_PRINT (0x03)
+ *
* @return true if the ShareType returned is SMB2_SHARE_TYPE_PRINT (0x03)
*/
public boolean isPrinterShare() {
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteRequest.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteRequest.java
index 8fee9cc9..81a4b8c3 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteRequest.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteRequest.java
@@ -16,12 +16,11 @@
package com.hierynomus.mssmb2.messages;
import com.hierynomus.mssmb2.*;
-import com.hierynomus.smbj.io.ByteChunkProvider;
import com.hierynomus.smbj.common.SMBBuffer;
+import com.hierynomus.smbj.io.ByteChunkProvider;
/**
* [MS-SMB2].pdf 2.2.21 SMB2 Write Request
- *
*/
public class SMB2WriteRequest extends SMB2MultiCreditPacket {
diff --git a/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteResponse.java b/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteResponse.java
index cb4c6a78..ce1d304d 100644
--- a/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteResponse.java
+++ b/src/main/java/com/hierynomus/mssmb2/messages/SMB2WriteResponse.java
@@ -22,14 +22,13 @@
/**
* [MS-SMB2].pdf 2.2.22 SMB2 Write Response
- *
*/
public class SMB2WriteResponse extends SMB2Packet {
private long bytesWritten;
public SMB2WriteResponse() {
- super();
+ super();
}
diff --git a/src/main/java/com/hierynomus/ntlm/functions/NtlmFunctions.java b/src/main/java/com/hierynomus/ntlm/functions/NtlmFunctions.java
index 934b517f..989f6ef1 100644
--- a/src/main/java/com/hierynomus/ntlm/functions/NtlmFunctions.java
+++ b/src/main/java/com/hierynomus/ntlm/functions/NtlmFunctions.java
@@ -15,18 +15,17 @@
*/
package com.hierynomus.ntlm.functions;
-import com.hierynomus.msdtyp.MsDataTypes;
-import com.hierynomus.ntlm.NtlmException;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import com.hierynomus.protocol.commons.buffer.Endian;
-
-import javax.crypto.*;
-import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Arrays;
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+import com.hierynomus.msdtyp.MsDataTypes;
+import com.hierynomus.ntlm.NtlmException;
+import com.hierynomus.protocol.commons.buffer.Buffer;
+import com.hierynomus.protocol.commons.buffer.Endian;
/**
* NTLM Helper functions
@@ -155,7 +154,7 @@ public static byte[] LMOWFv1(String password, String username, String userDomain
/**
* [MS-NLMP].pdf 2.2.2.7 NTLM v2: NTLMv2_CLIENT_CHALLENGE
- *
+ *
* 3.3.2 NTLM v2 Authentication
* Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), Time, ClientChallenge, Z(4), ServerName, Z(4))
*
@@ -170,8 +169,8 @@ public static byte[] getNTLMv2ClientChallenge(byte[] targetInformation) {
long nowAsFileTime = MsDataTypes.nowAsFileTime();
byte[] l_targetInfo = (targetInformation == null) ? new byte[0] : targetInformation;
Buffer.PlainBuffer ccBuf = new Buffer.PlainBuffer(Endian.LE);
- ccBuf.putByte((byte)0x01); // RespType (1)
- ccBuf.putByte((byte)0x01); // HiRespType (1)
+ ccBuf.putByte((byte) 0x01); // RespType (1)
+ ccBuf.putByte((byte) 0x01); // HiRespType (1)
ccBuf.putUInt16(0); // Reserved1 (2)
ccBuf.putUInt32(0); // Reserved2 (4)
ccBuf.putLong(nowAsFileTime); // Timestamp (8)
@@ -184,9 +183,8 @@ public static byte[] getNTLMv2ClientChallenge(byte[] targetInformation) {
}
/**
- *
* 3.3.2 NTLM v2 Authentication
- *
+ *
* Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
* Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
*
@@ -211,7 +209,7 @@ public static byte[] encryptRc4(byte[] key, byte[] val) throws NtlmException {
try {
Cipher c = getRC4Cipher(key);
byte[] enc = c.doFinal(val);
- return enc;
+ return enc;
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new NtlmException(e);
}
@@ -223,7 +221,9 @@ public static SecureRandom getRandom() {
}
public static void setRandom(SecureRandom sRandom) {
- if (sRandom != null) secureRandom = sRandom;
+ if (sRandom != null) {
+ secureRandom = sRandom;
+ }
}
@@ -231,17 +231,17 @@ private static byte[] setupKey(byte[] key56) {
byte[] key = new byte[8];
key[0] = (byte) ((key56[0] >> 1) & 0xff);
key[1] = (byte) ((((key56[0] & 0x01) << 6)
- | (((key56[1] & 0xff) >> 2) & 0xff)) & 0xff);
+ | (((key56[1] & 0xff) >> 2) & 0xff)) & 0xff);
key[2] = (byte) ((((key56[1] & 0x03) << 5)
- | (((key56[2] & 0xff) >> 3) & 0xff)) & 0xff);
+ | (((key56[2] & 0xff) >> 3) & 0xff)) & 0xff);
key[3] = (byte) ((((key56[2] & 0x07) << 4)
- | (((key56[3] & 0xff) >> 4) & 0xff)) & 0xff);
+ | (((key56[3] & 0xff) >> 4) & 0xff)) & 0xff);
key[4] = (byte) ((((key56[3] & 0x0f) << 3)
- | (((key56[4] & 0xff) >> 5) & 0xff)) & 0xff);
+ | (((key56[4] & 0xff) >> 5) & 0xff)) & 0xff);
key[5] = (byte) ((((key56[4] & 0x1f) << 2)
- | (((key56[5] & 0xff) >> 6) & 0xff)) & 0xff);
+ | (((key56[5] & 0xff) >> 6) & 0xff)) & 0xff);
key[6] = (byte) ((((key56[5] & 0x3f) << 1)
- | (((key56[6] & 0xff) >> 7) & 0xff)) & 0xff);
+ | (((key56[6] & 0xff) >> 7) & 0xff)) & 0xff);
key[7] = (byte) (key56[6] & 0x7f);
for (int i = 0; i < key.length; i++) {
diff --git a/src/main/java/com/hierynomus/ntlm/messages/NtlmAuthenticate.java b/src/main/java/com/hierynomus/ntlm/messages/NtlmAuthenticate.java
index 4cff6b8e..8a6878ea 100644
--- a/src/main/java/com/hierynomus/ntlm/messages/NtlmAuthenticate.java
+++ b/src/main/java/com/hierynomus/ntlm/messages/NtlmAuthenticate.java
@@ -15,12 +15,11 @@
*/
package com.hierynomus.ntlm.messages;
+import java.nio.charset.StandardCharsets;
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.protocol.commons.buffer.Endian;
-import java.nio.charset.StandardCharsets;
-
import static com.hierynomus.ntlm.functions.NtlmFunctions.unicode;
/**
@@ -38,9 +37,9 @@ public class NtlmAuthenticate extends NtlmPacket {
private long negotiateFlags;
public NtlmAuthenticate(
- byte[] lmResponse, byte[] ntResponse,
- String userName, String domainName, String workstation,
- byte[] encryptedRandomSessionKey, long negotiateFlags
+ byte[] lmResponse, byte[] ntResponse,
+ String userName, String domainName, String workstation,
+ byte[] encryptedRandomSessionKey, long negotiateFlags
) {
super();
this.lmResponse = ensureNotNull(lmResponse);
@@ -92,16 +91,17 @@ public void write(Buffer.PlainBuffer buffer) {
/**
* MS-NLMP 2.2.2.10 VERSION
+ *
* @return
*/
public byte[] getVersion() {
Buffer.PlainBuffer plainBuffer = new Buffer.PlainBuffer(Endian.LE);
- plainBuffer.putByte((byte)0x06); // Major Version 6
- plainBuffer.putByte((byte)0x01); // Minor Version 1
+ plainBuffer.putByte((byte) 0x06); // Major Version 6
+ plainBuffer.putByte((byte) 0x01); // Minor Version 1
plainBuffer.putUInt16(7600); // Product Build 7600
- byte[] reserved = {(byte)0x00, (byte)0x00, (byte)0x00};
+ byte[] reserved = {(byte) 0x00, (byte) 0x00, (byte) 0x00};
plainBuffer.putRawBytes(reserved); // Reserver 3 bytes
- plainBuffer.putByte((byte)0x0F); // NTLM Revision Current
+ plainBuffer.putByte((byte) 0x0F); // NTLM Revision Current
return plainBuffer.getCompactData();
}
diff --git a/src/main/java/com/hierynomus/ntlm/messages/NtlmChallenge.java b/src/main/java/com/hierynomus/ntlm/messages/NtlmChallenge.java
index bd4cffb0..6f7d294e 100644
--- a/src/main/java/com/hierynomus/ntlm/messages/NtlmChallenge.java
+++ b/src/main/java/com/hierynomus/ntlm/messages/NtlmChallenge.java
@@ -15,16 +15,15 @@
*/
package com.hierynomus.ntlm.messages;
-import com.hierynomus.msdtyp.MsDataTypes;
-import com.hierynomus.protocol.commons.EnumWithValue;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.msdtyp.MsDataTypes;
+import com.hierynomus.protocol.commons.EnumWithValue;
+import com.hierynomus.protocol.commons.buffer.Buffer;
/**
* [MS-NLMP].pdf 2.2.1.2 CHALLENGE_MESSAGE
diff --git a/src/main/java/com/hierynomus/ntlm/messages/NtlmNegotiate.java b/src/main/java/com/hierynomus/ntlm/messages/NtlmNegotiate.java
index 8caadd8e..7d4bb535 100644
--- a/src/main/java/com/hierynomus/ntlm/messages/NtlmNegotiate.java
+++ b/src/main/java/com/hierynomus/ntlm/messages/NtlmNegotiate.java
@@ -15,29 +15,38 @@
*/
package com.hierynomus.ntlm.messages;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
+import com.hierynomus.protocol.commons.buffer.Buffer;
-import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.*;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.EnumUtils;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_128;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_56;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_KEY_EXCH;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_NTLM;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_SIGN;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_TARGET_INFO;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_UNICODE;
+import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_REQUEST_TARGET;
/**
* [MS-NLMP].pdf 2.2.1.1 NEGOTIATE_MESSAGE
*/
public class NtlmNegotiate extends NtlmPacket {
- public static final long DEFAULT_FLAGS = EnumUtils.toLong(EnumSet.of(
- NTLMSSP_NEGOTIATE_56,
- NTLMSSP_NEGOTIATE_128,
- NTLMSSP_NEGOTIATE_TARGET_INFO,
- NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY,
- NTLMSSP_NEGOTIATE_SIGN,
- NTLMSSP_NEGOTIATE_ALWAYS_SIGN,
- NTLMSSP_NEGOTIATE_KEY_EXCH,
- NTLMSSP_NEGOTIATE_NTLM,
- NTLMSSP_NEGOTIATE_NTLM,
- NTLMSSP_REQUEST_TARGET,
- NTLMSSP_NEGOTIATE_UNICODE));
+ public static final long DEFAULT_FLAGS = EnumUtils.toLong(EnumSet.of(
+ NTLMSSP_NEGOTIATE_56,
+ NTLMSSP_NEGOTIATE_128,
+ NTLMSSP_NEGOTIATE_TARGET_INFO,
+ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY,
+ NTLMSSP_NEGOTIATE_SIGN,
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN,
+ NTLMSSP_NEGOTIATE_KEY_EXCH,
+ NTLMSSP_NEGOTIATE_NTLM,
+ NTLMSSP_NEGOTIATE_NTLM,
+ NTLMSSP_REQUEST_TARGET,
+ NTLMSSP_NEGOTIATE_UNICODE));
private long flags = DEFAULT_FLAGS;
diff --git a/src/main/java/com/hierynomus/protocol/commons/Base64.java b/src/main/java/com/hierynomus/protocol/commons/Base64.java
index 60b505da..98780c8f 100644
--- a/src/main/java/com/hierynomus/protocol/commons/Base64.java
+++ b/src/main/java/com/hierynomus/protocol/commons/Base64.java
@@ -32,7 +32,7 @@ public class Base64 {
* @since 1.3
*/
public static class InputStream
- extends java.io.FilterInputStream {
+ extends java.io.FilterInputStream {
private final boolean encode; // Encoding or decoding
private int position; // Current position in the buffer
@@ -97,7 +97,7 @@ public InputStream(java.io.InputStream in, int options) {
*/
@Override
public int read()
- throws java.io.IOException {
+ throws java.io.IOException {
// Do we need to get data?
if (position < 0)
@@ -194,7 +194,7 @@ else if (i == 0)
*/
@Override
public int read(byte[] dest, int off, int len)
- throws java.io.IOException {
+ throws java.io.IOException {
int i;
int b;
for (i = 0; i < len; i++) {
@@ -220,7 +220,7 @@ else if (i == 0)
* @since 1.3
*/
public static class OutputStream
- extends java.io.FilterOutputStream {
+ extends java.io.FilterOutputStream {
private final boolean encode;
private int position;
@@ -286,7 +286,7 @@ public OutputStream(java.io.OutputStream out, int options) {
*/
@Override
public void close()
- throws java.io.IOException {
+ throws java.io.IOException {
// 1. Ensure that pending characters are written
flush();
@@ -306,7 +306,7 @@ public void close()
*/
@Override
public void flush()
- throws java.io.IOException {
+ throws java.io.IOException {
flushBase64();
super.flush();
}
@@ -317,7 +317,7 @@ public void flush()
* @throws java.io.IOException if there's an error.
*/
public void flushBase64()
- throws java.io.IOException {
+ throws java.io.IOException {
if (position > 0)
if (encode) {
out.write(encode3to4(b4, buffer, position, options));
@@ -346,7 +346,7 @@ public void resumeEncoding() {
* @since 1.5.1
*/
public void suspendEncoding()
- throws java.io.IOException {
+ throws java.io.IOException {
flushBase64();
suspendEncoding = true;
} // end suspendEncoding
@@ -361,7 +361,7 @@ public void suspendEncoding()
*/
@Override
public void write(byte[] theBytes, int off, int len)
- throws java.io.IOException {
+ throws java.io.IOException {
// Encoding suspended?
if (suspendEncoding) {
super.out.write(theBytes, off, len);
@@ -383,7 +383,7 @@ public void write(byte[] theBytes, int off, int len)
*/
@Override
public void write(int theByte)
- throws java.io.IOException {
+ throws java.io.IOException {
// Encoding suspended?
if (suspendEncoding) {
super.out.write(theByte);
@@ -494,40 +494,40 @@ else if (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC)
*/
/* Host platform me be something funny like EBCDIC, so we hardcode these values. */
private final static byte[] _STANDARD_ALPHABET = {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
- (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
- (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
- (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
- (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
- (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
- (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
- (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'};
+ (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
+ (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
+ (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
+ (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
+ (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
+ (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/'};
/**
* Translates a Base64 value to either its 6-bit reconstruction value or a negative number indicating some other
* meaning.
*/
private final static byte[] _STANDARD_DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal
- // 0 - 8
- -5, -5, // Whitespace: Tab and Linefeed
- -9, -9, // Decimal 11 - 12
- -5, // Whitespace: Carriage Return
- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
- -9, -9, -9, -9, -9, // Decimal 27 - 31
- -5, // Whitespace: Space
- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
- 62, // Plus sign at decimal 43
- -9, -9, -9, // Decimal 44 - 46
- 63, // Slash at decimal 47
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
- -9, -9, -9, // Decimal 58 - 60
- -1, // Equals sign at decimal 61
- -9, -9, -9, // Decimal 62 - 64
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
- 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
- -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
- 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
- -9, -9, -9, -9 // Decimal 123 - 126
+ // 0 - 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ 62, // Plus sign at decimal 43
+ -9, -9, -9, // Decimal 44 - 46
+ 63, // Slash at decimal 47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
+ -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
+ -9, -9, -9, -9 // Decimal 123 - 126
/*
* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
* -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
@@ -550,43 +550,43 @@ else if (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC)
* bytes become "hyphen" and "underscore" instead of "plus" and "slash."
*/
private final static byte[] _URL_SAFE_ALPHABET = {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
- (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
- (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
- (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
- (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
- (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
- (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
- (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_'};
+ (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
+ (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
+ (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
+ (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
+ (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
+ (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_'};
/**
* Used in decoding URL- and Filename-safe dialects of Base64.
*/
private final static byte[] _URL_SAFE_DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal
- // 0 - 8
- -5, -5, // Whitespace: Tab and Linefeed
- -9, -9, // Decimal 11 - 12
- -5, // Whitespace: Carriage Return
- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
- -9, -9, -9, -9, -9, // Decimal 27 - 31
- -5, // Whitespace: Space
- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
- -9, // Plus sign at decimal 43
- -9, // Decimal 44
- 62, // Minus sign at decimal 45
- -9, // Decimal 46
- -9, // Slash at decimal 47
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
- -9, -9, -9, // Decimal 58 - 60
- -1, // Equals sign at decimal 61
- -9, -9, -9, // Decimal 62 - 64
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
- 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
- -9, -9, -9, -9, // Decimal 91 - 94
- 63, // Underscore at decimal 95
- -9, // Decimal 96
- 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
- 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
- -9, -9, -9, -9 // Decimal 123 - 126
+ // 0 - 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 62, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
+ -9, -9, -9, -9, // Decimal 91 - 94
+ 63, // Underscore at decimal 95
+ -9, // Decimal 96
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
+ -9, -9, -9, -9 // Decimal 123 - 126
/*
* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
* -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
@@ -608,43 +608,43 @@ else if (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC)
* href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html.
*/
private final static byte[] _ORDERED_ALPHABET = {(byte) '-', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
- (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C',
- (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
- (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
- (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a', (byte) 'b', (byte) 'c',
- (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
- (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
- (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z'};
+ (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C',
+ (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
+ (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
+ (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a', (byte) 'b', (byte) 'c',
+ (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
+ (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+ (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z'};
/**
* Used in decoding the "ordered" dialect of Base64.
*/
private final static byte[] _ORDERED_DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal
- // 0 - 8
- -5, -5, // Whitespace: Tab and Linefeed
- -9, -9, // Decimal 11 - 12
- -5, // Whitespace: Carriage Return
- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
- -9, -9, -9, -9, -9, // Decimal 27 - 31
- -5, // Whitespace: Space
- -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
- -9, // Plus sign at decimal 43
- -9, // Decimal 44
- 0, // Minus sign at decimal 45
- -9, // Decimal 46
- -9, // Slash at decimal 47
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine
- -9, -9, -9, // Decimal 58 - 60
- -1, // Equals sign at decimal 61
- -9, -9, -9, // Decimal 62 - 64
- 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M'
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z'
- -9, -9, -9, -9, // Decimal 91 - 94
- 37, // Underscore at decimal 95
- -9, // Decimal 96
- 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm'
- 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z'
- -9, -9, -9, -9 // Decimal 123 - 126
+ // 0 - 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 0, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M'
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z'
+ -9, -9, -9, -9, // Decimal 91 - 94
+ 37, // Underscore at decimal 95
+ -9, // Decimal 96
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm'
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z'
+ -9, -9, -9, -9 // Decimal 123 - 126
/*
* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
* -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
@@ -696,21 +696,21 @@ public static byte[] decode(byte[] source) {
* @since 1.3
*/
public static byte[] decode(byte[] source, int off, int len, int options)
- throws java.io.IOException {
+ throws java.io.IOException {
// Lots of error checking and exception throwing
if (source == null)
throw new NullPointerException("Cannot decode null source array.");
if (off < 0 || off + len > source.length)
throw new IllegalArgumentException(String.format(
- "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off,
- len));
+ "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off,
+ len));
if (len == 0)
return new byte[0];
else if (len < 4)
throw new IllegalArgumentException(
- "Base64-encoded string must have at least four characters, but length specified was " + len);
+ "Base64-encoded string must have at least four characters, but length specified was " + len);
byte[] DECODABET = getDecodabet(options);
@@ -748,7 +748,7 @@ else if (len < 4)
else
// There's a bad input character in the Base64 stream.
throw new java.io.IOException(String.format("Bad Base64 input character '%c' in array position %d",
- source[i], i));
+ source[i], i));
} // each input character
byte[] out = new byte[outBuffPosn];
@@ -765,7 +765,7 @@ else if (len < 4)
* @since 1.4
*/
public static byte[] decode(String s)
- throws java.io.IOException {
+ throws java.io.IOException {
return decode(s, NO_OPTIONS);
}
@@ -780,7 +780,7 @@ public static byte[] decode(String s)
* @since 1.4
*/
public static byte[] decode(String s, int options)
- throws java.io.IOException {
+ throws java.io.IOException {
if (s == null)
throw new NullPointerException("Input string was null.");
@@ -854,7 +854,7 @@ public static byte[] decode(String s, int options)
* @since 2.2
*/
public static void decodeFileToFile(String infile, String outfile)
- throws java.io.IOException {
+ throws java.io.IOException {
byte[] decoded = Base64.decodeFromFile(infile);
java.io.OutputStream out = null;
@@ -884,7 +884,7 @@ public static void decodeFileToFile(String infile, String outfile)
* @since 2.1
*/
public static byte[] decodeFromFile(String filename)
- throws java.io.IOException {
+ throws java.io.IOException {
byte[] decodedData = null;
Base64.InputStream bis = null;
@@ -898,12 +898,12 @@ public static byte[] decodeFromFile(String filename)
// Check for size of file
if (file.length() > Integer.MAX_VALUE)
throw new java.io.IOException("File is too big for this convenience method (" + file.length()
- + " bytes).");
+ + " bytes).");
buffer = new byte[(int) file.length()];
// Open a stream
bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)),
- Base64.DECODE);
+ Base64.DECODE);
// Read until done
while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
@@ -938,7 +938,7 @@ public static byte[] decodeFromFile(String filename)
* @since 2.1
*/
public static void decodeToFile(String dataToDecode, String filename)
- throws java.io.IOException {
+ throws java.io.IOException {
Base64.OutputStream bos = null;
try {
@@ -969,8 +969,8 @@ public static void decodeToFile(String dataToDecode, String filename)
* @since 1.5
*/
public static Object decodeToObject(String encodedObject)
- throws java.io.IOException,
- java.lang.ClassNotFoundException {
+ throws java.io.IOException,
+ java.lang.ClassNotFoundException {
// Decode and gunzip if necessary
byte[] objBytes = decode(encodedObject);
@@ -1092,7 +1092,7 @@ public static String encodeBytes(byte[] source) {
* @since 2.0
*/
public static String encodeBytes(byte[] source, int options)
- throws java.io.IOException {
+ throws java.io.IOException {
return encodeBytes(source, 0, source.length, options);
} // end encodeBytes
@@ -1148,7 +1148,7 @@ public static String encodeBytes(byte[] source, int off, int len) {
* @since 2.0
*/
public static String encodeBytes(byte[] source, int off, int len, int options)
- throws java.io.IOException {
+ throws java.io.IOException {
byte[] encoded = encodeBytesToBytes(source, off, len, options);
// Return value according to relevant encoding.
@@ -1197,7 +1197,7 @@ public static byte[] encodeBytesToBytes(byte[] source) {
* @since 2.3.1
*/
public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options)
- throws java.io.IOException {
+ throws java.io.IOException {
if (source == null)
throw new NullPointerException("Cannot serialize a null array.");
@@ -1210,7 +1210,7 @@ public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int opt
if (off + len > source.length)
throw new IllegalArgumentException(String.format(
- "Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
+ "Cannot have offset of %d and length of %d with array of length %d", off, len, source.length));
// Compress?
if ((options & GZIP) > 0) {
@@ -1310,7 +1310,7 @@ public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int opt
* @since 2.2
*/
public static void encodeFileToFile(String infile, String outfile)
- throws java.io.IOException {
+ throws java.io.IOException {
String encoded = Base64.encodeFromFile(infile);
java.io.OutputStream out = null;
@@ -1340,7 +1340,7 @@ public static void encodeFileToFile(String infile, String outfile)
* @since 2.1
*/
public static String encodeFromFile(String filename)
- throws java.io.IOException {
+ throws java.io.IOException {
String encodedData = null;
Base64.InputStream bis = null;
@@ -1355,7 +1355,7 @@ public static String encodeFromFile(String filename)
// Open a stream
bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)),
- Base64.ENCODE);
+ Base64.ENCODE);
// Read until done
while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
@@ -1393,7 +1393,7 @@ public static String encodeFromFile(String filename)
* @since 1.4
*/
public static String encodeObject(java.io.Serializable serializableObject)
- throws java.io.IOException {
+ throws java.io.IOException {
return encodeObject(serializableObject, NO_OPTIONS);
} // end encodeObject
@@ -1425,7 +1425,7 @@ public static String encodeObject(java.io.Serializable serializableObject)
* @since 2.0
*/
public static String encodeObject(java.io.Serializable serializableObject, int options)
- throws java.io.IOException {
+ throws java.io.IOException {
if (serializableObject == null)
throw new NullPointerException("Cannot serialize a null object.");
@@ -1486,7 +1486,7 @@ public static String encodeObject(java.io.Serializable serializableObject, int o
* @since 2.1
*/
public static void encodeToFile(byte[] dataToEncode, String filename)
- throws java.io.IOException {
+ throws java.io.IOException {
if (dataToEncode == null)
throw new NullPointerException("Data to encode was null.");
@@ -1536,12 +1536,12 @@ private static int decode4to3(byte[] source, int srcOffset, byte[] destination,
throw new NullPointerException("Destination array was null.");
if (srcOffset < 0 || srcOffset + 3 >= source.length)
throw new IllegalArgumentException(String.format(
- "Source array with length %d cannot have offset of %d and still process four bytes.",
- source.length, srcOffset));
+ "Source array with length %d cannot have offset of %d and still process four bytes.",
+ source.length, srcOffset));
if (destOffset < 0 || destOffset + 2 >= destination.length)
throw new IllegalArgumentException(String.format(
- "Destination array with length %d cannot have offset of %d and still store three bytes.",
- destination.length, destOffset));
+ "Destination array with length %d cannot have offset of %d and still store three bytes.",
+ destination.length, destOffset));
byte[] DECODABET = getDecodabet(options);
@@ -1563,7 +1563,7 @@ else if (source[srcOffset + 3] == EQUALS_SIGN) {
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
int outBuff = (DECODABET[source[srcOffset]] & 0xFF) << 18 | (DECODABET[source[srcOffset + 1]] & 0xFF) << 12
- | (DECODABET[source[srcOffset + 2]] & 0xFF) << 6;
+ | (DECODABET[source[srcOffset + 2]] & 0xFF) << 6;
destination[destOffset] = (byte) (outBuff >>> 16);
destination[destOffset + 1] = (byte) (outBuff >>> 8);
@@ -1578,7 +1578,7 @@ else if (source[srcOffset + 3] == EQUALS_SIGN) {
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
// | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
int outBuff = (DECODABET[source[srcOffset]] & 0xFF) << 18 | (DECODABET[source[srcOffset + 1]] & 0xFF) << 12
- | (DECODABET[source[srcOffset + 2]] & 0xFF) << 6 | DECODABET[source[srcOffset + 3]] & 0xFF;
+ | (DECODABET[source[srcOffset + 2]] & 0xFF) << 6 | DECODABET[source[srcOffset + 3]] & 0xFF;
destination[destOffset] = (byte) (outBuff >> 16);
destination[destOffset + 1] = (byte) (outBuff >> 8);
@@ -1639,8 +1639,8 @@ private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes,
// We have to shift left 24 in order to flush out the 1's that appear
// when Java treats a value as negative that is cast from a byte to an int.
int inBuff = (numSigBytes > 0 ? source[srcOffset] << 24 >>> 8 : 0)
- | (numSigBytes > 1 ? source[srcOffset + 1] << 24 >>> 16 : 0)
- | (numSigBytes > 2 ? source[srcOffset + 2] << 24 >>> 24 : 0);
+ | (numSigBytes > 1 ? source[srcOffset + 1] << 24 >>> 16 : 0)
+ | (numSigBytes > 2 ? source[srcOffset + 2] << 24 >>> 24 : 0);
switch (numSigBytes) {
case 3:
diff --git a/src/main/java/com/hierynomus/protocol/commons/ByteArrayUtils.java b/src/main/java/com/hierynomus/protocol/commons/ByteArrayUtils.java
index d67fcc33..3d1fccb0 100644
--- a/src/main/java/com/hierynomus/protocol/commons/ByteArrayUtils.java
+++ b/src/main/java/com/hierynomus/protocol/commons/ByteArrayUtils.java
@@ -15,7 +15,9 @@
*/
package com.hierynomus.protocol.commons;
-/** Utility functions for byte arrays. */
+/**
+ * Utility functions for byte arrays.
+ */
public class ByteArrayUtils {
final static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
@@ -29,7 +31,6 @@ public class ByteArrayUtils {
* @param a2
* @param a2Offset
* @param length
- *
* @return true
or false
*/
public static boolean equals(byte[] a1, final int a1Offset, byte[] a2, final int a2Offset, final int length) {
@@ -48,7 +49,6 @@ public static boolean equals(byte[] a1, final int a1Offset, byte[] a2, final int
* Get a hexadecimal representation of the full byte array, with each octet separated by a space.
*
* @param array
- *
* @return hex string, each octet delimited by a space
*/
public static String printHex(byte[] array) {
@@ -62,7 +62,6 @@ public static String printHex(byte[] array) {
* @param array
* @param offset
* @param len
- *
* @return hex string, each octet delimited by a space
*/
public static String printHex(byte[] array, int offset, int len) {
@@ -81,7 +80,6 @@ public static String printHex(byte[] array, int offset, int len) {
* Get the hexadecimal representation of a byte array.
*
* @param array
- *
* @return hex string
*/
public static String toHex(byte[] array) {
@@ -95,7 +93,6 @@ public static String toHex(byte[] array) {
* @param array
* @param offset
* @param len
- *
* @return hex string
*/
public static String toHex(byte[] array, int offset, int len) {
diff --git a/src/main/java/com/hierynomus/protocol/commons/Factory.java b/src/main/java/com/hierynomus/protocol/commons/Factory.java
index eb73d3e8..bd063332 100644
--- a/src/main/java/com/hierynomus/protocol/commons/Factory.java
+++ b/src/main/java/com/hierynomus/protocol/commons/Factory.java
@@ -32,7 +32,7 @@ public interface Factory {
* @param type of object created by this factory
*/
interface Named
- extends Factory {
+ extends Factory {
/**
* Utility functions
diff --git a/src/main/java/com/hierynomus/protocol/commons/IOUtils.java b/src/main/java/com/hierynomus/protocol/commons/IOUtils.java
index 91d9533b..9ae7deb6 100644
--- a/src/main/java/com/hierynomus/protocol/commons/IOUtils.java
+++ b/src/main/java/com/hierynomus/protocol/commons/IOUtils.java
@@ -15,11 +15,10 @@
*/
package com.hierynomus.protocol.commons;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.Closeable;
import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class IOUtils {
diff --git a/src/main/java/com/hierynomus/protocol/commons/backport/Jdk7HttpProxySocket.java b/src/main/java/com/hierynomus/protocol/commons/backport/Jdk7HttpProxySocket.java
index 9618ed24..c64982d5 100644
--- a/src/main/java/com/hierynomus/protocol/commons/backport/Jdk7HttpProxySocket.java
+++ b/src/main/java/com/hierynomus/protocol/commons/backport/Jdk7HttpProxySocket.java
@@ -55,7 +55,7 @@ private void connectHttpProxy(SocketAddress endpoint, int timeout) throws IOExce
checkAndFlushProxyResponse();
}
- private void checkAndFlushProxyResponse()throws IOException {
+ private void checkAndFlushProxyResponse() throws IOException {
InputStream socketInput = getInputStream();
byte[] tmpBuffer = new byte[512];
int len = socketInput.read(tmpBuffer, 0, tmpBuffer.length);
diff --git a/src/main/java/com/hierynomus/protocol/commons/buffer/Buffer.java b/src/main/java/com/hierynomus/protocol/commons/buffer/Buffer.java
index 739bd4e4..25272b50 100644
--- a/src/main/java/com/hierynomus/protocol/commons/buffer/Buffer.java
+++ b/src/main/java/com/hierynomus/protocol/commons/buffer/Buffer.java
@@ -15,20 +15,19 @@
*/
package com.hierynomus.protocol.commons.buffer;
-import com.hierynomus.protocol.commons.ByteArrayUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.protocol.commons.ByteArrayUtils;
public class Buffer> {
private static final Logger logger = LoggerFactory.getLogger(Buffer.class);
public static class BufferException
- extends Exception {
+ extends Exception {
public BufferException(String message) {
super(message);
@@ -179,7 +178,7 @@ public void wpos(int wpos) {
* @throws BufferException If there are less than a
bytes available
*/
protected void ensureAvailable(int a)
- throws BufferException {
+ throws BufferException {
if (available() < a) {
throw new BufferException("Underflow");
}
@@ -229,7 +228,7 @@ public byte[] getCompactData() {
* @return the {@code true} or {@code false} value read
*/
public boolean readBoolean()
- throws BufferException {
+ throws BufferException {
return readByte() != 0;
}
@@ -249,7 +248,7 @@ public Buffer putBoolean(boolean b) {
* @return the byte read
*/
public byte readByte()
- throws BufferException {
+ throws BufferException {
ensureAvailable(1);
return data[rpos++];
}
@@ -286,7 +285,7 @@ public byte[] readRawBytes(int length) throws BufferException {
* @throws BufferException If the read operation would cause an underflow (less bytes available than array size)
*/
public void readRawBytes(byte[] buf)
- throws BufferException {
+ throws BufferException {
readRawBytes(buf, 0, buf.length);
}
@@ -299,7 +298,7 @@ public void readRawBytes(byte[] buf)
* @throws BufferException If the read operation would cause an underflow (less than length bytes available)
*/
public void readRawBytes(byte[] buf, int offset, int length)
- throws BufferException {
+ throws BufferException {
ensureAvailable(length);
System.arraycopy(data, rpos, buf, offset, length);
rpos += length;
@@ -530,8 +529,9 @@ public Buffer putUInt64(long uint64, Endian endianness) {
/**
* Writes a long in the buffer's endianness.
- *
+ *
* Note: unlike a uint64, a long can be negative.
+ *
* @param longVal
* @return this
*/
@@ -541,8 +541,9 @@ public Buffer putLong(long longVal) {
/**
* Writes a long in the specified endianness.
- *
+ *
* Note: unlike a uint64, a long can be negative or overflowed.
+ *
* @param longVal
* @return this
*/
diff --git a/src/main/java/com/hierynomus/protocol/commons/buffer/Endian.java b/src/main/java/com/hierynomus/protocol/commons/buffer/Endian.java
index 5d151bb9..2d965512 100644
--- a/src/main/java/com/hierynomus/protocol/commons/buffer/Endian.java
+++ b/src/main/java/com/hierynomus/protocol/commons/buffer/Endian.java
@@ -41,7 +41,7 @@ public > void writeUInt16(Buffer buffer, int uint16) {
public > int readUInt16(Buffer buffer) throws Buffer.BufferException {
buffer.ensureAvailable(2);
return buffer.data[buffer.rpos++] << 8 & 0xFF00 |
- buffer.data[buffer.rpos++] & 0x00FF;
+ buffer.data[buffer.rpos++] & 0x00FF;
}
@Override
@@ -58,8 +58,8 @@ public > void writeUInt24(Buffer buffer, int uint24) {
public > int readUInt24(Buffer buffer) throws Buffer.BufferException {
buffer.ensureAvailable(3);
return buffer.data[buffer.rpos++] << 16 & 0xFF0000 |
- buffer.data[buffer.rpos++] << 8 & 0x00FF00 |
- buffer.data[buffer.rpos++] & 0x0000FF;
+ buffer.data[buffer.rpos++] << 8 & 0x00FF00 |
+ buffer.data[buffer.rpos++] & 0x0000FF;
}
@Override
@@ -77,9 +77,9 @@ public > void writeUInt32(Buffer buffer, long uint32) {
public > long readUInt32(Buffer buffer) throws Buffer.BufferException {
buffer.ensureAvailable(4);
return buffer.data[buffer.rpos++] << 24 & 0xFF000000L |
- buffer.data[buffer.rpos++] << 16 & 0x00FF0000L |
- buffer.data[buffer.rpos++] << 8 & 0x0000FF00L |
- buffer.data[buffer.rpos++] & 0x000000FFL;
+ buffer.data[buffer.rpos++] << 16 & 0x00FF0000L |
+ buffer.data[buffer.rpos++] << 8 & 0x0000FF00L |
+ buffer.data[buffer.rpos++] & 0x000000FFL;
}
@Override
@@ -155,7 +155,7 @@ public > void writeUInt16(Buffer buffer, int uint16) {
public > int readUInt16(Buffer buffer) throws Buffer.BufferException {
buffer.ensureAvailable(2);
return buffer.data[buffer.rpos++] & 0x00FF |
- buffer.data[buffer.rpos++] << 8 & 0xFF00;
+ buffer.data[buffer.rpos++] << 8 & 0xFF00;
}
@Override
@@ -173,8 +173,8 @@ public > void writeUInt24(Buffer buffer, int uint24) {
public > int readUInt24(Buffer buffer) throws Buffer.BufferException {
buffer.ensureAvailable(3);
return buffer.data[buffer.rpos++] & 0x0000FF |
- buffer.data[buffer.rpos++] << 8 & 0x00FF00 |
- buffer.data[buffer.rpos++] << 16 & 0xFF0000;
+ buffer.data[buffer.rpos++] << 8 & 0x00FF00 |
+ buffer.data[buffer.rpos++] << 16 & 0xFF0000;
}
@Override
@@ -193,9 +193,9 @@ public > void writeUInt32(Buffer buffer, long uint32) {
public > long readUInt32(Buffer buffer) throws Buffer.BufferException {
buffer.ensureAvailable(4);
return buffer.data[buffer.rpos++] & 0x000000FFL |
- buffer.data[buffer.rpos++] << 8 & 0x0000FF00L |
- buffer.data[buffer.rpos++] << 16 & 0x00FF0000L |
- buffer.data[buffer.rpos++] << 24 & 0xFF000000L;
+ buffer.data[buffer.rpos++] << 8 & 0x0000FF00L |
+ buffer.data[buffer.rpos++] << 16 & 0x00FF0000L |
+ buffer.data[buffer.rpos++] << 24 & 0xFF000000L;
}
@Override
diff --git a/src/main/java/com/hierynomus/protocol/commons/concurrent/Promise.java b/src/main/java/com/hierynomus/protocol/commons/concurrent/Promise.java
index 88b012dd..a3286710 100644
--- a/src/main/java/com/hierynomus/protocol/commons/concurrent/Promise.java
+++ b/src/main/java/com/hierynomus/protocol/commons/concurrent/Promise.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.protocol.commons.concurrent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Represents promised data of the parameterized type {@code V} and allows waiting on it. An exception may also be
@@ -121,7 +120,7 @@ public void clear() {
* @throws T in case another thread informs the promise of an error meanwhile
*/
public V retrieve()
- throws T {
+ throws T {
return tryRetrieve(0, TimeUnit.SECONDS);
}
@@ -134,7 +133,7 @@ public V retrieve()
* @throws T in case another thread informs the promise of an error meanwhile, or the timeout expires
*/
public V retrieve(long timeout, TimeUnit unit)
- throws T {
+ throws T {
final V value = tryRetrieve(timeout, unit);
if (value == null)
throw wrapper.wrap(new TimeoutException("Timeout expired"));
@@ -153,7 +152,7 @@ public V retrieve(long timeout, TimeUnit unit)
* @throws T in case another thread informs the promise of an error meanwhile
*/
public V tryRetrieve(long timeout, TimeUnit unit)
- throws T {
+ throws T {
lock.lock();
try {
if (pendingEx != null)
diff --git a/src/main/java/com/hierynomus/protocol/commons/socket/ProxySocketFactory.java b/src/main/java/com/hierynomus/protocol/commons/socket/ProxySocketFactory.java
index 985f17d0..375c691c 100644
--- a/src/main/java/com/hierynomus/protocol/commons/socket/ProxySocketFactory.java
+++ b/src/main/java/com/hierynomus/protocol/commons/socket/ProxySocketFactory.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.protocol.commons.socket;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.SocketFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
+import javax.net.SocketFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ProxySocketFactory extends SocketFactory {
private static final Logger logger = LoggerFactory.getLogger(ProxySocketFactory.class);
diff --git a/src/main/java/com/hierynomus/protocol/commons/socket/SocketClient.java b/src/main/java/com/hierynomus/protocol/commons/socket/SocketClient.java
index 78fe7655..4d04b649 100644
--- a/src/main/java/com/hierynomus/protocol/commons/socket/SocketClient.java
+++ b/src/main/java/com/hierynomus/protocol/commons/socket/SocketClient.java
@@ -15,14 +15,17 @@
*/
package com.hierynomus.protocol.commons.socket;
-import javax.net.SocketFactory;
+import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
+import javax.net.SocketFactory;
public abstract class SocketClient {
+ private static final int INITIAL_BUFFER_SIZE = 9000; // Size of a Jumbo frame.
+
private final int defaultPort;
private Socket socket;
@@ -115,7 +118,7 @@ protected OutputStream getOutputStream() {
protected void onConnect() throws IOException {
socket.setSoTimeout(soTimeout);
input = socket.getInputStream();
- output = socket.getOutputStream();
+ output = new BufferedOutputStream(socket.getOutputStream(), INITIAL_BUFFER_SIZE);
}
public int getRemotePort() {
diff --git a/src/main/java/com/hierynomus/smbj/Config.java b/src/main/java/com/hierynomus/smbj/Config.java
index 9f7f67d4..d83c7afa 100644
--- a/src/main/java/com/hierynomus/smbj/Config.java
+++ b/src/main/java/com/hierynomus/smbj/Config.java
@@ -15,11 +15,13 @@
*/
package com.hierynomus.smbj;
-import com.hierynomus.mssmb2.SMB2Dialect;
-
import java.util.EnumSet;
+import java.util.List;
import java.util.Random;
import java.util.UUID;
+import com.hierynomus.mssmb2.SMB2Dialect;
+import com.hierynomus.protocol.commons.Factory;
+import com.hierynomus.smbj.auth.Authenticator;
public interface Config {
@@ -27,5 +29,13 @@ public interface Config {
EnumSet getSupportedDialects();
+ List> getSupportedAuthenticators();
+
UUID getClientGuid();
+
+ /**
+ * enforces message signing. When message signing is enforced a received message that is not signed properly
+ * will be dropped.
+ */
+ boolean isStrictSigning();
}
diff --git a/src/main/java/com/hierynomus/smbj/ConfigImpl.java b/src/main/java/com/hierynomus/smbj/ConfigImpl.java
index 7166d935..4176879e 100644
--- a/src/main/java/com/hierynomus/smbj/ConfigImpl.java
+++ b/src/main/java/com/hierynomus/smbj/ConfigImpl.java
@@ -15,17 +15,21 @@
*/
package com.hierynomus.smbj;
-import com.hierynomus.mssmb2.SMB2Dialect;
-
import java.util.EnumSet;
+import java.util.List;
import java.util.Random;
import java.util.UUID;
+import com.hierynomus.mssmb2.SMB2Dialect;
+import com.hierynomus.protocol.commons.Factory;
+import com.hierynomus.smbj.auth.Authenticator;
public class ConfigImpl implements Config {
protected EnumSet dialects;
+ protected List> authenticators;
protected Random random;
protected UUID clientGuid;
+ protected boolean isStrictSigning;
@Override
public Random getRandomProvider() {
@@ -41,4 +45,14 @@ public EnumSet getSupportedDialects() {
public UUID getClientGuid() {
return clientGuid;
}
+
+ @Override
+ public boolean isStrictSigning() {
+ return isStrictSigning;
+ }
+
+ @Override
+ public List> getSupportedAuthenticators() {
+ return authenticators;
+ }
}
diff --git a/src/main/java/com/hierynomus/smbj/DefaultConfig.java b/src/main/java/com/hierynomus/smbj/DefaultConfig.java
index 24cb7179..35fbcabd 100644
--- a/src/main/java/com/hierynomus/smbj/DefaultConfig.java
+++ b/src/main/java/com/hierynomus/smbj/DefaultConfig.java
@@ -15,17 +15,31 @@
*/
package com.hierynomus.smbj;
-import com.hierynomus.mssmb2.SMB2Dialect;
-
import java.security.SecureRandom;
+import java.util.ArrayList;
import java.util.EnumSet;
import java.util.UUID;
+import com.hierynomus.mssmb2.SMB2Dialect;
+import com.hierynomus.protocol.commons.Factory;
+import com.hierynomus.smbj.auth.Authenticator;
+import com.hierynomus.smbj.auth.NtlmAuthenticator;
+import com.hierynomus.smbj.auth.SpnegoAuthenticator;
+
public class DefaultConfig extends ConfigImpl {
public DefaultConfig() {
random = new SecureRandom();
dialects = EnumSet.of(SMB2Dialect.SMB_2_1, SMB2Dialect.SMB_2_0_2);
clientGuid = UUID.randomUUID();
+ isStrictSigning = false; //TODO change to true when we are more confident
+ registerDefaultAuthenticators();
+ }
+
+ private void registerDefaultAuthenticators() {
+ authenticators = new ArrayList>();
+ // order is important. The authenticators listed first will be selected
+ authenticators.add(new SpnegoAuthenticator.Factory());
+ authenticators.add(new NtlmAuthenticator.Factory());
}
}
diff --git a/src/main/java/com/hierynomus/smbj/ProgressListener.java b/src/main/java/com/hierynomus/smbj/ProgressListener.java
index 76f5e5f4..a16a5a80 100644
--- a/src/main/java/com/hierynomus/smbj/ProgressListener.java
+++ b/src/main/java/com/hierynomus/smbj/ProgressListener.java
@@ -19,6 +19,7 @@ public interface ProgressListener {
/**
* Invoked when the progress of the API call changes.
+ *
* @param numBytes the number of bytes completed.
* @param totalBytes the total number of bytes.
*/
diff --git a/src/main/java/com/hierynomus/smbj/SMBClient.java b/src/main/java/com/hierynomus/smbj/SMBClient.java
index 3dfd2dca..a6567562 100644
--- a/src/main/java/com/hierynomus/smbj/SMBClient.java
+++ b/src/main/java/com/hierynomus/smbj/SMBClient.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.smbj;
-import com.hierynomus.smbj.connection.Connection;
-import com.hierynomus.smbj.event.SMBEventBus;
-import com.hierynomus.smbj.transport.tcp.DirectTcpTransport;
-
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import com.hierynomus.smbj.connection.Connection;
+import com.hierynomus.smbj.event.SMBEventBus;
+import com.hierynomus.smbj.transport.tcp.DirectTcpTransport;
/**
* Server Message Block Client API.
@@ -49,6 +48,7 @@ public SMBClient(Config config) {
/**
* Connect to the host at hostname
on the default port (445)
+ *
* @param hostname The hostname to connect to.
* @return An established connection.
* @throws IOException If the connection could not be established.
@@ -57,6 +57,17 @@ public Connection connect(String hostname) throws IOException {
return getEstablishedOrConnect(hostname, DEFAULT_PORT);
}
+ /**
+ * Connect to the host at hostname
on the given port
+ *
+ * @param hostname The hostname to connect to.
+ * @param port The port to connect to
+ * @return An established connection.
+ * @throws IOException If the connection could not be established.
+ */
+ public Connection connect(String hostname, int port) throws IOException {
+ return getEstablishedOrConnect(hostname, port);
+ }
private Connection getEstablishedOrConnect(String hostname, int port) throws IOException {
synchronized (this) {
diff --git a/src/main/java/com/hierynomus/smbj/auth/Authenticator.java b/src/main/java/com/hierynomus/smbj/auth/Authenticator.java
index a0ea9bc9..22c79f72 100644
--- a/src/main/java/com/hierynomus/smbj/auth/Authenticator.java
+++ b/src/main/java/com/hierynomus/smbj/auth/Authenticator.java
@@ -15,6 +15,13 @@
*/
package com.hierynomus.smbj.auth;
-interface Authenticator {
+import java.io.IOException;
-}
\ No newline at end of file
+import com.hierynomus.smbj.session.Session;
+
+public interface Authenticator {
+
+ boolean supports(AuthenticationContext context);
+
+ byte[] authenticate(AuthenticationContext context, byte[] gssToken, Session session) throws IOException;
+}
diff --git a/src/main/java/com/hierynomus/smbj/auth/GSSAuthenticationContext.java b/src/main/java/com/hierynomus/smbj/auth/GSSAuthenticationContext.java
new file mode 100755
index 00000000..4eadc8e5
--- /dev/null
+++ b/src/main/java/com/hierynomus/smbj/auth/GSSAuthenticationContext.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C)2016 - SMBJ Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.hierynomus.smbj.auth;
+
+import javax.security.auth.Subject;
+
+import org.ietf.jgss.GSSCredential;
+
+public class GSSAuthenticationContext extends AuthenticationContext {
+ Subject subject;
+ GSSCredential creds;
+ public GSSAuthenticationContext(String username, String domain, Subject subject, GSSCredential creds) {
+ super(username, "".toCharArray(), domain);
+ this.subject = subject;
+ this.creds = creds;
+ }
+ public Subject getSubject() {
+ return subject;
+ }
+ public GSSCredential getCreds() {
+ return creds;
+ }
+}
diff --git a/src/main/java/com/hierynomus/smbj/auth/NtlmAuthenticator.java b/src/main/java/com/hierynomus/smbj/auth/NtlmAuthenticator.java
index 7be64bd5..1c66f1c5 100644
--- a/src/main/java/com/hierynomus/smbj/auth/NtlmAuthenticator.java
+++ b/src/main/java/com/hierynomus/smbj/auth/NtlmAuthenticator.java
@@ -15,9 +15,15 @@
*/
package com.hierynomus.smbj.auth;
-import com.hierynomus.mserref.NtStatus;
-import com.hierynomus.mssmb2.messages.SMB2SessionSetup;
-import com.hierynomus.ntlm.NtlmException;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.microsoft.MicrosoftObjectIdentifiers;
+import org.bouncycastle.util.Arrays;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.hierynomus.ntlm.functions.NtlmFunctions;
import com.hierynomus.ntlm.messages.NtlmAuthenticate;
import com.hierynomus.ntlm.messages.NtlmChallenge;
@@ -26,28 +32,16 @@
import com.hierynomus.protocol.commons.ByteArrayUtils;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.protocol.commons.buffer.Endian;
-import com.hierynomus.protocol.commons.concurrent.Futures;
-import com.hierynomus.smbj.connection.Connection;
-import com.hierynomus.smbj.transport.TransportException;
+import com.hierynomus.smbj.session.Session;
import com.hierynomus.spnego.NegTokenInit;
import com.hierynomus.spnego.NegTokenTarg;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.microsoft.MicrosoftObjectIdentifiers;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.concurrent.Future;
public class NtlmAuthenticator implements Authenticator {
private static final Logger logger = LoggerFactory.getLogger(NtlmAuthenticator.class);
private static final ASN1ObjectIdentifier NTLMSSP = MicrosoftObjectIdentifiers.microsoft.branch("2.2.10");
- public static class Factory implements com.hierynomus.protocol.commons.Factory.Named {
+ public static class Factory implements com.hierynomus.protocol.commons.Factory.Named {
@Override
public String getName() {
// The OID for NTLMSSP
@@ -60,65 +54,56 @@ public NtlmAuthenticator create() {
}
}
- public long authenticate(Connection connection, AuthenticationContext context) throws TransportException {
- try {
- logger.info("Authenticating {} on {} using NTLM", context.getUsername(), connection.getRemoteHostname());
- EnumSet signingEnabled = EnumSet.of
- (SMB2SessionSetup.SMB2SecurityMode.SMB2_NEGOTIATE_SIGNING_ENABLED);
+ private boolean initialized = false;
+ private boolean completed = false;
- SMB2SessionSetup smb2SessionSetup = new SMB2SessionSetup(connection.getNegotiatedProtocol().getDialect(), signingEnabled);
+ @Override
+ public byte[] authenticate(final AuthenticationContext context, final byte[] gssToken, Session session) throws IOException {
+ if (completed) {
+ return null;
+ } else if (!initialized) {
+ logger.info("Initialized Authentication of {} using NTLM", context.getUsername());
NtlmNegotiate ntlmNegotiate = new NtlmNegotiate();
- byte[] asn1 = negTokenInit(ntlmNegotiate);
- smb2SessionSetup.setSecurityBuffer(asn1);
- Future future = connection.send(smb2SessionSetup);
- SMB2SessionSetup receive = Futures.get(future, TransportException.Wrapper);
- long sessionId = receive.getHeader().getSessionId();
- if (receive.getHeader().getStatus() == NtStatus.STATUS_MORE_PROCESSING_REQUIRED) {
- logger.debug("More processing required for authentication of {}", context.getUsername());
- byte[] securityBuffer = receive.getSecurityBuffer();
- logger.debug("Received token: {}", ByteArrayUtils.printHex(securityBuffer));
-
- NegTokenTarg negTokenTarg = new NegTokenTarg().read(securityBuffer);
- BigInteger negotiationResult = negTokenTarg.getNegotiationResult();
- NtlmChallenge challenge = (NtlmChallenge) new NtlmChallenge().read(new Buffer.PlainBuffer(negTokenTarg.getResponseToken(), Endian.LE));
- logger.debug("Received NTLM challenge from: {}", challenge.getTargetName());
-
- byte[] serverChallenge = challenge.getServerChallenge();
- byte[] responseKeyNT = NtlmFunctions.NTOWFv2(String.valueOf(context.getPassword()), context.getUsername(), context.getDomain());
- byte[] ntlmv2ClientChallenge = NtlmFunctions.getNTLMv2ClientChallenge(challenge.getTargetInfo());
- byte[] ntlmv2Response = NtlmFunctions.getNTLMv2Response(responseKeyNT, serverChallenge, ntlmv2ClientChallenge);
- byte[] sessionkey = null;
-
- if (challenge.getNegotiateFlags().contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_SIGN)) {
- byte[] userSessionKey = NtlmFunctions.hmac_md5(
- responseKeyNT, ByteBuffer.wrap(ntlmv2Response, 0, 16).array());
-
- if ((challenge.getNegotiateFlags().contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_KEY_EXCH))) {
- byte[] masterKey = new byte[16];
- NtlmFunctions.getRandom().nextBytes(masterKey);
- sessionkey = NtlmFunctions.encryptRc4(userSessionKey, masterKey);
- } else {
- sessionkey = userSessionKey;
- }
- }
-
- SMB2SessionSetup smb2SessionSetup2 = new SMB2SessionSetup(connection.getNegotiatedProtocol().getDialect(), signingEnabled);
- smb2SessionSetup2.getHeader().setSessionId(sessionId);
- //smb2SessionSetup2.getHeader().setCreditRequest(256);
-
- NtlmAuthenticate resp = new NtlmAuthenticate(new byte[0], ntlmv2Response,
- context.getUsername(), context.getDomain(), null, sessionkey, NtlmNegotiate.DEFAULT_FLAGS);
- asn1 = negTokenTarg(resp, negTokenTarg.getResponseToken());
- smb2SessionSetup2.setSecurityBuffer(asn1);
- Future send = connection.send(smb2SessionSetup2);
- SMB2SessionSetup setupResponse = Futures.get(send, TransportException.Wrapper);
- if (setupResponse.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
- throw new NtlmException("Setup failed with " + setupResponse.getHeader().getStatus());
+ initialized = true;
+ return negTokenInit(ntlmNegotiate);
+ } else {
+ logger.debug("Received token: {}", ByteArrayUtils.printHex(gssToken));
+
+ NegTokenTarg negTokenTarg = new NegTokenTarg().read(gssToken);
+ BigInteger negotiationResult = negTokenTarg.getNegotiationResult();
+ NtlmChallenge challenge = null;
+ try {
+ challenge = (NtlmChallenge) new NtlmChallenge().read(new Buffer.PlainBuffer(negTokenTarg.getResponseToken(), Endian.LE));
+ } catch (Buffer.BufferException e) {
+ throw new IOException(e);
+ }
+ logger.debug("Received NTLM challenge from: {}", challenge.getTargetName());
+
+ byte[] serverChallenge = challenge.getServerChallenge();
+ byte[] responseKeyNT = NtlmFunctions.NTOWFv2(String.valueOf(context.getPassword()), context.getUsername(), context.getDomain());
+ byte[] ntlmv2ClientChallenge = NtlmFunctions.getNTLMv2ClientChallenge(challenge.getTargetInfo());
+ byte[] ntlmv2Response = NtlmFunctions.getNTLMv2Response(responseKeyNT, serverChallenge, ntlmv2ClientChallenge);
+ byte[] sessionkey = null;
+
+ if (challenge.getNegotiateFlags().contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_SIGN)) {
+ byte[] userSessionKey = NtlmFunctions.hmac_md5(responseKeyNT, Arrays.copyOfRange(ntlmv2Response, 0, 16)); // first 16 bytes of ntlmv2Response is ntProofStr
+ if ((challenge.getNegotiateFlags().contains(NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_KEY_EXCH))) {
+ byte[] masterKey = new byte[16];
+ NtlmFunctions.getRandom().nextBytes(masterKey);
+ sessionkey = NtlmFunctions.encryptRc4(userSessionKey, masterKey);
+ session.setSigningKey(masterKey);
+ } else {
+ sessionkey = userSessionKey;
+ session.setSigningKey(sessionkey);
}
}
- return sessionId;
- } catch (IOException | Buffer.BufferException e) {
- throw new TransportException(e);
+
+ completed = true;
+
+ // If NTLM v2 is used, KeyExchangeKey MUST be set to the given 128-bit SessionBaseKey value.
+ NtlmAuthenticate resp = new NtlmAuthenticate(new byte[0], ntlmv2Response,
+ context.getUsername(), context.getDomain(), null, sessionkey, NtlmNegotiate.DEFAULT_FLAGS);
+ return negTokenTarg(resp, negTokenTarg.getResponseToken());
}
}
@@ -144,4 +129,9 @@ private byte[] negTokenTarg(NtlmAuthenticate resp, byte[] responseToken) {
return negTokenBuffer.getCompactData();
}
+ @Override
+ public boolean supports(AuthenticationContext context) {
+ return context.getClass().equals(AuthenticationContext.class);
+ }
+
}
diff --git a/src/main/java/com/hierynomus/smbj/auth/SpnegoAuthenticator.java b/src/main/java/com/hierynomus/smbj/auth/SpnegoAuthenticator.java
index 68f0363c..1cd2e205 100644
--- a/src/main/java/com/hierynomus/smbj/auth/SpnegoAuthenticator.java
+++ b/src/main/java/com/hierynomus/smbj/auth/SpnegoAuthenticator.java
@@ -15,8 +15,27 @@
*/
package com.hierynomus.smbj.auth;
+import java.io.IOException;
+import java.security.Key;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import javax.security.auth.Subject;
+import org.ietf.jgss.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.mssmb2.SMB2Header;
+import com.hierynomus.protocol.commons.ByteArrayUtils;
+import com.hierynomus.smbj.session.Session;
+import com.hierynomus.smbj.transport.TransportException;
+import com.sun.security.jgss.ExtendedGSSContext;
+import com.sun.security.jgss.InquireType;
+
+
public class SpnegoAuthenticator implements Authenticator {
- public static class Factory implements com.hierynomus.protocol.commons.Factory.Named {
+ private static final Logger logger = LoggerFactory.getLogger(SpnegoAuthenticator.class);
+
+ public static class Factory implements com.hierynomus.protocol.commons.Factory.Named {
@Override
public String getName() {
@@ -26,30 +45,91 @@ public String getName() {
@Override
public SpnegoAuthenticator create() {
- return null;
+ return new SpnegoAuthenticator();
+ }
+ }
+
+ private GSSContext gssContext;
+
+ @Override
+ public byte[] authenticate(final AuthenticationContext context, final byte[] gssToken, final Session session) throws IOException {
+ final GSSAuthenticationContext gssAuthenticationContext = (GSSAuthenticationContext) context;
+ try {
+ return Subject.doAs(gssAuthenticationContext.getSubject(), new PrivilegedExceptionAction() {
+ public byte[] run() throws Exception {
+ return authenticateSession(gssAuthenticationContext, gssToken, session);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new TransportException(e);
+ }
+ }
+
+ private byte[] authenticateSession(GSSAuthenticationContext context, byte[] gssToken, Session session) throws TransportException {
+ try {
+ logger.info("Authenticating {} on {} using SPNEGO", context.getUsername(), session.getConnection().getRemoteHostname());
+ if (gssContext == null) {
+ // GSS context is not established yet because this is the first pass at authentication,
+ // so create the GSS context and attach it to our AuthenticationContext
+ if (gssToken == null) {
+ logger.error("GSS token is null, but should have been provided by the SMB negotiation response");
+ }
+
+ GSSManager gssManager = GSSManager.getInstance();
+ Oid spnegoOid = new Oid("1.3.6.1.5.5.2"); //SPNEGO
+
+ String service = "cifs";
+ String hostName = session.getConnection().getRemoteHostname();
+ GSSName serverName = gssManager.createName(service + "@" + hostName, GSSName.NT_HOSTBASED_SERVICE);
+ gssContext = gssManager.createContext(serverName, spnegoOid, context.getCreds(), GSSContext.DEFAULT_LIFETIME);
+ gssContext.requestMutualAuth(false);
+ // TODO fill in all the other options too
+
+ }
+
+ byte[] newToken = gssContext.initSecContext(gssToken, 0, gssToken.length);
+ if (newToken != null) {
+ logger.debug("Received token: {}", ByteArrayUtils.printHex(newToken));
+ }
+ if (gssContext.isEstablished()) {
+ ExtendedGSSContext e = (ExtendedGSSContext) gssContext;
+ Key key = (Key) e.inquireSecContext(InquireType.KRB5_GET_SESSION_KEY);
+ if (key != null) {
+ // if a session key was negotiated, save it.
+ session.setSigningKey(adjustSessionKeyLength(key.getEncoded()));
+ }
+ }
+ return newToken;
+ } catch (GSSException e) {
+ throw new TransportException(e);
}
}
/**
- * Authenticate the user against
- * @param gssToken
- * @param context
- * @return
+ * [MS-SMB2] 3.2.5.3.1 Handling a New Authentication
+ * Session.SessionKey MUST be set to the first 16 bytes of the cryptographic key queried from the
+ * GSS protocol for this authenticated context. If the cryptographic key is less than 16 bytes,
+ * it is right-padded with zero bytes.
+ *
+ * @param key session key from the GSS API
+ * @return key, truncated or padded to 16 bytes
*/
- public byte[] authenticate(byte[] gssToken, AuthenticationContext context) {
- return null;
+ private byte[] adjustSessionKeyLength(byte[] key) {
+ byte[] newKey;
+ if (key.length > SMB2Header.SIGNATURE_SIZE) {
+ newKey = Arrays.copyOfRange(key, 0, SMB2Header.SIGNATURE_SIZE);
+ } else if (key.length < SMB2Header.SIGNATURE_SIZE) {
+ newKey = new byte[16];
+ System.arraycopy(key, 0, newKey, 0, key.length);
+ Arrays.fill(newKey, key.length, SMB2Header.SIGNATURE_SIZE - 1, (byte) 0);
+ } else {
+ newKey = key;
+ }
+ return newKey;
}
-
- public void authenticate(String username, String password, String domain) {
-// try {
-// GSSManager gssManager = GSSManager.getInstance();
-// Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
-// GSSName serverName = gssManager.createName(, GSSName.NT_HOSTBASED_SERVICE, spnegoOid);
-// GSSContext context = gssManager.createContext(serverName, spnegoOid, null, GSSContext.DEFAULT_LIFETIME);
-// byte[] bytes = context.acceptSecContext(gssToken, 0, gssToken.length);
-// } catch (GSSException e) {
-// e.printStackTrace();
-// }
+ @Override
+ public boolean supports(AuthenticationContext context) {
+ return context.getClass().equals(GSSAuthenticationContext.class);
}
}
diff --git a/src/main/java/com/hierynomus/smbj/common/MessageSigning.java b/src/main/java/com/hierynomus/smbj/common/MessageSigning.java
new file mode 100755
index 00000000..22be4224
--- /dev/null
+++ b/src/main/java/com/hierynomus/smbj/common/MessageSigning.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C)2016 - SMBJ Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.hierynomus.smbj.common;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import com.hierynomus.mssmb2.SMB2Header;
+
+public class MessageSigning {
+
+ public static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
+
+ /**
+ * check that the signature field of the SMB message buffer is correct.
+ *
+ * @param buffer byte array containing the SMB message.
+ * @param len message length. Note that the buffer array might contain more
+ * bytes than the message length. The len parameter indicates how
+ * many bytes of the buffer array are in the message.
+ * @param signingKeySpec the session's signing key, a SecretKeySpec
+ * @return
+ */
+ public static boolean validateSignature(byte[] buffer, int len, SecretKeySpec signingKeySpec) {
+ try {
+ byte[] signature = computeSignature(buffer, len, signingKeySpec);
+
+ // are signatures identical?
+ for (int i = 0; i < SMB2Header.SIGNATURE_SIZE; i++) {
+ if (signature[i] != buffer[SMB2Header.SIGNATURE_OFFSET + i]) {
+ return false;
+ }
+ }
+ return true;
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ return false; // cannot check signature?
+ }
+ }
+
+ /**
+ * sign a SMB message buffer
+ *
+ * @param buffer byte array containing the SMB message.
+ * @param len message length. Note that the buffer array might contain more
+ * bytes than the message length. The len parameter indicates how
+ * many bytes of the buffer array are in the message.
+ * @param signingKey the session's signing key.
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ */
+ // [MS-SMB2] 3.1.4.1 Signing An Outgoing Message
+ // 1. The sender MUST zero out the 16-byte signature field in the SMB2 Header of the message to be sent
+ // prior to generating the signature.
+ // 2. If Connection.Dialect belongs to the SMB 3.x dialect family, the sender MUST compute a 16-byte hash
+ // using AES-128-CMAC over the entire message, beginning with the SMB2 Header from step 1, and using the
+ // key provided. The AES-128-CMAC is specified in [RFC4493]. If the message is part of a compounded chain,
+ // any padding at the end of the message MUST be used in the hash computation. The sender MUST copy the
+ // 16-byte hash into the signature field of the SMB2 header.
+ // 3. If Connection.Dialect is "2.0.2" or "2.1", the sender MUST compute a 32-byte hash using HMAC-SHA256
+ // over the entire message, beginning with the SMB2 Header from step 1, and using the key provided.
+ // The HMAC-SHA256 is specified in [FIPS180-4] and [RFC2104]. If the message is part of a compounded
+ // chain, any padding at the end of the message MUST be used in the hash computation. The first
+ // 16 bytes (the high-order portion) of the hash MUST be copied (beginning with the first, most
+ // significant, byte) into the 16-byte signature field of the SMB2 Header.
+ public static void signBuffer(byte[] buffer, int len, SecretKeySpec signingKeySpec) throws InvalidKeyException,
+ NoSuchAlgorithmException {
+ byte[] signature = computeSignature(buffer, len, signingKeySpec);
+ System.arraycopy(signature, 0, buffer, SMB2Header.SIGNATURE_OFFSET, SMB2Header.SIGNATURE_SIZE);
+ }
+
+ /**
+ * compute the HMAC signature on a SMB buffer. The calculation is performed
+ * as if the signature field is filled with zeros.
+ *
+ * @param buffer byte array containing the SMB message.
+ * @param len message length. Note that the buffer array might contain more
+ * bytes than the message length. The len parameter indicates how
+ * many bytes of the buffer array are in the message.
+ * @param signingKeySpec the session's signing key, a SecretKeySpec
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ */
+ private static byte[] computeSignature(byte[] buffer, int len, SecretKeySpec signingKeySpec) throws NoSuchAlgorithmException,
+ InvalidKeyException {
+ if (len < SMB2Header.STRUCTURE_SIZE) {
+ throw new IllegalArgumentException("Buffer must be longer than 64 bytes");
+ }
+
+ Mac mac = Mac.getInstance(signingKeySpec.getAlgorithm());
+ mac.init(signingKeySpec);
+ mac.update(buffer, 0, SMB2Header.SIGNATURE_OFFSET);
+ for (int i = 0; i < SMB2Header.SIGNATURE_SIZE; i++) { // pretend the signature bytes are zero
+ mac.update((byte) 0);
+ }
+ mac.update(buffer, SMB2Header.STRUCTURE_SIZE, len - SMB2Header.STRUCTURE_SIZE);
+ byte[] signature = mac.doFinal();
+ return signature;
+ }
+}
diff --git a/src/main/java/com/hierynomus/smbj/common/SMBApiException.java b/src/main/java/com/hierynomus/smbj/common/SMBApiException.java
index b94da0ae..435116b0 100644
--- a/src/main/java/com/hierynomus/smbj/common/SMBApiException.java
+++ b/src/main/java/com/hierynomus/smbj/common/SMBApiException.java
@@ -22,22 +22,26 @@
public class SMBApiException extends SMBRuntimeException {
private final NtStatus status;
private final SMB2MessageCommandCode failedCommand;
+ private long statusCode;
- public SMBApiException(NtStatus status, SMB2MessageCommandCode failedCommand, String message) {
+ public SMBApiException(NtStatus status, long statusCode, SMB2MessageCommandCode failedCommand, String message) {
super(message);
this.status = status;
+ this.statusCode = statusCode;
this.failedCommand = failedCommand;
}
- public SMBApiException(NtStatus status, SMB2MessageCommandCode failedCommand, Throwable t) {
+ public SMBApiException(NtStatus status, long statusCode, SMB2MessageCommandCode failedCommand, Throwable t) {
super(t);
this.status = status;
+ this.statusCode = statusCode;
this.failedCommand = failedCommand;
}
public SMBApiException(SMB2Header header, String message) {
super(message);
this.status = header.getStatus();
+ this.statusCode = header.getStatusCode();
this.failedCommand = header.getMessage();
}
@@ -45,12 +49,16 @@ public NtStatus getStatus() {
return status;
}
+ public long getStatusCode() {
+ return statusCode;
+ }
+
public SMB2MessageCommandCode getFailedCommand() {
return failedCommand;
}
@Override
public String getMessage() {
- return status + "(" + status.getValue() + "): " + super.getMessage();
+ return status + "(" + status.getValue() + "/" + statusCode + "): " + super.getMessage();
}
}
diff --git a/src/main/java/com/hierynomus/smbj/common/SMBBuffer.java b/src/main/java/com/hierynomus/smbj/common/SMBBuffer.java
index 1eabf00f..53f5b0c7 100644
--- a/src/main/java/com/hierynomus/smbj/common/SMBBuffer.java
+++ b/src/main/java/com/hierynomus/smbj/common/SMBBuffer.java
@@ -15,11 +15,10 @@
*/
package com.hierynomus.smbj.common;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import com.hierynomus.protocol.commons.buffer.Endian;
-
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import com.hierynomus.protocol.commons.buffer.Buffer;
+import com.hierynomus.protocol.commons.buffer.Endian;
public class SMBBuffer extends Buffer {
private static final byte[] RESERVED_2 = new byte[]{0x0, 0x0};
diff --git a/src/main/java/com/hierynomus/smbj/common/SMBException.java b/src/main/java/com/hierynomus/smbj/common/SMBException.java
index 09a83633..732629f8 100644
--- a/src/main/java/com/hierynomus/smbj/common/SMBException.java
+++ b/src/main/java/com/hierynomus/smbj/common/SMBException.java
@@ -15,9 +15,8 @@
*/
package com.hierynomus.smbj.common;
-import com.hierynomus.protocol.commons.concurrent.ExceptionWrapper;
-
import java.io.IOException;
+import com.hierynomus.protocol.commons.concurrent.ExceptionWrapper;
public class SMBException extends IOException {
public static ExceptionWrapper Wrapper = new ExceptionWrapper() {
diff --git a/src/main/java/com/hierynomus/smbj/connection/Connection.java b/src/main/java/com/hierynomus/smbj/connection/Connection.java
index c5550457..43e02e0d 100644
--- a/src/main/java/com/hierynomus/smbj/connection/Connection.java
+++ b/src/main/java/com/hierynomus/smbj/connection/Connection.java
@@ -15,17 +15,36 @@
*/
package com.hierynomus.smbj.connection;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import java.util.concurrent.Future;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.hierynomus.mserref.NtStatus;
+import com.hierynomus.mssmb2.SMB2MessageCommandCode;
import com.hierynomus.mssmb2.SMB2MessageFlag;
import com.hierynomus.mssmb2.SMB2MultiCreditPacket;
import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.mssmb2.messages.SMB2NegotiateRequest;
import com.hierynomus.mssmb2.messages.SMB2NegotiateResponse;
+import com.hierynomus.mssmb2.messages.SMB2SessionSetup;
+import com.hierynomus.protocol.commons.Factory;
import com.hierynomus.protocol.commons.concurrent.Futures;
import com.hierynomus.protocol.commons.socket.SocketClient;
import com.hierynomus.smbj.Config;
import com.hierynomus.smbj.auth.AuthenticationContext;
-import com.hierynomus.smbj.auth.NtlmAuthenticator;
+import com.hierynomus.smbj.auth.Authenticator;
+import com.hierynomus.smbj.common.MessageSigning;
+import com.hierynomus.smbj.common.SMBApiException;
import com.hierynomus.smbj.common.SMBRuntimeException;
import com.hierynomus.smbj.event.SMBEventBus;
import com.hierynomus.smbj.event.SessionLoggedOff;
@@ -37,19 +56,13 @@
import com.hierynomus.smbj.transport.tcp.DirectTcpPacketReader;
import com.hierynomus.smbj.transport.tcp.DirectTcpTransport;
import com.hierynomus.spnego.NegTokenInit;
-import net.engio.mbassy.listener.Handler;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-import java.util.concurrent.Future;
-import java.util.concurrent.locks.ReentrantLock;
+import net.engio.mbassy.listener.Handler;
+import static com.hierynomus.mssmb2.messages.SMB2SessionSetup.SMB2SecurityMode.SMB2_NEGOTIATE_SIGNING_ENABLED;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.isSet;
import static com.hierynomus.smbj.connection.NegotiatedProtocol.SINGLE_CREDIT_PAYLOAD_SIZE;
+import static java.lang.String.format;
/**
* A connection to a server.
@@ -91,7 +104,13 @@ protected void onConnect() throws IOException {
@Override
public void close() throws Exception {
- connectionInfo.getSessionTable().closeRemainingSessions();
+ for (Session session : connectionInfo.getSessionTable().activeSessions()) {
+ try {
+ session.close();
+ } catch (IOException e) {
+ logger.warn("Exception while closing session {}", session.getSessionId(), e);
+ }
+ }
packetReader.stop();
logger.info("Closed connection to {}", getRemoteHostname());
super.disconnect();
@@ -103,25 +122,83 @@ public void close() throws Exception {
* @return a (new) Session that is authenticated for the user.
*/
public Session authenticate(AuthenticationContext authContext) {
- // TODO hardcoded for now
- NtlmAuthenticator.Factory factory = new NtlmAuthenticator.Factory();
try {
NegTokenInit negTokenInit = new NegTokenInit().read(connectionInfo.getGssNegotiateToken());
- if (negTokenInit.getSupportedMechTypes().contains(new ASN1ObjectIdentifier(factory.getName()))) {
- NtlmAuthenticator ntlmAuthenticator = factory.create();
- long sessionId = ntlmAuthenticator.authenticate(this, authContext);
- logger.info("Successfully authenticated {} on {}, session is {}", authContext.getUsername(), getRemoteHostname(), sessionId);
- Session session = new Session(sessionId, this, bus);
- connectionInfo.getSessionTable().registerSession(sessionId, session);
+ Authenticator authenticator = getAuthenticator(negTokenInit.getSupportedMechTypes(), authContext);
+ Session session = new Session(0, this, bus, connectionInfo.isRequireSigning());
+ SMB2SessionSetup receive = authenticationRound(authenticator, authContext, connectionInfo.getGssNegotiateToken(), session);
+ long sessionId = receive.getHeader().getSessionId();
+ session.setSessionId(sessionId);
+ connectionInfo.getPreauthSessionTable().registerSession(sessionId, session);
+ try {
+ while (receive.getHeader().getStatus() == NtStatus.STATUS_MORE_PROCESSING_REQUIRED) {
+ logger.debug("More processing required for authentication of {} using {}", authContext.getUsername(), authenticator);
+ receive = authenticationRound(authenticator, authContext, receive.getSecurityBuffer(), session);
+ }
+
+ if (receive.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
+ throw new SMBApiException(receive.getHeader(), format("Authentication failed for '%s' using %s", authContext.getUsername(), authenticator));
+ }
+
+ if (receive.getSecurityBuffer() != null) {
+ // process the last received buffer
+ authenticator.authenticate(authContext, receive.getSecurityBuffer(), session);
+ }
+ logger.info("Successfully authenticated {} on {}, session is {}", authContext.getUsername(), getRemoteHostname(), session.getSessionId());
+ connectionInfo.getSessionTable().registerSession(session.getSessionId(), session);
return session;
+ } finally {
+ connectionInfo.getPreauthSessionTable().sessionClosed(sessionId);
}
} catch (IOException e) {
throw new SMBRuntimeException(e);
}
- return null;
}
+ private SMB2SessionSetup authenticationRound(Authenticator authenticator, AuthenticationContext authContext, byte[] inputToken, Session session) throws IOException {
+ byte[] securityContext = authenticator.authenticate(authContext, inputToken, session);
+ SMB2SessionSetup req = new SMB2SessionSetup(connectionInfo.getNegotiatedProtocol().getDialect(), EnumSet.of(SMB2_NEGOTIATE_SIGNING_ENABLED));
+ req.setSecurityBuffer(securityContext);
+ req.getHeader().setSessionId(session.getSessionId());
+ return sendAndReceive(req);
+ }
+
+ private Authenticator getAuthenticator(List mechTypes, AuthenticationContext context) {
+ for (Factory.Named factory : config.getSupportedAuthenticators()) {
+ if (mechTypes.contains(new ASN1ObjectIdentifier(factory.getName()))) {
+ Authenticator authenticator = factory.create();
+ if (authenticator.supports(context)) {
+ return authenticator;
+ }
+ }
+ }
+ throw new SMBRuntimeException("No authenticator is configured for the supported mechtypes: " + mechTypes);
+ }
+
+ /**
+ * send a packet, unsigned.
+ *
+ * @param packet SMBPacket to send
+ * @return a Future to be used to retrieve the response packet
+ * @throws TransportException
+ */
public Future send(SMB2Packet packet) throws TransportException {
+ return send(packet, null);
+ }
+
+ private T sendAndReceive(SMB2Packet packet) throws TransportException {
+ return Futures.get(this.send(packet), TransportException.Wrapper);
+ }
+
+ /**
+ * send a packet, potentially signed
+ *
+ * @param packet SMBPacket to send
+ * @param signingKeySpec if null, do not sign the packet. Otherwise, the signingKey will be used to sign the packet.
+ * @return a Future to be used to retrieve the response packet
+ * @throws TransportException
+ */
+ public Future send(SMB2Packet packet, SecretKeySpec signingKeySpec) throws TransportException {
lock.lock();
try {
int availableCredits = connectionInfo.getSequenceWindow().available();
@@ -152,7 +229,11 @@ public Future send(SMB2Packet packet) throws Transport
Request request = new Request(packet.getHeader().getMessageId(), UUID.randomUUID(), packet);
connectionInfo.getOutstandingRequests().registerOutstanding(request);
- transport.write(packet);
+ if (signingKeySpec != null) {
+ transport.writeSigned(packet, signingKeySpec);
+ } else {
+ transport.write(packet);
+ }
return request.getFuture(null); // TODO cancel callback
} finally {
lock.unlock();
@@ -218,6 +299,40 @@ public void handle(SMB2Packet packet) throws TransportException {
return;
}
+ if (packet.getHeader().getSessionId() != 0 && (packet.getHeader().getMessage() != SMB2MessageCommandCode.SMB2_SESSION_SETUP)) {
+ Session session = connectionInfo.getSessionTable().find(packet.getHeader().getSessionId());
+ if (session == null) {
+ // check for a not-yet-authenticated session
+ session = connectionInfo.getPreauthSessionTable().find(packet.getHeader().getSessionId());
+ if (session == null) {
+ logger.warn("Illegal request, no session matching the sessionId: {}", packet.getHeader().getSessionId());
+ //TODO maybe tear down the connection?
+ return;
+ }
+ }
+
+ // check packet signature. Drop the packet if it is not correct.
+ if (session.isSigningRequired()) {
+ if (packet.getHeader().isFlagSet(SMB2MessageFlag.SMB2_FLAGS_SIGNED)) {
+ packet.getBuffer().rpos(0);
+ if (!MessageSigning.validateSignature(packet.getBuffer().array(), packet.getBuffer().available(), session.getSigningKeySpec())) {
+ logger.warn("Invalid packet signature");
+ if (config.isStrictSigning()) {
+ return; // drop the packet
+ }
+ }
+ } else {
+ logger.warn("Illegal request, session requires message signing, but the message is not signed.");
+ return;
+ }
+ } else {
+ if (packet.getHeader().isFlagSet(SMB2MessageFlag.SMB2_FLAGS_SIGNED)) {
+ logger.trace("Received a signed packet, but signing is not required on this session.");
+ // but this is OK, so we fall through.
+ }
+ }
+ }
+
// [MS-SMB2].pdf 3.2.5.1.8 Processing the Response
connectionInfo.getOutstandingRequests().receivedResponseFor(messageId).getPromise().deliver(packet);
}
diff --git a/src/main/java/com/hierynomus/smbj/connection/ConnectionInfo.java b/src/main/java/com/hierynomus/smbj/connection/ConnectionInfo.java
index 3af4e581..917e4685 100644
--- a/src/main/java/com/hierynomus/smbj/connection/ConnectionInfo.java
+++ b/src/main/java/com/hierynomus/smbj/connection/ConnectionInfo.java
@@ -15,12 +15,10 @@
*/
package com.hierynomus.smbj.connection;
-import com.hierynomus.mssmb2.messages.SMB2NegotiateResponse;
-import com.hierynomus.protocol.commons.EnumWithValue;
-
import java.util.EnumSet;
-import java.util.List;
import java.util.UUID;
+import com.hierynomus.mssmb2.messages.SMB2NegotiateResponse;
+import com.hierynomus.protocol.commons.EnumWithValue;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toEnumSet;
@@ -51,7 +49,7 @@ public long getValue() {
// All SMB2 Dialect
private SessionTable sessionTable = new SessionTable();
- private List preauthSessionTable;
+ private SessionTable preauthSessionTable = new SessionTable();
private OutstandingRequests outstandingRequests = new OutstandingRequests();
private SequenceWindow sequenceWindow;
private byte[] gssNegotiateToken;
@@ -99,6 +97,10 @@ SessionTable getSessionTable() {
return sessionTable;
}
+ public SessionTable getPreauthSessionTable() {
+ return preauthSessionTable;
+ }
+
public UUID getClientGuid() {
return clientGuid;
}
diff --git a/src/main/java/com/hierynomus/smbj/connection/OutstandingRequests.java b/src/main/java/com/hierynomus/smbj/connection/OutstandingRequests.java
index 10f75e6b..b019e74d 100644
--- a/src/main/java/com/hierynomus/smbj/connection/OutstandingRequests.java
+++ b/src/main/java/com/hierynomus/smbj/connection/OutstandingRequests.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.smbj.connection;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import com.hierynomus.smbj.common.SMBRuntimeException;
class OutstandingRequests {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
diff --git a/src/main/java/com/hierynomus/smbj/connection/Request.java b/src/main/java/com/hierynomus/smbj/connection/Request.java
index f58b8864..cd46e545 100644
--- a/src/main/java/com/hierynomus/smbj/connection/Request.java
+++ b/src/main/java/com/hierynomus/smbj/connection/Request.java
@@ -15,12 +15,6 @@
*/
package com.hierynomus.smbj.connection;
-import com.hierynomus.mssmb2.SMB2Packet;
-import com.hierynomus.protocol.commons.concurrent.Promise;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
@@ -29,6 +23,11 @@
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.mssmb2.SMB2Packet;
+import com.hierynomus.protocol.commons.concurrent.Promise;
+import com.hierynomus.smbj.common.SMBRuntimeException;
class Request {
diff --git a/src/main/java/com/hierynomus/smbj/connection/SequenceWindow.java b/src/main/java/com/hierynomus/smbj/connection/SequenceWindow.java
index 4d706b3b..9fee263b 100644
--- a/src/main/java/com/hierynomus/smbj/connection/SequenceWindow.java
+++ b/src/main/java/com/hierynomus/smbj/connection/SequenceWindow.java
@@ -15,11 +15,10 @@
*/
package com.hierynomus.smbj.connection;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
+import com.hierynomus.smbj.common.SMBRuntimeException;
/**
* [MS-SMB2].pdf 3.2.4.1.6 Algorithm for Handling Available Message Sequence Numbers by the Client.
diff --git a/src/main/java/com/hierynomus/smbj/connection/SessionTable.java b/src/main/java/com/hierynomus/smbj/connection/SessionTable.java
index 8faccb5b..3ebe5b61 100644
--- a/src/main/java/com/hierynomus/smbj/connection/SessionTable.java
+++ b/src/main/java/com/hierynomus/smbj/connection/SessionTable.java
@@ -15,15 +15,12 @@
*/
package com.hierynomus.smbj.connection;
-import com.hierynomus.smbj.session.Session;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.smbj.session.Session;
class SessionTable {
private static final Logger logger = LoggerFactory.getLogger(SessionTable.class);
@@ -39,6 +36,15 @@ void registerSession(Long id, Session session) {
}
}
+ Session find(Long id) {
+ lock.lock();
+ try {
+ return lookup.get(id);
+ } finally {
+ lock.unlock();
+ }
+ }
+
Session sessionClosed(Long id) {
lock.lock();
try {
@@ -57,17 +63,10 @@ boolean isActive(Long id) {
}
}
- void closeRemainingSessions() {
+ Collection activeSessions() {
lock.lock();
try {
- for (Long id : new HashSet<>(lookup.keySet())) {
- Session session = lookup.get(id);
- try {
- session.close();
- } catch (IOException e) {
- logger.error("Error closing session", e);
- }
- }
+ return new ArrayList<>(lookup.values());
} finally {
lock.unlock();
}
diff --git a/src/main/java/com/hierynomus/smbj/io/ByteChunkProvider.java b/src/main/java/com/hierynomus/smbj/io/ByteChunkProvider.java
index 6bb478e2..1ea961f3 100644
--- a/src/main/java/com/hierynomus/smbj/io/ByteChunkProvider.java
+++ b/src/main/java/com/hierynomus/smbj/io/ByteChunkProvider.java
@@ -15,21 +15,21 @@
*/
package com.hierynomus.smbj.io;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-
import java.io.IOException;
import java.io.OutputStream;
+import com.hierynomus.protocol.commons.buffer.Buffer;
+import com.hierynomus.smbj.common.SMBRuntimeException;
public abstract class ByteChunkProvider {
- static final int CHUNK_SIZE = 64 * 1024;
+ protected static final int CHUNK_SIZE = 64 * 1024;
- protected long offset = 0;
+ protected long offset;
+ protected int chunkSize = CHUNK_SIZE;
public abstract boolean isAvailable();
public void writeChunk(OutputStream os) {
- byte[] chunk = new byte[CHUNK_SIZE];
+ byte[] chunk = new byte[chunkSize];
try {
int size = getChunk(chunk);
os.write(chunk, 0, size);
@@ -40,7 +40,7 @@ public void writeChunk(OutputStream os) {
}
public void writeChunks(Buffer> buffer, int nrChunks) {
- byte[] chunk = new byte[CHUNK_SIZE];
+ byte[] chunk = new byte[chunkSize];
for (int i = 0; i < nrChunks; i++) {
try {
int size = getChunk(chunk);
@@ -53,7 +53,7 @@ public void writeChunks(Buffer> buffer, int nrChunks) {
}
public void writeChunk(Buffer> buffer) {
- byte[] chunk = new byte[CHUNK_SIZE];
+ byte[] chunk = new byte[chunkSize];
try {
int size = getChunk(chunk);
buffer.putRawBytes(chunk, 0, size);
diff --git a/src/main/java/com/hierynomus/smbj/io/FileByteChunkProvider.java b/src/main/java/com/hierynomus/smbj/io/FileByteChunkProvider.java
index db1a5566..598f85dc 100644
--- a/src/main/java/com/hierynomus/smbj/io/FileByteChunkProvider.java
+++ b/src/main/java/com/hierynomus/smbj/io/FileByteChunkProvider.java
@@ -15,9 +15,8 @@
*/
package com.hierynomus.smbj.io;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-
import java.io.*;
+import com.hierynomus.smbj.common.SMBRuntimeException;
public class FileByteChunkProvider extends ByteChunkProvider {
@@ -29,6 +28,24 @@ public FileByteChunkProvider(File file) throws FileNotFoundException {
fis = new BufferedInputStream(new FileInputStream(file), CHUNK_SIZE);
}
+ public FileByteChunkProvider(File file, long offset) throws IOException {
+ this.file = file;
+ fis = new BufferedInputStream(new FileInputStream(file), CHUNK_SIZE);
+ ensureSkipped(fis, offset);
+ this.offset = offset;
+ }
+
+ private void ensureSkipped(final BufferedInputStream fis, final long offset) throws IOException {
+ long skipped = 0;
+ while (skipped < offset && fis.available() > 0) {
+ skipped += fis.skip(offset);
+ }
+
+ if (skipped < offset) {
+ throw new IOException("Was unable to go to the requested offset of " + offset + " of file " + file);
+ }
+ }
+
@Override
protected int getChunk(byte[] chunk) throws IOException {
int count = 0;
diff --git a/src/main/java/com/hierynomus/smbj/io/InputStreamByteChunkProvider.java b/src/main/java/com/hierynomus/smbj/io/InputStreamByteChunkProvider.java
index cc143276..f6ca5944 100644
--- a/src/main/java/com/hierynomus/smbj/io/InputStreamByteChunkProvider.java
+++ b/src/main/java/com/hierynomus/smbj/io/InputStreamByteChunkProvider.java
@@ -15,10 +15,11 @@
*/
package com.hierynomus.smbj.io;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import com.hierynomus.smbj.common.SMBRuntimeException;
-import java.io.*;
-
public class InputStreamByteChunkProvider extends ByteChunkProvider {
private BufferedInputStream is;
diff --git a/src/main/java/com/hierynomus/smbj/session/Session.java b/src/main/java/com/hierynomus/smbj/session/Session.java
index 683de167..4f22eb3b 100644
--- a/src/main/java/com/hierynomus/smbj/session/Session.java
+++ b/src/main/java/com/hierynomus/smbj/session/Session.java
@@ -17,13 +17,16 @@
import java.io.IOException;
import java.util.concurrent.Future;
+import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.mssmb2.SMB2ShareCapabilities;
import com.hierynomus.mssmb2.messages.SMB2Logoff;
import com.hierynomus.mssmb2.messages.SMB2TreeConnectRequest;
import com.hierynomus.mssmb2.messages.SMB2TreeConnectResponse;
import com.hierynomus.protocol.commons.concurrent.Futures;
+import com.hierynomus.smbj.common.MessageSigning;
import com.hierynomus.smbj.common.SMBApiException;
import com.hierynomus.smbj.common.SMBRuntimeException;
import com.hierynomus.smbj.common.SmbPath;
@@ -41,16 +44,24 @@
*/
public class Session implements AutoCloseable {
private static final Logger logger = LoggerFactory.getLogger(Session.class);
- long sessionId;
+ private long sessionId;
+
+ private SecretKeySpec signingKeySpec;
+ private boolean signingRequired;
+
private Connection connection;
private SMBEventBus bus;
private TreeConnectTable treeConnectTable = new TreeConnectTable();
- public Session(long sessionId, Connection connection, SMBEventBus bus) {
+ public Session(long sessionId, Connection connection, SMBEventBus bus, boolean signingRequired) {
this.sessionId = sessionId;
this.connection = connection;
this.bus = bus;
- bus.subscribe(this);
+ this.signingKeySpec = null;
+ this.signingRequired = signingRequired;
+ if (bus != null) {
+ bus.subscribe(this);
+ }
}
public long getSessionId() {
@@ -84,9 +95,10 @@ private Share connectTree(final String shareName) {
try {
SMB2TreeConnectRequest smb2TreeConnectRequest = new SMB2TreeConnectRequest(connection.getNegotiatedProtocol().getDialect(), smbPath, sessionId);
smb2TreeConnectRequest.getHeader().setCreditRequest(256);
- Future send = connection.send(smb2TreeConnectRequest);
+ Future send = this.send(smb2TreeConnectRequest);
SMB2TreeConnectResponse response = Futures.get(send, TransportException.Wrapper);
if (response.getHeader().getStatus().isError()) {
+ logger.debug(response.getHeader().toString());
throw new SMBApiException(response.getHeader(), "Could not connect to " + smbPath);
}
@@ -114,28 +126,43 @@ private Share connectTree(final String shareName) {
@Handler
private void disconnectTree(TreeDisconnected disconnectEvent) {
if (disconnectEvent.getSessionId() == sessionId) {
- logger.debug("Notified of TreeDisconnected <<" + disconnectEvent.getTreeId() + ">>");
+ logger.debug("Notified of TreeDisconnected <<{}>>", disconnectEvent.getTreeId());
treeConnectTable.closed(disconnectEvent.getTreeId());
}
}
public void logoff() throws TransportException {
- logger.info("Logging off session " + sessionId + " from host " + connection.getRemoteHostname());
+ logger.info("Logging off session {} from host {}", sessionId, connection.getRemoteHostname());
for (TreeConnect treeConnect : treeConnectTable.getOpenTreeConnects()) {
try {
treeConnect.getHandle().close();
} catch (IOException e) {
- logger.error(String.format("Caught exception while closing TreeConnect with id: %s", treeConnect.getTreeId()), e);
+ logger.error("Caught exception while closing TreeConnect with id: {}", treeConnect.getTreeId(), e);
}
}
SMB2Logoff logoff = new SMB2Logoff(connection.getNegotiatedProtocol().getDialect(), sessionId);
- SMB2Logoff response = Futures.get(connection.send(logoff), TransportException.Wrapper);
+ SMB2Logoff response = Futures.get(this.send(logoff), TransportException.Wrapper);
if (!response.getHeader().getStatus().isSuccess()) {
throw new SMBApiException(response.getHeader(), "Could not logoff session <<" + sessionId + ">>");
}
bus.publish(new SessionLoggedOff(sessionId));
}
+ public boolean isSigningRequired() {
+ return signingRequired;
+ }
+
+ public void setSigningKey(byte[] signingKeyBytes) {
+ if (connection.getNegotiatedProtocol().getDialect().isSmb3x()) {
+ throw new IllegalStateException("Cannot set a signing key (yet) for SMB3.x");
+ } else {
+ this.signingKeySpec = new SecretKeySpec(signingKeyBytes, MessageSigning.HMAC_SHA256_ALGORITHM);
+ }
+ }
+
+ public SecretKeySpec getSigningKeySpec() {
+ return signingKeySpec;
+ }
@Override
public void close() throws IOException {
@@ -145,4 +172,31 @@ public void close() throws IOException {
public Connection getConnection() {
return connection;
}
+
+ /**
+ * send a packet. The packet will be signed or not depending on the session's flags.
+ *
+ * @param packet SMBPacket to send
+ * @return a Future to be used to retrieve the response packet
+ * @throws TransportException
+ */
+ public Future send(SMB2Packet packet) throws TransportException {
+ if (signingRequired && signingKeySpec == null) {
+ throw new TransportException("Message signing is required, but no signing key is negotiated");
+ }
+ return connection.send(packet, signingKeySpec);
+ }
+
+ public void setBus(SMBEventBus bus) {
+ if (this.bus != null) {
+ this.bus.unsubscribe(this);
+ this.bus = null;
+ }
+ this.bus = bus;
+ bus.subscribe(this);
+ }
+
+ public void setSessionId(long sessionId) {
+ this.sessionId = sessionId;
+ }
}
diff --git a/src/main/java/com/hierynomus/smbj/session/TreeConnectTable.java b/src/main/java/com/hierynomus/smbj/session/TreeConnectTable.java
index 42d6e161..9a17bef5 100644
--- a/src/main/java/com/hierynomus/smbj/session/TreeConnectTable.java
+++ b/src/main/java/com/hierynomus/smbj/session/TreeConnectTable.java
@@ -15,17 +15,16 @@
*/
package com.hierynomus.smbj.session;
-import com.hierynomus.smbj.share.TreeConnect;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import com.hierynomus.smbj.share.TreeConnect;
/**
* [MS-SMB2].pdf 3.2.1.3 Per Session
- *
+ *
* A table of tree connects, as specified in section 3.2.1.4. The table MUST allow lookup by both TreeConnect.TreeConnectId and by share name.
*/
class TreeConnectTable {
diff --git a/src/main/java/com/hierynomus/smbj/share/Directory.java b/src/main/java/com/hierynomus/smbj/share/Directory.java
index 15417eb7..1c1c7382 100644
--- a/src/main/java/com/hierynomus/smbj/share/Directory.java
+++ b/src/main/java/com/hierynomus/smbj/share/Directory.java
@@ -15,6 +15,14 @@
*/
package com.hierynomus.smbj.share;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import com.hierynomus.mssmb2.SMB2MessageCommandCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.msfscc.FileInformationClass;
import com.hierynomus.msfscc.fileinformation.FileInfo;
@@ -28,12 +36,6 @@
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.EnumSet;
-import java.util.List;
-import java.util.concurrent.Future;
public class Directory extends DiskEntry {
@@ -46,28 +48,44 @@ public Directory(SMB2FileId fileId, TreeConnect treeConnect, String fileName) {
public List list() throws TransportException, SMBApiException {
Session session = treeConnect.getSession();
Connection connection = session.getConnection();
+ int index = 0;
+ int newDataLength = -1;
+ List fileList = new ArrayList();
- // Query Directory Request
- SMB2QueryDirectoryRequest qdr = new SMB2QueryDirectoryRequest(connection.getNegotiatedProtocol().getDialect(),
+ // Keep querying until we don't get new data
+ do {
+ // Query Directory Request
+ SMB2QueryDirectoryRequest qdr = new SMB2QueryDirectoryRequest(connection.getNegotiatedProtocol().getDialect(),
session.getSessionId(), treeConnect.getTreeId(),
getFileId(), FileInformationClass.FileIdBothDirectoryInformation, // FileInformationClass
// .FileDirectoryInformation,
- EnumSet.of(SMB2QueryDirectoryRequest.SMB2QueryDirectoryFlags.SMB2_REOPEN),
- 0, null);
- Future qdFuture = connection.send(qdr);
+ EnumSet.of(SMB2QueryDirectoryRequest.SMB2QueryDirectoryFlags.SMB2_INDEX_SPECIFIED),
+ index, null);
+ Future qdFuture = connection.send(qdr);
- SMB2QueryDirectoryResponse qdResp = Futures.get(qdFuture, TransportException.Wrapper);
+ SMB2QueryDirectoryResponse qdResp = Futures.get(qdFuture, TransportException.Wrapper);
- if (qdResp.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
- throw new SMBApiException(qdResp.getHeader(), "Query directory failed for " + fileName + "/" + fileId);
- }
- byte[] outputBuffer = qdResp.getOutputBuffer();
+ if (qdResp.getHeader().getStatus() == NtStatus.STATUS_NO_MORE_FILES) {
+ newDataLength = 0;
+ } else {
+ if (qdResp.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
+ throw new SMBApiException(qdResp.getHeader().getStatus(),
+ qdResp.getHeader().getStatusCode(), SMB2MessageCommandCode.SMB2_QUERY_DIRECTORY,
+ "Query directory failed for " + fileName + "/" + fileId);
+ }
+ byte[] outputBuffer = qdResp.getOutputBuffer();
+ newDataLength = outputBuffer.length;
+ index += newDataLength;
- try {
- return FileInformationFactory.parseFileInformationList(outputBuffer, FileInformationClass.FileIdBothDirectoryInformation);
- } catch (Buffer.BufferException e) {
- throw new TransportException(e);
- }
+ try {
+ fileList.addAll(FileInformationFactory.parseFileInformationList(outputBuffer, FileInformationClass.FileIdBothDirectoryInformation));
+ } catch (Buffer.BufferException e) {
+ throw new TransportException(e);
+ }
+ }
+ } while(newDataLength > 65000); // Optimization for not making the last call which returns NO_MORE_FILES.
+
+ return fileList;
}
public SMB2FileId getFileId() {
diff --git a/src/main/java/com/hierynomus/smbj/share/DiskEntry.java b/src/main/java/com/hierynomus/smbj/share/DiskEntry.java
index 6760f544..5d3f0613 100644
--- a/src/main/java/com/hierynomus/smbj/share/DiskEntry.java
+++ b/src/main/java/com/hierynomus/smbj/share/DiskEntry.java
@@ -15,11 +15,11 @@
*/
package com.hierynomus.smbj.share;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.mssmb2.SMB2FileId;
import com.hierynomus.smbj.common.SMBApiException;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
abstract class DiskEntry {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
diff --git a/src/main/java/com/hierynomus/smbj/share/DiskShare.java b/src/main/java/com/hierynomus/smbj/share/DiskShare.java
index 17486810..ce5b2e27 100644
--- a/src/main/java/com/hierynomus/smbj/share/DiskShare.java
+++ b/src/main/java/com/hierynomus/smbj/share/DiskShare.java
@@ -15,6 +15,11 @@
*/
package com.hierynomus.smbj.share;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.Future;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msdtyp.SecurityDescriptor;
import com.hierynomus.msdtyp.SecurityInformation;
@@ -41,18 +46,15 @@
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.EnumSet;
-import java.util.List;
-import java.util.concurrent.Future;
import static com.hierynomus.msdtyp.AccessMask.FILE_READ_ATTRIBUTES;
import static com.hierynomus.msdtyp.AccessMask.GENERIC_READ;
import static com.hierynomus.msfscc.FileAttributes.FILE_ATTRIBUTE_DIRECTORY;
import static com.hierynomus.msfscc.FileAttributes.FILE_ATTRIBUTE_NORMAL;
-import static com.hierynomus.mssmb2.SMB2ShareAccess.*;
+import static com.hierynomus.mssmb2.SMB2ShareAccess.EnumUtils;
+import static com.hierynomus.mssmb2.SMB2ShareAccess.FILE_SHARE_DELETE;
+import static com.hierynomus.mssmb2.SMB2ShareAccess.FILE_SHARE_READ;
+import static com.hierynomus.mssmb2.SMB2ShareAccess.FILE_SHARE_WRITE;
import static com.hierynomus.mssmb2.messages.SMB2QueryInfoRequest.SMB2QueryInfoType.SMB2_0_INFO_SECURITY;
import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.toLong;
@@ -122,10 +124,10 @@ public DiskEntry getFile(String path) {
* Get a handle to a directory in the given path
*/
public Directory openDirectory(
- String path,
- EnumSet accessMask,
- EnumSet shareAccess,
- SMB2CreateDisposition createDisposition) throws TransportException, SMBApiException {
+ String path,
+ EnumSet accessMask,
+ EnumSet shareAccess,
+ SMB2CreateDisposition createDisposition) throws TransportException, SMBApiException {
logger.info("OpenDirectory {},{},{},{},{}", path, accessMask, shareAccess, createDisposition);
SMB2FileId fileId = open(path, toLong(accessMask), EnumSet.of(FILE_ATTRIBUTE_DIRECTORY), shareAccess, createDisposition, EnumSet.of(SMB2CreateOptions.FILE_DIRECTORY_FILE));
@@ -136,7 +138,7 @@ public Directory openDirectory(
/**
* Get a handle to a file
*/
- public File openFile( String path, EnumSet accessMask, SMB2CreateDisposition createDisposition) throws TransportException, SMBApiException {
+ public File openFile(String path, EnumSet accessMask, SMB2CreateDisposition createDisposition) throws TransportException, SMBApiException {
logger.info("OpenFile {},{},{}", path, accessMask, createDisposition);
SMB2FileId fileId = open(path, toLong(accessMask), null, EnumSet.of(FILE_SHARE_READ), createDisposition, EnumSet.of(SMB2CreateOptions.FILE_NON_DIRECTORY_FILE));
@@ -365,13 +367,13 @@ private String makePath(String first, String... more) {
}
private void deleteCommon(String path, SMB2CreateRequest smb2CreateRequest)
- throws TransportException, SMBApiException {
+ throws TransportException, SMBApiException {
Session session = treeConnect.getSession();
Connection connection = session.getConnection();
// TODO Use Compounding
- Future sendFuture = connection.send(smb2CreateRequest);
+ Future sendFuture = session.send(smb2CreateRequest);
SMB2CreateResponse response = Futures.get(sendFuture, TransportException.Wrapper);
if (response.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
@@ -390,7 +392,7 @@ private void deleteCommon(String path, SMB2CreateRequest smb2CreateRequest)
SMB2SetInfoResponse setInfoResponse = Futures.get(setInfoFuture, TransportException.Wrapper);
if (setInfoResponse.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
- throw new SMBApiException(response.getHeader(), "SetInfo failed for " + path);
+ throw new SMBApiException(setInfoResponse.getHeader(), "SetInfo failed for " + path);
}
} finally {
SMB2Close closeReq = new SMB2Close(connection.getNegotiatedProtocol().getDialect(),
@@ -399,7 +401,7 @@ private void deleteCommon(String path, SMB2CreateRequest smb2CreateRequest)
SMB2Close closeResponse = Futures.get(closeFuture, TransportException.Wrapper);
if (closeResponse.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
- throw new SMBApiException(response.getHeader(), "Close failed for " + path);
+ throw new SMBApiException(closeResponse.getHeader(), "Close failed for " + path);
}
}
@@ -431,11 +433,11 @@ private boolean exists(String path, EnumSet createOptions) th
}
private byte[] queryInfoCommon(
- String path,
- SMB2QueryInfoRequest.SMB2QueryInfoType infoType,
- EnumSet securityInfo,
- FileInformationClass fileInformationClass)
- throws SMBApiException {
+ String path,
+ SMB2QueryInfoRequest.SMB2QueryInfoType infoType,
+ EnumSet securityInfo,
+ FileInformationClass fileInformationClass)
+ throws SMBApiException {
SMB2FileId fileId = null;
try {
@@ -478,7 +480,7 @@ private byte[] queryInfoCommon(
fileId, infoType,
fileInformationClass, fileSysemInformationClass, null, securityInfo);
try {
- Future qiResponseFuture = connection.send(qreq);
+ Future qiResponseFuture = session.send(qreq);
SMB2QueryInfoResponse qresp = Futures.get(qiResponseFuture, SMBRuntimeException.Wrapper);
if (qresp.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
diff --git a/src/main/java/com/hierynomus/smbj/share/File.java b/src/main/java/com/hierynomus/smbj/share/File.java
index 54383d2a..c404e6c1 100644
--- a/src/main/java/com/hierynomus/smbj/share/File.java
+++ b/src/main/java/com/hierynomus/smbj/share/File.java
@@ -15,6 +15,12 @@
*/
package com.hierynomus.smbj.share;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Future;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.mssmb2.SMB2FileId;
import com.hierynomus.mssmb2.messages.SMB2WriteRequest;
@@ -26,13 +32,6 @@
import com.hierynomus.smbj.io.ByteChunkProvider;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.concurrent.Future;
public class File extends DiskEntry {
@@ -52,7 +51,7 @@ public void write(ByteChunkProvider provider, ProgressListener progressListener)
logger.debug("Writing to {} from offset {}", this.fileName, provider.getOffset());
SMB2WriteRequest wreq = new SMB2WriteRequest(connection.getNegotiatedProtocol().getDialect(), getFileId(),
session.getSessionId(), treeConnect.getTreeId(), provider, connection.getNegotiatedProtocol().getMaxWriteSize());
- Future writeFuture = connection.send(wreq);
+ Future writeFuture = session.send(wreq);
SMB2WriteResponse wresp = Futures.get(writeFuture, TransportException.Wrapper);
if (wresp.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
throw new SMBApiException(wresp.getHeader(), "Write failed for " + this);
@@ -100,8 +99,8 @@ public OutputStream getOutputStream(final ProgressListener listener) {
@Override
public String toString() {
return "File{" +
- "fileId=" + fileId +
- ", fileName='" + fileName + '\'' +
- '}';
+ "fileId=" + fileId +
+ ", fileName='" + fileName + '\'' +
+ '}';
}
}
diff --git a/src/main/java/com/hierynomus/smbj/share/FileInputStream.java b/src/main/java/com/hierynomus/smbj/share/FileInputStream.java
index 551ec0b7..b92f90a4 100644
--- a/src/main/java/com/hierynomus/smbj/share/FileInputStream.java
+++ b/src/main/java/com/hierynomus/smbj/share/FileInputStream.java
@@ -15,6 +15,11 @@
*/
package com.hierynomus.smbj.share;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.Future;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.mssmb2.SMB2FileId;
import com.hierynomus.mssmb2.messages.SMB2ReadRequest;
@@ -25,12 +30,6 @@
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.concurrent.Future;
public class FileInputStream extends InputStream {
@@ -121,6 +120,6 @@ private void loadBuffer() throws IOException {
private Future sendRequest() throws IOException {
SMB2ReadRequest rreq = new SMB2ReadRequest(connection.getNegotiatedProtocol(), fileId,
session.getSessionId(), treeConnect.getTreeId(), offset);
- return connection.send(rreq);
+ return session.send(rreq);
}
}
diff --git a/src/main/java/com/hierynomus/smbj/share/FileOutputStream.java b/src/main/java/com/hierynomus/smbj/share/FileOutputStream.java
index 55c4e3ce..9384a26a 100644
--- a/src/main/java/com/hierynomus/smbj/share/FileOutputStream.java
+++ b/src/main/java/com/hierynomus/smbj/share/FileOutputStream.java
@@ -15,6 +15,11 @@
*/
package com.hierynomus.smbj.share;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.Future;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.mssmb2.SMB2FileId;
import com.hierynomus.mssmb2.messages.SMB2WriteRequest;
@@ -26,12 +31,6 @@
import com.hierynomus.smbj.io.ByteChunkProvider;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.concurrent.Future;
public class FileOutputStream extends OutputStream {
@@ -98,7 +97,7 @@ public void flush() throws IOException {
private void sendWriteRequest() throws TransportException {
SMB2WriteRequest wreq = new SMB2WriteRequest(connection.getNegotiatedProtocol().getDialect(), fileId,
session.getSessionId(), treeConnect.getTreeId(), provider, connection.getNegotiatedProtocol().getMaxWriteSize());
- Future writeFuture = connection.send(wreq);
+ Future writeFuture = session.send(wreq);
SMB2WriteResponse wresp = Futures.get(writeFuture, TransportException.Wrapper);
if (wresp.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
throw new SMBApiException(wresp.getHeader(), "Write failed for " + this);
diff --git a/src/main/java/com/hierynomus/smbj/share/Share.java b/src/main/java/com/hierynomus/smbj/share/Share.java
index e8b6ef3f..6e37f392 100644
--- a/src/main/java/com/hierynomus/smbj/share/Share.java
+++ b/src/main/java/com/hierynomus/smbj/share/Share.java
@@ -15,6 +15,12 @@
*/
package com.hierynomus.smbj.share;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.mserref.NtStatus;
import com.hierynomus.msfscc.FileAttributes;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
@@ -31,13 +37,6 @@
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.EnumSet;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicBoolean;
public class Share implements AutoCloseable {
private static final Logger logger = LoggerFactory.getLogger(Share.class);
@@ -71,15 +70,14 @@ public SMB2FileId open(
String path, long accessMask,
EnumSet fileAttributes, EnumSet shareAccess,
SMB2CreateDisposition createDisposition, EnumSet createOptions)
- throws SMBApiException {
+ throws SMBApiException {
logger.info("open {},{}", path);
Session session = treeConnect.getSession();
- Connection connection = session.getConnection();
SMB2CreateRequest cr = openFileRequest(
- treeConnect, path, accessMask, shareAccess, fileAttributes, createDisposition, createOptions);
+ treeConnect, path, accessMask, shareAccess, fileAttributes, createDisposition, createOptions);
try {
- Future responseFuture = connection.send(cr);
+ Future responseFuture = session.send(cr);
SMB2CreateResponse cresponse = Futures.get(responseFuture, SMBRuntimeException.Wrapper);
if (cresponse.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
throw new SMBApiException(cresponse.getHeader(), "Create failed for " + path);
@@ -94,31 +92,32 @@ public SMB2FileId open(
protected static SMB2CreateRequest openFileRequest(
- TreeConnect treeConnect, String path,
- long accessMask,
- EnumSet shareAccess,
- EnumSet fileAttributes,
- SMB2CreateDisposition createDisposition,
- EnumSet createOptions) {
+ TreeConnect treeConnect, String path,
+ long accessMask,
+ EnumSet shareAccess,
+ EnumSet fileAttributes,
+ SMB2CreateDisposition createDisposition,
+ EnumSet createOptions) {
Session session = treeConnect.getSession();
SMB2CreateRequest cr = new SMB2CreateRequest(
session.getConnection().getNegotiatedProtocol().getDialect(),
- session.getSessionId(), treeConnect.getTreeId(),
- accessMask,
- fileAttributes,
- shareAccess,
- createDisposition,
- createOptions, path);
+ session.getSessionId(), treeConnect.getTreeId(),
+ accessMask,
+ fileAttributes,
+ shareAccess,
+ createDisposition,
+ createOptions, path);
return cr;
}
public void close(SMB2FileId fileId) throws TransportException, SMBApiException {
- Connection connection = treeConnect.getSession().getConnection();
+ Session session = treeConnect.getSession();
+ Connection connection = session.getConnection();
SMB2Close closeReq = new SMB2Close(
connection.getNegotiatedProtocol().getDialect(),
treeConnect.getSession().getSessionId(), treeConnect.getTreeId(), fileId);
- Future closeFuture = connection.send(closeReq);
+ Future closeFuture = session.send(closeReq);
SMB2Close closeResp = Futures.get(closeFuture, TransportException.Wrapper);
if (closeResp.getHeader().getStatus() != NtStatus.STATUS_SUCCESS) {
diff --git a/src/main/java/com/hierynomus/smbj/share/TreeConnect.java b/src/main/java/com/hierynomus/smbj/share/TreeConnect.java
index 64fb392d..067bdd1a 100644
--- a/src/main/java/com/hierynomus/smbj/share/TreeConnect.java
+++ b/src/main/java/com/hierynomus/smbj/share/TreeConnect.java
@@ -15,6 +15,8 @@
*/
package com.hierynomus.smbj.share;
+import java.util.EnumSet;
+import java.util.concurrent.Future;
import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.mssmb2.SMB2ShareCapabilities;
import com.hierynomus.mssmb2.messages.SMB2TreeDisconnect;
@@ -27,9 +29,6 @@
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.transport.TransportException;
-import java.util.EnumSet;
-import java.util.concurrent.Future;
-
/**
*
*/
@@ -64,7 +63,7 @@ Connection getConnection() {
void close(Share share) throws TransportException {
SMB2TreeDisconnect disconnect = new SMB2TreeDisconnect(connection.getNegotiatedProtocol().getDialect(), session.getSessionId(), treeId);
- Future send = connection.send(disconnect);
+ Future send = session.send(disconnect);
SMB2Packet smb2Packet = Futures.get(send, TransportException.Wrapper);
if (!smb2Packet.getHeader().getStatus().isSuccess()) {
throw new SMBApiException(smb2Packet.getHeader(), "Error closing connection to " + smbPath);
diff --git a/src/main/java/com/hierynomus/smbj/transport/BaseTransport.java b/src/main/java/com/hierynomus/smbj/transport/BaseTransport.java
index 7578e3e9..e4b70c51 100644
--- a/src/main/java/com/hierynomus/smbj/transport/BaseTransport.java
+++ b/src/main/java/com/hierynomus/smbj/transport/BaseTransport.java
@@ -15,22 +15,25 @@
*/
package com.hierynomus.smbj.transport;
-import com.hierynomus.mssmb2.SMB2Packet;
-import com.hierynomus.smbj.common.SMBBuffer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
import java.util.concurrent.locks.ReentrantLock;
+import javax.crypto.spec.SecretKeySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.mssmb2.SMB2MessageFlag;
+import com.hierynomus.mssmb2.SMB2Packet;
+import com.hierynomus.smbj.common.MessageSigning;
+import com.hierynomus.smbj.common.SMBBuffer;
public abstract class BaseTransport implements TransportLayer {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
protected InputStream in;
protected OutputStream out;
-
private final ReentrantLock writeLock = new ReentrantLock();
@Override
@@ -57,5 +60,32 @@ public void write(SMB2Packet packet) throws TransportException {
}
}
+ @Override
+ public void writeSigned(SMB2Packet packet, SecretKeySpec signingKeySpec) throws TransportException {
+ writeLock.lock();
+ try {
+ try {
+ SMBBuffer buffer = new SMBBuffer();
+ packet.getHeader().setFlag(SMB2MessageFlag.SMB2_FLAGS_SIGNED); // set the SMB2_FLAGS_SIGNED flag
+ packet.write(buffer);
+
+ signBuffer(buffer, signingKeySpec);
+
+ logger.trace("Writing packet << {} >>, sequence number << {} >>", packet.getHeader().getMessage(), packet.getSequenceNumber());
+ doWrite(buffer);
+ out.flush();
+ } catch (IOException | InvalidKeyException | NoSuchAlgorithmException ioe) {
+ throw new TransportException(ioe);
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
protected abstract void doWrite(SMBBuffer packetData) throws IOException;
+
+
+ private static void signBuffer(SMBBuffer buffer, SecretKeySpec signingKeySpec) throws InvalidKeyException, NoSuchAlgorithmException {
+ MessageSigning.signBuffer(buffer.array(), buffer.available(), signingKeySpec);
+ }
}
diff --git a/src/main/java/com/hierynomus/smbj/transport/PacketReader.java b/src/main/java/com/hierynomus/smbj/transport/PacketReader.java
index 27fefb00..15213f6d 100644
--- a/src/main/java/com/hierynomus/smbj/transport/PacketReader.java
+++ b/src/main/java/com/hierynomus/smbj/transport/PacketReader.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.smbj.transport;
-import com.hierynomus.protocol.Packet;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.hierynomus.protocol.Packet;
+import com.hierynomus.smbj.common.SMBRuntimeException;
public abstract class PacketReader> implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(PacketReader.class);
@@ -65,6 +64,7 @@ private void readPacket() throws TransportException {
/**
* Read the actual SMB2 Packet from the {@link InputStream}
+ *
* @return the read SMB2Packet
* @throws TransportException
*/
diff --git a/src/main/java/com/hierynomus/smbj/transport/TransportLayer.java b/src/main/java/com/hierynomus/smbj/transport/TransportLayer.java
index de39ee0c..dcaf9512 100644
--- a/src/main/java/com/hierynomus/smbj/transport/TransportLayer.java
+++ b/src/main/java/com/hierynomus/smbj/transport/TransportLayer.java
@@ -15,16 +15,16 @@
*/
package com.hierynomus.smbj.transport;
-import com.hierynomus.mssmb2.SMB2Packet;
-
import java.io.InputStream;
import java.io.OutputStream;
+import javax.crypto.spec.SecretKeySpec;
+import com.hierynomus.mssmb2.SMB2Packet;
public interface TransportLayer {
/**
* Initialize the Transport layer.
- *
+ *
* This is called directly after a connection has been established.
*/
void init(InputStream in, OutputStream out);
@@ -32,14 +32,24 @@ public interface TransportLayer {
/**
* The default port for the specified SMB transport layer.
*
- * @return the default port
+ * @return the default port
*/
int getDefaultPort();
/**
* Write the packet to the transport.
+ *
* @param packet The packet to write.
* @return The sequence number of the packet.
*/
void write(SMB2Packet packet) throws TransportException;
+
+ /**
+ * Write the packet to the transport, signed using the given signing key.
+ *
+ * @param packet The packet to write.
+ * @param signingKeySpec a SecretKeySpec to use while signing. If null, no signing should be done.
+ * @return The sequence number of the packet.
+ */
+ void writeSigned(SMB2Packet packet, SecretKeySpec signingKeySpec) throws TransportException;
}
diff --git a/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpPacketReader.java b/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpPacketReader.java
index baf61b22..d353b0e9 100644
--- a/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpPacketReader.java
+++ b/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpPacketReader.java
@@ -15,6 +15,8 @@
*/
package com.hierynomus.smbj.transport.tcp;
+import java.io.IOException;
+import java.io.InputStream;
import com.hierynomus.mssmb2.SMB2Packet;
import com.hierynomus.mssmb2.messages.SMB2ResponseMessageFactory;
import com.hierynomus.protocol.Packet;
@@ -25,9 +27,6 @@
import com.hierynomus.smbj.transport.PacketReceiver;
import com.hierynomus.smbj.transport.TransportException;
-import java.io.IOException;
-import java.io.InputStream;
-
public class DirectTcpPacketReader extends PacketReader {
public DirectTcpPacketReader(InputStream in, PacketReceiver handler) {
diff --git a/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpTransport.java b/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpTransport.java
index 7f88e0dd..560004e2 100644
--- a/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpTransport.java
+++ b/src/main/java/com/hierynomus/smbj/transport/tcp/DirectTcpTransport.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.smbj.transport.tcp;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.hierynomus.smbj.common.SMBBuffer;
import com.hierynomus.smbj.transport.BaseTransport;
import com.hierynomus.smbj.transport.TransportLayer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
/**
* A transport layer to do SMB2 over Direct TCP/IP.
diff --git a/src/main/java/com/hierynomus/spnego/NegTokenInit.java b/src/main/java/com/hierynomus/spnego/NegTokenInit.java
index 7ccabd83..1ca395fb 100644
--- a/src/main/java/com/hierynomus/spnego/NegTokenInit.java
+++ b/src/main/java/com/hierynomus/spnego/NegTokenInit.java
@@ -15,15 +15,14 @@
*/
package com.hierynomus.spnego;
-import com.hierynomus.protocol.commons.buffer.Buffer;
-import com.hierynomus.protocol.commons.buffer.Endian;
-import com.hierynomus.smbj.common.SMBRuntimeException;
-import org.bouncycastle.asn1.*;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
+import org.bouncycastle.asn1.*;
+import com.hierynomus.protocol.commons.buffer.Buffer;
+import com.hierynomus.protocol.commons.buffer.Endian;
+import com.hierynomus.smbj.common.SMBRuntimeException;
import static com.hierynomus.spnego.ObjectIdentifiers.SPNEGO;
@@ -102,7 +101,7 @@ public NegTokenInit read(byte[] bytes) throws IOException {
}
private NegTokenInit read(Buffer> buffer) throws IOException {
- try(ASN1InputStream is = new ASN1InputStream(buffer.asInputStream())) {
+ try (ASN1InputStream is = new ASN1InputStream(buffer.asInputStream())) {
ASN1Primitive applicationSpecific = is.readObject();
if (!(applicationSpecific instanceof BERApplicationSpecific || applicationSpecific instanceof DERApplicationSpecific)) {
throw new SpnegoException("Incorrect GSS-API ASN.1 token received, expected to find an [APPLICATION 0], not: " + applicationSpecific);
diff --git a/src/main/java/com/hierynomus/spnego/NegTokenTarg.java b/src/main/java/com/hierynomus/spnego/NegTokenTarg.java
index 876cc254..2d1612a2 100644
--- a/src/main/java/com/hierynomus/spnego/NegTokenTarg.java
+++ b/src/main/java/com/hierynomus/spnego/NegTokenTarg.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.spnego;
+import java.io.IOException;
+import java.math.BigInteger;
+import org.bouncycastle.asn1.*;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.protocol.commons.buffer.Endian;
import com.hierynomus.smbj.common.SMBRuntimeException;
-import org.bouncycastle.asn1.*;
-
-import java.io.IOException;
-import java.math.BigInteger;
/**
* This class can encode and decode the SPNEGO negTokenInit Token.
diff --git a/src/main/java/com/hierynomus/spnego/SpnegoToken.java b/src/main/java/com/hierynomus/spnego/SpnegoToken.java
index 67ffa610..774d7d6d 100644
--- a/src/main/java/com/hierynomus/spnego/SpnegoToken.java
+++ b/src/main/java/com/hierynomus/spnego/SpnegoToken.java
@@ -15,13 +15,12 @@
*/
package com.hierynomus.spnego;
-import com.hierynomus.protocol.commons.buffer.Buffer;
+import java.io.IOException;
+import java.util.Enumeration;
import org.bouncycastle.asn1.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Enumeration;
+import com.hierynomus.protocol.commons.buffer.Buffer;
import static com.hierynomus.spnego.ObjectIdentifiers.SPNEGO;
@@ -58,8 +57,8 @@ protected void parseSpnegoToken(ASN1Encodable spnegoToken) throws IOException {
}
Enumeration tokenObjects = ((ASN1Sequence) negToken).getObjects();
- while(tokenObjects.hasMoreElements()) {
- ASN1Encodable asn1Encodable = (ASN1Encodable)tokenObjects.nextElement();
+ while (tokenObjects.hasMoreElements()) {
+ ASN1Encodable asn1Encodable = (ASN1Encodable) tokenObjects.nextElement();
if (!(asn1Encodable instanceof ASN1TaggedObject)) {
throw new SpnegoException("Expected an ASN.1 TaggedObject as " + tokenName + " contents, not: " + asn1Encodable);
}
diff --git a/src/test/groovy/com/hierynomus/msdtyp/SIDTest.groovy b/src/test/groovy/com/hierynomus/msdtyp/SIDTest.groovy
index 65f8ce5b..99297230 100644
--- a/src/test/groovy/com/hierynomus/msdtyp/SIDTest.groovy
+++ b/src/test/groovy/com/hierynomus/msdtyp/SIDTest.groovy
@@ -23,4 +23,14 @@ class SIDTest extends Specification {
expect:
SID.EVERYONE.toString() == "S-1-1-0"
}
+
+ def "SID identity"() {
+ given:
+ SID s1 = new SID((byte) 1, [0, 0, 0, 0, 0, 1] as byte[], [0] as long[]);
+ SID s2 = new SID((byte) 1, [0, 0, 0, 0, 0, 1] as byte[], [0] as long[]);
+
+ expect:
+ s1 == s2
+ s1.hashCode() == s2.hashCode()
+ }
}
diff --git a/src/test/groovy/com/hierynomus/mssmb2/SMB2NotifyResponseTest.groovy b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponseTest.groovy
similarity index 96%
rename from src/test/groovy/com/hierynomus/mssmb2/SMB2NotifyResponseTest.groovy
rename to src/test/groovy/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponseTest.groovy
index e4c0a608..4a770b1f 100644
--- a/src/test/groovy/com/hierynomus/mssmb2/SMB2NotifyResponseTest.groovy
+++ b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2ChangeNotifyResponseTest.groovy
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.hierynomus.mssmb2
+package com.hierynomus.mssmb2.messages
import com.hierynomus.mssmb2.messages.SMB2ChangeNotifyResponse
import com.hierynomus.smbj.common.SMBBuffer
@@ -21,7 +21,7 @@ import spock.lang.Specification
import javax.xml.bind.DatatypeConverter
-class SMB2NotifyResponseTest extends Specification {
+class SMB2ChangeNotifyResponseTest extends Specification {
def "should parse notifications"() {
given:
diff --git a/src/test/groovy/com/hierynomus/mssmb2/SMB2CreateResponseTest.groovy b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2CreateResponseTest.groovy
similarity index 97%
rename from src/test/groovy/com/hierynomus/mssmb2/SMB2CreateResponseTest.groovy
rename to src/test/groovy/com/hierynomus/mssmb2/messages/SMB2CreateResponseTest.groovy
index a36bf1fb..0c3a11a6 100644
--- a/src/test/groovy/com/hierynomus/mssmb2/SMB2CreateResponseTest.groovy
+++ b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2CreateResponseTest.groovy
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.hierynomus.mssmb2
+package com.hierynomus.mssmb2.messages
import com.hierynomus.mssmb2.messages.SMB2CreateResponse
import com.hierynomus.smbj.common.SMBBuffer
diff --git a/src/test/groovy/com/hierynomus/mssmb2/SMB2QueryDirectoryResponseTest.groovy b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryResponseTest.groovy
similarity index 99%
rename from src/test/groovy/com/hierynomus/mssmb2/SMB2QueryDirectoryResponseTest.groovy
rename to src/test/groovy/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryResponseTest.groovy
index 32cb8655..cc1598e5 100644
--- a/src/test/groovy/com/hierynomus/mssmb2/SMB2QueryDirectoryResponseTest.groovy
+++ b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2QueryDirectoryResponseTest.groovy
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.hierynomus.mssmb2
+package com.hierynomus.mssmb2.messages
import com.hierynomus.msfscc.FileInformationClass
import com.hierynomus.msfscc.fileinformation.FileInformationFactory
diff --git a/src/test/groovy/com/hierynomus/mssmb2/SMB2ReadResponseTest.groovy b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2ReadResponseTest.groovy
similarity index 99%
rename from src/test/groovy/com/hierynomus/mssmb2/SMB2ReadResponseTest.groovy
rename to src/test/groovy/com/hierynomus/mssmb2/messages/SMB2ReadResponseTest.groovy
index b4b73563..8d7ffac2 100644
--- a/src/test/groovy/com/hierynomus/mssmb2/SMB2ReadResponseTest.groovy
+++ b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2ReadResponseTest.groovy
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.hierynomus.mssmb2
+package com.hierynomus.mssmb2.messages
import com.hierynomus.mserref.NtStatus
import com.hierynomus.mssmb2.messages.SMB2ReadResponse
diff --git a/src/test/groovy/com/hierynomus/mssmb2/SMB2TreeConnectResponseTest.groovy b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponseTest.groovy
similarity index 94%
rename from src/test/groovy/com/hierynomus/mssmb2/SMB2TreeConnectResponseTest.groovy
rename to src/test/groovy/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponseTest.groovy
index d130f5d1..680e0b07 100644
--- a/src/test/groovy/com/hierynomus/mssmb2/SMB2TreeConnectResponseTest.groovy
+++ b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2TreeConnectResponseTest.groovy
@@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.hierynomus.mssmb2
+package com.hierynomus.mssmb2.messages
+import com.hierynomus.mssmb2.SMB2ShareCapabilities
import com.hierynomus.mssmb2.messages.SMB2TreeConnectResponse
import com.hierynomus.smbj.common.SMBBuffer
import spock.lang.Specification
diff --git a/src/test/groovy/com/hierynomus/mssmb2/SMB2WriteResponseTest.groovy b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2WriteResponseTest.groovy
similarity index 97%
rename from src/test/groovy/com/hierynomus/mssmb2/SMB2WriteResponseTest.groovy
rename to src/test/groovy/com/hierynomus/mssmb2/messages/SMB2WriteResponseTest.groovy
index 99da05f6..4f26c4ec 100644
--- a/src/test/groovy/com/hierynomus/mssmb2/SMB2WriteResponseTest.groovy
+++ b/src/test/groovy/com/hierynomus/mssmb2/messages/SMB2WriteResponseTest.groovy
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.hierynomus.mssmb2
+package com.hierynomus.mssmb2.messages
import com.hierynomus.mssmb2.messages.SMB2WriteResponse
import com.hierynomus.smbj.common.SMBBuffer
diff --git a/src/test/groovy/com/hierynomus/smbj/io/FileByteChunkProviderTest.groovy b/src/test/groovy/com/hierynomus/smbj/io/FileByteChunkProviderTest.groovy
index b3668634..be7d411d 100644
--- a/src/test/groovy/com/hierynomus/smbj/io/FileByteChunkProviderTest.groovy
+++ b/src/test/groovy/com/hierynomus/smbj/io/FileByteChunkProviderTest.groovy
@@ -67,6 +67,24 @@ class FileByteChunkProviderTest extends Specification {
provider.isAvailable()
}
+ def "should start at provided offset"() {
+ given:
+ def file = getFileWithRandomData(ByteChunkProvider.CHUNK_SIZE)
+ def provider = new FileByteChunkProvider(file, 100)
+ def baos = new ByteArrayOutputStream()
+
+ when:
+ provider.writeChunk(baos)
+
+ then:
+ def tmpBytes = new byte[ByteChunkProvider.CHUNK_SIZE - 100]
+ System.arraycopy(file.bytes, 100, tmpBytes, 0, tmpBytes.length)
+ baos.toByteArray() == tmpBytes
+ provider.offset == ByteChunkProvider.CHUNK_SIZE
+ !provider.isAvailable()
+
+ }
+
private def getFileWithRandomData(int size) {
def bytes = new byte[size]
new Random().nextBytes(bytes)