Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 2597 → Rev 2598

/kernel/branches/net/applications/ftpd/commands.inc
6,7 → 6,7
 
home_dir rb 1024
work_dir rb 1024
fpath rb 1024*3
fpath rb 1024*3 ; Will also be used to temporarily store username
 
type db ? ; ASCII/EBDIC/IMAGE/..
mode db ? ; active/passive
14,6 → 14,8
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 ?
buffer_ptr dd ?
 
datasock sockaddr_in
 
21,8 → 23,30
ends
 
 
macro sendFTP str {
local .string, .length, .label
xor edi, edi
mcall send, [edx + thread_data.socketnum], .string, .length
jmp @f
.string db str, 13, 10
.length = $ - .string
@@:
 
}
 
;------------------------------------------------
; parse_cmd
;
; Internal function wich uses the 'commands'
; table to call an appropriate cmd_xx function.
;
; input: esi = ptr to ascii commands
; ecx = number of bytes input
; edx = pointer to thread_data structure
;
; output: none
;
;------------------------------------------------
align 4
parse_cmd: ; esi must point to command
 
31,12 → 55,11
inc esi
dec ecx
cmp ecx, 3
ja parse_cmd
ret
jb .error
jmp parse_cmd
.ok:
 
cmp byte [esi+3], 0x20
jae @f
ja @f
mov byte [esi+3], 0
@@:
 
45,71 → 68,263
mov edi, commands ; list of commands to scan
.scanloop:
cmp eax, [edi]
jne .try_next
je .got_it
 
jmp dword [edi+4]
 
.try_next:
add edi, 8
add edi, 4+4*4
cmp byte [edi], 0
jne .scanloop
 
.error:
mcall send, [edx + thread_data.socketnum], str500, str500.length, 0
 
cmp [edx + thread_data.state], STATE_ACTIVE
jb login_first
sendFTP "500 Unsupported command"
ret
 
.got_it:
mov eax, [edx + thread_data.state]
jmp dword [edi + 4 + eax]
 
 
align 4
commands: ; all commands must be in uppercase
 
db 'ABOR'
dd cmdABOR
db 'CDUP'
dd cmdCDUP
db 'CWD', 0
dd cmdCWD
db 'DELE'
dd cmdDELE
db 'LIST'
dd cmdLIST
db 'NLST'
dd cmdNLST
db 'NOOP'
dd cmdNOOP
db 'PASS'
dd cmdPASS
db 'PASV'
dd cmdPASV
db 'PORT'
dd cmdPORT
db 'PWD', 0
dd cmdPWD
db 'QUIT'
dd cmdQUIT
db 'RETR'
dd cmdRETR
db 'STOR'
dd cmdSTOR
db 'SYST'
dd cmdSYST
db 'TYPE'
dd cmdTYPE
db 'USER'
dd cmdUSER
dd 'ABOR'
dd login_first, login_first, login_first, cmdABOR
; dd 'ACCT
; dd login_fitst, login_first, login_first, cmd_ACCT
; dd 'APPE'
; dd login_fitst, login_first, login_first, cmd_APPE
dd 'CDUP'
dd login_first, login_first, login_first, cmdCDUP
dd 'CWD'
dd login_first, login_first, login_first, cmdCWD
dd 'DELE'
dd login_first, login_first, login_first, cmdDELE
; dd 'HELP'
; dd login_fitst, login_first, login_first, cmd_HELP
dd 'LIST'
dd login_first, login_first, login_first, cmdLIST
; dd 'MDTM'
; dd login_fitst, login_first, login_first, cmd_MDTM
; dd 'MKD'
; dd login_fitst, login_first, login_first, cmd_MKD
; dd 'MODE'
; dd login_fitst, login_first, login_first, cmd_MODE
dd 'NLST'
dd login_first, login_first, login_first, cmdNLST
dd 'NOOP'
dd login_first, login_first, login_first, cmdNOOP
dd 'PASS'
dd cmdPASS.0, cmdPASS , cmdPASS.2, cmdPASS.3
dd 'PASV'
dd login_first, login_first, login_first, cmdPASV
dd 'PORT'
dd login_first, login_first, login_first, cmdPORT
dd 'PWD'
dd login_first, login_first, login_first, cmdPWD
dd 'QUIT'
dd cmdQUIT, cmdQUIT, cmdQUIT, cmdQUIT
; dd 'REIN'
; dd login_fitst, login_first, login_first, cmd_REIN
; dd 'REST'
; dd login_fitst, login_first, login_first, cmd_REST
dd 'RETR'
dd login_first, login_first, login_first, cmdRETR
; dd 'RMD'
; dd login_fitst, login_first, login_first, cmd_RMD
; dd 'RNFR'
; dd login_fitst, login_first, login_first, cmd_RNFR
; dd 'RNTO'
; dd login_fitst, login_first, login_first, cmd_RNTO
; dd 'SITE'
; dd login_fitst, login_first, login_first, cmd_SITE
; dd 'SIZE'
; dd login_fitst, login_first, login_first, cmd_SIZE
; dd 'STAT'
; dd login_fitst, login_first, login_first, cmd_STAT
dd 'STOR'
dd login_first, login_first, login_first, cmdSTOR
; dd 'STOU'
; dd login_fitst, login_first, login_first, cmd_STOU
; dd 'STRU'
; dd login_fitst, login_first, login_first, cmd_STRU
dd 'SYST'
dd login_first, login_first, login_first, cmdSYST
dd 'TYPE'
dd login_first, login_first, login_first, cmdTYPE
dd 'USER'
dd cmdUSER, cmdUSER, cmdUSER, cmdUSER.2
db 0 ; end marker
 
