Subversion Repositories Kolibri OS

Rev

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

  1. ;
  2. ; Kolibrios FTP Daemon
  3. ;
  4. ; hidnplayr@gmail.com
  5. ;
  6. ; GPLv2
  7. ;
  8.  
  9. BUFFERSIZE              = 8192
  10.  
  11. ; using multiple's of 4
  12. STATE_CONNECTED         = 4*0
  13. STATE_LOGIN             = 4*1
  14. STATE_LOGIN_FAIL        = 4*2           ; When an invalid username was given
  15. STATE_ACTIVE            = 4*3
  16.  
  17. TYPE_UNDEF              = 0
  18.  
  19. TYPE_ASCII              = 00000100b
  20. TYPE_EBDIC              = 00001000b
  21. ; subtypes for ascii & ebdic (np = default)
  22. TYPE_NP                 = 00000001b     ; non printable
  23. TYPE_TELNET             = 00000010b
  24. TYPE_ASA                = 00000011b
  25.  
  26. TYPE_IMAGE              = 01000000b     ; binary data
  27. TYPE_LOCAL              = 10000000b     ; bits per byte must be specified
  28.                                         ; lower 4 bits will hold this value
  29. MODE_NOTREADY           = 0
  30. MODE_ACTIVE             = 1
  31. MODE_PASSIVE_WAIT       = 2
  32. MODE_PASSIVE_OK         = 3
  33. MODE_PASSIVE_FAILED     = 4
  34.  
  35. PERMISSION_EXEC         = 1b            ; LIST
  36. PERMISSION_READ         = 10b
  37. PERMISSION_WRITE        = 100b
  38. PERMISSION_DELETE       = 1000b
  39. PERMISSION_CD           = 10000b        ; Change Directory
  40.  
  41. ABORT                   = 1 shl 31
  42.  
  43. format binary as ""
  44.  
  45. use32
  46.         db      'MENUET01'      ; signature
  47.         dd      1               ; header version
  48.         dd      start           ; entry point
  49.         dd      i_end           ; initialized size
  50.         dd      mem+0x1000      ; required memory
  51.         dd      mem+0x1000      ; stack pointer
  52.         dd      params          ; parameters
  53.         dd      path            ; path
  54.  
  55. include '../macros.inc'
  56. purge mov,add,sub
  57. include '../proc32.inc'
  58. include '../dll.inc'
  59. include '../struct.inc'
  60. include '../libio.inc'
  61.  
  62. include '../network.inc'
  63. include 'commands.inc'
  64.  
  65. start:
  66.         mcall   68, 11                  ; init heap
  67.         mcall   40, 1 shl 7             ; we only want network events
  68.  
  69. ; load libraries
  70.         stdcall dll.Load, @IMPORT
  71.         test    eax, eax
  72.         jnz     exit
  73.  
  74. ; find path to main settings file (ftpd.ini)
  75.         mov     edi, path               ; Calculate the length of zero-terminated string
  76.         xor     al, al
  77.         mov     ecx, 1024
  78.         repne   scasb
  79.         dec     edi
  80.         mov     esi, str_ini            ; append it with '.ini', 0
  81.         movsd
  82.         movsb
  83.  
  84. ; now create the second path (users.ini)
  85.         std
  86.         mov     al, '/'
  87.         repne   scasb
  88.         lea     ecx, [edi - path + 2]
  89.         cld
  90.         mov     esi, path
  91.         mov     edi, path2
  92.         rep     movsb
  93.         mov     esi, str_users
  94.         movsd
  95.         movsd
  96.         movsw
  97.  
  98. ; initialize console
  99.         invoke  con_start, 1
  100.         invoke  con_init, -1, -1, -1, -1, title
  101.  
  102.         invoke  ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0
  103.         mov     esi, ini_buf
  104.         mov     cl, '.'
  105.         call    ip_to_dword
  106.         mov     [serverip], ebx
  107.  
  108.         invoke  ini.get_int, path, str_ftpd, str_port, 21
  109.         mov     [sockaddr1.port], ax
  110.  
  111.         invoke  con_printf, str1, eax
  112.         add     esp, 8
  113.  
  114.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  115.         cmp     eax, -1
  116.         je      sock_err
  117.         mov     [socketnum], eax
  118.  
  119.         invoke  con_write_asciiz, str2
  120.  
  121. ;        mcall   setsockopt, [socketnum], SOL_SOCKET, SO_REUSEADDR, &yes,
  122. ;        cmp     eax, -1
  123. ;        je      opt_err
  124.  
  125.         mcall   bind, [socketnum], sockaddr1, sockaddr1.length
  126.         cmp     eax, -1
  127.         je      bind_err
  128.  
  129.         invoke  con_write_asciiz, str2
  130.  
  131.         invoke  ini.get_int, path, str_ftpd, str_conn, 1        ; Backlog (max connections)
  132.         mov     edx, eax
  133.  
  134.         invoke  con_write_asciiz, str2
  135.  
  136.         mcall   listen, [socketnum]
  137.         cmp     eax, -1
  138.         je      listen_err
  139.  
  140.         invoke  con_write_asciiz, str2b
  141.  
  142.         invoke  ini.get_int, path, str_pasv, str_start, 2000
  143.         mov     [pasv_start], ax
  144.         invoke  ini.get_int, path, str_pasv, str_end, 5000
  145.         mov     [pasv_end], ax
  146.  
  147.         mov     [alive], 1
  148.  
  149. mainloop:
  150.         mcall   23, 100                         ; Wait here for incoming connections on the base socket (socketnum)
  151.                                                 ; One second timeout, we will use this to check if console is still working
  152.  
  153.         test    eax, eax                        ; network event?
  154.         jz      .checkconsole
  155.  
  156.         mcall   51, 1, threadstart, 0           ; Start a new thread for every incoming connection
  157.                                                 ; NOTE: upon initialisation of the thread, stack will not be available!
  158.         jmp     mainloop
  159.  
  160.   .checkconsole:
  161.  
  162.         invoke  con_get_flags                   ; Is console still running?
  163.         test    eax, 0x0200
  164.         jz      mainloop
  165.         mcall   close, [socketnum]              ; kill the listening socket
  166.         mov     [alive], 0
  167.         mcall   -1                              ; and exit
  168.  
  169.         diff16  "threadstart", 0, $
  170.  
  171. threadstart:
  172. ;;;        mcall   68, 11                          ; init heap
  173.         mcall   68, 12, sizeof.thread_data      ; allocate the thread data struct
  174.         test    eax, eax
  175.         je      exit
  176.  
  177.         lea     esp, [eax + thread_data.stack]  ; init stack
  178.         mov     ebp, eax
  179.  
  180.         mcall   40, 1 shl 7                     ; we only want network events for this thread
  181.  
  182.         lea     ebx, [ebp + thread_data.buffer] ; get information about the current process
  183.         or      ecx, -1
  184.         mcall   9
  185.         mov     eax, dword [ebp + thread_data.buffer + 30]              ; PID is at offset 30
  186.         mov     [ebp + thread_data.pid], eax
  187.  
  188.         invoke  con_set_flags, 0x03
  189.         invoke  con_printf, str8, [ebp + thread_data.pid]               ; print on the console that we have created the new thread successfully
  190.         add     esp, 8                                                  ; balance stack
  191.         invoke  con_set_flags, 0x07
  192.  
  193.         mcall   accept, [socketnum], sockaddr1, sockaddr1.length        ; time to accept the awaiting connection..
  194.         cmp     eax, -1
  195.         je      thread_exit
  196.         mov     [ebp + thread_data.socketnum], eax
  197.  
  198.         mov     [ebp + thread_data.state], STATE_CONNECTED
  199.         mov     [ebp + thread_data.permissions], 0
  200.         mov     [ebp + thread_data.mode], MODE_NOTREADY
  201.         lea     eax, [ebp + thread_data.buffer]
  202.         mov     [ebp + thread_data.buffer_ptr], eax
  203.         mov     [ebp + thread_data.passivesocknum], -1
  204.  
  205.         sendFTP "220 Welcome to KolibriOS FTP daemon"
  206.  
  207.         diff16  "threadloop", 0, $
  208. threadloop:
  209. ; Check if our socket is still connected
  210.         mcall   send, [ebp + thread_data.socketnum], 0, 0       ; Try to send zero bytes, if socket is closed, this will return -1
  211.         cmp     eax, -1
  212.         je      thread_exit
  213.  
  214.         cmp     [alive], 0                                      ; Did main thread take a run for it?
  215.         je      thread_exit
  216.  
  217.         mcall   10                                              ; Wait for network event
  218.  
  219.         cmp     [ebp + thread_data.mode], MODE_PASSIVE_WAIT
  220.         jne     .not_passive
  221.         mov     ecx, [ebp + thread_data.passivesocknum]
  222.         lea     edx, [ebp + thread_data.datasock]
  223.         mov     esi, sizeof.thread_data.datasock
  224.         mcall   accept
  225.         cmp     eax, -1
  226.         je      .not_passive
  227.         mov     [ebp + thread_data.datasocketnum], eax
  228.         mov     [ebp + thread_data.mode], MODE_PASSIVE_OK
  229.         mcall   close   ; [ebp + thread_data.passivesocknum]
  230.         mov     [ebp + thread_data.passivesocknum], -1
  231.  
  232.         invoke  con_write_asciiz, str_datasock
  233.   .not_passive:
  234.  
  235.         mov     ecx, [ebp + thread_data.socketnum]
  236.         mov     edx, [ebp + thread_data.buffer_ptr]
  237.         mov     esi, sizeof.thread_data.buffer    ;;; FIXME
  238.         mcall   recv
  239.         inc     eax                                     ; error? (-1)
  240.         jz      threadloop
  241.         dec     eax                                     ; 0 bytes read?
  242.         jz      threadloop
  243.  
  244.         mov     edi, [ebp + thread_data.buffer_ptr]
  245.         add     [ebp + thread_data.buffer_ptr], eax
  246.  
  247. ; Check if we received a newline character, if not, wait for more data
  248.         mov     ecx, eax
  249.         mov     al, 13
  250.         repne   scasb
  251.         jne     threadloop
  252.  
  253. ; We got a command!
  254.         mov     byte [edi + 1], 0                       ; append string with zero byte
  255.         lea     esi, [ebp + thread_data.buffer]
  256.         mov     ecx, [ebp + thread_data.buffer_ptr]
  257.         sub     ecx, esi
  258.         mov     [ebp + thread_data.buffer_ptr], esi     ; reset buffer ptr
  259.  
  260.         invoke  con_set_flags, 0x02                     ; print received data to console (in green color)
  261.         invoke  con_write_asciiz, str_newline
  262.         invoke  con_write_asciiz, esi
  263.         invoke  con_set_flags, 0x07
  264.  
  265.         push    threadloop
  266.         jmp     parse_cmd
  267.  
  268. listen_err:
  269.         invoke  con_set_flags, 0x0c                     ; print errors in red
  270.         invoke  con_write_asciiz, str3
  271.         jmp     done
  272.  
  273. bind_err:
  274.         invoke  con_set_flags, 0x0c                     ; print errors in red
  275.         invoke  con_write_asciiz, str4
  276.         jmp     done
  277.  
  278. sock_err:
  279.         invoke  con_set_flags, 0x0c                     ; print errors in red
  280.         invoke  con_write_asciiz, str6
  281.         jmp     done
  282.  
  283. done:
  284.         invoke  con_exit, 0
  285. exit:
  286.         mcall   -1
  287.  
  288.  
  289. thread_exit:
  290.         invoke  con_set_flags, 0x03                             ; print thread info in blue
  291.         invoke  con_printf, str_bye, [ebp + thread_data.pid]    ; print on the console that we are about to kill the thread
  292.         add     esp, 8                                          ; balance stack
  293.         mcall   68, 13, ebp                                     ; free the memory
  294.         mcall   -1                                              ; and kill the thread
  295.  
  296.  
  297. ; initialized data
  298.  
  299. title           db 'KolibriOS FTP daemon 0.1', 0
  300. str1            db 'Starting FTP daemon on port %u.', 0
  301. str2            db '.', 0
  302. str2b           db ' OK!',10,0
  303. str3            db 'Listen error',10,0
  304. str4            db 10,'ERROR: local port is already in use.',10,0
  305. ;str5            db 'Setsockopt error.',10,10,0
  306. str6            db 'ERROR: Could not open socket.',10,0
  307. str7            db 'Got data!',10,10,0
  308. str8            db 10,'Thread %d created',10,0
  309. str_bye         db 10,'Thread %d killed',10,0
  310.  
  311. str_logged_in   db 'Login ok',10,0
  312. str_pass_ok     db 'Password ok',10,0
  313. str_pass_err    db 'Password/Username incorrect',10,0
  314. str_pwd         db 'Current directory is "%s"\n',0
  315. str_err2        db 'ERROR: cannot open the directory.',10,0
  316. str_datasock    db 'Passive data socket connected.',10,0
  317. str_notfound    db 'ERROR: file not found.',10,0
  318. str_sockerr     db 'ERROR: socket error.',10,0
  319.  
  320. str_newline     db 10, 0
  321. str_mask        db '*', 0
  322. str_infinity    db 0xff, 0xff, 0xff, 0xff, 0
  323.  
  324. months          dd 'Jan '
  325.                 dd 'Feb '
  326.                 dd 'Mar '
  327.                 dd 'Apr '
  328.                 dd 'May '
  329.                 dd 'Jun '
  330.                 dd 'Jul '
  331.                 dd 'Aug '
  332.                 dd 'Sep '
  333.                 dd 'Oct '
  334.                 dd 'Nov '
  335.                 dd 'Dec '
  336.  
  337. str_users       db 'users'
  338. str_ini         db '.ini', 0
  339. str_port        db 'port', 0
  340. str_ftpd        db 'ftpd', 0
  341. str_conn        db 'conn', 0
  342. str_ip          db 'ip', 0
  343. str_pass        db 'pass', 0
  344. str_home        db 'home', 0
  345. str_mode        db 'mode', 0
  346. str_pasv        db 'pasv', 0
  347. str_start       db 'start', 0
  348. str_end         db 'end', 0
  349.  
  350.  
  351. sockaddr1:
  352.                 dw AF_INET4
  353.   .port         dw 21
  354.   .ip           dd 0
  355.                 rb 10
  356.   .length       = $ - sockaddr1
  357.  
  358. ; import
  359.  
  360. align 4
  361. @IMPORT:
  362.  
  363. diff16 "import", 0, $
  364.  
  365. library console,                'console.obj',\
  366.         libini,                 'libini.obj', \
  367.         libio,                  'libio.obj'
  368.  
  369. import  console,\
  370.         con_start,              'START',\
  371.         con_init,               'con_init',\
  372.         con_write_asciiz,       'con_write_asciiz',\
  373.         con_exit,               'con_exit',\
  374.         con_gets,               'con_gets',\
  375.         con_cls,                'con_cls',\
  376.         con_printf,             'con_printf',\
  377.         con_getch2,             'con_getch2',\
  378.         con_set_cursor_pos,     'con_set_cursor_pos',\
  379.         con_set_flags,          'con_set_flags',\
  380.         con_get_flags,          'con_get_flags'
  381.  
  382. import  libini,\
  383.         ini.get_str,            'ini_get_str',\
  384.         ini.get_int,            'ini_get_int'
  385.  
  386. import  libio,\
  387.         libio.init,             'lib_init',\
  388.         file.size,              'file_size',\
  389.         file.open,              'file_open',\
  390.         file.read,              'file_read',\
  391.         file.close,             'file_close',\
  392.         file.find.first,        'file_find_first',\
  393.         file.find.next,         'file_find_next',\
  394.         file.find.close,        'file_find_close'
  395.  
  396.  
  397. i_end:
  398.  
  399. diff16 "i_end", 0, $
  400.  
  401. ; uninitialised data
  402.  
  403.         socketnum       dd ?
  404.         path            rb 1024
  405.         path2           rb 1024
  406.         params          rb 1024
  407.         serverip        dd ?
  408.         pasv_start      dw ?
  409.         pasv_end        dw ?
  410.         pasv_port       dw ?
  411.  
  412.         ini_buf         rb 3*4+3+1
  413.  
  414.         alive           db ?
  415.  
  416. mem:
  417.  
  418.  
  419.