Subversion Repositories Kolibri OS

Rev

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