align 4
login_first:
sendFTP "530 Please login with USER and PASS"
ret
 
align 4
cmdABOR:
permission_denied:
sendFTP "550 Permission denied"
ret
 
; TODO: abort the current filetransfer
align 4
socketerror:
pushd 0x0c
call [con_set_flags]
push str_sockerr
call [con_write_asciiz]
pushd 0x07
call [con_set_flags]
 
mov edx, [ebp]
sendFTP "425 Can't open data connection"
ret
 
align 4
abort_transfer:
and [edx + thread_data.permissions], not ABORT
mov [edx + thread_data.mode], MODE_NOTREADY
push ebx
call [file.close]
mcall close, [edx + thread_data.datasocketnum]
mov edx, [ebp]
sendFTP "530 Transfer aborted"
ret
 
align 4
ip_to_dword: ; esi = ptr to str, cl = separator ('.', ',')
 
call ascii_to_byte
mov bh, al
cmp byte [esi], cl
jne .err
 
call ascii_to_byte
mov bh, al
cmp byte [esi], cl
jne .err
shl ebx, 16
 
call ascii_to_byte
mov bh, al
cmp byte [esi], cl
jne .err
 
call ascii_to_byte
mov bh, al
 
ror ebx, 16
ret
 
.err:
xor ebx, ebx
ret
 
align 4 ; esi = ptr to str, output in eax
ascii_to_byte:
 
xor eax, eax
push ebx
 
.loop:
movzx ebx, byte[esi]
sub bl, '0'
jb .done
cmp bl, 9
ja .done
lea eax, [eax*4 + eax] ;
shl eax, 1 ; eax = eax * 10
add eax, ebx
inc esi
 
jmp .loop
 
.done:
pop ebx
ret
 
align 4
dword_to_ascii: ; edi = ptr where to write, eax is number
 
push edx ebx ecx
mov ebx, 10
xor ecx, ecx
 
@@:
xor edx, edx
div ebx
add edx, '0'
pushw dx
inc ecx
test eax, eax
jnz @r
 
@@:
popw ax
stosb
dec ecx
jnz @r
 
pop ecx ebx edx
ret
 
align 4
create_path: ; combine home_dir and work_dir strings into fpath
 
mov edx, [ebp]
lea edi, [edx + thread_data.fpath]
lea esi, [edx + thread_data.home_dir]
mov ecx, 1024
.loop1:
lodsb
or al, al
jz .next
stosb
loop .loop1
.next:
 
cmp byte[edi-1], '/'
jne @f
dec edi
@@:
 
lea esi, [edx + thread_data.work_dir]
mov ecx, 1024
.loop2:
lodsb
or al, al
jz .done
stosb
loop .loop2
 
.done:
stosb
ret
 
;------------------------------------------------
; "ABOR"
;
; This command aborts the current filetransfer.
;
;------------------------------------------------
align 4
cmdABOR:
 
