1--- 2-- TN3270 Emulator Library 3-- 4-- Summary 5-- * This library implements an RFC 1576 and 2355 (somewhat) compliant TN3270 emulator. 6-- 7-- The library consists of one class <code>Telnet</code> consisting of multiple 8-- functions required for initiating a TN3270 connection. 9-- 10-- The following sample code illustrates how scripts can use this class 11-- to interface with a mainframe: 12-- 13-- <code> 14-- mainframe = Telnet:new() 15-- status, err = mainframe:initiate(host, port) 16-- status, err = mainframe:send_cursor("LOGON APPLID(TSO)") 17-- mainframe:get_data() 18-- curr_screen = mainframe:get_screen() 19-- status, err = mainframe:disconnect() 20-- </code> 21-- 22-- The implementation is based on packet dumps, x3270, the excellent decoding 23-- provided by Wireshark and the Data Stream Programmers Reference (Dec 88) 24 25local stdnse = require "stdnse" 26local drda = require "drda" -- We only need this to decode EBCDIC 27local comm = require "comm" 28local math = require "math" 29local nmap = require "nmap" 30local string = require "string" 31local table = require "table" 32 33_ENV = stdnse.module("tn3270", stdnse.seeall) 34 35Telnet = { 36 --__index = Telnet, 37 38 commands = { 39 SE = "\240", -- End of subnegotiation parameters 40 SB = "\250", -- Sub-option to follow 41 WILL = "\251", -- Will; request or confirm option begin 42 WONT = "\252", -- Wont; deny option request 43 DO = "\253", -- Do = Request or confirm remote option 44 DONT = "\254", -- Don't = Demand or confirm option halt 45 IAC = "\255", -- Interpret as Command 46 SEND = "\001", -- Sub-process negotiation SEND command 47 IS = "\000", -- Sub-process negotiation IS command 48 EOR = "\239" 49 }, 50 tncommands = { 51 ASSOCIATE = "\000", 52 CONNECT = "\001", 53 DEVICETYPE = "\002", 54 FUNCTIONS = "\003", 55 IS = "\004", 56 REASON = "\005", 57 REJECT = "\006", 58 REQUEST = "\007", 59 RESPONSES = "\002", 60 SEND = "\008", 61 EOR = "\239" 62 }, 63 64 -- Thesse are the options we accept for telnet 65 options = { 66 BINARY = "\000", 67 EOR = "\025", 68 TTYPE = "\024", 69 TN3270 = "\028", 70 TN3270E = "\040" 71 }, 72 73 command = { 74 EAU = "\015", 75 EW = "\005", 76 EWA = "\013", 77 RB = "\002", 78 RM = "\006", 79 RMA = "", 80 W = "\001", 81 WSF = "\017", 82 NOP = "\003", 83 SNS = "\004", 84 SNSID = "\228" 85 }, 86 sna_command ={ 87 RMA = "\110", 88 EAU = "\111", 89 EWA = "\126", 90 W = "\241", 91 RB = "\242", 92 WSF = "\243", 93 EW = "\245", 94 NOP = "\003", 95 RM = "\246" 96 }, 97 98 orders = { 99 SF = "\029", 100 SFE = "\041", 101 SBA = "\017", 102 SA = "\040", 103 MF = "\044", 104 IC = "\019", 105 PT = "\005", 106 RA = "\060", 107 EUA = "\018", 108 GE = "\008" 109 }, 110 111 fcorders = { 112 NUL = "\000", 113 SUB = "\063", 114 DUP = "\028", 115 FM = "\030", 116 FF = "\012", 117 CR = "\013", 118 NL = "\021", 119 EM = "\025", 120 EO = "\255" 121 }, 122 123 aids = { 124 NO = 0x60, -- no aid 125 QREPLY = 0x61, -- reply 126 ENTER = 0x7d, -- enter 127 PF1 = 0xf1, 128 PF2 = 0xf2, 129 PF3 = 0xf3, 130 PF4 = 0xf4, 131 PF5 = 0xf5, 132 PF6 = 0xf6, 133 PF7 = 0xf7, 134 PF8 = 0xf8, 135 PF9 = 0xf9, 136 PF10 = 0x7a, 137 PF11 = 0x7b, 138 PF12 = 0x7c, 139 PF13 = 0xc1, 140 PF14 = 0xc2, 141 PF15 = 0xc3, 142 PF16 = 0xc4, 143 PF17 = 0xc5, 144 PF18 = 0xc6, 145 PF19 = 0xc7, 146 PF20 = 0xc8, 147 PF21 = 0xc9, 148 PF22 = 0x4a, 149 PF23 = 0x4b, 150 PF24 = 0x4c, 151 OICR = 0xe6, 152 MSR_MHS = 0xe7, 153 SELECT = 0x7e, 154 PA1 = 0x6c, 155 PA2 = 0x6e, 156 PA3 = 0x6b, 157 CLEAR = 0x6d, 158 SYSREQ = 0xf0 159 }, 160 161 -- used to translate buffer addresses 162 code_table = { 163 0x40, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 164 0xC8, 0xC9, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 165 0x50, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 166 0xD8, 0xD9, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 167 0x60, 0x61, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 168 0xE8, 0xE9, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 169 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 170 0xF8, 0xF9, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F 171 }, 172 173 -- Variables used for Telnet Negotiation and data buffers 174 word_state = { "Negotiating", "Connected", "TN3270 mode", "TN3270E mode"}, 175 NEGOTIATING = 1, 176 CONNECTED = 2, 177 TN3270_DATA = 3, 178 TN3270E_DATA = 4, 179 device_type = "IBM-3278-2", 180 181 -- TN3270E Header variables 182 tn3270_header = { 183 data_type = '', 184 request_flag = '', 185 response_flag = '', 186 seq_number = '' 187 }, 188 189 -- TN3270 Datatream Processing flags 190 NO_OUTPUT = 0, 191 OUTPUT = 1, 192 BAD_COMMAND = 2, 193 BAD_ADDRESS = 3, 194 NO_AID = 0x60, 195 aid = 0x60, -- initial Attention Identifier is No AID 196 197 -- Header response flags. 198 NO_RESPONSE = 0x00, 199 ERROR_RESPONSE = 0x01, 200 ALWAYS_RESPONSE = 0x02, 201 POSITIVE_RESPONSE = 0x00, 202 NEGATIVE_RESPONSE = 0x01, 203 204 -- Header data type names. 205 DT_3270_DATA = 0x00, 206 DT_SCS_DATA = 0x01, 207 DT_RESPONSE = 0x02, 208 DT_BIND_IMAGE = 0x03, 209 DT_UNBIND = 0x04, 210 DT_NVT_DATA = 0x05, 211 DT_REQUEST = 0x06, 212 DT_SSCP_LU_DATA = 0x07, 213 DT_PRINT_EOJ = 0x08, 214 215 -- Header response data. 216 POS_DEVICE_END = 0x00, 217 NEG_COMMAND_REJECT = 0x00, 218 NEG_INTERVENTION_REQUIRED = 0x01, 219 NEG_OPERATION_CHECK = 0x02, 220 NEG_COMPONENT_DISCONNECTED = 0x03, 221 222 -- TN3270E Negotiation Options 223 TN3270E_ASSOCIATE = 0x00, 224 TN3270E_CONNECT = 0x01, 225 TN3270E_DEVICE_TYPE = 0x02, 226 TN3270E_FUNCTIONS = 0x03, 227 TN3270E_IS = 0x04, 228 TN3270E_REASON = 0x05, 229 TN3270E_REJECT = 0x06, 230 TN3270E_REQUEST = 0x07, 231 TN3270E_SEND = 0x08, 232 233 -- SFE Attributes 234 SFE_3270 = "192", 235 order_max = "\063", -- tn3270 orders can't be greater than 0x3F 236 COLS = 80, -- hardcoded width. 237 ROWS = 24, -- hardcoded rows. We only support 3270 model 2 which was 24x80. 238 buffer_addr = 1, 239 cursor_addr = 1, 240 isSSL = true, 241 242 --- Creates a new TN3270 Client object 243 244 new = function(self, socket) 245 local o = { 246 socket = socket or nmap.new_socket(), 247 -- TN3270 Buffers 248 buffer = {}, 249 fa_buffer = {}, 250 output_buffer = {}, 251 overwrite_buf = {}, 252 telnet_state = 0, -- same as TNS_DATA to begin with 253 server_options = {}, 254 client_options = {}, 255 unsupported_opts = {}, 256 sb_options = '', 257 connected_lu = '', 258 connected_dtype= '', 259 telnet_data = '', 260 tn_buffer = '', 261 negotiated = false, 262 first_screen = false, 263 state = 0, 264 buffer_address = 1, 265 formatted = false, 266 } 267 setmetatable(o, self) 268 self.__index = self 269 return o 270 end, 271 272 --- Connects to a tn3270 servers 273 connect = function ( self, host, port ) 274 275 local TN_PROTOCOLS = { "ssl", "tcp" } 276 local status, err 277 if not self.isSSL then 278 status, err = self.socket:connect(host, port, 'tcp') 279 local proto = 'tcp' 280 if status then 281 TN_PROTOCOLS = {proto} 282 return true 283 end 284 else 285 286 for _, proto in pairs(TN_PROTOCOLS) do 287 status, err = self.socket:connect(host, port, proto) 288 if status then 289 TN_PROTOCOLS = {proto} 290 return true 291 end 292 stdnse.debug(3,"Can't connect using %s: %s", proto, err) 293 end 294 end 295 self.socket:close() 296 return false, err 297 end, 298 299 disconnect = function ( self ) 300 stdnse.debug(2,"Disconnecting") 301 return self.socket:close() 302 end, 303 304 recv_data = function ( self ) 305 return self.socket:receive() 306 end, 307 308 close = function ( self ) 309 return self.socket:close() 310 end, 311 312 send_data = function ( self, data ) 313 stdnse.debug(2, "Sending data: 0x%s", stdnse.tohex(data)) 314 return self.socket:send( data ) 315 end, 316 317 ------------- End networking functions 318 319 320 -- TN3270 Helper functions 321 ----------- 322 --- Decode Buffer Address 323 -- 324 -- Buffer addresses can come in 14 or 12 (this terminal doesn't support 16 bit) 325 -- this function takes two bytes (buffer addresses are two bytes long) and returns 326 -- the decoded buffer address. 327 -- @param1 unsigned char, first byte of buffer address. 328 -- @param2 unsigned char, second byte of buffer address. 329 -- @return integer of buffer address 330 DECODE_BADDR = function ( byte1, byte2 ) 331 if (byte1 & 0xC0) == 0 then 332 -- (byte1 & 0x3F) << 8 | byte2 333 return (((byte1 & 0x3F) << 8) | byte2) 334 else 335 -- (byte1 & 0x3F) << 6 | (byte2 & 0x3F) 336 return (((byte1 & 0x3F) << 6) | (byte2 & 0x3F)) 337 end 338 end, 339 340 --- Encode Buffer Address 341 -- 342 -- @param integer buffer address 343 -- @return TN3270 encoded buffer address (12 bit) as string 344 ENCODE_BADDR = function ( self, address ) 345 stdnse.debug(3, "Encoding Address: " .. address) 346 return string.pack("BB", 347 -- (address >> 8) & 0x3F 348 -- we need the +1 because LUA tables start at 1 (yay!) 349 self.code_table[((address >> 6) & 0x3F)+1], 350 -- address & 0x3F 351 self.code_table[(address & 0x3F)+1] 352 ) 353 end, 354 355 BA_TO_ROW = function ( self, addr ) 356 return math.ceil((addr / self.COLS) + 0.5) 357 end, 358 359 BA_TO_COL = function ( self, addr ) 360 return addr % self.COLS 361 end, 362 363 INC_BUF_ADDR = function ( self, addr ) 364 return ((addr + 1) % (self.COLS * self.ROWS)) 365 end, 366 367 DEC_BUF_ADDR = function ( self, addr ) 368 return ((addr + 1) % (self.COLS * self.ROWS)) 369 end, 370 371 --- Initiates tn3270 connection 372 initiate = function ( self, host, port ) 373 local status = true 374 --local status, err = self:connect(host , port) 375 local opts = {recv_before = true} 376 self.socket, self.telnet_data = comm.tryssl(host, port, '', opts) 377 378 if ( not(self.socket) ) then 379 return false, self.telnet_data 380 end 381 -- clear out options buffers 382 self.client_options = {} 383 self.server_options = {} 384 self.state = self.NEGOTIATING 385 self.first_screen = false 386 387 self:process_packets() -- process the first batch of information 388 -- then loop through until we're done negotiating telnet/tn3270 options 389 while not self.first_screen and status do 390 status, self.telnet_data = self:recv_data() 391 self:process_packets() 392 end 393 return status 394 end, 395 396 --- rebuilds tn3270 screen based on information sent 397 -- Closes the socket if the mainframe has closed the socket on us 398 -- Is done reading when it encounters EOR 399 get_data = function ( self ) 400 local status = true 401 self.first_screen = false 402 while not self.first_screen and status do 403 status, self.telnet_data = self:recv_data() 404 self:process_packets() 405 end 406 if not status then 407 self:disconnect() 408 end 409 return status 410 end, 411 412 get_all_data = function ( self, timeout ) 413 if timeout == nil then 414 timeout = 200 415 end 416 local status = true 417 self.first_screen = false 418 self.socket:set_timeout(timeout) 419 while status do 420 status, self.telnet_data = self:recv_data() 421 if self.telnet_data ~= "TIMEOUT" then 422 self:process_packets() 423 end 424 end 425 self.socket:set_timeout(3000) 426 return status 427 end, 428 429 process_packets = function ( self ) 430 for i = 1,#self.telnet_data,1 do 431 self:ts_processor(self.telnet_data:sub(i,i)) 432 end 433 -- once all the data has been processed we clear out the buffer 434 self.telnet_data = '' 435 end, 436 437 --- Disable SSL 438 -- by default the tn3270 object uses SSL first. This disables SSL 439 disableSSL = function (self) 440 stdnse.debug(2,"Disabling SSL connections") 441 self.isSSL = false 442 end, 443 444 --- Telnet State processor 445 -- 446 -- @return true if success false if encoutered any issues 447 448 ts_processor = function ( self, data ) 449 local TNS_DATA = 0 450 local TNS_IAC = 1 451 local TNS_WILL = 2 452 local TNS_WONT = 3 453 local TNS_DO = 4 454 local TNS_DONT = 5 455 local TNS_SB = 6 456 local TNS_SB_IAC = 7 457 local supported = false 458 local DO_reply = self.commands.IAC .. self.commands.DO 459 local DONT_reply = self.commands.IAC .. self.commands.DONT 460 local WILL_reply = self.commands.IAC .. self.commands.WILL 461 local WONT_reply = self.commands.IAC .. self.commands.WONT 462 463 --nsedebug.print_hex(data) 464 --stdnse.debug(3,"current state:" .. self.telnet_state) 465 466 if self.telnet_state == TNS_DATA then 467 if data == self.commands.IAC then 468 -- got an IAC 469 self.telnet_state = TNS_IAC 470 return true 471 end 472 -- stdnse.debug("Adding 0x%s to Data Buffer", stdnse.tohex(data)) 473 self:store3270(data) 474 elseif self.telnet_state == TNS_IAC then 475 if data == self.commands.IAC then 476 -- insert this 0xFF in to the buffer 477 self:store3270(data) 478 self.telnet_state = TNS_DATA 479 elseif data == self.commands.EOR then 480 -- we're at the end of the TN3270 data 481 -- let's process it and see what we've got 482 -- but only if we're in 3270 mode 483 if self.state == self.TN3270_DATA or self.state == self.TN3270E_DATA then 484 self:process_data() 485 end 486 self.telnet_state = TNS_DATA 487 elseif data == self.commands.WILL then self.telnet_state = TNS_WILL 488 elseif data == self.commands.WONT then self.telnet_state = TNS_WONT 489 elseif data == self.commands.DO then self.telnet_state = TNS_DO 490 elseif data == self.commands.DONT then self.telnet_state = TNS_DONT 491 elseif data == self.commands.SB then self.telnet_state = TNS_SB 492 end 493 elseif self.telnet_state == TNS_WILL then 494 stdnse.debug(3, "[TELNET] IAC WILL 0x%s?", stdnse.tohex(data)) 495 for _,v in pairs(self.options) do -- check to see if we support this sub option (SB) 496 if v == data then 497 stdnse.debug(3, "[TELNET] IAC DO 0x%s", stdnse.tohex(data)) 498 supported = true 499 break 500 end 501 end -- end of checking options 502 for _,v in pairs(self.unsupported_opts) do 503 if v == data then 504 stdnse.debug(3, "[TELNET] IAC DONT 0x%s (disabled)", stdnse.tohex(data)) 505 supported = false 506 end 507 end 508 if supported then 509 if not self.server_options[data] then -- if we haven't already replied to this, let's reply 510 self.server_options[data] = true 511 self:send_data(DO_reply..data) 512 stdnse.debug(3, "[TELNET] Sent Will Reply: 0x%s", stdnse.tohex(data)) 513 self:in3270() 514 end 515 else 516 self:send_data(DONT_reply..data) 517 stdnse.debug(3, "[TELNET] Sent Don't Reply: 0x%s", stdnse.tohex(data)) 518 end 519 self.telnet_state = TNS_DATA 520 elseif self.telnet_state == TNS_WONT then 521 if self.server_options[data] then 522 self.server_options[data] = false 523 self:send_data(DONT_reply..data) 524 stdnse.debug(3, "[TELNET] Sent Don't Reply: 0x%s", stdnse.tohex(data)) 525 self:in3270() 526 end 527 self.telnet_state = TNS_DATA 528 elseif self.telnet_state == TNS_DO then 529 stdnse.debug(3, "[TELNET] IAC DO 0x%s?", stdnse.tohex(data)) 530 for _,v in pairs(self.options) do -- check to see if we support this sub option (SB) 531 if v == data then 532 stdnse.debug(3, "[TELNET] IAC WILL 0x%s", stdnse.tohex(data)) 533 supported = true 534 break 535 end 536 end -- end of checking options 537 for _,v in pairs(self.unsupported_opts) do 538 if v == data then 539 stdnse.debug(3, "[TELNET] IAC WONT 0x%s (disabled)", stdnse.tohex(data)) 540 supported = false 541 end 542 end 543 if supported then 544 if not self.client_options[data] then 545 self.client_options[data] = true 546 self:send_data(WILL_reply..data) 547 stdnse.debug(3, "[TELNET] Sent Do Reply: 0x%s" , stdnse.tohex(data)) 548 self:in3270() 549 end 550 else 551 self:send_data(WONT_reply..data) 552 stdnse.debug(3, "[TELNET] Got unsupported Do. Sent Won't Reply: " .. data .. " " .. self.telnet_data) 553 end 554 self.telnet_state = TNS_DATA 555 elseif self.telnet_state == TNS_DONT then 556 if self.client_options[data] then 557 self.client_options[data] = false 558 self:send_data(WONT_reply .. data) 559 stdnse.debug(3, "[TELNET] Sent Wont Reply: 0x%s", stdnse.tohex(data)) 560 self:in3270() 561 end 562 self.telnet_state = TNS_DATA 563 elseif self.telnet_state == TNS_SB then 564 if data == self.commands.IAC then 565 self.telnet_state = TNS_SB_IAC 566 else 567 self.sb_options = self.sb_options .. data 568 end 569 elseif self.telnet_state == TNS_SB_IAC then 570 stdnse.debug(3, "[TELNET] Processing SB options") 571-- self.sb_options = self.sb_options .. data -- looks like this is a bug? Why append F0 to the end? 572 if data == self.commands.SE then 573 self.telnet_state = TNS_DATA 574 if self.sb_options:sub(1,1) == self.options.TTYPE and 575 self.sb_options:sub(2,2) == self.commands.SEND then 576 self:send_data(self.commands.IAC .. 577 self.commands.SB .. 578 self.options.TTYPE .. 579 self.commands.IS .. 580 self.device_type .. 581 self.commands.IAC .. 582 self.commands.SE ) 583 elseif (self.client_options[self.options.TN3270] or self.client_options[self.options.TN3270E]) and 584 (self.sb_options:sub(1,1) == self.options.TN3270 or 585 self.sb_options:sub(1,1) == self.options.TN3270E) then 586 if not self:negotiate_tn3270() then 587 return false 588 end 589 stdnse.debug(3, "[TELNET] Done Negotiating Options") 590 else 591 self.telnet_state = TNS_DATA 592 end 593 self.sb_options = '' 594 end 595 --self.sb_options = '' 596 end -- end of makeshift switch/case 597 return true 598 end, 599 600 --- Stores a character on a buffer to be processed 601 -- 602 store3270 = function ( self, char ) 603 self.tn_buffer = self.tn_buffer .. char 604 end, 605 606 --- Function to negotiate TN3270 sub options 607 608 negotiate_tn3270 = function ( self ) 609 stdnse.debug(3, "[TN3270] Processing tn data subnegotiation options ") 610 local option = self.sb_options:sub(2,2) 611 -- stdnse.debug("[TN3270E] We got this: 0x%s", stdnse.tohex(option)) 612 613 if option == self.tncommands.SEND then 614 if self.sb_options:sub(3,3) == self.tncommands.DEVICETYPE then 615 if self.connected_lu == '' then 616 self:send_data(self.commands.IAC .. 617 self.commands.SB .. 618 self.options.TN3270E .. 619 self.tncommands.DEVICETYPE .. 620 self.tncommands.REQUEST .. 621 self.device_type .. 622 self.commands.IAC .. 623 self.commands.SE ) 624 else 625 stdnse.debug(3,"[TN3270] Sending LU: %s", self.connected_lu) 626 self:send_data(self.commands.IAC .. 627 self.commands.SB .. 628 self.options.TN3270E .. 629 self.tncommands.DEVICETYPE .. 630 self.tncommands.REQUEST .. 631 self.device_type .. 632 self.tncommands.CONNECT .. 633 self.connected_lu .. 634 self.commands.IAC .. 635 self.commands.SE ) 636 end 637 else 638 stdnse.debug(3,"[TN3270] Received TN3270 Send but not device type. Weird.") 639 return false 640 end 641 elseif option == self.tncommands.DEVICETYPE then -- Mainframe is confirming device type. Good! 642 if self.sb_options:sub(3,3) == self.tncommands.REJECT then 643 -- Welp our LU request failed, shut it down 644 stdnse.debug(3,"[TN3270] Received TN3270 REJECT.") 645 return false 646 elseif self.sb_options:sub(3,3) == self.tncommands.IS then 647 local tn_loc = 1 648 while self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.commands.SE and 649 self.sb_options:sub(4+tn_loc,4+tn_loc) ~= self.tncommands.CONNECT do 650 tn_loc = tn_loc + 1 651 end 652 --XXX Unused variable??? Should this be tn_loc? 653 -- local sn_loc = 1 654 if self.sb_options:sub(4+tn_loc,4+tn_loc) == self.tncommands.CONNECT then 655 self.connected_lu = self.sb_options:sub(5+tn_loc, #self.sb_options) 656 self.connected_dtype = self.sb_options:sub(4,3+tn_loc) 657 stdnse.debug(3,"[TN3270] Current LU: %s", self.connected_lu) 658 end 659 -- since We've connected lets send our options 660 self:send_data(self.commands.IAC .. 661 self.commands.SB .. 662 self.options.TN3270E .. 663 self.tncommands.FUNCTIONS .. 664 self.tncommands.REQUEST .. 665 --self.tncommands.RESPONSES .. -- we'll only support basic 3270E mode 666 self.commands.IAC .. 667 self.commands.SE ) 668 end 669 elseif option == self.tncommands.FUNCTIONS then 670 if self.sb_options:sub(3,3) == self.tncommands.IS then 671 -- they accepted the function request, lets move on 672 self.negotiated = true 673 stdnse.debug(3,"[TN3270] Option Negotiation Done!") 674 self:in3270() 675 elseif self.sb_options:sub(3,3) == self.tncommands.REQUEST then 676 -- dummy functions for now. Our client doesn't have any 677 -- functions really but we'll agree to whatever they want 678 self:send_data(self.commands.IAC .. 679 self.commands.SB .. 680 self.options.TN3270E .. 681 self.tncommands.FUNCTIONS .. 682 self.tncommands.IS .. 683 self.sb_options:sub(4,4) .. 684 self.commands.IAC .. 685 self.commands.SE ) 686 self.negotiated = true 687 self:in3270() 688 end 689 end 690 return true 691 end, 692 693 --- Check to see if we're in TN3270 694 in3270 = function ( self ) 695 if self.client_options[self.options.TN3270E] then 696 stdnse.debug(3,"[in3270] In TN3270E mode") 697 if self.negotiated then 698 stdnse.debug(3,"[in3270] TN3270E negotiated") 699 self.state = self.TN3270E_DATA 700 end 701 elseif self.client_options[self.options.EOR] and 702 self.client_options[self.options.BINARY] and 703 self.client_options[self.options.EOR] and 704 self.client_options[self.options.BINARY] and 705 self.client_options[self.options.TTYPE] then 706 stdnse.debug(3,"[in3270] In TN3270 mode") 707 self.state = self.TN3270_DATA 708 end 709 710 if self.state == self.TN3270_DATA or self.state == self.TN3270E_DATA then 711 -- since we're in TN3270 mode, let's create an empty buffer 712 stdnse.debug(3, "[in3270] Creating Empty IBM-3278-2 Buffer") 713 for i=0, 1920 do 714 self.buffer[i] = "\0" 715 self.fa_buffer[i] = "\0" 716 self.overwrite_buf[i] = "\0" 717 end 718 stdnse.debug(3, "[in3270] Empty Buffer Created. Length: " .. #self.buffer) 719 end 720 stdnse.debug(3,"[in3270] Current State: "..self.word_state[self.state]) 721 end, 722 723 --- Also known as process_eor 724 process_data = function ( self ) 725 local reply = 0 726 stdnse.debug(3,"Processing TN3270 Data") 727 if self.state == self.TN3270E_DATA then 728 stdnse.debug(3,"[TN3270E] Processing TN3270 Data header: %s", stdnse.tohex(self.tn_buffer:sub(1,5))) 729 self.tn3270_header.data_type = self.tn_buffer:sub(1,1) 730 self.tn3270_header.request_flag = self.tn_buffer:sub(2,2) 731 self.tn3270_header.response_flag = self.tn_buffer:sub(3,3) 732 self.tn3270_header.seq_number = self.tn_buffer:sub(4,5) 733 if self.tn3270_header.data_type == "\000" then 734 reply = self:process_3270(self.tn_buffer:sub(6)) 735 stdnse.debug(3,"[TN3270E] Reply: %s", reply) 736 end 737 if reply < 0 and self.tn3270_header.request_flag ~= self.TN3270E_RSF_NO_RESPONSE then 738 self:tn3270e_nak(reply) 739 elseif reply == self.NO_OUTPUT and 740 self.tn3270_header.request_flag == self.ALWAYS_RESPONSE then 741 self:tn3270e_ack() 742 end 743 else 744 self:process_3270(self.tn_buffer) 745 end 746 -- nsedebug.print_hex(self.tn_buffer) 747 748 self.tn_buffer = '' 749 return true 750 end, 751 752 tn3270e_nak = function ( self, reply ) 753 local neg = "" 754 if reply == self.BAD_COMMAND then 755 neg = self.NEG_COMMAND_REJECT 756 elseif reply == self.BAD_ADDRESS then 757 neg = self.NEG_OPERATION_CHECK 758 end 759 760 -- build the TN3270E nak reply header 761 local reply_buf = string.pack("BBB c2", 762 self.DT_RESPONSE, -- type 763 0, -- request 764 self.NEGATIVE_RESPONSE, -- response 765 -- because this is telnet we gotta double up 0xFF chars 766 self.tn3270_header.seq_number:sub(1,2):gsub(self.commands.IAC, self.commands.IAC:rep(2)) 767 ) .. neg .. self.commands.IAC .. self.commands.EOR 768 769 -- now send the whole thing 770 self:send_data(reply_buf) 771 end, 772 773 tn3270e_ack = function ( self ) 774 -- build the TN3270E ack reply header 775 local reply_buf = string.pack("BBB c2", 776 self.DT_RESPONSE, -- type 777 0, -- request 778 self.POSITIVE_RESPONSE, -- response 779 -- because this is telnet we gotta double up 0xFF chars 780 self.tn3270_header.seq_number:sub(1,2):gsub(self.commands.IAC, self.commands.IAC:rep(2)) 781 ) .. self.POS_DEVICE_END .. self.commands.IAC .. self.commands.EOR 782 -- now send the whole package 783 self:send_data(reply_buf) 784 end, 785 786 clear_screen = function ( self ) 787 self.buffer_address = 1 788 for i=1,1920,1 do 789 self.buffer[i] = "\0" 790 self.fa_buffer[i] = "\0" 791 end 792 end, 793 794 clear_unprotected = function ( self ) 795 -- we don't support protect vs unprotected (yet) 796 -- this function is a stub for now 797 end, 798 799 process_3270 = function ( self, data ) 800 -- the first byte will be the command we have to follow 801 local com = data:sub(1,1) 802 stdnse.debug(3, "[PROCESS 3270] Value Received: 0x%s", stdnse.tohex(com)) 803 if com == self.command.EAU then 804 stdnse.debug(3,"TN3270 Command: Erase All Unprotected") 805 self:clear_unprotected() 806 return self.NO_OUTPUT 807 elseif com == self.command.EWA or com == self.sna_command.EWA or 808 com == self.command.EW or com == self.sna_command.EW then 809 stdnse.debug(3,"TN3270 Command: Erase Write (Alternate)") 810 self:clear_screen() 811 self:process_write(data) -- so far should only return No Output 812 return self.NO_OUTPUT 813 elseif com == self.command.W or com == self.sna_command.W then 814 stdnse.debug(3,"TN3270 Command: Write") 815 self:process_write(data) 816 elseif com == self.command.RB or com == self.sna_command.RB then 817 stdnse.debug(3,"TN3270 Command: Read Buffer") 818 self:process_read() 819 return self.OUTPUT 820 elseif com == self.command.RM or com == self.sna_command.RM or 821 com == self.command.RMA or com == self.sna_command.RMA then 822 stdnse.debug(3,"TN3270 Command: Read Modified (All)") 823 --XXX What is read_modified? What is aid? 824 --self:read_modified(aid) 825 --return self.OUTPUT 826 stdnse.debug1("UNIMPLEMENTED TN3270 Command: Read Modified (All)") 827 return self.BAD_COMMAND 828 elseif com == self.command.WSF or com == self.sna_command.WSF then 829 stdnse.debug(3,"TN3270 Command: Write Structured Field") 830 return self:w_structured_field(data) 831 elseif com == self.command.NOP or com == self.sna_command.NOP then 832 stdnse.debug(3,"TN3270 Command: No OP (NOP)") 833 return self.NO_OUTPUT 834 else 835 stdnse.debug(3,"Unknown 3270 Data Stream command: 0x"..stdnse.tohex(com)) 836 return self.BAD_COMMAND 837 838 end 839 return 1 -- we may sometimes enter a state where we have nothing which is fine 840 841 end, 842 843 --- WCC / tn3270 data stream processor 844 -- 845 -- @param tn3270 data stream 846 -- @return status true on success, false on failure 847 -- @return changes self.buffer to match requested changes 848 process_write = function ( self, data ) 849 stdnse.debug(3, "Processing TN3270 Write Command") 850 local prev = '' 851 local cp = '' 852 local num_attr = 0 853 local last_cmd = false 854 local i = 2 -- skip SF to get WCC 855 856 if (data:byte(i) & 0x40) == 0x40 then 857 stdnse.debug(3,"[WCC] Reset") 858 end 859 860 if (data:byte(i) & 0x02) == 0x02 then 861 stdnse.debug(3,"[WCC] Restore") 862 end 863 864 i = 3 -- skip the SF and the WCC. 865 while i <= #data do 866 cp = data:sub(i,i) 867 stdnse.debug(4,"Current Position: ".. i .. " of " .. #data) 868 stdnse.debug(4,"Current Item: ".. stdnse.tohex(cp)) 869 -- yay! lua has no switch statement 870 if cp == self.orders.SF then 871 stdnse.debug(4,"Start Field") 872 prev = 'ORDER' 873 874 last_cmd = true 875 i = i + 1 -- skip SF 876 stdnse.debug(4,"Writting Zero to buffer at address: " .. self.buffer_address) 877 stdnse.debug(4,"Attribute Type: 0x".. stdnse.tohex(data:sub(i,i))) 878 self:write_field_attribute(data:sub(i,i)) 879 self:write_char("\00") 880 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 881 -- set the current position one ahead (after SF) 882 i = i + 1 883 884 elseif cp == self.orders.SFE then 885 stdnse.debug(4,"Start Field Extended") 886 i = i + 1 -- skip SFE 887 num_attr = data:byte(i) 888 stdnse.debug(4,"Number of Attributes: ".. num_attr) 889 for j = 1,num_attr do 890 i = i + 1 891 if data:byte(i) == 0xc0 then 892 stdnse.debug(4,"Writting Zero to buffer at address: " .. self.buffer_address) 893 stdnse.debug(4,"Attribute Type: 0x".. stdnse.tohex(data:sub(i,i))) 894 self:write_char("\00") 895 self:write_field_attribute(data:sub(i,i)) 896 end 897 898 i = i + 1 899 end 900 i = i + 1 901 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 902 elseif cp == self.orders.SBA then 903 stdnse.debug(4,"Set Buffer Address (SBA) 0x11") 904 self.buffer_address = self.DECODE_BADDR(data:byte(i+1), data:byte(i+2)) 905 stdnse.debug(4,"Buffer Address: " .. self.buffer_address) 906 stdnse.debug(4,"Row: " .. self:BA_TO_ROW(self.buffer_address)) 907 stdnse.debug(4,"Col: " .. self:BA_TO_COL(self.buffer_address)) 908 last_cmd = true 909 prev = 'SBA' 910 -- the current position is SBA, the next two bytes are the lengths 911 i = i + 3 912 stdnse.debug(4,"Next Command: ".. stdnse.tohex(data:sub(i,i))) 913 elseif cp == self.orders.IC then -- Insert Cursor 914 stdnse.debug(4,"Insert Cursor (IC) 0x13") 915 stdnse.debug(4,"Current Cursor Address: " .. self.cursor_addr) 916 stdnse.debug(4,"Buffer Address: " .. self.buffer_address) 917 stdnse.debug(4,"Row: " .. self:BA_TO_ROW(self.buffer_address)) 918 stdnse.debug(4,"Col: " .. self:BA_TO_COL(self.buffer_address)) 919 prev = 'ORDER' 920 self.cursor_addr = self.buffer_address 921 last_cmd = true 922 i = i + 1 923 elseif cp == self.orders.RA then 924 -- Repeat address repeats whatever the next char is after the two byte buffer address 925 -- There's all kinds of weird GE stuff we could do, but not now. Maybe in future vers 926 stdnse.debug(4,"Repeat to Address (RA) 0x3C") 927 local ra_baddr = self.DECODE_BADDR(data:byte(i+1), data:byte(i+2)) 928 stdnse.debug(4,"Repeat Character: " .. stdnse.tohex(data:sub(i+1,i+2))) 929 930 stdnse.debug(4,"Repeat to this Address: " .. ra_baddr) 931 stdnse.debug(4,"Currrent Address: " .. self.buffer_address) 932 prev = 'ORDER' 933 --char_code = data:sub(i+3,i+3) 934 i = i + 3 935 local char_to_repeat = data:sub(i,i) 936 stdnse.debug(4,"Repeat Character: " .. stdnse.tohex(char_to_repeat)) 937 while (self.buffer_address ~= ra_baddr) do 938 self:write_char(char_to_repeat) 939 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 940 end 941 elseif cp == self.orders.EUA then 942 stdnse.debug(4,"Erase Unprotected All (EAU) 0x12") 943 local eua_baddr = self.DECODE_BADDR(data:byte(i+1), data:byte(i+2)) 944 i = i + 3 945 stdnse.debug(4,"EAU to this Address: " .. eua_baddr) 946 stdnse.debug(4,"Currrent Address: " .. self.buffer_address) 947 while (self.buffer_address ~= eua_baddr) do 948 -- do nothing for now. this feature isn't supported/required at the moment 949 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 950 --stdnse.debug(3,"Currrent Address: " .. self.buffer_address) 951 --stdnse.debug(3,"EAU to this Address: " .. eua_baddr) 952 end 953 elseif cp == self.orders.GE then 954 stdnse.debug(4,"Graphical Escape (GE) 0x08") 955 prev = 'ORDER' 956 i = i + 1 -- move to next byte 957 local ge_char = data:sub(i,i) 958 self:write_char(self, ge_char) 959 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 960 elseif cp == self.orders.MF then 961 -- MotherFucker, lol! 962 -- or mainframe maybe 963 -- we don't actually have 'fields' at this point 964 -- so there's nothing to be modified 965 stdnse.debug(4,"Modify Field (MF) 0x2C") 966 prev = 'ORDER' 967 i = i + 1 968 local num_attr = tonumber(data:sub(i,i)) 969 for j = 1, num_attr, 1 do 970 -- placeholder in case we need to do something here 971 stdnse.debug(4,"Set Attribute (MF) 0x2C") 972 i = i + 1 973 end 974 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 975 elseif cp == self.orders.SA then 976 -- We'll add alerting here to identify hidden field 977 -- but for now we're doing NOTHING 978 i = i + 1 979 980 elseif cp == self.fcorders.NUL or 981 cp == self.fcorders.SUB or 982 cp == self.fcorders.DUP or 983 cp == self.fcorders.FM or 984 cp == self.fcorders.FF or 985 cp == self.fcorders.CR or 986 cp == self.fcorders.NL or 987 cp == self.fcorders.EM or 988 cp == self.fcorders.EO then 989 stdnse.debug(4,"Format Control Order received") 990 prev = 'ORDER' 991 self:write_char("\064") 992 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 993 i = i + 1 994 else -- whoa we made it. 995 local ascii_char = drda.StringUtil.toASCII(cp) 996 stdnse.debug(4,"Inserting 0x"..stdnse.tohex(cp).." (".. ascii_char ..") at the following location:") 997 stdnse.debug(4,"Row: " .. self:BA_TO_ROW(self.buffer_address)) 998 stdnse.debug(4,"Col: " .. self:BA_TO_COL(self.buffer_address)) 999 stdnse.debug(4,"Buffer Address: " .. self.buffer_address) 1000 self:write_char(data:sub(i,i)) 1001 self.buffer_address = self:INC_BUF_ADDR(self.buffer_address) 1002 self.first_screen = true 1003 i = i + 1 1004 end -- end of massive if/else 1005 end -- end of while loop 1006 self.formatted = true 1007 end, 1008 1009 write_char = function ( self, char ) 1010 if self.buffer[self.buffer_address] == "\0" then 1011 self.buffer[self.buffer_address] = char 1012 else 1013 self.overwrite_buf[self.buffer_address] = self.buffer[self.buffer_address] 1014 self.buffer[self.buffer_address] = char 1015 end 1016 end, 1017 1018 write_field_attribute = function ( self, attr ) 1019 self.fa_buffer[self.buffer_address] = attr 1020 end, 1021 1022 process_read = function ( self ) 1023 local output_addr = 0 1024 self.output_buffer = {} 1025 stdnse.debug(3,"Generating Read Buffer") 1026 self.output_buffer[output_addr] = string.pack("B",self.aid) 1027 output_addr = output_addr + 1 1028 stdnse.debug(3,"Output Address: ".. output_addr) 1029 self.output_buffer[output_addr] = self:ENCODE_BADDR(self.cursor_addr) 1030 return self:send_tn3270(self.output_buffer) 1031 1032 -- need to add while loop 1033 1034 end, 1035 1036 w_structured_field = function ( self, wsf_data ) 1037 -- this is the ugliest hack ever 1038 -- but it works and it doesn't matter what we support anyway 1039 stdnse.debug(3, "Processing TN3270 Write Structured Field Command") 1040 -- all our options, one liner style 1041 local query_options = 1042 "\x88\x00\x16\x81\x86\x00\x08\x00\xf4\xf1\x00\xf2\x00\xf3\x00\xf4\z 1043 \x00\xf5\x00\xf6\x00\xf7\x00\x00\x0d\x81\x87\x04\x00\xf0\xf1\xf1\z 1044 \xf2\xf2\xf4\xf4\x00\x22\x81\x85\x82\x00\x07\x10\x00\x00\x00\x00\z 1045 \x07\x00\x00\x00\x00\x65\x00\x25\x00\x00\x00\x02\xb9\x00\x25\x01\z 1046 \x00\xf1\x03\xc3\x01\x36\x00\x2e\x81\x81\x03\x00\x00\x50\x00\x18\z 1047 \x00\x00\x01\x00\x48\x00\x01\x00\x48\x07\x10\x00\x00\x00\x00\x00\z 1048 \x00\x13\x02\x00\x01\x00\x50\x00\x18\x00\x00\x01\x00\x48\x00\x01\z 1049 \x00\x48\x07\x10\x00\x1c\x81\xa6\x00\x00\x0b\x01\x00\x00\x50\x00\z 1050 \x18\x00\x50\x00\x18\x0b\x02\x00\x00\x07\x00\x10\x00\x07\x00\x10\z 1051 \x00\x07\x81\x88\x00\x01\x02\x00\x16\x81\x80\x80\x81\x84\x85\x86\z 1052 \x87\x88\xa1\xa6\xa8\x96\x99\xb0\xb1\xb2\xb3\xb4\xb6\x00\x08\x81\z 1053 \x84\x00\x0a\x00\x04\x00\x06\x81\x99\x00\x00\xff\xef" 1054 stdnse.debug(3, "Current WSF : %s", stdnse.tohex(wsf_data:sub(4,4)) ) 1055 1056 if self.state == self.TN3270E_DATA then 1057 -- We need to add the header here since we're in TN3270E mode 1058 query_options = "\x00\x00\x00\x00\x00" .. query_options 1059 end 1060 self:send_data(query_options) 1061 return 1 1062 end, 1063 1064 1065 --- Sends TN3270 Packet 1066 -- 1067 -- Expands IAC to IAC IAC and finally appends IAC EOR 1068 -- @param data: table containing buffer array 1069 send_tn3270 = function ( self, data ) 1070 local packet = '' 1071 if self.state == self.TN3270E_DATA then 1072 packet = "\x00\x00\x00\x00\x00" 1073 -- we need to create the tn3270E (the E is important) header 1074 -- which, in basic 3270E is 5 bytes of 0x00 1075 --packet = string.pack("BBB >I2", 1076 -- self.DT_3270_DATA, -- type 1077 -- 0, -- request 1078 -- 0, -- response 1079 -- 0 1080 -- ) 1081 --self.tn3270_header.seq_number 1082 end 1083 -- create send buffer and double up IACs 1084 1085 for i=0,#data do 1086 stdnse.debug(3,"Adding 0x" .. stdnse.tohex(data[i]) .. " to the read buffer") 1087 packet = packet .. data[i] 1088 if data[i] == self.commands.IAC then 1089 packet = packet .. self.commands.IAC 1090 end 1091 end 1092 packet = packet .. self.commands.IAC .. self.commands.EOR 1093 return self:send_data(packet) -- send the output buffer 1094 end, 1095 1096 get_screen = function ( self ) 1097 stdnse.debug(3,"Returning the current TN3270 buffer") 1098 local buff = '\n' 1099 for i = 0,#self.buffer do 1100 if self.buffer[i] == "\00" then 1101 buff = buff .. " " 1102 else 1103 buff = buff .. drda.StringUtil.toASCII(self.buffer[i]) 1104 end 1105 if (i+1) % 80 == 0 then 1106 buff = buff .. "\n" 1107 end 1108 end 1109 return buff 1110 end, 1111 1112 get_screen_debug = function ( self, lvl ) 1113 lvl = lvl or 1 1114 stdnse.debug(lvl,"---------------------- Printing the current TN3270 buffer ----------------------") 1115 local buff = '' 1116 for i = 0,#self.buffer do 1117 if self.buffer[i] == "\00" then 1118 buff = buff .. " " 1119 else 1120 buff = buff .. drda.StringUtil.toASCII(self.buffer[i]) 1121 end 1122 if (i+1) % 80 == 0 then 1123 stdnse.debug(lvl, buff) 1124 buff = '' 1125 end 1126 end 1127 stdnse.debug(lvl,"----------------------- End of the current TN3270 buffer ---------------------") 1128 1129 return buff 1130 end, 1131 1132 get_screen_raw = function ( self ) 1133 local buff = '' 1134 for i = 0,#self.buffer do 1135 buff = buff .. drda.StringUtil.toASCII(self.buffer[i]) 1136 end 1137 return buff 1138 end, 1139 1140 1141 --- Sends data at the current cursor location. Ignores field attributes. 1142 -- 1143 -- It only uses enter key (AID = 0x7d) to send this data 1144 -- for more complicated items use send_location 1145 -- @param string you wish to send. 1146 send_cursor = function ( self, data ) 1147 local ebcdic_letter = '' 1148 self.output_buffer = {} -- empty the output buffer 1149 self.output_buffer[0] = string.pack("B",self.aids.ENTER) -- what follows is an ENTER 1150 stdnse.debug(3,"Cursor Location ("..self.cursor_addr.."): Row: %s, Column: %s ", 1151 self:BA_TO_ROW(self.cursor_addr), 1152 self:BA_TO_COL(self.cursor_addr) ) 1153 table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr + #data)) -- location of cursor 1154 table.insert(self.output_buffer, self.orders.SBA) -- set the buffer address to the following location 1155 table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr)) -- location of buffer address 1156 for i = 1, #data do 1157 stdnse.debug(3,"Inserting %s to the send buffer", data:sub(i,i)) 1158 ebcdic_letter = drda.StringUtil.toEBCDIC( data:sub(i,i) ) 1159 table.insert(self.output_buffer, ebcdic_letter ) -- insert the ebcdic character on the array 1160 end 1161 return self:send_tn3270(self.output_buffer) 1162 end, 1163 1164 --- Sends the data to the location specified 1165 -- 1166 -- Using a location on the screen sends the data 1167 -- @param location: a location on the screen (between 0 and 1920) 1168 -- @param data: ascii data to send to that location 1169 send_location = function( self, location, data ) 1170 local cursor_location = location + #data 1171 local ebcdic_letter = '' 1172 self.output_buffer = {} 1173 self.output_buffer[0] = string.pack("B",self.aids.ENTER) 1174 table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location)) 1175 stdnse.debug(3,"Cursor Location ("..cursor_location.."): Row: %s, Column: %s ", 1176 self:BA_TO_ROW(cursor_location), 1177 self:BA_TO_COL(cursor_location) ) 1178 stdnse.debug(3,"Inserting %s at location %d", data, location ) 1179 table.insert(self.output_buffer, self.orders.SBA) 1180 cursor_location = location 1181 table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location)) 1182 for j = 1, #data do 1183 ebcdic_letter = drda.StringUtil.toEBCDIC( data:sub(j,j) ) 1184 table.insert(self.output_buffer, ebcdic_letter ) 1185 end 1186 1187 return self:send_tn3270(self.output_buffer) 1188 end, 1189 1190 --- Sends the data to multiple locations on the screen 1191 -- 1192 -- Using a supplied tuple of location and data generates tn3270 data to 1193 -- fill out the screen 1194 -- @param location_tuple: and array of tuples with location and data. For 1195 -- example: send_locations([{579:"dade"},{630:"secret"}]) 1196 send_locations = function( self, location_tuple ) 1197 local cursor_location = location_tuple[#location_tuple][1] + #location_tuple[#location_tuple][2] 1198 local ebcdic_letter = '' 1199 self.output_buffer = {} 1200 self.output_buffer[0] = string.pack("B",self.aids.ENTER) 1201 table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location)) 1202 stdnse.debug(3,"Cursor Location ("..cursor_location.."): Row: %s, Column: %s ", 1203 self:BA_TO_ROW(cursor_location), 1204 self:BA_TO_COL(cursor_location) ) 1205 for i = 1, #location_tuple do 1206 stdnse.debug(3,"Inserting %s at location %d", location_tuple[i][2], location_tuple[i][1] ) 1207 table.insert(self.output_buffer, self.orders.SBA) 1208 cursor_location = location_tuple[i][1] 1209 table.insert(self.output_buffer, self:ENCODE_BADDR(cursor_location)) 1210 for j = 1, #location_tuple[i][2] do 1211 ebcdic_letter = drda.StringUtil.toEBCDIC( location_tuple[i][2]:sub(j,j) ) 1212 table.insert(self.output_buffer, ebcdic_letter ) 1213 end 1214 end 1215 return self:send_tn3270(self.output_buffer) 1216 end, 1217 1218 send_enter = function ( self ) 1219 local ebcdic_letter = '' 1220 self.output_buffer = {} 1221 self.output_buffer[0] = string.pack("B",self.aids.ENTER) 1222 table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr)) 1223 table.insert(self.output_buffer, self.orders.SBA) 1224 table.insert(self.output_buffer, self:ENCODE_BADDR(self.cursor_addr)) 1225 return self:send_tn3270(self.output_buffer) 1226 end, 1227 1228 send_clear = function ( self ) 1229 return self:send_data( string.pack("B",self.aids.CLEAR) .. self.commands.IAC .. self.commands.EOR ) 1230 end, 1231 1232 send_pf = function ( self, pf ) 1233 if pf > 24 or pf < 0 then 1234 return false, "PF Value must be between 1 and 24" 1235 end 1236 self.output_buffer = {} 1237 self.output_buffer[0] = string.pack("B", self.aids["PF"..pf] ) 1238 stdnse.debug(3,"Cursor Location ("..self.cursor_addr.."): Row: %s, Column: %s ", 1239 self:BA_TO_ROW(self.cursor_addr), 1240 self:BA_TO_COL(self.cursor_addr) ) 1241 self.output_buffer[1] = self:ENCODE_BADDR(self.cursor_addr) 1242 return self:send_tn3270(self.output_buffer) 1243 end, 1244 1245 writeable = function (self) 1246 -- Returns a list with all writeable fields as {location, length} tuples 1247 local writeable_list = {} 1248 for i = 0,#self.fa_buffer do 1249 if ( self.fa_buffer[i] ~= "\00" ) and (self.fa_buffer[i]:byte(1) & 0x20) ~= 0x20 then 1250 -- found writeable flag 1251 for j = i,#self.fa_buffer do 1252 -- find end of field 1253 if (self.fa_buffer[j]:byte(1) & 0x20) == 0x20 then 1254 stdnse.debug(3,"[WRITEABLE] Area: %d Row: %d Col: %d Length: %d", i + 1, self:BA_TO_ROW(i + 1), self:BA_TO_COL(i + 2), j-i-1) 1255 table.insert(writeable_list, {i + 1, j-i-1}) 1256 break 1257 end 1258 end 1259 end 1260 end 1261 return writeable_list 1262 end, 1263 1264 find = function ( self, str ) 1265 local buff = '' 1266 for i = 0,#self.buffer do 1267 if self.buffer[i] == "\00" then 1268 buff = buff .. " " 1269 else 1270 buff = buff .. drda.StringUtil.toASCII(self.buffer[i]) 1271 end 1272 end 1273 --local buff = self:get_screen() 1274 stdnse.debug(3, "[FIND] Looking for: %s", tostring(str)) 1275 local i, j = string.find(buff, str) 1276 if i == nil then 1277 stdnse.debug(3, "[FIND] Couldn't find: %s", tostring(str)) 1278 return false 1279 else 1280 stdnse.debug(3, "[FIND] Found String: %s", tostring(str)) 1281 return i , j 1282 end 1283 end, 1284 1285 isClear = function ( self ) 1286 local buff = '' 1287 for i = 0,#self.buffer do 1288 if self.buffer[i] == "\00" then 1289 buff = buff .. " " 1290 else 1291 buff = buff .. drda.StringUtil.toASCII(self.buffer[i]) 1292 end 1293 end 1294 local i, j = string.find(buff, '%w') 1295 if i ~= nil then 1296 stdnse.debug(3, "[CLEAR] Screen has text") 1297 return false 1298 else 1299 stdnse.debug(3, "[CLEAR] Screen is Empty") 1300 return true 1301 end 1302 end, 1303 1304 --- Any Hidden Fields 1305 -- 1306 -- @returns true if there are any hidden fields in the buffer 1307 any_hidden = function ( self ) 1308 local hidden_attrib = 0x0c -- 00001100 is hidden 1309 for i = 0,#self.fa_buffer do 1310 if (self.fa_buffer[i]:byte(1) & hidden_attrib) == hidden_attrib then 1311 return true 1312 end 1313 end 1314 end, 1315 1316 --- Hidden Fields 1317 -- 1318 -- @returns the locations of hidden fields in a table with each pair being the start and stop of the hidden field 1319 hidden_fields_location = function ( self ) 1320 local hidden_attrib = 0x0c -- 00001100 is hidden 1321 local hidden_location = {} 1322 local i = 1 1323 if not self:any_hidden() then 1324 return hidden_location 1325 end 1326 while i <= #self.fa_buffer do 1327 if (self.fa_buffer[i]:byte(1) & hidden_attrib) == hidden_attrib then 1328 stdnse.debug(3, "Found hidden field at buffer location: " .. i) 1329 table.insert(hidden_location, i) 1330 i = i + 1 1331 while self.fa_buffer[i] == "\0" do 1332 i = i + 1 1333 end 1334 table.insert(hidden_location, i) 1335 end 1336 i = i + 1 1337 end 1338 return hidden_location 1339 end, 1340 1341 hidden_fields = function ( self ) 1342 local locations = self:hidden_fields_location() 1343 local fields = {} 1344 local i, j = 1,1 1345 local start, stop = 0 1346 while i <= #locations do 1347 start = locations[i] + 1 1348 stop = locations[i+1] - 1 1349 stdnse.debug(3, "Start Location: %i Stop Location %i", start, stop) 1350 fields[j] = '' 1351 for k = start,stop do 1352 -- stdnse.debug(3, "k = %i Inserting 0x%s", k, stdnse.tohex(self.buffer[k])) 1353 fields[j] = fields[j] .. drda.StringUtil.toASCII(self.buffer[k]) 1354 end 1355 j = j + 1 1356 i = i + 2 1357 end 1358 return fields 1359 end, 1360 1361 any_overwritten = function ( self ) 1362 for i = 1, #self.overwrite_buf do 1363 if self.overwrite_buf[i] ~= "\0" then 1364 return true 1365 end 1366 end 1367 return false 1368 end, 1369 1370 set_lu = function (self, LU) 1371 -- Sets an LU 1372 self.connected_lu = LU 1373 end, 1374 1375 get_lu = function ( self ) 1376 return self.connected_lu 1377 end, 1378 disable_tn3270e = function ( self ) 1379 stdnse.debug(3,"Disabling TN3270E") 1380 table.insert(self.unsupported_opts,self.options.TN3270E) 1381 end, 1382 overwrite_data = function ( self ) 1383 if not self:any_overwritten() then 1384 return false 1385 end 1386 stdnse.debug(3,"Printing the overwritten TN3270 buffer") 1387 local buff = '\n' 1388 for i = 0,#self.overwrite_buf do 1389 if self.overwrite_buf[i] == "\0" then 1390 buff = buff .. " " 1391 else 1392 buff = buff .. drda.StringUtil.toASCII(self.buffer[i]) 1393 end 1394 if i % 80 == 0 then 1395 buff = buff .. "\n" 1396 end 1397 end 1398 return buff 1399 end 1400} 1401 1402return _ENV 1403