Subversion Repositories Kolibri OS

Rev

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

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