Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3618 hidnplayr 3
;; Copyright (C) KolibriOS team 2010-2013. All rights reserved.    ;;
3545 hidnplayr 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
 
3618 hidnplayr 66
include '../../macros.inc'
3545 hidnplayr 67
purge mov,add,sub
3618 hidnplayr 68
include '../../proc32.inc'
69
include '../../dll.inc'
70
include '../../struct.inc'
71
include '../../libio.inc'
3545 hidnplayr 72
 
3618 hidnplayr 73
include '../../network.inc'
3545 hidnplayr 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
3562 hidnplayr 273
        xor     edi, edi
3545 hidnplayr 274
        mcall   recv
275
        inc     eax                                     ; error? (-1)
276
        jz      threadloop
277
        dec     eax                                     ; 0 bytes read?
278
        jz      threadloop
279
 
280
        mov     edi, [ebp + thread_data.buffer_ptr]
281
        add     [ebp + thread_data.buffer_ptr], eax
282
 
283
; Check if we received a newline character, if not, wait for more data
284
        mov     ecx, eax
285
        mov     al, 13
286
        repne   scasb
287
        jne     threadloop
288
 
289
; We got a command!
290
        mov     byte [edi + 1], 0                       ; append string with zero byte
291
        lea     esi, [ebp + thread_data.buffer]
292
        mov     ecx, [ebp + thread_data.buffer_ptr]
293
        sub     ecx, esi
294
        mov     [ebp + thread_data.buffer_ptr], esi     ; reset buffer ptr
295
 
296
        invoke  con_set_flags, 0x02                     ; print received data to console (in green color)
297
        invoke  con_write_asciiz, str_newline
298
        invoke  con_write_asciiz, esi
299
        invoke  con_set_flags, 0x07
300
 
301
        push    threadloop
302
        jmp     parse_cmd
303
 
304
listen_err:
305
        invoke  con_set_flags, 0x0c                     ; print errors in red
306
        invoke  con_write_asciiz, str3
307
        jmp     done
308
 
309
bind_err:
310
        invoke  con_set_flags, 0x0c                     ; print errors in red
311
        invoke  con_write_asciiz, str4
312
        jmp     done
313
 
314
sock_err:
315
        invoke  con_set_flags, 0x0c                     ; print errors in red
316
        invoke  con_write_asciiz, str6
317
        jmp     done
318
 
319
done:
320
        invoke  con_exit, 0
321
exit:
322
        mcall   -1
323
 
324
 
325
thread_exit:
326
        invoke  con_set_flags, 0x03                             ; print thread info in blue
327
        invoke  con_printf, str_bye, [ebp + thread_data.pid]    ; print on the console that we are about to kill the thread
328
        add     esp, 8                                          ; balance stack
329
        mcall   68, 13, ebp                                     ; free the memory
330
        mcall   -1                                              ; and kill the thread
331
 
332
 
333
; initialized data
334
 
335
title           db 'KolibriOS FTP daemon 0.1', 0
336
str1            db 'Starting FTP daemon on port %u.', 0
337
str2            db '.', 0
338
str2b           db ' OK!',10,0
339
str3            db 'Listen error',10,0
340
str4            db 10,'ERROR: local port is already in use.',10,0
341
;str5            db 'Setsockopt error.',10,10,0
342
str6            db 'ERROR: Could not open socket.',10,0
343
str7            db 'Got data!',10,10,0
344
str8            db 10,'Thread %d created',10,0
345
str_bye         db 10,'Thread %d killed',10,0
346
 
347
str_logged_in   db 'Login ok',10,0
348
str_pass_ok     db 'Password ok',10,0
349
str_pass_err    db 'Password/Username incorrect',10,0
350
str_pwd         db 'Current directory is "%s"\n',0
351
str_err2        db 'ERROR: cannot open the directory.',10,0
352
str_datasock    db 'Passive data socket connected.',10,0
353
str_notfound    db 'ERROR: file not found.',10,0
354
str_sockerr     db 'ERROR: socket error.',10,0
355
 
356
str_newline     db 10, 0
357
str_mask        db '*', 0
358
str_infinity    db 0xff, 0xff, 0xff, 0xff, 0
359
 
360
months          dd 'Jan '
361
                dd 'Feb '
362
                dd 'Mar '
363
                dd 'Apr '
364
                dd 'May '
365
                dd 'Jun '
366
                dd 'Jul '
367
                dd 'Aug '
368
                dd 'Sep '
369
                dd 'Oct '
370
                dd 'Nov '
371
                dd 'Dec '
372
 
373
str_users       db 'users'
374
str_ini         db '.ini', 0
375
str_port        db 'port', 0
376
str_ftpd        db 'ftpd', 0
377
str_conn        db 'conn', 0
378
str_ip          db 'ip', 0
379
str_pass        db 'pass', 0
380
str_home        db 'home', 0
381
str_mode        db 'mode', 0
382
str_pasv        db 'pasv', 0
383
str_start       db 'start', 0
384
str_end         db 'end', 0
385
 
386
 
387
sockaddr1:
388
                dw AF_INET4
389
  .port         dw 0
390
  .ip           dd 0
391
                rb 10
392
  .length       = $ - sockaddr1
393
 
394
; import
395
 
396
align 4
397
@IMPORT:
398
 
399
diff16 "import", 0, $
400
 
401
library console,                'console.obj',\
402
        libini,                 'libini.obj', \
403
        libio,                  'libio.obj'
404
 
405
import  console,\
406
        con_start,              'START',\
407
        con_init,               'con_init',\
408
        con_write_asciiz,       'con_write_asciiz',\
409
        con_exit,               'con_exit',\
410
        con_gets,               'con_gets',\
411
        con_cls,                'con_cls',\
412
        con_printf,             'con_printf',\
413
        con_getch2,             'con_getch2',\
414
        con_set_cursor_pos,     'con_set_cursor_pos',\
415
        con_set_flags,          'con_set_flags',\
416
        con_get_flags,          'con_get_flags'
417
 
418
import  libini,\
419
        ini.get_str,            'ini_get_str',\
420
        ini.get_int,            'ini_get_int'
421
 
422
import  libio,\
423
        file.size,              'file_size',\
424
        file.open,              'file_open',\
425
        file.read,              'file_read',\
426
        file.close,             'file_close',\
427
        file.find.first,        'file_find_first',\
428
        file.find.next,         'file_find_next',\
429
        file.find.close,        'file_find_close'
430
 
431
 
432
IncludeIGlobals
433
 
434
 
435
i_end:
436
 
437
diff16 "i_end", 0, $
438
 
439
; uninitialised data
440
 
441
        socketnum       dd ?
442
        path            rb 1024
443
        path2           rb 1024
444
        params          rb 1024
445
        serverip        dd ?
446
        pasv_start      dw ?
447
        pasv_end        dw ?
448
        pasv_port       dw ?
449
 
450
        ini_buf         rb 3*4+3+1
451
 
452
        alive           db ?
453
 
454
mem:
455