diff --git a/kernel/branches/net/applications/ftpd/commands.inc b/kernel/branches/net/applications/ftpd/commands.inc index e7b2297bd4..c1252f48aa 100644 --- a/kernel/branches/net/applications/ftpd/commands.inc +++ b/kernel/branches/net/applications/ftpd/commands.inc @@ -4,9 +4,10 @@ struct thread_data rb 1024 stack rb 0 - home_dir rb 1024 - work_dir rb 1024 - fpath rb 1024*3 ; Will also be used to temporarily store username + home_dir rb 1024 ; home directory in wich the user is locked, asciiz + work_dir rb 1024 ; working directory, must at all times begin and end with a '/', asciiz + fpath rb 1024*3 ; file path, combination of home_dir, work_dir and filename + ; Will also be used to temporarily store username type db ? ; ASCII/EBDIC/IMAGE/.. mode db ? ; active/passive @@ -14,7 +15,7 @@ struct thread_data state dd ? ; disconnected/logging in/logged in/.. passivesocknum dd ? ; when in passive mode, this is the listening socket datasocketnum dd ? ; socket used for data transfers - permissions dd ? + permissions dd ? ; read/write/execute/.... buffer_ptr dd ? datasock sockaddr_in @@ -266,6 +267,27 @@ create_path: ; combine home_dir and work_dir strings into fpath stosb ret + +align 4 +nextpasvport: + + inc [pasv_port] + + mov ax, [pasv_port] + cmp ax, [pasv_start] + jb .restart + cmp ax, [pasv_end] + ja .restart + + ret + + .restart: + pushw [pasv_start] + popw [pasv_port] + + ret + + ;------------------------------------------------ ; "ABOR" ; @@ -291,29 +313,31 @@ cmdCDUP: test [ebp + thread_data.permissions], PERMISSION_CD jz permission_denied - cmp byte [ebp + thread_data.work_dir+1], 0 ; are we in "/" ? - je .done + cmp byte [ebp + thread_data.work_dir+1], 0 ; are we in "/" ? + je .done ; if so, we cant go up.. +; find the end of asciiz string work_dir mov ecx, 1024 xor al, al lea edi, [ebp + thread_data.work_dir] repne scasb +; return 2 characters (right before last /) sub edi, 3 +; and now search backwards, for a '/' mov al,'/' - std neg ecx add ecx, 1024 + std repne scasb cld - mov byte[edi+1], 0 +; terminate the string here + mov byte[edi+2], 0 .done: ; Print the new working dir on the console lea eax, [ebp + thread_data.work_dir] - push eax - call [con_write_asciiz] - push str_newline - call [con_write_asciiz] + invoke con_write_asciiz, eax + invoke con_write_asciiz, str_newline sendFTP "250 Command succesul" ret @@ -330,44 +354,40 @@ cmdCWD: test [ebp + thread_data.permissions], PERMISSION_CD jz permission_denied +; do we have enough parameters? sub ecx, 4 - jb .err - add esi, 4 + jbe .err +; get ready to copy the path + add esi, 4 mov ecx, 1024 lea edi, [ebp + thread_data.work_dir] - cmp byte [esi], '/' - je .loop - .scan: - lea edi, [ebp + thread_data.work_dir + 1] - push ecx - mov ecx, 1024 +; if received dir starts with '/', we will simply copy it +; If not, we will append the current path with the received path. + cmp byte [esi], '/' + je .copyloop + +; Find the end of work_dir string. + xor al, al .find_zero: - cmp byte [edi], 0 - je .found_zero - inc edi - loop .find_zero - .found_zero: - pop ecx - .scan2: + repne scasb + dec edi - cmp byte [esi], '/' - jne @f - inc esi - dec ecx - jz .done - @@: +; and now append work_dir with received string + mov ecx, 1024 - .loop: +; scan for end byte, or '.' + .copyloop: lodsb cmp al, 0x20 jb .done - cmp al, '.' - je .up - .continue: +;;; cmp al, '.' ; '..' means we must go up one dir TODO +;;; je .up stosb - loop .loop + loop .copyloop + +; now, now make sure it ends with '/', 0 .done: cmp byte [edi-1], '/' je @f @@ -378,24 +398,12 @@ cmdCWD: ; Print the new working dir on the console lea eax, [ebp + thread_data.work_dir] - push eax - call [con_write_asciiz] - push str_newline - call [con_write_asciiz] + invoke con_write_asciiz, eax + invoke con_write_asciiz, str_newline sendFTP "250 Command succesful" ret - .up: - lodsb - cmp al, '.' - jne .continue - -;;;; TODO: find second last '\' in work_dir and make next char zero -;;;; point edi to that 0 - - jmp .scan2 - .err: sendFTP "550 Directory does not exist" ret @@ -426,17 +434,44 @@ cmdLIST: test [ebp + thread_data.permissions], PERMISSION_EXEC jz permission_denied + cmp [ebp + thread_data.mode], MODE_PASSIVE_OK + je .start + ; If we are in active mode, it's time to open a data socket.. cmp [ebp + thread_data.mode], MODE_ACTIVE - jne @f + jne .not_active mov ecx, [ebp + thread_data.datasocketnum] lea edx, [ebp + thread_data.datasock] mov esi, sizeof.thread_data.datasock mcall connect cmp eax, -1 je socketerror - @@: + jmp .start +; If we are still in passive_wait, it's time we accept an incomming call.. + .not_active: + cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT + jne socketerror + mov [ebp + thread_data.mode], MODE_PASSIVE_FAILED ; assume that we will fail + .try_now: + mov ecx, [ebp + thread_data.passivesocknum] + lea edx, [ebp + thread_data.datasock] + mov esi, sizeof.thread_data.datasock + mcall accept + cmp eax, -1 + jne .pasv_ok + mcall 23, 200 + mcall accept + cmp eax, -1 + je socketerror + .pasv_ok: + mov [ebp + thread_data.datasocketnum], eax + mov [ebp + thread_data.mode], MODE_PASSIVE_OK + mcall close ; [ebp + thread_data.passivesocknum] + mov [ebp + thread_data.passivesocknum], -1 + invoke con_write_asciiz, str_datasock + + .start: ; Create fpath from home_dir and work_dir call create_path @@ -606,27 +641,31 @@ cmdNOOP: ;------------------------------------------------ align 4 cmdPASS: - lea esi, [esi + 5] ; read the password from users.ini lea edi, [ebp + thread_data.buffer + 512] ; temp pass + mov byte [edi], 0 lea ebx, [ebp + thread_data.fpath] ; temp username invoke ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity - test eax, eax + test eax, eax ; unable to read password? fail! jnz .incorrect - cmp dword [edi], -1 + cmp dword [edi], -1 ; no key, section or file found.. fail! je .incorrect - cmp byte[edi], 0 - je .pass_ok + cmp byte [edi], 0 ; zero password? ok! + je .ok + + add esi, 5 + sub ecx, 5 + jbe .incorrect ; no password given? but hey, we need one! fail.. ; compare with received password repe cmpsb - cmp byte [esi], 0x20 + cmp byte [esi-1], 0x20 ; printeable characters left? jae .incorrect - cmp byte [edi], 0 + cmp byte [edi-1], 0 jne .incorrect - .pass_ok: + .ok: invoke ini.get_int, path2, ebx, str_mode, 0 mov [ebp + thread_data.permissions], eax @@ -637,16 +676,15 @@ cmdPASS: .2: .incorrect: - mov [ebp + thread_data.state], STATE_CONNECTED + invoke con_write_asciiz, str_pass_err + mov [ebp + thread_data.state], STATE_CONNECTED ; reset state sendFTP "530 Login incorrect" ret -align 4 .0: sendFTP "503 Login with USER first" ret -align 4 .3: sendFTP "230 Already logged in" ret @@ -660,6 +698,11 @@ align 4 align 4 cmdPASV: + cmp [ebp + thread_data.passivesocknum], -1 + je @f + mcall close, [ebp + thread_data.passivesocknum] ; if there is still a socket open, close it + @@: + ; Open a new TCP socket mcall socket, AF_INET4, SOCK_STREAM, 0 cmp eax, -1 @@ -668,22 +711,25 @@ cmdPASV: ; Bind it to a known local port mov [ebp + thread_data.datasock.sin_family], AF_INET4 - pushw [pasvport] - popw [ebp + thread_data.datasock.sin_port] - inc [pasvport] mov [ebp + thread_data.datasock.sin_addr], 0 mov ecx, eax ; passivesocketnum lea edx, [ebp + thread_data.datasock] mov esi, sizeof.thread_data.datasock + + .next_port: ; TODO: break the endless loop + call nextpasvport + pushw [pasv_port] + popw [ebp + thread_data.datasock.sin_port] + mcall bind cmp eax, -1 -; je bind_err ; TODO + je .next_port ; And set it to listen! mcall listen, , 1 cmp eax, -1 -; je listen_err ; TODO + je socketerror ; Tell our thread we are ready to accept incoming calls mov [ebp + thread_data.mode], MODE_PASSIVE_WAIT @@ -694,24 +740,24 @@ cmdPASV: ; '227 (' lea edi, [ebp + thread_data.buffer] - mov eax, '227 ' ; FIXME (now hardcoded to 127.0.0.1:2000) + mov eax, '227 ' stosd mov al, '(' stosb ; ip - mov eax, 127 + movzx eax, byte [serverip] call dword_to_ascii mov al, ',' stosb - mov eax, 0 + movzx eax, byte [serverip+1] call dword_to_ascii mov al, ',' stosb - mov eax, 0 + movzx eax, byte [serverip+2] call dword_to_ascii mov al, ',' stosb - mov eax, 1 + movzx eax, byte [serverip+3] call dword_to_ascii mov al, ',' stosb @@ -851,24 +897,50 @@ cmdRETR: sub ecx, 5 jb .cannot_open + cmp [ebp + thread_data.mode], MODE_PASSIVE_OK + je .start + +; If we are in active mode, it's time to open a data socket.. cmp [ebp + thread_data.mode], MODE_ACTIVE - jne @f - push ecx esi + jne .not_active mov ecx, [ebp + thread_data.datasocketnum] lea edx, [ebp + thread_data.datasock] mov esi, sizeof.thread_data.datasock mcall connect - pop esi ecx cmp eax, -1 je socketerror - @@: + jmp .start - push ecx esi +; If we are still in passive_wait, it's time we accept an incomming call.. + .not_active: + cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT + jne socketerror + mov [ebp + thread_data.mode], MODE_PASSIVE_FAILED ; assume that we will fail + .try_now: + mov ecx, [ebp + thread_data.passivesocknum] + lea edx, [ebp + thread_data.datasock] + mov esi, sizeof.thread_data.datasock + mcall accept + cmp eax, -1 + jne .pasv_ok + mcall 23, 200 + mcall accept + cmp eax, -1 + je socketerror + .pasv_ok: + mov [ebp + thread_data.datasocketnum], eax + mov [ebp + thread_data.mode], MODE_PASSIVE_OK + mcall close ; [ebp + thread_data.passivesocknum] + mov [ebp + thread_data.passivesocknum], -1 + invoke con_write_asciiz, str_datasock + + .start: call create_path - pop esi ecx dec edi add esi, 5 + lea esi, [ebp + thread_data.buffer] ; FIXME + mov ecx, 1024 .loop: lodsb cmp al, 0x20 @@ -929,7 +1001,6 @@ cmdRETR: invoke con_write_asciiz, str_notfound invoke con_set_flags, 0x07 - mov edx, [ebp] sendFTP "550 No such file" ret @@ -1084,7 +1155,7 @@ cmdUSER: ret .login_fail: - invoke con_write_asciiz, str_login_invalid + invoke con_write_asciiz, str_pass_err mov [ebp + thread_data.state], STATE_LOGIN_FAIL jmp .sendstr diff --git a/kernel/branches/net/applications/ftpd/ftpd.asm b/kernel/branches/net/applications/ftpd/ftpd.asm index bb2d6f95aa..db3f31a22e 100644 --- a/kernel/branches/net/applications/ftpd/ftpd.asm +++ b/kernel/branches/net/applications/ftpd/ftpd.asm @@ -102,6 +102,7 @@ start: invoke ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0 mov esi, ini_buf + mov cl, '.' call ip_to_dword mov [serverip], ebx @@ -138,7 +139,10 @@ start: invoke con_write_asciiz, str2b - mov [pasvport], 2000 ;;;;;; FIXME + invoke ini.get_int, path, str_pasv, str_start, 2000 + mov [pasv_start], ax + invoke ini.get_int, path, str_pasv, str_end, 5000 + mov [pasv_end], ax mainloop: mcall 10 ; Wait here for incoming connections on the base socket (socketnum) @@ -163,7 +167,7 @@ threadstart: invoke con_write_asciiz, str8 ; print on the console that we have created the new thread successfully invoke con_set_flags, 0x07 - mcall accept, [socketnum], sockaddr1, sockaddr1.length ; time to accept the awaiting connection.. + mcall accept, [socketnum], sockaddr1, sockaddr1.length ; time to accept the awaiting connection.. cmp eax, -1 je thread_exit mov [ebp + thread_data.socketnum], eax @@ -173,16 +177,16 @@ threadstart: mov [ebp + thread_data.mode], MODE_NOTREADY lea eax, [ebp + thread_data.buffer] mov [ebp + thread_data.buffer_ptr], eax + mov [ebp + thread_data.passivesocknum], -1 sendFTP "220 Welcome to KolibriOS FTP daemon" threadloop: mcall 10 - mov edx, [ebp] ; pointer to thread_data cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT jne .not_passive - mov [ebp + thread_data.mode], MODE_PASSIVE_FAILED ; assume that we will fail + mov [ebp + thread_data.mode], MODE_PASSIVE_FAILED ; assume that we will fail mov ecx, [ebp + thread_data.passivesocknum] lea edx, [ebp + thread_data.datasock] mov esi, sizeof.thread_data.datasock @@ -191,6 +195,8 @@ threadloop: je .not_passive mov [ebp + thread_data.datasocketnum], eax mov [ebp + thread_data.mode], MODE_PASSIVE_OK + mcall close ; [ebp + thread_data.passivesocknum] + mov [ebp + thread_data.passivesocknum], -1 invoke con_write_asciiz, str_datasock .not_passive: @@ -199,9 +205,9 @@ threadloop: mov edx, [ebp + thread_data.buffer_ptr] mov esi, sizeof.thread_data.buffer ;;; FIXME mcall recv - inc eax ; error? (-1) + inc eax ; error? (-1) jz threadloop - dec eax ; 0 bytes read? + dec eax ; 0 bytes read? jz threadloop mov edi, [ebp + thread_data.buffer_ptr] @@ -214,13 +220,13 @@ threadloop: jne threadloop ; We got a command! - mov byte [edi + 1], 0 ; append string with zero byte + mov byte [edi + 1], 0 ; append string with zero byte lea esi, [ebp + thread_data.buffer] mov ecx, [ebp + thread_data.buffer_ptr] sub ecx, esi - mov [ebp + thread_data.buffer_ptr], esi ; reset buffer ptr + mov [ebp + thread_data.buffer_ptr], esi ; reset buffer ptr - invoke con_set_flags, 0x02 ; print received data to console (in green color) + invoke con_set_flags, 0x02 ; print received data to console (in green color) invoke con_write_asciiz, str_newline invoke con_write_asciiz, esi invoke con_set_flags, 0x07 @@ -229,17 +235,17 @@ threadloop: jmp parse_cmd listen_err: - invoke con_set_flags, 0x0c ; print received data to console (in green color) + invoke con_set_flags, 0x0c ; print errors in red invoke con_write_asciiz, str3 jmp done bind_err: - invoke con_set_flags, 0x0c ; print received data to console (in green color) + invoke con_set_flags, 0x0c ; print errors in red invoke con_write_asciiz, str4 jmp done sock_err: - invoke con_set_flags, 0x0c ; print received data to console (in green color) + invoke con_set_flags, 0x0c ; print errors in red invoke con_write_asciiz, str6 jmp done @@ -251,12 +257,11 @@ exit: thread_exit: - invoke con_set_flags, 0x02 ; print received data to console (in green color) + invoke con_set_flags, 0x02 ; print thread info in blue invoke con_write_asciiz, str_bye - pop ecx ; get the thread_data pointer from stack - mcall 68, 13 ; free the memory - mcall -1 ; and kill the thread - + pop ecx ; get the thread_data pointer from stack + mcall 68, 13 ; free the memory + mcall -1 ; and kill the thread ; initialized data @@ -275,16 +280,13 @@ str_bye db 10,'Closing thread!',10,0 str_logged_in db 'Login ok',10,0 str_pass_ok db 'Password ok',10,0 +str_pass_err db 'Password/Username incorrect',10,0 str_pwd db 'Current directory is "%s"\n',0 str_err2 db 'ERROR: cannot open directory',10,0 str_datasock db 'Passive data socket connected!',10,0 str_notfound db 'ERROR: file not found',10,0 str_sockerr db 'ERROR: socket error',10,0 -str_login_invalid db 'Login invalid',10,0 - -str_test db 'test: %x ', 0 - str_newline db 10, 0 str_mask db '*', 0 str_infinity db 0xff, 0xff, 0xff, 0xff, 0 @@ -311,6 +313,9 @@ str_ip db 'ip', 0 str_pass db 'pass', 0 str_home db 'home', 0 str_mode db 'mode', 0 +str_pasv db 'pasv', 0 +str_start db 'start', 0 +str_end db 'end', 0 sockaddr1: @@ -369,7 +374,9 @@ diff16 "i_end", 0, $ path2 rb 1024 params rb 1024 serverip dd ? - pasvport dw ? + pasv_start dw ? + pasv_end dw ? + pasv_port dw ? ini_buf rb 3*4+3+1