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