or [edx + thread_data.permissions], ABORT
sendFTP "250 Command succesul"
ret
 
;------------------------------------------------
; "CDUP"
;
; Change the directory to move up one level.
;
;------------------------------------------------
align 4
cmdCDUP:
 
test [edx + thread_data.permissions], PERMISSION_CD
jz permission_denied
 
cmp byte [edx + thread_data.work_dir+1], 0 ; are we in "/" ?
je .done
 
134,13 → 349,21
push str_newline
call [con_write_asciiz]
 
mcall send, [edx + thread_data.socketnum], str250, str250.length, 0 ; command successful
sendFTP "250 Command succesul"
ret
 
 
;------------------------------------------------
; "CWD"
;
; Change Working Directory.
;
;------------------------------------------------
align 4
cmdCWD: ; Change Working Directory
cmdCWD:
 
test [edx + thread_data.permissions], PERMISSION_CD
jz permission_denied
 
sub ecx, 4
jb .err
add esi, 4
189,8 → 412,7
push str_newline
call [con_write_asciiz]
 
mcall send, [edx + thread_data.socketnum], str250, str250.length, 0
 
sendFTP "250 Command succesful"
ret
 
.up:
204,19 → 426,35
jmp .scan2
 
.err:
; TODO: print correct error message (550?)
 
sendFTP "550 Directory does not exist"
ret
 
;------------------------------------------------
; "DELE"
;
; Delete a file from the server.
;
;------------------------------------------------
align 4
cmdDELE:
 
test [edx + thread_data.permissions], PERMISSION_DELETE
jz permission_denied
 
ret
 
 
;------------------------------------------------
; "LIST"
;
; List the files in the current working directory.
;
;------------------------------------------------
align 4
cmdLIST:
 
test [edx + thread_data.permissions], PERMISSION_EXEC
jz permission_denied
 
; If we are in active mode, it's time to open a data socket..
cmp [edx + thread_data.mode], MODE_ACTIVE
jne @f
224,7 → 462,6
lea edx, [edx + thread_data.datasock]
mov esi, sizeof.thread_data.datasock
mcall connect
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1
je socketerror
@@:
239,6 → 476,7
call [con_write_asciiz]
 
; Start the search
mov edx, [ebp]
push FA_ANY
push str_mask
lea eax, [edx + thread_data.fpath]
248,9 → 486,10
test eax, eax
jz .nosuchdir
 
mov edx, [ebp]
lea edi, [edx + thread_data.buffer]
 
.parse_file:
 
test eax, eax ; did we find a file?
jz .done
mov ebx, eax ; yes, save the descripter in ebx
331,6 → 570,9
mov ax, 0x0a0d
stosw
 
test [edx + thread_data.permissions], ABORT
;;; jnz .abort
 
; check next file
push ebx
call [file.find.next]
338,7 → 580,7
 
; close file desc
.done:
push ebx
push eax ; file discriptor is still in eax at this point!
call [file.find.close]
 
; append the string with a 0
346,11 → 588,13
stosb
 
; Warn the client we're about to send the data
push edi edx
mcall send, [edx + thread_data.socketnum], str150, str150.length, 0 ; here it comes..
pop edx esi
mov edx, [ebp]
push edi
sendFTP "150 Here it comes.."
pop esi
 
; and send it to the client
mov edx, [ebp]
mov ecx, [edx + thread_data.datasocketnum]
lea edx, [edx + thread_data.buffer]
sub esi, edx
358,56 → 602,110
mcall send
 
; close the data socket..
mov edx, [esp+4] ; thread_data pointer
mov edx, [ebp] ; thread_data pointer
mcall close, [edx + thread_data.datasocketnum]
mov [edx + thread_data.mode], MODE_NOTREADY
 
; And send "transfer ok" on the base connection
mcall send, [edx + thread_data.socketnum], str226, str226.length, 0
 
sendFTP "226 Transfer OK"
ret
 
.nosuchdir:
mcall send, [edx + thread_data.socketnum], str550, str550.length, 0
 
sendFTP "550 Directory does not exist"
ret
 
 
;------------------------------------------------
; "NLST"
;
; List the filenames of the files in the current working directory.
;
;------------------------------------------------
align 4
cmdNLST:
 
