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; 102 /** The want client auth flag. */ 103 private boolean isWantClientAuth; 104 /** The cipher suites */ 105 private String[] suites; 106 /** The protocol versions */ 107 private String[] protocols; 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; 116 117 /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ 118 private HostnameVerifier hostnameVerifier; 119 120 /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */ 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 this.protocol = protocol; 160 this.isImplicit = isImplicit; 161 if (isImplicit) { 162 setDefaultPort(DEFAULT_FTPS_PORT); 163 } 164 } 165 166 /** 167 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS 168 * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} 169 * @param isImplicit The security mode(Implicit/Explicit). 170 * @param context A pre-configured SSL Context 171 */ 172 public FTPSClient(final boolean isImplicit, final SSLContext context) { 173 this(DEFAULT_PROTOCOL, isImplicit); 174 this.context = context; 175 } 176 177 /** 178 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS 179 * and isImplicit {@code false} 180 * Calls {@link #FTPSClient(boolean, SSLContext)} 181 * @param context A pre-configured SSL Context 182 */ 183 public FTPSClient(final SSLContext context) { 184 this(false, context); 185 } 186 187 188 /** 189 * Set AUTH command use value. 190 * This processing is done before connected processing. 191 * @param auth AUTH command use value. 192 */ 193 public void setAuthValue(final String auth) { 194 this.auth = auth; 195 } 196 197 /** 198 * Return AUTH command use value. 199 * @return AUTH command use value. 200 */ 201 public String getAuthValue() { 202 return this.auth; 203 } 204 205 206 /** 207 * Because there are so many connect() methods, 208 * the _connectAction_() method is provided as a means of performing 209 * some action immediately after establishing a connection, 210 * rather than reimplementing all of the connect() methods. 211 * @throws IOException If it throw by _connectAction_. 212 * @see org.apache.commons.net.SocketClient#_connectAction_() 213 */ 214 @Override 215 protected void _connectAction_() throws IOException { 216 // Implicit mode. 217 if (isImplicit) { 218 applySocketAttributes(); 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 = 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(_hostname_, 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 = cipherSuites.clone(); 416 } 417 418 /** 419 * Returns the names of the cipher suites which could be enabled 420 * for use on this connection. 421 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. 422 * @return An array of cipher suite names, or <code>null</code> 423 */ 424 public String[] getEnabledCipherSuites() { 425 if (_socket_ instanceof SSLSocket) { 426 return ((SSLSocket)_socket_).getEnabledCipherSuites(); 427 } 428 return null; 429 } 430 431 /** 432 * Controls which particular protocol versions are enabled for use on this 433 * connection. I perform setting before a server negotiation. 434 * @param protocolVersions The protocol versions. 435 */ 436 public void setEnabledProtocols(final String[] protocolVersions) { 437 protocols = protocolVersions.clone(); 438 } 439 440 /** 441 * Returns the names of the protocol versions which are currently 442 * enabled for use on this connection. 443 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. 444 * @return An array of protocols, or <code>null</code> 445 */ 446 public String[] getEnabledProtocols() { 447 if (_socket_ instanceof SSLSocket) { 448 return ((SSLSocket)_socket_).getEnabledProtocols(); 449 } 450 return null; 451 } 452 453 /** 454 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 455 * @param pbsz Protection Buffer Size. 456 * @throws SSLException If the server reply code does not equal "200". 457 * @throws IOException If an I/O error occurs while sending 458 * the command. 459 * @see #parsePBSZ(long) 460 */ 461 public void execPBSZ(final long pbsz) throws SSLException, IOException { 462 if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number 463 throw new IllegalArgumentException(); 464 } 465 final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); 466 if (FTPReply.COMMAND_OK != status) { 467 throw new SSLException(getReplyString()); 468 } 469 } 470 471 /** 472 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 473 * Issues the command and parses the response to return the negotiated value. 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 478 * the command. 479 * @return the negotiated value. 480 * @see #execPBSZ(long) 481 * @since 3.0 482 */ 483 public long parsePBSZ(final long pbsz) throws SSLException, IOException { 484 execPBSZ(pbsz); 485 long minvalue = pbsz; 486 final String remainder = extractPrefixedData("PBSZ=", getReplyString()); 487 if (remainder != null) { 488 final long replysz = Long.parseLong(remainder); 489 if (replysz < minvalue) { 490 minvalue = replysz; 491 } 492 } 493 return minvalue; 494 } 495 496 /** 497 * PROT command. 498 * <ul> 499 * <li>C - Clear</li> 500 * <li>S - Safe(SSL protocol only)</li> 501 * <li>E - Confidential(SSL protocol only)</li> 502 * <li>P - Private</li> 503 * </ul> 504 * <b>N.B.</b> the method calls 505 * {@link #setSocketFactory(javax.net.SocketFactory)} and 506 * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} 507 * 508 * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}. 509 * @throws SSLException If the server reply code does not equal {@code 200}. 510 * @throws IOException If an I/O error occurs while sending 511 * the command. 512 */ 513 public void execPROT(String prot) throws SSLException, IOException { 514 if (prot == null) { 515 prot = DEFAULT_PROT; 516 } 517 if (!checkPROTValue(prot)) { 518 throw new IllegalArgumentException(); 519 } 520 if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) { 521 throw new SSLException(getReplyString()); 522 } 523 if (DEFAULT_PROT.equals(prot)) { 524 setSocketFactory(null); 525 setServerSocketFactory(null); 526 } else { 527 setSocketFactory(new FTPSSocketFactory(context)); 528 setServerSocketFactory(new FTPSServerSocketFactory(context)); 529 initSslContext(); 530 } 531 } 532 533 /** 534 * Check the value that can be set in PROT Command value. 535 * @param prot Data Channel Protection Level. 536 * @return True - A set point is right / False - A set point is not right 537 */ 538 private boolean checkPROTValue(final String prot) { 539 for (final String element : PROT_COMMAND_VALUE) 540 { 541 if (element.equals(prot)) { 542 return true; 543 } 544 } 545 return false; 546 } 547 548 /** 549 * Send an FTP command. 550 * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} 551 * instance to be assigned to a plain {@link Socket} 552 * @param command The FTP command. 553 * @return server reply. 554 * @throws IOException If an I/O error occurs while sending the command. 555 * @throws SSLException if a CCC command fails 556 * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) 557 */ 558 // Would like to remove this method, but that will break any existing clients that are using CCC 559 @Override 560 public int sendCommand(final String command, final String args) throws IOException { 561 final int repCode = super.sendCommand(command, args); 562 /* If CCC is issued, restore socket i/o streams to unsecured versions */ 563 if (CMD_CCC.equals(command)) { 564 if (FTPReply.COMMAND_OK == repCode) { 565 _socket_.close(); 566 _socket_ = plainSocket; 567 _controlInput_ = new BufferedReader( 568 new InputStreamReader( 569 _socket_ .getInputStream(), getControlEncoding())); 570 _controlOutput_ = new BufferedWriter( 571 new OutputStreamWriter( 572 _socket_.getOutputStream(), getControlEncoding())); 573 } else { 574 throw new SSLException(getReplyString()); 575 } 576 } 577 return repCode; 578 } 579 580 /** 581 * Returns a socket of the data connection. 582 * Wrapped as an {@link SSLSocket}, which carries out handshake processing. 583 * @param command The int representation of the FTP command to send. 584 * @param arg The arguments to the FTP command. 585 * If this parameter is set to null, then the command is sent with 586 * no arguments. 587 * @return corresponding to the established data connection. 588 * Null is returned if an FTP protocol error is reported at any point 589 * during the establishment and initialization of the connection. 590 * @throws IOException If there is any problem with the connection. 591 * @see FTPClient#_openDataConnection_(int, String) 592 * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead 593 */ 594 @Override 595 // Strictly speaking this is not needed, but it works round a Clirr bug 596 // So rather than invoke the parent code, we do it here 597 @Deprecated 598 protected Socket _openDataConnection_(final int command, final String arg) 599 throws IOException { 600 return _openDataConnection_(FTPCommand.getCommand(command), arg); 601 } 602 603 /** 604 * Returns a socket of the data connection. 605 * Wrapped as an {@link SSLSocket}, which carries out handshake processing. 606 * @param command The textual representation of the FTP command to send. 607 * @param arg The arguments to the FTP command. 608 * If this parameter is set to null, then the command is sent with 609 * no arguments. 610 * @return corresponding to the established data connection. 611 * Null is returned if an FTP protocol error is reported at any point 612 * during the establishment and initialization of the connection. 613 * @throws IOException If there is any problem with the connection. 614 * @see FTPClient#_openDataConnection_(int, String) 615 * @since 3.2 616 */ 617 @Override 618 protected Socket _openDataConnection_(final String command, final String arg) 619 throws IOException { 620 final Socket socket = super._openDataConnection_(command, arg); 621 _prepareDataSocket_(socket); 622 if (socket instanceof SSLSocket) { 623 final SSLSocket sslSocket = (SSLSocket)socket; 624 625 sslSocket.setUseClientMode(isClientMode); 626 sslSocket.setEnableSessionCreation(isCreation); 627 628 // server mode 629 if (!isClientMode) { 630 sslSocket.setNeedClientAuth(isNeedClientAuth); 631 sslSocket.setWantClientAuth(isWantClientAuth); 632 } 633 if (suites != null) { 634 sslSocket.setEnabledCipherSuites(suites); 635 } 636 if (protocols != null) { 637 sslSocket.setEnabledProtocols(protocols); 638 } 639 sslSocket.startHandshake(); 640 } 641 642 return socket; 643 } 644 645 /** 646 * Performs any custom initialization for a newly created SSLSocket (before 647 * the SSL handshake happens). 648 * Called by {@link #_openDataConnection_(int, String)} immediately 649 * after creating the socket. 650 * The default implementation is a no-op 651 * @param socket the socket to set up 652 * @throws IOException on error 653 * @since 3.1 654 */ 655 protected void _prepareDataSocket_(final Socket socket) 656 throws IOException { 657 } 658 659 /** 660 * Get the currently configured {@link TrustManager}. 661 * 662 * @return A TrustManager instance. 663 */ 664 public TrustManager getTrustManager() { 665 return trustManager; 666 } 667 668 /** 669 * Override the default {@link TrustManager} to use; if set to {@code null}, 670 * the default TrustManager from the JVM will be used. 671 * 672 * @param trustManager The TrustManager implementation to set, may be {@code null} 673 * @see org.apache.commons.net.util.TrustManagerUtils 674 */ 675 public void setTrustManager(final TrustManager trustManager) { 676 this.trustManager = trustManager; 677 } 678 679 /** 680 * Get the currently configured {@link HostnameVerifier}. 681 * The verifier is only used on client mode connections. 682 * @return A HostnameVerifier instance. 683 * @since 3.4 684 */ 685 public HostnameVerifier getHostnameVerifier() 686 { 687 return hostnameVerifier; 688 } 689 690 /** 691 * Override the default {@link HostnameVerifier} to use. 692 * The verifier is only used on client mode connections. 693 * @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable. 694 * @since 3.4 695 */ 696 public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) 697 { 698 hostnameVerifier = newHostnameVerifier; 699 } 700 701 /** 702 * Return whether or not endpoint identification using the HTTPS algorithm 703 * on Java 1.7+ is enabled. The default behavior is for this to be disabled. 704 * 705 * This check is only performed on client mode connections. 706 * 707 * @return True if enabled, false if not. 708 * @since 3.4 709 */ 710 public boolean isEndpointCheckingEnabled() 711 { 712 return tlsEndpointChecking; 713 } 714 715 /** 716 * Automatic endpoint identification checking using the HTTPS algorithm 717 * is supported on Java 1.7+. The default behavior is for this to be disabled. 718 * 719 * This check is only performed on client mode connections. 720 * 721 * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. 722 * @since 3.4 723 */ 724 public void setEndpointCheckingEnabled(final boolean enable) 725 { 726 tlsEndpointChecking = enable; 727 } 728 729 /** 730 * Closes the connection to the FTP server and restores 731 * connection parameters to the default values. 732 * <p> 733 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} 734 * to reset the factories that may have been changed during the session, 735 * e.g. by {@link #execPROT(String)} 736 * @throws IOException If an error occurs while disconnecting. 737 * @since 3.0 738 */ 739 @Override 740 public void disconnect() throws IOException 741 { 742 super.disconnect(); 743 if (plainSocket != null) { 744 plainSocket.close(); 745 } 746 setSocketFactory(null); 747 setServerSocketFactory(null); 748 } 749 750 /** 751 * Send the AUTH command with the specified mechanism. 752 * @param mechanism The mechanism name to send with the command. 753 * @return server reply. 754 * @throws IOException If an I/O error occurs while sending 755 * the command. 756 * @since 3.0 757 */ 758 public int execAUTH(final String mechanism) throws IOException 759 { 760 return sendCommand(CMD_AUTH, mechanism); 761 } 762 763 /** 764 * Send the ADAT command with the specified authentication data. 765 * @param data The data to send with the command. 766 * @return server reply. 767 * @throws IOException If an I/O error occurs while sending 768 * the command. 769 * @since 3.0 770 */ 771 public int execADAT(final byte[] data) throws IOException 772 { 773 if (data != null) 774 { 775 return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); 776 } 777 return sendCommand(CMD_ADAT); 778 } 779 780 /** 781 * Send the CCC command to the server. 782 * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned 783 * to a plain {@link Socket} instances 784 * @return server reply. 785 * @throws IOException If an I/O error occurs while sending 786 * the command. 787 * @since 3.0 788 */ 789 public int execCCC() throws IOException 790 { 791 final int repCode = sendCommand(CMD_CCC); 792// This will be performed by sendCommand(String, String) 793// if (FTPReply.isPositiveCompletion(repCode)) { 794// _socket_.close(); 795// _socket_ = plainSocket; 796// _controlInput_ = new BufferedReader( 797// new InputStreamReader( 798// _socket_.getInputStream(), getControlEncoding())); 799// _controlOutput_ = new BufferedWriter( 800// new OutputStreamWriter( 801// _socket_.getOutputStream(), getControlEncoding())); 802// } 803 return repCode; 804 } 805 806 /** 807 * Send the MIC command with the specified data. 808 * @param data The data to send with the command. 809 * @return server reply. 810 * @throws IOException If an I/O error occurs while sending 811 * the command. 812 * @since 3.0 813 */ 814 public int execMIC(final byte[] data) throws IOException 815 { 816 if (data != null) 817 { 818 return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); 819 } 820 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? 821 } 822 823 /** 824 * Send the CONF command with the specified data. 825 * @param data The data to send with the command. 826 * @return server reply. 827 * @throws IOException If an I/O error occurs while sending 828 * the command. 829 * @since 3.0 830 */ 831 public int execCONF(final byte[] data) throws IOException 832 { 833 if (data != null) 834 { 835 return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); 836 } 837 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? 838 } 839 840 /** 841 * Send the ENC command with the specified data. 842 * @param data The data to send with the command. 843 * @return server reply. 844 * @throws IOException If an I/O error occurs while sending 845 * the command. 846 * @since 3.0 847 */ 848 public int execENC(final byte[] data) throws IOException 849 { 850 if (data != null) 851 { 852 return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); 853 } 854 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? 855 } 856 857 /** 858 * Parses the given ADAT response line and base64-decodes the data. 859 * @param reply The ADAT reply to parse. 860 * @return the data in the reply, base64-decoded. 861 * @since 3.0 862 */ 863 public byte[] parseADATReply(final String reply) 864 { 865 if (reply == null) { 866 return null; 867 } 868 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); 869 } 870 871 /** 872 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 873 * @param prefix the prefix to find 874 * @param reply where to find the prefix 875 * @return the remainder of the string after the prefix, or null if the prefix was not present. 876 */ 877 private String extractPrefixedData(final String prefix, final String reply) { 878 final int idx = reply.indexOf(prefix); 879 if (idx == -1) { 880 return null; 881 } 882 // N.B. Cannot use trim before substring as leading space would affect the offset. 883 return reply.substring(idx+prefix.length()).trim(); 884 } 885 886 /** 887 * Create SSL socket from plain socket. 888 * 889 * @param socket 890 * @return SSL Socket 891 * @throws IOException 892 */ 893 private SSLSocket createSSLSocket(final Socket socket) throws IOException { 894 if (socket != null) { 895 final SSLSocketFactory f = context.getSocketFactory(); 896 return (SSLSocket) f.createSocket(socket, _hostname_, socket.getPort(), false); 897 } 898 return null; 899 } 900 901 // DEPRECATED - for API compatibility only - DO NOT USE 902 903 /** @deprecated - not used - may be removed in a future release */ 904 @Deprecated 905 public static String KEYSTORE_ALGORITHM; 906 907 /** @deprecated - not used - may be removed in a future release */ 908 @Deprecated 909 public static String TRUSTSTORE_ALGORITHM; 910 911 /** @deprecated - not used - may be removed in a future release */ 912 @Deprecated 913 public static String PROVIDER; 914 915 /** @deprecated - not used - may be removed in a future release */ 916 @Deprecated 917 public static String STORE_TYPE; 918 919} 920/* kate: indent-width 4; replace-tabs on; */