Subversion Repositories Kolibri OS

Rev

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

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