test [edx + thread_data.permissions], PERMISSION_EXEC
jz permission_denied
 
; TODO: same as list but simpler output format
 
ret
 
;------------------------------------------------
; "NOOP"
;
; No operation, just keep the connection alive.
;
;------------------------------------------------
align 4
cmdNOOP:
 
ret
 
;------------------------------------------------
; "PASS"
;
; Second phase of login process, client provides password.
;
;------------------------------------------------
align 4
cmdPASS:
lea esi, [esi + 5]
lea edi, [edx + thread_data.buffer + 512] ; temp pass
lea eax, [edx + thread_data.fpath] ; temp username
invoke ini.get_str, path2, eax, str_pass, edi, 512
test eax, eax
jnz .incorrect
 
; TODO: verify password
repe cmpsb
 
mcall send, [edx + thread_data.socketnum], str230, str230.length, 0
cmp byte [esi], 0x20
jae .incorrect
 
cmp byte [edi], 0
jne .incorrect
 
.pass_ok:
lea eax, [edx + thread_data.fpath]
invoke ini.get_int, path2, eax, str_mode, 0
mov [edx + thread_data.permissions], eax
 
push str_pass_ok
call [con_write_asciiz]
 
mov edx, [esp+4] ; thread_data pointer
mov edx, [ebp] ; thread_data pointer
mov [edx + thread_data.state], STATE_ACTIVE
sendFTP "230 You are now logged in"
ret
 
.2:
.incorrect:
mov [edx + thread_data.state], STATE_CONNECTED
sendFTP "530 Login incorrect"
ret
 
align 4
.0:
sendFTP "503 Login with USER first"
ret
 
align 4
.3:
sendFTP "230 Already logged in"
ret
 
;------------------------------------------------
; "PASV"
;
; Initiate a passive dataconnection.
;
;------------------------------------------------
align 4
cmdPASV:
 
; Open a new TCP socket
mcall socket, AF_INET4, SOCK_STREAM, 0
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1
je socketerror
mov edx, [ebp] ; thread_data pointer
mov [edx + thread_data.passivesocknum], eax
 
; Bind it to a known local port
415,41 → 713,59
mov [edx + thread_data.datasock.sin_port], 2000
mov [edx + thread_data.datasock.sin_addr], 0
 
mov ecx, eax ;[edx + thread_data.passivesocknum]
mov ecx, eax ; passivesocketnum
lea edx, [edx + thread_data.datasock]
mov esi, sizeof.thread_data.datasock
mcall bind
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1
je bind_err
; je bind_err
 
; And set it to listen!
mcall listen, [edx + thread_data.passivesocknum], 10 ;;;;; FIXME
mcall listen, , 1
cmp eax, -1
; je listen_err
 
; Tell our thread we are ready to accept incoming calls
mov edx, [esp+4] ; thread_data pointer
mov edx, [ebp] ; thread_data pointer
mov [edx + thread_data.mode], MODE_PASSIVE_WAIT
 
; Now tell the client where to connect to in this format:
; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
 
; '227 ('
lea edi, [edx + thread_data.buffer]
mov eax, '227 ' ; FIXME (now hardcoded to 127.0.0.1:2000)
stosd
mov eax, '(127'
stosd
mov eax, ',0,0'
stosd
mov eax, ',1,7'
stosd
mov eax, ',208'
stosd
mov al, ')'
mov al, '('
stosb
mov ax, 0x0a0d
stosw
xor al, al
; ip
mov eax, 127
call dword_to_ascii
mov al, ','
stosb
mov eax, 0
call dword_to_ascii
mov al, ','
stosb
mov eax, 0
call dword_to_ascii
mov al, ','
stosb
mov eax, 1
call dword_to_ascii
mov al, ','
stosb
; port
mov eax, 7
call dword_to_ascii
mov al, ','
stosb
mov eax, 208
call dword_to_ascii
; ')', 13, 10, 0
mov eax, ')' + 0x000a0d00
stosd
 
lea esi, [edi - thread_data.buffer]
sub esi, edx
460,9 → 776,14
 
ret
 
 
;------------------------------------------------
; "PWD"
;
; Print the current working directory.
;
;------------------------------------------------
align 4
cmdPWD: ; Print Working Directory
cmdPWD:
 
