login7-payload.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _sprintfJs = require("sprintf-js");
  7. const FLAGS_1 = {
  8. ENDIAN_LITTLE: 0x00,
  9. ENDIAN_BIG: 0x01,
  10. CHARSET_ASCII: 0x00,
  11. CHARSET_EBCDIC: 0x02,
  12. FLOAT_IEEE_754: 0x00,
  13. FLOAT_VAX: 0x04,
  14. FLOAT_ND5000: 0x08,
  15. BCP_DUMPLOAD_ON: 0x00,
  16. BCP_DUMPLOAD_OFF: 0x10,
  17. USE_DB_ON: 0x00,
  18. USE_DB_OFF: 0x20,
  19. INIT_DB_WARN: 0x00,
  20. INIT_DB_FATAL: 0x40,
  21. SET_LANG_WARN_OFF: 0x00,
  22. SET_LANG_WARN_ON: 0x80
  23. };
  24. const FLAGS_2 = {
  25. INIT_LANG_WARN: 0x00,
  26. INIT_LANG_FATAL: 0x01,
  27. ODBC_OFF: 0x00,
  28. ODBC_ON: 0x02,
  29. F_TRAN_BOUNDARY: 0x04,
  30. F_CACHE_CONNECT: 0x08,
  31. USER_NORMAL: 0x00,
  32. USER_SERVER: 0x10,
  33. USER_REMUSER: 0x20,
  34. USER_SQLREPL: 0x40,
  35. INTEGRATED_SECURITY_OFF: 0x00,
  36. INTEGRATED_SECURITY_ON: 0x80
  37. };
  38. const TYPE_FLAGS = {
  39. SQL_DFLT: 0x00,
  40. SQL_TSQL: 0x08,
  41. OLEDB_OFF: 0x00,
  42. OLEDB_ON: 0x10,
  43. READ_WRITE_INTENT: 0x00,
  44. READ_ONLY_INTENT: 0x20
  45. };
  46. const FLAGS_3 = {
  47. CHANGE_PASSWORD_NO: 0x00,
  48. CHANGE_PASSWORD_YES: 0x01,
  49. BINARY_XML: 0x02,
  50. SPAWN_USER_INSTANCE: 0x04,
  51. UNKNOWN_COLLATION_HANDLING: 0x08,
  52. EXTENSION_USED: 0x10
  53. };
  54. const FEDAUTH_OPTIONS = {
  55. FEATURE_ID: 0x02,
  56. LIBRARY_SECURITYTOKEN: 0x01,
  57. LIBRARY_ADAL: 0x02,
  58. FEDAUTH_YES_ECHO: 0x01,
  59. FEDAUTH_NO_ECHO: 0x00,
  60. ADAL_WORKFLOW_USER_PASS: 0x01,
  61. ADAL_WORKFLOW_INTEGRATED: 0x02
  62. };
  63. const FEATURE_EXT_TERMINATOR = 0xFF;
  64. /*
  65. s2.2.6.3
  66. */
  67. class Login7Payload {
  68. constructor({
  69. tdsVersion,
  70. packetSize,
  71. clientProgVer,
  72. clientPid,
  73. connectionId,
  74. clientTimeZone,
  75. clientLcid
  76. }) {
  77. this.tdsVersion = tdsVersion;
  78. this.packetSize = packetSize;
  79. this.clientProgVer = clientProgVer;
  80. this.clientPid = clientPid;
  81. this.connectionId = connectionId;
  82. this.clientTimeZone = clientTimeZone;
  83. this.clientLcid = clientLcid;
  84. this.readOnlyIntent = false;
  85. this.initDbFatal = false;
  86. this.fedAuth = undefined;
  87. this.userName = undefined;
  88. this.password = undefined;
  89. this.serverName = undefined;
  90. this.appName = undefined;
  91. this.hostname = undefined;
  92. this.libraryName = undefined;
  93. this.language = undefined;
  94. this.database = undefined;
  95. this.clientId = undefined;
  96. this.sspi = undefined;
  97. this.attachDbFile = undefined;
  98. this.changePassword = undefined;
  99. }
  100. toBuffer() {
  101. const fixedData = Buffer.alloc(94);
  102. const buffers = [fixedData];
  103. let offset = 0;
  104. let dataOffset = fixedData.length; // Length: 4-byte
  105. offset = fixedData.writeUInt32LE(0, offset); // TDSVersion: 4-byte
  106. offset = fixedData.writeUInt32LE(this.tdsVersion, offset); // PacketSize: 4-byte
  107. offset = fixedData.writeUInt32LE(this.packetSize, offset); // ClientProgVer: 4-byte
  108. offset = fixedData.writeUInt32LE(this.clientProgVer, offset); // ClientPID: 4-byte
  109. offset = fixedData.writeUInt32LE(this.clientPid, offset); // ConnectionID: 4-byte
  110. offset = fixedData.writeUInt32LE(this.connectionId, offset); // OptionFlags1: 1-byte
  111. offset = fixedData.writeUInt8(this.buildOptionFlags1(), offset); // OptionFlags2: 1-byte
  112. offset = fixedData.writeUInt8(this.buildOptionFlags2(), offset); // TypeFlags: 1-byte
  113. offset = fixedData.writeUInt8(this.buildTypeFlags(), offset); // OptionFlags3: 1-byte
  114. offset = fixedData.writeUInt8(this.buildOptionFlags3(), offset); // ClientTimZone: 4-byte
  115. offset = fixedData.writeInt32LE(this.clientTimeZone, offset); // ClientLCID: 4-byte
  116. offset = fixedData.writeUInt32LE(this.clientLcid, offset); // ibHostName: 2-byte
  117. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchHostName: 2-byte
  118. if (this.hostname) {
  119. const buffer = Buffer.from(this.hostname, 'ucs2');
  120. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  121. dataOffset += buffer.length;
  122. buffers.push(buffer);
  123. } else {
  124. offset = fixedData.writeUInt16LE(dataOffset, offset);
  125. } // ibUserName: 2-byte
  126. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchUserName: 2-byte
  127. if (this.userName) {
  128. const buffer = Buffer.from(this.userName, 'ucs2');
  129. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  130. dataOffset += buffer.length;
  131. buffers.push(buffer);
  132. } else {
  133. offset = fixedData.writeUInt16LE(0, offset);
  134. } // ibPassword: 2-byte
  135. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchPassword: 2-byte
  136. if (this.password) {
  137. const buffer = Buffer.from(this.password, 'ucs2');
  138. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  139. dataOffset += buffer.length;
  140. buffers.push(this.scramblePassword(buffer));
  141. } else {
  142. offset = fixedData.writeUInt16LE(0, offset);
  143. } // ibAppName: 2-byte
  144. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchAppName: 2-byte
  145. if (this.appName) {
  146. const buffer = Buffer.from(this.appName, 'ucs2');
  147. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  148. dataOffset += buffer.length;
  149. buffers.push(buffer);
  150. } else {
  151. offset = fixedData.writeUInt16LE(0, offset);
  152. } // ibServerName: 2-byte
  153. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchServerName: 2-byte
  154. if (this.serverName) {
  155. const buffer = Buffer.from(this.serverName, 'ucs2');
  156. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  157. dataOffset += buffer.length;
  158. buffers.push(buffer);
  159. } else {
  160. offset = fixedData.writeUInt16LE(0, offset);
  161. } // (ibUnused / ibExtension): 2-byte
  162. offset = fixedData.writeUInt16LE(dataOffset, offset); // (cchUnused / cbExtension): 2-byte
  163. const extensions = this.buildFeatureExt();
  164. offset = fixedData.writeUInt16LE(4, offset);
  165. const extensionOffset = Buffer.alloc(4);
  166. extensionOffset.writeUInt32LE(dataOffset += 4, 0);
  167. dataOffset += extensions.length;
  168. buffers.push(extensionOffset, extensions); // ibCltIntName: 2-byte
  169. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchCltIntName: 2-byte
  170. if (this.libraryName) {
  171. const buffer = Buffer.from(this.libraryName, 'ucs2');
  172. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  173. dataOffset += buffer.length;
  174. buffers.push(buffer);
  175. } else {
  176. offset = fixedData.writeUInt16LE(0, offset);
  177. } // ibLanguage: 2-byte
  178. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchLanguage: 2-byte
  179. if (this.language) {
  180. const buffer = Buffer.from(this.language, 'ucs2');
  181. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  182. dataOffset += buffer.length;
  183. buffers.push(buffer);
  184. } else {
  185. offset = fixedData.writeUInt16LE(0, offset);
  186. } // ibDatabase: 2-byte
  187. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchDatabase: 2-byte
  188. if (this.database) {
  189. const buffer = Buffer.from(this.database, 'ucs2');
  190. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  191. dataOffset += buffer.length;
  192. buffers.push(buffer);
  193. } else {
  194. offset = fixedData.writeUInt16LE(0, offset);
  195. } // ClientID: 6-byte
  196. if (this.clientId) {
  197. this.clientId.copy(fixedData, offset, 0, 6);
  198. }
  199. offset += 6; // ibSSPI: 2-byte
  200. offset = fixedData.writeUInt16LE(dataOffset, offset); // cbSSPI: 2-byte
  201. if (this.sspi) {
  202. if (this.sspi.length > 65535) {
  203. offset = fixedData.writeUInt16LE(65535, offset);
  204. } else {
  205. offset = fixedData.writeUInt16LE(this.sspi.length, offset);
  206. }
  207. buffers.push(this.sspi);
  208. } else {
  209. offset = fixedData.writeUInt16LE(0, offset);
  210. } // ibAtchDBFile: 2-byte
  211. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchAtchDBFile: 2-byte
  212. if (this.attachDbFile) {
  213. const buffer = Buffer.from(this.attachDbFile, 'ucs2');
  214. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  215. dataOffset += buffer.length;
  216. buffers.push(buffer);
  217. } else {
  218. offset = fixedData.writeUInt16LE(0, offset);
  219. } // ibChangePassword: 2-byte
  220. offset = fixedData.writeUInt16LE(dataOffset, offset); // cchChangePassword: 2-byte
  221. if (this.changePassword) {
  222. const buffer = Buffer.from(this.changePassword, 'ucs2');
  223. offset = fixedData.writeUInt16LE(buffer.length / 2, offset);
  224. dataOffset += buffer.length;
  225. buffers.push(buffer);
  226. } else {
  227. offset = fixedData.writeUInt16LE(0, offset);
  228. } // cbSSPILong: 4-byte
  229. if (this.sspi && this.sspi.length > 65535) {
  230. fixedData.writeUInt32LE(this.sspi.length, offset);
  231. } else {
  232. fixedData.writeUInt32LE(0, offset);
  233. }
  234. const data = Buffer.concat(buffers);
  235. data.writeUInt32LE(data.length, 0);
  236. return data;
  237. }
  238. buildOptionFlags1() {
  239. let flags1 = FLAGS_1.ENDIAN_LITTLE | FLAGS_1.CHARSET_ASCII | FLAGS_1.FLOAT_IEEE_754 | FLAGS_1.BCP_DUMPLOAD_OFF | FLAGS_1.USE_DB_OFF | FLAGS_1.SET_LANG_WARN_ON;
  240. if (this.initDbFatal) {
  241. flags1 |= FLAGS_1.INIT_DB_FATAL;
  242. } else {
  243. flags1 |= FLAGS_1.INIT_DB_WARN;
  244. }
  245. return flags1;
  246. }
  247. buildFeatureExt() {
  248. const buffers = [];
  249. const fedAuth = this.fedAuth;
  250. if (fedAuth) {
  251. switch (fedAuth.type) {
  252. case 'ADAL':
  253. const buffer = Buffer.alloc(7);
  254. buffer.writeUInt8(FEDAUTH_OPTIONS.FEATURE_ID, 0);
  255. buffer.writeUInt32LE(2, 1);
  256. buffer.writeUInt8(FEDAUTH_OPTIONS.LIBRARY_ADAL << 1 | (fedAuth.echo ? FEDAUTH_OPTIONS.FEDAUTH_YES_ECHO : FEDAUTH_OPTIONS.FEDAUTH_NO_ECHO), 5);
  257. buffer.writeUInt8(fedAuth.workflow === 'integrated' ? 0x02 : FEDAUTH_OPTIONS.ADAL_WORKFLOW_USER_PASS, 6);
  258. buffers.push(buffer);
  259. break;
  260. case 'SECURITYTOKEN':
  261. const token = Buffer.from(fedAuth.fedAuthToken, 'ucs2');
  262. const buf = Buffer.alloc(10);
  263. let offset = 0;
  264. offset = buf.writeUInt8(FEDAUTH_OPTIONS.FEATURE_ID, offset);
  265. offset = buf.writeUInt32LE(token.length + 4 + 1, offset);
  266. offset = buf.writeUInt8(FEDAUTH_OPTIONS.LIBRARY_SECURITYTOKEN << 1 | (fedAuth.echo ? FEDAUTH_OPTIONS.FEDAUTH_YES_ECHO : FEDAUTH_OPTIONS.FEDAUTH_NO_ECHO), offset);
  267. buf.writeInt32LE(token.length, offset);
  268. buffers.push(buf);
  269. buffers.push(token);
  270. break;
  271. }
  272. }
  273. buffers.push(Buffer.from([FEATURE_EXT_TERMINATOR]));
  274. return Buffer.concat(buffers);
  275. }
  276. buildOptionFlags2() {
  277. let flags2 = FLAGS_2.INIT_LANG_WARN | FLAGS_2.ODBC_OFF | FLAGS_2.USER_NORMAL;
  278. if (this.sspi) {
  279. flags2 |= FLAGS_2.INTEGRATED_SECURITY_ON;
  280. } else {
  281. flags2 |= FLAGS_2.INTEGRATED_SECURITY_OFF;
  282. }
  283. return flags2;
  284. }
  285. buildTypeFlags() {
  286. let typeFlags = TYPE_FLAGS.SQL_DFLT | TYPE_FLAGS.OLEDB_OFF;
  287. if (this.readOnlyIntent) {
  288. typeFlags |= TYPE_FLAGS.READ_ONLY_INTENT;
  289. } else {
  290. typeFlags |= TYPE_FLAGS.READ_WRITE_INTENT;
  291. }
  292. return typeFlags;
  293. }
  294. buildOptionFlags3() {
  295. return FLAGS_3.CHANGE_PASSWORD_NO | FLAGS_3.UNKNOWN_COLLATION_HANDLING | FLAGS_3.EXTENSION_USED;
  296. }
  297. scramblePassword(password) {
  298. for (let b = 0, len = password.length; b < len; b++) {
  299. let byte = password[b];
  300. const lowNibble = byte & 0x0f;
  301. const highNibble = byte >> 4;
  302. byte = lowNibble << 4 | highNibble;
  303. byte = byte ^ 0xa5;
  304. password[b] = byte;
  305. }
  306. return password;
  307. }
  308. toString(indent = '') {
  309. return indent + 'Login7 - ' + (0, _sprintfJs.sprintf)('TDS:0x%08X, PacketSize:0x%08X, ClientProgVer:0x%08X, ClientPID:0x%08X, ConnectionID:0x%08X', this.tdsVersion, this.packetSize, this.clientProgVer, this.clientPid, this.connectionId) + '\n' + indent + ' ' + (0, _sprintfJs.sprintf)('Flags1:0x%02X, Flags2:0x%02X, TypeFlags:0x%02X, Flags3:0x%02X, ClientTimezone:%d, ClientLCID:0x%08X', this.buildOptionFlags1(), this.buildOptionFlags2(), this.buildTypeFlags(), this.buildOptionFlags3(), this.clientTimeZone, this.clientLcid) + '\n' + indent + ' ' + (0, _sprintfJs.sprintf)("Hostname:'%s', Username:'%s', Password:'%s', AppName:'%s', ServerName:'%s', LibraryName:'%s'", this.hostname, this.userName, this.password, this.appName, this.serverName, this.libraryName) + '\n' + indent + ' ' + (0, _sprintfJs.sprintf)("Language:'%s', Database:'%s', SSPI:'%s', AttachDbFile:'%s', ChangePassword:'%s'", this.language, this.database, this.sspi, this.attachDbFile, this.changePassword);
  310. }
  311. }
  312. var _default = Login7Payload;
  313. exports.default = _default;
  314. module.exports = Login7Payload;