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