Subversion Repositories Kolibri OS

Rev

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