mov dword [edx + thread_data.buffer], '257 '
mov byte [edx + thread_data.buffer+4], '"'
487,7 → 808,7
xor edi, edi
mcall send
 
mov edx, [esp+4]
mov edx, [ebp]
; Print the new working dir on the console
lea eax, [edx + thread_data.work_dir]
push eax
497,7 → 818,12
 
ret
 
 
;------------------------------------------------
; "PORT"
;
; Initiate an active dataconnection.
;
;------------------------------------------------
align 4
cmdPORT:
 
504,26 → 830,12
; PORT a1,a2,a3,a4,p1,p2
; IP address a1.a2.a3.a4, port p1*256+p2
 
mov [edx + thread_data.mode], MODE_ACTIVE
 
; Convert the IP
lea esi, [esi+5]
; Convert the IP
call ascii_to_byte
mov bl, al
inc esi ; skip past ','
call ascii_to_byte
mov bh, al
shl ebx, 16
inc esi
call ascii_to_byte
mov bl, al
inc esi
call ascii_to_byte
mov bh, al
inc esi
rol ebx, 16
 
mov cl, ','
call ip_to_dword
; And put it in datasock
mov edx, [ebp]
mov [edx + thread_data.datasock.sin_addr], ebx
 
; Now the same with portnumber
539,30 → 851,46
; We will open the socket, but do not connect yet!
mov [edx + thread_data.datasock.sin_family], AF_INET4
mcall socket, AF_INET4, SOCK_STREAM, 0
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1
je socketerror
 
mov edx, [ebp] ; thread_data pointer
mov [edx + thread_data.datasocketnum], eax
mov [edx + thread_data.mode], MODE_ACTIVE
 
; Tell the client we are ready
mov edx, [esp+4] ; thread_data pointer
mcall send, [edx + thread_data.socketnum], str225, str225.length, 0
sendFTP "225 Data connection open"
ret
 
 
;------------------------------------------------
; "QUIT"
;
; Close the connection with client.
;
;------------------------------------------------
align 4
cmdQUIT:
 
mcall close, [edx + thread_data.datasocketnum]
mcall send, [edx + thread_data.socketnum], str221, str221.length, 0 ; 221 - bye!
mcall close;, [edx + thread_data.socketnum]
 
sendFTP "221 Bye!"
mcall close, [edx + thread_data.socketnum]
 
add esp, 4 ; get rid of call return address
jmp thread_exit ; now close this thread
 
 
;------------------------------------------------
; "RETR"
;
; Retrieve a file from the ftp server.
;
;------------------------------------------------
align 4
cmdRETR:
 
test [edx + thread_data.permissions], PERMISSION_READ
jz permission_denied
 
sub ecx, 5
jb .cannot_open
 
574,7 → 902,6
mov esi, sizeof.thread_data.datasock
mcall connect
pop esi
mov edx, [esp+4] ; thread_data pointer
cmp eax, -1
je socketerror
@@:
601,6 → 928,7
push str_newline
call [con_write_asciiz]
 
mov edx, [ebp]
push O_READ
lea eax, [edx + thread_data.fpath]
push eax
608,12 → 936,16
test eax, eax
jz .cannot_open
 
mov edx, [ebp]
push eax
mcall send, [edx + thread_data.socketnum], str150, str150.length, 0 ; here it comes..
sendFTP "150 Here it comes.."
pop ebx
 
mov edx, [esp+4] ; thread_data pointer
.read_more:
mov edx, [ebp]
test [edx + thread_data.permissions], ABORT
jnz abort_transfer
 
push BUFFERSIZE
lea eax, [edx + thread_data.buffer]
push eax
622,16 → 954,15
cmp eax, -1
je .cannot_open ; fixme: this is not the correct error
 
push eax
push ebx
mov edx, [ebp]
push eax ebx
mov esi, eax
mov ecx, [edx + thread_data.datasocketnum]
lea edx, [edx + thread_data.buffer]
xor esi, esi
mcall send
pop ebx
pop ecx
mov edx, [esp+4] ; thread_data pointer
pop ebx ecx
mov edx, [ebp] ; thread_data pointer
cmp eax, -1
je socketerror
 
641,8 → 972,10
mcall close, [edx + thread_data.datasocketnum]
mov [edx + thread_data.mode], MODE_NOTREADY
 
