Subversion Repositories Kolibri OS

Rev

Rev 2945 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1.  
  2.  
  3. struct  thread_data
  4.                         rb 1024
  5.         stack           rb 0
  6.  
  7.         home_dir        rb 1024         ; home directory in wich the user is locked, asciiz
  8.         work_dir        rb 1024         ; working directory, must at all times begin and end with a '/', asciiz
  9.         fpath           rb 1024*3       ; file path, combination of home_dir, work_dir and filename
  10.                                         ; Will also be used to temporarily store username
  11.  
  12.         type            db ?    ; ASCII/EBDIC/IMAGE/..
  13.         mode            db ?    ; active/passive
  14.         socketnum       dd ?    ; Commands socket
  15.         state           dd ?    ; disconnected/logging in/logged in/..
  16.         passivesocknum  dd ?    ; when in passive mode, this is the listening socket
  17.         datasocketnum   dd ?    ; socket used for data transfers
  18.         permissions     dd ?    ; read/write/execute/....
  19.         buffer_ptr      dd ?
  20.         pid             dd ?    ; Process id of the current thread
  21.  
  22.         datasock        sockaddr_in
  23.  
  24.         buffer          rb BUFFERSIZE
  25. ends
  26.  
  27. ;------------------------------------------------
  28. ; parse_cmd
  29. ;
  30. ; Internal function wich uses the 'commands'
  31. ;  table to call an appropriate cmd_xx function.
  32. ;
  33. ; input: esi = ptr to ascii commands
  34. ;        ecx = number of bytes input
  35. ;        ebp = pointer to thread_data structure
  36. ;
  37. ; output: none
  38. ;
  39. ;------------------------------------------------
  40. align 4
  41. parse_cmd:                              ; esi must point to command
  42.  
  43.         cmp     byte [esi], 0x20        ; skip all leading characters
  44.         ja      .ok
  45.         inc     esi
  46.         dec     ecx
  47.         cmp     ecx, 3
  48.         jb      .error
  49.         jmp     parse_cmd
  50.   .ok:
  51.         cmp     byte [esi+3], 0x20
  52.         ja      @f
  53.         mov     byte [esi+3], 0
  54.        @@:
  55.  
  56.         mov     eax, [esi]
  57.         and     eax, not 0x20202020     ; convert to upper case
  58.         mov     edi, commands           ; list of commands to scan
  59.   .scanloop:
  60.         cmp     eax, [edi]
  61.         je      .got_it
  62.  
  63.         add     edi, 5*4
  64.         cmp     byte [edi], 0
  65.         jne     .scanloop
  66.  
  67.   .error:
  68.         cmp     [ebp + thread_data.state], STATE_ACTIVE
  69.         jb      login_first
  70.         sendFTP "500 Unsupported command"
  71.         ret
  72.  
  73.   .got_it:
  74.         mov     eax, [ebp + thread_data.state]
  75.         jmp     dword [edi + 4 + eax]
  76.  
  77.  
  78. align 4
  79. iglobal
  80. commands:               ; all commands must be in uppercase
  81.  
  82.         dd 'ABOR', login_first, login_first, login_first, cmdABOR
  83. ;        dd 'ACCT', login_first, login_first, login_first, cmd_ACCT
  84. ;        dd 'APPE', login_first, login_first, login_first, cmd_APPE
  85.         dd 'CDUP', login_first, login_first, login_first, cmdCDUP
  86.         dd 'CWD',  login_first, login_first, login_first, cmdCWD
  87.         dd 'DELE', login_first, login_first, login_first, cmdDELE
  88. ;        dd 'HELP', login_first, login_first, login_first, cmd_HELP
  89.         dd 'LIST', login_first, login_first, login_first, cmdLIST
  90. ;        dd 'MDTM', login_first, login_first, login_first, cmd_MDTM
  91. ;        dd 'MKD',  login_first, login_first, login_first, cmd_MKD
  92. ;        dd 'MODE', login_first, login_first, login_first, cmd_MODE
  93.         dd 'NLST', login_first, login_first, login_first, cmdNLST
  94.         dd 'NOOP', login_first, login_first, login_first, cmdNOOP
  95.         dd 'PASS', cmdPASS.0,   cmdPASS    , cmdPASS.2,   cmdPASS.3
  96.         dd 'PASV', login_first, login_first, login_first, cmdPASV
  97.         dd 'PORT', login_first, login_first, login_first, cmdPORT
  98.         dd 'PWD',  login_first, login_first, login_first, cmdPWD
  99.         dd 'QUIT', cmdQUIT,     cmdQUIT,     cmdQUIT,     cmdQUIT
  100. ;        dd 'REIN', login_first, login_first, login_first, cmd_REIN
  101. ;        dd 'REST', login_first, login_first, login_first, cmd_REST
  102.         dd 'RETR', login_first, login_first, login_first, cmdRETR
  103. ;        dd 'RMD', login_first, login_first, login_first, cmd_RMD
  104. ;        dd 'RNFR', login_first, login_first, login_first, cmd_RNFR
  105. ;        dd 'RNTO', login_first, login_first, login_first, cmd_RNTO
  106. ;        dd 'SITE', login_first, login_first, login_first, cmd_SITE
  107. ;        dd 'SIZE', login_first, login_first, login_first, cmd_SIZE
  108. ;        dd 'STAT', login_first, login_first, login_first, cmd_STAT
  109.         dd 'STOR', login_first, login_first, login_first, cmdSTOR
  110. ;        dd 'STOU', login_first, login_first, login_first, cmd_STOU
  111. ;        dd 'STRU', login_first, login_first, login_first, cmd_STRU
  112.         dd 'SYST', login_first, login_first, login_first, cmdSYST
  113.         dd 'TYPE', login_first, login_first, login_first, cmdTYPE
  114.         dd 'USER', cmdUSER,     cmdUSER,     cmdUSER,     cmdUSER.2
  115.         db 0    ; end marker
  116. endg
  117.  
  118. align 4
  119. login_first:
  120.         sendFTP "530 Please login with USER and PASS"
  121.         ret
  122.  
  123. align 4
  124. permission_denied:
  125.         sendFTP "550 Permission denied"
  126.         ret
  127.  
  128. align 4
  129. socketerror:
  130.         invoke  con_set_flags, 0x0c
  131.         invoke  con_write_asciiz, str_sockerr
  132.         invoke  con_set_flags, 0x07
  133.  
  134.         sendFTP "425 Can't open data connection"
  135.         ret
  136.  
  137. align 4
  138. abort_transfer:
  139.         and     [ebp + thread_data.permissions], not ABORT
  140.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  141.         invoke  file.close, ebx
  142.         mcall   close, [ebp + thread_data.datasocketnum]
  143.  
  144.         sendFTP "530 Transfer aborted"
  145.         ret
  146.  
  147. align 4
  148. ip_to_dword:    ; esi = ptr to str, cl = separator ('.', ',')
  149.  
  150.         call    ascii_to_byte
  151.         mov     bl, al
  152.         cmp     byte [esi], cl
  153.         jne     .err
  154.         inc     esi
  155.  
  156.         call    ascii_to_byte
  157.         mov     bh, al
  158.         cmp     byte [esi], cl
  159.         jne     .err
  160.         inc     esi
  161.  
  162.         shl     ebx, 16
  163.  
  164.         call    ascii_to_byte
  165.         mov     bl, al
  166.         cmp     byte [esi], cl
  167.         jne     .err
  168.         inc     esi
  169.  
  170.         call    ascii_to_byte
  171.         mov     bh, al
  172.  
  173.         ror     ebx, 16
  174.         ret
  175.  
  176.   .err:
  177.         xor     ebx, ebx
  178.         ret
  179.  
  180. align 4         ; esi = ptr to str, output in eax
  181. ascii_to_byte:
  182.  
  183.         xor     eax, eax
  184.         push    ebx
  185.  
  186.   .loop:
  187.         movzx   ebx, byte[esi]
  188.         sub     bl, '0'
  189.         jb      .done
  190.         cmp     bl, 9
  191.         ja      .done
  192.         lea     eax, [eax*4 + eax]      ;
  193.         shl     eax, 1                  ; eax = eax * 10
  194.         add     eax, ebx
  195.         inc     esi
  196.  
  197.         jmp     .loop
  198.  
  199.   .done:
  200.         pop     ebx
  201.         ret
  202.  
  203. align 4
  204. dword_to_ascii: ; edi = ptr where to write, eax is number
  205.  
  206.         push    edx ebx ecx
  207.         mov     ebx, 10
  208.         xor     ecx, ecx
  209.  
  210.        @@:
  211.         xor     edx, edx
  212.         div     ebx
  213.         add     edx, '0'
  214.         pushw   dx
  215.         inc     ecx
  216.         test    eax, eax
  217.         jnz     @r
  218.  
  219.        @@:
  220.         popw    ax
  221.         stosb
  222.         dec     ecx
  223.         jnz     @r
  224.  
  225.         pop     ecx ebx edx
  226.         ret
  227.  
  228. align 4
  229. create_path:            ; combine home_dir and work_dir strings into fpath
  230.  
  231.         lea     edi, [ebp + thread_data.fpath]
  232.         lea     esi, [ebp + thread_data.home_dir]
  233.         mov     ecx, 1024
  234.   .loop1:
  235.         lodsb
  236.         cmp     al, 0x20
  237.         jb      .next
  238.         stosb
  239.         loop    .loop1
  240.   .next:
  241.  
  242.         cmp     byte[edi-1], '/'
  243.         jne     @f
  244.         dec     edi
  245.        @@:
  246.  
  247.         lea     esi, [ebp + thread_data.work_dir]
  248.         mov     ecx, 1024
  249.   .loop2:
  250.         lodsb
  251.         cmp     al, 0x20
  252.         jb      .done
  253.         stosb
  254.         loop    .loop2
  255.  
  256.   .done:
  257.         xor     al, al
  258.         stosb
  259.         ret
  260.  
  261.  
  262. align 4
  263. nextpasvport:
  264.  
  265.         inc     [pasv_port]
  266.  
  267.         mov     ax, [pasv_port]
  268.         cmp     ax, [pasv_start]
  269.         jb      .restart
  270.         cmp     ax, [pasv_end]
  271.         ja      .restart
  272.  
  273.         ret
  274.  
  275.   .restart:
  276.         pushw   [pasv_start]
  277.         popw    [pasv_port]
  278.  
  279.         ret
  280.  
  281.  
  282. 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, [ebx + FileInfoA.FileSizeLow]
  535.         call    dword_to_ascii
  536.         mov     al, ' '
  537.         stosb
  538.  
  539. ; then date (month/day/year)
  540.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.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 + FileDateTime.day]
  548.         call    dword_to_ascii
  549.         mov     al, ' '
  550.         stosb
  551.  
  552.         movzx   eax, [ebx + FileInfoA.DateModify + FileDateTime.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.         pushw   [pasv_port]
  724.         popw    [ebp + thread_data.datasock.sin_port]
  725.  
  726.         mcall   bind
  727.         cmp     eax, -1
  728.         je      .next_port
  729.  
  730. ; And set it to listen!
  731.         mcall   listen, , 1
  732.         cmp     eax, -1
  733.         je      socketerror
  734.  
  735. ; Tell our thread we are ready to accept incoming calls
  736.         mov     [ebp + thread_data.mode], MODE_PASSIVE_WAIT
  737.  
  738. ; Now tell the client where to connect to in this format:
  739. ; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
  740. ; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
  741.  
  742. ; '227 ('
  743.         lea     edi, [ebp + thread_data.buffer]
  744.         mov     eax, '227 '
  745.         stosd
  746.         mov     al, '('
  747.         stosb
  748. ; ip
  749.         movzx   eax, byte [serverip]
  750.         call    dword_to_ascii
  751.         mov     al, ','
  752.         stosb
  753.         movzx   eax, byte [serverip+1]
  754.         call    dword_to_ascii
  755.         mov     al, ','
  756.         stosb
  757.         movzx   eax, byte [serverip+2]
  758.         call    dword_to_ascii
  759.         mov     al, ','
  760.         stosb
  761.         movzx   eax, byte [serverip+3]
  762.         call    dword_to_ascii
  763.         mov     al, ','
  764.         stosb
  765. ; port
  766.         movzx   eax, byte [ebp + thread_data.datasock.sin_port + 1]
  767.         call    dword_to_ascii
  768.         mov     al, ','
  769.         stosb
  770.         movzx   eax, byte [ebp + thread_data.datasock.sin_port]
  771.         call    dword_to_ascii
  772. ; ')', 13, 10, 0
  773.         mov     eax, ')' + 0x000a0d00
  774.         stosd
  775.  
  776.         lea     esi, [edi - thread_data.buffer]
  777.         sub     esi, ebp
  778.         mov     ecx, [ebp + thread_data.socketnum]
  779.         lea     edx, [ebp + thread_data.buffer]
  780.         xor     edi, edi
  781.         mcall   send
  782.  
  783.         ret
  784.  
  785. ;------------------------------------------------
  786. ; "PWD"
  787. ;
  788. ; Print the current working directory.
  789. ;
  790. ;------------------------------------------------
  791. align 4
  792. cmdPWD:
  793.  
  794.         mov     dword [ebp + thread_data.buffer], '257 '
  795.         mov     byte [ebp + thread_data.buffer+4], '"'
  796.  
  797.         lea     edi, [ebp + thread_data.buffer+5]
  798.         lea     esi, [ebp + thread_data.work_dir]
  799.         mov     ecx, 1024
  800.   .loop:
  801.         lodsb
  802.         or      al, al
  803.         jz      .ok
  804.         stosb
  805.         dec     ecx
  806.         jnz     .loop
  807.  
  808.   .ok:
  809.         mov     dword [edi], '"' + 0x000a0d00    ; '"',13,10,0
  810.         lea     esi, [edi - thread_data.buffer + 4]
  811.         sub     esi, ebp
  812.         mov     ecx, [ebp + thread_data.socketnum]
  813.         lea     edx, [ebp + thread_data.buffer]
  814.         xor     edi, edi
  815.         mcall   send
  816.  
  817. ; Print the new working dir on the console
  818.         lea     eax, [ebp + thread_data.work_dir]
  819.         invoke  con_write_asciiz, eax
  820.         invoke  con_write_asciiz, str_newline
  821.  
  822.         ret
  823.  
  824. ;------------------------------------------------
  825. ; "PORT"
  826. ;
  827. ; Initiate an active dataconnection.
  828. ;
  829. ;------------------------------------------------
  830. align 4
  831. cmdPORT:
  832.  
  833. ; PORT a1,a2,a3,a4,p1,p2
  834. ; IP address a1.a2.a3.a4, port p1*256+p2
  835.  
  836. ; Convert the IP
  837.         lea     esi, [esi+5]
  838.         mov     cl, ','
  839.         call    ip_to_dword
  840. ; And put it in datasock
  841.         mov     [ebp + thread_data.datasock.sin_addr], ebx
  842.  
  843. ; Now the same with portnumber
  844.         inc     esi
  845.         call    ascii_to_byte
  846.         mov     bh, al
  847.         inc     esi
  848.         call    ascii_to_byte
  849.         mov     bl, al
  850.  
  851. ; Save it in datasock too
  852.         mov     [ebp + thread_data.datasock.sin_port], bx
  853.  
  854. ; We will open the socket, but do not connect yet!
  855.         mov     [ebp + thread_data.datasock.sin_family], AF_INET4
  856.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  857.         cmp     eax, -1
  858.         je      socketerror
  859.  
  860.         mov     [ebp + thread_data.datasocketnum], eax
  861.         mov     [ebp + thread_data.mode], MODE_ACTIVE
  862.  
  863.         sendFTP "225 Data connection open"
  864.         ret
  865.  
  866. ;------------------------------------------------
  867. ; "QUIT"
  868. ;
  869. ; Close the connection with client.
  870. ;
  871. ;------------------------------------------------
  872. align 4
  873. cmdQUIT:
  874.  
  875.         sendFTP "221 Bye!"
  876.         mcall   close, [ebp + thread_data.datasocketnum]
  877.         mcall   close, [ebp + thread_data.socketnum]
  878.  
  879.         add     esp, 4          ; get rid of call return address
  880.         jmp     thread_exit     ; now close this thread
  881.  
  882.  
  883. ;------------------------------------------------
  884. ; "RETR"
  885. ;
  886. ; Retrieve a file from the ftp server.
  887. ;
  888. ;------------------------------------------------
  889. align 4
  890. cmdRETR:
  891.  
  892.         test    [ebp + thread_data.permissions], PERMISSION_READ
  893.         jz      permission_denied
  894.  
  895.         cmp     ecx, 1024 + 5
  896.         jae     .cannot_open
  897.  
  898.         sub     ecx, 5
  899.         jb      .cannot_open
  900.  
  901.         call    open_datasock
  902.  
  903.         call    create_path
  904.         dec     edi
  905.         lea     esi, [ebp + thread_data.buffer + 5]
  906.         mov     ecx, 1024
  907.         cmp     byte [esi], '/'
  908.         jne     .loop
  909.         inc     esi
  910.   .loop:
  911.         lodsb
  912.         cmp     al, 0x20
  913.         jl      .done
  914.         stosb
  915.         loop    .loop
  916.   .done:
  917.         xor     al, al
  918.         stosb
  919.  
  920.         lea     ebx, [ebp + thread_data.fpath]
  921.         invoke  con_write_asciiz, ebx
  922.         invoke  con_write_asciiz, str_newline
  923.  
  924.         invoke  file.open, ebx, O_READ
  925.         test    eax, eax
  926.         jz      .cannot_open
  927.  
  928.         push    eax
  929.         sendFTP "150 Here it comes.."
  930.         pop     ebx
  931.  
  932.   .read_more:
  933.         test    [ebp + thread_data.permissions], ABORT
  934.         jnz     abort_transfer
  935.  
  936.         lea     eax, [ebp + thread_data.buffer]                 ; FIXME: use another buffer!! if we receive something on control connection now, we screw up!
  937.         invoke  file.read, ebx, eax, BUFFERSIZE
  938.         cmp     eax, -1
  939.         je      .cannot_open                                    ; FIXME: this is not the correct error
  940.  
  941.         invoke  con_write_asciiz, str2
  942.  
  943.         push    eax ebx
  944.         mov     esi, eax
  945.         mov     ecx, [ebp + thread_data.datasocketnum]
  946.         lea     edx, [ebp + thread_data.buffer]
  947.         xor     edi, edi
  948.         mcall   send
  949.         pop     ebx ecx
  950.         cmp     eax, -1
  951.         je      socketerror                                     ; FIXME: not the correct error
  952.  
  953. ;        cmp     eax, ecx
  954. ;        jne     not_all_byes_sent                               ; TODO
  955.  
  956.         cmp     ecx, BUFFERSIZE
  957.         je      .read_more
  958.  
  959.         invoke  file.close, ebx
  960.  
  961.         invoke  con_write_asciiz, str2b
  962.  
  963.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  964.         mcall   close, [ebp + thread_data.datasocketnum]
  965.  
  966.         sendFTP "226 Transfer OK, closing connection"
  967.         ret
  968.  
  969.   .cannot_open:
  970.         invoke  con_set_flags, 0x0c
  971.         invoke  con_write_asciiz, str_notfound
  972.         invoke  con_set_flags, 0x07
  973.  
  974.         sendFTP "550 No such file"
  975.         ret
  976.  
  977.  
  978.  
  979. ;------------------------------------------------
  980. ; "STOR"
  981. ;
  982. ; Store a file on the server.
  983. ;
  984. ;------------------------------------------------
  985. align 4
  986. cmdSTOR:
  987.  
  988.         test    [ebp + thread_data.permissions], PERMISSION_WRITE
  989.         jz      permission_denied
  990.  
  991.  
  992. ;;;;
  993.         test    [ebp + thread_data.permissions], ABORT
  994.         jnz     abort_transfer
  995.  
  996. ;;;;
  997.  
  998.         ret
  999.  
  1000. ;------------------------------------------------
  1001. ; "SYST"
  1002. ;
  1003. ; Send information about the system.
  1004. ;
  1005. ;------------------------------------------------
  1006. align 4
  1007. cmdSYST:
  1008.  
  1009.         sendFTP "215 UNIX type: L8"
  1010.         ret
  1011.  
  1012. ;------------------------------------------------
  1013. ; "TYPE"
  1014. ;
  1015. ; Choose the file transfer type.
  1016. ;
  1017. ;------------------------------------------------
  1018. align 4
  1019. cmdTYPE:
  1020.  
  1021.         cmp     ecx, 6
  1022.         jb      parse_cmd.error
  1023.  
  1024.         mov     al, byte[esi+5]
  1025.         and     al, not 0x20
  1026.  
  1027.         cmp     al, 'A'
  1028.         je      .ascii
  1029.         cmp     al, 'E'
  1030.         je      .ebdic
  1031.         cmp     al, 'I'
  1032.         je      .image
  1033.         cmp     al, 'L'
  1034.         je      .local
  1035.  
  1036.         jmp     parse_cmd.error
  1037.  
  1038.   .ascii:
  1039.         mov     [ebp + thread_data.type], TYPE_ASCII
  1040.         jmp     .subtype
  1041.  
  1042.   .ebdic:
  1043.         mov     [ebp + thread_data.type], TYPE_EBDIC
  1044.  
  1045.   .subtype:
  1046.         cmp     ecx, 8
  1047.         jb      .non_print
  1048.  
  1049.         mov     al, byte[esi+7]
  1050.         and     al, not 0x20
  1051.  
  1052.         cmp     al, 'N'
  1053.         je      .non_print
  1054.         cmp     al, 'T'
  1055.         je      .telnet
  1056.         cmp     al, 'C'
  1057.         je      .asacc
  1058.         cmp     al, 0x20
  1059.         jb      .non_print
  1060.  
  1061.         jmp     parse_cmd.error
  1062.  
  1063.   .non_print:
  1064.         or      [ebp + thread_data.type], TYPE_NP
  1065.         jmp     .ok
  1066.  
  1067.   .telnet:
  1068.         or      [ebp + thread_data.type], TYPE_TELNET
  1069.         jmp     .ok
  1070.  
  1071.   .asacc:
  1072.         or      [ebp + thread_data.type], TYPE_ASA
  1073.         jmp     .ok
  1074.  
  1075.   .image:
  1076.         mov     [ebp + thread_data.type], TYPE_IMAGE
  1077.         jmp     .ok
  1078.  
  1079.   .local:
  1080.         cmp     ecx, 8
  1081.         jb      parse_cmd.error
  1082.  
  1083.         mov     al, byte[esi+7]
  1084.         sub     al, '0'
  1085.         jb      parse_cmd.error                         ; FIXME: this is not the correct errormessage
  1086.         cmp     al, 9
  1087.         ja      parse_cmd.error                         ; FIXME
  1088.         or      al, TYPE_LOCAL
  1089.         mov     [ebp + thread_data.type], al
  1090.  
  1091.   .ok:
  1092.         sendFTP "200 Command ok"
  1093.         ret
  1094.  
  1095. ;------------------------------------------------
  1096. ; "USER"
  1097. ;
  1098. ; Login to the server, step one of two.                         ;;; TODO: prevent buffer overflow!
  1099. ;
  1100. ;------------------------------------------------
  1101. align 4
  1102. cmdUSER:
  1103.  
  1104.         lea     esi, [esi + 5]
  1105.         lea     edi, [ebp + thread_data.fpath]                  ; temp buffer for username
  1106.   .loop:
  1107.         lodsb
  1108.         stosb
  1109.         cmp     al, 0x20
  1110.         jae     .loop
  1111.         mov     byte [edi-1], 0
  1112.  
  1113.         lea     esi, [ebp + thread_data.fpath]
  1114.         lea     eax, [ebp + thread_data.home_dir]
  1115.         invoke  ini.get_str, path2, esi, str_home, eax, 1024, str_infinity
  1116.         cmp     eax, -1
  1117.         je      .login_fail
  1118.         cmp     dword [esi], -1
  1119.         je      .login_fail
  1120.  
  1121.         mov     word [ebp + thread_data.work_dir], "/"          ; "/", 0
  1122.  
  1123.         invoke  con_write_asciiz, str_logged_in
  1124.         mov     [ebp + thread_data.state], STATE_LOGIN
  1125.   .sendstr:
  1126.         sendFTP "331 Please specify the password"
  1127.         ret
  1128.  
  1129.   .login_fail:
  1130.         invoke  con_write_asciiz, str_pass_err
  1131.         mov     [ebp + thread_data.state], STATE_LOGIN_FAIL
  1132.         jmp     .sendstr
  1133.  
  1134. align 4
  1135.   .2:
  1136.         sendFTP "530 Can't change to another user"
  1137.         ret
  1138.