* * Marinetti / SMB1 Test (THIS IS NOT SMB2), Mark II * * CHANGELOG * Thursday, April 30, 2015 - Restarted effort, ported code from ORCA/M to Merlin32 and debugged Merlin32 environment * Friday, May 1, 2015 - Ported more code to Merlin32, set up Merlin32 equates * Saturday, May 2, 2015 - Formatting fixes, refactoring, rewritten SMB Negotiation code * Saturday, May 9, 2015 - Receive and interpret NEG_PROT reply and start login * Sunday, May 24, 2015 - Some bugfixes, Tool128 and Tool129 requirement for hashing and DES, LM password hashing support * Also introducing successful SMB_Tree_ANDX message. We connect to remote shares now. * Also introducing SMB_Open_ANDX message. We open a file now. * Monday, May 25, 2015 - Bugfixes on SMB_Open_ANDX; file opening now successful * Also introducing SMB_Read_ANDX message. We read a file now. * * REFERENCES * smb.c / smb.h from libOGC * http://www.ubiqx.org/cifs/SMB.html * rel dsk smbdemo.l * Macros (mostly from Merlin32 dist) use GsOs.Macs use Util.Macs use Misc.Macs use Locator.Macs use Mem.Macs use Qd.Macs use QdAux.Macs use Event.Macs use Window.Macs use Ctl.Macs use Menu.Macs use Desk.Macs use Sound.Macs use Line.Macs use Dialog.Macs use TCPIP.Macs ; from MOSP CVS * Equates (ripped off from Merlin 16) use E16.Dialog.Macs use E16.GsOs.Macs * Equates (from MOSP/Tools/Orca.M/e16.tcpip) use E16.TCPIP.Macs *----------------------------------------------------------------------------- * DP variables and local equates *----------------------------------------------------------------------------- * DUM $000000 is broken on merlin32, if you want LDA (DP) $A5 opcode, write one-byte equates instead * cause merlin32 will always give you $AD (LDAL) * dum 0 *AppMMID * ds 2,0 ; Memory Manager ID *HndlRef * ds 2,0 ; For Dereferencing MM Handle *DPBase * ds 1,0 ; Deref'd handle * dend * workaround: do this instead for DP variables AppMMID = $0 HndlRef = $2 DPBase = $4 *----------------------------------------------------------------------------- * GS/OS Program Entry Point *----------------------------------------------------------------------------- Entry mx %00 phk plb brl Main * * Check for toolbox errors * too-simple error handler * CheckError bcs SysDeath rts SysDeath pha PushLong #0000 _SysFailMgr * * StartUpTools - start up the various toolsets * StartUpTools _TLStartUp pha _MMStartUp jsr CheckError PullWord AppMMID _MTStartUp pha pha PushLong #$900 ; 9 pages of DP space PushWord AppMMID PushWord #$C005 ; Fixed, Page-Aligned, Locked, Unpurgeable PushLong #$000000 ; in Bank $00, $0000 _NewHandle jsr CheckError PullLong HndlRef lda [HndlRef] sta DPBase pha ; save dp pointer for later pha PushWord #$0080 ; Screen Mode ($0000 = 320, $0080 = 640) PushWord #$00A0 ; Pixel Map Size ($0050 = 320, $00A0 = 640) PushWord AppMMID _QDStartUp jsr CheckError pla ; saved dp pointer clc adc #$300 pha ; save dp pointer for later pha PushWord #20 ; Event Queue size PushWord #0 ; Min X clamp PushWord #640 ; Max X clamp PushWord #0 ; Min Y clamp PushWord #200 ; Max Y clamp PushWord AppMMID _EMStartUp jsr CheckError PushWord #0 _SetBackColor PushWord #3 _SetForeColor PushWord #50 ; X position PushWord #85 ; Y position _MoveTo PushLong #OneMoment _DrawCString PushLong #ToolList _LoadTools jsr CheckError PushWord AppMMID _WindStartUp jsr CheckError pla ; saved dp pointer clc adc #$100 pha ; save it for later tax ; save dp pointer in x PushWord AppMMID phx _CtlStartUp jsr CheckError pla clc adc #$100 pha tax PushWord AppMMID phx _LEStartUp jsr CheckError PushWord AppMMID _DialogStartUp jsr CheckError pla clc adc #$100 pha tax PushWord AppMMID phx _MenuStartUp jsr CheckError _DeskStartUp jsr CheckError pla clc adc #$100 pha pha _SoundStartUp jsr CheckError _TCPIPStartUp jsr CheckError Tool $280 ; HashStartUp jsr CheckError pla clc adc #$100 pha Tool $281 ; CryptoStartUp rts * * ShutDownTools - shut em back down * ShutDownTools lda ToolList asl asl tax lda ToolList-2,x cmp #$2 ; Memory Manager? bne ShutDownOne ; Nope, do it normally PushWord AppMMID _DisposeAll PushWord AppMMID lda #$2 ; set up for toolset #2 (MM) ShutDownOne ora #$300 ; Call #3 (Shutdown) tax jsl $E10000 dec ToolList bne ShutDownTools rts * * Main - main sequence of events * Main jsr StartUpTools jsr PrepDeskTop sep $20 ldal $e0c034 sta ScreenColorByte lda #00 stal $e0c034 rep $30 * pretty corner rounding PushWord #0000 _SetForeColor * upper left PushWord #0001 PushWord #0000 _MoveTo PushWord #0001 PushWord #0002 _LineTo PushWord #0002 PushWord #0000 _MoveTo PushWord #0002 PushWord #0001 _LineTo PushWord #0003 PushWord #0000 _MoveTo PushWord #0003 PushWord #0000 _LineTo * upper right PushWord #0638 PushWord #0000 _MoveTo PushWord #0638 PushWord #0002 _LineTo PushWord #0637 PushWord #0000 _MoveTo PushWord #0637 PushWord #0001 _LineTo * lower left PushWord #0000 PushWord #0195 _MoveTo PushWord #0000 PushWord #0199 _LineTo PushWord #0001 PushWord #0197 _MoveTo PushWord #0001 PushWord #0199 _LineTo PushWord #0002 PushWord #0199 _MoveTo PushWord #0002 PushWord #0199 _LineTo * lower right PushWord #0639 PushWord #0195 _MoveTo PushWord #0639 PushWord #0199 _LineTo PushWord #0638 PushWord #0197 _MoveTo PushWord #0638 PushWord #0199 _LineTo PushWord #0637 PushWord #0199 _MoveTo PushWord #0637 PushWord #0199 _LineTo EventLoop pha ; Result Space PushWord #$ffff ; Event Mask PushLong #EventRec _TaskMaster pla beq EventLoop cmp #$11 ; wInMenuBar? bne EventLoop ; no, so ignore jsr MenuDispatch bit QuitFlag bpl EventLoop sep $20 lda ScreenColorByte stal $e0c034 rep $30 jsr ShutDownTools iGSOS _Quit;QParams;1 * * Prepare Desktop * PrepDeskTop PushLong #0000 _RefreshDesktop _InitCursor NextMenu pha pha lda MenuTbl asl tax lda MenuTbl,x phb phb pha _NewMenu PushWord #0000 _InsertMenu dec MenuTbl bne NextMenu PushWord #1 _FixAppleMenu pha _FixMenuBar pla _DrawMenuBar rts * * Apple Menu: About * About PushLong #AboutString jsr InfoDialog rts * * File Menu: Quit * Quit dec QuitFlag rts * * TCP/IP Test * TCPIPTest pha PushWord #0000 _TCPIPGetConnectStatus pla cmp #$0000 bne tgood PushLong #MarinettiBad jsr InfoDialog bra tret tgood PushLong #MarinettiGood jsr InfoDialog tret pla rts * * Connect To Server * ConnectToSvr PushLong #$00000000 ; space for result PushLong #CTSRect _GetNewModalDialog PullLong CTSWinPtr PushLong CTSWinPtr _BeginUpdate PushLong CTSWinPtr _DrawDialog PushLong CTSWinPtr _EndUpdate PushLong #00000000 _TCPIPConnect ; make sure marinetti is connected PushLong #00000000 _TCPIPGetMyIPAddress plx ply PushWord #0000 phy phx PushLong #ascaddr PushWord #0000 _TCPIPConvertIPToASCII ; convert our address to ASCII pla PushLong CTSWinPtr PushWord #1360 PushLong #ascaddr _SetIText ; show it CTSLoop1 PushWord #0000 ; space for result PushLong #00000000 ; nil filter _ModalDialog pla ; get item hit cmp #2 ; Cancel? beq CTSClose cmp #1 ; Connect? bne CTSLoop1 bra CTSConnect CTSClose PushLong CTSWinPtr _CloseDialog rts CTSConnect PushLong #00000000 PushLong CTSWinPtr PushWord #0001 _GetControlDItem plx ply PushWord #255 phy phx _HiliteControl ; dim/disable 'Connect' button PushLong #00000000 PushLong CTSWinPtr PushWord #1349 _GetControlDItem plx ply PushWord #255 phy phx _HiliteControl ; dim/disable 'Address' text input PushLong CTSWinPtr PushWord #1349 PushLong #fqdnptr _GetIText PushWord CTSText4 ; preserve old length byte (word) sep #$30 mx %11 lda fqdnptr tax clc adc CTSText4 sta CTSText4 hostcopy lda fqdnptr,x sta inhost-1,x dex bne hostcopy rep #$30 mx %00 PushLong CTSWinPtr PushWord #1350 PushLong #CTSText4 _SetIText ; show 'resolving' status string pla sta CTSText4 PushWord #0000 PushWord #$F800 PushLong #fqdnptr _TCPIPMangleDomainName ; mangle entered domain name pla ; port number; trash PushWord #0000 PushLong #fqdnptr _TCPIPValidateIPString pla beq resolve ; engage DNS if this wasn't an ip address PushLong #ipaddrip PushLong #fqdnptr _TCPIPConvertIPToHex ; else just convert to long bra Connect ; and on with the show resolve PushLong #fqdnptr PushLong #ipaddr _TCPIPDNRNameToIP ; resolve fqdn ResolvLoop PushWord #0000 ; check for mouse events (cancel) PushWord #$0006 ; with _EventAvail PushLong #EventRec ; because _ModalDialog will block _EventAvail pla beq noevent PushWord #0000 PushLong #00000000 _ModalDialog pla cmp #2 beq CTSClose2 noevent _TCPIPPoll lda ipaddr cmp #$0001 beq Connect ; continue to Connect if resolved okay cmp #$0000 beq ResolvLoop ; pending; stay in 'Resolving' loop bra CTSBadDNS CTSClose2 PushLong CTSWinPtr _CloseDialog rts CTSBadDNS PushLong CTSWinPtr PushWord #1350 PushLong #CTSText5 _SetIText bra CTSClose2 Connect PushWord #0000 PushLong ipaddrip PushLong #destaddr PushWord #0000 _TCPIPConvertIPToASCII pla PushWord CTSText6 ; preserve old length byte (word) sep #$30 mx %11 lda destaddr tax clc adc CTSText6 sta CTSText6 ipcopy lda destaddr,x sta ascdest-1,x dex bne ipcopy rep #$30 mx %00 PushLong CTSWinPtr PushWord #1350 PushLong #CTSText6 _SetIText ; change status to 'Connecting' pla sta CTSText6 ; restore length byte PushWord #0000 ; space for result PushWord AppMMID ; our Memory Manager handle PushLong ipaddrip ; ipaddress to connect to PushWord #0445 ; try port 445 first PushWord #0000 ; default TOS: 0000 PushWord #$0040 ; default TTL: 64 _TCPIPLogin pla sta MyIPID PushWord #$0000 PushWord MyIPID _TCPIPOpenTCP pla beq ConnectLoop jmp CTSClose3 ConnectLoop PushWord #0000 PushWord #$0006 PushLong #EventRec _EventAvail pla beq noevent2 PushWord #0000 ; space for result PushLong #00000000 ; nil filter procedure _ModalDialog pla cmp #2 bne noevent2 jmp CTSClose3 noevent2 _TCPIPPoll PushWord #0000 PushWord MyIPID PushLong #statbuf _TCPIPStatusTCP pla beq notbroke jmp CTSClose3 ; something broke notbroke lda statbuf cmp #$0004 beq estab cmp #$0000 beq closed_trampoline bra ConnectLoop ; ; SMB_Negot_Prot ; estab PushLong CTSWinPtr PushWord #1350 PushLong #CTSText9 _SetIText PushLong MyIPID jsr SMB_Init ; feed our Marinetti IPID into SMB system PullLong MySMBHandle ; get back our SMB handle PushLong MySMBHandle ; SMB_Negotiate wants our SMB handle jsr SMB_Negotiate ; and hopefully we send a SMB Negotiate Protocol Request and get a response bra ct_far closed_trampoline jmp closed ct_far sendloop2 PushWord #0000 PushWord #$0006 PushLong #EventRec _EventAvail pla beq noevent3 PushWord #0000 PushLong #00000000 _ModalDialog pla cmp #2 bne noevent3 jmp CTSClose3 noevent3 PushLong MySMBHandle jsr SMB_Negotiate_Poll pla ; get negotiation status bcc sendloop2 ; ; SMB_Setup_ANDX ; login PushLong CTSWinPtr PushWord #1350 PushLong #CTSTextB _SetIText PushLong MySMBHandle jsr SMB_SetupAndX sendloop3 PushWord #0000 PushWord #$0006 PushLong #EventRec _EventAvail pla beq noevent4 PushWord #0000 PushLong #00000000 _ModalDialog pla cmp #2 bne noevent4 jmp CTSClose3 noevent4 PushLong MySMBHandle jsr SMB_Setup_Poll pla ; get negotiation status bcc sendloop3 ; ; SMB_Tree_ANDX ; ; fun fact: change 'treex' to 'tree' to coredump Merlin32 v1.0 ; inside a65816_Line.c function CheckForDuplicatedLabel() treex PushLong CTSWinPtr PushWord #1350 PushLong #CTSTextC _SetIText PushLong MySMBHandle jsr SMB_TreeAndX sendloop4 PushWord #0000 PushWord #$0006 PushLong #EventRec _EventAvail pla beq noevent5 PushWord #0000 PushLong #00000000 _ModalDialog pla cmp #2 bne noevent5 jmp CTSClose3 noevent5 PushLong MySMBHandle jsr SMB_TreeX_Poll pla bcc sendloop4 ; ; SMB_OpenFile ; openf PushLong CTSWinPtr PushWord #1350 PushLong #CTSTextC _SetIText PushLong MySMBHandle PushLong #SMB_target_file jsr SMB_OpenFile sendloop5 PushWord #0000 PushWord #$0006 PushLong #EventRec _EventAvail pla beq noevent6 PushWord #0000 PushLong #00000000 _ModalDialog pla cmp #2 bne noevent6 jmp CTSClose3 noevent6 PushLong MySMBHandle jsr SMB_OpenFile_Poll bcc sendloop5 tax pla phx ; save SFID ; ; SMB_ReadFile ; readf PushLong CTSWinPtr PushWord #1350 PushLong #CTSTextD _SetIText ; SFID already on stack still PushLong MySMBHandle PushLong #$E12000 ; read buffer = SHR screen PushLong #$8000 ; size of read buffer PushLong #0000 ; offset into file jsr SMB_ReadFile sendloop6 PushWord #0000 PushWord #$0006 PushLong #EventRec _EventAvail pla beq noevent7 PushWord #0000 PushLong #00000000 _ModalDialog pla cmp #2 bne noevent7 jmp CTSClose3 noevent7 PushLong MySMBHandle jsr SMB_ReadFile_Poll bcc sendloop6 ; ; Display what was downloaded ; ; squish length byte a little closer to the string lda SMB_input+SMB_header_size+25 xba sta SMB_input+SMB_header_size+25 PushLong #SMB_input+SMB_header_size+26 jsr InfoDialog jmp SMB_staging_brk ; ; Closed ; closed PushLong CTSWinPtr PushWord #1350 PushLong #CTSTextA _SetIText ; ; Kill dialog window and TCPIP connection ; CTSClose3 PushWord #MyIPID _TCPIPLogout ; get rid of our IPID PushLong CTSWinPtr ; and close the dialog window _CloseDialog rts * * Menu Dispatcher * MenuDispatch lda TaskData and #$00ff asl tax jsr (MenuDispatchTbl,x) PushWord #0000 PushWord TaskData+2 _HiliteMenu rts * * Information Dialog * InfoDialog plx ; preserve return address PullLong dialogMsg phx ; put return back on stack pha ; room for result PushLong #OurAlert ; pointer to dialog PushLong #$0000 _NoteAlert pla ; get the item selected rts * * Non-DP Variables * QuitFlag dw 00,00 ScreenColorByte dw 00 MyIPID dw 00 ; Marinetti IPID MySMBHandle dw 00,00 ; SMB driver handle CTSWinPtr dw 00,00 ; Connect To Server grafport ptr fqdnptr ds 101 ; 101 bytes for user-entered hostname ipaddr dw 00 ; DNS resolution status ipaddrip dw 00,00 ; Resolved IP address ascaddr ds 16 ; My IP address, in ASCII destaddr ds 16 ; Destination IP address, in ASCII statbuf ds 2 ; TCP state, statbuf+0 ds 2 ; ICMP error code, statbuf+2 ds 4 ; sendq size, statbuf+4 ds 4 ; recvq size, statbuf+8 ds 4 ; dest ip ds 2 ; dest port ds 2 ; connection type ds 2 ; accept count readbuf ds 4 ; rrBuffCount ds 4 ; rrBuffHandle ds 2 ; rrMoreFlag ds 2 ; rrPushFlag ds 2 ; rrUrgentFlag * * Tool List * ToolList dw 15 ; Tool Count dw 01,00 ; Tool Locator, any vers dw 02,00 ; Memory Manager, any vers dw 03,00 ; Misc Tools, any vers dw 04,00 ; QuickDraw II, any vers dw 06,00 ; Event Manager, any vers dw 14,00 ; Window Manager, any vers dw 16,00 ; Control Manager, any vers dw 15,00 ; Menu Manager, any vers dw 05,00 ; Desk Manager, any vers dw 08,00 ; Sound Manager, any vers dw 20,00 ; Line Edit, any vers dw 21,00 ; Dialog Manager, any vers dw 54,00 ; Marinetti, any vers dw 128,00 ; HashTool, any vers (MD2/MD4/MD5/SHA1 hashing for NTLMv2) dw 129,00 ; Crypto tool, any vers (DES for NTLMv1) ToolListEnd * * Menu Structures * MenuDispatchTbl dw About dw Quit dw TCPIPTest dw ConnectToSvr MenuTbl dw 4 ; count dw Menu1 dw Menu2 dw Menu3 dw Menu4 MenuTblEnd Menu1 asc '>>@\XN1'00 asc '--About This Program...\N256*??'00 asc '---\D'00 asc '>' Menu2 asc '>> File \N2'00 asc '--Quit\N257*Qq'00 asc '>' Menu3 asc '>> Edit \N3D'00 asc '--Undo\N250V*Zz'00 asc '--Cut\N251*Xx'00 asc '--Copy\N252*Cc'00 asc '--Paste\N253V*Vv'00 asc '--Clear\N254'00 asc '>' Menu4 asc '>> Test \N4'00 asc '--TCP/IP Test\N258*Tt'00 asc '--Connect to Server\N259*Uu'00 asc '>' * * Event Record * EventRec Event_What ds 2 Event_Msg ds 4 Event_When ds 4 Event_Where ds 4 Event_Mods ds 2 TaskData ds 4 TaskMask dw $1fff,$0000 * * Strings * OneMoment asc 'One Moment Please...'00 MarinettiGood str 'Marinetti is Up.' MarinettiBad str 'Marinetti is Not Up.' AboutString str 'TCPIP Test Program' But1 str 'OK' * * Connect To Server Dialog * CTSRect dw 30,120,120,520 ; bounds rect CTSVis dw 0001 ; visible CTSRef dw 0000,0000 ; refcon CTSiptr1 adrl CTSItem1 ; string 'Host To Connect To' CTSiptr2 adrl CTSItem2 ; edit line CTSiptr3 adrl CTSItem3 ; connect button CTSiptr4 adrl CTSItem4 ; cancel button CTSiptr5 adrl CTSItem5 ; status line CTSiptr6 adrl CTSItem6 ; My IP Address CTSiptr7 adrl CTSItem7 ; "My Ip Address: " dw 0000 ; end of the line CTSItem1 dw 1348 ; id dw 5,10,15,300 ; bounds dw statText+$8000 ; type + disabled adrl CTSText1 dw 00 ; item value dw 00 ; item flag adrl 00 ; end CTSText1 str 'Address Of CIFS Server To Connect To:' CTSItem2 dw 1349 ; id dw 25,10,38,200 ; bounds dw editLine adrl CTSText2 dw 100 dw 00 adrl 00 CTSText2 str 'example.com' CTSItem3 dw 1 dw 50,10,60,100 dw buttonItem adrl But2 dw 00 dw 00 adrl 00 But2 str 'Connect' CTSItem4 dw 2 dw 50,111,60,210 dw buttonItem adrl But3 dw 00 dw 00 adrl 00 But3 str 'Cancel' CTSItem5 dw 1350 ; id dw 65,10,75,300 ; bounds dw statText+$8000 ; type + disabled adrl CTSText3 dw 00 dw 00 adrl 00 CTSText3 str 'Status: Awaiting Input' CTSText4 str 'Status: Resolving Hostname ' inhost ds 101 CTSText5 str 'Status: Resolution Failure' CTSText6 str 'Status: Connecting to ' ascdest ds 20 CTSText9 str 'Status: Connected, CIFS negotiating' CTSTextA str 'Status: Connect Failed' CTSTextB str 'Status: Logging In' CTSTextC str 'Status: Mounting Share' CTSTextD str 'Status: Opening \\testfile' CTSTextE str 'Status: Reading testfile' ascdata ds 100 ; we download this from testfile CTSItem6 dw 1360 ; id dw 77,120,87,300 ; bounds dw statText+$8000 adrl CTSText7 dw 00 dw 00 adrl 00 CTSText7 str '0.0.0.0' CTSItem7 dw 1361 ; id dw 77,10,87,120 ; bounds dw statText+$8000 adrl CTSText8 dw 00 dw 00 adrl 00 CTSText8 str 'My IP Address:' * * TCPIP Test Output Dialog * OurAlert dw 30,120,80,520 ; bounds rect dw 2374 ; id db $80 db $80 db $80 db $80 adrl item1 adrl item2 adrl 00 item1 dw 1 ; id dw 25,320,0,0 ; bounds rect for button dw buttonItem ; type adrl But1 ; item descriptor dw 00 ; item value dw 00 ; item flag adrl 00 ; item color item2 dw 1348 ; id dw 11,72,200,640 ; bounds rect for message dw statText+$8000 ; type + disabled dialogMsg adrl MarinettiGood ; item descriptor dw 00 ; item value dw 00 ; item flag adrl 00 ; item color * * GS/OS Quit Params * QParams ds 4 ds 4 *** CIFS / SMB internals only past this point (will eventually be its own linker segment) * * SMB equates (should move into Library/E16.CIFS.Macs.s eventually) * * offsets into SMB header SMB_offset_tcplength = 1 ; tcp length: all dgram length including header SMB_offset_proto = 0+4 SMB_offset_cmd = 4+4 SMB_offset_ntstatus = 5+4 SMB_offset_eclass = 5+4 SMB_offset_flags = 9+4 SMB_offset_flags2 = 10+4 SMB_offset_extra = 12+4 SMB_offset_tid = 24+4 SMB_offset_pid = 26+4 SMB_offset_uid = 28+4 SMB_offset_mid = 30+4 SMB_header_size = 32+4 ; SMB headers are always 32 bytes long * message / commands NBT_session_msg = 00 SMB_neg_protocol = $72 SMB_setup_ANDX = $73 SMB_treec_ANDX = $75 * keepalive NBT_keepalive_msg = $85 keepalive_size = 4 * SMBTrans2 SMB_trans2 = $32 SMB_open2 = 0 SMB_find_first2 = 1 SMB_find_next2 = 2 SMB_query_fs_info = 3 SMB_query_path_info = 5 SMB_set_path_info = 6 SMB_query_file_info = 7 SMB_set_file_info = 8 SMB_create_dir = 13 SMB_find_close2 = $34 SMB_query_file_all_info = $107 * File I/O SMB_open_ANDX = $2d SMB_write_ANDX = $2f SMB_read_ANDX = $2e SMB_close = $04 * SMB_COM SMB_COM_create_directory = $00 SMB_COM_delete_directory = $01 SMB_COM_delete = $06 SMB_COM_rename = $07 SMB_COM_query_information_disk = $80 * TRANS2 offsets T2_word_cnt = SMB_header_size T2_prm_cnt = T2_word_cnt+1 T2_data_cnt = T2_prm_cnt+2 T2_maxprm_cnt = T2_data_cnt+2 T2_maxbuffer = T2_maxprm_cnt+2 T2_setup_cnt = T2_maxbuffer+2 T2_sprm_cnt = T2_setup_cnt+10 T2_sprm_ofs = T2_sprm_cnt+2 T2_sdata_cnt = T2_sprm_ofs+2 T2_sdata_ofs = T2_sdata_cnd+2 T2_ssetup_cnt = T2_sdata_ofs+2 T2_sub_cmd = T2_ssetup_cnt+2 T2_byte_cnt = T2_sub_cmd+2 SMB_proto1 = $53ff ; $ff + 'S' SMB_proto2 = $424d ; 'MB' SMB_max_net_read_size = 16384 SMB_max_net_write_size = 4096 SMB_max_transmit_size = 16384 CAP_large_files = $00000008 ; 64-bit file sizes and offsets supported CAP_unicode = $00000004 ; unicode supported CIFS_flags1 = $08 ; paths are caseless CIFS_flags2_unicode = $8001 ; server may return long components in paths in the response - Unicode supported CIFS_flags2 = $0001 ; server may return long components in paths in the response - ASCII supported SMB_connhandles_max = 8 SMB_filehandles_max = (32*SMB_connhandles_max) SMB_objtype_handle = 7 * NBT session service packet type codes SESS_msg = $0 SESS_req = $81 SESS_pos_resp = $82 SESS_neg_resp = $83 SESS_retarget = $84 SESS_keepalive = $85 SMB_maxpath = 4096 * SMB error codes SMB_success = 0 SMB_error = $ffff ; -1 SMB_bad_protocol = $fffe ; -2 SMB_bad_command = $fffd ; -3 SMB_proto_fail = $fffc ; -4 SMB_not_user = $fffb ; -5 SMB_bad_keylen = $fffa ; -6 SMB_bad_datalen = $fff9 ; -7 SMB_bad_logindata = $fff8 ; -8 * SMB file open function SMB_of_open = 1 SMB_of_truncate = 2 SMB_of_create = 16 * FileSearch SMB_srch_readonly = 1 SMB_srch_hidden = 2 SMB_srch_system = 4 SMB_srch_volume = 8 SMB_srch_directory = 16 SMB_srch_archive = 32 * SMB file access modes SMB_open_reading = 0 SMB_open_writing = 1 SMB_open_readwrite = 2 SMB_open_compatible = 0 SMB_deny_readwrite = $10 SMB_deny_write = $20 SMB_deny_read = $30 SMB_deny_none = $40 * * SMB variable space * * SMB DP variables SMB_sessid = 8 SMB_tmp1 = 12 SMB_tmp2 = 14 SMB_tmp3 = 16 SMB_tmp4 = 18 SMB_tmp5 = 20 SMB_tmp6 = 22 SMB_tmp7 = 24 SMB_tmp8 = 26 * SMB session information * TODO dynamically allocate these - see SMB_Init SMB_sess_begin SMB_sess_ipid dw 0 ; Marinetti IPID SMB_sess_tid dw 0 ; SMB TID SMB_sess_pid dw $dead ; SMB PID SMB_sess_uid dw 0 ; SMB UID SMB_sess_mid dw $0001 ; SMB MID SMB_sess_skey dw 0,0 ; sKey SMB_sess_caps dw 0,0 ; capabilities SMB_sess_maxbuffer dw 0,0 ; max buffer SMB_sess_seclvl dw 0 ; server security level SMB_sess_maxmpx dw 0 ; server max pending outstanding requests SMB_sess_maxvcs dw 0 ; server max virtual circuits SMB_sess_challenge_used dw 0 ; challenge Used? SMB_sess_challenge dw 0,0,0,0 ; challenge SMB_sess_domain ds 32 ; sloppy 32 byte buffer to hold SMB domain * Strings SMB_dialect asc 02'NT LM 0.12'00 ; the only dialect we're gonna speak SMB_os asc 'GS/OS'00 ; native Operating System SMB_lanman asc 'Apple IIgs'00 ; native LAN Manager SMB_lm_username asc 'PI'00,00,00,00,00,00,00,00,00,00,00,00 ; lanman hash login username SMB_lm_password asc 'APPLE2'00,00,00,00,00,00,00,00 ; lanman hash login password SMB_lm_magic asc 'KGS!@#$%' ; lanman hash magic DES crypt string SMB_lm_hash ds 21 ; LM Hash, actually 16 bytes but the extra zeroes make response easier to generate SMB_lm_response ds 24 ; LM Response SMB_target_tree asc '\\LIVINGROOM\GSFILES'00 ; remote tree to connect to SMB_target_svc asc '?????'00 ; service type (wildcard) SMB_target_file asc '\TESTFILE'00 ; file to download * SMB packet staging area * TODO these will probably be dynamically allocated too? * also SMB_max_transmit size should go up to 65535 and use an allocated bank like Marinetti does SMB_staging_brk brk 00 ; jump here to crash somewhere where you can easily inspect the generated SMB datagram SMB_staging ds SMB_max_transmit_size+2 SMB_input_brk brk 00 SMB_input ds SMB_max_net_read_size ; TODO Memory Manage this eh * * SMB Subroutines * * SMB_Init - Call me to tell me about your Marinetti IPID and get a session handle returned for future SMB calls * Arguments: * Marinetti IPID (one word, on stack) * Returns: * SMB session handle (two words, on stack) * Carry flag set if error * TODO: make this support multiple sessions in the future SMB_Init plx ; return address pla sta SMB_sess_ipid PushLong #SMB_sess_begin phx ; saved return address clc rts * SMB_Negotiate - Call me when you've opened a TCPIP connection and want to perform Negotiate Protocol Request * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_Negotiate plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_neg_protocol ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information sep $30 mx %11 ldy #0 ldx #0 dialect_copy lda SMB_dialect,x ; 8-bit copy of dialect string into SMB staging area beq dialect_done sta SMB_staging+SMB_header_size+3,x inx iny bra dialect_copy dialect_done sta SMB_staging+SMB_header_size+3,x ; do write the trailing zero inx iny rep $30 mx %00 tya sta SMB_staging+SMB_header_size+1 ; save byte count clc adc #SMB_header_size+3 pha ; 'length' parameter for _SMB_Send dec dec dec dec xba sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram jsr _SMB_Send clc rts * SMB_Negotiate_Poll - Call me until I tell you to stop, to receive and complete SMB negotiation * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Negotiation status (word) * $0000 - Negotiation proceeding * $0001 - Negotiation finished * $0002 - Negotiation failed * Carry flag set means you can stop calling me SMB_Negotiate_Poll plx ; our return address PullLong SMB_sessid ; your smb sessid phx _TCPIPPoll PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushLong #statbuf _TCPIPStatusTCP ; see if marinetti has anything for us pla cmp #terrNOCONNECTION beq nf_trampoline cmp #terrBADIPID beq nf_trampoline lda statbuf+8 ; get recvq size, low word cmp #0000 ; yeah i know. for clarity. beq np_trampoline ; poll us again later, marinetti got nothing PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushWord #0000 ; bufftype: static pre-allocated buffer PushLong #SMB_input ; where it's all goin PushLong #SMB_max_net_read_size PushLong #readbuf _TCPIPReadTCP pla cmp #terrNOCONNECTION beq nf_trampoline cmp #terrBADIPID beq nf_trampoline jsr _SMB_Check ; do basic check to make sure we received SMB data bcs np_trampoline ; if not, wait for them to send again i guess ` lda SMB_input+SMB_offset_cmd cmp #SMB_neg_protocol bne np_trampoline ; punt if not protocol negotiation reply lda SMB_input+SMB_offset_eclass cmp #0000 bne nf_trampoline ; they returned an error, kbye lda SMB_input+SMB_header_size and #$ff cmp #17 bne nf_trampoline ; they should always return 17 words lda SMB_input+SMB_header_size xba and #$ff cmp #00 bne nf_trampoline ; they should always select dialect 0 bra nft_far nf_trampoline jmp nego_failed np_trampoline jmp nego_proceeding nft_far lda SMB_input+SMB_header_size+3 and #$01 ldy #SMB_sess_seclvl-SMB_sess_begin sta [SMB_sessid],y ; save session security level (1=user level, 0=share level) lda SMB_input+SMB_header_size+4 and #$ff ldy #SMB_sess_maxmpx-SMB_sess_begin sta [SMB_sessid],y ; save session MaxMPX lda SMB_input+SMB_header_size+6 and #$ff ldy #SMB_sess_maxvcs-SMB_sess_begin sta [SMB_sessid],y ; save session MaxVCS lda SMB_input+SMB_header_size+8 ldy #SMB_sess_maxbuffer-SMB_sess_begin sta [SMB_sessid],y ; save session maxbuffer lda SMB_input+SMB_header_size+16 ldy #SMB_sess_skey-SMB_sess_begin sta [SMB_sessid],y ; save skey lda SMB_input+SMB_header_size+20 ldy #SMB_sess_caps-SMB_sess_begin sta [SMB_sessid],y iny iny lda SMB_input+SMB_header_size+22 sta [SMB_sessid],y ; save server capabilities ; TODO serverTime lda SMB_input+SMB_header_size+33 and #$ff cmp #8 bne challenge_used cmp #0 bne nego_failed ; should be either 8 or zero lda #$0000 ldy #SMB_sess_challenge_used sta [SMB_sessid],y bra getdomain challenge_used lda #$0001 ldy #SMB_sess_challenge_used-SMB_sess_begin sta [SMB_sessid],y lda SMB_input+SMB_header_size+37 ldy #SMB_sess_challenge-SMB_sess_begin sta [SMB_sessid],y iny iny lda SMB_input+SMB_header_size+39 sta [SMB_sessid],y iny iny lda SMB_input+SMB_header_size+41 sta [SMB_sessid],y iny iny lda SMB_input+SMB_header_size+43 sta [SMB_sessid],y ; save 8-byte challenge getdomain ldy #SMB_sess_domain-SMB_sess_begin ldx #00 gdloop lda SMB_input+SMB_header_size+45,x and #$00ff cmp #0000 beq eod sta [SMB_sessid],y ; if this looks off to you, see how iny ; the domain name is actually encoded inx ; W\00O\00R\00K\00G\00R\00O\00U\00P\00 inx bra gdloop eod sta [SMB_sessid],y ; save terminating zero nego_finished plx ; our return address PushWord #0001 ; finished! phx sec rts nego_failed plx ; our return address PushWord #0002 ; failure phx sec rts nego_proceeding plx ; our return address PushWord #0000 ; in progress phx clc rts * * SMB_SetupAndX - Next step after negotiating protocol, includes authentication * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_SetupAndX plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_setup_ANDX ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information sep $30 mx %11 lda #13 sta SMB_staging+SMB_header_size ; word count lda #$ff sta SMB_staging+SMB_header_size+1 ; next AndX lda #00 sta SMB_staging+SMB_header_size+2 ; reserved rep $30 mx %00 ldy #SMB_sess_maxbuffer-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_header_size+5 ; max buffer size ldy #SMB_sess_maxmpx-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_header_size+7 ; max MPX ldy #SMB_sess_maxvcs-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_header_size+9 ; max VCS ldy #SMB_sess_skey-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_header_size+11 ; session key lda #0 sta SMB_staging+SMB_header_size+13 ; session key (upper, should always be zero?) lda #24 sta SMB_staging+SMB_header_size+15 ; password length (case insensitive) lda #0 sta SMB_staging+SMB_header_size+17 ; password length (case sensitive/NTLM) lda #0 sta SMB_staging+SMB_header_size+19 ; reserved sta SMB_staging+SMB_header_size+21 ; reserved ldy #SMB_sess_caps-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_header_size+23 iny iny lda [SMB_sessid],y sta SMB_staging+SMB_header_size+25 ; session capabilities jsr SMB_LM_Hash ; generate NTLMv1 Hash jsr SMB_LM_Response ; generate NTLMv1 Response lda #0 sta SMB_tmp5 ; initialize pointer ; Case Insensitive Password (LM Response) PushLong #SMB_lm_response ; source pea #^SMB_staging lda #SMB_staging+SMB_header_size+29 clc adc SMB_tmp5 pha ldx #24 jsr _strncpy lda #24 clc adc SMB_tmp5 sta SMB_tmp5 ; Case Sensitive Password (NTLM Response) clc adc #24 sta SMB_tmp5 ; skip it / zero it for now ; Account PushLong #SMB_lm_username ; source pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+29 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 ; Domain PushLong #SMB_sess_domain ; source pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+29 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 ; OS PushLong #SMB_os ; source pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+29 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 ; LanMan PushLong #SMB_lanman pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+29 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 sta SMB_staging+SMB_header_size+27 ; update byte count clc adc #SMB_header_size+29 pha ; 'length' parameter for _SMB_Send dec dec dec dec xba sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram jsr _SMB_Send ; send our reply! clc rts * SMB_LM_Hash - operate on the SMB_lm_username and SMB_lm_password values to produce * SMB_lm_hash, using V1 DES-based operation. Requires TOOL129 (Crypto Tool) * * The password has been uppercased and chopped to 14 bytes, with 0x00 padding * We take it in two 7-byte pieces, add parity, and use each piece to DES-encrypt the string * 'KGS!@#$%'. The result is the LM hash. SMB_LM_Hash PushLong #SMB_tmp1 ; SMB_tmp1 will have our parity-enhanced key PushLong #SMB_lm_password ; key to add parity to Tool $0A81 ; DESAddParity PushLong #SMB_lm_hash ; where DES-encrypted data will go PushLong #SMB_tmp1 ; parity-enhanced key PushLong #SMB_lm_magic ; the magic string we're encrypting PushWord #0000 ; operation: encrypt Tool $0981 ; DESCipher ; now do the same thing with the second 7 bytes of the password PushLong #SMB_tmp1 PushLong #SMB_lm_password+7 Tool $0A81 ; DesAddParity PushLong #SMB_lm_hash+8 PushLong #SMB_tmp1 PushLong #SMB_lm_magic PushWord #0000 Tool $0981 ; SMB_lm_hash should now contain the NTLMv1 hash of the password clc rts * SMB_LM_Response - operate on SMB_lm_hash and 8-byte challenge to produce * SMB_lm_response, using V1 DES-based operation. Requires TOOL129 (Crypto Tool) * * LM Hash is padded out to 21 bytes, each of which gets parity added and is * used to DES encrypt the session challenge. The result is the LM response. SMB_LM_Response PushLong #SMB_tmp1 ; SMB_tmp1 will have our parity-enhanced key PushLong #SMB_lm_hash ; key to add parity to Tool $0A81 ; DESAddParity PushLong #SMB_lm_response ; where the DES-encrypted data will go PushLong #SMB_tmp1 ; parity-enhanced key ldy #SMB_sess_challenge-SMB_sess_begin lda [SMB_sessid],y ; PushLong [SMB_sessid],y pha iny iny lda [SMB_sessid],y pha PushWord #0000 ; operation: encrypt Tool $0981 ; DESCipher ; second 7 bytes of hash PushLong #SMB_tmp1 PushLong #SMB_lm_hash+7 Tool $0A81 ; DESAddParity PushLong #SMB_lm_response+8 PushLong #SMB_tmp1 ldy #SMB_sess_challenge-SMB_sess_begin lda [SMB_sessid],y ; PushLong [SMB_sessid],y pha iny iny lda [SMB_sessid],y pha PushWord #0000 Tool $0981 ; DESCipher ; third 7 bytes of hash PushLong #SMB_tmp1 PushLong #SMB_lm_hash+14 Tool $0A81 ; DesAddParity PushLong #SMB_lm_response+16 PushLong #SMB_tmp1 ldy #SMB_sess_challenge-SMB_sess_begin lda [SMB_sessid],y pha iny iny lda [SMB_sessid],y pha PushWord #0000 Tool $0981 ; DESCipher clc rts * SMB_Setup_Poll - Call me until I tell you to stop, to receive and complete SMB setup * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Setup status (word) * $0000 - Setup proceeding * $0001 - Setup finished * $0002 - Setup failed * Carry flag set means you can stop calling me SMB_Setup_Poll plx ; our return address PullLong SMB_sessid ; your smb sessid phx _TCPIPPoll PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushLong #statbuf _TCPIPStatusTCP ; see if marinetti has anything for us pla cmp #terrNOCONNECTION beq sf_trampoline cmp #terrBADIPID beq sf_trampoline lda statbuf+8 ; get recvq size, low word cmp #0000 ; yeah i know. for clarity. beq sp_trampoline ; poll us again later, marinetti got nothing PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushWord #0000 ; bufftype: static pre-allocated buffer PushLong #SMB_input ; where it's all goin PushLong #SMB_max_net_read_size PushLong #readbuf _TCPIPReadTCP pla cmp #terrNOCONNECTION beq sf_trampoline cmp #terrBADIPID beq sf_trampoline jsr _SMB_Check ; do basic check to make sure we received SMB data bcs sp_trampoline ; if not, wait for them to send again i guess bra sft_far sf_trampoline jmp setup_failed sp_trampoline jmp setup_proceeding sft_far lda SMB_input+SMB_offset_cmd cmp #SMB_setup_ANDX bne sp_trampoline ; punt if not setup_ANDX reply lda SMB_input+SMB_offset_eclass cmp #0000 bne sf_trampoline ; they returned an error, kbye lda SMB_input+SMB_offset_uid ldy #SMB_sess_uid-SMB_sess_begin sta [SMB_sessid],y ; save returned UID * TODO save far end's OS, Lan Manager, and Workgroup? setup_finished plx ; our return address PushWord #0001 ; finished! phx sec rts setup_failed plx ; our return address PushWord #0002 ; failure phx sec rts setup_proceeding plx ; our return address PushWord #0000 ; in progress phx clc rts * * SMB_TreeAndX - Connect to the remote share * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_TreeAndX plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_treec_ANDX ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information sep $30 mx %11 lda #4 sta SMB_staging+SMB_header_size ; word count lda #$ff sta SMB_staging+SMB_header_size+1 ; next AndX rep $30 mx %00 lda #0000 sta SMB_staging+SMB_header_size+3 ; reserved lda #0000 sta SMB_staging+SMB_header_size+5 ; flags lda #1 sta SMB_staging+SMB_header_size+7 ; password length (1 if user-level security) lda #0 sta SMB_tmp5 ; initialize pointer ; Share password lda #00 sta SMB_staging+SMB_header_size+11 ; 0x00 (nul password, no share level security) inc SMB_tmp5 ; Target Tree PushLong #SMB_target_tree pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+11 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 ; Target Service Type PushLong #SMB_target_svc pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+11 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 sta SMB_staging+SMB_header_size+9 ; update byte count clc adc #SMB_header_size+11 pha ; 'length' parameter for _SMB_Send dec dec dec dec xba sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram jsr _SMB_Send ; send our reply! clc rts * SMB_TreeX_Poll - Call me until I tell you to stop, to receive and complete SMB Tree_ANDX * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Setup status (word) * $0000 - Setup proceeding * $0001 - Setup finished * $0002 - Setup failed * Carry flag set means you can stop calling me SMB_TreeX_Poll plx ; our return address PullLong SMB_sessid ; your smb sessid phx _TCPIPPoll PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushLong #statbuf _TCPIPStatusTCP ; see if marinetti has anything for us pla cmp #terrNOCONNECTION beq tf_trampoline cmp #terrBADIPID beq tf_trampoline lda statbuf+8 ; get recvq size, low word cmp #0000 ; yeah i know. for clarity. beq tp_trampoline ; poll us again later, marinetti got nothing PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushWord #0000 ; bufftype: static pre-allocated buffer PushLong #SMB_input ; where it's all goin PushLong #SMB_max_net_read_size PushLong #readbuf _TCPIPReadTCP pla cmp #terrNOCONNECTION beq tf_trampoline cmp #terrBADIPID beq tf_trampoline jsr _SMB_Check ; do basic check to make sure we received SMB data bcs tp_trampoline ; if not, wait for them to send again i guess bra tft_far tf_trampoline jmp treex_failed tp_trampoline jmp treex_proceeding tft_far lda SMB_input+SMB_offset_cmd cmp #SMB_treec_ANDX bne tp_trampoline ; punt if not setup_ANDX reply lda SMB_input+SMB_offset_eclass cmp #0000 bne tf_trampoline ; they returned an error, kbye lda SMB_input+SMB_offset_tid ldy #SMB_sess_tid-SMB_sess_begin sta [SMB_sessid],y ; save returned TID * TODO save remote servicetype or filesystem type? treex_finished plx ; our return address PushWord #0001 ; finished! phx sec rts treex_failed plx ; our return address PushWord #0002 ; failure phx sec rts treex_proceeding plx ; our return address PushWord #0000 ; in progress phx clc rts * * SMB_OpenFile - Open a file on the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to filename (two words, on stack) * Things I return on stack: * A = SMB filehandle id * Carry flag set if error SMB_OpenFile plx ; return address PullLong SMB_tmp7 ; filename PullLong SMB_sessid phx ; saved return address PushWord #SMB_open_ANDX ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information sep $30 mx %11 lda #15 sta SMB_staging+SMB_header_size ; word count lda #$ff sta SMB_staging+SMB_header_size+1 ; next AndX lda #$00 sta SMB_staging+SMB_header_size+2 ; AndX Reserved rep $30 mx %00 lda #$0000 sta SMB_staging+SMB_header_size+3 ; AndX Offset lda #$0000 sta SMB_staging+SMB_header_size+5 ; Flags lda #SMB_open_reading sta SMB_staging+SMB_header_size+7 ; Access Mode lda #0000 sta SMB_staging+SMB_header_size+9 ; SearchAttrib (6 = HIDDEN & SYSTEM?) lda #0000 sta SMB_staging+SMB_header_size+11 ; file attributes lda #0000 sta SMB_staging+SMB_header_size+13 ; file time (don't care, let server decide) sta SMB_staging+SMB_header_size+15 lda #SMB_of_open sta SMB_staging+SMB_header_size+17 ; openmode lda #0000 sta SMB_staging+SMB_header_size+19 ; allocation size lda #0000 sta SMB_staging+SMB_header_size+21 ; allocation size lda #0000 sta SMB_staging+SMB_header_size+23 ; timeout lda #0000 sta SMB_staging+SMB_header_size+25 ; timeout lda #0000 sta SMB_staging+SMB_header_size+27 ; reserved[0] must be zero lda #0000 sta SMB_staging+SMB_header_size+29 ; reserved[1] must be zero lda #0000 sta SMB_staging+SMB_header_size+31 ; byte count lda #0 sta SMB_tmp5 ; initialize pointer ; Target File PushLong SMB_tmp7 ; source pea #^SMB_staging ; destination lda #SMB_staging+SMB_header_size+33 clc adc SMB_tmp5 pha jsr _strcpy tya clc adc SMB_tmp5 sta SMB_tmp5 sta SMB_staging+SMB_header_size+31 ; update byte count clc adc #SMB_header_size+33 pha ; 'length' parameter for _SMB_Send dec dec dec dec xba sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram jsr _SMB_Send ; send our reply! clc rts * SMB_OpenFile_Poll - Call me until I tell you to stop, to receive and complete SMB Tree_ANDX * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Setup status (word) * $0000 - Setup proceeding * $0001 - Setup finished * $0002 - Setup failed * Carry flag set means you can stop calling me SMB_OpenFile_Poll plx ; our return address PullLong SMB_sessid ; your smb sessid phx _TCPIPPoll PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushLong #statbuf _TCPIPStatusTCP ; see if marinetti has anything for us pla cmp #terrNOCONNECTION beq of_trampoline cmp #terrBADIPID beq of_trampoline lda statbuf+8 ; get recvq size, low word cmp #0000 ; yeah i know. for clarity. beq op_trampoline ; poll us again later, marinetti got nothing PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushWord #0000 ; bufftype: static pre-allocated buffer PushLong #SMB_input ; where it's all goin PushLong #SMB_max_net_read_size PushLong #readbuf _TCPIPReadTCP pla cmp #terrNOCONNECTION beq of_trampoline cmp #terrBADIPID beq of_trampoline jsr _SMB_Check ; do basic check to make sure we received SMB data bcs op_trampoline ; if not, wait for them to send again i guess bra oft_far of_trampoline jmp openx_failed op_trampoline jmp openx_proceeding oft_far lda SMB_input+SMB_offset_cmd cmp #SMB_open_ANDX bne op_trampoline ; punt if not setup_ANDX reply lda SMB_input+SMB_offset_eclass cmp #0000 bne of_trampoline ; they returned an error, kbye lda SMB_input+SMB_header_size+5 ; saved returned sfid openx_finished plx ; our return address PushWord #0001 ; finished! phx sec rts openx_failed plx ; our return address PushWord #0002 ; failure phx sec rts openx_proceeding plx ; our return address PushWord #0000 ; in progress phx clc rts * * SMB_CloseFile - Close an open file on the remote share * Arguments: * SMB session handle (two words, on stack) * A = SMB filehandle id * Things I return on stack: * Carry flag set if error SMB_CloseFile plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_close ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_CreateDirectory - Create a directory on the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to filename (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_CreateDirectory plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_COM_create_directory ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_DeleteDirectory - Delete a directory on the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to filename (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_DeleteDirectory plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_COM_delete_directory ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_DeleteFile - Delete a file on the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to filename (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_DeleteFile plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_COM_delete ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_RenameFile - Rename a file on the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to old filename (two words, on stack) * Long pointer to new filename (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_RenameFile plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_COM_rename ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_DiskInformation - Get information about the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to disk statbuf (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_DiskInformation plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_COM_query_information_disk ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_ReadFile - Read an open file from the remote share * Arguments: * SFID of open file (one word, on stack) * SMB session handle (two words, on stack) * Long pointer to read buffer (two words, on stack) * Size of read buffer (two words, on stack) * Offset into file (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_ReadFile plx ; return address PullLong SMB_tmp7 ; SMB_tmp7/SMB_tmp8 = offset PullLong SMB_tmp5 ; SMB_tmp5/SMB_tmp6 = sizeof read_buffer PullLong SMB_tmp3 ; SMB_tmp3/SMB_tmp4 = *read_buffer PullLong SMB_sessid PullWord SMB_tmp1 ; SMB_tmp1 = SFID phx ; saved return address PushWord #SMB_read_ANDX ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information sep $30 mx %11 lda #12 sta SMB_staging+SMB_header_size ; word count lda #$ff sta SMB_staging+SMB_header_size+1 ; next AndX lda #$00 sta SMB_staging+SMB_header_size+2 ; AndX Reserved rep $30 mx %00 lda #$0000 sta SMB_staging+SMB_header_size+3 ; AndX Offset lda SMB_tmp1 sta SMB_staging+SMB_header_size+5 ; SFID lda SMB_tmp7 sta SMB_staging+SMB_header_size+7 ; Offsetlow lda SMB_tmp8 sta SMB_staging+SMB_header_size+9 ; Offsetlow2 lda #1024 sta SMB_staging+SMB_header_size+11 ; maxcountbytestoreturn lda #0000 sta SMB_staging+SMB_header_size+13 ; mincountbytestoreturn lda #0000 sta SMB_staging+SMB_header_size+15 ; timeout lda #0000 sta SMB_staging+SMB_header_size+17 ; timeout2 lda #0000 sta SMB_staging+SMB_header_size+19 ; remaining lda #0000 sta SMB_staging+SMB_header_size+21 ; offsethigh lda #0000 sta SMB_staging+SMB_header_size+23 ; offsethigh2 lda #0000 sta SMB_staging+SMB_header_size+25 ; byte count (always 0) clc adc #SMB_header_size+27 pha ; 'length' parameter for _SMB_Send dec dec dec dec xba sta SMB_staging+SMB_offset_tcplength+1 ; save length for naked-TCP dgram jsr _SMB_Send ; send our reply! clc rts * SMB_ReadFile_Poll - Call me until I tell you to stop, to receive and complete SMB Tree_ANDX * Arguments: * SMB session handle (two words, on stack) * Things I return on stack: * Setup status (word) * $0000 - Setup proceeding * $0001 - Setup finished * $0002 - Setup failed * Carry flag set means you can stop calling me SMB_ReadFile_Poll plx ; our return address PullLong SMB_sessid ; your smb sessid phx _TCPIPPoll PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushLong #statbuf _TCPIPStatusTCP ; see if marinetti has anything for us pla cmp #terrNOCONNECTION beq rf_trampoline cmp #terrBADIPID beq rf_trampoline lda statbuf+8 ; get recvq size, low word cmp #0000 ; yeah i know. for clarity. beq rp_trampoline ; poll us again later, marinetti got nothing PushWord #0000 ; space for result ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; push Marinetti IPID for this SMB_sessid PushWord #0000 ; bufftype: static pre-allocated buffer PushLong #SMB_input ; where it's all goin PushLong #SMB_max_net_read_size PushLong #readbuf _TCPIPReadTCP pla cmp #terrNOCONNECTION beq rf_trampoline cmp #terrBADIPID beq rf_trampoline jsr _SMB_Check ; do basic check to make sure we received SMB data bcs rp_trampoline ; if not, wait for them to send again i guess bra rft_far rf_trampoline jmp readx_failed rp_trampoline jmp readx_proceeding rft_far lda SMB_input+SMB_offset_cmd cmp #SMB_read_ANDX bne rp_trampoline ; punt if not read_ANDX reply lda SMB_input+SMB_offset_eclass cmp #0000 bne rf_trampoline ; they returned an error, kbye ; TODO something readx_finished plx ; our return address PushWord #0001 ; finished! phx sec rts readx_failed plx ; our return address PushWord #0002 ; failure phx sec rts readx_proceeding plx ; our return address PushWord #0000 ; in progress phx clc rts * * SMB_WriteFile - Write to an open file from the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to data buffer (two words, on stack) * Size of data buffer (two words, on stack) * Offset into file (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_WriteFile plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_write_ANDX ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_PathInfo - Get information about a file/path on the remote share * Arguments: * SMB session handle (two words, on stack) * Long pointer to pathname (two words, on stack) * Long pointer to smb direntry struct buffer (two words, on stack) * Things I return on stack: * Carry flag set if error SMB_PathInfo plx ; return address PullLong SMB_sessid phx ; saved return address PushWord #SMB_query_path_info ; command PushWord #CIFS_flags1 ; flags1 PushWord #CIFS_flags2 ; flags2 jsr _InitSMBHeader ; make an SMB header with this information * TODO rts * * SMB_FindFirst - Find first file in a directory listing * Arguments: * SMB session handle (two words, on stack) * Long pointer to pathname (two words, on stack) * Flags (one word, on stack) * Long pointer to smb direntry struct buffer (two words, on stack) * Things I return on stack: * Carry flag set if error * TODO TRANS2 call * * SMB_FindNext - Find next file in a directory listing * Arguments: * SMB session handle (two words, on stack) * Long pointer to smb direntry struct buffer (two words, on stack) * Things I return on stack: * Carry flag set if error * TODO TRANS2 call * * SMB_FindClose - Close a directory listing * Arguments: * SMB session handle (two words, on stack) * Long pointer to smb direntry struct buffer (two words, on stack) * Things I return on stack: * Carry flag set if error * TODO TRANS2 call * * Internal subroutines for SMB stuff * * _strcpy - Copy a string somewhere... * Arguments: * Pointer to source (two words, on stack) * Pointer to destination (two words, on stack) * returns: * Y = number of bytes copied (including terminating zero) _strcpy plx PullLong SMB_tmp1 ; Destination PullLong SMB_tmp3 ; Source phx ldy #00 sep #$30 mx %11 _sclp lda [SMB_tmp3],y sta [SMB_tmp1],y cmp #00 beq _scrt iny bra _sclp _scrt rep #$30 mx %00 iny rts * _strncpy - Copy a string somewhere, only n bytes * Arguments: * Pointer to source (two words, on stack) * Pointer to destination (two words, on stack) * X = number of bytes to copy _strncpy txy plx PullLong SMB_tmp1 ; Destination PullLong SMB_tmp3 ; Source phx tyx ldy #00 sep #$30 mx %11 _snclp lda [SMB_tmp3],y sta [SMB_tmp1],y dex cpx #00 beq _sncrt iny bra _snclp _sncrt rep #$30 mx %00 rts * _SMB_Check - Check to see if TCP received data is SMB _SMB_Check lda SMB_input+SMB_offset_proto cmp #SMB_proto1 bne check_inv lda SMB_input+SMB_offset_proto+2 cmp #SMB_proto2 bne check_inv ; starts with 'SMB'\ff clc rts check_inv sec rts * _SMB_Send - Send the SMB datagram staging area out to Marinetti * Arguments: * length (word, pushed on stack first) _SMB_Send plx ; save return address PullWord SMB_tmp1 phx ; restore return address lda #0 sta SMB_tmp2 PushWord #0000 ldy #SMB_sess_ipid-SMB_sess_begin lda [SMB_sessid],y pha ; IPID for Marinetti PushLong #SMB_staging PushLong SMB_tmp1 ; length PushWord #0001 ; Samba sets PSH, so will I PushWord #0000 _TCPIPWriteTCP pla rts * _InitSMBHeader - Zero-out old SMB datagram data and start with some fresh header values * Arguments: * Command (word, pushed on stack first) * Flags1 (word, pushed on stack second) * Flags2 (word, pushed on stack third) * Session Handle (already stored in DP SMB_sessid) * Things I return on stack: * Carry flag set if error _InitSMBHeader ldx #00 lda #00 zero_loop sta SMB_staging,x ; loop to zero-out any old data from SMB header staging place inx inx cpx #SMB_max_transmit_size blt zero_loop lda #SMB_proto1 sta SMB_staging+SMB_offset_proto lda #SMB_proto2 sta SMB_staging+SMB_offset_proto+2 ; $FF + 'SMB' at start of header ldy #SMB_sess_tid-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_offset_tid ; set session TID ldy #SMB_sess_pid-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_offset_pid ; set session PID ldy #SMB_sess_uid-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_offset_uid ; set session UID ldy #SMB_sess_mid-SMB_sess_begin lda [SMB_sessid],y sta SMB_staging+SMB_offset_mid ; set session MID plx ; save return address pla ; flags2 (word) sta SMB_staging+SMB_offset_flags2 ; set Flags2 pla ; flags1 (word, but written as byte) ora SMB_staging+SMB_offset_flags sta SMB_staging+SMB_offset_flags ; write one-byte value where it goes pla ; command (word, but written as byte) ora SMB_staging+SMB_offset_cmd sta SMB_staging+SMB_offset_cmd ; write one-byte value where it goes phx rts