Subversion Repositories Kolibri OS

Rev

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