1 17 package net.sf.drftpd.master.command.plugins; 18 import java.io.FileNotFoundException ; 19 import java.io.IOException ; 20 import java.io.PrintWriter ; 21 import java.net.BindException ; 22 import java.net.InetAddress ; 23 import java.net.InetSocketAddress ; 24 import java.net.ServerSocket ; 25 import java.net.Socket ; 26 import java.net.UnknownHostException ; 27 import java.rmi.RemoteException ; 28 import java.util.Collections ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 import java.util.StringTokenizer ; 33 34 import javax.net.SocketFactory; 35 import javax.net.ssl.SSLContext; 36 import javax.net.ssl.SSLSocket; 37 import javax.net.ssl.SSLSocketFactory; 38 39 import net.sf.drftpd.Bytes; 40 import net.sf.drftpd.Checksum; 41 import net.sf.drftpd.FileExistsException; 42 import net.sf.drftpd.NoAvailableSlaveException; 43 import net.sf.drftpd.NoSFVEntryException; 44 import net.sf.drftpd.SFVFile; 45 import net.sf.drftpd.SlaveUnavailableException; 46 import net.sf.drftpd.event.TransferEvent; 47 import net.sf.drftpd.master.BaseFtpConnection; 48 import net.sf.drftpd.master.FtpReply; 49 import net.sf.drftpd.master.FtpRequest; 50 import net.sf.drftpd.master.RemoteSlave; 51 import net.sf.drftpd.master.command.CommandManager; 52 import net.sf.drftpd.master.command.CommandManagerFactory; 53 import net.sf.drftpd.master.usermanager.UserFileException; 54 import net.sf.drftpd.remotefile.LinkedRemoteFile; 55 import net.sf.drftpd.remotefile.LinkedRemoteFileInterface; 56 import net.sf.drftpd.remotefile.StaticRemoteFile; 57 import net.sf.drftpd.slave.Transfer; 58 import net.sf.drftpd.slave.TransferFailedException; 59 import net.sf.drftpd.slave.TransferStatus; 60 import net.sf.drftpd.util.ListUtils; 61 import net.sf.drftpd.util.PortRange; 62 import net.sf.drftpd.util.SSLGetContext; 63 64 import org.apache.log4j.Level; 65 import org.apache.log4j.Logger; 66 import org.drftpd.commands.CommandHandler; 67 import org.drftpd.commands.CommandHandlerFactory; 68 import org.drftpd.commands.UnhandledCommandException; 69 import org.tanesha.replacer.ReplacerEnvironment; 70 75 public class DataConnectionHandler implements CommandHandlerFactory, CommandHandler, Cloneable { 76 private static final Logger logger = Logger 77 .getLogger(DataConnectionHandler.class); 78 private SSLContext _ctx; 79 private boolean _encryptedDataChannel; 80 protected boolean _isPasv = false; 81 protected boolean _isPort = false; 82 85 private InetSocketAddress _portAddress; 86 private PortRange _portRange = new PortRange(); 87 protected boolean _preTransfer = false; 88 private RemoteSlave _preTransferRSlave; 89 private long _resumePosition = 0; 90 private RemoteSlave _rslave; 91 94 private ServerSocket _serverSocket; 95 private Transfer _transfer; 96 private LinkedRemoteFileInterface _transferFile; 97 private char type = 'A'; 98 public DataConnectionHandler() { 99 super(); 100 try { 101 _ctx = SSLGetContext.getSSLContext(); 102 } catch (Exception e) { 103 _ctx = null; 104 logger.warn("Couldn't load SSLContext, SSL/TLS disabled", e); 105 } 106 } 107 private FtpReply doAUTH(BaseFtpConnection conn) { 108 if (_ctx == null) 109 return new FtpReply(500, "TLS not configured"); 110 Socket s = conn.getControlSocket(); 111 conn.getControlWriter().write( 113 new FtpReply(234, conn.getRequest().getCommandLine() 114 + " successfull").toString()); 115 conn.getControlWriter().flush(); 116 try { 117 SSLSocket s2; 118 s2 = (SSLSocket) ((SSLSocketFactory) _ctx.getSocketFactory()) 119 .createSocket(s, s.getInetAddress().getHostAddress(), s 120 .getPort(), true); 121 s2.setUseClientMode(false); 122 s2.startHandshake(); 123 conn.setControlSocket(s2); 124 } catch (IOException e) { 125 logger.warn("", e); 126 conn.stop(e.getMessage()); 127 return null; 128 } 129 return null; 130 } 131 140 175 181 private FtpReply doMODE(BaseFtpConnection conn) { 182 FtpRequest request = conn.getRequest(); 183 if (!request.hasArgument()) { 185 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 186 } 187 if (request.getArgument().equalsIgnoreCase("S")) { 188 return FtpReply.RESPONSE_200_COMMAND_OK; 189 } else { 190 return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM; 191 } 192 } 193 201 private FtpReply doPASV(BaseFtpConnection conn) { 202 if (!_preTransfer) { 203 return new FtpReply(500, 204 "You need to use a client supporting PRET (PRE Transfer) to use PASV"); 205 } 206 _preTransfer = false; 208 if(isPort() == true) throw new RuntimeException (); 209 InetSocketAddress address; 210 if (_preTransferRSlave == null) { 211 try { 212 address = new InetSocketAddress (conn.getControlSocket() 213 .getLocalAddress(), _portRange.getPort()); 214 _serverSocket = (_encryptedDataChannel ? _ctx 215 .getServerSocketFactory() : conn 216 .getServerSocketFactory()).createServerSocket(); 217 _serverSocket.bind(address, 1); 218 _serverSocket.setSoTimeout(60000); 219 _isPasv = true; 224 } catch (BindException ex) { 225 _serverSocket = null; 226 logger.warn("", ex); 227 return new FtpReply(550, ex.getMessage()); 228 } catch (Exception ex) { 229 logger.log(Level.WARN, "", ex); 230 return new FtpReply(550, ex.getMessage()); 231 } 232 } else { 233 try { 234 _transfer = _preTransferRSlave.getSlave().listen(false); 235 address = new InetSocketAddress (_preTransferRSlave 236 .getInetAddress(), _transfer.getLocalPort()); 237 _isPasv = true; 238 } catch (RemoteException e) { 239 _preTransferRSlave.handleRemoteException(e); 240 return new FtpReply(450, "Remote error: " + e.getMessage()); 241 } catch (SlaveUnavailableException e) { 242 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE; 243 } catch (IOException e) { 244 logger.log(Level.FATAL, "", e); 245 return new FtpReply(450, e.getMessage()); 246 } 247 } 248 String addrStr = address.getAddress().getHostAddress() 251 .replace('.', ',') 252 + ',' 253 + (address.getPort() >> 8) 254 + ',' 255 + (address.getPort() & 0xFF); 256 return new FtpReply(227, "Entering Passive Mode (" + addrStr + ")."); 257 } 258 private FtpReply doPBSZ(BaseFtpConnection conn) 259 throws UnhandledCommandException { 260 String cmd = conn.getRequest().getArgument(); 261 if (cmd == null || !cmd.equals("0")) 262 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 263 return FtpReply.RESPONSE_200_COMMAND_OK; 264 } 265 281 private FtpReply doPORT(BaseFtpConnection conn) { 282 FtpRequest request = conn.getRequest(); 283 reset(); 284 InetAddress clientAddr = null; 285 if (!request.hasArgument()) { 287 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 289 } 290 StringTokenizer st = new StringTokenizer (request.getArgument(), ","); 291 if (st.countTokens() != 6) { 292 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 293 } 294 String dataSrvName = st.nextToken() + '.' + st.nextToken() + '.' 296 + st.nextToken() + '.' + st.nextToken(); 297 try { 298 clientAddr = InetAddress.getByName(dataSrvName); 299 } catch (UnknownHostException ex) { 300 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 301 } 302 String portHostAddress = clientAddr.getHostAddress(); 303 String clientHostAddress = conn.getControlSocket().getInetAddress() 304 .getHostAddress(); 305 if ((portHostAddress.startsWith("192.168.") && !clientHostAddress 306 .startsWith("192.168.")) 307 || (portHostAddress.startsWith("10.") && !clientHostAddress 308 .startsWith("10."))) { 309 FtpReply response = new FtpReply(501); 310 response.addComment("==YOU'RE BEHIND A NAT ROUTER=="); 311 response 312 .addComment("Configure the firewall settings of your FTP client"); 313 response 314 .addComment(" to use your real IP: " 315 + conn.getControlSocket().getInetAddress() 316 .getHostAddress()); 317 response.addComment("And set up port forwarding in your router."); 318 response 319 .addComment("Or you can just use a PRET capable client, see"); 320 response 321 .addComment(" http://drftpd.org/ for PRET capable clients"); 322 return response; 323 } 324 int clientPort; 325 try { 327 int hi = Integer.parseInt(st.nextToken()); 328 int lo = Integer.parseInt(st.nextToken()); 329 clientPort = (hi << 8) | lo; 330 } catch (NumberFormatException ex) { 331 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 332 } 334 _isPort = true; 335 _portAddress = new InetSocketAddress (clientAddr, clientPort); 336 if (portHostAddress.startsWith("127.")) { 337 return new FtpReply(200, 338 "Ok, but distributed transfers won't work with local addresses"); 339 } 340 if (!clientAddr.equals(conn.getControlSocket().getInetAddress())) { 343 return new FtpReply(200, 344 "FXP allowed. If you're not FXPing and set your IP to " 345 + conn.getControlSocket().getInetAddress() 346 .getHostAddress() 347 + " (usually in firewall settings)"); 348 } 349 return FtpReply.RESPONSE_200_COMMAND_OK; 350 } 351 private FtpReply doPRET(BaseFtpConnection conn) { 352 reset(); 353 FtpRequest request = conn.getRequest(); 354 FtpRequest ghostRequest = new FtpRequest(request.getArgument()); 355 String cmd = ghostRequest.getCommand(); 356 if (cmd.equals("LIST") || cmd.equals("NLST") || cmd.equals("MLSD")) { 357 _preTransferRSlave = null; 358 _preTransfer = true; 359 return new FtpReply(200, 360 "OK, will use master for upcoming transfer"); 361 } else if (cmd.equals("RETR")) { 362 try { 363 LinkedRemoteFileInterface downFile = conn.getCurrentDirectory() 364 .lookupFile(ghostRequest.getArgument()); 365 _preTransferRSlave = conn.getSlaveManager() 366 .getSlaveSelectionManager().getASlave( 367 downFile.getAvailableSlaves(), 368 Transfer.TRANSFER_SENDING_DOWNLOAD, conn, 369 downFile); 370 _preTransfer = true; 371 return new FtpReply(200, "OK, will use " 372 + _preTransferRSlave.getName() 373 + " for upcoming transfer"); 374 } catch (NoAvailableSlaveException e) { 375 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE; 376 } catch (FileNotFoundException e) { 377 return FtpReply.RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN; 378 } 379 } else if (cmd.equals("STOR")) { 380 LinkedRemoteFile.NonExistingFile nef = conn.getCurrentDirectory() 381 .lookupNonExistingFile(ghostRequest.getArgument()); 382 if (nef.exists()) { 383 return FtpReply.RESPONSE_530_ACCESS_DENIED; 384 } 385 if (!ListUtils.isLegalFileName(nef.getPath())) { 386 return FtpReply.RESPONSE_530_ACCESS_DENIED; 387 } 388 try { 389 _preTransferRSlave = conn.getSlaveManager() 390 .getSlaveSelectionManager().getASlave( 391 conn.getSlaveManager().getAvailableSlaves(), 392 Transfer.TRANSFER_RECEIVING_UPLOAD, conn, 393 nef.getFile()); 394 _preTransfer = true; 395 return new FtpReply(200, "OK, will use " 396 + _preTransferRSlave.getName() 397 + " for upcoming transfer"); 398 } catch (NoAvailableSlaveException e) { 399 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE; 400 } 401 } else { 402 return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM; 403 } 404 } 405 private FtpReply doPROT(BaseFtpConnection conn) 406 throws UnhandledCommandException { 407 if (_ctx == null) 408 return new FtpReply(500, "TLS not configured"); 409 FtpRequest req = conn.getRequest(); 410 if (!req.hasArgument() || req.getArgument().length() != 1) 411 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 412 switch (Character.toUpperCase(req.getArgument().charAt(0))) { 413 case 'C' : 414 _encryptedDataChannel = false; 416 return FtpReply.RESPONSE_200_COMMAND_OK; 417 case 'P' : 418 _encryptedDataChannel = true; 420 return FtpReply.RESPONSE_200_COMMAND_OK; 421 default : 422 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 423 } 424 } 425 434 private FtpReply doREST(BaseFtpConnection conn) { 435 FtpRequest request = conn.getRequest(); 436 if (!request.hasArgument()) { 438 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 439 } 440 String skipNum = request.getArgument(); 441 try { 442 _resumePosition = Long.parseLong(skipNum); 443 } catch (NumberFormatException ex) { 444 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 445 } 446 if (_resumePosition < 0) { 447 _resumePosition = 0; 448 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 449 } 450 return FtpReply.RESPONSE_350_PENDING_FURTHER_INFORMATION; 451 } 452 private FtpReply doSITE_RESCAN(BaseFtpConnection conn) { 453 FtpRequest request = conn.getRequest(); 454 boolean forceRescan = (request.hasArgument() && request.getArgument() 455 .equalsIgnoreCase("force")); 456 LinkedRemoteFileInterface directory = conn.getCurrentDirectory(); 457 SFVFile sfv; 458 try { 459 sfv = conn.getCurrentDirectory().lookupSFVFile(); 460 } catch (Exception e) { 461 return new FtpReply(200, "Error getting SFV File: " 462 + e.getMessage()); 463 } 464 PrintWriter out = conn.getControlWriter(); 465 for (Iterator i = sfv.getEntries().entrySet().iterator(); i.hasNext();) { 466 Map.Entry entry = (Map.Entry ) i.next(); 467 String fileName = (String ) entry.getKey(); 468 Long checkSum = (Long ) entry.getValue(); 469 LinkedRemoteFileInterface file; 470 try { 471 file = directory.lookupFile(fileName); 472 } catch (FileNotFoundException ex) { 473 out.write("200- SFV: " 474 + Checksum.formatChecksum(checkSum.longValue()) 475 + " SLAVE: " + fileName + " MISSING" 476 + BaseFtpConnection.NEWLINE); 477 continue; 478 } 479 String status; 480 long fileCheckSum; 481 try { 482 if (forceRescan) { 483 fileCheckSum = file.getCheckSumFromSlave(); 484 } else { 485 fileCheckSum = file.getCheckSum(); 486 } 487 } catch (NoAvailableSlaveException e1) { 488 out.println("200- " + fileName + "SFV: " 489 + Checksum.formatChecksum(checkSum.longValue()) 490 + " SLAVE: OFFLINE"); 491 continue; 492 } catch (IOException ex) { 493 out.print("200- " + fileName + " SFV: " 494 + Checksum.formatChecksum(checkSum.longValue()) 495 + " SLAVE: IO error: " + ex.getMessage()); 496 continue; 497 } 498 if (fileCheckSum == 0L) { 499 status = "FAILED - failed to checksum file"; 500 } else if (checkSum.longValue() == fileCheckSum) { 501 status = "OK"; 502 } else { 503 status = "FAILED - checksum missmatch"; 504 } 505 out.println("200- " + fileName + " SFV: " 506 + Checksum.formatChecksum(checkSum.longValue()) 507 + " SLAVE: " 508 + Checksum.formatChecksum(checkSum.longValue()) + " " 509 + status); 510 continue; 511 } 512 return FtpReply.RESPONSE_200_COMMAND_OK; 513 } 514 private FtpReply doSITE_XDUPE(BaseFtpConnection conn) { 515 return FtpReply.RESPONSE_502_COMMAND_NOT_IMPLEMENTED; 516 } 544 549 private FtpReply doSTRU(BaseFtpConnection conn) { 550 FtpRequest request = conn.getRequest(); 551 if (!request.hasArgument()) { 553 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 554 } 555 if (request.getArgument().equalsIgnoreCase("F")) { 556 return FtpReply.RESPONSE_200_COMMAND_OK; 557 } else { 558 return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM; 559 } 560 565 } 566 572 private FtpReply doSYST(BaseFtpConnection conn) { 573 579 return FtpReply.RESPONSE_215_SYSTEM_TYPE; 580 } 583 588 private FtpReply doTYPE(BaseFtpConnection conn) { 589 FtpRequest request = conn.getRequest(); 590 if (!request.hasArgument()) { 592 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 593 } 594 if (setType(request.getArgument().charAt(0))) { 596 return FtpReply.RESPONSE_200_COMMAND_OK; 597 } else { 598 return FtpReply.RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM; 599 } 600 } 601 public FtpReply execute(BaseFtpConnection conn) 602 throws UnhandledCommandException { 603 String cmd = conn.getRequest().getCommand(); 604 if ("MODE".equals(cmd)) 605 return doMODE(conn); 606 if ("PASV".equals(cmd)) 607 return doPASV(conn); 608 if ("PORT".equals(cmd)) 609 return doPORT(conn); 610 if ("PRET".equals(cmd)) 611 return doPRET(conn); 612 if ("REST".equals(cmd)) 613 return doREST(conn); 614 if ("RETR".equals(cmd) || "STOR".equals(cmd) || "APPE".equals(cmd)) 615 return transfer(conn); 616 if ("SITE RESCAN".equals(cmd)) 617 return doSITE_RESCAN(conn); 618 if ("SITE XDUPE".equals(cmd)) 619 return doSITE_XDUPE(conn); 620 if ("STRU".equals(cmd)) 621 return doSTRU(conn); 622 if ("SYST".equals(cmd)) 623 return doSYST(conn); 624 if ("TYPE".equals(cmd)) 625 return doTYPE(conn); 626 if ("AUTH".equals(cmd)) 627 return doAUTH(conn); 628 if ("PROT".equals(cmd)) 629 return doPROT(conn); 630 if ("PBSZ".equals(cmd)) 631 return doPBSZ(conn); 632 throw UnhandledCommandException.create(DataConnectionHandler.class, 633 conn.getRequest()); 634 } 635 640 public Socket getDataSocket(SocketFactory socketFactory) throws IOException { 641 Socket dataSocket; 642 if (isPort()) { 644 try { 645 SocketFactory ssf = _encryptedDataChannel ? _ctx 646 .getSocketFactory() : socketFactory; 647 dataSocket = ssf.createSocket(); 648 dataSocket.connect(_portAddress); 650 } catch (IOException ex) { 651 logger.warn("Error opening data socket", ex); 652 dataSocket = null; 653 throw ex; 654 } 655 } else if (isPasv()) { 656 try { 657 dataSocket = _serverSocket.accept(); 658 } finally { 659 _serverSocket.close(); 660 _portRange.releasePort(_serverSocket.getLocalPort()); 661 _serverSocket = null; 662 } 663 } else { 664 throw new IllegalStateException ("Neither PASV nor PORT"); 665 } 666 if (_encryptedDataChannel) { 667 SSLSocket ssldatasocket = (SSLSocket) dataSocket; 668 ssldatasocket.setUseClientMode(false); 669 ssldatasocket.startHandshake(); 670 } 671 dataSocket.setSoTimeout(15000); return dataSocket; 673 } 674 public String [] getFeatReplies() { 675 if (_ctx != null) 676 return new String []{"PRET", "AUTH SSL", "PBSZ"}; 677 return new String []{"PRET"}; 678 } 679 684 690 public RemoteSlave getTranferSlave() { 694 return _rslave; 695 } 696 public Transfer getTransfer() { 697 if (_transfer == null) 698 throw new IllegalStateException (); 699 return _transfer; 700 } 701 public LinkedRemoteFileInterface getTransferFile() { 702 return _transferFile; 703 } 704 707 public char getType() { 708 return type; 709 } 710 public CommandHandler initialize(BaseFtpConnection conn, 711 CommandManager initializer) { 712 try { 713 return (DataConnectionHandler) clone(); 714 } catch (CloneNotSupportedException e) { 715 throw new RuntimeException (e); 716 } 717 } 718 public boolean isEncryptedDataChannel() { 719 return _encryptedDataChannel; 720 } 721 724 public boolean isPasv() { 725 return _isPasv; 726 } 727 public boolean isPort() { 728 return _isPort; 729 } 730 public boolean isPreTransfer() { 731 return _preTransfer || isPasv(); 732 } 733 public boolean isTransfering() { 734 return _transfer != null; 735 } 736 public void load(CommandManagerFactory initializer) { 737 } 738 protected void reset() { 739 _rslave = null; 740 _transfer = null; 741 _transferFile = null; 742 _preTransfer = false; 743 _preTransferRSlave = null; 744 if (_serverSocket != null) { _portRange.releasePort(_serverSocket.getLocalPort()); 746 } 747 _isPasv = false; 748 _serverSocket = null; 749 _isPort = false; 750 _resumePosition = 0; 751 } 752 757 private boolean setType(char type) { 758 type = Character.toUpperCase(type); 759 if ((type != 'A') && (type != 'I')) { 760 return false; 761 } 762 this.type = type; 763 return true; 764 } 765 772 810 835 private FtpReply transfer(BaseFtpConnection conn) 837 throws UnhandledCommandException { 838 if (!_encryptedDataChannel 839 && conn.getConfig() 840 .checkDenyDataUnencrypted(conn.getUserNull())) { 841 return new FtpReply(530, "USE SECURE DATA CONNECTION"); 842 } 843 try { 844 FtpRequest request = conn.getRequest(); 845 char direction = conn.getDirection(); 846 String cmd = conn.getRequest().getCommand(); 847 boolean isStor = cmd.equals("STOR"); 848 boolean isRetr = cmd.equals("RETR"); 849 boolean isAppe = cmd.equals("APPE"); 850 boolean isStou = cmd.equals("STOU"); 851 String eventType = isRetr ? "RETR" : "STOR"; 852 if (isAppe || isStou) 853 throw UnhandledCommandException.create( 854 DataConnectionHandler.class, conn.getRequest()); 855 if (!request.hasArgument()) { 857 return FtpReply.RESPONSE_501_SYNTAX_ERROR; 858 } 859 LinkedRemoteFileInterface targetDir; 861 String targetFileName; 862 if (isRetr) { 863 try { 864 _transferFile = conn.getCurrentDirectory().lookupFile( 865 request.getArgument()); 866 if (!_transferFile.isFile()) { 867 return new FtpReply(550, "Not a plain file"); 868 } 869 targetDir = _transferFile.getParentFileNull(); 870 targetFileName = _transferFile.getName(); 871 } catch (FileNotFoundException ex) { 872 return new FtpReply(550, ex.getMessage()); 873 } 874 } else if (isStor) { 875 LinkedRemoteFile.NonExistingFile ret = conn 876 .getCurrentDirectory().lookupNonExistingFile( 877 conn.getConnectionManager().getConfig() 878 .getFileName(request.getArgument())); 879 targetDir = ret.getFile(); 880 targetFileName = ret.getPath(); 881 if (ret.exists()) { 882 return new FtpReply(550, 885 "Requested action not taken. File exists."); 886 } 896 if (!ListUtils.isLegalFileName(targetFileName) 897 || !conn.getConfig().checkPrivPath(conn.getUserNull(), 898 targetDir)) { 899 return new FtpReply(553, 900 "Requested action not taken. File name not allowed."); 901 } 902 } else { 903 throw UnhandledCommandException.create( 904 DataConnectionHandler.class, request); 905 } 906 if (!conn.getConfig().checkPrivPath(conn.getUserNull(), targetDir)) { 908 return new FtpReply(550, request.getArgument() 909 + ": No such file"); 910 } 911 switch (direction) { 912 case Transfer.TRANSFER_SENDING_DOWNLOAD : 913 if (!conn.getConnectionManager().getConfig().checkDownload( 914 conn.getUserNull(), targetDir)) { 915 return FtpReply.RESPONSE_530_ACCESS_DENIED; 916 } 917 break; 918 case Transfer.TRANSFER_RECEIVING_UPLOAD : 919 if (!conn.getConnectionManager().getConfig().checkUpload( 920 conn.getUserNull(), targetDir)) { 921 return FtpReply.RESPONSE_530_ACCESS_DENIED; 922 } 923 break; 924 default : 925 throw UnhandledCommandException.create( 926 DataConnectionHandler.class, request); 927 } 928 if (isRetr) { 930 if (conn.getUserNull().getRatio() != 0 931 && conn.getUserNull().getCredits() < _transferFile 932 .length()) { 933 return new FtpReply(550, "Not enough credits."); 934 } 935 } 936 if (isPasv()) { 938 if (isRetr 943 && !_transferFile.getSlaves().contains( 944 _preTransferRSlave)) { 945 return FtpReply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS; 946 } 947 _rslave = _preTransferRSlave; 948 } else { 952 try { 953 if (direction == Transfer.TRANSFER_SENDING_DOWNLOAD) { 954 _rslave = conn.getConfig().getSlaveManager() 955 .getSlaveSelectionManager().getASlave( 956 _transferFile.getAvailableSlaves(), 957 Transfer.TRANSFER_SENDING_DOWNLOAD, 958 conn, _transferFile); 959 } else if (direction == Transfer.TRANSFER_RECEIVING_UPLOAD) { 960 _rslave = conn.getSlaveManager() 961 .getSlaveSelectionManager().getASlave( 962 conn.getSlaveManager() 963 .getAvailableSlaves(), 964 Transfer.TRANSFER_RECEIVING_UPLOAD, 965 conn, targetDir); 966 } else { 967 throw new RuntimeException (); 968 } 969 } catch (NoAvailableSlaveException ex) { 970 return FtpReply.RESPONSE_530_SLAVE_UNAVAILABLE; 971 } 972 } 973 if (isStor) { 974 if(_rslave == null) throw new NullPointerException (); 976 List rslaves = Collections.singletonList(_rslave); 977 StaticRemoteFile uploadFile = new StaticRemoteFile(rslaves, 978 targetFileName, conn.getUserNull().getUsername(), conn 979 .getUserNull().getGroupName(), 0L, System 980 .currentTimeMillis(), 0L); 981 _transferFile = targetDir.addFile(uploadFile); 982 } 983 if (isPort()) { 985 try { 986 _transfer = _rslave.getSlave().connect(_portAddress, 987 _encryptedDataChannel); 988 } catch (RemoteException ex) { 989 _rslave.handleRemoteException(ex); 990 return new FtpReply(450, "Remote error: " + ex.getMessage()); 991 } catch (Exception ex) { 992 logger.fatal("rslave=" + _rslave, ex); 993 return new FtpReply(450, ex.getClass().getName() 994 + " from slave: " + ex.getMessage()); 995 } 996 } else if (isPasv()) { 997 } else { 999 return FtpReply.RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS; 1000 } 1001 if( _transfer == null)throw new NullPointerException (); 1002 { 1003 PrintWriter out = conn.getControlWriter(); 1004 out.write(new FtpReply(150, 1005 "File status okay; about to open data connection " 1006 + (isRetr ? "from " : "to ") 1007 + _rslave.getName() + ".").toString()); 1008 out.flush(); 1009 } 1010 TransferStatus status; 1011 try { 1013 if (isRetr) { 1015 status = _transferFile.sendFile(_transfer, getType(), 1016 _resumePosition); 1017 } else if (isStor) { 1018 status = _transferFile.receiveFile(_transfer, getType(), 1019 _resumePosition); 1020 } else { 1021 throw new RuntimeException (); 1022 } 1023 } catch (RemoteException ex) { 1024 _rslave.handleRemoteException(ex); 1025 if (isStor) { 1026 _transferFile.delete(); 1027 logger 1028 .error("RemoteException during transfer, deleting file"); 1029 return new FtpReply(426, "RemoteException, deleting file"); 1030 } else { 1031 logger.error("RemoteException during transfer"); 1032 return new FtpReply(426, "RemoteException during transfer"); 1033 } 1034 } catch (FileExistsException ex) { 1035 logger.warn("Slave is unsynchronized", ex); 1037 return new FtpReply(426, 1038 "FileExistsException, slave is unsynchronized: " 1039 + ex.getMessage()); 1040 } catch (IOException ex) { 1041 if (ex instanceof TransferFailedException) { 1042 status = ((TransferFailedException) ex).getStatus(); 1043 conn.getConnectionManager().dispatchFtpEvent( 1044 new TransferEvent(conn.getUserNull(), eventType, 1045 _transferFile, conn.getClientAddress(), 1046 _rslave, status.getPeer(), type, false)); 1047 if (isRetr) { 1048 conn.getUserNull().updateCredits( 1049 -status.getTransfered()); 1050 } 1051 } 1052 FtpReply reply = null; 1053 if (isStor) { 1054 _transferFile.delete(); 1055 logger.error("IOException during transfer, deleting file", 1056 ex); 1057 reply = new FtpReply(426, "IOException, deleting file"); 1058 } else { 1059 logger.error("IOException during transfer", ex); 1060 reply = new FtpReply(426, "IOException during transfer"); 1061 } 1062 reply.addComment(ex.getLocalizedMessage()); 1063 return reply; 1064 } 1065 ReplacerEnvironment env = new ReplacerEnvironment(); 1075 env.add("bytes", Bytes.formatBytes(status.getTransfered())); 1076 env.add("speed", Bytes.formatBytes(status.getXferSpeed()) + "/s"); 1077 env.add("seconds", "" + status.getElapsed() / 1000); 1078 env.add("checksum", Checksum.formatChecksum(status.getChecksum())); 1079 FtpReply response = new FtpReply(226, conn.jprintf( 1080 DataConnectionHandler.class.getName(), "transfer.complete", 1081 env)); 1082 if (isStor) { 1083 if (_resumePosition == 0) { 1085 _transferFile.setCheckSum(status.getChecksum()); 1086 } else { 1087 } 1103 _transferFile.setLastModified(System.currentTimeMillis()); 1104 _transferFile.setLength(status.getTransfered()); 1105 _transferFile.setXfertime(status.getElapsed()); 1106 } 1107 boolean zipscript = zipscript(isRetr, isStor, status.getChecksum(), 1108 response, targetFileName, targetDir); 1109 if (zipscript) { 1110 if (isRetr) { 1112 float ratio = conn.getConfig().getCreditLossRatio( 1113 _transferFile, conn.getUserNull()); 1114 if (ratio != 0) { 1115 conn.getUserNull().updateCredits( 1116 (long) (-status.getTransfered() * ratio)); 1117 } 1118 conn.getUserNull().updateDownloadedBytes( 1119 status.getTransfered()); 1120 conn.getUserNull().updateDownloadedMilliseconds( 1121 status.getElapsed()); 1122 conn.getUserNull().updateDownloadedFiles(1); 1123 } else { 1124 conn.getUserNull().updateCredits( 1125 (long) (status.getTransfered() * conn.getConfig() 1126 .getCreditCheckRatio(_transferFile, 1127 conn.getUserNull()))); 1128 conn.getUserNull().updateUploadedBytes( 1129 status.getTransfered()); 1130 conn.getUserNull().updateUploadedMilliseconds( 1131 status.getElapsed()); 1132 conn.getUserNull().updateUploadedFiles(1); 1133 } 1134 try { 1135 conn.getUserNull().commit(); 1136 } catch (UserFileException e) { 1137 logger.warn("", e); 1138 } 1139 } 1140 conn.getConnectionManager().dispatchFtpEvent( 1142 new TransferEvent(conn.getUserNull(), eventType, 1143 _transferFile, conn.getClientAddress(), _rslave, 1144 status.getPeer(), getType(), zipscript)); 1145 return response; 1146 } finally { 1147 reset(); 1148 } 1149 } 1150 public void unload() { 1151 if (isPasv()) { 1152 _portRange.releasePort(_serverSocket.getLocalPort()); 1153 } 1154 } 1155 1165 private boolean zipscript(boolean isRetr, boolean isStor, long checksum, 1166 FtpReply response, String targetFileName, 1167 LinkedRemoteFileInterface targetDir) { 1168 logger.debug("Running zipscript on file " + targetFileName 1170 + " with CRC of " + checksum); 1171 if (isRetr) { 1172 logger.debug("checksum from transfer = " + checksum); 1174 if (checksum != 0) { 1175 response.addComment("Checksum from transfer: " 1176 + Checksum.formatChecksum(checksum)); 1177 long cachedChecksum; 1178 cachedChecksum = _transferFile.getCheckSumCached(); 1179 if (cachedChecksum == 0) { 1180 _transferFile.setCheckSum(checksum); 1181 } else if (cachedChecksum != checksum) { 1182 response 1183 .addComment("WARNING: checksum from transfer didn't match cached checksum"); 1184 logger.info("checksum from transfer " 1185 + Checksum.formatChecksum(checksum) 1186 + "didn't match cached checksum" 1187 + Checksum.formatChecksum(cachedChecksum) + " for " 1188 + _transferFile.toString() + " from slave " 1189 + _rslave.getName(), new Throwable ()); 1190 } 1191 try { 1193 long sfvChecksum = _transferFile.getParentFileNull() 1194 .lookupSFVFile().getChecksum( 1195 _transferFile.getName()); 1196 if (sfvChecksum == checksum) { 1197 response 1198 .addComment("checksum from transfer matched checksum in .sfv"); 1199 } else { 1200 response 1201 .addComment("WARNING: checksum from transfer didn't match checksum in .sfv"); 1202 } 1203 } catch (NoAvailableSlaveException e1) { 1204 response 1205 .addComment("slave with .sfv offline, checksum not verified"); 1206 } catch (FileNotFoundException e1) { 1207 } catch (NoSFVEntryException e1) { 1209 } catch (IOException e1) { 1211 logger.info("", e1); 1212 response.addComment("IO Error reading sfv file: " 1213 + e1.getMessage()); 1214 } 1215 } else { } 1218 } else if (isStor) { 1219 if (!targetFileName.toLowerCase().endsWith(".sfv")) { 1220 try { 1221 long sfvChecksum = targetDir.lookupSFVFile().getChecksum( 1222 targetFileName); 1223 if (checksum == sfvChecksum) { 1224 response.addComment("checksum match: SLAVE/SFV:" 1225 + Long.toHexString(checksum)); 1226 } else if (checksum == 0) { 1227 response 1228 .addComment("checksum match: SLAVE/SFV: DISABLED"); 1229 } else { 1230 response.addComment("checksum mismatch: SLAVE: " 1231 + Long.toHexString(checksum) + " SFV: " 1232 + Long.toHexString(sfvChecksum)); 1233 response.addComment(" deleting file"); 1234 response.setMessage("Checksum mismatch, deleting file"); 1235 _transferFile.delete(); 1236 return false; } 1260 } catch (NoAvailableSlaveException e) { 1261 response 1262 .addComment("zipscript - SFV unavailable, slave(s) with .sfv file is offline"); 1263 } catch (NoSFVEntryException e) { 1264 response.addComment("zipscript - no entry in sfv for file"); 1265 } catch (IOException e) { 1266 response 1267 .addComment("zipscript - SFV unavailable, IO error: " 1268 + e.getMessage()); 1269 } 1270 } 1271 } 1272 return true; } 1274} | Popular Tags |