UNPKG

@sharelist/node-smb-server

Version:

Sharelist SMB Server Implementation Base On node-smb-server

222 lines (196 loc) 6.38 kB
/* * Copyright 2015 Adobe Systems Incorporated. All rights reserved. * This file is licensed to you 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 REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ 'use strict'; var put = require('put'); var binary = require('binary'); var ntstatus = require('../ntstatus'); var consts = require('./constants'); var flags = require('./flags'); function decode(buf) { // SMB uses little endian byte order! var parser = binary.parse(buf); var raw = parser.buffer('protocolId', 4)// 0xff, 'S', 'M', 'B' .word8('command') .word32le('status') .word8('flags') .word16le('flags2') .word16le('extra.pidHigh') .buffer('extra.signature', 8) .skip(2) .word16le('tid') .word16le('pidLow') .word16le('uid') .word16le('mid') .word8('params.wordCount') .buffer('params.words', 2 * parser.vars['params']['wordCount']) .word16le('data.byteCount') .buffer('data.bytes', 'data.byteCount') .vars; var cmdId = raw.command; var header = { commandId: cmdId, command: consts.COMMAND_TO_STRING[cmdId], status: raw.status, flags: flags.decode(raw.flags, raw.flags2), extra: { pidHigh: raw.extra.pidHigh, signature: raw.extra.signature }, tid: raw.tid, pidLow: raw.pidLow, pid: (raw.extra.pidHigh << 16) + (raw.pidLow), uid: raw.uid, mid: raw.mid }; var params = raw.params.words; var paramsOffset = consts.SMB_MIN_LENGTH; var data = raw.data.bytes; var dataOffset = paramsOffset + params.length; var msg = { protocolId: raw.protocolId, header: header, params: params, data: data, buf: buf // raw message buffer }; // unify andX and non-andX style message format: commands will be represented as array, even for andX-style messages msg.commands = []; decodeCommands(buf, header.commandId, params, data, paramsOffset, dataOffset, msg.commands); return msg; } function decodeCommands(buf, commandId, params, data, paramsOffset, dataOffset, commands) { commands.push({ commandId: commandId, params: params, data: data, paramsOffset: paramsOffset, dataOffset: dataOffset }); if (!consts.IS_ANDX_COMMAND(commandId)) { return; } // parse andX prefix var nextCmdId = params.readUInt8(0); var offset = params.readUInt16LE(2); var nextParamsOffset, nextDataOffset; if (nextCmdId !== 0xff && offset) { // extract params & data var nextBody = buf.slice(offset); var off = 0; var wordCount = nextBody.readUInt8(off); nextParamsOffset = off += 1; var nextParams = nextBody.slice(off, off + (2 * wordCount)); off += (2 * wordCount); var byteCount = nextBody.readUInt16LE(off); nextDataOffset = off += 2; var nextData = nextBody.slice(off, off + byteCount); // recurse decodeCommands(buf, nextCmdId, nextParams, nextData, nextParamsOffset, nextDataOffset, commands); } } function encode(msg) { var out = put(); var flgs = flags.encode(msg.header.flags); // header out.put(msg.protocolId) .word8(msg.header.commandId) .word32le(msg.header.status) .word8(flgs.flags) .word16le(flgs.flags2) .word16le(msg.header.extra.pidHigh) .put(msg.header.extra.signature) .pad(2) .word16le(msg.header.tid) .word16le(msg.header.pid) .word16le(msg.header.uid) .word16le(msg.header.mid); var offset = consts.SMB_HEADER_LENGTH; var wordCount, byteCount; // body (params, data) if (msg.header.status !== ntstatus.STATUS_SUCCESS && msg.header.status !== ntstatus.STATUS_MORE_PROCESSING_REQUIRED) { // error message // according to the CIFS spec: // "Error responses SHOULD be sent with empty SMB Parameters and SMB Data blocks" out.word8(0) // wordCount .word16le(0); // byteCount } else if (!consts.IS_ANDX_COMMAND(msg.header.commandId)) { // regular message body with single params/data pair msg.params = msg.commands[0].params; wordCount = msg.params.length / 2; if (msg.commands[0].wordCount) { // override wordCount wordCount = msg.commands[0].wordCount; } msg.data = msg.commands[0].data; byteCount = msg.data.length; if (msg.commands[0].byteCount) { // override byteCount byteCount = msg.commands[0].byteCount; } // wordCount out.word8(wordCount) // params .put(msg.params) // byteCount .word16le(byteCount) // data .put(msg.data); } else { // andX-type message body with multiple params/data pairs for (var i = 0; i < msg.commands.length; i++) { var cmd = msg.commands[i]; // next params/data block offset offset += (1 + cmd.params.length + 2 + cmd.data.length); wordCount = cmd.params.length / 2; if (cmd.wordCount) { // override wordCount wordCount = cmd.wordCount; } byteCount = cmd.data.length; if (cmd.byteCount) { // override byteCount byteCount = cmd.byteCount; } // wordCount out.word8(wordCount); // andX header if (i === msg.commands.length - 1) { // last command in chain if (consts.IS_ANDX_COMMAND(cmd.commandId)) { // next andX command cmd.params.writeUInt8(0xff, 0); // andX reserved cmd.params.writeUInt8(0x0, 1); // andX offset cmd.params.writeUInt16LE(0x0, 2); } } else { // next andX command cmd.params.writeUInt8(msg.commands[i + 1].commandId, 0); // andX reserved cmd.params.writeUInt8(0x0, 1); // andX offset cmd.params.writeUInt16LE(offset, 2); } // params out.put(cmd.params) // byteCount .word16le(byteCount) // data .put(cmd.data); } } return out.buffer(); } module.exports.decode = decode; module.exports.encode = encode;