Subversion Repositories Kolibri OS

Rev

Rev 3824 | 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. ; TODO: Check directory on disk
  444.  
  445.  
  446. ; Print the new working dir on the console
  447.         lea     eax, [ebp + thread_data.work_dir]
  448.         invoke  con_write_asciiz, eax
  449.         invoke  con_write_asciiz, str_newline
  450.  
  451.         sendFTP "250 Command succesful"
  452.         ret
  453.  
  454.   .err:
  455.         sendFTP "550 Directory does not exist"
  456.         ret
  457.  
  458. ;------------------------------------------------
  459. ; "DELE"
  460. ;
  461. ; Delete a file from the server.
  462. ;
  463. ;------------------------------------------------
  464. align 4
  465. cmdDELE:
  466.  
  467.         test    [ebp + thread_data.permissions], PERMISSION_DELETE
  468.         jz      permission_denied
  469.  
  470.         ; Create path
  471.         cmp     ecx, 1024 + 5
  472.         jae     .err
  473.  
  474.         sub     ecx, 5
  475.         jb      .err
  476.  
  477.         call    create_path
  478.         dec     edi
  479.         lea     esi, [ebp + thread_data.buffer + 5]
  480.         mov     ecx, 1024
  481.         cmp     byte [esi], '/'
  482.         jne     .loop
  483.         inc     esi
  484.   .loop:
  485.         lodsb
  486.         cmp     al, 0x20
  487.         jl      .done
  488.         stosb
  489.         loop    .loop
  490.   .done:
  491.         xor     al, al
  492.         stosb
  493.  
  494.         lea     ebx, [ebp + thread_data.fpath]
  495.         invoke  con_write_asciiz, ebx
  496.         invoke  con_write_asciiz, str_newline
  497.         ; called fs function
  498.         push    ebx
  499.         dec     esp
  500.         mov     byte[esp], 0
  501.         push    dword 0
  502.         push    dword 0
  503.         push    dword 0
  504.         push    dword 0
  505.         push    dword 8
  506.         mov     ebx, esp
  507.         mcall   70
  508.         add     esp, 6*4 + 1
  509.  
  510.         test    eax, eax
  511.         jnz     .err
  512.  
  513.         sendFTP "250 Command succesful"
  514.         ret
  515. .err:
  516.         sendFTP "550 No such file"
  517.         ret
  518.  
  519. ;------------------------------------------------
  520. ; "LIST"
  521. ;
  522. ; List the files in the current working directory.
  523. ;
  524. ;------------------------------------------------
  525. align 4
  526. cmdLIST:
  527.  
  528.         test    [ebp + thread_data.permissions], PERMISSION_EXEC
  529.         jz      permission_denied
  530.  
  531.         call    open_datasock
  532.  
  533. ; Create fpath from home_dir and work_dir
  534.         call    create_path
  535.  
  536.         lea     ebx, [ebp + thread_data.fpath]
  537.         invoke  con_write_asciiz, ebx
  538.         invoke  con_write_asciiz, str_newline
  539.  
  540. ; Start the search
  541.         invoke  file.find.first, ebx, str_mask, FA_READONLY+FA_FOLDER+FA_ARCHIVED;+FA_NORMAL
  542.         test    eax, eax
  543.         jz      .nosuchdir
  544.  
  545.         lea     edi, [ebp + thread_data.buffer]
  546.   .parse_file:
  547.         test    eax, eax        ; did we find a file?
  548.         jz      .done
  549.         mov     ebx, eax        ; yes, save the descripter in ebx
  550.  
  551. ; first, convert the attributes
  552.         test    [ebx + FileInfoA.Attributes], FA_FOLDER
  553.         jnz     .folder
  554.  
  555.         test    [ebx + FileInfoA.Attributes], FA_READONLY
  556.         jnz     .readonly
  557.  
  558.         mov     eax, '-rw-'
  559.         stosd
  560.         jmp     .attr
  561.  
  562.   .folder:
  563.         mov     eax, 'drwx'
  564.         stosd
  565.         jmp     .attr
  566.  
  567.   .readonly:
  568.         mov     eax, '-r--'
  569.         stosd
  570.  
  571.   .attr:
  572.         mov     eax, 'rw-r'
  573.         stosd
  574.         mov     ax, 'w-'
  575.         stosw
  576.         mov     al, ' '
  577.         stosb
  578.  
  579. ; now..
  580.         mov     ax, '1 '
  581.         stosw
  582.  
  583. ; now write owner, everything is owned by FTP, woohoo!
  584.         mov     eax, 'FTP '
  585.         stosd
  586.         stosd
  587.  
  588. ; now the filesize in ascii
  589.         mov     eax, dword[ebx + FileInfoA.FileSize]
  590.         call    dword_to_ascii
  591.         mov     al, ' '
  592.         stosb
  593.  
  594. ; then date (month/day/year)
  595.         movzx   eax, [ebx + FileInfoA.DateModify.month]
  596.         cmp     eax, 12
  597.         ja      @f
  598.         mov     eax, [months - 4 + 4*eax]
  599.         stosd
  600.        @@:
  601.  
  602.         movzx   eax, [ebx + FileInfoA.DateModify.day]
  603.         call    dword_to_ascii
  604.         mov     al, ' '
  605.         stosb
  606.  
  607.         movzx   eax, [ebx + FileInfoA.DateModify.year]
  608.         call    dword_to_ascii
  609.         mov     al, ' '
  610.         stosb
  611.  
  612. ; and last but not least, filename
  613.         lea     esi, [ebx + FileInfoA.FileName]
  614.         mov     ecx, 264
  615.   .nameloop:
  616.         lodsb
  617.         test    al, al
  618.         jz      .namedone
  619.         stosb
  620.         loop    .nameloop
  621.  
  622. ; insert a cr lf
  623.   .namedone:
  624.         mov     ax, 0x0a0d
  625.         stosw
  626.  
  627.         test    [ebp + thread_data.permissions], ABORT          ; Did we receive ABOR command from client?
  628.         jnz     abort_transfer
  629.  
  630. ; check next file
  631.         invoke  file.find.next, ebx
  632.         jmp     .parse_file
  633.  
  634. ; close file desc
  635.   .done:
  636.         invoke  file.find.close, ebx                            ; ebx is descriptor of last file, eax will be -1 !!
  637.  
  638. ; append the string with a 0
  639.         xor     al, al
  640.         stosb
  641.  
  642. ; Warn the client we're about to send the data
  643.         push    edi
  644.         sendFTP "150 Here it comes.."
  645.         pop     esi
  646.  
  647. ; and send it to the client
  648.         mov     ecx, [ebp + thread_data.datasocketnum]          ; socket num
  649.         lea     edx, [ebp + thread_data.buffer]                 ; buffer ptr
  650.         sub     esi, edx                                        ; length
  651.         xor     edi, edi                                        ; flags
  652.         mcall   send
  653.  
  654. ; close the data socket..
  655.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  656.         mcall   close, [ebp + thread_data.datasocketnum]
  657.  
  658.         sendFTP "226 List OK"
  659.         ret
  660.  
  661.   .nosuchdir:
  662.         sendFTP "550 Directory does not exist"
  663.         ret
  664.  
  665. ;------------------------------------------------
  666. ; "NLST"
  667. ;
  668. ; List the filenames of the files in the current working directory.
  669. ;
  670. ;------------------------------------------------
  671. align 4
  672. cmdNLST:
  673.  
  674.         test    [ebp + thread_data.permissions], PERMISSION_EXEC
  675.         jz      permission_denied
  676.  
  677.         ; TODO: same as list but simpler output format
  678.  
  679.         ret
  680.  
  681. ;------------------------------------------------
  682. ; "NOOP"
  683. ;
  684. ; No operation, just keep the connection alive.
  685. ;
  686. ;------------------------------------------------
  687. align 4
  688. cmdNOOP:
  689.  
  690.         sendFTP "200 Command OK"
  691.         ret
  692.  
  693. ;------------------------------------------------
  694. ; "PASS"
  695. ;
  696. ; Second phase of login process, client provides password.
  697. ;
  698. ;------------------------------------------------
  699. align 4
  700. cmdPASS:
  701.  
  702. ; read the password from users.ini
  703.         lea     edi, [ebp + thread_data.buffer + 512]           ; temp pass
  704.         lea     ebx, [ebp + thread_data.fpath]                  ; temp username
  705.         invoke  ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity
  706.         test    eax, eax                                        ; unable to read password? fail!
  707.         jnz     .incorrect
  708.         cmp     dword [edi], -1                                 ; no key, section or file found.. fail!
  709.         je      .incorrect
  710.         cmp     byte [edi], 0                                   ; zero password? ok!
  711.         je      .ok
  712.  
  713.         add     esi, 5
  714.         sub     ecx, 5
  715.         jbe     .incorrect                                      ; no password given? but hey, we need one! fail..
  716.  
  717. ; compare with received password
  718.         repe    cmpsb
  719.         cmp     byte [esi-1], 0x20                              ; printeable characters left?
  720.         jae     .incorrect
  721.         cmp     byte [edi-1], 0
  722.         jne     .incorrect
  723.  
  724.   .ok:
  725.         invoke  ini.get_int, path2, ebx, str_mode, 0
  726.         mov     [ebp + thread_data.permissions], eax
  727.  
  728.         invoke  con_write_asciiz, str_pass_ok
  729.         mov     [ebp + thread_data.state], STATE_ACTIVE
  730.         sendFTP "230 You are now logged in"
  731.         ret
  732.  
  733.   .2:
  734.   .incorrect:
  735.         invoke  con_write_asciiz, str_pass_err
  736.         mov     [ebp + thread_data.state], STATE_CONNECTED      ; reset state
  737.         sendFTP "530 Login incorrect"
  738.         ret
  739.  
  740.   .0:
  741.         sendFTP "503 Login with USER first"
  742.         ret
  743.  
  744.   .3:
  745.         sendFTP "230 Already logged in"
  746.         ret
  747.  
  748. ;------------------------------------------------
  749. ; "PASV"
  750. ;
  751. ; Initiate a passive dataconnection.
  752. ;
  753. ;------------------------------------------------
  754. align 4
  755. cmdPASV:
  756.  
  757. ;        cmp     [ebp + thread_data.passivesocknum], -1
  758. ;        je      @f
  759. ;        mcall   close, [ebp + thread_data.passivesocknum]       ; if there is still a socket open, close it
  760. ;       @@:
  761.  
  762. ; Open a new TCP socket
  763.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  764.         cmp     eax, -1
  765.         je      socketerror
  766.         mov     [ebp + thread_data.passivesocknum], eax
  767.  
  768. ; Bind it to a known local port
  769.         mov     [ebp + thread_data.datasock.sin_family], AF_INET4
  770.         mov     [ebp + thread_data.datasock.sin_addr], 0
  771.  
  772.         mov     ecx, eax                                        ; passivesocketnum
  773.         lea     edx, [ebp + thread_data.datasock]
  774.         mov     esi, sizeof.thread_data.datasock
  775.  
  776.   .next_port:                                                   ; TODO: break the endless loop
  777.         call    nextpasvport
  778.         mov     ax, [pasv_port]
  779.         xchg    al, ah
  780.         mov     [ebp + thread_data.datasock.sin_port], ax
  781.  
  782.         mcall   bind
  783.         cmp     eax, -1
  784.         je      .next_port
  785.  
  786. ; And set it to listen!
  787.         mcall   listen, , 1
  788.         cmp     eax, -1
  789.         je      socketerror
  790.  
  791. ; Tell our thread we are ready to accept incoming calls
  792.         mov     [ebp + thread_data.mode], MODE_PASSIVE_WAIT
  793.  
  794. ; Now tell the client where to connect to in this format:
  795. ; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
  796. ; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
  797.  
  798. ; '227 Entering passive mode ('
  799.         lea     edi, [ebp + thread_data.buffer]
  800.         mov     ecx, str_227.length
  801.         mov     esi, str_227
  802.         rep movsb
  803. ; ip
  804.         movzx   eax, byte [serverip]
  805.         call    dword_to_ascii
  806.         mov     al, ','
  807.         stosb
  808.         movzx   eax, byte [serverip+1]
  809.         call    dword_to_ascii
  810.         mov     al, ','
  811.         stosb
  812.         movzx   eax, byte [serverip+2]
  813.         call    dword_to_ascii
  814.         mov     al, ','
  815.         stosb
  816.         movzx   eax, byte [serverip+3]
  817.         call    dword_to_ascii
  818.         mov     al, ','
  819.         stosb
  820. ; port
  821.         movzx   eax, byte [ebp + thread_data.datasock.sin_port]
  822.         call    dword_to_ascii
  823.         mov     al, ','
  824.         stosb
  825.         movzx   eax, byte [ebp + thread_data.datasock.sin_port+1]
  826.         call    dword_to_ascii
  827. ; ')', 13, 10, 0
  828.         mov     eax, ')' + (0x000a0d shl 8)
  829.         stosd
  830.  
  831.         lea     esi, [edi - thread_data.buffer - 1]      ; calculate length, do not cound the trailing 0 byte
  832.         sub     esi, ebp
  833.         mov     ecx, [ebp + thread_data.socketnum]
  834.         lea     edx, [ebp + thread_data.buffer]
  835.         xor     edi, edi
  836.         mcall   send
  837.  
  838.         invoke  con_write_asciiz, edx
  839.  
  840.         ret
  841.  
  842.  
  843. iglobal
  844.         str_227 db "227 Entering passive mode ("
  845.         .length = $ - str_227
  846. endg
  847.  
  848. ;------------------------------------------------
  849. ; "PWD"
  850. ;
  851. ; Print the current working directory.
  852. ;
  853. ;------------------------------------------------
  854. align 4
  855. cmdPWD:
  856.  
  857.         mov     dword [ebp + thread_data.buffer], '257 '
  858.         mov     byte [ebp + thread_data.buffer+4], '"'
  859.  
  860.         lea     edi, [ebp + thread_data.buffer+5]
  861.         lea     esi, [ebp + thread_data.work_dir]
  862.         mov     ecx, 1024
  863.   .loop:
  864.         lodsb
  865.         or      al, al
  866.         jz      .ok
  867.         stosb
  868.         dec     ecx
  869.         jnz     .loop
  870.  
  871.   .ok:
  872.         mov     dword [edi], '"' + 0x000a0d00    ; '"',13,10,0
  873.         lea     esi, [edi - thread_data.buffer + 3]
  874.         sub     esi, ebp
  875.         mov     ecx, [ebp + thread_data.socketnum]
  876.         lea     edx, [ebp + thread_data.buffer]
  877.         xor     edi, edi
  878.         mcall   send
  879.  
  880. ; Print the new working dir on the console
  881.         lea     eax, [ebp + thread_data.work_dir]
  882.         invoke  con_write_asciiz, eax
  883.         invoke  con_write_asciiz, str_newline
  884.  
  885.         ret
  886.  
  887. ;------------------------------------------------
  888. ; "PORT"
  889. ;
  890. ; Initiate an active dataconnection.
  891. ;
  892. ;------------------------------------------------
  893. align 4
  894. cmdPORT:
  895.  
  896. ; PORT a1,a2,a3,a4,p1,p2
  897. ; IP address a1.a2.a3.a4, port p1*256+p2
  898.  
  899. ; Convert the IP
  900.         lea     esi, [esi+5]
  901.         mov     cl, ','
  902.         call    ip_to_dword
  903. ; And put it in datasock
  904.         mov     [ebp + thread_data.datasock.sin_addr], ebx
  905.  
  906. ; Now the same with portnumber
  907.         inc     esi
  908.         call    ascii_to_byte
  909.         mov     byte[ebp + thread_data.datasock.sin_port], al
  910.         inc     esi
  911.         call    ascii_to_byte
  912.         mov     byte[ebp + thread_data.datasock.sin_port+1], al
  913.  
  914. ; We will open the socket, but do not connect yet!
  915.         mov     [ebp + thread_data.datasock.sin_family], AF_INET4
  916.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  917.         cmp     eax, -1
  918.         je      socketerror
  919.  
  920.         mov     [ebp + thread_data.datasocketnum], eax
  921.         mov     [ebp + thread_data.mode], MODE_ACTIVE
  922.  
  923.         sendFTP "225 Data connection open"
  924.         ret
  925.  
  926. ;------------------------------------------------
  927. ; "QUIT"
  928. ;
  929. ; Close the connection with client.
  930. ;
  931. ;------------------------------------------------
  932. align 4
  933. cmdQUIT:
  934.  
  935.         sendFTP "221 Bye!"
  936.         mcall   close, [ebp + thread_data.datasocketnum]
  937.         mcall   close, [ebp + thread_data.socketnum]
  938.  
  939.         add     esp, 4          ; get rid of call return address
  940.         jmp     thread_exit     ; now close this thread
  941.  
  942.  
  943. ;------------------------------------------------
  944. ; "RETR"
  945. ;
  946. ; Retrieve a file from the ftp server.
  947. ;
  948. ;------------------------------------------------
  949. align 4
  950. cmdRETR:
  951.  
  952.         test    [ebp + thread_data.permissions], PERMISSION_READ
  953.         jz      permission_denied
  954.  
  955.         cmp     ecx, 1024 + 5
  956.         jae     .cannot_open
  957.  
  958.         sub     ecx, 5
  959.         jb      .cannot_open
  960.  
  961.         call    open_datasock
  962.  
  963.         call    create_path
  964.         dec     edi
  965.         lea     esi, [ebp + thread_data.buffer + 5]
  966.         mov     ecx, 1024
  967.         cmp     byte [esi], '/'
  968.         jne     .loop
  969.         inc     esi
  970.   .loop:
  971.         lodsb
  972.         cmp     al, 0x20
  973.         jl      .done
  974.         stosb
  975.         loop    .loop
  976.   .done:
  977.         xor     al, al
  978.         stosb
  979.  
  980.         lea     ebx, [ebp + thread_data.fpath]
  981.         invoke  con_write_asciiz, ebx
  982.         invoke  con_write_asciiz, str_newline
  983.  
  984.         invoke  file.open, ebx, O_READ
  985.         test    eax, eax
  986.         jz      .cannot_open
  987.  
  988.         push    eax
  989.         sendFTP "150 Here it comes.."
  990.         pop     ebx
  991.  
  992.   .read_more:
  993.         test    [ebp + thread_data.permissions], ABORT
  994.         jnz     abort_transfer
  995.  
  996.         lea     eax, [ebp + thread_data.buffer]                 ; FIXME: use another buffer!! if we receive something on control connection now, we screw up!
  997.         invoke  file.read, ebx, eax, BUFFERSIZE
  998.         cmp     eax, -1
  999.         je      .cannot_open                                    ; FIXME: this is not the correct error
  1000.  
  1001.         invoke  con_write_asciiz, str2
  1002.  
  1003.         push    eax ebx
  1004.         mov     esi, eax
  1005.         mov     ecx, [ebp + thread_data.datasocketnum]
  1006.         lea     edx, [ebp + thread_data.buffer]
  1007.         xor     edi, edi
  1008.         mcall   send
  1009.         pop     ebx ecx
  1010.         cmp     eax, -1
  1011.         je      socketerror                                     ; FIXME: not the correct error
  1012.  
  1013. ;        cmp     eax, ecx
  1014. ;        jne     not_all_byes_sent                               ; TODO
  1015.  
  1016.         cmp     ecx, BUFFERSIZE
  1017.         je      .read_more
  1018.  
  1019.         invoke  file.close, ebx
  1020.  
  1021.         invoke  con_write_asciiz, str2b
  1022.  
  1023.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  1024.         mcall   close, [ebp + thread_data.datasocketnum]
  1025.  
  1026.         sendFTP "226 Transfer OK, closing connection"
  1027.         ret
  1028.  
  1029.   .cannot_open:
  1030.         invoke  con_set_flags, 0x0c
  1031.         invoke  con_write_asciiz, str_notfound
  1032.         invoke  con_set_flags, 0x07
  1033.  
  1034.         sendFTP "550 No such file"
  1035.         ret
  1036.  
  1037.  
  1038.  
  1039. ;------------------------------------------------
  1040. ; "STOR"
  1041. ;
  1042. ; Store a file on the server.
  1043. ;
  1044. ;------------------------------------------------
  1045. align 4
  1046. cmdSTOR:
  1047.  
  1048.         test    [ebp + thread_data.permissions], PERMISSION_WRITE
  1049.         jz      permission_denied
  1050.  
  1051.         ;sendFTP " Ready to receive"
  1052.         ; open datasocket
  1053.         cmp     ecx, 1024 + 5
  1054.         jae     .cannot_open
  1055.  
  1056.         sub     ecx, 5
  1057.         jb      .cannot_open
  1058.  
  1059.         call    open_datasock
  1060.  
  1061.         ; creat path
  1062.         call    create_path
  1063.         dec     edi
  1064.         lea     esi, [ebp + thread_data.buffer + 5]
  1065.         mov     ecx, 1024
  1066.         cmp     byte [esi], '/'
  1067.         jne     .loop
  1068.         inc     esi
  1069.   .loop:
  1070.         lodsb
  1071.         cmp     al, 0x20
  1072.         jl      .done
  1073.         stosb
  1074.         loop    .loop
  1075.   .done:
  1076.         xor     al, al
  1077.         stosb
  1078.  
  1079.         lea     ebx, [ebp + thread_data.fpath]
  1080.         invoke  con_write_asciiz, ebx
  1081.         invoke  con_write_asciiz, str_newline
  1082.  
  1083.         ; open file
  1084.         invoke  file.open, ebx, O_CREATE + O_WRITE
  1085.         test    eax, eax
  1086.         jz      .cannot_open
  1087.  
  1088.         push    eax
  1089.         sendFTP "150 Here it comes.."
  1090.         pop     ebx
  1091.  
  1092.   .write_more:
  1093.         test    [ebp + thread_data.permissions], ABORT
  1094.         jnz     abort_transfer
  1095.  
  1096.         push    eax ebx
  1097.         mov     esi, BUFFERSIZE ; eax
  1098.         mov     ecx, [ebp + thread_data.datasocketnum]
  1099.         lea     edx, [ebp + thread_data.buffer]
  1100.         xor     edi, edi
  1101.         mcall   recv
  1102.         pop     ebx ecx
  1103.         cmp     eax, -1
  1104.         je      socketerror                                     ; FIXME: not the correct error
  1105.  
  1106.         test    eax, eax
  1107.         jz      @f
  1108.  
  1109.         push    edx
  1110.         mov     edx, eax
  1111.         lea     eax, [ebp + thread_data.buffer]                 ; FIXME: use another buffer!! if we receive something on control connection now, we screw up!
  1112.         invoke  file.write, ebx, eax, edx
  1113.         pop     edx
  1114.  
  1115.         cmp     eax, -1
  1116.         je      .cannot_open                                    ; FIXME: this is not the correct error
  1117.  
  1118.         invoke  con_write_asciiz, str2
  1119.  
  1120. ;        cmp     eax, ecx
  1121. ;        jne     not_all_byes_sent                               ; TODO
  1122.  
  1123.         ;cmp     ecx, BUFFERSIZE
  1124.         ;je      .write_more
  1125.         jmp      .write_more
  1126. @@:
  1127.  
  1128.         invoke  file.close, ebx
  1129.  
  1130.         invoke  con_write_asciiz, str2b
  1131.  
  1132.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  1133.         mcall   close, [ebp + thread_data.datasocketnum]
  1134.  
  1135.  
  1136.  
  1137. ;;;;    TODO
  1138. ;
  1139. ;        test    [ebp + thread_data.permissions], ABORT
  1140. ;        jnz     abort_transfer
  1141. ;
  1142. ;;;;
  1143.  
  1144.         sendFTP "226 Transfer OK"
  1145.         ret
  1146.  
  1147. .cannot_open:
  1148.         sendFTP "550 No create file"
  1149.         ret
  1150.  
  1151. ;------------------------------------------------
  1152. ; "SYST"
  1153. ;
  1154. ; Send information about the system.
  1155. ;
  1156. ;------------------------------------------------
  1157. align 4
  1158. cmdSYST:
  1159.  
  1160.         sendFTP "215 UNIX type: L8"
  1161.         ret
  1162.  
  1163. ;------------------------------------------------
  1164. ; "TYPE"
  1165. ;
  1166. ; Choose the file transfer type.
  1167. ;
  1168. ;------------------------------------------------
  1169. align 4
  1170. cmdTYPE:
  1171.  
  1172.         cmp     ecx, 6
  1173.         jb      parse_cmd.error
  1174.  
  1175.         mov     al, byte[esi+5]
  1176.         and     al, not 0x20
  1177.  
  1178.         cmp     al, 'A'
  1179.         je      .ascii
  1180.         cmp     al, 'E'
  1181.         je      .ebdic
  1182.         cmp     al, 'I'
  1183.         je      .image
  1184.         cmp     al, 'L'
  1185.         je      .local
  1186.  
  1187.         jmp     parse_cmd.error
  1188.  
  1189.   .ascii:
  1190.         mov     [ebp + thread_data.type], TYPE_ASCII
  1191.         jmp     .subtype
  1192.  
  1193.   .ebdic:
  1194.         mov     [ebp + thread_data.type], TYPE_EBDIC
  1195.  
  1196.   .subtype:
  1197.         cmp     ecx, 8
  1198.         jb      .non_print
  1199.  
  1200.         mov     al, byte[esi+7]
  1201.         and     al, not 0x20
  1202.  
  1203.         cmp     al, 'N'
  1204.         je      .non_print
  1205.         cmp     al, 'T'
  1206.         je      .telnet
  1207.         cmp     al, 'C'
  1208.         je      .asacc
  1209.         cmp     al, 0x20
  1210.         jb      .non_print
  1211.  
  1212.         jmp     parse_cmd.error
  1213.  
  1214.   .non_print:
  1215.         or      [ebp + thread_data.type], TYPE_NP
  1216.         jmp     .ok
  1217.  
  1218.   .telnet:
  1219.         or      [ebp + thread_data.type], TYPE_TELNET
  1220.         jmp     .ok
  1221.  
  1222.   .asacc:
  1223.         or      [ebp + thread_data.type], TYPE_ASA
  1224.         jmp     .ok
  1225.  
  1226.   .image:
  1227.         mov     [ebp + thread_data.type], TYPE_IMAGE
  1228.         jmp     .ok
  1229.  
  1230.   .local:
  1231.         cmp     ecx, 8
  1232.         jb      parse_cmd.error
  1233.  
  1234.         mov     al, byte[esi+7]
  1235.         sub     al, '0'
  1236.         jb      parse_cmd.error                         ; FIXME: this is not the correct errormessage
  1237.         cmp     al, 9
  1238.         ja      parse_cmd.error                         ; FIXME
  1239.         or      al, TYPE_LOCAL
  1240.         mov     [ebp + thread_data.type], al
  1241.  
  1242.   .ok:
  1243.         sendFTP "200 Command ok"
  1244.         ret
  1245.  
  1246. ;------------------------------------------------
  1247. ; "USER"
  1248. ;
  1249. ; Login to the server, step one of two.                         ;;; TODO: prevent buffer overflow!
  1250. ;
  1251. ;------------------------------------------------
  1252. align 4
  1253. cmdUSER:
  1254.  
  1255.         lea     esi, [esi + 5]
  1256.         lea     edi, [ebp + thread_data.fpath]                  ; temp buffer for username
  1257.   .loop:
  1258.         lodsb
  1259.         stosb
  1260.         cmp     al, 0x20
  1261.         jae     .loop
  1262.         mov     byte [edi-1], 0
  1263.  
  1264.         lea     esi, [ebp + thread_data.fpath]
  1265.         lea     eax, [ebp + thread_data.home_dir]
  1266.         invoke  ini.get_str, path2, esi, str_home, eax, 1024, str_infinity
  1267.         cmp     eax, -1
  1268.         je      .login_fail
  1269.         cmp     dword [esi], -1
  1270.         je      .login_fail
  1271.  
  1272.         mov     word [ebp + thread_data.work_dir], "/"          ; "/", 0
  1273.  
  1274.         invoke  con_write_asciiz, str_logged_in
  1275.         mov     [ebp + thread_data.state], STATE_LOGIN
  1276.   .sendstr:
  1277.         sendFTP "331 Please specify the password"
  1278.         ret
  1279.  
  1280.   .login_fail:
  1281.         invoke  con_write_asciiz, str_pass_err
  1282.         mov     [ebp + thread_data.state], STATE_LOGIN_FAIL
  1283.         jmp     .sendstr
  1284.  
  1285. align 4
  1286.   .2:
  1287.         sendFTP "530 Can't change to another user"
  1288.         ret
  1289.