mcall send, [edx + thread_data.socketnum], str226, str226.length, 0 ; transfer ok
push ebx
call [file.close]
 
sendFTP "226 Transfer OK, closing connection"
ret
 
.cannot_open:
653,24 → 986,51
pushd 0x07
call [con_set_flags]
 
mcall send, [edx + thread_data.socketnum], str550, str550.length, 0 ; file not found
 
mov edx, [ebp]
sendFTP "550 No such file"
ret
 
 
 
;------------------------------------------------
; "STOR"
;
; Store a file on the server.
;
;------------------------------------------------
align 4
cmdSTOR:
 
; TODO: check if user has write permission, and write file if so
test [edx + thread_data.permissions], PERMISSION_WRITE
jz permission_denied
 
 
;;;;
test [edx + thread_data.permissions], ABORT
jnz abort_transfer
 
;;;;
 
ret
 
;------------------------------------------------
; "SYST"
;
; Send information about the system.
;
;------------------------------------------------
align 4
cmdSYST:
 
mcall send, [edx + thread_data.socketnum], str215, str215.length, 0
 
sendFTP "215 UNIX type: L8"
ret
 
;------------------------------------------------
; "TYPE"
;
; Choose the file transfer type.
;
;------------------------------------------------
align 4
cmdTYPE:
 
743,136 → 1103,53
mov [edx + thread_data.type], al
 
.ok:
mcall send, [edx + thread_data.socketnum], str200, str200.length, 0
 
sendFTP "200 Command ok"
ret
 
 
;------------------------------------------------
; "USER"
;
; Login to the server, step one of two.
;
;------------------------------------------------
align 4
cmdUSER:
 
; TODO: check user and set home directory (and permissions)
 
mov [edx + thread_data.state], STATE_LOGIN
mov word [edx + thread_data.home_dir], "/" ; "/", 0
mov word [edx + thread_data.work_dir], "/" ; "/", 0
 
push str_logged_in
call [con_write_asciiz]
 
mcall send, [edx + thread_data.socketnum], str331, str331.length, 0 ; Now send me the password!
 
ret
 
 
 
align 4 ; esi = ptr to str, output in eax
ascii_to_byte:
 
xor eax, eax
push ebx
 
.loop:
movzx ebx, byte[esi]
sub bl, '0'
jb .done
cmp bl, 9
ja .done
lea eax, [eax*4 + eax] ;
shl eax, 1 ; eax = eax * 10
add eax, ebx
inc esi
 
jmp .loop
 
.done:
pop ebx
ret
 
align 4
dword_to_ascii: ; edi = ptr where to write, eax is number
 
mov eax, '1'
stosb
 
ret
 
align 4
create_path: ; combine home_dir and work_dir strings into fpath
 
lea esi, [esi + 5]
lea edi, [edx + thread_data.fpath]
lea esi, [edx + thread_data.home_dir]
mov ecx, 1024
.loop1:
.loop: ;;; TODO: prevent buffer overflow!
lodsb
or al, al
jz .next
stosb
loop .loop1
.next:
cmp al, 0x20
jae .loop
mov byte [edi-1], 0
 
cmp byte[edi-1], '/'
jne @f
dec edi
@@:
lea esi, [edx + thread_data.fpath]
lea eax, [edx + thread_data.home_dir]
invoke ini.get_str, path2, esi, str_home, eax, 1024
cmp eax, -1
je .login_fail
 
lea esi, [edx + thread_data.work_dir]
mov ecx, 1024
.loop2:
lodsb
or al, al
jz .done
stosb
loop .loop2
mov word [edx + thread_data.work_dir], "/" ; "/", 0
 
.done:
stosb
push str_logged_in
call [con_write_asciiz]
 
mov edx, [ebp]
mov [edx + thread_data.state], STATE_LOGIN
.sendstr:
sendFTP "331 Please specify the password"
ret
 
 
align 4
socketerror:
 
pushd 0x0c
call [con_set_flags]
push str_sockerr
.login_fail:
push str_login_invalid
call [con_write_asciiz]
pushd 0x07
call [con_set_flags]
 
mcall send, [edx + thread_data.socketnum], str425, str425.length, 0 ; data connection error
mov edx, [ebp]
mov [edx + thread_data.state], STATE_LOGIN_FAIL
jmp .sendstr
 
