Subversion Repositories Kolibri OS

Rev

Rev 2598 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1.  
  2.  
  3. struct  thread_data
  4.                         rb 1024
  5.         stack           rb 0
  6.  
  7.         home_dir        rb 1024
  8.         work_dir        rb 1024
  9.         fpath           rb 1024*3       ; Will also be used to temporarily store username
  10.  
  11.         type            db ?    ; ASCII/EBDIC/IMAGE/..
  12.         mode            db ?    ; active/passive
  13.         socketnum       dd ?    ; Commands socket
  14.         state           dd ?    ; disconnected/logging in/logged in/..
  15.         passivesocknum  dd ?    ; when in passive mode, this is the listening socket
  16.         datasocketnum   dd ?    ; socket used for data transfers
  17.         permissions     dd ?
  18.         buffer_ptr      dd ?
  19.  
  20.         datasock        sockaddr_in
  21.  
  22.         buffer          rb BUFFERSIZE
  23. ends
  24.  
  25.  
  26. macro sendFTP str {
  27. local .string, .length, .label
  28.         xor     edi, edi
  29.         mcall   send, [edx + thread_data.socketnum], .string, .length
  30.         jmp     @f
  31. .string db str, 13, 10
  32. .length = $ - .string
  33. @@:
  34.  
  35. }
  36.  
  37. ;------------------------------------------------
  38. ; parse_cmd
  39. ;
  40. ; Internal function wich uses the 'commands'
  41. ;  table to call an appropriate cmd_xx function.
  42. ;
  43. ; input: esi = ptr to ascii commands
  44. ;        ecx = number of bytes input
  45. ;        edx = pointer to thread_data structure
  46. ;
  47. ; output: none
  48. ;
  49. ;------------------------------------------------
  50. align 4
  51. parse_cmd:                              ; esi must point to command
  52.  
  53.         cmp     byte [esi], 0x20        ; skip all leading characters
  54.         ja      .ok
  55.         inc     esi
  56.         dec     ecx
  57.         cmp     ecx, 3
  58.         jb      .error
  59.         jmp     parse_cmd
  60.   .ok:
  61.         cmp     byte [esi+3], 0x20
  62.         ja      @f
  63.         mov     byte [esi+3], 0
  64.        @@:
  65.  
  66.         mov     eax, [esi]
  67.         and     eax, not 0x20202020     ; convert to upper case
  68.         mov     edi, commands           ; list of commands to scan
  69.   .scanloop:
  70.         cmp     eax, [edi]
  71.         je      .got_it
  72.  
  73.         add     edi, 4+4*4
  74.         cmp     byte [edi], 0
  75.         jne     .scanloop
  76.  
  77.   .error:
  78.         cmp     [edx + thread_data.state], STATE_ACTIVE
  79.         jb      login_first
  80.         sendFTP "500 Unsupported command"
  81.         ret
  82.  
  83.   .got_it:
  84.         mov     eax, [edx + thread_data.state]
  85.         jmp     dword [edi + 4 + eax]
  86.  
  87.  
  88. align 4
  89. commands:               ; all commands must be in uppercase
  90.  
  91.         dd 'ABOR'
  92.         dd login_first, login_first, login_first, cmdABOR
  93. ;        dd 'ACCT
  94. ;        dd login_first, login_first, login_first, cmd_ACCT
  95. ;        dd 'APPE'
  96. ;        dd login_first, login_first, login_first, cmd_APPE
  97.         dd 'CDUP'
  98.         dd login_first, login_first, login_first, cmdCDUP
  99.         dd 'CWD'
  100.         dd login_first, login_first, login_first, cmdCWD
  101.         dd 'DELE'
  102.         dd login_first, login_first, login_first, cmdDELE
  103. ;        dd 'HELP'
  104. ;        dd login_first, login_first, login_first, cmd_HELP
  105.         dd 'LIST'
  106.         dd login_first, login_first, login_first, cmdLIST
  107. ;        dd 'MDTM'
  108. ;        dd login_first, login_first, login_first, cmd_MDTM
  109. ;        dd 'MKD'
  110. ;        dd login_first, login_first, login_first, cmd_MKD
  111. ;        dd 'MODE'
  112. ;        dd login_first, login_first, login_first, cmd_MODE
  113.         dd 'NLST'
  114.         dd login_first, login_first, login_first, cmdNLST
  115.         dd 'NOOP'
  116.         dd login_first, login_first, login_first, cmdNOOP
  117.         dd 'PASS'
  118.         dd cmdPASS.0,   cmdPASS    , cmdPASS.2,   cmdPASS.3
  119.         dd 'PASV'
  120.         dd login_first, login_first, login_first, cmdPASV
  121.         dd 'PORT'
  122.         dd login_first, login_first, login_first, cmdPORT
  123.         dd 'PWD'
  124.         dd login_first, login_first, login_first, cmdPWD
  125.         dd 'QUIT'
  126.         dd cmdQUIT,     cmdQUIT,     cmdQUIT,     cmdQUIT
  127. ;        dd 'REIN'
  128. ;        dd login_first, login_first, login_first, cmd_REIN
  129. ;        dd 'REST'
  130. ;        dd login_first, login_first, login_first, cmd_REST
  131.         dd 'RETR'
  132.         dd login_first, login_first, login_first, cmdRETR
  133. ;        dd 'RMD'
  134. ;        dd login_first, login_first, login_first, cmd_RMD
  135. ;        dd 'RNFR'
  136. ;        dd login_first, login_first, login_first, cmd_RNFR
  137. ;        dd 'RNTO'
  138. ;        dd login_first, login_first, login_first, cmd_RNTO
  139. ;        dd 'SITE'
  140. ;        dd login_first, login_first, login_first, cmd_SITE
  141. ;        dd 'SIZE'
  142. ;        dd login_first, login_first, login_first, cmd_SIZE
  143. ;        dd 'STAT'
  144. ;        dd login_first, login_first, login_first, cmd_STAT
  145.         dd 'STOR'
  146.         dd login_first, login_first, login_first, cmdSTOR
  147. ;        dd 'STOU'
  148. ;        dd login_first, login_first, login_first, cmd_STOU
  149. ;        dd 'STRU'
  150. ;        dd login_first, login_first, login_first, cmd_STRU
  151.         dd 'SYST'
  152.         dd login_first, login_first, login_first, cmdSYST
  153.         dd 'TYPE'
  154.         dd login_first, login_first, login_first, cmdTYPE
  155.         dd 'USER'
  156.         dd cmdUSER,     cmdUSER,     cmdUSER,     cmdUSER.2
  157.         db 0                                                    ; end marker
  158.  
  159. align 4
  160. login_first:
  161.         sendFTP "530 Please login with USER and PASS"
  162.         ret
  163.  
  164. align 4
  165. permission_denied:
  166.         sendFTP "550 Permission denied"
  167.         ret
  168.  
  169. align 4
  170. socketerror:
  171.         invoke  con_set_flags, 0x0c
  172.         invoke  con_write_asciiz, str_sockerr
  173.         invoke  con_set_flags, 0x07
  174.  
  175.         sendFTP "425 Can't open data connection"
  176.         ret
  177.  
  178. align 4
  179. abort_transfer:
  180.         and     [edx + thread_data.permissions], not ABORT
  181.         mov     [edx + thread_data.mode], MODE_NOTREADY
  182.         invoke  file.close, ebx
  183.         mcall   close, [edx + thread_data.datasocketnum]
  184.  
  185.         mov     edx, [ebp]
  186.         sendFTP "530 Transfer aborted"
  187.         ret
  188.  
  189. align 4
  190. ip_to_dword:    ; esi = ptr to str, cl = separator ('.', ',')
  191.  
  192.         call    ascii_to_byte
  193.         mov     bl, al
  194.         cmp     byte [esi], cl
  195.         jne     .err
  196.         inc     esi
  197.  
  198.         call    ascii_to_byte
  199.         mov     bh, al
  200.         cmp     byte [esi], cl
  201.         jne     .err
  202.         inc     esi
  203.  
  204.         shl     ebx, 16
  205.  
  206.         call    ascii_to_byte
  207.         mov     bl, al
  208.         cmp     byte [esi], cl
  209.         jne     .err
  210.         inc     esi
  211.  
  212.         call    ascii_to_byte
  213.         mov     bh, al
  214.  
  215.         ror     ebx, 16
  216.         ret
  217.  
  218.   .err:
  219.         xor     ebx, ebx
  220.         ret
  221.  
  222. align 4         ; esi = ptr to str, output in eax
  223. ascii_to_byte:
  224.  
  225.         xor     eax, eax
  226.         push    ebx
  227.  
  228.   .loop:
  229.         movzx   ebx, byte[esi]
  230.         sub     bl, '0'
  231.         jb      .done
  232.         cmp     bl, 9
  233.         ja      .done
  234.         lea     eax, [eax*4 + eax]      ;
  235.         shl     eax, 1                  ; eax = eax * 10
  236.         add     eax, ebx
  237.         inc     esi
  238.  
  239.         jmp     .loop
  240.  
  241.   .done:
  242.         pop     ebx
  243.         ret
  244.  
  245. align 4
  246. dword_to_ascii: ; edi = ptr where to write, eax is number
  247.  
  248.         push    edx ebx ecx
  249.         mov     ebx, 10
  250.         xor     ecx, ecx
  251.  
  252.        @@:
  253.         xor     edx, edx
  254.         div     ebx
  255.         add     edx, '0'
  256.         pushw   dx
  257.         inc     ecx
  258.         test    eax, eax
  259.         jnz     @r
  260.  
  261.        @@:
  262.         popw    ax
  263.         stosb
  264.         dec     ecx
  265.         jnz     @r
  266.  
  267.         pop     ecx ebx edx
  268.         ret
  269.  
  270. align 4
  271. create_path:            ; combine home_dir and work_dir strings into fpath
  272.  
  273.         mov     edx, [ebp]
  274.         lea     edi, [edx + thread_data.fpath]
  275.         lea     esi, [edx + thread_data.home_dir]
  276.         mov     ecx, 1024
  277.   .loop1:
  278.         lodsb
  279.         cmp     al, 0x20
  280.         jb      .next
  281.         stosb
  282.         loop    .loop1
  283.   .next:
  284.  
  285.         cmp     byte[edi-1], '/'
  286.         jne     @f
  287.         dec     edi
  288.        @@:
  289.  
  290.         lea     esi, [edx + thread_data.work_dir]
  291.         mov     ecx, 1024
  292.   .loop2:
  293.         lodsb
  294.         cmp     al, 0x20
  295.         jb      .done
  296.         stosb
  297.         loop    .loop2
  298.  
  299.   .done:
  300.         xor     al, al
  301.         stosb
  302.         ret
  303.  
  304. ;------------------------------------------------
  305. ; "ABOR"
  306. ;
  307. ; This command aborts the current filetransfer.
  308. ;
  309. ;------------------------------------------------
  310. align 4
  311. cmdABOR:
  312.  
  313.         or      [edx + thread_data.permissions], ABORT
  314.         sendFTP "250 Command succesul"
  315.         ret
  316.  
  317. ;------------------------------------------------
  318. ; "CDUP"
  319. ;
  320. ; Change the directory to move up one level.
  321. ;
  322. ;------------------------------------------------
  323. align 4
  324. cmdCDUP:
  325.  
  326.         test    [edx + thread_data.permissions], PERMISSION_CD
  327.         jz      permission_denied
  328.  
  329.         cmp     byte [edx + thread_data.work_dir+1], 0                          ; are we in "/" ?
  330.         je      .done
  331.  
  332.         mov     ecx, 1024
  333.         xor     al, al
  334.         lea     edi, [edx + thread_data.work_dir]
  335.         repne   scasb
  336.         std
  337.         dec     edi
  338.         dec     edi
  339.         dec     edi
  340.         mov     al,'/'
  341.         repne   scasb
  342.         cld
  343.         mov     byte[edi+1], 0
  344.  
  345.   .done:
  346. ; Print the new working dir on the console
  347.         lea     eax, [edx + thread_data.work_dir]
  348.         push    eax
  349.         call    [con_write_asciiz]
  350.         push    str_newline
  351.         call    [con_write_asciiz]
  352.  
  353.         sendFTP "250 Command succesul"
  354.         ret
  355.  
  356. ;------------------------------------------------
  357. ; "CWD"
  358. ;
  359. ; Change Working Directory.
  360. ;
  361. ;------------------------------------------------
  362. align 4
  363. cmdCWD:
  364.  
  365.         test    [edx + thread_data.permissions], PERMISSION_CD
  366.         jz      permission_denied
  367.  
  368.         sub     ecx, 4
  369.         jb      .err
  370.         add     esi, 4
  371.  
  372.   .scan:
  373.         lea     edi, [edx + thread_data.work_dir + 1]
  374.         push    ecx
  375.         mov     ecx, 1024
  376.   .find_zero:
  377.         cmp     byte [edi], 0
  378.         je      .found_zero
  379.         inc     edi
  380.         loop    .find_zero
  381.   .found_zero:
  382.         pop     ecx
  383.   .scan2:
  384.  
  385.         cmp     byte [esi], '/'
  386.         jne     @f
  387.         inc     esi
  388.         dec     ecx
  389.         jz      .done
  390.        @@:
  391.  
  392.   .loop:
  393.         lodsb
  394.         cmp     al, 0x20
  395.         jb      .done
  396.         cmp     al, '.'
  397.         je      .up
  398.   .continue:
  399.         stosb
  400.         loop    .loop
  401.   .done:
  402.         cmp     byte [edi-1], '/'
  403.         je      @f
  404.         mov     byte [edi], '/'
  405.         inc     edi
  406.        @@:
  407.         mov     byte [edi], 0
  408.  
  409. ; Print the new working dir on the console
  410.         lea     eax, [edx + thread_data.work_dir]
  411.         push    eax
  412.         call    [con_write_asciiz]
  413.         push    str_newline
  414.         call    [con_write_asciiz]
  415.  
  416.         sendFTP "250 Command succesful"
  417.         ret
  418.  
  419.   .up:
  420.         lodsb
  421.         cmp     al, '.'
  422.         jne     .continue
  423.  
  424. ;;;;        TODO: find second last '\' in work_dir and make next char zero
  425. ;;;;        point edi to that 0
  426.  
  427.         jmp     .scan2
  428.  
  429.   .err:
  430.         sendFTP "550 Directory does not exist"
  431.         ret
  432.  
  433. ;------------------------------------------------
  434. ; "DELE"
  435. ;
  436. ; Delete a file from the server.
  437. ;
  438. ;------------------------------------------------
  439. align 4
  440. cmdDELE:
  441.  
  442.         test    [edx + thread_data.permissions], PERMISSION_DELETE
  443.         jz      permission_denied
  444.  
  445.         ret
  446.  
  447. ;------------------------------------------------
  448. ; "LIST"
  449. ;
  450. ; List the files in the current working directory.
  451. ;
  452. ;------------------------------------------------
  453. align 4
  454. cmdLIST:
  455.  
  456.         test    [edx + thread_data.permissions], PERMISSION_EXEC
  457.         jz      permission_denied
  458.  
  459. ; If we are in active mode, it's time to open a data socket..
  460.         cmp     [edx + thread_data.mode], MODE_ACTIVE
  461.         jne     @f
  462.         mov     ecx, [edx + thread_data.datasocketnum]
  463.         lea     edx, [edx + thread_data.datasock]
  464.         mov     esi, sizeof.thread_data.datasock
  465.         mcall   connect
  466.         cmp     eax, -1
  467.         je      socketerror
  468.   @@:
  469.         mov     edx, [ebp]
  470.  
  471. ; Create fpath from home_dir and work_dir
  472.         call    create_path
  473.  
  474.         lea     ebx, [edx + thread_data.fpath]
  475.         invoke  con_write_asciiz, ebx
  476.         invoke  con_write_asciiz, str_newline
  477.  
  478.  
  479.         mov     edx, [ebp]                        ;;;
  480.         lea     ebx, [edx + thread_data.fpath]       ;;;;
  481. ; Start the search
  482.         invoke  file.find.first, ebx, str_mask, FA_ANY
  483.         test    eax, eax
  484.         jz      .nosuchdir
  485.  
  486.         mov     edx, [ebp]                        ;;;
  487.         lea     edi, [edx + thread_data.buffer]
  488.   .parse_file:
  489.         test    eax, eax        ; did we find a file?
  490.         jz      .done
  491.         mov     ebx, eax        ; yes, save the descripter in ebx
  492.  
  493. ; first, convert the attributes
  494.         test    [ebx + FileInfoA.Attributes], FA_FOLDER
  495.         jnz     .folder
  496.  
  497.         test    [ebx + FileInfoA.Attributes], FA_READONLY
  498.         jnz     .readonly
  499.  
  500.         mov     eax, '-rw-'
  501.         stosd
  502.         jmp     .attr
  503.  
  504.   .folder:
  505.         mov     eax, 'drwx'
  506.         stosd
  507.         jmp     .attr
  508.  
  509.   .readonly:
  510.         mov     eax, '-r--'
  511.         stosd
  512.  
  513.   .attr:
  514.         mov     eax, 'rw-r'
  515.         stosd
  516.         mov     ax, 'w-'
  517.         stosw
  518.         mov     al, ' '
  519.         stosb
  520.  
  521. ; now..
  522.         mov     ax, '1 '
  523.         stosw
  524.  
  525. ; now write owner, everything is owned by FTP, woohoo!
  526.         mov     eax, 'FTP '
  527.         stosd
  528.         stosd
  529.  
  530. ; now the filesize in ascii
  531.         mov     eax, [ebx + FileInfoA.FileSizeLow]
  532.         call    dword_to_ascii
  533.         mov     al, ' '
  534.         stosb
  535.  
  536. ; then date (month/day/year)
  537.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.month]
  538.         cmp     eax, 12
  539.         ja      @f
  540.         mov     eax, [months - 4 + 4*eax]
  541.         stosd
  542.        @@:
  543.  
  544.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.day]
  545.         call    dword_to_ascii
  546.         mov     al, ' '
  547.         stosb
  548.  
  549.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.year]
  550.         call    dword_to_ascii
  551.         mov     al, ' '
  552.         stosb
  553.  
  554. ; and last but not least, filename
  555.         lea     esi, [ebx + FileInfoA.FileName]
  556.         mov     ecx, 264
  557.   .nameloop:
  558.         lodsb
  559.         test    al, al
  560.         jz      .namedone
  561.         stosb
  562.         loop    .nameloop
  563.  
  564. ; insert a cr lf
  565.   .namedone:
  566.         mov     ax, 0x0a0d
  567.         stosw
  568.  
  569.         test    [edx + thread_data.permissions], ABORT          ; Did we receive ABOR command from client?
  570. ;;;        jnz     .abort                                         ; TODO
  571.  
  572. ; check next file
  573. ;;;        invoke  file.find.next, ebx
  574. ;;;        jmp     .parse_file
  575.         mov     eax, ebx        ;;;;;
  576.  
  577. ; close file desc
  578.   .done:
  579.         invoke  file.find.close, eax                            ; file discriptor is still in eax at this point!
  580.  
  581. ; append the string with a 0
  582.         xor     al, al
  583.         stosb
  584.  
  585. ; Warn the client we're about to send the data
  586.         push    edi
  587.         mov     edx, [ebp]              ;;;;;;;
  588.         sendFTP "150 Here it comes.."
  589.         pop     esi
  590.  
  591. ; and send it to the client
  592.         mov     edx, [ebp]
  593.         mov     ecx, [edx + thread_data.datasocketnum]
  594.         lea     edx, [edx + thread_data.buffer]
  595.         sub     esi, edx
  596.         xor     edi, edi
  597.         mcall   send
  598.  
  599. ; close the data socket..
  600.         mov     edx, [ebp]                                      ; thread_data pointer
  601.         mov     [edx + thread_data.mode], MODE_NOTREADY
  602.         mcall   close, [edx + thread_data.datasocketnum]
  603.  
  604.         sendFTP "226 Transfer OK"
  605.         ret
  606.  
  607.   .nosuchdir:
  608.         sendFTP "550 Directory does not exist"
  609.         ret
  610.  
  611. ;------------------------------------------------
  612. ; "NLST"
  613. ;
  614. ; List the filenames of the files in the current working directory.
  615. ;
  616. ;------------------------------------------------
  617. align 4
  618. cmdNLST:
  619.  
  620.         test    [edx + thread_data.permissions], PERMISSION_EXEC
  621.         jz      permission_denied
  622.  
  623.         ; TODO: same as list but simpler output format
  624.  
  625.         ret
  626.  
  627. ;------------------------------------------------
  628. ; "NOOP"
  629. ;
  630. ; No operation, just keep the connection alive.
  631. ;
  632. ;------------------------------------------------
  633. align 4
  634. cmdNOOP:
  635.  
  636.         sendFTP "200 Command OK"
  637.         ret
  638.  
  639. ;------------------------------------------------
  640. ; "PASS"
  641. ;
  642. ; Second phase of login process, client provides password.
  643. ;
  644. ;------------------------------------------------
  645. align 4
  646. cmdPASS:
  647.         lea     esi, [esi + 5]
  648.  
  649. ; read the password from users.ini
  650.         lea     edi, [edx + thread_data.buffer + 512]           ; temp pass
  651.         lea     ebx, [edx + thread_data.fpath]                  ; temp username
  652.         invoke  ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity
  653.         test    eax, eax
  654.         jnz     .incorrect
  655.         cmp     dword [edi], -1
  656.         je      .incorrect
  657.         cmp     byte[edi], 0
  658.         je      .pass_ok
  659.  
  660. ; compare with received password
  661.         repe    cmpsb
  662.         cmp     byte [esi], 0x20
  663.         jae     .incorrect
  664.         cmp     byte [edi], 0
  665.         jne     .incorrect
  666.  
  667.   .pass_ok:
  668.         invoke  ini.get_int, path2, ebx, str_mode, 0
  669.         mov     edx, [ebp]                                      ; because libini destroys edx!
  670.         mov     [edx + thread_data.permissions], eax
  671.  
  672.         invoke  con_write_asciiz, str_pass_ok
  673.         mov     [edx + thread_data.state], STATE_ACTIVE
  674.         sendFTP "230 You are now logged in"
  675.         ret
  676.  
  677.   .2:
  678.   .incorrect:
  679.         mov     [edx + thread_data.state], STATE_CONNECTED
  680.         sendFTP "530 Login incorrect"
  681.         ret
  682.  
  683. align 4
  684.   .0:
  685.         sendFTP "503 Login with USER first"
  686.         ret
  687.  
  688. align 4
  689.   .3:
  690.         sendFTP "230 Already logged in"
  691.         ret
  692.  
  693. ;------------------------------------------------
  694. ; "PASV"
  695. ;
  696. ; Initiate a passive dataconnection.
  697. ;
  698. ;------------------------------------------------
  699. align 4
  700. cmdPASV:
  701.  
  702. ; Open a new TCP socket
  703.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  704.         cmp     eax, -1
  705.         je      socketerror
  706.         mov     edx, [ebp]                                      ; thread_data pointer
  707.         mov     [edx + thread_data.passivesocknum], eax
  708.  
  709. ; Bind it to a known local port
  710.         mov     [edx + thread_data.datasock.sin_family], AF_INET4
  711.         mov     [edx + thread_data.datasock.sin_port], 2000
  712.         mov     [edx + thread_data.datasock.sin_addr], 0
  713.  
  714.         mov     ecx, eax                                        ; passivesocketnum
  715.         lea     edx, [edx + thread_data.datasock]
  716.         mov     esi, sizeof.thread_data.datasock
  717.         mcall   bind
  718.         cmp     eax, -1
  719. ;        je      bind_err       ; TODO
  720.  
  721. ; And set it to listen!
  722.         mcall   listen, , 1
  723.         cmp     eax, -1
  724. ;        je      listen_err     ; TODO
  725.  
  726. ; Tell our thread we are ready to accept incoming calls
  727.         mov     edx, [ebp]                                      ; thread_data pointer
  728.         mov     [edx + thread_data.mode], MODE_PASSIVE_WAIT
  729.  
  730. ; Now tell the client where to connect to in this format:
  731. ; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
  732. ; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
  733.  
  734. ; '227 ('
  735.         lea     edi, [edx + thread_data.buffer]
  736.         mov     eax, '227 '     ; FIXME (now hardcoded to 127.0.0.1:2000)
  737.         stosd
  738.         mov     al, '('
  739.         stosb
  740. ; ip
  741.         mov     eax, 127
  742.         call    dword_to_ascii
  743.         mov     al, ','
  744.         stosb
  745.         mov     eax, 0
  746.         call    dword_to_ascii
  747.         mov     al, ','
  748.         stosb
  749.         mov     eax, 0
  750.         call    dword_to_ascii
  751.         mov     al, ','
  752.         stosb
  753.         mov     eax, 1
  754.         call    dword_to_ascii
  755.         mov     al, ','
  756.         stosb
  757. ; port
  758.         mov     eax, 7
  759.         call    dword_to_ascii
  760.         mov     al, ','
  761.         stosb
  762.         mov     eax, 208
  763.         call    dword_to_ascii
  764. ; ')', 13, 10, 0
  765.         mov     eax, ')' + 0x000a0d00
  766.         stosd
  767.  
  768.         lea     esi, [edi - thread_data.buffer]
  769.         sub     esi, edx
  770.         mov     ecx, [edx + thread_data.socketnum]
  771.         lea     edx, [edx + thread_data.buffer]
  772.         xor     edi, edi
  773.         mcall   send
  774.  
  775.         ret
  776.  
  777. ;------------------------------------------------
  778. ; "PWD"
  779. ;
  780. ; Print the current working directory.
  781. ;
  782. ;------------------------------------------------
  783. align 4
  784. cmdPWD:
  785.  
  786.         mov     dword [edx + thread_data.buffer], '257 '
  787.         mov     byte [edx + thread_data.buffer+4], '"'
  788.  
  789.         lea     edi, [edx + thread_data.buffer+5]
  790.         lea     esi, [edx + thread_data.work_dir]
  791.         mov     ecx, 1024
  792.   .loop:
  793.         lodsb
  794.         or      al, al
  795.         jz      .ok
  796.         stosb
  797.         dec     ecx
  798.         jnz     .loop
  799.  
  800.   .ok:
  801.         mov     dword [edi], '"' + 0x000a0d00    ; '"',13,10,0
  802.         lea     esi, [edi - thread_data.buffer + 4]
  803.         sub     esi, edx
  804.         mov     ecx, [edx + thread_data.socketnum]
  805.         lea     edx, [edx + thread_data.buffer]
  806.         xor     edi, edi
  807.         mcall   send
  808.  
  809.         mov     edx, [ebp]
  810. ; Print the new working dir on the console
  811.         lea     eax, [edx + thread_data.work_dir]
  812.         invoke  con_write_asciiz, eax
  813.         invoke  con_write_asciiz, str_newline
  814.  
  815.         ret
  816.  
  817. ;------------------------------------------------
  818. ; "PORT"
  819. ;
  820. ; Initiate an active dataconnection.
  821. ;
  822. ;------------------------------------------------
  823. align 4
  824. cmdPORT:
  825.  
  826. ; PORT a1,a2,a3,a4,p1,p2
  827. ; IP address a1.a2.a3.a4, port p1*256+p2
  828.  
  829. ; Convert the IP
  830.         lea     esi, [esi+5]
  831.         mov     cl, ','
  832.         call    ip_to_dword
  833. ; And put it in datasock
  834. ;;;        mov     edx, [ebp]
  835.         mov     [edx + thread_data.datasock.sin_addr], ebx
  836.  
  837. ; Now the same with portnumber
  838.         inc     esi
  839.         call    ascii_to_byte
  840.         mov     bh, al
  841.         inc     esi
  842.         call    ascii_to_byte
  843.         mov     bl, al
  844.  
  845. ; Save it in datasock too
  846.         mov     [edx + thread_data.datasock.sin_port], bx
  847.  
  848. ; We will open the socket, but do not connect yet!
  849.         mov     [edx + thread_data.datasock.sin_family], AF_INET4
  850.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  851.         cmp     eax, -1
  852.         je      socketerror
  853.  
  854.         mov     edx, [ebp]                                      ; thread_data pointer
  855.         mov     [edx + thread_data.datasocketnum], eax
  856.         mov     [edx + thread_data.mode], MODE_ACTIVE
  857.  
  858.         sendFTP "225 Data connection open"
  859.         ret
  860.  
  861. ;------------------------------------------------
  862. ; "QUIT"
  863. ;
  864. ; Close the connection with client.
  865. ;
  866. ;------------------------------------------------
  867. align 4
  868. cmdQUIT:
  869.  
  870.         sendFTP "221 Bye!"
  871.         mov     edx, [ebp]
  872.         mcall   close, [edx + thread_data.datasocketnum]
  873.         mcall   close, [edx + thread_data.socketnum]
  874.  
  875.         add     esp, 4          ; get rid of call return address
  876.         jmp     thread_exit     ; now close this thread
  877.  
  878.  
  879. ;------------------------------------------------
  880. ; "RETR"
  881. ;
  882. ; Retrieve a file from the ftp server.
  883. ;
  884. ;------------------------------------------------
  885. align 4
  886. cmdRETR:
  887.  
  888.         test    [edx + thread_data.permissions], PERMISSION_READ
  889.         jz      permission_denied
  890.  
  891.         cmp     ecx, 1024 + 5
  892.         jae     .cannot_open
  893.  
  894.         sub     ecx, 5
  895.         jb      .cannot_open
  896.  
  897.         cmp     [edx + thread_data.mode], MODE_ACTIVE
  898.         jne     @f
  899.         push    ecx esi
  900.         mov     ecx, [edx + thread_data.datasocketnum]
  901.         lea     edx, [edx + thread_data.datasock]
  902.         mov     esi, sizeof.thread_data.datasock
  903.         mcall   connect
  904.         pop     esi ecx
  905.         cmp     eax, -1
  906.         je      socketerror
  907.   @@:
  908.  
  909.         push    ecx esi
  910.         call    create_path
  911.         pop     esi ecx
  912.         dec     edi
  913.         add     esi, 5
  914.  
  915.   .loop:
  916.         lodsb
  917.         cmp     al, 0x20
  918.         jl      .done
  919.         stosb
  920.         loop    .loop
  921.   .done:
  922.         xor     al, al
  923.         stosb
  924.  
  925.         lea     ebx, [edx + thread_data.fpath]
  926.         invoke  con_write_asciiz, ebx
  927.         invoke  con_write_asciiz, str_newline
  928.  
  929.         invoke  file.open, ebx, O_READ
  930.         test    eax, eax
  931.         jz      .cannot_open
  932.  
  933.         push    eax
  934.         mov     edx, [ebp]
  935.         sendFTP "150 Here it comes.."
  936.         pop     ebx
  937.  
  938.   .read_more:
  939.         mov     edx, [ebp]
  940.         test    [edx + thread_data.permissions], ABORT
  941.         jnz     abort_transfer
  942.  
  943.         lea     eax, [edx + thread_data.buffer]                 ; FIXME: use another buffer!! if we receive something on control connection now, we screw up!
  944.         invoke  file.read, ebx, eax, BUFFERSIZE
  945.         cmp     eax, -1
  946.         je      .cannot_open                                    ; FIXME: this is not the correct error
  947.  
  948.         push    eax ebx
  949.         mov     esi, eax
  950.         mov     ecx, [edx + thread_data.datasocketnum]
  951.         lea     edx, [edx + thread_data.buffer]
  952.         xor     esi, esi
  953.         mcall   send
  954.         pop     ebx ecx
  955.         cmp     eax, -1
  956.         je      socketerror
  957.  
  958. ;        cmp     eax, ecx
  959. ;        jne     not_all_byes_sent                               ; TODO
  960.  
  961.         cmp     ecx, BUFFERSIZE
  962.         je      .read_more
  963.  
  964.         invoke  file.close, ebx
  965.  
  966.         mov     edx, [ebp]
  967.         mov     [edx + thread_data.mode], MODE_NOTREADY
  968.         mcall   close, [edx + thread_data.datasocketnum]
  969.  
  970.         mov     edx, [ebp]
  971.         sendFTP "226 Transfer OK, closing connection"
  972.         ret
  973.  
  974.   .cannot_open:
  975.         invoke  con_set_flags, 0x0c
  976.         invoke  con_write_asciiz, str_notfound
  977.         invoke  con_set_flags, 0x07
  978.  
  979.         mov     edx, [ebp]
  980.         sendFTP "550 No such file"
  981.         ret
  982.  
  983.  
  984.  
  985. ;------------------------------------------------
  986. ; "STOR"
  987. ;
  988. ; Store a file on the server.
  989. ;
  990. ;------------------------------------------------
  991. align 4
  992. cmdSTOR:
  993.  
  994.         test    [edx + thread_data.permissions], PERMISSION_WRITE
  995.         jz      permission_denied
  996.  
  997.  
  998. ;;;;
  999.         test    [edx + thread_data.permissions], ABORT
  1000.         jnz     abort_transfer
  1001.  
  1002. ;;;;
  1003.  
  1004.         ret
  1005.  
  1006. ;------------------------------------------------
  1007. ; "SYST"
  1008. ;
  1009. ; Send information about the system.
  1010. ;
  1011. ;------------------------------------------------
  1012. align 4
  1013. cmdSYST:
  1014.  
  1015.         sendFTP "215 UNIX type: L8"
  1016.         ret
  1017.  
  1018. ;------------------------------------------------
  1019. ; "TYPE"
  1020. ;
  1021. ; Choose the file transfer type.
  1022. ;
  1023. ;------------------------------------------------
  1024. align 4
  1025. cmdTYPE:
  1026.  
  1027.         cmp     ecx, 6
  1028.         jb      parse_cmd.error
  1029.  
  1030.         mov     al, byte[esi+5]
  1031.         and     al, not 0x20
  1032.  
  1033.         cmp     al, 'A'
  1034.         je      .ascii
  1035.         cmp     al, 'E'
  1036.         je      .ebdic
  1037.         cmp     al, 'I'
  1038.         je      .image
  1039.         cmp     al, 'L'
  1040.         je      .local
  1041.  
  1042.         jmp     parse_cmd.error
  1043.  
  1044.   .ascii:
  1045.         mov     [edx + thread_data.type], TYPE_ASCII
  1046.         jmp     .subtype
  1047.  
  1048.   .ebdic:
  1049.         mov     [edx + thread_data.type], TYPE_EBDIC
  1050.  
  1051.   .subtype:
  1052.         cmp     ecx, 8
  1053.         jb      .non_print
  1054.  
  1055.         mov     al, byte[esi+7]
  1056.         and     al, not 0x20
  1057.  
  1058.         cmp     al, 'N'
  1059.         je      .non_print
  1060.         cmp     al, 'T'
  1061.         je      .telnet
  1062.         cmp     al, 'C'
  1063.         je      .asacc
  1064.  
  1065.         jmp     parse_cmd.error
  1066.  
  1067.   .non_print:
  1068.         or      [edx + thread_data.type], TYPE_NP
  1069.         jmp     .ok
  1070.  
  1071.   .telnet:
  1072.         or      [edx + thread_data.type], TYPE_TELNET
  1073.         jmp     .ok
  1074.  
  1075.   .asacc:
  1076.         or      [edx + thread_data.type], TYPE_ASA
  1077.         jmp     .ok
  1078.  
  1079.   .image:
  1080.         mov     [edx + thread_data.type], TYPE_IMAGE
  1081.         jmp     .ok
  1082.  
  1083.   .local:
  1084.         cmp     ecx, 8
  1085.         jb      parse_cmd.error
  1086.  
  1087.         mov     al, byte[esi+7]
  1088.         sub     al, '0'
  1089.         jb      parse_cmd.error                         ; FIXME: this is not the correct errormessage
  1090.         cmp     al, 9
  1091.         ja      parse_cmd.error                         ; FIXME
  1092.         or      al, TYPE_LOCAL
  1093.         mov     [edx + thread_data.type], al
  1094.  
  1095.   .ok:
  1096.         sendFTP "200 Command ok"
  1097.         ret
  1098.  
  1099. ;------------------------------------------------
  1100. ; "USER"
  1101. ;
  1102. ; Login to the server, step one of two.                         ;;; TODO: prevent buffer overflow!
  1103. ;
  1104. ;------------------------------------------------
  1105. align 4
  1106. cmdUSER:
  1107.  
  1108.         lea     esi, [esi + 5]
  1109.         lea     edi, [edx + thread_data.fpath]                  ; temp buffer for username
  1110.   .loop:
  1111.         lodsb
  1112.         stosb
  1113.         cmp     al, 0x20
  1114.         jae     .loop
  1115.         mov     byte [edi-1], 0
  1116.  
  1117.         lea     esi, [edx + thread_data.fpath]
  1118.         lea     eax, [edx + thread_data.home_dir]
  1119.         invoke  ini.get_str, path2, esi, str_home, eax, 1024, str_infinity
  1120.         cmp     eax, -1
  1121.         je      .login_fail
  1122.         cmp     dword [esi], -1
  1123.         je      .login_fail
  1124.  
  1125.         mov     word [edx + thread_data.work_dir], "/"          ; "/", 0
  1126.  
  1127.         invoke  con_write_asciiz, str_logged_in
  1128.         mov     [edx + thread_data.state], STATE_LOGIN
  1129.   .sendstr:
  1130.         sendFTP "331 Please specify the password"
  1131.         ret
  1132.  
  1133.   .login_fail:
  1134.         invoke  con_write_asciiz, str_login_invalid
  1135.         mov     [edx + thread_data.state], STATE_LOGIN_FAIL
  1136.         jmp     .sendstr
  1137.  
  1138. align 4
  1139.   .2:
  1140.         sendFTP "530 Can't change to another user"
  1141.         ret
  1142.