001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.net.ftp; 019 020import java.io.BufferedReader; 021import java.io.BufferedWriter; 022import java.io.IOException; 023import java.io.InputStreamReader; 024import java.io.OutputStreamWriter; 025import java.net.Inet6Address; 026import java.net.InetAddress; 027import java.net.InetSocketAddress; 028import java.net.ServerSocket; 029import java.net.Socket; 030 031import javax.net.ssl.HostnameVerifier; 032import javax.net.ssl.KeyManager; 033import javax.net.ssl.SSLContext; 034import javax.net.ssl.SSLException; 035import javax.net.ssl.SSLHandshakeException; 036import javax.net.ssl.SSLSocket; 037import javax.net.ssl.SSLSocketFactory; 038import javax.net.ssl.TrustManager; 039 040import org.apache.commons.net.util.Base64; 041import org.apache.commons.net.util.SSLContextUtils; 042import org.apache.commons.net.util.SSLSocketUtils; 043import org.apache.commons.net.util.TrustManagerUtils; 044 045/** 046 * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to see wire-level SSL details. 047 * 048 * Warning: the hostname is not verified against the certificate by default, use {@link #setHostnameVerifier(HostnameVerifier)} or 049 * {@link #setEndpointCheckingEnabled(boolean)} (on Java 1.7+) to enable verification. Verification is only performed on client mode connections. 050 * 051 * @since 2.0 052 */ 053public class FTPSClient extends FTPClient { 054 055// From http://www.iana.org/assignments/port-numbers 056 057// ftps-data 989/tcp ftp protocol, data, over TLS/SSL 058// ftps-data 989/udp ftp protocol, data, over TLS/SSL 059// ftps 990/tcp ftp protocol, control, over TLS/SSL 060// ftps 990/udp ftp protocol, control, over TLS/SSL 061 062 public static final int DEFAULT_FTPS_DATA_PORT = 989; 063 public static final int DEFAULT_FTPS_PORT = 990; 064 065 /** The value that I can set in PROT command (C = Clear, P = Protected) */ 066 private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" }; 067 /** Default PROT Command */ 068 private static final String DEFAULT_PROT = "C"; 069 /** Default secure socket protocol name, i.e. TLS */ 070 private static final String DEFAULT_PROTOCOL = "TLS"; 071 072 /** The AUTH (Authentication/Security Mechanism) command. */ 073 private static final String CMD_AUTH = "AUTH"; 074 /** The ADAT (Authentication/Security Data) command. */ 075 private static final String CMD_ADAT = "ADAT"; 076 /** The PROT (Data Channel Protection Level) command. */ 077 private static final String CMD_PROT = "PROT"; 078 /** The PBSZ (Protection Buffer Size) command. */ 079 private static final String CMD_PBSZ = "PBSZ"; 080 /** The MIC (Integrity Protected Command) command. */ 081 private static final String CMD_MIC = "MIC"; 082 /** The CONF (Confidentiality Protected Command) command. */ 083 private static final String CMD_CONF = "CONF"; 084 /** The ENC (Privacy Protected Command) command. */ 085 private static final String CMD_ENC = "ENC"; 086 /** The CCC (Clear Command Channel) command. */ 087 private static final String CMD_CCC = "CCC"; 088 089 /** @deprecated - not used - may be removed in a future release */ 090 @Deprecated 091 public static String KEYSTORE_ALGORITHM; 092 /** @deprecated - not used - may be removed in a future release */ 093 @Deprecated 094 public static String TRUSTSTORE_ALGORITHM; 095 /** @deprecated - not used - may be removed in a future release */ 096 @Deprecated 097 public static String PROVIDER; 098 /** @deprecated - not used - may be removed in a future release */ 099 @Deprecated 100 public static String STORE_TYPE; 101 /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ 102 private final boolean isImplicit; 103 /** The secure socket protocol to be used, e.g. SSL/TLS. */ 104 private final String protocol; 105 /** The AUTH Command value */ 106 private String auth = DEFAULT_PROTOCOL; 107 /** The context object. */ 108 private SSLContext context; 109 /** The socket object. */ 110 private Socket plainSocket; 111 /** Controls whether a new SSL session may be established by this socket. Default true. */ 112 private boolean isCreation = true; 113 /** The use client mode flag. */ 114 private boolean isClientMode = true; 115 116 /** The need client auth flag. */ 117 private boolean isNeedClientAuth; 118 119 /** The want client auth flag. */ 120 private boolean isWantClientAuth; 121 122 /** The cipher suites */ 123 private String[] suites; 124 125 /** The protocol versions */ 126 private String[] protocols; 127 128 /** 129 * The FTPS {@link TrustManager} implementation, default validate only {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. 130 */ 131 private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); 132 133 /** The {@link KeyManager}, default null (i.e. use system default). */ 134 private KeyManager keyManager; 135 136 /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ 137 private HostnameVerifier hostnameVerifier; 138 139 /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */ 140 private boolean tlsEndpointChecking; 141 142 /** 143 * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. 144 * 145 * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false) 146 */ 147 public FTPSClient() { 148 this(DEFAULT_PROTOCOL, false); 149 } 150 151 /** 152 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS Calls {@link #FTPSClient(String, boolean)} 153 * 154 * @param isImplicit The security mode (Implicit/Explicit). 155 */ 156 public FTPSClient(final boolean isImplicit) { 157 this(DEFAULT_PROTOCOL, isImplicit); 158 } 159 160 /** 161 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS The default TrustManager is set from 162 * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} 163 * 164 * @param isImplicit The security mode(Implicit/Explicit). 165 * @param context A pre-configured SSL Context 166 */ 167 public FTPSClient(final boolean isImplicit, final SSLContext context) { 168 this(DEFAULT_PROTOCOL, isImplicit); 169 this.context = context; 170 } 171 172 /** 173 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS and isImplicit {@code false} Calls {@link #FTPSClient(boolean, SSLContext)} 174 * 175 * @param context A pre-configured SSL Context 176 */ 177 public FTPSClient(final SSLContext context) { 178 this(false, context); 179 } 180 181 /** 182 * Constructor for FTPSClient, using explict mode, calls {@link #FTPSClient(String, boolean)}. 183 * 184 * @param protocol the protocol to use 185 */ 186 public FTPSClient(final String protocol) { 187 this(protocol, false); 188 } 189 190 /** 191 * Constructor for FTPSClient allowing specification of protocol and security mode. If isImplicit is true, the port is set to {@link #DEFAULT_FTPS_PORT} 192 * i.e. 990. The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} 193 * 194 * @param protocol the protocol 195 * @param isImplicit The security mode(Implicit/Explicit). 196 */ 197 public FTPSClient(final String protocol, final boolean isImplicit) { 198 this.protocol = protocol; 199 this.isImplicit = isImplicit; 200 if (isImplicit) { 201 setDefaultPort(DEFAULT_FTPS_PORT); 202 } 203 } 204 205 /** 206 * Because there are so many connect() methods, the _connectAction_() method is provided as a means of performing some action immediately after establishing 207 * a connection, rather than reimplementing all of the connect() methods. 208 * 209 * @throws IOException If it throw by _connectAction_. 210 * @see org.apache.commons.net.SocketClient#_connectAction_() 211 */ 212 @Override 213 protected void _connectAction_() throws IOException { 214 // Implicit mode. 215 if (isImplicit) { 216 applySocketAttributes(); 217 sslNegotiation(); 218 } 219 super._connectAction_(); 220 // Explicit mode. 221 if (!isImplicit) { 222 execAUTH(); 223 sslNegotiation(); 224 } 225 } 226 227 /** 228 * Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing. 229 * 230 * @param command The int representation of the FTP command to send. 231 * @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments. 232 * @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and 233 * initialization of the connection. 234 * @throws IOException If there is any problem with the connection. 235 * @see FTPClient#_openDataConnection_(int, String) 236 * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead 237 */ 238 @Override 239 // Strictly speaking this is not needed, but it works round a Clirr bug 240 // So rather than invoke the parent code, we do it here 241 @Deprecated 242 protected Socket _openDataConnection_(final int command, final String arg) throws IOException { 243 return _openDataConnection_(FTPCommand.getCommand(command), arg); 244 } 245 246 /** 247 * Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing. 248 * 249 * @param command The textual representation of the FTP command to send. 250 * @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments. 251 * @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and 252 * initialization of the connection. 253 * @throws IOException If there is any problem with the connection. 254 * @see FTPClient#_openDataConnection_(int, String) 255 * @since 3.2 256 */ 257 @Override 258 protected Socket _openDataConnection_(final String command, final String arg) throws IOException { 259 final Socket socket = openDataSecureConnection(command, arg); 260 _prepareDataSocket_(socket); 261 if (socket instanceof SSLSocket) { 262 final SSLSocket sslSocket = (SSLSocket) socket; 263 264 sslSocket.setUseClientMode(isClientMode); 265 sslSocket.setEnableSessionCreation(isCreation); 266 267 // server mode 268 if (!isClientMode) { 269 sslSocket.setNeedClientAuth(isNeedClientAuth); 270 sslSocket.setWantClientAuth(isWantClientAuth); 271 } 272 if (suites != null) { 273 sslSocket.setEnabledCipherSuites(suites); 274 } 275 if (protocols != null) { 276 sslSocket.setEnabledProtocols(protocols); 277 } 278 sslSocket.startHandshake(); 279 } 280 281 return socket; 282 } 283 284 /** 285 * Performs any custom initialization for a newly created SSLSocket (before the SSL handshake happens). Called by {@link #_openDataConnection_(int, String)} 286 * immediately after creating the socket. The default implementation is a no-op 287 * 288 * @param socket the socket to set up 289 * @throws IOException on error 290 * @since 3.1 291 */ 292 protected void _prepareDataSocket_(final Socket socket) throws IOException { 293 } 294 295 /** 296 * Check the value that can be set in PROT Command value. 297 * 298 * @param prot Data Channel Protection Level. 299 * @return True - A set point is right / False - A set point is not right 300 */ 301 private boolean checkPROTValue(final String prot) { 302 for (final String element : PROT_COMMAND_VALUE) { 303 if (element.equals(prot)) { 304 return true; 305 } 306 } 307 return false; 308 } 309 310 /** 311 * Close open sockets. 312 * 313 * @param socket main socket for proxy if enabled 314 * @param sslSocket ssl socket 315 * @throws IOException closing sockets is not successful 316 */ 317 private void closeSockets(final Socket socket, final Socket sslSocket) throws IOException { 318 if (socket != null) { 319 socket.close(); 320 } 321 if (sslSocket != null) { 322 sslSocket.close(); 323 } 324 } 325 326 /** 327 * Create SSL socket from plain socket. 328 * 329 * @param socket 330 * @return SSL Socket 331 * @throws IOException 332 */ 333 private SSLSocket createSSLSocket(final Socket socket) throws IOException { 334 if (socket != null) { 335 final SSLSocketFactory f = context.getSocketFactory(); 336 return (SSLSocket) f.createSocket(socket, _hostname_, socket.getPort(), false); 337 } 338 return null; 339 } 340 341 /** 342 * Closes the connection to the FTP server and restores connection parameters to the default values. 343 * <p> 344 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} to reset the factories that may have been changed during the session, e.g. 345 * by {@link #execPROT(String)} 346 * 347 * @throws IOException If an error occurs while disconnecting. 348 * @since 3.0 349 */ 350 @Override 351 public void disconnect() throws IOException { 352 super.disconnect(); 353 if (plainSocket != null) { 354 plainSocket.close(); 355 } 356 setSocketFactory(null); 357 setServerSocketFactory(null); 358 } 359 360 /** 361 * Send the ADAT command with the specified authentication data. 362 * 363 * @param data The data to send with the command. 364 * @return server reply. 365 * @throws IOException If an I/O error occurs while sending the command. 366 * @since 3.0 367 */ 368 public int execADAT(final byte[] data) throws IOException { 369 if (data != null) { 370 return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); 371 } 372 return sendCommand(CMD_ADAT); 373 } 374 375 /** 376 * AUTH command. 377 * 378 * @throws SSLException If it server reply code not equal "234" and "334". 379 * @throws IOException If an I/O error occurs while either sending the command. 380 */ 381 protected void execAUTH() throws SSLException, IOException { 382 final int replyCode = sendCommand(CMD_AUTH, auth); 383 if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { 384 // replyCode = 334 385 // I carry out an ADAT command. 386 } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { 387 throw new SSLException(getReplyString()); 388 } 389 } 390 391 /** 392 * Send the AUTH command with the specified mechanism. 393 * 394 * @param mechanism The mechanism name to send with the command. 395 * @return server reply. 396 * @throws IOException If an I/O error occurs while sending the command. 397 * @since 3.0 398 */ 399 public int execAUTH(final String mechanism) throws IOException { 400 return sendCommand(CMD_AUTH, mechanism); 401 } 402 403 /** 404 * Send the CCC command to the server. The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain 405 * {@link Socket} instances 406 * 407 * @return server reply. 408 * @throws IOException If an I/O error occurs while sending the command. 409 * @since 3.0 410 */ 411 public int execCCC() throws IOException { 412 final int repCode = sendCommand(CMD_CCC); 413// This will be performed by sendCommand(String, String) 414// if (FTPReply.isPositiveCompletion(repCode)) { 415// _socket_.close(); 416// _socket_ = plainSocket; 417// _controlInput_ = new BufferedReader( 418// new InputStreamReader( 419// _socket_.getInputStream(), getControlEncoding())); 420// _controlOutput_ = new BufferedWriter( 421// new OutputStreamWriter( 422// _socket_.getOutputStream(), getControlEncoding())); 423// } 424 return repCode; 425 } 426 427 /** 428 * Send the CONF command with the specified data. 429 * 430 * @param data The data to send with the command. 431 * @return server reply. 432 * @throws IOException If an I/O error occurs while sending the command. 433 * @since 3.0 434 */ 435 public int execCONF(final byte[] data) throws IOException { 436 if (data != null) { 437 return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); 438 } 439 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? 440 } 441 442 /** 443 * Send the ENC command with the specified data. 444 * 445 * @param data The data to send with the command. 446 * @return server reply. 447 * @throws IOException If an I/O error occurs while sending the command. 448 * @since 3.0 449 */ 450 public int execENC(final byte[] data) throws IOException { 451 if (data != null) { 452 return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); 453 } 454 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? 455 } 456 457 /** 458 * Send the MIC command with the specified data. 459 * 460 * @param data The data to send with the command. 461 * @return server reply. 462 * @throws IOException If an I/O error occurs while sending the command. 463 * @since 3.0 464 */ 465 public int execMIC(final byte[] data) throws IOException { 466 if (data != null) { 467 return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); 468 } 469 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? 470 } 471 472 /** 473 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 474 * 475 * @param pbsz Protection Buffer Size. 476 * @throws SSLException If the server reply code does not equal "200". 477 * @throws IOException If an I/O error occurs while sending the command. 478 * @see #parsePBSZ(long) 479 */ 480 public void execPBSZ(final long pbsz) throws SSLException, IOException { 481 if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number 482 throw new IllegalArgumentException(); 483 } 484 final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); 485 if (FTPReply.COMMAND_OK != status) { 486 throw new SSLException(getReplyString()); 487 } 488 } 489 490 /** 491 * PROT command. 492 * <ul> 493 * <li>C - Clear</li> 494 * <li>S - Safe(SSL protocol only)</li> 495 * <li>E - Confidential(SSL protocol only)</li> 496 * <li>P - Private</li> 497 * </ul> 498 * <b>N.B.</b> the method calls {@link #setSocketFactory(javax.net.SocketFactory)} and {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} 499 * 500 * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}. 501 * @throws SSLException If the server reply code does not equal {@code 200}. 502 * @throws IOException If an I/O error occurs while sending the command. 503 */ 504 public void execPROT(String prot) throws SSLException, IOException { 505 if (prot == null) { 506 prot = DEFAULT_PROT; 507 } 508 if (!checkPROTValue(prot)) { 509 throw new IllegalArgumentException(); 510 } 511 if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) { 512 throw new SSLException(getReplyString()); 513 } 514 if (DEFAULT_PROT.equals(prot)) { 515 setSocketFactory(null); 516 setServerSocketFactory(null); 517 } else { 518 setSocketFactory(new FTPSSocketFactory(context)); 519 setServerSocketFactory(new FTPSServerSocketFactory(context)); 520 initSslContext(); 521 } 522 } 523 524 /** 525 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 526 * 527 * @param prefix the prefix to find 528 * @param reply where to find the prefix 529 * @return the remainder of the string after the prefix, or null if the prefix was not present. 530 */ 531 private String extractPrefixedData(final String prefix, final String reply) { 532 final int idx = reply.indexOf(prefix); 533 if (idx == -1) { 534 return null; 535 } 536 // N.B. Cannot use trim before substring as leading space would affect the offset. 537 return reply.substring(idx + prefix.length()).trim(); 538 } 539 540 /** 541 * Return AUTH command use value. 542 * 543 * @return AUTH command use value. 544 */ 545 public String getAuthValue() { 546 return this.auth; 547 } 548 549 /** 550 * Returns the names of the cipher suites which could be enabled for use on this connection. When the underlying {@link Socket} is not an {@link SSLSocket} 551 * instance, returns null. 552 * 553 * @return An array of cipher suite names, or <code>null</code> 554 */ 555 public String[] getEnabledCipherSuites() { 556 if (_socket_ instanceof SSLSocket) { 557 return ((SSLSocket) _socket_).getEnabledCipherSuites(); 558 } 559 return null; 560 } 561 562 /** 563 * Returns the names of the protocol versions which are currently enabled for use on this connection. When the underlying {@link Socket} is not an 564 * {@link SSLSocket} instance, returns null. 565 * 566 * @return An array of protocols, or <code>null</code> 567 */ 568 public String[] getEnabledProtocols() { 569 if (_socket_ instanceof SSLSocket) { 570 return ((SSLSocket) _socket_).getEnabledProtocols(); 571 } 572 return null; 573 } 574 575 /** 576 * Returns true if new SSL sessions may be established by this socket. When the underlying {@link Socket} instance is not SSL-enabled (i.e. an instance of 577 * {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, this returns False. 578 * 579 * @return true - Indicates that sessions may be created; this is the default. false - indicates that an existing session must be resumed. 580 */ 581 public boolean getEnableSessionCreation() { 582 if (_socket_ instanceof SSLSocket) { 583 return ((SSLSocket) _socket_).getEnableSessionCreation(); 584 } 585 return false; 586 } 587 588 /** 589 * Get the currently configured {@link HostnameVerifier}. The verifier is only used on client mode connections. 590 * 591 * @return A HostnameVerifier instance. 592 * @since 3.4 593 */ 594 public HostnameVerifier getHostnameVerifier() { 595 return hostnameVerifier; 596 } 597 598 /** 599 * Gets the {@link KeyManager} instance. 600 * 601 * @return The {@link KeyManager} instance 602 */ 603 private KeyManager getKeyManager() { 604 return keyManager; 605 } 606 607 /** 608 * Returns true if the socket will require client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 609 * 610 * @return true - If the server mode socket should request that the client authenticate itself. 611 */ 612 public boolean getNeedClientAuth() { 613 if (_socket_ instanceof SSLSocket) { 614 return ((SSLSocket) _socket_).getNeedClientAuth(); 615 } 616 return false; 617 } 618 619 /** 620 * Get the currently configured {@link TrustManager}. 621 * 622 * @return A TrustManager instance. 623 */ 624 public TrustManager getTrustManager() { 625 return trustManager; 626 } 627 628 /** 629 * Returns true if the socket is set to use client mode in its first handshake. When the underlying {@link Socket} is not an {@link SSLSocket} instance, 630 * returns false. 631 * 632 * @return true - If the socket should start its first handshake in "client" mode. 633 */ 634 public boolean getUseClientMode() { 635 if (_socket_ instanceof SSLSocket) { 636 return ((SSLSocket) _socket_).getUseClientMode(); 637 } 638 return false; 639 } 640 641 /** 642 * Returns true if the socket will request client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 643 * 644 * @return true - If the server mode socket should request that the client authenticate itself. 645 */ 646 public boolean getWantClientAuth() { 647 if (_socket_ instanceof SSLSocket) { 648 return ((SSLSocket) _socket_).getWantClientAuth(); 649 } 650 return false; 651 } 652 653 /** 654 * Performs a lazy init of the SSL context 655 * 656 * @throws IOException 657 */ 658 private void initSslContext() throws IOException { 659 if (context == null) { 660 context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); 661 } 662 } 663 664 /** 665 * Return whether or not endpoint identification using the HTTPS algorithm on Java 1.7+ is enabled. The default behavior is for this to be disabled. 666 * 667 * This check is only performed on client mode connections. 668 * 669 * @return True if enabled, false if not. 670 * @since 3.4 671 */ 672 public boolean isEndpointCheckingEnabled() { 673 return tlsEndpointChecking; 674 } 675 676 /** 677 * Establishes a data connection with the FTP server, returning a Socket for the connection if successful. If a restart offset has been set with 678 * {@link #setRestartOffset(long)}, a REST command is issued to the server with the offset as an argument before establishing the data connection. Active 679 * mode connections also cause a local PORT command to be issued. 680 * 681 * @param command The text representation of the FTP command to send. 682 * @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument. 683 * @return A Socket corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the 684 * establishment and initialization of the connection. 685 * @throws IOException If an I/O error occurs while either sending a command to the server or receiving a reply from the server. 686 * @since 3.1 687 */ 688 private Socket openDataSecureConnection(final String command, final String arg) throws IOException { 689 if (getDataConnectionMode() != ACTIVE_LOCAL_DATA_CONNECTION_MODE && getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { 690 return null; 691 } 692 693 final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; 694 695 final Socket socket; 696 Socket sslSocket = null; 697 final int soTimeoutMillis = DurationUtils.toMillisInt(getDataTimeout()); 698 if (getDataConnectionMode() == ACTIVE_LOCAL_DATA_CONNECTION_MODE) { 699 // if no activePortRange was set (correctly) -> getActivePort() = 0 700 // -> new ServerSocket(0) -> bind to any free local port 701 try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) { 702 // Try EPRT only if remote server is over IPv6, if not use PORT, 703 // because EPRT has no advantage over PORT on IPv4. 704 // It could even have the disadvantage, 705 // that EPRT will make the data connection fail, because 706 // today's intelligent NAT Firewalls are able to 707 // substitute IP addresses in the PORT command, 708 // but might not be able to recognize the EPRT command. 709 if (isInet6Address) { 710 if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) { 711 return null; 712 } 713 } else if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) { 714 return null; 715 } 716 717 if ((getRestartOffset() > 0) && !restart(getRestartOffset())) { 718 return null; 719 } 720 721 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { 722 return null; 723 } 724 725 // For now, let's just use the data timeout value for waiting for 726 // the data connection. It may be desirable to let this be a 727 // separately configurable value. In any case, we really want 728 // to allow preventing the accept from blocking indefinitely. 729 if (soTimeoutMillis >= 0) { 730 server.setSoTimeout(soTimeoutMillis); 731 } 732 socket = server.accept(); 733 734 // Ensure the timeout is set before any commands are issued on the new socket 735 if (soTimeoutMillis >= 0) { 736 socket.setSoTimeout(soTimeoutMillis); 737 } 738 if (getReceiveDataSocketBufferSize() > 0) { 739 socket.setReceiveBufferSize(getReceiveDataSocketBufferSize()); 740 } 741 if (getSendDataSocketBufferSize() > 0) { 742 socket.setSendBufferSize(getSendDataSocketBufferSize()); 743 } 744 } 745 } else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE 746 747 // Try EPSV command first on IPv6 - and IPv4 if enabled. 748 // When using IPv4 with NAT it has the advantage 749 // to work with more rare configurations. 750 // E.g. if FTP server has a static PASV address (external network) 751 // and the client is coming from another internal network. 752 // In that case the data connection after PASV command would fail, 753 // while EPSV would make the client succeed by taking just the port. 754 final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; 755 if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) { 756 _parseExtendedPassiveModeReply(_replyLines.get(0)); 757 } else { 758 if (isInet6Address) { 759 return null; // Must use EPSV for IPV6 760 } 761 // If EPSV failed on IPV4, revert to PASV 762 if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { 763 return null; 764 } 765 _parsePassiveModeReply(_replyLines.get(0)); 766 } 767 768 if (getProxy() != null) { 769 socket = new Socket(getProxy()); 770 } else { 771 socket = _socketFactory_.createSocket(); 772 } 773 774 if (getReceiveDataSocketBufferSize() > 0) { 775 socket.setReceiveBufferSize(getReceiveDataSocketBufferSize()); 776 } 777 if (getSendDataSocketBufferSize() > 0) { 778 socket.setSendBufferSize(getSendDataSocketBufferSize()); 779 } 780 if (getPassiveLocalIPAddress() != null) { 781 socket.bind(new InetSocketAddress(getPassiveLocalIPAddress(), 0)); 782 } 783 784 // For now, let's just use the data timeout value for waiting for 785 // the data connection. It may be desirable to let this be a 786 // separately configurable value. In any case, we really want 787 // to allow preventing the accept from blocking indefinitely. 788 if (soTimeoutMillis >= 0) { 789 socket.setSoTimeout(soTimeoutMillis); 790 } 791 792 socket.connect(new InetSocketAddress(getPassiveHost(), getPassivePort()), connectTimeout); 793 794 if (getProxy() != null) { 795 sslSocket = context.getSocketFactory().createSocket(socket, getPassiveHost(), getPassivePort(), true); 796 } 797 798 if ((getRestartOffset() > 0) && !restart(getRestartOffset())) { 799 closeSockets(socket, sslSocket); 800 return null; 801 } 802 803 if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { 804 closeSockets(socket, sslSocket); 805 return null; 806 } 807 } 808 809 if (isRemoteVerificationEnabled() && !verifyRemote(socket)) { 810 // Grab the host before we close the socket to avoid NET-663 811 final InetAddress socketHost = socket.getInetAddress(); 812 813 closeSockets(socket, sslSocket); 814 815 throw new IOException( 816 "Host attempting data connection " + socketHost.getHostAddress() + " is not same as server " + getRemoteAddress().getHostAddress()); 817 } 818 819 return getProxy() != null ? sslSocket : socket; 820 } 821 822 /** 823 * Parses the given ADAT response line and base64-decodes the data. 824 * 825 * @param reply The ADAT reply to parse. 826 * @return the data in the reply, base64-decoded. 827 * @since 3.0 828 */ 829 public byte[] parseADATReply(final String reply) { 830 if (reply == null) { 831 return null; 832 } 833 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); 834 } 835 836 /** 837 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. Issues the command and parses the response to return the negotiated value. 838 * 839 * @param pbsz Protection Buffer Size. 840 * @throws SSLException If the server reply code does not equal "200". 841 * @throws IOException If an I/O error occurs while sending the command. 842 * @return the negotiated value. 843 * @see #execPBSZ(long) 844 * @since 3.0 845 */ 846 public long parsePBSZ(final long pbsz) throws SSLException, IOException { 847 execPBSZ(pbsz); 848 long minvalue = pbsz; 849 final String remainder = extractPrefixedData("PBSZ=", getReplyString()); 850 if (remainder != null) { 851 final long replysz = Long.parseLong(remainder); 852 if (replysz < minvalue) { 853 minvalue = replysz; 854 } 855 } 856 return minvalue; 857 } 858 859 /** 860 * Send an FTP command. A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain 861 * {@link Socket} 862 * 863 * @param command The FTP command. 864 * @return server reply. 865 * @throws IOException If an I/O error occurs while sending the command. 866 * @throws SSLException if a CCC command fails 867 * @see org.apache.commons.net.ftp.FTP#sendCommand(String) 868 */ 869 // Would like to remove this method, but that will break any existing clients that are using CCC 870 @Override 871 public int sendCommand(final String command, final String args) throws IOException { 872 final int repCode = super.sendCommand(command, args); 873 /* If CCC is issued, restore socket i/o streams to unsecured versions */ 874 if (CMD_CCC.equals(command)) { 875 if (FTPReply.COMMAND_OK != repCode) { 876 throw new SSLException(getReplyString()); 877 } 878 _socket_.close(); 879 _socket_ = plainSocket; 880 _controlInput_ = new BufferedReader(new InputStreamReader(_socket_.getInputStream(), getControlEncoding())); 881 _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding())); 882 } 883 return repCode; 884 } 885 886 /** 887 * Set AUTH command use value. This processing is done before connected processing. 888 * 889 * @param auth AUTH command use value. 890 */ 891 public void setAuthValue(final String auth) { 892 this.auth = auth; 893 } 894 895 /** 896 * Controls which particular cipher suites are enabled for use on this connection. Called before server negotiation. 897 * 898 * @param cipherSuites The cipher suites. 899 */ 900 public void setEnabledCipherSuites(final String[] cipherSuites) { 901 suites = cipherSuites.clone(); 902 } 903 904 /** 905 * Controls which particular protocol versions are enabled for use on this connection. I perform setting before a server negotiation. 906 * 907 * @param protocolVersions The protocol versions. 908 */ 909 public void setEnabledProtocols(final String[] protocolVersions) { 910 protocols = protocolVersions.clone(); 911 } 912 913 /** 914 * Controls whether a new SSL session may be established by this socket. 915 * 916 * @param isCreation The established socket flag. 917 */ 918 public void setEnabledSessionCreation(final boolean isCreation) { 919 this.isCreation = isCreation; 920 } 921 922 /** 923 * Automatic endpoint identification checking using the HTTPS algorithm is supported on Java 1.7+. The default behavior is for this to be disabled. 924 * 925 * This check is only performed on client mode connections. 926 * 927 * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. 928 * @since 3.4 929 */ 930 public void setEndpointCheckingEnabled(final boolean enable) { 931 tlsEndpointChecking = enable; 932 } 933 934 /** 935 * Override the default {@link HostnameVerifier} to use. The verifier is only used on client mode connections. 936 * 937 * @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable. 938 * @since 3.4 939 */ 940 public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) { 941 hostnameVerifier = newHostnameVerifier; 942 } 943 944 /** 945 * Set a {@link KeyManager} to use 946 * 947 * @param keyManager The KeyManager implementation to set. 948 * @see org.apache.commons.net.util.KeyManagerUtils 949 */ 950 public void setKeyManager(final KeyManager keyManager) { 951 this.keyManager = keyManager; 952 } 953 954 // DEPRECATED - for API compatibility only - DO NOT USE 955 956 /** 957 * Configures the socket to require client authentication. 958 * 959 * @param isNeedClientAuth The need client auth flag. 960 */ 961 public void setNeedClientAuth(final boolean isNeedClientAuth) { 962 this.isNeedClientAuth = isNeedClientAuth; 963 } 964 965 /** 966 * Override the default {@link TrustManager} to use; if set to {@code null}, the default TrustManager from the JVM will be used. 967 * 968 * @param trustManager The TrustManager implementation to set, may be {@code null} 969 * @see org.apache.commons.net.util.TrustManagerUtils 970 */ 971 public void setTrustManager(final TrustManager trustManager) { 972 this.trustManager = trustManager; 973 } 974 975 /** 976 * Configures the socket to use client (or server) mode in its first handshake. 977 * 978 * @param isClientMode The use client mode flag. 979 */ 980 public void setUseClientMode(final boolean isClientMode) { 981 this.isClientMode = isClientMode; 982 } 983 984 /** 985 * Configures the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated. 986 * 987 * @param isWantClientAuth The want client auth flag. 988 */ 989 public void setWantClientAuth(final boolean isWantClientAuth) { 990 this.isWantClientAuth = isWantClientAuth; 991 } 992 993 /** 994 * SSL/TLS negotiation. Acquires an SSL socket of a control connection and carries out handshake processing. 995 * 996 * @throws IOException If server negotiation fails 997 */ 998 protected void sslNegotiation() throws IOException { 999 plainSocket = _socket_; 1000 initSslContext(); 1001 final SSLSocket socket = createSSLSocket(_socket_); 1002 socket.setEnableSessionCreation(isCreation); 1003 socket.setUseClientMode(isClientMode); 1004 1005 // client mode 1006 if (isClientMode) { 1007 if (tlsEndpointChecking) { 1008 SSLSocketUtils.enableEndpointNameVerification(socket); 1009 } 1010 } else { // server mode 1011 socket.setNeedClientAuth(isNeedClientAuth); 1012 socket.setWantClientAuth(isWantClientAuth); 1013 } 1014 1015 if (protocols != null) { 1016 socket.setEnabledProtocols(protocols); 1017 } 1018 if (suites != null) { 1019 socket.setEnabledCipherSuites(suites); 1020 } 1021 socket.startHandshake(); 1022 1023 // TODO the following setup appears to duplicate that in the super class methods 1024 _socket_ = socket; 1025 _controlInput_ = new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); 1026 _controlOutput_ = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding())); 1027 1028 if (isClientMode && (hostnameVerifier != null && !hostnameVerifier.verify(_hostname_, socket.getSession()))) { 1029 throw new SSLHandshakeException("Hostname doesn't match certificate"); 1030 } 1031 } 1032 1033} 1034/* kate: indent-width 4; replace-tabs on; */