Subversion Repositories Kolibri OS

Rev

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