Subversion Repositories Kolibri OS

Rev

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