More updates and bugfixes for FTPd (net branch)

git-svn-id: svn://kolibrios.org@2610 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2012-04-13 15:54:21 +00:00
parent ea68a6e1ce
commit 02ea12584c
2 changed files with 183 additions and 105 deletions

View File

@ -4,9 +4,10 @@ struct thread_data
rb 1024 rb 1024
stack rb 0 stack rb 0
home_dir rb 1024 home_dir rb 1024 ; home directory in wich the user is locked, asciiz
work_dir rb 1024 work_dir rb 1024 ; working directory, must at all times begin and end with a '/', asciiz
fpath rb 1024*3 ; Will also be used to temporarily store username 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/.. type db ? ; ASCII/EBDIC/IMAGE/..
mode db ? ; active/passive mode db ? ; active/passive
@ -14,7 +15,7 @@ struct thread_data
state dd ? ; disconnected/logging in/logged in/.. state dd ? ; disconnected/logging in/logged in/..
passivesocknum dd ? ; when in passive mode, this is the listening socket passivesocknum dd ? ; when in passive mode, this is the listening socket
datasocketnum dd ? ; socket used for data transfers datasocketnum dd ? ; socket used for data transfers
permissions dd ? permissions dd ? ; read/write/execute/....
buffer_ptr dd ? buffer_ptr dd ?
datasock sockaddr_in datasock sockaddr_in
@ -266,6 +267,27 @@ create_path: ; combine home_dir and work_dir strings into fpath
stosb stosb
ret 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" ; "ABOR"
; ;
@ -291,29 +313,31 @@ cmdCDUP:
test [ebp + thread_data.permissions], PERMISSION_CD test [ebp + thread_data.permissions], PERMISSION_CD
jz permission_denied jz permission_denied
cmp byte [ebp + thread_data.work_dir+1], 0 ; are we in "/" ? cmp byte [ebp + thread_data.work_dir+1], 0 ; are we in "/" ?
je .done je .done ; if so, we cant go up..
; find the end of asciiz string work_dir
mov ecx, 1024 mov ecx, 1024
xor al, al xor al, al
lea edi, [ebp + thread_data.work_dir] lea edi, [ebp + thread_data.work_dir]
repne scasb repne scasb
; return 2 characters (right before last /)
sub edi, 3 sub edi, 3
; and now search backwards, for a '/'
mov al,'/' mov al,'/'
std
neg ecx neg ecx
add ecx, 1024 add ecx, 1024
std
repne scasb repne scasb
cld cld
mov byte[edi+1], 0 ; terminate the string here
mov byte[edi+2], 0
.done: .done:
; Print the new working dir on the console ; Print the new working dir on the console
lea eax, [ebp + thread_data.work_dir] lea eax, [ebp + thread_data.work_dir]
push eax invoke con_write_asciiz, eax
call [con_write_asciiz] invoke con_write_asciiz, str_newline
push str_newline
call [con_write_asciiz]
sendFTP "250 Command succesul" sendFTP "250 Command succesul"
ret ret
@ -330,44 +354,40 @@ cmdCWD:
test [ebp + thread_data.permissions], PERMISSION_CD test [ebp + thread_data.permissions], PERMISSION_CD
jz permission_denied jz permission_denied
; do we have enough parameters?
sub ecx, 4 sub ecx, 4
jb .err jbe .err
add esi, 4
; get ready to copy the path
add esi, 4
mov ecx, 1024 mov ecx, 1024
lea edi, [ebp + thread_data.work_dir] lea edi, [ebp + thread_data.work_dir]
cmp byte [esi], '/'
je .loop
.scan: ; if received dir starts with '/', we will simply copy it
lea edi, [ebp + thread_data.work_dir + 1] ; If not, we will append the current path with the received path.
push ecx cmp byte [esi], '/'
mov ecx, 1024 je .copyloop
; Find the end of work_dir string.
xor al, al
.find_zero: .find_zero:
cmp byte [edi], 0 repne scasb
je .found_zero dec edi
inc edi
loop .find_zero
.found_zero:
pop ecx
.scan2:
cmp byte [esi], '/' ; and now append work_dir with received string
jne @f mov ecx, 1024
inc esi
dec ecx
jz .done
@@:
.loop: ; scan for end byte, or '.'
.copyloop:
lodsb lodsb
cmp al, 0x20 cmp al, 0x20
jb .done jb .done
cmp al, '.' ;;; cmp al, '.' ; '..' means we must go up one dir TODO
je .up ;;; je .up
.continue:
stosb stosb
loop .loop loop .copyloop
; now, now make sure it ends with '/', 0
.done: .done:
cmp byte [edi-1], '/' cmp byte [edi-1], '/'
je @f je @f
@ -378,24 +398,12 @@ cmdCWD:
; Print the new working dir on the console ; Print the new working dir on the console
lea eax, [ebp + thread_data.work_dir] lea eax, [ebp + thread_data.work_dir]
push eax invoke con_write_asciiz, eax
call [con_write_asciiz] invoke con_write_asciiz, str_newline
push str_newline
call [con_write_asciiz]
sendFTP "250 Command succesful" sendFTP "250 Command succesful"
ret 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: .err:
sendFTP "550 Directory does not exist" sendFTP "550 Directory does not exist"
ret ret
@ -426,17 +434,44 @@ cmdLIST:
test [ebp + thread_data.permissions], PERMISSION_EXEC test [ebp + thread_data.permissions], PERMISSION_EXEC
jz permission_denied 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.. ; If we are in active mode, it's time to open a data socket..
cmp [ebp + thread_data.mode], MODE_ACTIVE cmp [ebp + thread_data.mode], MODE_ACTIVE
jne @f jne .not_active
mov ecx, [ebp + thread_data.datasocketnum] mov ecx, [ebp + thread_data.datasocketnum]
lea edx, [ebp + thread_data.datasock] lea edx, [ebp + thread_data.datasock]
mov esi, sizeof.thread_data.datasock mov esi, sizeof.thread_data.datasock
mcall connect mcall connect
cmp eax, -1 cmp eax, -1
je socketerror 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 ; Create fpath from home_dir and work_dir
call create_path call create_path
@ -606,27 +641,31 @@ cmdNOOP:
;------------------------------------------------ ;------------------------------------------------
align 4 align 4
cmdPASS: cmdPASS:
lea esi, [esi + 5]
; read the password from users.ini ; read the password from users.ini
lea edi, [ebp + thread_data.buffer + 512] ; temp pass lea edi, [ebp + thread_data.buffer + 512] ; temp pass
mov byte [edi], 0
lea ebx, [ebp + thread_data.fpath] ; temp username lea ebx, [ebp + thread_data.fpath] ; temp username
invoke ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity 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 jnz .incorrect
cmp dword [edi], -1 cmp dword [edi], -1 ; no key, section or file found.. fail!
je .incorrect je .incorrect
cmp byte[edi], 0 cmp byte [edi], 0 ; zero password? ok!
je .pass_ok je .ok
add esi, 5
sub ecx, 5
jbe .incorrect ; no password given? but hey, we need one! fail..
; compare with received password ; compare with received password
repe cmpsb repe cmpsb
cmp byte [esi], 0x20 cmp byte [esi-1], 0x20 ; printeable characters left?
jae .incorrect jae .incorrect
cmp byte [edi], 0 cmp byte [edi-1], 0
jne .incorrect jne .incorrect
.pass_ok: .ok:
invoke ini.get_int, path2, ebx, str_mode, 0 invoke ini.get_int, path2, ebx, str_mode, 0
mov [ebp + thread_data.permissions], eax mov [ebp + thread_data.permissions], eax
@ -637,16 +676,15 @@ cmdPASS:
.2: .2:
.incorrect: .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" sendFTP "530 Login incorrect"
ret ret
align 4
.0: .0:
sendFTP "503 Login with USER first" sendFTP "503 Login with USER first"
ret ret
align 4
.3: .3:
sendFTP "230 Already logged in" sendFTP "230 Already logged in"
ret ret
@ -660,6 +698,11 @@ align 4
align 4 align 4
cmdPASV: 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 ; Open a new TCP socket
mcall socket, AF_INET4, SOCK_STREAM, 0 mcall socket, AF_INET4, SOCK_STREAM, 0
cmp eax, -1 cmp eax, -1
@ -668,22 +711,25 @@ cmdPASV:
; Bind it to a known local port ; Bind it to a known local port
mov [ebp + thread_data.datasock.sin_family], AF_INET4 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 [ebp + thread_data.datasock.sin_addr], 0
mov ecx, eax ; passivesocketnum mov ecx, eax ; passivesocketnum
lea edx, [ebp + thread_data.datasock] lea edx, [ebp + thread_data.datasock]
mov esi, sizeof.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 mcall bind
cmp eax, -1 cmp eax, -1
; je bind_err ; TODO je .next_port
; And set it to listen! ; And set it to listen!
mcall listen, , 1 mcall listen, , 1
cmp eax, -1 cmp eax, -1
; je listen_err ; TODO je socketerror
; Tell our thread we are ready to accept incoming calls ; Tell our thread we are ready to accept incoming calls
mov [ebp + thread_data.mode], MODE_PASSIVE_WAIT mov [ebp + thread_data.mode], MODE_PASSIVE_WAIT
@ -694,24 +740,24 @@ cmdPASV:
; '227 (' ; '227 ('
lea edi, [ebp + thread_data.buffer] lea edi, [ebp + thread_data.buffer]
mov eax, '227 ' ; FIXME (now hardcoded to 127.0.0.1:2000) mov eax, '227 '
stosd stosd
mov al, '(' mov al, '('
stosb stosb
; ip ; ip
mov eax, 127 movzx eax, byte [serverip]
call dword_to_ascii call dword_to_ascii
mov al, ',' mov al, ','
stosb stosb
mov eax, 0 movzx eax, byte [serverip+1]
call dword_to_ascii call dword_to_ascii
mov al, ',' mov al, ','
stosb stosb
mov eax, 0 movzx eax, byte [serverip+2]
call dword_to_ascii call dword_to_ascii
mov al, ',' mov al, ','
stosb stosb
mov eax, 1 movzx eax, byte [serverip+3]
call dword_to_ascii call dword_to_ascii
mov al, ',' mov al, ','
stosb stosb
@ -851,24 +897,50 @@ cmdRETR:
sub ecx, 5 sub ecx, 5
jb .cannot_open 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 cmp [ebp + thread_data.mode], MODE_ACTIVE
jne @f jne .not_active
push ecx esi
mov ecx, [ebp + thread_data.datasocketnum] mov ecx, [ebp + thread_data.datasocketnum]
lea edx, [ebp + thread_data.datasock] lea edx, [ebp + thread_data.datasock]
mov esi, sizeof.thread_data.datasock mov esi, sizeof.thread_data.datasock
mcall connect mcall connect
pop esi ecx
cmp eax, -1 cmp eax, -1
je socketerror 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 call create_path
pop esi ecx
dec edi dec edi
add esi, 5 add esi, 5
lea esi, [ebp + thread_data.buffer] ; FIXME
mov ecx, 1024
.loop: .loop:
lodsb lodsb
cmp al, 0x20 cmp al, 0x20
@ -929,7 +1001,6 @@ cmdRETR:
invoke con_write_asciiz, str_notfound invoke con_write_asciiz, str_notfound
invoke con_set_flags, 0x07 invoke con_set_flags, 0x07
mov edx, [ebp]
sendFTP "550 No such file" sendFTP "550 No such file"
ret ret
@ -1084,7 +1155,7 @@ cmdUSER:
ret ret
.login_fail: .login_fail:
invoke con_write_asciiz, str_login_invalid invoke con_write_asciiz, str_pass_err
mov [ebp + thread_data.state], STATE_LOGIN_FAIL mov [ebp + thread_data.state], STATE_LOGIN_FAIL
jmp .sendstr jmp .sendstr

