Subversion Repositories Kolibri OS

Rev

Rev 3819 | Go to most recent revision | Blame | Compare with Previous | 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. align 4
  283. open_datasock:
  284.  
  285.         cmp     [ebp + thread_data.mode], MODE_PASSIVE_OK
  286.         je      .already_open
  287.  
  288. ; If we are in active mode, it's time to open the data socket..
  289.         cmp     [ebp + thread_data.mode], MODE_ACTIVE
  290.         jne     .not_active
  291.         mov     ecx, [ebp + thread_data.datasocketnum]
  292.         lea     edx, [ebp + thread_data.datasock]
  293.         mov     esi, sizeof.thread_data.datasock
  294.         mcall   connect
  295.         cmp     eax, -1
  296.         je      .socketerror
  297.         invoke  con_write_asciiz, str_datasock2
  298.         ret
  299.  
  300.   .already_open:
  301.         invoke  con_write_asciiz, str_alopen
  302.         ret
  303.  
  304.   .socketerror:
  305.         add     esp, 4
  306.         jmp     socketerror
  307.  
  308. ; If we are still in passive_wait, it's time we accept an incomming call..
  309.   .not_active:
  310.         cmp     [ebp + thread_data.mode], MODE_PASSIVE_WAIT
  311.         jne     .socketerror
  312.  
  313.   .try_now:
  314.         mov     ecx, [ebp + thread_data.passivesocknum]
  315.         lea     edx, [ebp + thread_data.datasock]
  316.         mov     esi, sizeof.thread_data.datasock
  317.         mcall   accept
  318.         cmp     eax, -1
  319.         jne     .pasv_ok
  320.         mov     [ebp + thread_data.mode], MODE_PASSIVE_FAILED                   ; assume that we will fail
  321.         mcall   23, 200
  322.         mcall   accept
  323.         cmp     eax, -1
  324.         je      .socketerror
  325.   .pasv_ok:
  326.         mov     [ebp + thread_data.datasocketnum], eax
  327.         mov     [ebp + thread_data.mode], MODE_PASSIVE_OK
  328.         mcall   close   ; [ebp + thread_data.passivesocknum]
  329.         mov     [ebp + thread_data.passivesocknum], -1
  330.         invoke  con_write_asciiz, str_datasock
  331.  
  332.         ret
  333.  
  334.  
  335. ;------------------------------------------------
  336. ; "ABOR"
  337. ;
  338. ; This command aborts the current filetransfer.
  339. ;
  340. ;------------------------------------------------
  341. align 4
  342. cmdABOR:
  343.  
  344.         or      [ebp + thread_data.permissions], ABORT
  345.         sendFTP "250 Command succesul"
  346.         ret
  347.  
  348. ;------------------------------------------------
  349. ; "CDUP"
  350. ;
  351. ; Change the directory to move up one level.
  352. ;
  353. ;------------------------------------------------
  354. align 4
  355. cmdCDUP:
  356.  
  357.         test    [ebp + thread_data.permissions], PERMISSION_CD
  358.         jz      permission_denied
  359.  
  360.         cmp     byte [ebp + thread_data.work_dir+1], 0  ; are we in "/" ?
  361.         je      .done                                   ; if so, we cant go up..
  362.  
  363. ; find the end of asciiz string work_dir
  364.         mov     ecx, 1024
  365.         xor     al, al
  366.         lea     edi, [ebp + thread_data.work_dir]
  367.         repne   scasb
  368. ; return 2 characters (right before last /)
  369.         sub     edi, 3
  370. ; and now search backwards, for a '/'
  371.         mov     al,'/'
  372.         neg     ecx
  373.         add     ecx, 1024
  374.         std
  375.         repne   scasb
  376.         cld
  377. ; terminate the string here
  378.         mov     byte[edi+2], 0
  379.  
  380.   .done:
  381. ; Print the new working dir on the console
  382.         lea     eax, [ebp + thread_data.work_dir]
  383.         invoke  con_write_asciiz, eax
  384.         invoke  con_write_asciiz, str_newline
  385.  
  386.         sendFTP "250 Command succesul"
  387.         ret
  388.  
  389. ;------------------------------------------------
  390. ; "CWD"
  391. ;
  392. ; Change Working Directory.
  393. ;
  394. ;------------------------------------------------
  395. align 4
  396. cmdCWD:
  397.  
  398.         test    [ebp + thread_data.permissions], PERMISSION_CD
  399.         jz      permission_denied
  400.  
  401. ; do we have enough parameters?
  402.         sub     ecx, 4
  403.         jbe     .err
  404.  
  405. ; get ready to copy the path
  406.         add     esi, 4
  407.         mov     ecx, 1024
  408.         lea     edi, [ebp + thread_data.work_dir]
  409.  
  410. ; if received dir starts with '/', we will simply copy it
  411. ; If not, we will append the current path with the received path.
  412.         cmp     byte [esi], '/'
  413.         je      .copyloop
  414.  
  415. ; Find the end of work_dir string.
  416.         xor     al, al
  417.   .find_zero:
  418.         repne   scasb
  419.         dec     edi
  420.  
  421. ; and now append work_dir with received string
  422.         mov     ecx, 1024
  423.  
  424. ; scan for end byte, or '.'
  425.   .copyloop:
  426.         lodsb
  427.         cmp     al, 0x20
  428.         jb      .done
  429. ;;;        cmp     al, '.'         ; '..' means we must go up one dir   TODO
  430. ;;;        je      .up
  431.         stosb
  432.         loop    .copyloop
  433.  
  434. ; now, now make sure it ends with '/', 0
  435.   .done:
  436.         cmp     byte [edi-1], '/'
  437.         je      @f
  438.         mov     byte [edi], '/'
  439.         inc     edi
  440.        @@:
  441.         mov     byte [edi], 0
  442.  
  443. ; Print the new working dir on the console
  444.         lea     eax, [ebp + thread_data.work_dir]
  445.         invoke  con_write_asciiz, eax
  446.         invoke  con_write_asciiz, str_newline
  447.  
  448.         sendFTP "250 Command succesful"
  449.         ret
  450.  
  451.   .err:
  452.         sendFTP "550 Directory does not exist"
  453.         ret
  454.  
  455. ;------------------------------------------------
  456. ; "DELE"
  457. ;
  458. ; Delete a file from the server.
  459. ;
  460. ;------------------------------------------------
  461. align 4
  462. cmdDELE:
  463.  
  464.         test    [ebp + thread_data.permissions], PERMISSION_DELETE
  465.         jz      permission_denied
  466.  
  467.         ret
  468.  
  469. ;------------------------------------------------
  470. ; "LIST"
  471. ;
  472. ; List the files in the current working directory.
  473. ;
  474. ;------------------------------------------------
  475. align 4
  476. cmdLIST:
  477.  
  478.         test    [ebp + thread_data.permissions], PERMISSION_EXEC
  479.         jz      permission_denied
  480.  
  481.         call    open_datasock
  482.  
  483. ; Create fpath from home_dir and work_dir
  484.         call    create_path
  485.  
  486.         lea     ebx, [ebp + thread_data.fpath]
  487.         invoke  con_write_asciiz, ebx
  488.         invoke  con_write_asciiz, str_newline
  489.  
  490. ; Start the search
  491.         invoke  file.find.first, ebx, str_mask, FA_READONLY+FA_FOLDER+FA_ARCHIVED;+FA_NORMAL
  492.         test    eax, eax
  493.         jz      .nosuchdir
  494.  
  495.         lea     edi, [ebp + thread_data.buffer]
  496.   .parse_file:
  497.         test    eax, eax        ; did we find a file?
  498.         jz      .done
  499.         mov     ebx, eax        ; yes, save the descripter in ebx
  500.  
  501. ; first, convert the attributes
  502.         test    [ebx + FileInfoA.Attributes], FA_FOLDER
  503.         jnz     .folder
  504.  
  505.         test    [ebx + FileInfoA.Attributes], FA_READONLY
  506.         jnz     .readonly
  507.  
  508.         mov     eax, '-rw-'
  509.         stosd
  510.         jmp     .attr
  511.  
  512.   .folder:
  513.         mov     eax, 'drwx'
  514.         stosd
  515.         jmp     .attr
  516.  
  517.   .readonly:
  518.         mov     eax, '-r--'
  519.         stosd
  520.  
  521.   .attr:
  522.         mov     eax, 'rw-r'
  523.         stosd
  524.         mov     ax, 'w-'
  525.         stosw
  526.         mov     al, ' '
  527.         stosb
  528.  
  529. ; now..
  530.         mov     ax, '1 '
  531.         stosw
  532.  
  533. ; now write owner, everything is owned by FTP, woohoo!
  534.         mov     eax, 'FTP '
  535.         stosd
  536.         stosd
  537.  
  538. ; now the filesize in ascii
  539.         mov     eax, dword[ebx + FileInfoA.FileSize]
  540.         call    dword_to_ascii
  541.         mov     al, ' '
  542.         stosb
  543.  
  544. ; then date (month/day/year)
  545.         movzx   eax, [ebx + FileInfoA.DateModify.month]
  546.         cmp     eax, 12
  547.         ja      @f
  548.         mov     eax, [months - 4 + 4*eax]
  549.         stosd
  550.        @@:
  551.  
  552.         movzx   eax, [ebx + FileInfoA.DateModify.day]
  553.         call    dword_to_ascii
  554.         mov     al, ' '
  555.         stosb
  556.  
  557.         movzx   eax, [ebx + FileInfoA.DateModify.year]
  558.         call    dword_to_ascii
  559.         mov     al, ' '
  560.         stosb
  561.  
  562. ; and last but not least, filename
  563.         lea     esi, [ebx + FileInfoA.FileName]
  564.         mov     ecx, 264
  565.   .nameloop:
  566.         lodsb
  567.         test    al, al
  568.         jz      .namedone
  569.         stosb
  570.         loop    .nameloop
  571.  
  572. ; insert a cr lf
  573.   .namedone:
  574.         mov     ax, 0x0a0d
  575.         stosw
  576.  
  577.         test    [ebp + thread_data.permissions], ABORT          ; Did we receive ABOR command from client?
  578.         jnz     abort_transfer
  579.  
  580. ; check next file
  581.         invoke  file.find.next, ebx
  582.         jmp     .parse_file
  583.  
  584. ; close file desc
  585.   .done:
  586.         invoke  file.find.close, ebx                            ; ebx is descriptor of last file, eax will be -1 !!
  587.  
  588. ; append the string with a 0
  589.         xor     al, al
  590.         stosb
  591.  
  592. ; Warn the client we're about to send the data
  593.         push    edi
  594.         sendFTP "150 Here it comes.."
  595.         pop     esi
  596.  
  597. ; and send it to the client
  598.         mov     ecx, [ebp + thread_data.datasocketnum]          ; socket num
  599.         lea     edx, [ebp + thread_data.buffer]                 ; buffer ptr
  600.         sub     esi, edx                                        ; length
  601.         xor     edi, edi                                        ; flags
  602.         mcall   send
  603.  
  604. ; close the data socket..
  605.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  606.         mcall   close, [ebp + thread_data.datasocketnum]
  607.  
  608.         sendFTP "226 List OK"
  609.         ret
  610.  
  611.   .nosuchdir:
  612.         sendFTP "550 Directory does not exist"
  613.         ret
  614.  
  615. ;------------------------------------------------
  616. ; "NLST"
  617. ;
  618. ; List the filenames of the files in the current working directory.
  619. ;
  620. ;------------------------------------------------
  621. align 4
  622. cmdNLST:
  623.  
  624.         test    [ebp + thread_data.permissions], PERMISSION_EXEC
  625.         jz      permission_denied
  626.  
  627.         ; TODO: same as list but simpler output format
  628.  
  629.         ret
  630.  
  631. ;------------------------------------------------
  632. ; "NOOP"
  633. ;
  634. ; No operation, just keep the connection alive.
  635. ;
  636. ;------------------------------------------------
  637. align 4
  638. cmdNOOP:
  639.  
  640.         sendFTP "200 Command OK"
  641.         ret
  642.  
  643. ;------------------------------------------------
  644. ; "PASS"
  645. ;
  646. ; Second phase of login process, client provides password.
  647. ;
  648. ;------------------------------------------------
  649. align 4
  650. cmdPASS:
  651.  
  652. ; read the password from users.ini
  653.         lea     edi, [ebp + thread_data.buffer + 512]           ; temp pass
  654.         lea     ebx, [ebp + thread_data.fpath]                  ; temp username
  655.         invoke  ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity
  656.         test    eax, eax                                        ; unable to read password? fail!
  657.         jnz     .incorrect
  658.         cmp     dword [edi], -1                                 ; no key, section or file found.. fail!
  659.         je      .incorrect
  660.         cmp     byte [edi], 0                                   ; zero password? ok!
  661.         je      .ok
  662.  
  663.         add     esi, 5
  664.         sub     ecx, 5
  665.         jbe     .incorrect                                      ; no password given? but hey, we need one! fail..
  666.  
  667. ; compare with received password
  668.         repe    cmpsb
  669.         cmp     byte [esi-1], 0x20                              ; printeable characters left?
  670.         jae     .incorrect
  671.         cmp     byte [edi-1], 0
  672.         jne     .incorrect
  673.  
  674.   .ok:
  675.         invoke  ini.get_int, path2, ebx, str_mode, 0
  676.         mov     [ebp + thread_data.permissions], eax
  677.  
  678.         invoke  con_write_asciiz, str_pass_ok
  679.         mov     [ebp + thread_data.state], STATE_ACTIVE
  680.         sendFTP "230 You are now logged in"
  681.         ret
  682.  
  683.   .2:
  684.   .incorrect:
  685.         invoke  con_write_asciiz, str_pass_err
  686.         mov     [ebp + thread_data.state], STATE_CONNECTED      ; reset state
  687.         sendFTP "530 Login incorrect"
  688.         ret
  689.  
  690.   .0:
  691.         sendFTP "503 Login with USER first"
  692.         ret
  693.  
  694.   .3:
  695.         sendFTP "230 Already logged in"
  696.         ret
  697.  
  698. ;------------------------------------------------
  699. ; "PASV"
  700. ;
  701. ; Initiate a passive dataconnection.
  702. ;
  703. ;------------------------------------------------
  704. align 4
  705. cmdPASV:
  706.  
  707. ;        cmp     [ebp + thread_data.passivesocknum], -1
  708. ;        je      @f
  709. ;        mcall   close, [ebp + thread_data.passivesocknum]       ; if there is still a socket open, close it
  710. ;       @@:
  711.  
  712. ; Open a new TCP socket
  713.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  714.         cmp     eax, -1
  715.         je      socketerror
  716.         mov     [ebp + thread_data.passivesocknum], eax
  717.  
  718. ; Bind it to a known local port
  719.         mov     [ebp + thread_data.datasock.sin_family], AF_INET4
  720.         mov     [ebp + thread_data.datasock.sin_addr], 0
  721.  
  722.         mov     ecx, eax                                        ; passivesocketnum
  723.         lea     edx, [ebp + thread_data.datasock]
  724.         mov     esi, sizeof.thread_data.datasock
  725.  
  726.   .next_port:                                                   ; TODO: break the endless loop
  727.         call    nextpasvport
  728.         mov     ax, [pasv_port]
  729.         xchg    al, ah
  730.         mov     [ebp + thread_data.datasock.sin_port], ax
  731.  
  732.         mcall   bind
  733.         cmp     eax, -1
  734.         je      .next_port
  735.  
  736. ; And set it to listen!
  737.         mcall   listen, , 1
  738.         cmp     eax, -1
  739.         je      socketerror
  740.  
  741. ; Tell our thread we are ready to accept incoming calls
  742.         mov     [ebp + thread_data.mode], MODE_PASSIVE_WAIT
  743.  
  744. ; Now tell the client where to connect to in this format:
  745. ; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
  746. ; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
  747.  
  748. ; '227 Entering passive mode ('
  749.         lea     edi, [ebp + thread_data.buffer]
  750.         mov     ecx, str_227.length
  751.         mov     esi, str_227
  752.         rep movsb
  753. ; ip
  754.         movzx   eax, byte [serverip]
  755.         call    dword_to_ascii
  756.         mov     al, ','
  757.         stosb
  758.         movzx   eax, byte [serverip+1]
  759.         call    dword_to_ascii
  760.         mov     al, ','
  761.         stosb
  762.         movzx   eax, byte [serverip+2]
  763.         call    dword_to_ascii
  764.         mov     al, ','
  765.         stosb
  766.         movzx   eax, byte [serverip+3]
  767.         call    dword_to_ascii
  768.         mov     al, ','
  769.         stosb
  770. ; port
  771.         movzx   eax, byte [ebp + thread_data.datasock.sin_port]
  772.         call    dword_to_ascii
  773.         mov     al, ','
  774.         stosb
  775.         movzx   eax, byte [ebp + thread_data.datasock.sin_port+1]
  776.         call    dword_to_ascii
  777. ; ')', 13, 10, 0
  778.         mov     eax, ')' + (0x000a0d shl 8)
  779.         stosd
  780.  
  781.         lea     esi, [edi - thread_data.buffer - 1]      ; calculate length, do not cound the trailing 0 byte
  782.         sub     esi, ebp
  783.         mov     ecx, [ebp + thread_data.socketnum]
  784.         lea     edx, [ebp + thread_data.buffer]
  785.         xor     edi, edi
  786.         mcall   send
  787.  
  788.         invoke  con_write_asciiz, edx
  789.  
  790.         ret
  791.  
  792.  
  793. iglobal
  794.         str_227 db "227 Entering passive mode ("
  795.         .length = $ - str_227
  796. endg
  797.  
  798. ;------------------------------------------------
  799. ; "PWD"
  800. ;
  801. ; Print the current working directory.
  802. ;
  803. ;------------------------------------------------
  804. align 4
  805. cmdPWD:
  806.  
  807.         mov     dword [ebp + thread_data.buffer], '257 '
  808.         mov     byte [ebp + thread_data.buffer+4], '"'
  809.  
  810.         lea     edi, [ebp + thread_data.buffer+5]
  811.         lea     esi, [ebp + thread_data.work_dir]
  812.         mov     ecx, 1024
  813.   .loop:
  814.         lodsb
  815.         or      al, al
  816.         jz      .ok
  817.         stosb
  818.         dec     ecx
  819.         jnz     .loop
  820.  
  821.   .ok:
  822.         mov     dword [edi], '"' + 0x000a0d00    ; '"',13,10,0
  823.         lea     esi, [edi - thread_data.buffer + 3]
  824.         sub     esi, ebp
  825.         mov     ecx, [ebp + thread_data.socketnum]
  826.         lea     edx, [ebp + thread_data.buffer]
  827.         xor     edi, edi
  828.         mcall   send
  829.  
  830. ; Print the new working dir on the console
  831.         lea     eax, [ebp + thread_data.work_dir]
  832.         invoke  con_write_asciiz, eax
  833.         invoke  con_write_asciiz, str_newline
  834.  
  835.         ret
  836.  
  837. ;------------------------------------------------
  838. ; "PORT"
  839. ;
  840. ; Initiate an active dataconnection.
  841. ;
  842. ;------------------------------------------------
  843. align 4
  844. cmdPORT:
  845.  
  846. ; PORT a1,a2,a3,a4,p1,p2
  847. ; IP address a1.a2.a3.a4, port p1*256+p2
  848.  
  849. ; Convert the IP
  850.         lea     esi, [esi+5]
  851.         mov     cl, ','
  852.         call    ip_to_dword
  853. ; And put it in datasock
  854.         mov     [ebp + thread_data.datasock.sin_addr], ebx
  855.  
  856. ; Now the same with portnumber
  857.         inc     esi
  858.         call    ascii_to_byte
  859.         mov     byte[ebp + thread_data.datasock.sin_port], al
  860.         inc     esi
  861.         call    ascii_to_byte
  862.         mov     byte[ebp + thread_data.datasock.sin_port+1], al
  863.  
  864. ; We will open the socket, but do not connect yet!
  865.         mov     [ebp + thread_data.datasock.sin_family], AF_INET4
  866.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  867.         cmp     eax, -1
  868.         je      socketerror
  869.  
  870.         mov     [ebp + thread_data.datasocketnum], eax
  871.         mov     [ebp + thread_data.mode], MODE_ACTIVE
  872.  
  873.         sendFTP "225 Data connection open"
  874.         ret
  875.  
  876. ;------------------------------------------------
  877. ; "QUIT"
  878. ;
  879. ; Close the connection with client.
  880. ;
  881. ;------------------------------------------------
  882. align 4
  883. cmdQUIT:
  884.  
  885.         sendFTP "221 Bye!"
  886.         mcall   close, [ebp + thread_data.datasocketnum]
  887.         mcall   close, [ebp + thread_data.socketnum]
  888.  
  889.         add     esp, 4          ; get rid of call return address
  890.         jmp     thread_exit     ; now close this thread
  891.  
  892.  
  893. ;------------------------------------------------
  894. ; "RETR"
  895. ;
  896. ; Retrieve a file from the ftp server.
  897. ;
  898. ;------------------------------------------------
  899. align 4
  900. cmdRETR:
  901.  
  902.         test    [ebp + thread_data.permissions], PERMISSION_READ
  903.         jz      permission_denied
  904.  
  905.         cmp     ecx, 1024 + 5
  906.         jae     .cannot_open
  907.  
  908.         sub     ecx, 5
  909.         jb      .cannot_open
  910.  
  911.         call    open_datasock
  912.  
  913.         call    create_path
  914.         dec     edi
  915.         lea     esi, [ebp + thread_data.buffer + 5]
  916.         mov     ecx, 1024
  917.         cmp     byte [esi], '/'
  918.         jne     .loop
  919.         inc     esi
  920.   .loop:
  921.         lodsb
  922.         cmp     al, 0x20
  923.         jl      .done
  924.         stosb
  925.         loop    .loop
  926.   .done:
  927.         xor     al, al
  928.         stosb
  929.  
  930.         lea     ebx, [ebp + thread_data.fpath]
  931.         invoke  con_write_asciiz, ebx
  932.         invoke  con_write_asciiz, str_newline
  933.  
  934.         invoke  file.open, ebx, O_READ
  935.         test    eax, eax
  936.         jz      .cannot_open
  937.  
  938.         push    eax
  939.         sendFTP "150 Here it comes.."
  940.         pop     ebx
  941.  
  942.   .read_more:
  943.         test    [ebp + thread_data.permissions], ABORT
  944.         jnz     abort_transfer
  945.  
  946.         lea     eax, [ebp + thread_data.buffer]                 ; FIXME: use another buffer!! if we receive something on control connection now, we screw up!
  947.         invoke  file.read, ebx, eax, BUFFERSIZE
  948.         cmp     eax, -1
  949.         je      .cannot_open                                    ; FIXME: this is not the correct error
  950.  
  951.         invoke  con_write_asciiz, str2
  952.  
  953.         push    eax ebx
  954.         mov     esi, eax
  955.         mov     ecx, [ebp + thread_data.datasocketnum]
  956.         lea     edx, [ebp + thread_data.buffer]
  957.         xor     edi, edi
  958.         mcall   send
  959.         pop     ebx ecx
  960.         cmp     eax, -1
  961.         je      socketerror                                     ; FIXME: not the correct error
  962.  
  963. ;        cmp     eax, ecx
  964. ;        jne     not_all_byes_sent                               ; TODO
  965.  
  966.         cmp     ecx, BUFFERSIZE
  967.         je      .read_more
  968.  
  969.         invoke  file.close, ebx
  970.  
  971.         invoke  con_write_asciiz, str2b
  972.  
  973.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  974.         mcall   close, [ebp + thread_data.datasocketnum]
  975.  
  976.         sendFTP "226 Transfer OK, closing connection"
  977.         ret
  978.  
  979.   .cannot_open:
  980.         invoke  con_set_flags, 0x0c
  981.         invoke  con_write_asciiz, str_notfound
  982.         invoke  con_set_flags, 0x07
  983.  
  984.         sendFTP "550 No such file"
  985.         ret
  986.  
  987.  
  988.  
  989. ;------------------------------------------------
  990. ; "STOR"
  991. ;
  992. ; Store a file on the server.
  993. ;
  994. ;------------------------------------------------
  995. align 4
  996. cmdSTOR:
  997.  
  998.         test    [ebp + thread_data.permissions], PERMISSION_WRITE
  999.         jz      permission_denied
  1000.  
  1001.         sendFTP " Ready to receive"
  1002.  
  1003.  
  1004. ;;;;    TODO
  1005.  
  1006.         test    [ebp + thread_data.permissions], ABORT
  1007.         jnz     abort_transfer
  1008.  
  1009. ;;;;
  1010.  
  1011.         sendFTP "226 Transfer OK"
  1012.  
  1013.         ret
  1014.  
  1015. ;------------------------------------------------
  1016. ; "SYST"
  1017. ;
  1018. ; Send information about the system.
  1019. ;
  1020. ;------------------------------------------------
  1021. align 4
  1022. cmdSYST:
  1023.  
  1024.         sendFTP "215 UNIX type: L8"
  1025.         ret
  1026.  
  1027. ;------------------------------------------------
  1028. ; "TYPE"
  1029. ;
  1030. ; Choose the file transfer type.
  1031. ;
  1032. ;------------------------------------------------
  1033. align 4
  1034. cmdTYPE:
  1035.  
  1036.         cmp     ecx, 6
  1037.         jb      parse_cmd.error
  1038.  
  1039.         mov     al, byte[esi+5]
  1040.         and     al, not 0x20
  1041.  
  1042.         cmp     al, 'A'
  1043.         je      .ascii
  1044.         cmp     al, 'E'
  1045.         je      .ebdic
  1046.         cmp     al, 'I'
  1047.         je      .image
  1048.         cmp     al, 'L'
  1049.         je      .local
  1050.  
  1051.         jmp     parse_cmd.error
  1052.  
  1053.   .ascii:
  1054.         mov     [ebp + thread_data.type], TYPE_ASCII
  1055.         jmp     .subtype
  1056.  
  1057.   .ebdic:
  1058.         mov     [ebp + thread_data.type], TYPE_EBDIC
  1059.  
  1060.   .subtype:
  1061.         cmp     ecx, 8
  1062.         jb      .non_print
  1063.  
  1064.         mov     al, byte[esi+7]
  1065.         and     al, not 0x20
  1066.  
  1067.         cmp     al, 'N'
  1068.         je      .non_print
  1069.         cmp     al, 'T'
  1070.         je      .telnet
  1071.         cmp     al, 'C'
  1072.         je      .asacc
  1073.         cmp     al, 0x20
  1074.         jb      .non_print
  1075.  
  1076.         jmp     parse_cmd.error
  1077.  
  1078.   .non_print:
  1079.         or      [ebp + thread_data.type], TYPE_NP
  1080.         jmp     .ok
  1081.  
  1082.   .telnet:
  1083.         or      [ebp + thread_data.type], TYPE_TELNET
  1084.         jmp     .ok
  1085.  
  1086.   .asacc:
  1087.         or      [ebp + thread_data.type], TYPE_ASA
  1088.         jmp     .ok
  1089.  
  1090.   .image:
  1091.         mov     [ebp + thread_data.type], TYPE_IMAGE
  1092.         jmp     .ok
  1093.  
  1094.   .local:
  1095.         cmp     ecx, 8
  1096.         jb      parse_cmd.error
  1097.  
  1098.         mov     al, byte[esi+7]
  1099.         sub     al, '0'
  1100.         jb      parse_cmd.error                         ; FIXME: this is not the correct errormessage
  1101.         cmp     al, 9
  1102.         ja      parse_cmd.error                         ; FIXME
  1103.         or      al, TYPE_LOCAL
  1104.         mov     [ebp + thread_data.type], al
  1105.  
  1106.   .ok:
  1107.         sendFTP "200 Command ok"
  1108.         ret
  1109.  
  1110. ;------------------------------------------------
  1111. ; "USER"
  1112. ;
  1113. ; Login to the server, step one of two.                         ;;; TODO: prevent buffer overflow!
  1114. ;
  1115. ;------------------------------------------------
  1116. align 4
  1117. cmdUSER:
  1118.  
  1119.         lea     esi, [esi + 5]
  1120.         lea     edi, [ebp + thread_data.fpath]                  ; temp buffer for username
  1121.   .loop:
  1122.         lodsb
  1123.         stosb
  1124.         cmp     al, 0x20
  1125.         jae     .loop
  1126.         mov     byte [edi-1], 0
  1127.  
  1128.         lea     esi, [ebp + thread_data.fpath]
  1129.         lea     eax, [ebp + thread_data.home_dir]
  1130.         invoke  ini.get_str, path2, esi, str_home, eax, 1024, str_infinity
  1131.         cmp     eax, -1
  1132.         je      .login_fail
  1133.         cmp     dword [esi], -1
  1134.         je      .login_fail
  1135.  
  1136.         mov     word [ebp + thread_data.work_dir], "/"          ; "/", 0
  1137.  
  1138.         invoke  con_write_asciiz, str_logged_in
  1139.         mov     [ebp + thread_data.state], STATE_LOGIN
  1140.   .sendstr:
  1141.         sendFTP "331 Please specify the password"
  1142.         ret
  1143.  
  1144.   .login_fail:
  1145.         invoke  con_write_asciiz, str_pass_err
  1146.         mov     [ebp + thread_data.state], STATE_LOGIN_FAIL
  1147.         jmp     .sendstr
  1148.  
  1149. align 4
  1150.   .2:
  1151.         sendFTP "530 Can't change to another user"
  1152.         ret
  1153.