UNPKG

@vinothnb/smb2

Version:
301 lines (272 loc) 7.21 kB
/* * CONSTANTS */ var protocolId = Buffer.from([ 0xfe, 'S'.charCodeAt(0), 'M'.charCodeAt(0), 'B'.charCodeAt(0), ]); var headerTranslates = { Command: { NEGOTIATE: 0x0000, SESSION_SETUP: 0x0001, LOGOFF: 0x0002, TREE_CONNECT: 0x0003, TREE_DISCONNECT: 0x0004, CREATE: 0x0005, CLOSE: 0x0006, FLUSH: 0x0007, READ: 0x0008, WRITE: 0x0009, LOCK: 0x000a, IOCTL: 0x000b, CANCEL: 0x000c, ECHO: 0x000d, QUERY_DIRECTORY: 0x000e, CHANGE_NOTIFY: 0x000f, QUERY_INFO: 0x0010, SET_INFO: 0x0011, OPLOCK_BREAK: 0x0012, }, }; // eslint-disable-next-line no-unused-vars var flags = { SERVER_TO_REDIR: 0x00000001, ASYNC_COMMAND: 0x00000002, RELATED_OPERATIONS: 0x00000004, SIGNED: 0x00000008, DFS_OPERATIONS: 0x10000000, REPLAY_OPERATION: 0x20000000, }; var headerLength = 64; var headerSync = function(processId, sessionId) { return [ ['ProtocolId', 4, protocolId], ['StructureSize', 2, headerLength], ['CreditCharge', 2, 0], ['Status', 4, 0], ['Command', 2], ['Credit', 2, 126], ['Flags', 4, 0], ['NextCommand', 4, 0], ['MessageId', 4], ['MessageIdHigh', 4, 0], ['ProcessId', 4, processId], ['TreeId', 4, 0], ['SessionId', 8, sessionId], ['Signature', 16, 0], ]; }; var headerASync = function(processId, sessionId) { return [ ['ProtocolId', 4, protocolId], ['StructureSize', 2, headerLength], ['CreditCharge', 2, 0], ['Status', 4, 0], ['Command', 2], ['Credit', 2, 126], ['Flags', 4, 0], ['NextCommand', 4, 0], ['MessageId', 4], ['MessageIdHigh', 4, 0], ['AsyncId', 8], ['SessionId', 8, sessionId], ['Signature', 16, 0], ]; }; /* * CONSTRUCTOR */ var SMB2Message = (module.exports = function(options) { // INIT HEADERS this.headers = {}; if (options && options.headers) { this.setHeaders(options.headers); } // INIT REQUEST this.request = {}; if (options && options.request) { this.setRequest(options.request); } // INIT RESPONSE this.response = {}; }); var proto = (SMB2Message.prototype = {}); proto.setHeaders = function(obj) { for (var key in obj) { this.headers[key] = obj[key]; } this.structure = require('../structures/' + this.headers['Command'].toLowerCase()); }; proto.getHeaders = function() { return this.headers; }; proto.setRequest = function(request) { this.request = request; }; proto.getResponse = function() { return this.response; }; proto.getBuffer = function(connection) { var buffer = Buffer.allocUnsafe(0xffff); var length = 0; // SET MESSAGE ID if (!this.isMessageIdSetted) { this.isMessageIdSetted = true; this.headers['MessageId'] = connection.messageId++; } // HEADERS length += writeHeaders(this, buffer); // REQUEST length += writeRequest(this, buffer, headerLength); // extract the data var output = Buffer.allocUnsafe(length); buffer.copy(output, 0, 0, length); return output; }; proto.parseBuffer = function(buffer) { // HEADERS readHeaders(this, buffer); // RESPONSE readResponse(this, buffer, headerLength); }; /* * HELPERS */ function dataToBuffer(data, length) { // buffers will be buffers if (Buffer.isBuffer(data)) { return data; } // string to buffer if (typeof data === 'string') { return Buffer.from(data); } // raw data to buffer var result = Buffer.allocUnsafe(length); for (var i = 0; i < length; i++) { result.writeUInt8(0xff & (data >> (i * 8)), i); } return result; } function bufferToData(buffer) { // not a buffer go away if (!Buffer.isBuffer(buffer)) { return buffer; } // raw data to buffer var result = 0; for (var i = 0; i < buffer.length; i++) { result += buffer.readUInt8(i) << (i * 8); } return result; } function writeData(buffer, data, offset, length) { dataToBuffer(data, length).copy(buffer, offset, 0); } function readData(buffer, offset, length) { return buffer.slice(offset, offset + length); } function translate(key, value) { if ( headerTranslates[key] && typeof headerTranslates[key][value] !== 'undefined' ) { return headerTranslates[key][value]; } return value; } function unTranslate(key, value) { if (headerTranslates[key]) { for (var t in headerTranslates[key]) { if (headerTranslates[key][t] === value) { return t; } } } return null; } /* * PRIVATE FUNCTIONS */ function readHeaders(message, buffer) { var header = (message.isAsync ? headerASync : headerSync)( message.ProcessId, message.SessionId ); var offset = 0; for (var i in header) { var key = header[i][0]; var length = header[i][1]; message.headers[key] = readData(buffer, offset, length); if (length <= 8) { message.headers[key] = unTranslate(key, bufferToData(message.headers[key])) || message.headers[key]; } offset += length; } message.structure = require('../structures/' + message.headers['Command'].toLowerCase()); } function writeHeaders(message, buffer) { var header = (message.isAsync ? headerASync : headerSync)( message.ProcessId, message.SessionId ); var offset = 0; for (var i in header) { var key = header[i][0]; var length = header[i][1]; var defaultValue = header[i][2] || 0; writeData( buffer, translate(key, message.headers[key] || defaultValue), offset, length ); offset += length; } return offset; } function readResponse(message, buffer, offset) { for (var i in message.structure.response) { var key = message.structure.response[i][0]; var length = message.structure.response[i][1] || 1; if (typeof length === 'string') { length = bufferToData(message.response[length]); } message.response[key] = readData(buffer, offset, length); offset += length; } } function writeRequest(message, buffer, offset) { var initOffset = offset; var needsRewrite = false; var tmpBuffer = Buffer.allocUnsafe(buffer.length); offset = 0; for (var i in message.structure.request) { var key = message.structure.request[i][0]; var length = message.structure.request[i][1] || 1; var defaultValue = message.structure.request[i][2] || 0; if (typeof length === 'string') { message.request[key] = message.request[key] || ''; if (message.request[length] !== message.request[key].length) { message.request[length] = message.request[key].length; needsRewrite = true; } length = message.request[key].length; } else { message.request[key] = message.request[key] || defaultValue; } writeData(tmpBuffer, message.request[key], offset, length); offset += length; } if (needsRewrite) { writeRequest(message, tmpBuffer, 0); } tmpBuffer.copy(buffer, initOffset, 0, offset); return offset; }