align 4
.2:
sendFTP "530 Can't change to another user"
ret
 
 
 
 
str150 db '150 Here it comes...', 13, 10
.length = $ - str150
str200 db '200 Command OK.', 13, 10
.length = $ - str200
str215 db '215 UNIX type: L8', 13, 10
.length = $ - str215
str220 db '220 KolibriOS FTP Daemon 1.0', 13, 10
.length = $ - str220
str221 db '221 Bye!', 13, 10
.length = $ - str221
str225 db '225 Data connection open', 13, 10
.length = $ - str225
str226 db '226 Transfer OK, Closing connection', 13, 10
.length = $ - str226
str230 db '230 You are now logged in.', 13, 10
.length = $ - str230
str250 db '250 command successful', 13, 10
.length = $ - str250
str331 db '331 Please specify the password.', 13, 10
.length = $ - str331
str421 db '421 Timeout!', 13, 10
.length = $ - str421
str425 db '425 Cant open data connection.', 13, 10
.length = $ - str425
str500 db '500 Unsupported command', 13, 10
.length = $ - str500
str550 db '550 No such file', 13, 10
.length = $ - str550
/kernel/branches/net/applications/ftpd/ftpd.asm
8,10 → 8,11
 
BUFFERSIZE = 8192
 
STATE_DISCONNECTED = 0
STATE_CONNECTED = 1
STATE_LOGIN = 2
STATE_ACTIVE = 3
; using multiple's of 4
STATE_CONNECTED = 4*0
STATE_LOGIN = 4*1
STATE_LOGIN_FAIL = 4*2 ; When an invalid username was given
STATE_ACTIVE = 4*3
 
TYPE_UNDEF = 0
 
25,12 → 26,20
TYPE_IMAGE = 01000000b ; binary data
TYPE_LOCAL = 10000000b ; bits per byte must be specified
; lower 4 bits will hold this value
 
MODE_NOTREADY = 0
MODE_ACTIVE = 1
MODE_PASSIVE_WAIT = 2
MODE_PASSIVE_OK = 3
MODE_PASSIVE_FAILED = 4
 
PERMISSION_EXEC = 1b ; LIST
PERMISSION_READ = 10b
PERMISSION_WRITE = 100b
PERMISSION_DELETE = 1000b
PERMISSION_CD = 10000b ; Change Directory
 
ABORT = 1 shl 31
 
format binary as ""
 
use32
62,16 → 71,30
 
mcall 68, 11 ; init heap
 
; find path to main settings file
; find path to main settings file (ftpd.ini)
mov edi, path ; Calculate the length of zero-terminated string
xor al, al
mov ecx, 1024
repne scasb
dec edi
mov esi, filename ; append it with '.ini'
mov esi, str_ini ; append it with '.ini', 0
movsd
movsb
 
; now create the second path (users.ini)
std
mov al, '/'
repne scasb
lea ecx, [edi - path + 2]
cld
mov esi, path
mov edi, path2
rep movsb
mov esi, str_users
movsd
movsd
movsw
 
; initialize console
push 1
call [con_start]
85,6 → 108,11
 
mcall 40, 1 shl 7 ; we only want network events
 
invoke ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0
mov esi, ini_buf
call ip_to_dword
mov [serverip], ebx
 
invoke ini.get_int, path, str_ftpd, str_port, 21
mov [sockaddr1.port], ax
 
140,6 → 168,7
 
lea esp, [eax + thread_data.stack] ; init stack
push eax ; save pointer to thread_data on stack
mov ebp, esp
 
mcall 40, 1 shl 7 ; we only want network events for this thread
 
153,55 → 182,75
mcall accept, [socketnum], sockaddr1, sockaddr1.length ; time to accept the awaiting connection..
cmp eax, -1
je thread_exit
mov edx, [esp] ; pointer to thread_data
mov edx, [ebp] ; pointer to thread_data
mov [edx + thread_data.socketnum], eax
 
mcall send, [edx + thread_data.socketnum], str220, str220.length, 0 ; send welcome string to the FTP client
mov [edx + thread_data.state], STATE_CONNECTED
mov [edx + thread_data.permissions], 0
mov [edx + thread_data.mode], MODE_NOTREADY
lea eax, [edx + thread_data.buffer]
mov [edx + thread_data.buffer_ptr], eax
 
