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(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(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(String protocol, 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(boolean isImplicit, 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(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(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 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 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(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(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(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(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(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(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(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(long pbsz) throws SSLException, IOException { 464 if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number 465 throw new IllegalArgumentException(); 466 } 467 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(long pbsz) throws SSLException, IOException { 486 execPBSZ(pbsz); 487 long minvalue = pbsz; 488 String remainder = extractPrefixedData("PBSZ=", getReplyString()); 489 if (remainder != null) { 490 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(String prot) { 541 for (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(String command, String args) throws IOException { 563 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_(int command, 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_(String command, String arg) 621 throws IOException { 622 Socket socket = super._openDataConnection_(command, arg); 623 socket = createSSLSocket(socket); 624 _prepareDataSocket_(socket); 625 if (socket instanceof SSLSocket) { 626 SSLSocket sslSocket = (SSLSocket)socket; 627 628 sslSocket.setUseClientMode(isClientMode); 629 sslSocket.setEnableSessionCreation(isCreation); 630 631 // server mode 632 if (!isClientMode) { 633 sslSocket.setNeedClientAuth(isNeedClientAuth); 634 sslSocket.setWantClientAuth(isWantClientAuth); 635 } 636 if (suites != null) { 637 sslSocket.setEnabledCipherSuites(suites); 638 } 639 if (protocols != null) { 640 sslSocket.setEnabledProtocols(protocols); 641 } 642 sslSocket.startHandshake(); 643 } 644 645 return socket; 646 } 647 648 /** 649 * Performs any custom initialization for a newly created SSLSocket (before 650 * the SSL handshake happens). 651 * Called by {@link #_openDataConnection_(int, String)} immediately 652 * after creating the socket. 653 * The default implementation is a no-op 654 * @param socket the socket to set up 655 * @throws IOException on error 656 * @since 3.1 657 */ 658 protected void _prepareDataSocket_(Socket socket) 659 throws IOException { 660 } 661 662 /** 663 * Get the currently configured {@link TrustManager}. 664 * 665 * @return A TrustManager instance. 666 */ 667 public TrustManager getTrustManager() { 668 return trustManager; 669 } 670 671 /** 672 * Override the default {@link TrustManager} to use; if set to {@code null}, 673 * the default TrustManager from the JVM will be used. 674 * 675 * @param trustManager The TrustManager implementation to set, may be {@code null} 676 * @see org.apache.commons.net.util.TrustManagerUtils 677 */ 678 public void setTrustManager(TrustManager trustManager) { 679 this.trustManager = trustManager; 680 } 681 682 /** 683 * Get the currently configured {@link HostnameVerifier}. 684 * The verifier is only used on client mode connections. 685 * @return A HostnameVerifier instance. 686 * @since 3.4 687 */ 688 public HostnameVerifier getHostnameVerifier() 689 { 690 return hostnameVerifier; 691 } 692 693 /** 694 * Override the default {@link HostnameVerifier} to use. 695 * The verifier is only used on client mode connections. 696 * @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable. 697 * @since 3.4 698 */ 699 public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) 700 { 701 hostnameVerifier = newHostnameVerifier; 702 } 703 704 /** 705 * Return whether or not endpoint identification using the HTTPS algorithm 706 * on Java 1.7+ is enabled. The default behavior is for this to be disabled. 707 * 708 * This check is only performed on client mode connections. 709 * 710 * @return True if enabled, false if not. 711 * @since 3.4 712 */ 713 public boolean isEndpointCheckingEnabled() 714 { 715 return tlsEndpointChecking; 716 } 717 718 /** 719 * Automatic endpoint identification checking using the HTTPS algorithm 720 * is supported on Java 1.7+. The default behavior is for this to be disabled. 721 * 722 * This check is only performed on client mode connections. 723 * 724 * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. 725 * @since 3.4 726 */ 727 public void setEndpointCheckingEnabled(boolean enable) 728 { 729 tlsEndpointChecking = enable; 730 } 731 732 /** 733 * Closes the connection to the FTP server and restores 734 * connection parameters to the default values. 735 * <p> 736 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} 737 * to reset the factories that may have been changed during the session, 738 * e.g. by {@link #execPROT(String)} 739 * @throws IOException If an error occurs while disconnecting. 740 * @since 3.0 741 */ 742 @Override 743 public void disconnect() throws IOException 744 { 745 super.disconnect(); 746 if (plainSocket != null) { 747 plainSocket.close(); 748 } 749 setSocketFactory(null); 750 setServerSocketFactory(null); 751 } 752 753 /** 754 * Send the AUTH command with the specified mechanism. 755 * @param mechanism The mechanism name to send with the command. 756 * @return server reply. 757 * @throws IOException If an I/O error occurs while sending 758 * the command. 759 * @since 3.0 760 */ 761 public int execAUTH(String mechanism) throws IOException 762 { 763 return sendCommand(CMD_AUTH, mechanism); 764 } 765 766 /** 767 * Send the ADAT command with the specified authentication data. 768 * @param data The data to send with the command. 769 * @return server reply. 770 * @throws IOException If an I/O error occurs while sending 771 * the command. 772 * @since 3.0 773 */ 774 public int execADAT(byte[] data) throws IOException 775 { 776 if (data != null) 777 { 778 return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); 779 } 780 else 781 { 782 return sendCommand(CMD_ADAT); 783 } 784 } 785 786 /** 787 * Send the CCC command to the server. 788 * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned 789 * to a plain {@link Socket} instances 790 * @return server reply. 791 * @throws IOException If an I/O error occurs while sending 792 * the command. 793 * @since 3.0 794 */ 795 public int execCCC() throws IOException 796 { 797 int repCode = sendCommand(CMD_CCC); 798// This will be performed by sendCommand(String, String) 799// if (FTPReply.isPositiveCompletion(repCode)) { 800// _socket_.close(); 801// _socket_ = plainSocket; 802// _controlInput_ = new BufferedReader( 803// new InputStreamReader( 804// _socket_.getInputStream(), getControlEncoding())); 805// _controlOutput_ = new BufferedWriter( 806// new OutputStreamWriter( 807// _socket_.getOutputStream(), getControlEncoding())); 808// } 809 return repCode; 810 } 811 812 /** 813 * Send the MIC command with the specified data. 814 * @param data The data to send with the command. 815 * @return server reply. 816 * @throws IOException If an I/O error occurs while sending 817 * the command. 818 * @since 3.0 819 */ 820 public int execMIC(byte[] data) throws IOException 821 { 822 if (data != null) 823 { 824 return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); 825 } 826 else 827 { 828 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? 829 } 830 } 831 832 /** 833 * Send the CONF command with the specified data. 834 * @param data The data to send with the command. 835 * @return server reply. 836 * @throws IOException If an I/O error occurs while sending 837 * the command. 838 * @since 3.0 839 */ 840 public int execCONF(byte[] data) throws IOException 841 { 842 if (data != null) 843 { 844 return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); 845 } 846 else 847 { 848 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? 849 } 850 } 851 852 /** 853 * Send the ENC command with the specified data. 854 * @param data The data to send with the command. 855 * @return server reply. 856 * @throws IOException If an I/O error occurs while sending 857 * the command. 858 * @since 3.0 859 */ 860 public int execENC(byte[] data) throws IOException 861 { 862 if (data != null) 863 { 864 return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); 865 } 866 else 867 { 868 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? 869 } 870 } 871 872 /** 873 * Parses the given ADAT response line and base64-decodes the data. 874 * @param reply The ADAT reply to parse. 875 * @return the data in the reply, base64-decoded. 876 * @since 3.0 877 */ 878 public byte[] parseADATReply(String reply) 879 { 880 if (reply == null) { 881 return null; 882 } else { 883 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); 884 } 885 } 886 887 /** 888 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 889 * @param prefix the prefix to find 890 * @param reply where to find the prefix 891 * @return the remainder of the string after the prefix, or null if the prefix was not present. 892 */ 893 private String extractPrefixedData(String prefix, String reply) { 894 int idx = reply.indexOf(prefix); 895 if (idx == -1) { 896 return null; 897 } 898 // N.B. Cannot use trim before substring as leading space would affect the offset. 899 return reply.substring(idx+prefix.length()).trim(); 900 } 901 902 /** 903 * Create SSL socket from plain socket. 904 * 905 * @param socket 906 * @return SSL Sockect 907 * @throws IOException 908 */ 909 private Socket createSSLSocket(Socket socket) throws IOException { 910 if (socket != null) { 911 SSLSocketFactory f = context.getSocketFactory(); 912 return f.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), false); 913 } else { 914 return null; 915 } 916 } 917 918 // DEPRECATED - for API compatibility only - DO NOT USE 919 920 /** @deprecated - not used - may be removed in a future release */ 921 @Deprecated 922 public static String KEYSTORE_ALGORITHM; 923 924 /** @deprecated - not used - may be removed in a future release */ 925 @Deprecated 926 public static String TRUSTSTORE_ALGORITHM; 927 928 /** @deprecated - not used - may be removed in a future release */ 929 @Deprecated 930 public static String PROVIDER; 931 932 /** @deprecated - not used - may be removed in a future release */ 933 @Deprecated 934 public static String STORE_TYPE; 935 936} 937/* kate: indent-width 4; replace-tabs on; */