Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/sun/net/www/ftptest/FtpCommandHandler.java
41152 views
1
/*
2
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
import java.net.*;
25
import java.io.*;
26
import java.util.regex.*;
27
import java.security.*;
28
import javax.net.ssl.*;
29
30
/*
31
* This class handles one client connection. It will interpret and act on the
32
* commands (like USER, GET, PUT etc...) sent through the socket passed to
33
* the constructor.
34
*
35
* To function it needs to be provided 2 handlers, one for the filesystem
36
* and one for authentication.
37
* @see FileSystemHandler
38
* @see AuthHandler
39
* @see #setHandlers(FtpFileSystemHandler,FtpAuthHandler)
40
*/
41
42
public class FtpCommandHandler extends Thread {
43
private FtpServer parent = null;
44
private Socket cmd = null;
45
private Socket oldCmd = null;
46
private InetAddress clientAddr = null;
47
private ServerSocket pasv = null;
48
49
private BufferedReader in = null;
50
51
private PrintStream out = null;
52
53
private FtpFileSystemHandler fsh = null;
54
private FtpAuthHandler auth = null;
55
56
private boolean done = false;
57
58
private String username = null;
59
private String password = null;
60
private String account = null;
61
private boolean logged = false;
62
private boolean epsvAll = false;
63
private int dataPort = 0;
64
private InetAddress dataAddress = null;
65
private boolean pasvEnabled = true;
66
private boolean portEnabled = true;
67
private boolean extendedEnabled = true;
68
private boolean binary = true;
69
private String renameFrom = null;
70
private long restart = 0;
71
private boolean useCrypto = false;
72
private boolean useDataCrypto = false;
73
private SSLSocketFactory sslFact = null;
74
75
private final int ERROR = -1;
76
private final int QUIT = 0;
77
private final int USER = 1;
78
private final int PASS = 2;
79
private final int CWD = 3;
80
private final int CDUP = 4;
81
private final int PWD = 5;
82
private final int TYPE = 6;
83
private final int NOOP = 7;
84
private final int RETR = 8;
85
private final int PORT = 9;
86
private final int PASV = 10;
87
private final int EPSV = 11;
88
private final int EPRT = 12;
89
private final int SYST = 13;
90
private final int STOR = 14;
91
private final int STOU = 15;
92
private final int LIST = 16;
93
private final int NLST = 17;
94
private final int RNFR = 18;
95
private final int RNTO = 19;
96
private final int DELE = 20;
97
private final int REST = 21;
98
private final int AUTH = 22;
99
private final int FEAT = 23;
100
private final int CCC = 24;
101
private final int PROT = 25;
102
private final int PBSZ = 26;
103
104
private String[] commands =
105
{ "QUIT", "USER", "PASS", "CWD", "CDUP", "PWD", "TYPE", "NOOP", "RETR",
106
"PORT", "PASV", "EPSV", "EPRT", "SYST", "STOR", "STOU", "LIST", "NLST",
107
"RNFR", "RNTO", "DELE", "REST", "AUTH", "FEAT", "CCC", "PROT", "PBSZ"
108
};
109
110
private boolean isPasvSet() {
111
if (pasv != null && !pasvEnabled) {
112
try {
113
pasv.close();
114
} catch ( IOException e) {
115
116
}
117
pasv = null;
118
}
119
if (pasvEnabled && pasv != null)
120
return true;
121
return false;
122
}
123
124
private OutputStream getOutDataStream() throws IOException {
125
if (isPasvSet()) {
126
Socket s = pasv.accept();
127
if (useCrypto && useDataCrypto) {
128
SSLSocket ssl = (SSLSocket) sslFact.createSocket(s, clientAddr.getHostName(), s.getPort(), true);
129
ssl.setUseClientMode(false);
130
s = ssl;
131
}
132
return s.getOutputStream();
133
}
134
if (dataAddress != null) {
135
Socket s;
136
if (useCrypto) {
137
s = sslFact.createSocket(dataAddress, dataPort);
138
} else
139
s = new Socket(dataAddress, dataPort);
140
dataAddress = null;
141
dataPort = 0;
142
return s.getOutputStream();
143
}
144
return null;
145
}
146
147
private InputStream getInDataStream() throws IOException {
148
if (isPasvSet()) {
149
Socket s = pasv.accept();
150
if (useCrypto && useDataCrypto) {
151
SSLSocket ssl = (SSLSocket) sslFact.createSocket(s, clientAddr.getHostName(), s.getPort(), true);
152
ssl.setUseClientMode(false);
153
s = ssl;
154
}
155
return s.getInputStream();
156
}
157
if (dataAddress != null) {
158
Socket s;
159
if (useCrypto) {
160
s = sslFact.createSocket(dataAddress, dataPort);
161
} else
162
s = new Socket(dataAddress, dataPort);
163
dataAddress = null;
164
dataPort = 0;
165
return s.getInputStream();
166
}
167
return null;
168
}
169
170
private void parsePort(String port_arg) throws IOException {
171
if (epsvAll) {
172
out.println("501 PORT not allowed after EPSV ALL.");
173
return;
174
}
175
if (!portEnabled) {
176
out.println("500 PORT command is disabled, please use PASV.");
177
return;
178
}
179
StringBuffer host;
180
int i = 0, j = 4;
181
while (j > 0) {
182
i = port_arg.indexOf(',', i + 1);
183
if (i < 0)
184
break;
185
j--;
186
}
187
if (j != 0) {
188
out.println("500 '" + port_arg + "': command not understood.");
189
return;
190
}
191
try {
192
host = new StringBuffer(port_arg.substring(0, i));
193
for (j = 0; j < host.length(); j++)
194
if (host.charAt(j) == ',')
195
host.setCharAt(j, '.');
196
String ports = port_arg.substring(i + 1);
197
i = ports.indexOf(',');
198
dataPort = Integer.parseInt(ports.substring(0, i)) << 8;
199
dataPort += (Integer.parseInt(ports.substring(i + 1)));
200
dataAddress = InetAddress.getByName(host.toString());
201
out.println("200 Command okay.");
202
} catch (Exception ex3) {
203
dataPort = 0;
204
dataAddress = null;
205
out.println("500 '" + port_arg + "': command not understood.");
206
}
207
}
208
209
private void parseEprt(String arg) {
210
if (epsvAll) {
211
out.println("501 PORT not allowed after EPSV ALL");
212
return;
213
}
214
if (!extendedEnabled || !portEnabled) {
215
out.println("500 EPRT is disabled, use PASV instead");
216
return;
217
}
218
Pattern p = Pattern.compile("\\|(\\d)\\|(.*)\\|(\\d+)\\|");
219
Matcher m = p.matcher(arg);
220
if (!m.find()) {
221
out.println("500 '" + arg + "': command not understood.");
222
return;
223
}
224
try {
225
dataAddress = InetAddress.getByName(m.group(2));
226
} catch (UnknownHostException e) {
227
out.println("500 " + arg + ": invalid address.");
228
dataAddress = null;
229
return;
230
}
231
dataPort = Integer.parseInt(m.group(3));
232
out.println("200 Command okay.");
233
}
234
235
private void doPasv() {
236
if (!pasvEnabled) {
237
out.println("500 PASV is disabled, use PORT.");
238
return;
239
}
240
try {
241
InetAddress rAddress = cmd.getLocalAddress();
242
if (rAddress instanceof Inet6Address) {
243
out.println("500 PASV illegal over IPv6 addresses, use EPSV.");
244
return;
245
}
246
if (pasv == null)
247
pasv = new ServerSocket(0, 0, rAddress);
248
int port = pasv.getLocalPort();
249
byte[] a = rAddress.getAddress();
250
out.println("227 Entering Passive Mode " + a[0] + "," + a[1] + "," + a[2] + "," + a[3] + "," +
251
(port >> 8) + "," + (port & 0xff) );
252
} catch (IOException e) {
253
out.println("425 can't build data connection: Connection refused.");
254
}
255
}
256
257
private void doEpsv(String arg) {
258
if (!extendedEnabled || !pasvEnabled) {
259
out.println("500 EPSV disabled, use PORT or PASV.");
260
return;
261
}
262
if ("all".equalsIgnoreCase(arg)) {
263
out.println("200 EPSV ALL Command successful.");
264
epsvAll = true;
265
return;
266
}
267
try {
268
if (pasv == null)
269
pasv = new ServerSocket(0, 0, parent.getInetAddress());
270
int port = pasv.getLocalPort();
271
out.println("229 Entering Extended Passive Mode (|||" + port + "|)");
272
} catch (IOException e) {
273
out.println("500 Can't create data connection.");
274
}
275
}
276
277
private void doRetr(String arg) {
278
try {
279
OutputStream dOut = getOutDataStream();
280
if (dOut != null) {
281
InputStream dIn = fsh.getFile(arg);
282
if (dIn == null) {
283
out.println("550 File not found.");
284
dOut.close();
285
return;
286
}
287
out.println("150 Opening " + (binary ? "BINARY " : "ASCII ") + " data connection for file " + arg +
288
"(" + fsh.getFileSize(arg) + " bytes).");
289
if (binary) {
290
byte[] buf = new byte[2048];
291
dOut = new BufferedOutputStream(dOut);
292
int count;
293
if (restart > 0) {
294
dIn.skip(restart);
295
restart = 0;
296
}
297
do {
298
count = dIn.read(buf);
299
if (count > 0)
300
dOut.write(buf, 0, count);
301
} while (count >= 0);
302
dOut.close();
303
dIn.close();
304
out.println("226 Transfer complete.");
305
}
306
}
307
} catch (IOException e) {
308
309
}
310
}
311
312
private void doStor(String arg, boolean unique) {
313
try {
314
InputStream dIn = getInDataStream();
315
if (dIn != null) {
316
OutputStream dOut = fsh.putFile(arg);
317
if (dOut == null) {
318
out.println("500 Can't create file " + arg);
319
dIn.close();
320
return;
321
}
322
out.println("150 Opening " + (binary ? "BINARY " : "ASCII ") + " data connection for file " + arg);
323
if (binary) {
324
byte[] buf = new byte[2048];
325
dOut = new BufferedOutputStream(dOut);
326
int count;
327
do {
328
count = dIn.read(buf);
329
if (count > 0)
330
dOut.write(buf, 0, count);
331
} while (count >= 0);
332
dOut.close();
333
dIn.close();
334
out.println("226 Transfer complete.");
335
}
336
}
337
} catch (IOException e) {
338
339
}
340
}
341
342
private void doList() {
343
try {
344
OutputStream dOut = getOutDataStream();
345
if (dOut != null) {
346
InputStream dIn = fsh.listCurrentDir();
347
if (dIn == null) {
348
out.println("550 File not found.");
349
dOut.close();
350
return;
351
}
352
out.println("150 Opening ASCII data connection for file list");
353
byte[] buf = new byte[2048];
354
dOut = new BufferedOutputStream(dOut);
355
int count;
356
do {
357
count = dIn.read(buf);
358
if (count > 0)
359
dOut.write(buf, 0, count);
360
} while (count >= 0);
361
dOut.close();
362
dIn.close();
363
out.println("226 Transfer complete.");
364
}
365
} catch (IOException e) {
366
367
}
368
}
369
370
private boolean useTLS() {
371
if (sslFact == null) {
372
sslFact = (SSLSocketFactory) SSLSocketFactory.getDefault();
373
}
374
if (sslFact == null)
375
return false;
376
return true;
377
}
378
379
private void stopTLS() {
380
if (useCrypto) {
381
SSLSocket ssl = (SSLSocket) cmd;
382
try {
383
ssl.close();
384
} catch (IOException e) {
385
// nada
386
}
387
cmd = oldCmd;
388
oldCmd = null;
389
try {
390
in = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
391
out = new PrintStream(cmd.getOutputStream(), true, "ISO8859_1");
392
} catch (Exception ex) {
393
394
}
395
}
396
}
397
398
public void setHandlers(FtpFileSystemHandler f, FtpAuthHandler a) {
399
fsh = f;
400
auth = a;
401
}
402
403
public FtpCommandHandler(Socket cl, FtpServer p) {
404
parent = p;
405
cmd = cl;
406
clientAddr = cl.getInetAddress();
407
}
408
409
public void terminate() {
410
done = true;
411
}
412
413
private int parseCmd(StringBuffer cmd) {
414
415
if (cmd == null || cmd.length() < 3) // Shortest command is 3 char long
416
return ERROR;
417
int blank = cmd.indexOf(" ");
418
if (blank < 0)
419
blank = cmd.length();
420
if (blank < 3)
421
return ERROR;
422
String s = cmd.substring(0,blank);
423
cmd.delete(0, blank + 1);
424
System.out.println("parse: cmd = " + s + " arg = " +cmd.toString());
425
for (int i = 0; i < commands.length; i++)
426
if (s.equalsIgnoreCase(commands[i]))
427
return i;
428
// Unknown command
429
return ERROR;
430
}
431
432
private boolean checkLogged() {
433
if (!logged) {
434
out.println("530 Not logged in.");
435
return false;
436
}
437
return true;
438
}
439
440
public void run() {
441
try {
442
// cmd.setSoTimeout(2000);
443
in = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
444
out = new PrintStream(cmd.getOutputStream(), true, "ISO8859_1");
445
// Below corrupted message style was intentional to test 8151586, please
446
// make sure each message line not broken ftp communication (such as for
447
// message line lenght >=4, the 4th char required '-' to allow
448
// implementation thinks that it has seen multi-line reply '###-'
449
// sequence), otherwise it will affect normal ftp tests which depends
450
// on this.
451
out.println("---------------------------------\n220 Java FTP test server"
452
+ " (j2se 6.0) ready.\n \n - Please send commands\n"
453
+ "-----------------------------\n\n\n");
454
out.flush();
455
if (auth.authType() == 0) // No auth needed
456
logged = true;
457
} catch (IOException e) {
458
e.printStackTrace();
459
return;
460
}
461
462
String str;
463
StringBuffer buf;
464
int res;
465
while (!done) {
466
try {
467
str = in.readLine();
468
System.out.println("line: " + str);
469
if (str == null) {
470
System.out.println("EOF read from input");
471
break;
472
}
473
buf = new StringBuffer(str);
474
res = parseCmd(buf);
475
switch (res) {
476
case ERROR:
477
out.println("500 '" + str +"': command not understood.");
478
break;
479
case QUIT:
480
out.println("221 Goodbye.");
481
done = true;
482
break;
483
case USER:
484
logged = false;
485
username = buf.toString();
486
if (auth.authType() > 1)
487
out.println("331 User name okay, need password.");
488
else {
489
if (auth.authenticate(username, null)) {
490
out.println("230 User logged in, proceed.");
491
logged = true;
492
} else {
493
out.println("331 User name okay, need password.");
494
}
495
}
496
break;
497
case PASS:
498
if (logged || (username == null)) {
499
out.println("503 Login with USER first.");
500
break;
501
}
502
password = buf.toString();
503
if (auth.authType() == 3) {
504
out.println("332 Need account for login.");
505
break;
506
}
507
if (auth.authenticate(username, password)) {
508
logged = true;
509
out.println("230 User " + username + " logged in.");
510
break;
511
}
512
out.println("530 Login incorrect.");
513
username = null;
514
break;
515
case CWD:
516
if (checkLogged()) {
517
String path = buf.toString();
518
if (fsh.cd(path)) {
519
out.println("250 CWD command successful.");
520
} else {
521
out.println("550 " + path + ": no such file or directory.");
522
}
523
}
524
break;
525
case CDUP:
526
if (checkLogged()) {
527
if (fsh.cdUp())
528
out.println("250 CWD command successful.");
529
else
530
out.println("550 invalid path.");
531
}
532
break;
533
case PWD:
534
if (checkLogged()) {
535
String s = fsh.pwd();
536
out.println("257 \"" + s + "\" is current directory");
537
}
538
break;
539
case NOOP:
540
if (checkLogged()) {
541
out.println("200 NOOP command successful.");
542
}
543
break;
544
case PORT:
545
if (checkLogged()) {
546
parsePort(buf.toString());
547
}
548
break;
549
case EPRT:
550
if (checkLogged()) {
551
parseEprt(buf.toString());
552
}
553
break;
554
case PASV:
555
if (checkLogged())
556
doPasv();
557
break;
558
case EPSV:
559
if (checkLogged())
560
doEpsv(buf.toString());
561
break;
562
case RETR:
563
if (checkLogged()) {
564
doRetr(buf.toString());
565
}
566
break;
567
case SYST:
568
if (checkLogged()) {
569
out.println("215 UNIX Type: L8 Version: Java 6.0");
570
}
571
break;
572
case TYPE:
573
if (checkLogged()) {
574
String arg = buf.toString();
575
if (arg.length() != 1 || "AIE".indexOf(arg.charAt(0)) < 0) {
576
out.println("500 'TYPE " + arg + "' command not understood.");
577
continue;
578
}
579
out.println("200 Type set to " + buf.toString() + ".");
580
if (arg.charAt(0) == 'I')
581
binary = true;
582
else
583
binary = false;
584
}
585
break;
586
case STOR:
587
case STOU:
588
// TODO: separate STOR and STOU (Store Unique)
589
if (checkLogged()) {
590
doStor(buf.toString(), false);
591
}
592
break;
593
case LIST:
594
if (checkLogged()) {
595
doList();
596
}
597
break;
598
case NLST:
599
// TODO: implememt
600
break;
601
case DELE:
602
if (checkLogged()) {
603
String arg = buf.toString();
604
if (fsh.removeFile(arg)) {
605
out.println("250 file " + arg + " deleted.");
606
break;
607
}
608
out.println("550 " + arg + ": no such file or directory.");
609
}
610
break;
611
case RNFR:
612
if (checkLogged()) {
613
if (renameFrom != null) {
614
out.println("503 Bad sequence of commands.");
615
break;
616
}
617
renameFrom = buf.toString();
618
if (fsh.fileExists(renameFrom)) {
619
out.println("350 File or directory exists, ready for destination name.");
620
} else {
621
out.println("550 " + renameFrom + ": no such file or directory");
622
renameFrom = null;
623
}
624
}
625
break;
626
case RNTO:
627
if (checkLogged()) {
628
if (renameFrom == null) {
629
out.println("503 Bad sequence of commands.");
630
break;
631
}
632
if (fsh.rename(renameFrom, buf.toString())) {
633
out.println("250 Rename successful");
634
} else {
635
out.println("550 Rename ");
636
}
637
renameFrom = null;
638
}
639
break;
640
case REST:
641
if (checkLogged()) {
642
String arg = buf.toString();
643
restart = Long.parseLong(arg);
644
if (restart > 0)
645
out.println("350 Restarting at " + restart + ". Send STORE or RETRIEVE to initiate transfer");
646
else
647
out.println("501 Syntax error in command of arguments.");
648
}
649
break;
650
case FEAT:
651
out.println("211-Features:");
652
out.println(" REST STREAM");
653
out.println(" PBSZ");
654
out.println(" AUTH TLS");
655
out.println(" PROT P");
656
out.println(" CCC");
657
out.println("211 End");
658
break;
659
case AUTH:
660
if ("TLS".equalsIgnoreCase(buf.toString()) && useTLS()) {
661
out.println("234 TLS Authentication OK.");
662
out.flush();
663
SSLSocket ssl;
664
String[] suites = sslFact.getSupportedCipherSuites();
665
try {
666
ssl = (SSLSocket) sslFact.createSocket(cmd, cmd.getInetAddress().getHostName(), cmd.getPort(), false);
667
ssl.setUseClientMode(false);
668
ssl.setEnabledCipherSuites(suites);
669
ssl.startHandshake();
670
} catch (IOException ioe) {
671
ioe.printStackTrace();
672
out.println("550 Unable to create secure channel.");
673
break;
674
}
675
oldCmd = cmd;
676
cmd = ssl;
677
out = new PrintStream(cmd.getOutputStream(), true, "ISO8859_1");
678
in = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
679
System.out.println("Secure socket created!");
680
useCrypto = true;
681
break;
682
}
683
out.println("501 Unknown or unsupported AUTH type");
684
break;
685
case CCC:
686
out.println("200 Command OK.");
687
stopTLS();
688
break;
689
case PROT:
690
String arg = buf.toString();
691
if ("C".equalsIgnoreCase(arg)) {
692
// PROT C : Clear protection level
693
// No protection on data channel;
694
useDataCrypto = false;
695
out.println("200 Command OK.");
696
break;
697
}
698
if ("P".equalsIgnoreCase(arg)) {
699
// PROT P : Private protection level
700
// Data channel is integrity and confidentiality protected
701
useDataCrypto = true;
702
out.println("200 Command OK.");
703
break;
704
}
705
out.println("537 Requested PROT level not supported by security mechanism.");
706
break;
707
case PBSZ:
708
// TODO: finish
709
out.println("200 Command OK.");
710
break;
711
712
}
713
714
} catch (InterruptedIOException ie) {
715
// loop
716
} catch (IOException e) {
717
e.printStackTrace();
718
return;
719
}
720
}
721
try {
722
in.close();
723
out.close();
724
cmd.close();
725
} catch (IOException e) {
726
}
727
parent.removeClient(this);
728
}
729
}
730
731