Files

329 lines
12 KiB
Swift

//
// SMB2NegotiationTypes.swift
// ExtDownloader
//
// Created by Amir Abbas Mousavian on 4/30/95.
// Copyright © 1395 Mousavian. All rights reserved.
//
import Foundation
extension SMB2 {
// MARK: SMB2 Negotiating
struct NegotiateRequest: SMBRequest {
let header: NegotiateRequest.Header
let dialects: [UInt16]
let contexts: [(type: NegotiateContextType, data: NSData)]
init(header: NegotiateRequest.Header, dialects: [UInt16] = [0x0202], contexts: [(type: NegotiateContextType, data: NSData)] = []) {
self.header = header
self.dialects = dialects
self.contexts = contexts
}
init(dialects: [UInt16] = [0x0202], contexts: [(type: NegotiateContextType, data: NSData)] = [],capabilities: GlobalCapabilities = [], clientStartTime: SMBTime? = nil, guid: uuid_t? = nil, signing: NegotiateSinging = [.ENABLED]) {
self.header = Header(capabilities: capabilities, clientStartTime: clientStartTime, guid: guid, signing: signing)
self.dialects = dialects
self.contexts = contexts
}
func data() -> NSData {
var header = self.header
header.dialectCount = UInt16(dialects.count)
let dialectData = NSMutableData()
for dialect in dialects {
var dialect = dialect
dialectData.appendBytes(&dialect, length: 2)
}
let pad = ((1024 - dialectData.length) % 8)
dialectData.increaseLengthBy(pad)
header.contextOffset = UInt32(sizeof(header.dynamicType.self)) + UInt32(dialectData.length)
header.contextCount = UInt16(contexts.count)
let contextData = NSMutableData()
for context in contexts {
var contextType = context.type.rawValue
contextData.appendBytes(&contextType, length: 2)
var dataLen = UInt16(context.data.length)
contextData.increaseLengthBy(4)
contextData.appendBytes(&dataLen, length: 2)
}
let result = NSMutableData(data: encode(&header))
result.appendData(dialectData)
result.appendData(contextData)
return result
}
struct Header {
var size: UInt16
var dialectCount: UInt16
let signing: NegotiateSinging
private let reserved: UInt16
let capabilities: GlobalCapabilities
let guid: uuid_t
var contextOffset: UInt32
var contextCount: UInt16
private let reserved2: UInt16
var clientStartTime: SMBTime {
let time = Int64(contextOffset) + (Int64(contextCount) << 32) + (Int64(contextCount) << 48)
return SMBTime(time: time)
}
init(capabilities: GlobalCapabilities, clientStartTime: SMBTime? = nil, guid: uuid_t? = nil, signing: NegotiateSinging = [.ENABLED]) {
self.size = 36
self.dialectCount = 0
self.signing = signing
self.reserved = 0
self.capabilities = capabilities
self.guid = guid ?? (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
if let clientStartTime = clientStartTime {
let time = clientStartTime.time
self.contextOffset = UInt32(time & 0xffffffff)
self.contextCount = UInt16(time & 0x0000ffff00000000 >> 32)
self.reserved2 = UInt16(time >> 48)
} else {
self.contextOffset = 0
self.contextCount = 0
self.reserved2 = 0
}
}
}
}
struct NegotiateResponse: SMBResponse {
let header: NegotiateResponse.Header
let buffer: NSData?
let contexts: [(type: NegotiateContextType, data: NSData)]
init? (data: NSData) {
if data.length < 64 {
return nil
}
self.header = decode(data)
if Int(header.size) != 65 {
return nil
}
let bufOffset = Int(self.header.bufferOffset) - sizeof(SMB2.Header.self)
let bufLen = Int(self.header.bufferLength)
if bufOffset > 0 && bufLen > 0 && data.length >= bufOffset + bufLen {
self.buffer = data.subdataWithRange(NSRange(location: bufOffset, length: bufLen))
} else {
self.buffer = nil
}
let contextCount = Int(self.header.contextCount)
let contextOffset = Int(self.header.contextOffset) - sizeof(SMB2.Header.self)
if contextCount > 0 && contextOffset > 0 {
// TODO: NegotiateResponse context support for SMB3
self.contexts = []
} else {
self.contexts = []
}
}
struct Header {
let size: UInt16
let singing: NegotiateSinging
let dialect: UInt16
let contextCount: UInt16
let serverGuid: uuid_t
let capabilities: GlobalCapabilities
let maxTransactSize: UInt32
let maxReadSize: UInt32
let maxWriteSize: UInt32
let systemTime: SMBTime
let serverStartTime: SMBTime
let bufferOffset: UInt16
let bufferLength: UInt16
let contextOffset: UInt32
}
}
struct NegotiateSinging: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let ENABLED = NegotiateSinging(rawValue: 0x0001)
static let REQUIRED = NegotiateSinging(rawValue: 0x0002)
}
struct NegotiateContextType: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let PREAUTH_INTEGRITY_CAPABILITIES = NegotiateContextType(rawValue: 0x0001)
static let ENCRYPTION_CAPABILITIES = NegotiateContextType(rawValue: 0x0002)
}
struct GlobalCapabilities: OptionSetType {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
static let DFS = GlobalCapabilities(rawValue: 0x00000001)
static let LEASING = GlobalCapabilities(rawValue: 0x00000002)
static let LARGE_MTU = GlobalCapabilities(rawValue: 0x00000004)
static let MULTI_CHANNEL = GlobalCapabilities(rawValue: 0x00000008)
static let PERSISTENT_HANDLES = GlobalCapabilities(rawValue: 0x00000010)
static let DIRECTORY_LEASING = GlobalCapabilities(rawValue: 0x00000020)
static let ENCRYPTION = GlobalCapabilities(rawValue: 0x00000040)
}
// MARK: SMB2 Session Setup
struct SessionSetupRequest: SMBRequest {
let header: SessionSetupRequest.Header
let buffer: NSData?
init(header: SessionSetupRequest.Header, buffer: NSData) {
self.header = header
self.buffer = buffer
}
init(sessionId: UInt64 = 0, flags: SessionSetupRequest.Flags = [], singing: SessionSetupSinging = [.ENABLED], capabilities: GlobalCapabilities = [], securityData: NSData? = nil) {
self.header = Header(sessionId: sessionId, flags: flags, singing: singing, capabilities: capabilities)
self.buffer = securityData
}
func data() -> NSData {
var header = self.header
header.bufferOffset = UInt16(sizeof(SMB2.Header.self) + sizeof(SessionSetupRequest.Header.self))
header.bufferLength = UInt16(buffer?.length ?? 0)
let result = NSMutableData(data: encode(&header))
if let buffer = self.buffer {
result.appendData(buffer)
}
return result
}
struct Header {
let size: UInt16
let flags: SessionSetupRequest.Flags
let signing: SessionSetupSinging
let capabilities: GlobalCapabilities
private let channel: UInt32
var bufferOffset: UInt16
var bufferLength: UInt16
let sessionId: UInt64
init(sessionId: UInt64, flags: SessionSetupRequest.Flags = [], singing: SessionSetupSinging, capabilities: GlobalCapabilities) {
self.size = 25
self.flags = flags
self.signing = singing
self.capabilities = capabilities
self.channel = 0
self.bufferOffset = 0
self.bufferLength = 0
self.sessionId = sessionId
}
}
/// Works the client implements the SMB 3.x dialect family
struct Flags: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
static let BINDING = NegotiateSinging(rawValue: 0x01)
}
}
struct SessionSetupResponse: SMBResponse {
let header: SessionSetupResponse.Header
let buffer: NSData?
init? (data: NSData) {
if data.length < 64 {
return nil
}
self.header = decode(data)
if Int(header.size) != 9 {
return nil
}
let bufOffset = Int(self.header.bufferOffset) - sizeof(SMB2.Header.self)
let bufLen = Int(self.header.bufferLength)
if bufOffset > 0 && bufLen > 0 && data.length >= bufOffset + bufLen {
self.buffer = data.subdataWithRange(NSRange(location: bufOffset, length: bufLen))
} else {
self.buffer = nil
}
}
struct Header {
let size: UInt16
let flags: SessionSetupResponse.Flags
let bufferOffset: UInt16
let bufferLength: UInt16
}
struct Flags: OptionSetType {
let rawValue: UInt16
init(rawValue: UInt16) {
self.rawValue = rawValue
}
static let IS_GUEST = Flags(rawValue: 0x0001)
static let IS_NULL = Flags(rawValue: 0x0002)
static let ENCRYPT_DATA = Flags(rawValue: 0x0004)
}
}
struct SessionSetupSinging: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
static let ENABLED = SessionSetupSinging(rawValue: 0x01)
static let REQUIRED = SessionSetupSinging(rawValue: 0x02)
}
// MARK: SMB2 Log off
struct LogOff: SMBRequest, SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
func data() -> NSData {
return encode(self)
}
}
// MARK: SMB2 Echo
struct Echo: SMBRequest, SMBResponse {
let size: UInt16
let reserved: UInt16
init() {
self.size = 4
self.reserved = 0
}
init? (data: NSData) {
self = decode(data)
}
func data() -> NSData {
return encode(self)
}
}
}