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 018 package org.apache.commons.net.ftp; 019 020 import java.io.BufferedReader; 021 import java.io.BufferedWriter; 022 import java.io.IOException; 023 import java.io.InputStreamReader; 024 import java.io.OutputStreamWriter; 025 import java.net.Socket; 026 import javax.net.ssl.KeyManager; 027 import javax.net.ssl.SSLContext; 028 import javax.net.ssl.SSLException; 029 import javax.net.ssl.SSLSocket; 030 import javax.net.ssl.SSLSocketFactory; 031 import javax.net.ssl.TrustManager; 032 033 import org.apache.commons.net.util.Base64; 034 import org.apache.commons.net.util.SSLContextUtils; 035 import org.apache.commons.net.util.TrustManagerUtils; 036 037 /** 038 * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to 039 * see wire-level SSL details. 040 * 041 * @version $Id: FTPSClient.java 1407341 2012-11-09 01:31:00Z ggregory $ 042 * @since 2.0 043 */ 044 public class FTPSClient extends FTPClient { 045 046 // From http://www.iana.org/assignments/port-numbers 047 048 // ftps-data 989/tcp ftp protocol, data, over TLS/SSL 049 // ftps-data 989/udp ftp protocol, data, over TLS/SSL 050 // ftps 990/tcp ftp protocol, control, over TLS/SSL 051 // ftps 990/udp ftp protocol, control, over TLS/SSL 052 053 public static final int DEFAULT_FTPS_DATA_PORT = 989; 054 public static final int DEFAULT_FTPS_PORT = 990; 055 056 /** The value that I can set in PROT command (C = Clear, P = Protected) */ 057 private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; 058 /** Default PROT Command */ 059 private static final String DEFAULT_PROT = "C"; 060 /** Default secure socket protocol name, i.e. TLS */ 061 private static final String DEFAULT_PROTOCOL = "TLS"; 062 063 /** The AUTH (Authentication/Security Mechanism) command. */ 064 private static final String CMD_AUTH = "AUTH"; 065 /** The ADAT (Authentication/Security Data) command. */ 066 private static final String CMD_ADAT = "ADAT"; 067 /** The PROT (Data Channel Protection Level) command. */ 068 private static final String CMD_PROT = "PROT"; 069 /** The PBSZ (Protection Buffer Size) command. */ 070 private static final String CMD_PBSZ = "PBSZ"; 071 /** The MIC (Integrity Protected Command) command. */ 072 private static final String CMD_MIC = "MIC"; 073 /** The CONF (Confidentiality Protected Command) command. */ 074 private static final String CMD_CONF = "CONF"; 075 /** The ENC (Privacy Protected Command) command. */ 076 private static final String CMD_ENC = "ENC"; 077 /** The CCC (Clear Command Channel) command. */ 078 private static final String CMD_CCC = "CCC"; 079 080 /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ 081 private final boolean isImplicit; 082 /** The secure socket protocol to be used, e.g. SSL/TLS. */ 083 private final String protocol; 084 /** The AUTH Command value */ 085 private String auth = DEFAULT_PROTOCOL; 086 /** The context object. */ 087 private SSLContext context; 088 /** The socket object. */ 089 private Socket plainSocket; 090 /** Controls whether a new SSL session may be established by this socket. Default true. */ 091 private boolean isCreation = true; 092 /** The use client mode flag. */ 093 private boolean isClientMode = true; 094 /** The need client auth flag. */ 095 private boolean isNeedClientAuth = false; 096 /** The want client auth flag. */ 097 private boolean isWantClientAuth = false; 098 /** The cipher suites */ 099 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 */ 573 @Override 574 // Strictly speaking this is not needed, but it works round a Clirr bug 575 // So rather than invoke the parent code, we do it here 576 protected Socket _openDataConnection_(int command, String arg) 577 throws IOException { 578 return _openDataConnection_(FTPCommand.getCommand(command), arg); 579 } 580 581 /** 582 * Returns a socket of the data connection. 583 * Wrapped as an {@link SSLSocket}, which carries out handshake processing. 584 * @param command The textual representation of the FTP command to send. 585 * @param arg The arguments to the FTP command. 586 * If this parameter is set to null, then the command is sent with 587 * no arguments. 588 * @return corresponding to the established data connection. 589 * Null is returned if an FTP protocol error is reported at any point 590 * during the establishment and initialization of the connection. 591 * @throws IOException If there is any problem with the connection. 592 * @see FTPClient#_openDataConnection_(int, String) 593 * @since 3.2 594 */ 595 @Override 596 protected Socket _openDataConnection_(String command, String arg) 597 throws IOException { 598 Socket socket = super._openDataConnection_(command, arg); 599 _prepareDataSocket_(socket); 600 if (socket instanceof SSLSocket) { 601 SSLSocket sslSocket = (SSLSocket)socket; 602 603 sslSocket.setUseClientMode(isClientMode); 604 sslSocket.setEnableSessionCreation(isCreation); 605 606 // server mode 607 if (!isClientMode) { 608 sslSocket.setNeedClientAuth(isNeedClientAuth); 609 sslSocket.setWantClientAuth(isWantClientAuth); 610 } 611 if (suites != null) { 612 sslSocket.setEnabledCipherSuites(suites); 613 } 614 if (protocols != null) { 615 sslSocket.setEnabledProtocols(protocols); 616 } 617 sslSocket.startHandshake(); 618 } 619 620 return socket; 621 } 622 623 /** 624 * Performs any custom initialization for a newly created SSLSocket (before 625 * the SSL handshake happens). 626 * Called by {@link #_openDataConnection_(int, String)} immediately 627 * after creating the socket. 628 * The default implementation is a no-op 629 * @throws IOException 630 * @since 3.1 631 */ 632 protected void _prepareDataSocket_(Socket socket) 633 throws IOException { 634 } 635 636 /** 637 * Get the currently configured {@link TrustManager}. 638 * 639 * @return A TrustManager instance. 640 */ 641 public TrustManager getTrustManager() { 642 return trustManager; 643 } 644 645 /** 646 * Override the default {@link TrustManager} to use; if set to {@code null}, 647 * the default TrustManager from the JVM will be used. 648 * 649 * @param trustManager The TrustManager implementation to set, may be {@code null} 650 * @see org.apache.commons.net.util.TrustManagerUtils 651 */ 652 public void setTrustManager(TrustManager trustManager) { 653 this.trustManager = trustManager; 654 } 655 656 /** 657 * Closes the connection to the FTP server and restores 658 * connection parameters to the default values. 659 * <p> 660 * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} 661 * to reset the factories that may have been changed during the session, 662 * e.g. by {@link #execPROT(String)} 663 * @exception IOException If an error occurs while disconnecting. 664 * @since 3.0 665 */ 666 @Override 667 public void disconnect() throws IOException 668 { 669 super.disconnect(); 670 setSocketFactory(null); 671 setServerSocketFactory(null); 672 } 673 674 /** 675 * Send the AUTH command with the specified mechanism. 676 * @param mechanism The mechanism name to send with the command. 677 * @return server reply. 678 * @throws IOException If an I/O error occurs while sending 679 * the command. 680 * @since 3.0 681 */ 682 public int execAUTH(String mechanism) throws IOException 683 { 684 return sendCommand(CMD_AUTH, mechanism); 685 } 686 687 /** 688 * Send the ADAT command with the specified authentication data. 689 * @param data The data to send with the command. 690 * @return server reply. 691 * @throws IOException If an I/O error occurs while sending 692 * the command. 693 * @since 3.0 694 */ 695 public int execADAT(byte[] data) throws IOException 696 { 697 if (data != null) 698 { 699 return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); 700 } 701 else 702 { 703 return sendCommand(CMD_ADAT); 704 } 705 } 706 707 /** 708 * Send the CCC command to the server. 709 * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned 710 * to a plain {@link Socket} instances 711 * @return server reply. 712 * @throws IOException If an I/O error occurs while sending 713 * the command. 714 * @since 3.0 715 */ 716 public int execCCC() throws IOException 717 { 718 int repCode = sendCommand(CMD_CCC); 719 // This will be performed by sendCommand(String, String) 720 // if (FTPReply.isPositiveCompletion(repCode)) { 721 // _socket_.close(); 722 // _socket_ = plainSocket; 723 // _controlInput_ = new BufferedReader( 724 // new InputStreamReader( 725 // _socket_.getInputStream(), getControlEncoding())); 726 // _controlOutput_ = new BufferedWriter( 727 // new OutputStreamWriter( 728 // _socket_.getOutputStream(), getControlEncoding())); 729 // } 730 return repCode; 731 } 732 733 /** 734 * Send the MIC command with the specified data. 735 * @param data The data to send with the command. 736 * @return server reply. 737 * @throws IOException If an I/O error occurs while sending 738 * the command. 739 * @since 3.0 740 */ 741 public int execMIC(byte[] data) throws IOException 742 { 743 if (data != null) 744 { 745 return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); 746 } 747 else 748 { 749 return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? 750 } 751 } 752 753 /** 754 * Send the CONF command with the specified data. 755 * @param data The data 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 execCONF(byte[] data) throws IOException 762 { 763 if (data != null) 764 { 765 return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); 766 } 767 else 768 { 769 return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? 770 } 771 } 772 773 /** 774 * Send the ENC command with the specified data. 775 * @param data The data to send with the command. 776 * @return server reply. 777 * @throws IOException If an I/O error occurs while sending 778 * the command. 779 * @since 3.0 780 */ 781 public int execENC(byte[] data) throws IOException 782 { 783 if (data != null) 784 { 785 return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); 786 } 787 else 788 { 789 return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? 790 } 791 } 792 793 /** 794 * Parses the given ADAT response line and base64-decodes the data. 795 * @param reply The ADAT reply to parse. 796 * @return the data in the reply, base64-decoded. 797 * @since 3.0 798 */ 799 public byte[] parseADATReply(String reply) 800 { 801 if (reply == null) { 802 return null; 803 } else { 804 return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); 805 } 806 } 807 808 /** 809 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 810 * @param prefix the prefix to find 811 * @param reply where to find the prefix 812 * @return the remainder of the string after the prefix, or null if the prefix was not present. 813 */ 814 private String extractPrefixedData(String prefix, String reply) { 815 int idx = reply.indexOf(prefix); 816 if (idx == -1) { 817 return null; 818 } 819 // N.B. Cannot use trim before substring as leading space would affect the offset. 820 return reply.substring(idx+prefix.length()).trim(); 821 } 822 823 // DEPRECATED - for API compatibility only - DO NOT USE 824 825 /** @deprecated - not used - may be removed in a future release */ 826 @Deprecated 827 public static String KEYSTORE_ALGORITHM; 828 829 /** @deprecated - not used - may be removed in a future release */ 830 @Deprecated 831 public static String TRUSTSTORE_ALGORITHM; 832 833 /** @deprecated - not used - may be removed in a future release */ 834 @Deprecated 835 public static String PROVIDER; 836 837 /** @deprecated - not used - may be removed in a future release */ 838 @Deprecated 839 public static String STORE_TYPE; 840 841 } 842 /* kate: indent-width 4; replace-tabs on; */