View File

@ -102,6 +102,7 @@ start:
invoke ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0 invoke ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0
mov esi, ini_buf mov esi, ini_buf
mov cl, '.'
call ip_to_dword call ip_to_dword
mov [serverip], ebx mov [serverip], ebx
@ -138,7 +139,10 @@ start:
invoke con_write_asciiz, str2b 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: mainloop:
mcall 10 ; Wait here for incoming connections on the base socket (socketnum) 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_write_asciiz, str8 ; print on the console that we have created the new thread successfully
invoke con_set_flags, 0x07 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 cmp eax, -1
je thread_exit je thread_exit
mov [ebp + thread_data.socketnum], eax mov [ebp + thread_data.socketnum], eax
@ -173,16 +177,16 @@ threadstart:
mov [ebp + thread_data.mode], MODE_NOTREADY mov [ebp + thread_data.mode], MODE_NOTREADY
lea eax, [ebp + thread_data.buffer] lea eax, [ebp + thread_data.buffer]
mov [ebp + thread_data.buffer_ptr], eax mov [ebp + thread_data.buffer_ptr], eax
mov [ebp + thread_data.passivesocknum], -1
sendFTP "220 Welcome to KolibriOS FTP daemon" sendFTP "220 Welcome to KolibriOS FTP daemon"
threadloop: threadloop:
mcall 10 mcall 10
mov edx, [ebp] ; pointer to thread_data
cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT
jne .not_passive 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] mov ecx, [ebp + thread_data.passivesocknum]
lea edx, [ebp + thread_data.datasock] lea edx, [ebp + thread_data.datasock]
mov esi, sizeof.thread_data.datasock mov esi, sizeof.thread_data.datasock
@ -191,6 +195,8 @@ threadloop:
je .not_passive je .not_passive
mov [ebp + thread_data.datasocketnum], eax mov [ebp + thread_data.datasocketnum], eax
mov [ebp + thread_data.mode], MODE_PASSIVE_OK 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 invoke con_write_asciiz, str_datasock
.not_passive: .not_passive:
@ -199,9 +205,9 @@ threadloop:
mov edx, [ebp + thread_data.buffer_ptr] mov edx, [ebp + thread_data.buffer_ptr]
mov esi, sizeof.thread_data.buffer ;;; FIXME mov esi, sizeof.thread_data.buffer ;;; FIXME
mcall recv mcall recv
inc eax ; error? (-1) inc eax ; error? (-1)
jz threadloop jz threadloop
dec eax ; 0 bytes read? dec eax ; 0 bytes read?
jz threadloop jz threadloop
mov edi, [ebp + thread_data.buffer_ptr] mov edi, [ebp + thread_data.buffer_ptr]
@ -214,13 +220,13 @@ threadloop:
jne threadloop jne threadloop
; We got a command! ; 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] lea esi, [ebp + thread_data.buffer]
mov ecx, [ebp + thread_data.buffer_ptr] mov ecx, [ebp + thread_data.buffer_ptr]
sub ecx, esi 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, str_newline
invoke con_write_asciiz, esi invoke con_write_asciiz, esi
invoke con_set_flags, 0x07 invoke con_set_flags, 0x07
@ -229,17 +235,17 @@ threadloop:
jmp parse_cmd jmp parse_cmd
listen_err: 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 invoke con_write_asciiz, str3
jmp done jmp done
bind_err: 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 invoke con_write_asciiz, str4
jmp done jmp done
sock_err: 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 invoke con_write_asciiz, str6
jmp done jmp done
@ -251,12 +257,11 @@ exit:
thread_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 invoke con_write_asciiz, str_bye
pop ecx ; get the thread_data pointer from stack pop ecx ; get the thread_data pointer from stack
mcall 68, 13 ; free the memory mcall 68, 13 ; free the memory
mcall -1 ; and kill the thread mcall -1 ; and kill the thread
; initialized data ; initialized data
@ -275,16 +280,13 @@ str_bye db 10,'Closing thread!',10,0
str_logged_in db 'Login ok',10,0 str_logged_in db 'Login ok',10,0
str_pass_ok db 'Password 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_pwd db 'Current directory is "%s"\n',0
str_err2 db 'ERROR: cannot open directory',10,0 str_err2 db 'ERROR: cannot open directory',10,0
str_datasock db 'Passive data socket connected!',10,0 str_datasock db 'Passive data socket connected!',10,0
str_notfound db 'ERROR: file not found',10,0 str_notfound db 'ERROR: file not found',10,0
str_sockerr db 'ERROR: socket error',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_newline db 10, 0
str_mask db '*', 0 str_mask db '*', 0
str_infinity db 0xff, 0xff, 0xff, 0xff, 0 str_infinity db 0xff, 0xff, 0xff, 0xff, 0
@ -311,6 +313,9 @@ str_ip db 'ip', 0
str_pass db 'pass', 0 str_pass db 'pass', 0
str_home db 'home', 0 str_home db 'home', 0
str_mode db 'mode', 0 str_mode db 'mode', 0
str_pasv db 'pasv', 0
str_start db 'start', 0
str_end db 'end', 0
sockaddr1: sockaddr1:
@ -369,7 +374,9 @@ diff16 "i_end", 0, $
path2 rb 1024 path2 rb 1024
params rb 1024 params rb 1024
serverip dd ? serverip dd ?
pasvport dw ? pasv_start dw ?
pasv_end dw ?
pasv_port dw ?
ini_buf rb 3*4+3+1 ini_buf rb 3*4+3+1