sendFTP "220 Welcome to KolibriOS FTP daemon"
 
threadloop:
mcall 10
 
mov edx, [esp] ; pointer to thread_data
mov edx, [ebp] ; pointer to thread_data
 
cmp [edx + thread_data.mode], MODE_PASSIVE_WAIT
jne @f
jne .not_passive
mov ecx, [edx + thread_data.passivesocknum]
lea edx, [edx + thread_data.datasock]
mov esi, sizeof.thread_data.datasock
mcall accept
mov edx, [esp] ; pointer to thread_data
mov edx, [ebp] ; pointer to thread_data
cmp eax, -1
je @f
je .not_passive
mov [edx + thread_data.datasocketnum], eax
mov [edx + thread_data.mode], MODE_PASSIVE_OK
mov [edx + thread_data.mode], MODE_PASSIVE_FAILED
 
push str_datasock
call [con_write_asciiz] ; print on the console that the datasock is now ready
@@:
.not_passive:
 
mov ecx, [edx + thread_data.socketnum]
lea edx, [edx + thread_data.buffer]
mov esi, sizeof.thread_data.buffer
mov edx, [edx + thread_data.buffer_ptr]
mov esi, sizeof.thread_data.buffer ;;; FIXME
mcall recv
cmp eax, -1 ; error?
je threadloop
or eax, eax ; 0 bytes read?
inc eax ; error? (-1)
jz threadloop
push eax ; save number of bytes read on stack
dec eax ; 0 bytes read?
jz threadloop
 
mov edx, [esp+4] ; pointer to thread_data
mov byte [edx + thread_data.buffer + eax], 0 ; append received data with a 0 byte
mov edx, [ebp] ; pointer to thread_data
mov edi, [edx + thread_data.buffer_ptr]
add [edx + thread_data.buffer_ptr], eax
 
; Check if we received a newline character, if not, wait for more data
mov ecx, eax
mov al, 13
repne scasb
jne threadloop
 
; We got a command!
lea eax, [edx + thread_data.buffer]
mov ecx, [edx + thread_data.buffer_ptr]
sub ecx, eax
push ecx ; push full data size on stack
mov [edx + thread_data.buffer_ptr], eax ; reset buffer ptr
 
push eax;;;;
pushd 0x02 ; print received data to console (in green color)
call [con_set_flags]
push str_newline
call [con_write_asciiz]
lea eax, [edx + thread_data.buffer]
push eax
;;;; push eax
call [con_write_asciiz]
pushd 0x07
call [con_set_flags]
 
mov edx, [ebp]
pop ecx ; number of bytes read
lea esi, [edx + thread_data.buffer]
call parse_cmd
268,6 → 317,8
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_newline db 10, 0
str_mask db '*', 0
 
284,11 → 335,17
dd 'Nov '
dd 'Dec '
 
filename db '.ini', 0
str_users db 'users'
str_ini db '.ini', 0
str_port db 'port', 0
str_ftpd db 'ftpd', 0
str_conn db 'conn', 0
str_ip db 'ip', 0
str_pass db 'pass', 0
str_home db 'home', 0
str_mode db 'mode', 0
 
 
sockaddr1:
dw AF_INET4
.port dw 21
338,8 → 395,12
 
socketnum dd ?
path rb 1024
path2 rb 1024
params rb 1024
serverip dd ?
 
ini_buf rb 3*4+3+1
 
mem:
 
 
/kernel/branches/net/applications/ftpd/ftpd.ini
1,3 → 1,4
[ftpd]
port=21
conn=10
conn=10
ip=127.0.0.1
/kernel/branches/net/applications/ftpd/users.ini
1,14 → 1,19
; Access modes
;
; List = 1
; Read = 2
; Write = 4
; Delete = 8
; Change directory = 16
 
 
[anonymous]
pass= ; leavy empty for none
home=/rd/1/
mode=5
mode=3
 
; Access modes
; 7 full
; 6 read and write
; 5 read and execute
; 4 read only
; 3 write and execute
; 2 write only
; 1 execute only (open folder)
; 0 none
[test]
pass=1234
home=/rd/1/
mode=31