1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.net.ftp; 19 20 import java.io.BufferedReader; 21 import java.io.BufferedWriter; 22 import java.io.IOException; 23 import java.io.InputStreamReader; 24 import java.io.OutputStreamWriter; 25 import java.net.Socket; 26 import javax.net.ssl.KeyManager; 27 import javax.net.ssl.SSLContext; 28 import javax.net.ssl.SSLException; 29 import javax.net.ssl.SSLSocket; 30 import javax.net.ssl.SSLSocketFactory; 31 import javax.net.ssl.TrustManager; 32 33 import org.apache.commons.net.util.Base64; 34 import org.apache.commons.net.util.SSLContextUtils; 35 import org.apache.commons.net.util.TrustManagerUtils; 36 37 /** 38 * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to 39 * see wire-level SSL details. 40 * 41 * @version $Id: FTPSClient.java 1489533 2013-06-04 17:49:00Z sebb $ 42 * @since 2.0 43 */ 44 public class FTPSClient extends FTPClient { 45 46 // From http://www.iana.org/assignments/port-numbers 47 48 // ftps-data 989/tcp ftp protocol, data, over TLS/SSL 49 // ftps-data 989/udp ftp protocol, data, over TLS/SSL 50 // ftps 990/tcp ftp protocol, control, over TLS/SSL 51 // ftps 990/udp ftp protocol, control, over TLS/SSL 52 53 public static final int DEFAULT_FTPS_DATA_PORT = 989; 54 public static final int DEFAULT_FTPS_PORT = 990; 55 56 /** The value that I can set in PROT command (C = Clear, P = Protected) */ 57 private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; 58 /** Default PROT Command */ 59 private static final String DEFAULT_PROT = "C"; 60 /** Default secure socket protocol name, i.e. TLS */ 61 private static final String DEFAULT_PROTOCOL = "TLS"; 62 63 /** The AUTH (Authentication/Security Mechanism) command. */ 64 private static final String CMD_AUTH = "AUTH"; 65 /** The ADAT (Authentication/Security Data) command. */ 66 private static final String CMD_ADAT = "ADAT"; 67 /** The PROT (Data Channel Protection Level) command. */ 68 private static final String CMD_PROT = "PROT"; 69 /** The PBSZ (Protection Buffer Size) command. */ 70 private static final String CMD_PBSZ = "PBSZ"; 71 /** The MIC (Integrity Protected Command) command. */ 72 private static final String CMD_MIC = "MIC"; 73 /** The CONF (Confidentiality Protected Command) command. */ 74 private static final String CMD_CONF = "CONF"; 75 /** The ENC (Privacy Protected Command) command. */ 76 private static final String CMD_ENC = "ENC"; 77 /** The CCC (Clear Command Channel) command. */ 78 private static final String CMD_CCC = "CCC"; 79 80 /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ 81 private final boolean isImplicit; 82 /** The secure socket protocol to be used, e.g. SSL/TLS. */ 83 private final String protocol; 84 /** The AUTH Command value */ 85 private String auth = DEFAULT_PROTOCOL; 86 /** The context object. */ 87 private SSLContext context; 88 /** The socket object. */ 89 private Socket plainSocket; 90 /** Controls whether a new SSL session may be established by this socket. Default true. */ 91 private boolean isCreation = true; 92 /** The use client mode flag. */ 93 private boolean isClientMode = true; 94 /** The need client auth flag. */ 95 private boolean isNeedClientAuth = false; 96 /** The want client auth flag. */ 97 private boolean isWantClientAuth = false; 98 /** The cipher suites */ 99 private String[] suites = null; 100 /** The protocol versions */ 101 private String[] protocols = null; 102 103 /** The FTPS {@link TrustManager} implementation, default validate only: {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. */ 104 private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); 105 106 /** The {@link KeyManager}, default null (i.e. use system default). */ 107 private KeyManager keyManager = null; 108 109 /** 110 * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. 111 * 112 * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false) 113 */ 114 public FTPSClient() { 115 this(DEFAULT_PROTOCOL, false); 116 } 117 118 /** 119 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS 120 * Calls {@link #FTPSClient(String, boolean)} 121 * @param isImplicit The security mode (Implicit/Explicit). 122 */ 123 public FTPSClient(boolean isImplicit) { 124 this(DEFAULT_PROTOCOL, isImplicit); 125 } 126 127 /** 128 * Constructor for FTPSClient, using explict mode, calls {@link #FTPSClient(String, boolean)}. 129 * 130 * @param protocol the protocol to use 131 */ 132 public FTPSClient(String protocol) { 133 this(protocol, false); 134 } 135 136 /** 137 * Constructor for FTPSClient allowing specification of protocol 138 * and security mode. If isImplicit is true, the port is set to 139 * {@link #DEFAULT_FTPS_PORT} i.e. 990. 140 * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} 141 * @param protocol the protocol 142 * @param isImplicit The security mode(Implicit/Explicit). 143 */ 144 public FTPSClient(String protocol, boolean isImplicit) { 145 super(); 146 this.protocol = protocol; 147 this.isImplicit = isImplicit; 148 if (isImplicit) { 149 setDefaultPort(DEFAULT_FTPS_PORT); 150 } 151 } 152 153 /** 154 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS 155 * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} 156 * @param isImplicit The security mode(Implicit/Explicit). 157 * @param context A pre-configured SSL Context 158 */ 159 public FTPSClient(boolean isImplicit, SSLContext context) { 160 this(DEFAULT_PROTOCOL, isImplicit); 161 this.context = context; 162 } 163 164 /** 165 * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS 166 * and isImplicit {@code false} 167 * Calls {@link #FTPSClient(boolean, SSLContext)} 168 * @param context A pre-configured SSL Context 169 */ 170 public FTPSClient(SSLContext context) { 171 this(false, context); 172 } 173 174 175 /** 176 * Set AUTH command use value. 177 * This processing is done before connected processing. 178 * @param auth AUTH command use value. 179 */ 180 public void setAuthValue(String auth) { 181 this.auth = auth; 182 } 183 184 /** 185 * Return AUTH command use value. 186 * @return AUTH command use value. 187 */ 188 public String getAuthValue() { 189 return this.auth; 190 } 191 192 193 /** 194 * Because there are so many connect() methods, 195 * the _connectAction_() method is provided as a means of performing 196 * some action immediately after establishing a connection, 197 * rather than reimplementing all of the connect() methods. 198 * @throws IOException If it throw by _connectAction_. 199 * @see org.apache.commons.net.SocketClient#_connectAction_() 200 */ 201 @Override 202 protected void _connectAction_() throws IOException { 203 // Implicit mode. 204 if (isImplicit) { 205 sslNegotiation(); 206 } 207 super._connectAction_(); 208 // Explicit mode. 209 if (!isImplicit) { 210 execAUTH(); 211 sslNegotiation(); 212 } 213 } 214 215 /** 216 * AUTH command. 217 * @throws SSLException If it server reply code not equal "234" and "334". 218 * @throws IOException If an I/O error occurs while either sending 219 * the command. 220 */ 221 protected void execAUTH() throws SSLException, IOException { 222 int replyCode = sendCommand(CMD_AUTH, auth); 223 if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { 224 // replyCode = 334 225 // I carry out an ADAT command. 226 } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { 227 throw new SSLException(getReplyString()); 228 } 229 } 230 231 /** 232 * Performs a lazy init of the SSL context 233 * @throws IOException 234 */ 235 private void initSslContext() throws IOException { 236 if (context == null) { 237 context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); 238 } 239 } 240 241 /** 242 * SSL/TLS negotiation. Acquires an SSL socket of a control 243 * connection and carries out handshake processing. 244 * @throws IOException If server negotiation fails 245 */ 246 protected void sslNegotiation() throws IOException { 247 plainSocket = _socket_; 248 initSslContext(); 249 250 SSLSocketFactory ssf = context.getSocketFactory(); 251 String ip = _socket_.getInetAddress().getHostAddress(); 252 int port = _socket_.getPort(); 253 SSLSocket socket = 254 (SSLSocket) ssf.createSocket(_socket_, ip, port, false); 255 socket.setEnableSessionCreation(isCreation); 256 socket.setUseClientMode(isClientMode); 257 // server mode 258 if (!isClientMode) { 259 socket.setNeedClientAuth(isNeedClientAuth); 260 socket.setWantClientAuth(isWantClientAuth); 261 } 262 263 if (protocols != null) { 264 socket.setEnabledProtocols(protocols); 265 } 266 if (suites != null) { 267 socket.setEnabledCipherSuites(suites); 268 } 269 socket.startHandshake(); 270 271 _socket_ = socket; 272 _controlInput_ = new BufferedReader(new InputStreamReader( 273 socket .getInputStream(), getControlEncoding())); 274 _controlOutput_ = new BufferedWriter(new OutputStreamWriter( 275 socket.getOutputStream(), getControlEncoding())); 276 } 277 278 /** 279 * Get the {@link KeyManager} instance. 280 * @return The {@link KeyManager} instance 281 */ 282 private KeyManager getKeyManager() { 283 return keyManager; 284 } 285 286 /** 287 * Set a {@link KeyManager} to use 288 * 289 * @param keyManager The KeyManager implementation to set. 290 * @see org.apache.commons.net.util.KeyManagerUtils 291 */ 292 public void setKeyManager(KeyManager keyManager) { 293 this.keyManager = keyManager; 294 } 295 296 /** 297 * Controls whether a new SSL session may be established by this socket. 298 * @param isCreation The established socket flag. 299 */ 300 public void setEnabledSessionCreation(boolean isCreation) { 301 this.isCreation = isCreation; 302 } 303 304 /** 305 * Returns true if new SSL sessions may be established by this socket. 306 * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an 307 * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, 308 * this returns False. 309 * @return true - Indicates that sessions may be created; 310 * this is the default. 311 * false - indicates that an existing session must be resumed. 312 */ 313 public boolean getEnableSessionCreation() { 314 if (_socket_ instanceof SSLSocket) { 315 return ((SSLSocket)_socket_).getEnableSessionCreation(); 316 } 317 return false; 318 } 319 320 /** 321 * Configures the socket to require client authentication. 322 * @param isNeedClientAuth The need client auth flag. 323 */ 324 public void setNeedClientAuth(boolean isNeedClientAuth) { 325 this.isNeedClientAuth = isNeedClientAuth; 326 } 327 328 /** 329 * Returns true if the socket will require client authentication. 330 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 331 * @return true - If the server mode socket should request 332 * that the client authenticate itself. 333 */ 334 public boolean getNeedClientAuth() { 335 if (_socket_ instanceof SSLSocket) { 336 return ((SSLSocket)_socket_).getNeedClientAuth(); 337 } 338 return false; 339 } 340 341 /** 342 * Configures the socket to request client authentication, 343 * but only if such a request is appropriate to the cipher 344 * suite negotiated. 345 * @param isWantClientAuth The want client auth flag. 346 */ 347 public void setWantClientAuth(boolean isWantClientAuth) { 348 this.isWantClientAuth = isWantClientAuth; 349 } 350 351 /** 352 * Returns true if the socket will request client authentication. 353 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 354 * @return true - If the server mode socket should request 355 * that the client authenticate itself. 356 */ 357 public boolean getWantClientAuth() { 358 if (_socket_ instanceof SSLSocket) { 359 return ((SSLSocket)_socket_).getWantClientAuth(); 360 } 361 return false; 362 } 363 364 /** 365 * Configures the socket to use client (or server) mode in its first 366 * handshake. 367 * @param isClientMode The use client mode flag. 368 */ 369 public void setUseClientMode(boolean isClientMode) { 370 this.isClientMode = isClientMode; 371 } 372 373 /** 374 * Returns true if the socket is set to use client mode 375 * in its first handshake. 376 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. 377 * @return true - If the socket should start its first handshake 378 * in "client" mode. 379 */ 380 public boolean getUseClientMode() { 381 if (_socket_ instanceof SSLSocket) { 382 return ((SSLSocket)_socket_).getUseClientMode(); 383 } 384 return false; 385 } 386 387 /** 388 * Controls which particular cipher suites are enabled for use on this 389 * connection. Called before server negotiation. 390 * @param cipherSuites The cipher suites. 391 */ 392 public void setEnabledCipherSuites(String[] cipherSuites) { 393 suites = new String[cipherSuites.length]; 394 System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); 395 } 396 397 /** 398 * Returns the names of the cipher suites which could be enabled 399 * for use on this connection. 400 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. 401 * @return An array of cipher suite names, or <code>null</code> 402 */ 403 public String[] getEnabledCipherSuites() { 404 if (_socket_ instanceof SSLSocket) { 405 return ((SSLSocket)_socket_).getEnabledCipherSuites(); 406 } 407 return null; 408 } 409 410 /** 411 * Controls which particular protocol versions are enabled for use on this 412 * connection. I perform setting before a server negotiation. 413 * @param protocolVersions The protocol versions. 414 */ 415 public void setEnabledProtocols(String[] protocolVersions) { 416 protocols = new String[protocolVersions.length]; 417 System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); 418 } 419 420 /** 421 * Returns the names of the protocol versions which are currently 422 * enabled for use on this connection. 423 * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. 424 * @return An array of protocols, or <code>null</code> 425 */ 426 public String[] getEnabledProtocols() { 427 if (_socket_ instanceof SSLSocket) { 428 return ((SSLSocket)_socket_).getEnabledProtocols(); 429 } 430 return null; 431 } 432 433 /** 434 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 435 * @param pbsz Protection Buffer Size. 436 * @throws SSLException If the server reply code does not equal "200". 437 * @throws IOException If an I/O error occurs while sending 438 * the command. 439 * @see #parsePBSZ(long) 440 */ 441 public void execPBSZ(long pbsz) throws SSLException, IOException { 442 if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number 443 throw new IllegalArgumentException(); 444 } 445 int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); 446 if (FTPReply.COMMAND_OK != status) { 447 throw new SSLException(getReplyString()); 448 } 449 } 450 451 /** 452 * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. 453 * Issues the command and parses the response to return the negotiated value. 454 * 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 * @return the negotiated value. 460 * @see #execPBSZ(long) 461 * @since 3.0 462 */ 463 public long parsePBSZ(long pbsz) throws SSLException, IOException { 464 execPBSZ(pbsz); 465 long minvalue = pbsz; 466 String remainder = extractPrefixedData("PBSZ=", getReplyString()); 467 if (remainder != null) { 468 long replysz = Long.parseLong(remainder); 469 if (replysz < minvalue) { 470 minvalue = replysz; 471 } 472 } 473 return minvalue; 474 } 475 476 /** 477 * PROT command. 478 * <ul> 479 * <li>C - Clear</li> 480 * <li>S - Safe(SSL protocol only)</li> 481 * <li>E - Confidential(SSL protocol only)</li> 482 * <li>P - Private</li> 483 * </ul> 484 * <b>N.B.</b> the method calls 485 * {@link #setSocketFactory(javax.net.SocketFactory)} and 486 * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} 487 * 488 * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}. 489 * @throws SSLException If the server reply code does not equal {@code 200}. 490 * @throws IOException If an I/O error occurs while sending 491 * the command. 492 */ 493 public void execPROT(String prot) throws SSLException, IOException { 494 if (prot == null) { 495 prot = DEFAULT_PROT; 496 } 497 if (!checkPROTValue(prot)) { 498 throw new IllegalArgumentException(); 499 } 500 if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) { 501 throw new SSLException(getReplyString()); 502 } 503 if (DEFAULT_PROT.equals(prot)) { 504 setSocketFactory(null); 505 setServerSocketFactory(null); 506 } else { 507 setSocketFactory(new FTPSSocketFactory(context)); 508 setServerSocketFactory(new FTPSServerSocketFactory(context)); 509 initSslContext(); 510 } 511 } 512 513 /** 514 * Check the value that can be set in PROT Command value. 515 * @param prot Data Channel Protection Level. 516 * @return True - A set point is right / False - A set point is not right 517 */ 518 private boolean checkPROTValue(String prot) { 519 for (String element : PROT_COMMAND_VALUE) 520 { 521 if (element.equals(prot)) { 522 return true; 523 } 524 } 525 return false; 526 } 527 528 /** 529 * Send an FTP command. 530 * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} 531 * instance to be assigned to a plain {@link Socket} 532 * @param command The FTP command. 533 * @return server reply. 534 * @throws IOException If an I/O error occurs while sending the command. 535 * @throws SSLException if a CCC command fails 536 * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) 537 */ 538 // Would like to remove this method, but that will break any existing clients that are using CCC 539 @Override 540 public int sendCommand(String command, String args) throws IOException { 541 int repCode = super.sendCommand(command, args); 542 /* If CCC is issued, restore socket i/o streams to unsecured versions */ 543 if (CMD_CCC.equals(command)) { 544 if (FTPReply.COMMAND_OK == repCode) { 545 _socket_.close(); 546 _socket_ = plainSocket; 547 _controlInput_ = new BufferedReader( 548 new InputStreamReader( 549 _socket_ .getInputStream(), getControlEncoding())); 550 _controlOutput_ = new BufferedWriter( 551 new OutputStreamWriter( 552 _socket_.getOutputStream(), getControlEncoding())); 553 } else { 554 throw new SSLException(getReplyString()); 555 } 556 } 557 return repCode; 558 } 559 560 /** 561 * Returns a socket of the data connection. 562 * Wrapped as an {@link SSLSocket}, which carries out handshake processing. 563 * @param command The int representation of the FTP command to send. 564 * @param arg The arguments to the FTP command. 565 * If this parameter is set to null, then the command is sent with 566 * no arguments. 567 * @return corresponding to the established data connection. 568 * Null is returned if an FTP protocol error is reported at any point 569 * during the establishment and initialization of the connection. 570 * @throws IOException If there is any problem with the connection. 571 * @see FTPClient#_openDataConnection_(int, String) 572 * @deprecated (3.3) Use {@link #_openDataConnection_(FTPCmd, String)} instead 573 */ 574 @Override 575 // Strictly speaking this is not needed, but it works round a Clirr bug 576 // So rather than invoke the parent code, we do it here 577 @Deprecated 578 protected Socket _openDataConnection_(int command, String arg) 579 throws IOException { 580 return _openDataConnection_(FTPCommand.getCommand(command), arg); 581 } 582 583 /** 584 * Returns a socket of the data connection. 585 * Wrapped as an {@link SSLSocket}, which carries out handshake processing. 586 * @param command The textual representation of the FTP command to send. 587 * @param arg The arguments to the FTP command. 588 * If this parameter is set to null, then the command is sent with 589 * no arguments. 590 * @return corresponding to the established data connection. 591 * Null is returned if an FTP protocol error is reported at any point 592 * during the establishment and initialization of the connection. 593 * @throws IOException If there is any problem with the connection. 594 * @see FTPClient#_openDataConnection_(int, String) 595 * @since 3.2 596 */ 597 @Override 598 protected Socket _openDataConnection_(String command, String arg) 599 throws IOException { 600 Socket socket = super._openDataConnection_(command, arg); 601 _prepareDataSocket_(socket); 602 if (socket instanceof SSLSocket) { 603 SSLSocket sslSocket = (SSLSocket)socket; 604 605 sslSocket.setUseClientMode(isClientMode); 606 sslSocket.setEnableSessionCreation(isCreation); 607 608 // server mode 609 if (!isClientMode) { 610 sslSocket.setNeedClientAuth(isNeedClientAuth); 611 sslSocket.setWantClientAuth(isWantClientAuth); 612 } 613 if (suites != null) { 614 sslSocket.setEnabledCipherSuites(suites); 615 } 616 if (protocols != null) { 617 sslSocket.setEnabledProtocols(protocols); 618 } 619 sslSocket.startHandshake(); 620 } 621 622 return socket; 623 } 624 625 /** 626 * Performs any custom initialization for a newly created SSLSocket (before 627 * the SSL handshake happens). 628 * Called by {@link #_openDataConnection_(int, String)} immediately 629 * after creating the socket. 630 * The default implementation is a no-op 631 * @throws IOException 632 * @since 3.1 633 */ 634 protected void _prepareDataSocket_(Socket socket) 635 throws IOException { 636 } 637 638 /** 639 * Get the currently configured {@link TrustManager}. 640 * 641 * @return A TrustManager instance. 642 */ 643 public TrustManager getTrustManager() { 644 return trustManager; 645 } 646 647 /** 648 * Override the default {@link TrustManager} to use; if set to {@code null}, 649 * the default TrustManager from the JVM will be used. 650 * 651 * @param trustManager The TrustManager implementation to set, may be {@code null} 652 * @see org.apache.commons.net.util.TrustManagerUtils 653 */ 654 public void setTrustManager(TrustManager trustManager) { 655 this.trustManager = trustManager; 656 } 657 658 /** 659 * Closes the connection to the FTP server and restores 660 * connection parameters to the default values. 661 * <p> 662 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} 663 * to reset the factories that may have been changed during the session, 664 * e.g. by {@link #execPROT(String)} 665 * @exception IOException If an error occurs while disconnecting. 666 * @since 3.0 667 */ 668 @Override 669 public void disconnect() throws IOException 670 { 671 super.disconnect(); 672 setSocketFactory(null); 673 setServerSocketFactory(null); 674 } 675 676 /** 677 * Send the AUTH command with the specified mechanism. 678 * @param mechanism The mechanism name to send with the command. 679 * @return server reply. 680 * @throws IOException If an I/O error occurs while sending 681 * the command. 682 * @since 3.0 683 */ 684 public int execAUTH(String mechanism) throws IOException 685 { 686 return sendCommand(CMD_AUTH, mechanism); 687 } 688 689 /** 690 * Send the ADAT command with the specified authentication data. 691 * @param data The data to send with the command. 692 * @return server reply. 693 * @throws IOException If an I/O error occurs while sending 694 * the command. 695 * @since 3.0 696 */ 697 public int execADAT(byte[] data) throws IOException 698 { 699 if (data != null) 700 { 701 return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); 702 } 703 else 704 { 705 return sendCommand(CMD_ADAT); 706 } 707 } 708 709 /** 710 * Send the CCC command to the server. 711 * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned 712 * to a plain {@link Socket} instances 713 * @return server reply. 714 * @throws IOException If an I/O error occurs while sending 715 * the command. 716 * @since 3.0 717 */ 718 public int execCCC() throws IOException 719 { 720 int repCode = sendCommand(CMD_CCC); 721 // This will be performed by sendCommand(String, String) 722 // if (FTPReply.isPositiveCompletion(repCode)) { 723 // _socket_.close(); 724 // _socket_ = plainSocket; 725 // _controlInput_ = new BufferedReader( 726 // new InputStreamReader( 727 // _socket_.getInputStream(), getControlEncoding())); 728 // _controlOutput_ = new BufferedWriter( 729 // new OutputStreamWriter( 730 // _socket_.getOutputStream(), getControlEncoding())); 731 // } 732 return repCode; 733 } 734 735 /** 736 * Send the MIC command with the specified data. 737 * @param data The data to send with the command. 738 * @return server reply. 739 * @throws IOException If an I/O error occurs while sending 740 * the command. 741 * @since 3.0 742 */ 743 public int execMIC(byte[] data) throws IOException 744 { 745 if (data != null) 746 { 747 return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); 748 } 749 else 750 { 751 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? 752 } 753 } 754 755 /** 756 * Send the CONF command with the specified data. 757 * @param data The data to send with the command. 758 * @return server reply. 759 * @throws IOException If an I/O error occurs while sending 760 * the command. 761 * @since 3.0 762 */ 763 public int execCONF(byte[] data) throws IOException 764 { 765 if (data != null) 766 { 767 return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); 768 } 769 else 770 { 771 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? 772 } 773 } 774 775 /** 776 * Send the ENC command with the specified data. 777 * @param data The data to send with the command. 778 * @return server reply. 779 * @throws IOException If an I/O error occurs while sending 780 * the command. 781 * @since 3.0 782 */ 783 public int execENC(byte[] data) throws IOException 784 { 785 if (data != null) 786 { 787 return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); 788 } 789 else 790 { 791 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? 792 } 793 } 794 795 /** 796 * Parses the given ADAT response line and base64-decodes the data. 797 * @param reply The ADAT reply to parse. 798 * @return the data in the reply, base64-decoded. 799 * @since 3.0 800 */ 801 public byte[] parseADATReply(String reply) 802 { 803 if (reply == null) { 804 return null; 805 } else { 806 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); 807 } 808 } 809 810 /** 811 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 812 * @param prefix the prefix to find 813 * @param reply where to find the prefix 814 * @return the remainder of the string after the prefix, or null if the prefix was not present. 815 */ 816 private String extractPrefixedData(String prefix, String reply) { 817 int idx = reply.indexOf(prefix); 818 if (idx == -1) { 819 return null; 820 } 821 // N.B. Cannot use trim before substring as leading space would affect the offset. 822 return reply.substring(idx+prefix.length()).trim(); 823 } 824 825 // DEPRECATED - for API compatibility only - DO NOT USE 826 827 /** @deprecated - not used - may be removed in a future release */ 828 @Deprecated 829 public static String KEYSTORE_ALGORITHM; 830 831 /** @deprecated - not used - may be removed in a future release */ 832 @Deprecated 833 public static String TRUSTSTORE_ALGORITHM; 834 835 /** @deprecated - not used - may be removed in a future release */ 836 @Deprecated 837 public static String PROVIDER; 838 839 /** @deprecated - not used - may be removed in a future release */ 840 @Deprecated 841 public static String STORE_TYPE; 842 843 } 844 /* kate: indent-width 4; replace-tabs on; */