Skip to content

Commit

Permalink
Cleaned up implementation of smb3-dev branch (#455)
Browse files Browse the repository at this point in the history
* WIP

* Clean code from smb3-dev

* SMB3 Cleaned up part of the implementation

* SMB3 added salt

* Move session creation to separate class

* WIP

- Renamed SMB2Header -> SMB2PacketHeader
- Added SMB3EncryptedPacket*
- Added start for IncomingPacketHandler

* Split up Packet Handling into handlers

* Add SMB2_TRANSFORM_HEADER

* WIP

* Work on SMB3

* Use SMB2.1 in integration tests

* Few more SMB3 parts

* Implemented 3.2.5.2

* Calculate SMB3.1.1 preauthIntegrityHashValue

* Fix workflow file

* Fix workflow file 2

* WIP

* organize imports

* Cleanup warnings

* Fixed build

* Start integrating PacketEncryptor

* Fixed signing/verification of messages

* TargetHint Array throws Index Out Of Bounds Exception (#588)

* Getting there... Encrypted message is not quite right yet

* Working encryption

* Fix preferred encryption when available

* Fixed bug in remoteCopy IOCTL requests

Co-authored-by: pranaysharmamanulife <pranay_sharma@manulife.com>
  • Loading branch information
hierynomus and pranaysharmamanulife authored Jan 8, 2021
1 parent da51799 commit 78da5c8
Show file tree
Hide file tree
Showing 124 changed files with 4,534 additions and 778 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Build SMBJ


on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
java11:
name: Build with Java 11
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Build with Gradle
run: ./gradlew check
integration:
name: Integration test
needs: [java11]
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Run integration tests
run: ./gradlew integrationTest

9 changes: 5 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defaultTasks "build"
repositories {
mavenCentral()
maven { url "https://jitpack.io" }
maven { url "http://dl.bintray.com/typesafe/maven-releases" }
maven { url "http://dl.bintray.com/hierynomus/maven" }
}

sourceCompatibility = 1.8
Expand Down Expand Up @@ -229,6 +229,7 @@ sonarqube {
}
}


task buildItestImage(type: DockerBuildImage) {
inputDir = file('src/it/docker-image')
images.add('smbj/smbj-itest:latest')
Expand All @@ -242,12 +243,12 @@ task createItestContainer(type: DockerCreateContainer) {
}

task startItestContainer(type: DockerStartContainer) {
dependsOn createItestContainer
targetContainerId createItestContainer.getContainerId()
dependsOn createItestContainer
targetContainerId createItestContainer.getContainerId()
}

task stopItestContainer(type: DockerStopContainer) {
targetContainerId createItestContainer.getContainerId()
targetContainerId createItestContainer.getContainerId()
}

project.tasks.integrationTest.dependsOn(startItestContainer)
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ MBASSADOR=net.engio:mbassador:1.3.0
OBJENESIS=org.objenesis:objenesis:2.6
SLF4J_API=org.slf4j:slf4j-api:1.7.25
SPOCK_CORE=org.spockframework:spock-core:2.0-M4-groovy-2.5
ASN_ONE=com.hierynomus:asn-one:0.4.0
ASN_ONE=com.hierynomus:asn-one:0.5.0
3 changes: 3 additions & 0 deletions src/it/docker-image/supervisord.conf
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
[supervisord]
nodaemon=true
/* user=root */
loglevel=info

[program:smbd]
/* command=/usr/sbin/smbd -i --daemon --foreground --log-stdout */
command=/usr/sbin/smbd --daemon --foreground --log-stdout
redirect_stderr=true

[program:nmbd]
/* command=/usr/sbin/nmbd -i --daemon --foreground --log-stdout */
command=/usr/sbin/nmbd --daemon --foreground --log-stdout
redirect_stderr=true
3 changes: 3 additions & 0 deletions src/it/groovy/com/hierynomus/smbj/DfsIntegrationSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package com.hierynomus.smbj

import com.hierynomus.msdtyp.AccessMask
import com.hierynomus.mssmb2.SMB2CreateDisposition
import com.hierynomus.mssmb2.SMB2Dialect
import com.hierynomus.mssmb2.SMB2ShareAccess
import com.hierynomus.security.bc.BCSecurityProvider
import com.hierynomus.smbj.auth.AuthenticationContext
import com.hierynomus.smbj.connection.Connection
import com.hierynomus.smbj.session.Session
Expand All @@ -33,6 +35,7 @@ class DfsIntegrationSpec extends Specification {
def setup() {
def config = SmbConfig
.builder()
.withDialects(SMB2Dialect.SMB_2_1)
.withMultiProtocolNegotiate(true)
.withSigningRequired(true)
.withDfsEnabled(true)
Expand Down
3 changes: 2 additions & 1 deletion src/it/groovy/com/hierynomus/smbj/IntegrationTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.hierynomus.smbj

import com.hierynomus.msdtyp.AccessMask
import com.hierynomus.mssmb2.SMB2Dialect
import com.hierynomus.mssmb2.SMB2ShareAccess
import com.hierynomus.security.bc.BCSecurityProvider
import com.hierynomus.smbj.auth.AuthenticationContext
Expand All @@ -35,7 +36,7 @@ class IntegrationTest extends Specification {
static final def FOLDER_THAT_DOES_NOT_EXIST = "foo"


def config = SmbConfig.builder().withSigningRequired(true).withMultiProtocolNegotiate(true).withDfsEnabled(true).withSecurityProvider(new BCSecurityProvider()).build()
def config = SmbConfig.builder().withDialects(SMB2Dialect.SMB_3_0).withEncryptData(true).withSigningRequired(true).withMultiProtocolNegotiate(true).withDfsEnabled(true).withSecurityProvider(new BCSecurityProvider()).build()
def client = new SMBClient(config)
def connection = _

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import com.hierynomus.msfscc.fileinformation.FileStandardInformation
import com.hierynomus.mssmb2.SMB2ChangeNotifyFlags
import com.hierynomus.mssmb2.SMB2CompletionFilter
import com.hierynomus.mssmb2.SMB2CreateDisposition
import com.hierynomus.mssmb2.SMB2Dialect
import com.hierynomus.mssmb2.SMB2ShareAccess
import com.hierynomus.mssmb2.SMBApiException
import com.hierynomus.mssmb2.messages.SMB2Cancel
import com.hierynomus.mssmb2.messages.SMB2ChangeNotifyResponse
import com.hierynomus.protocol.commons.concurrent.Futures
import com.hierynomus.security.bc.BCSecurityProvider
import com.hierynomus.smbj.auth.AuthenticationContext
import com.hierynomus.smbj.common.SMBRuntimeException
import com.hierynomus.smbj.connection.Connection
Expand All @@ -52,8 +54,11 @@ class SMB2DirectoryIntegrationTest extends Specification {
def setup() {
def config = SmbConfig
.builder()
.withDialects(SMB2Dialect.SMB_3_0)
.withEncryptData(true)
.withSecurityProvider(new BCSecurityProvider())
.withMultiProtocolNegotiate(true)
.withTransportLayerFactory(new AsyncDirectTcpTransportFactory<>())
.withTransportLayerFactory(new AsyncDirectTcpTransportFactory<>())
.withSigningRequired(true).build()
client = new SMBClient(config)
connection = client.connect("127.0.0.1")
Expand Down
22 changes: 15 additions & 7 deletions src/it/groovy/com/hierynomus/smbj/SMB2FileIntegrationTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import com.hierynomus.msfscc.fileinformation.FileStandardInformation
import com.hierynomus.mssmb2.SMB2ChangeNotifyFlags
import com.hierynomus.mssmb2.SMB2CompletionFilter
import com.hierynomus.mssmb2.SMB2CreateDisposition
import com.hierynomus.mssmb2.SMB2Dialect
import com.hierynomus.mssmb2.SMB2ShareAccess
import com.hierynomus.mssmb2.SMBApiException
import com.hierynomus.security.bc.BCSecurityProvider
import com.hierynomus.mssmb2.SMB2LockFlag
import com.hierynomus.mssmb2.SMB2ShareAccess
import com.hierynomus.mssmb2.SMBApiException
Expand All @@ -38,6 +42,7 @@ import com.hierynomus.smbj.io.InputStreamByteChunkProvider
import com.hierynomus.smbj.session.Session
import com.hierynomus.smbj.share.DiskShare
import com.hierynomus.smbj.transport.tcp.async.AsyncDirectTcpTransportFactory
import com.hierynomus.smbj.transport.tcp.direct.DirectTcpTransportFactory
import spock.lang.Specification
import spock.lang.Unroll

Expand All @@ -56,8 +61,11 @@ class SMB2FileIntegrationTest extends Specification {
def config = SmbConfig
.builder()
.withMultiProtocolNegotiate(true)
.withTransportLayerFactory(new AsyncDirectTcpTransportFactory<>())
.withSigningRequired(true).build()
.withDialects(SMB2Dialect.SMB_3_0).withEncryptData(true)
.withTransportLayerFactory(new DirectTcpTransportFactory<>())
.withSecurityProvider(new BCSecurityProvider())
.withSigningRequired(true)
/*.withEncryptData(true)*/.build()
client = new SMBClient(config)
connection = client.connect("127.0.0.1")
session = connection.authenticate(new AuthenticationContext("smbj", "smbj".toCharArray(), null))
Expand Down Expand Up @@ -275,7 +283,7 @@ class SMB2FileIntegrationTest extends Specification {
def bytes2 = new byte[1024 * 1024]
Random.newInstance().nextBytes(bytes2)
def istream2 = new ByteArrayInputStream(bytes2)
ostream = appendfile.getOutputStream(new LoggingProgressListener(),true)
ostream = appendfile.getOutputStream(new LoggingProgressListener(), true)
try {
byte[] buffer = new byte[4096]
int len
Expand All @@ -292,7 +300,7 @@ class SMB2FileIntegrationTest extends Specification {
share.fileExists("appendfile")

when:
def readBytes = new byte[2* 1024 * 1024]
def readBytes = new byte[2 * 1024 * 1024]
def readFile = share.openFile("appendfile", EnumSet.of(AccessMask.FILE_READ_DATA), null, SMB2ShareAccess.ALL, FILE_OPEN, null)
try {
def remoteIs = readFile.getInputStream(new LoggingProgressListener())
Expand All @@ -314,7 +322,7 @@ class SMB2FileIntegrationTest extends Specification {
}

then:
readBytes == [bytes,bytes2].flatten()
readBytes == [bytes, bytes2].flatten()

cleanup:
share.rm("appendfile")
Expand Down Expand Up @@ -385,8 +393,8 @@ class SMB2FileIntegrationTest extends Specification {
noExceptionThrown()

where:
method | func
"rm" | { s -> s.rm("test.txt") }
method | func
"rm" | { s -> s.rm("test.txt") }
"fileExists" | { s -> s.fileExists("test.txt") }
}

Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/hierynomus/mssmb/SMB1Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@
* This class is currently hardcoded to SMB_COM_NEGOTIATE
*/
public class SMB1Header implements SMBHeader {
private int headerStartPosition;
private int messageEndPosition;

@Override
public void writeTo(SMBBuffer buffer) {
this.headerStartPosition = buffer.wpos(); // Keep track of header start
buffer.putRawBytes(new byte[]{(byte) 0xFF, 'S', 'M', 'B'}); // Protocol (4 bytes)
buffer.putByte((byte) 0x72); // Command (1 byte)
buffer.putUInt32(0x0); // Status (4 bytes)
Expand All @@ -45,4 +49,18 @@ public void writeTo(SMBBuffer buffer) {
public void readFrom(Buffer<?> buffer) {
throw new UnsupportedOperationException("Receiving SMBv1 Messages not supported in SMBJ");
}

@Override
public int getHeaderStartPosition() {
return headerStartPosition;
}

@Override
public int getMessageEndPosition() {
return messageEndPosition;
}

public void setMessageEndPosition(int messageEndPosition) {
this.messageEndPosition = messageEndPosition;
}
}
1 change: 1 addition & 0 deletions src/main/java/com/hierynomus/mssmb/SMB1Packet.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ protected SMB1Packet() {

@Override
public final void write(SMBBuffer buffer) {
this.buffer = buffer;
header.writeTo(buffer);
writeTo(buffer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public void writeTo(SMBBuffer buffer) {
buffer.putByte((byte) 0x02); // BufferFormat (1 byte)
buffer.putNullTerminatedString(s, Charsets.UTF_8);
}
header.setMessageEndPosition(buffer.wpos());
}

@Override
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/hierynomus/mssmb2/DeadLetterPacketData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.mssmb2;

import com.hierynomus.smb.SMBHeader;
import com.hierynomus.smb.SMBPacketData;

/**
* Ignore this packet...
*/
public class DeadLetterPacketData extends SMBPacketData<SMBHeader> {
public DeadLetterPacketData(SMBHeader header) {
super(header);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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.mssmb2;

import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smb.SMBBuffer;
import com.hierynomus.smb.SMBHeader;
import com.hierynomus.smbj.common.Check;

/**
* [MS-SMB2] 2.2.42 SMB2 COMPRESSION_TRANSFORM_HEADER
* <p>
* The SMB2 COMPRESSION_TRANSFORM_HEADER is used by the client or server when sending compressed messages.
* This optional header is only valid for the SMB 3.1.1 dialect<73>.
*/
public class SMB2CompressionTransformHeader implements SMBHeader {
public static final byte[] COMPRESSED_PROTOCOL_ID = {(byte) 0xFC, 'S', 'M', 'B'};
private int headerStartPosition;
private int originalCompressedSegmentSize;
private SMB3CompressionAlgorithm compressionAlgorithm;
private int offset;
private int messageEndPosition;

@Override
public void writeTo(SMBBuffer buffer) {

}

@Override
public void readFrom(Buffer<?> buffer) throws Buffer.BufferException {
this.headerStartPosition = buffer.rpos(); // Keep track of the header start position.
byte[] protocolId = buffer.readRawBytes(4); // ProtocolId (4 bytes) (already verified)
Check.ensureEquals(protocolId, COMPRESSED_PROTOCOL_ID, "Could not find SMB2 Packet header");
this.originalCompressedSegmentSize = buffer.readUInt32AsInt(); // OriginalCompressedSegmentSize (4 bytes)
this.compressionAlgorithm = EnumWithValue.EnumUtils.valueOf(buffer.readUInt16(), SMB3CompressionAlgorithm.class, null);
Check.ensure(compressionAlgorithm != null && compressionAlgorithm != SMB3CompressionAlgorithm.NONE, "The CompressionAlgorithm field of the SMB2_COMPRESSION_TRANSFORM_HEADER should contain a valid value.");
buffer.skip(2);
this.offset = buffer.readUInt32AsInt(); // Offset (4 bytes)
this.messageEndPosition = buffer.wpos();
}

@Override
public int getHeaderStartPosition() {
return headerStartPosition;
}

@Override
public int getMessageEndPosition() {
return messageEndPosition;
}

public int getOriginalCompressedSegmentSize() {
return originalCompressedSegmentSize;
}

public SMB3CompressionAlgorithm getCompressionAlgorithm() {
return compressionAlgorithm;
}

public int getOffset() {
return offset;
}
}
Loading

0 comments on commit 78da5c8

Please sign in to comment.