Subversion Repositories Kolibri OS

Rev

Rev 3562 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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