1 17 package org.alfresco.filesys.ftp; 18 19 import java.io.IOException ; 20 import java.io.InputStream ; 21 import java.io.InputStreamReader ; 22 import java.io.OutputStream ; 23 import java.io.OutputStreamWriter ; 24 import java.io.Writer ; 25 import java.net.InetAddress ; 26 import java.net.Socket ; 27 import java.net.SocketException ; 28 import java.net.UnknownHostException ; 29 import java.util.Date ; 30 import java.util.Enumeration ; 31 import java.util.StringTokenizer ; 32 import java.util.Vector ; 33 34 import javax.transaction.UserTransaction ; 35 36 import org.alfresco.filesys.server.SrvSession; 37 import org.alfresco.filesys.server.auth.ClientInfo; 38 import org.alfresco.filesys.server.auth.acl.AccessControl; 39 import org.alfresco.filesys.server.auth.acl.AccessControlManager; 40 import org.alfresco.filesys.server.core.SharedDevice; 41 import org.alfresco.filesys.server.core.SharedDeviceList; 42 import org.alfresco.filesys.server.filesys.AccessDeniedException; 43 import org.alfresco.filesys.server.filesys.AccessMode; 44 import org.alfresco.filesys.server.filesys.DiskDeviceContext; 45 import org.alfresco.filesys.server.filesys.DiskFullException; 46 import org.alfresco.filesys.server.filesys.DiskInterface; 47 import org.alfresco.filesys.server.filesys.DiskSharedDevice; 48 import org.alfresco.filesys.server.filesys.FileAction; 49 import org.alfresco.filesys.server.filesys.FileAttribute; 50 import org.alfresco.filesys.server.filesys.FileInfo; 51 import org.alfresco.filesys.server.filesys.FileOpenParams; 52 import org.alfresco.filesys.server.filesys.FileStatus; 53 import org.alfresco.filesys.server.filesys.NetworkFile; 54 import org.alfresco.filesys.server.filesys.NotifyChange; 55 import org.alfresco.filesys.server.filesys.SearchContext; 56 import org.alfresco.filesys.server.filesys.SrvDiskInfo; 57 import org.alfresco.filesys.server.filesys.TreeConnection; 58 import org.alfresco.filesys.server.filesys.TreeConnectionHash; 59 import org.alfresco.filesys.smb.server.repo.ContentContext; 60 import org.alfresco.model.ContentModel; 61 import org.alfresco.repo.security.authentication.AuthenticationComponent; 62 import org.alfresco.service.cmr.repository.NodeRef; 63 import org.alfresco.service.cmr.repository.NodeService; 64 import org.alfresco.service.cmr.security.AuthenticationService; 65 import org.alfresco.service.cmr.security.PersonService; 66 import org.alfresco.service.transaction.TransactionService; 67 import org.apache.commons.logging.Log; 68 import org.apache.commons.logging.LogFactory; 69 70 import com.sun.star.uno.RuntimeException; 71 72 77 public class FTPSrvSession extends SrvSession implements Runnable 78 { 79 80 82 private static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol"); 83 84 88 public static final int DBG_STATE = 0x00000001; 90 public static final int DBG_SEARCH = 0x00000002; 92 public static final int DBG_INFO = 0x00000004; 94 public static final int DBG_FILE = 0x00000008; 96 public static final int DBG_FILEIO = 0x00000010; 98 public static final int DBG_ERROR = 0x00000020; 100 public static final int DBG_PKTTYPE = 0x00000040; 102 public static final int DBG_TIMING = 0x00000080; 104 106 public static final int DBG_DATAPORT = 0x00000100; 108 public static final int DBG_DIRECTORY = 0x00000200; 110 112 private static final String USER_ANONYMOUS = "anonymous"; 113 114 116 private static final String ROOT_DIRECTORY = "/"; 117 118 private static final String FTP_SEPERATOR = "/"; 119 120 private static final char FTP_SEPERATOR_CHAR = '/'; 121 122 124 private static final String DIR_SEPERATOR = "\\"; 125 126 private static final char DIR_SEPERATOR_CHAR = '\\'; 127 128 130 private static final int DEFAULT_BUFFERSIZE = 64000; 131 132 134 protected final static String CRLF = "\r\n"; 135 136 138 protected final static String LIST_OPTION_HIDDEN = "-a"; 139 140 142 private Socket m_sock; 143 144 146 private InputStreamReader m_in; 147 148 private char[] m_inbuf; 149 150 private OutputStreamWriter m_out; 151 152 private StringBuffer m_outbuf; 153 154 156 private FTPDataSession m_dataSess; 157 158 162 private FTPPath m_cwd; 163 164 166 private boolean m_binary = false; 167 168 170 private long m_restartPos = 0; 171 172 174 private FTPPath m_renameFrom; 175 176 178 private SharedDeviceList m_shares; 179 180 182 private TreeConnectionHash m_connections; 183 184 192 public FTPSrvSession(Socket sock, FTPNetworkServer srv) 193 { 194 super(-1, srv, "FTP", null); 195 196 198 m_sock = sock; 199 200 203 try 204 { 205 m_sock.setSoLinger(false, 0); 206 } 207 catch (SocketException ex) 208 { 209 } 210 211 213 setLoggedOn(false); 214 215 217 m_cwd = new FTPPath(); 218 219 221 m_connections = new TreeConnectionHash(); 222 } 223 224 227 public final void closeSession() 228 { 229 230 232 super.closeSession(); 233 234 236 if (m_dataSess != null) 237 { 238 getFTPServer().releaseDataSession(m_dataSess); 239 m_dataSess = null; 240 } 241 242 247 if (m_sock != null) 248 { 249 try 250 { 251 m_sock.close(); 252 } 253 catch (Exception ex) 254 { 255 } 256 m_sock = null; 257 } 258 259 261 if (m_in != null) 262 { 263 try 264 { 265 m_in.close(); 266 } 267 catch (Exception ex) 268 { 269 } 270 m_in = null; 271 } 272 273 if (m_out != null) 274 { 275 try 276 { 277 m_out.close(); 278 } 279 catch (Exception ex) 280 { 281 } 282 m_out = null; 283 } 284 285 287 getFTPServer().removeSession(this); 288 289 291 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 292 logger.debug("Session closed, " + getSessionId()); 293 } 294 295 300 public final String getCurrentWorkingDirectory() 301 { 302 return m_cwd.getFTPPath(); 303 } 304 305 310 public final FTPNetworkServer getFTPServer() 311 { 312 return (FTPNetworkServer) getServer(); 313 } 314 315 320 public final InetAddress getRemoteAddress() 321 { 322 return m_sock.getInetAddress(); 323 } 324 325 330 public final boolean hasCurrentWorkingDirectory() 331 { 332 return m_cwd != null ? true : false; 333 } 334 335 341 public final void setRootPath(FTPPath rootPath) 342 { 343 344 346 m_cwd = new FTPPath(rootPath); 347 if ( rootPath.hasSharedDevice()) 348 m_cwd.setSharedDevice( rootPath.getSharedDevice()); 349 else 350 m_cwd.setSharedDevice(getShareList(), this); 351 } 352 353 362 protected final FTPPath generatePathForRequest(FTPRequest req, boolean filePath) 363 { 364 return generatePathForRequest(req, filePath, true); 365 } 366 367 378 protected final FTPPath generatePathForRequest(FTPRequest req, boolean filePath, boolean checkExists) 379 { 380 382 SharedDeviceList shareList = null; 383 384 if ( getClientInformation().isGuest()) 385 shareList = getDynamicShareList(); 386 else 387 shareList = getShareList(); 388 389 391 String path = convertToFTPSeperators(req.getArgument()); 392 393 396 FTPPath ftpPath = null; 397 398 if (path.compareTo(ROOT_DIRECTORY) == 0) 399 { 400 401 403 FTPNetworkServer ftpSrv = (FTPNetworkServer) getServer(); 404 if (ftpSrv.hasRootPath()) 405 ftpPath = ftpSrv.getRootPath(); 406 else 407 { 408 try 409 { 410 ftpPath = new FTPPath("/"); 411 } 412 catch (Exception ex) 413 { 414 } 415 return ftpPath; 416 } 417 } 418 419 421 else if (FTPPath.isRelativePath(path) == false) 422 { 423 424 426 try 427 { 428 ftpPath = new FTPPath(path); 429 } 430 catch (InvalidPathException ex) 431 { 432 return null; 433 } 434 435 437 if (ftpPath.setSharedDevice( shareList, this) == false) 438 return null; 439 } 440 else 441 { 442 443 446 if (path.equals(".")) 447 return m_cwd; 448 449 453 if (path.equals("..")) 454 { 455 456 458 if (m_cwd.isRootPath() == false) 459 { 460 461 463 m_cwd.removeDirectory(); 464 m_cwd.setSharedDevice( shareList, this); 465 return m_cwd; 466 } 467 else 468 return null; 469 } 470 471 474 ftpPath = new FTPPath(m_cwd); 475 476 478 if (ftpPath.isRootPath()) 479 { 480 481 483 try 484 { 485 ftpPath.setSharePath(path, null); 486 } 487 catch (InvalidPathException ex) 488 { 489 return null; 490 } 491 } 492 else 493 { 494 if (filePath) 495 ftpPath.addFile(path); 496 else 497 ftpPath.addDirectory(path); 498 } 499 500 502 if (ftpPath.hasSharedDevice() == false && ftpPath.setSharedDevice( shareList, this) == false) 503 return null; 504 } 505 506 508 if (checkExists) 509 { 510 511 513 DiskInterface disk = null; 514 TreeConnection tree = null; 515 516 try 517 { 518 519 521 tree = getTreeConnection(ftpPath.getSharedDevice()); 522 523 525 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 526 527 529 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 530 531 if (sts == FileStatus.NotExist) 532 { 533 534 537 String pathStr = req.getArgument(); 538 if (pathStr.startsWith(FTP_SEPERATOR) == false) 539 pathStr = FTP_SEPERATOR + pathStr; 540 541 543 ftpPath = new FTPPath(pathStr); 544 545 547 if (ftpPath.setSharedDevice(getShareList(), this) == false) 548 ftpPath = null; 549 else 550 { 551 553 sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 554 if ( sts == FileStatus.NotExist) 555 ftpPath = null; 556 } 557 } 558 else if ((sts == FileStatus.FileExists && filePath == false) 559 || (sts == FileStatus.DirectoryExists && filePath == true)) 560 { 561 562 564 ftpPath = null; 565 } 566 } 567 catch (Exception ex) 568 { 569 571 if ( logger.isErrorEnabled()) 572 logger.error("Error generating FTP path", ex); 573 574 ftpPath = null; 575 } 576 } 577 578 580 return ftpPath; 581 } 582 583 590 protected final String convertToFTPSeperators(String path) 591 { 592 593 595 if (path == null || path.indexOf(DIR_SEPERATOR) == -1) 596 return path; 597 598 600 return path.replace(DIR_SEPERATOR_CHAR, FTP_SEPERATOR_CHAR); 601 } 602 603 610 protected final DiskSharedDevice findShare(String name) 611 { 612 613 615 if (name == null) 616 return null; 617 618 620 SharedDevice shr = getFTPServer().getShareList().findShare(m_cwd.getShareName()); 621 622 if (shr != null && shr instanceof DiskSharedDevice) 623 return (DiskSharedDevice) shr; 624 625 627 return null; 628 } 629 630 636 protected final void setBinary(boolean bin) 637 { 638 m_binary = bin; 639 } 640 641 650 protected final void sendFTPResponse(int stsCode, String msg) throws IOException 651 { 652 653 655 m_outbuf.setLength(0); 656 m_outbuf.append(stsCode); 657 m_outbuf.append(" "); 658 659 if (msg != null) 660 m_outbuf.append(msg); 661 662 664 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR) && stsCode >= 500) 665 logger.debug("Error status=" + stsCode + ", msg=" + msg); 666 667 669 m_outbuf.append(CRLF); 670 671 673 if (m_out != null) 674 { 675 m_out.write(m_outbuf.toString()); 676 m_out.flush(); 677 } 678 } 679 680 687 protected final void sendFTPResponse(StringBuffer msg) throws IOException 688 { 689 690 692 if (m_out != null) 693 { 694 m_out.write(msg.toString()); 695 m_out.write(CRLF); 696 m_out.flush(); 697 } 698 } 699 700 707 protected final void procUser(FTPRequest req) throws IOException 708 { 709 710 712 setClientInformation(null); 713 setLoggedOn(false); 714 715 717 if (req.hasArgument() == false) 718 { 719 sendFTPResponse(501, "Syntax error in parameters or arguments"); 720 return; 721 } 722 723 725 if (getFTPServer().allowAnonymous() == true 726 && req.getArgument().equalsIgnoreCase(getFTPServer().getAnonymousAccount())) 727 { 728 729 731 ClientInfo cinfo = new ClientInfo(getFTPServer().getAnonymousAccount(), null); 732 cinfo.setGuest(true); 733 setClientInformation(cinfo); 734 735 737 sendFTPResponse(331, "Guest login ok, send your complete e-mail address as password"); 738 return; 739 } 740 741 743 setClientInformation(new ClientInfo(req.getArgument(), null)); 744 745 747 sendFTPResponse(331, "User name okay, need password for " + req.getArgument()); 748 } 749 750 757 protected final void procPassword(FTPRequest req) throws IOException 758 { 759 760 763 if (hasClientInformation() == false) 764 { 765 sendFTPResponse(500, "Syntax error, command " 766 + FTPCommand.getCommandName(req.isCommand()) + " unrecognized"); 767 return; 768 } 769 770 772 ClientInfo cInfo = getClientInformation(); 773 774 if (cInfo.isGuest()) 775 { 776 if ( getFTPServer().allowAnonymous() == true) 777 { 778 780 AuthenticationComponent authComponent = getServer().getConfiguration().getAuthenticationComponent(); 781 cInfo.setUserName( authComponent.getGuestUserName()); 782 } 783 else 784 { 785 787 sendFTPResponse(530, "Access denied"); 788 789 791 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 792 logger.debug("Anonymous logon not allowed"); 793 794 796 closeSession(); 797 } 798 } 799 800 802 cInfo.setPassword(req.getArgument()); 803 804 806 AuthenticationService authService = getServer().getConfiguration().getAuthenticationService(); 807 808 try 809 { 810 812 if ( cInfo.isGuest()) 813 { 814 816 authService.authenticateAsGuest(); 817 } 818 else 819 { 820 822 authService.authenticate( cInfo.getUserName(), cInfo.getPasswordAsCharArray()); 823 } 824 825 827 sendFTPResponse(230, "User logged in, proceed"); 828 setLoggedOn(true); 829 830 832 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 833 logger.debug("User " + getClientInformation().getUserName() + ", logon successful"); 834 } 835 catch (org.alfresco.repo.security.authentication.AuthenticationException ex) 836 { 837 839 if ( logger.isDebugEnabled()) 840 logger.debug("Logon failed", ex); 841 } 842 843 845 if ( isLoggedOn() == true) 846 { 847 849 getFTPServer().sessionLoggedOn(this); 850 851 854 if ( cInfo.isGuest()) 855 { 856 858 DiskSharedDevice guestShare = createHomeDiskShare( cInfo); 859 addDynamicShare( guestShare); 860 861 863 StringBuilder rootPath = new StringBuilder (); 864 865 rootPath.append(FTP_SEPERATOR); 866 rootPath.append( guestShare.getName()); 867 rootPath.append(FTP_SEPERATOR); 868 869 FTPPath guestRoot = null; 870 871 try 872 { 873 875 guestRoot = new FTPPath( rootPath.toString()); 876 guestRoot.setSharedDevice( guestShare); 877 setRootPath( guestRoot); 878 } 879 catch ( InvalidPathException ex) 880 { 881 if ( logger.isErrorEnabled()) 882 logger.error("Error setting guest FTP root path", ex); 883 } 884 885 887 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 888 logger.debug(" Using root path " + guestRoot); 889 } 890 } 891 else 892 { 893 894 896 sendFTPResponse(530, "Access denied"); 897 898 900 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 901 logger.debug("User " + getClientInformation().getUserName() + ", logon failed"); 902 903 905 closeSession(); 906 } 907 } 908 909 916 protected final void procPort(FTPRequest req) throws IOException 917 { 918 919 921 if (isLoggedOn() == false) 922 { 923 sendFTPResponse(500, ""); 924 return; 925 } 926 927 929 if (req.hasArgument() == false) 930 { 931 sendFTPResponse(501, "Required argument missing"); 932 return; 933 } 934 935 937 StringTokenizer token = new StringTokenizer (req.getArgument(), ","); 938 if (token.countTokens() != 6) 939 { 940 sendFTPResponse(501, "Invalid argument"); 941 return; 942 } 943 944 946 String addrStr = token.nextToken() 947 + "." + token.nextToken() + "." + token.nextToken() + "." + token.nextToken(); 948 InetAddress addr = null; 949 950 try 951 { 952 addr = InetAddress.getByName(addrStr); 953 } 954 catch (UnknownHostException ex) 955 { 956 sendFTPResponse(501, "Invalid argument (address)"); 957 return; 958 } 959 960 962 int port = -1; 963 964 try 965 { 966 port = Integer.parseInt(token.nextToken()) * 256; 967 port += Integer.parseInt(token.nextToken()); 968 } 969 catch (NumberFormatException ex) 970 { 971 sendFTPResponse(501, "Invalid argument (port)"); 972 return; 973 } 974 975 978 m_dataSess = getFTPServer().allocateDataSession(this, addr, port); 979 980 982 sendFTPResponse(200, "Port OK"); 983 984 986 if (logger.isDebugEnabled() && hasDebug(DBG_DATAPORT)) 987 logger.debug("Port open addr=" + addr + ", port=" + port); 988 } 989 990 997 protected final void procPassive(FTPRequest req) throws IOException 998 { 999 1000 1002 if (isLoggedOn() == false) 1003 { 1004 sendFTPResponse(500, ""); 1005 return; 1006 } 1007 1008 1010 try 1011 { 1012 m_dataSess = getFTPServer().allocateDataSession(this, null, 0); 1013 } 1014 catch (IOException ex) 1015 { 1016 m_dataSess = null; 1017 } 1018 1019 1021 if (m_dataSess == null) 1022 { 1023 sendFTPResponse(550, "Requested action not taken"); 1024 return; 1025 } 1026 1027 1029 int pasvPort = m_dataSess.getPassivePort(); 1030 1031 StringBuffer msg = new StringBuffer (); 1032 1033 msg.append("227 Entering Passive Mode ("); 1034 msg.append(getFTPServer().getLocalFTPAddressString()); 1035 msg.append(","); 1036 msg.append(pasvPort >> 8); 1037 msg.append(","); 1038 msg.append(pasvPort & 0xFF); 1039 msg.append(")"); 1040 1041 sendFTPResponse(msg); 1042 1043 1045 if (logger.isDebugEnabled() && hasDebug(DBG_DATAPORT)) 1046 logger.debug("Passive open addr=" + getFTPServer().getLocalFTPAddressString() + ", port=" + pasvPort); 1047 } 1048 1049 1056 protected final void procPrintWorkDir(FTPRequest req) throws IOException 1057 { 1058 1059 1061 if (isLoggedOn() == false) 1062 { 1063 sendFTPResponse(500, ""); 1064 return; 1065 } 1066 1067 1069 sendFTPResponse(257, "\"" + m_cwd.getFTPPath() + "\""); 1070 1071 1073 if (logger.isDebugEnabled() && hasDebug(DBG_DIRECTORY)) 1074 logger.debug("Pwd ftp=" 1075 + m_cwd.getFTPPath() + ", share=" + m_cwd.getShareName() + ", path=" + m_cwd.getSharePath()); 1076 } 1077 1078 1085 protected final void procChangeWorkDir(FTPRequest req) throws IOException 1086 { 1087 1088 1090 if (isLoggedOn() == false) 1091 { 1092 sendFTPResponse(500, ""); 1093 return; 1094 } 1095 1096 1098 if (req.hasArgument() == false) 1099 { 1100 sendFTPResponse(501, "Path not specified"); 1101 return; 1102 } 1103 1104 1106 FTPPath newPath = generatePathForRequest(req, false); 1107 if (newPath == null) 1108 { 1109 sendFTPResponse(550, "Invalid path " + req.getArgument()); 1110 return; 1111 } 1112 1113 1115 m_cwd = newPath; 1116 1117 1119 sendFTPResponse(250, "Requested file action OK"); 1120 1121 1123 if (logger.isDebugEnabled() && hasDebug(DBG_DIRECTORY)) 1124 logger.debug("Cwd ftp=" 1125 + m_cwd.getFTPPath() + ", share=" + m_cwd.getShareName() + ", path=" + m_cwd.getSharePath()); 1126 } 1127 1128 1135 protected final void procCdup(FTPRequest req) throws IOException 1136 { 1137 1138 1140 if (isLoggedOn() == false) 1141 { 1142 sendFTPResponse(500, ""); 1143 return; 1144 } 1145 1146 1148 if (m_cwd.isRootPath()) 1149 { 1150 1151 1153 sendFTPResponse(550, "Already at root directory"); 1154 return; 1155 } 1156 else 1157 { 1158 1159 1161 m_cwd.removeDirectory(); 1162 if (m_cwd.isRootPath() == false && m_cwd.getSharedDevice() == null) 1163 m_cwd.setSharedDevice(getShareList(), this); 1164 } 1165 1166 1168 sendFTPResponse(250, "Requested file action OK"); 1169 1170 1172 if (logger.isDebugEnabled() && hasDebug(DBG_DIRECTORY)) 1173 logger.debug("Cdup ftp=" 1174 + m_cwd.getFTPPath() + ", share=" + m_cwd.getShareName() + ", path=" + m_cwd.getSharePath()); 1175 } 1176 1177 1184 protected final void procList(FTPRequest req) throws IOException 1185 { 1186 1187 1189 if (isLoggedOn() == false) 1190 { 1191 sendFTPResponse(500, ""); 1192 return; 1193 } 1194 1195 1197 boolean hidden = false; 1198 1199 if (req.hasArgument() && req.getArgument().startsWith(LIST_OPTION_HIDDEN)) 1200 { 1201 1203 hidden = true; 1204 1205 1208 String arg = req.getArgument(); 1209 int pos = arg.indexOf(" "); 1210 if (pos > 0) 1211 arg = arg.substring(pos + 1); 1212 else 1213 arg = null; 1214 1215 req.updateArgument(arg); 1216 } 1217 1218 1220 FTPPath ftpPath = m_cwd; 1221 if ( req.hasArgument()) 1222 ftpPath = generatePathForRequest(req, true); 1223 1224 if (ftpPath == null) 1225 { 1226 sendFTPResponse(500, "Invalid path"); 1227 return; 1228 } 1229 1230 1232 if (ftpPath.isRootPath() == false) 1233 { 1234 1235 1237 TreeConnection tree = getTreeConnection(ftpPath.getSharedDevice()); 1238 if (tree == null || tree.hasReadAccess() == false) 1239 { 1240 1241 1243 sendFTPResponse(550, "Access denied"); 1244 return; 1245 } 1246 } 1247 1248 1250 sendFTPResponse(150, "File status okay, about to open data connection"); 1251 1252 1254 if (m_dataSess == null) 1255 { 1256 sendFTPResponse(425, "Can't open data connection"); 1257 return; 1258 } 1259 1260 1262 Socket dataSock = null; 1263 1264 try 1265 { 1266 dataSock = m_dataSess.getSocket(); 1267 } 1268 catch (Exception ex) 1269 { 1270 logger.debug(ex); 1271 } 1272 1273 if (dataSock == null) 1274 { 1275 sendFTPResponse(426, "Connection closed; transfer aborted"); 1276 return; 1277 } 1278 1279 1281 Writer dataWrt = null; 1282 1283 try 1284 { 1285 1286 1288 dataWrt = new OutputStreamWriter (dataSock.getOutputStream()); 1289 1290 1292 Vector <FileInfo> files = null; 1293 1294 if (req.hasArgument()) 1295 { 1296 } 1297 1298 1300 files = listFilesForPath(ftpPath, false, hidden); 1301 1302 1304 if (files != null) 1305 { 1306 1307 1309 if (logger.isDebugEnabled() && hasDebug(DBG_SEARCH)) 1310 logger.debug("List found " + files.size() + " files in " + ftpPath.getFTPPath()); 1311 1312 1314 StringBuffer str = new StringBuffer (256); 1315 1316 for (FileInfo finfo : files) 1317 { 1318 1319 1321 str.setLength(0); 1322 1323 str.append(finfo.isDirectory() ? "d" : "-"); 1324 str.append("rw-rw-rw- 1 user group "); 1325 str.append(finfo.getSize()); 1326 str.append(" "); 1327 1328 FTPDate.packUnixDate(str, new Date (finfo.getModifyDateTime())); 1329 1330 str.append(" "); 1331 str.append(finfo.getFileName()); 1332 str.append(CRLF); 1333 1334 1336 dataWrt.write(str.toString()); 1337 } 1338 1339 1341 dataWrt.flush(); 1342 } 1343 1344 1346 dataWrt.close(); 1347 dataWrt = null; 1348 1349 getFTPServer().releaseDataSession(m_dataSess); 1350 m_dataSess = null; 1351 1352 1354 sendFTPResponse(226, "Closing data connection"); 1355 } 1356 catch (Exception ex) 1357 { 1358 1359 1361 sendFTPResponse(451, "Error reading file list"); 1362 } finally 1363 { 1364 1365 1367 if (dataWrt != null) 1368 dataWrt.close(); 1369 1370 1372 if (m_dataSess != null) 1373 { 1374 getFTPServer().releaseDataSession(m_dataSess); 1375 m_dataSess = null; 1376 } 1377 } 1378 } 1379 1380 1387 protected final void procNList(FTPRequest req) throws IOException 1388 { 1389 1390 1392 if (isLoggedOn() == false) 1393 { 1394 sendFTPResponse(500, ""); 1395 return; 1396 } 1397 1398 1400 FTPPath ftpPath = m_cwd; 1401 if (req.hasArgument()) 1402 ftpPath = generatePathForRequest(req, true); 1403 1404 if (ftpPath == null) 1405 { 1406 sendFTPResponse(500, "Invalid path"); 1407 return; 1408 } 1409 1410 1412 if (ftpPath.isRootPath() == false) 1413 { 1414 1415 1417 TreeConnection tree = getTreeConnection(ftpPath.getSharedDevice()); 1418 if (tree == null || tree.hasReadAccess() == false) 1419 { 1420 1421 1423 sendFTPResponse(550, "Access denied"); 1424 return; 1425 } 1426 } 1427 1428 1430 sendFTPResponse(150, "File status okay, about to open data connection"); 1431 1432 1434 if (m_dataSess == null) 1435 { 1436 sendFTPResponse(425, "Can't open data connection"); 1437 return; 1438 } 1439 1440 1442 Socket dataSock = null; 1443 1444 try 1445 { 1446 dataSock = m_dataSess.getSocket(); 1447 } 1448 catch (Exception ex) 1449 { 1450 logger.error("Data socket error", ex); 1451 } 1452 1453 if (dataSock == null) 1454 { 1455 sendFTPResponse(426, "Connection closed; transfer aborted"); 1456 return; 1457 } 1458 1459 1461 Writer dataWrt = null; 1462 1463 try 1464 { 1465 1466 1468 dataWrt = new OutputStreamWriter (dataSock.getOutputStream()); 1469 1470 1472 Vector <FileInfo> files = null; 1473 1474 if (req.hasArgument()) 1475 { 1476 } 1477 1478 1480 files = listFilesForPath(ftpPath, false, false); 1481 1482 1484 if (files != null) 1485 { 1486 1487 1489 if (logger.isDebugEnabled() && hasDebug(DBG_SEARCH)) 1490 logger.debug("List found " + files.size() + " files in " + ftpPath.getFTPPath()); 1491 1492 1494 for (FileInfo finfo : files) 1495 { 1496 1497 1499 dataWrt.write(finfo.getFileName()); 1500 dataWrt.write(CRLF); 1501 } 1502 } 1503 1504 1506 sendFTPResponse(226, "Closing data connection"); 1507 } 1508 catch (Exception ex) 1509 { 1510 1511 1513 sendFTPResponse(451, "Error reading file list"); 1514 } finally 1515 { 1516 1517 1519 if (dataWrt != null) 1520 dataWrt.close(); 1521 1522 1524 if (m_dataSess != null) 1525 { 1526 getFTPServer().releaseDataSession(m_dataSess); 1527 m_dataSess = null; 1528 } 1529 } 1530 } 1531 1532 1539 protected final void procSystemStatus(FTPRequest req) throws IOException 1540 { 1541 1542 1544 sendFTPResponse(215, "UNIX Type: Java FTP Server"); 1545 } 1546 1547 1554 protected final void procServerStatus(FTPRequest req) throws IOException 1555 { 1556 1557 1559 sendFTPResponse(211, "JLAN Server - Java FTP Server"); 1560 } 1561 1562 1569 protected final void procHelp(FTPRequest req) throws IOException 1570 { 1571 1572 1574 sendFTPResponse(211, "HELP text"); 1575 } 1576 1577 1584 protected final void procNoop(FTPRequest req) throws IOException 1585 { 1586 1587 1589 sendFTPResponse(200, ""); 1590 } 1591 1592 1599 protected final void procQuit(FTPRequest req) throws IOException 1600 { 1601 1602 1604 sendFTPResponse(221, "Bye"); 1605 1606 1608 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 1609 logger.debug("Quit closing connection(s) to client"); 1610 1611 1613 closeSession(); 1614 } 1615 1616 1623 protected final void procType(FTPRequest req) throws IOException 1624 { 1625 1626 1628 if (req.hasArgument() == false) 1629 { 1630 sendFTPResponse(501, "Syntax error, parameter required"); 1631 return; 1632 } 1633 1634 1636 String arg = req.getArgument().toUpperCase(); 1637 if (arg.startsWith("A")) 1638 setBinary(false); 1639 else if (arg.startsWith("I") || arg.startsWith("L")) 1640 setBinary(true); 1641 else 1642 { 1643 1644 1646 sendFTPResponse(501, "Syntax error, invalid parameter"); 1647 return; 1648 } 1649 1650 1652 sendFTPResponse(200, "Command OK"); 1653 1654 1656 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 1657 logger.debug("Type arg=" + req.getArgument() + ", binary=" + m_binary); 1658 } 1659 1660 1667 protected final void procRestart(FTPRequest req) throws IOException 1668 { 1669 1670 1672 if (isLoggedOn() == false) 1673 { 1674 sendFTPResponse(500, ""); 1675 return; 1676 } 1677 1678 1680 if (req.hasArgument() == false) 1681 { 1682 sendFTPResponse(501, "Syntax error, parameter required"); 1683 return; 1684 } 1685 1686 1688 try 1689 { 1690 m_restartPos = Integer.parseInt(req.getArgument()); 1691 } 1692 catch (NumberFormatException ex) 1693 { 1694 sendFTPResponse(501, "Invalid restart position"); 1695 return; 1696 } 1697 1698 1700 sendFTPResponse(350, "Restart OK"); 1701 1702 1704 if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO)) 1705 logger.debug("Restart pos=" + m_restartPos); 1706 } 1707 1708 1715 protected final void procReturnFile(FTPRequest req) throws IOException 1716 { 1717 1718 1720 if (isLoggedOn() == false) 1721 { 1722 sendFTPResponse(500, ""); 1723 return; 1724 } 1725 1726 1728 if (req.hasArgument() == false) 1729 { 1730 sendFTPResponse(501, "Syntax error, parameter required"); 1731 return; 1732 } 1733 1734 1736 FTPPath ftpPath = generatePathForRequest(req, true); 1737 if (ftpPath == null) 1738 { 1739 sendFTPResponse(500, "Invalid path"); 1740 return; 1741 } 1742 1743 1745 if (ftpPath.isRootPath() || ftpPath.isRootSharePath()) 1746 { 1747 sendFTPResponse(550, "That is a directory"); 1748 return; 1749 } 1750 1751 1753 sendFTPResponse(150, "Connection accepted"); 1754 1755 1757 if (m_dataSess == null) 1758 { 1759 sendFTPResponse(425, "Can't open data connection"); 1760 return; 1761 } 1762 1763 1765 Socket dataSock = null; 1766 1767 try 1768 { 1769 dataSock = m_dataSess.getSocket(); 1770 } 1771 catch (Exception ex) 1772 { 1773 } 1774 1775 if (dataSock == null) 1776 { 1777 sendFTPResponse(426, "Connection closed; transfer aborted"); 1778 return; 1779 } 1780 1781 1783 if (logger.isDebugEnabled() && hasDebug(DBG_FILE)) 1784 logger.debug("Returning ftp=" 1785 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" + ftpPath.getSharePath()); 1786 1787 1789 OutputStream os = null; 1790 DiskInterface disk = null; 1791 TreeConnection tree = null; 1792 NetworkFile netFile = null; 1793 1794 try 1795 { 1796 1797 1799 os = dataSock.getOutputStream(); 1800 1801 1803 tree = getTreeConnection(ftpPath.getSharedDevice()); 1804 1805 1808 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 1809 1810 1812 FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(), FileAction.OpenIfExists, 1813 AccessMode.ReadOnly, 0); 1814 1815 1817 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 1818 1819 if (sts == FileStatus.FileExists) 1820 { 1821 1822 1824 netFile = disk.openFile(this, tree, params); 1825 } 1826 1827 1829 if (netFile == null) 1830 { 1831 sendFTPResponse(550, "File " + req.getArgument() + " not available"); 1832 return; 1833 } 1834 1835 1837 byte[] buf = new byte[DEFAULT_BUFFERSIZE]; 1838 long filePos = m_restartPos; 1839 1840 int len = -1; 1841 1842 while (filePos < netFile.getFileSize()) 1843 { 1844 1845 1847 len = disk.readFile(this, tree, netFile, buf, 0, buf.length, filePos); 1848 1849 1851 if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO)) 1852 logger.debug(" Write len=" + len + " bytes"); 1853 1854 1857 if (len > 0) 1858 { 1859 1860 1862 os.write(buf, 0, len); 1863 1864 1866 filePos += len; 1867 } 1868 } 1869 1870 1872 os.close(); 1873 os = null; 1874 1875 1877 sendFTPResponse(226, "Closing data connection"); 1878 1879 1881 getFTPServer().releaseDataSession(m_dataSess); 1882 m_dataSess = null; 1883 1884 1886 disk.closeFile(this, tree, netFile); 1887 netFile = null; 1888 1889 1891 if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO)) 1892 logger.debug(" Transfer complete, file closed"); 1893 } 1894 catch (SocketException ex) 1895 { 1896 1897 1899 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 1900 logger.debug(" Error during transfer", ex); 1901 1902 1904 if (m_dataSess != null) 1905 { 1906 m_dataSess.closeSession(); 1907 m_dataSess = null; 1908 } 1909 1910 1913 sendFTPResponse(426, "Data connection closed by client"); 1914 } 1915 catch (Exception ex) 1916 { 1917 1918 1920 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 1921 logger.debug(" Error during transfer", ex); 1922 1923 1926 sendFTPResponse(426, "Error during transmission"); 1927 } finally 1928 { 1929 1930 1932 if (netFile != null && disk != null && tree != null) 1933 disk.closeFile(this, tree, netFile); 1934 1935 1937 if (os != null) 1938 os.close(); 1939 1940 1942 if (m_dataSess != null) 1943 { 1944 getFTPServer().releaseDataSession(m_dataSess); 1945 m_dataSess = null; 1946 } 1947 } 1948 } 1949 1950 1957 protected final void procStoreFile(FTPRequest req) throws IOException 1958 { 1959 1960 1962 if (isLoggedOn() == false) 1963 { 1964 sendFTPResponse(500, ""); 1965 return; 1966 } 1967 1968 1970 if (req.hasArgument() == false) 1971 { 1972 sendFTPResponse(501, "Syntax error, parameter required"); 1973 return; 1974 } 1975 1976 1978 FTPPath ftpPath = generatePathForRequest(req, true, false); 1979 if (ftpPath == null) 1980 { 1981 sendFTPResponse(500, "Invalid path"); 1982 return; 1983 } 1984 1985 1987 InputStream is = null; 1988 DiskInterface disk = null; 1989 TreeConnection tree = null; 1990 NetworkFile netFile = null; 1991 1992 try 1993 { 1994 1995 1997 tree = getTreeConnection(ftpPath.getSharedDevice()); 1998 1999 2001 if (tree == null || tree.hasWriteAccess() == false) 2002 { 2003 2004 2006 sendFTPResponse(550, "Access denied"); 2007 return; 2008 } 2009 2010 2012 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2013 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 2014 2015 if (sts == FileStatus.DirectoryExists) 2016 { 2017 2018 2020 sendFTPResponse(500, "Invalid path (existing directory)"); 2021 return; 2022 } 2023 2024 2026 FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(), 2027 sts == FileStatus.FileExists ? FileAction.TruncateExisting : FileAction.CreateNotExist, 2028 AccessMode.ReadWrite, 0); 2029 2030 2032 if (sts == FileStatus.FileExists) 2033 { 2034 2035 2037 netFile = disk.openFile(this, tree, params); 2038 } 2039 else 2040 { 2041 2042 2044 netFile = disk.createFile(this, tree, params); 2045 } 2046 2047 2049 DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext(); 2050 2051 if (diskCtx.hasChangeHandler()) 2052 diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, ftpPath.getSharePath()); 2053 2054 2056 sendFTPResponse(150, "File status okay, about to open data connection"); 2057 2058 2060 if (m_dataSess == null) 2061 { 2062 sendFTPResponse(425, "Can't open data connection"); 2063 return; 2064 } 2065 2066 2068 Socket dataSock = null; 2069 2070 try 2071 { 2072 dataSock = m_dataSess.getSocket(); 2073 } 2074 catch (Exception ex) 2075 { 2076 } 2077 2078 if (dataSock == null) 2079 { 2080 sendFTPResponse(426, "Connection closed; transfer aborted"); 2081 return; 2082 } 2083 2084 2086 is = dataSock.getInputStream(); 2087 2088 2090 if (logger.isDebugEnabled() && hasDebug(DBG_FILE)) 2091 logger.debug("Storing ftp=" 2092 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" 2093 + ftpPath.getSharePath()); 2094 2095 2097 byte[] buf = new byte[DEFAULT_BUFFERSIZE]; 2098 long filePos = 0; 2099 int len = is.read(buf, 0, buf.length); 2100 2101 while (len > 0) 2102 { 2103 2104 2106 if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO)) 2107 logger.debug(" Receive len=" + len + " bytes"); 2108 2109 2112 disk.writeFile(this, tree, netFile, buf, 0, len, filePos); 2113 filePos += len; 2114 2115 2117 len = is.read(buf, 0, buf.length); 2118 } 2119 2120 2122 is.close(); 2123 is = null; 2124 2125 2127 disk.closeFile(this, tree, netFile); 2128 netFile = null; 2129 2130 2132 sendFTPResponse(226, "Closing data connection"); 2133 2134 2136 if (logger.isDebugEnabled() && hasDebug(DBG_FILEIO)) 2137 logger.debug(" Transfer complete, file closed"); 2138 } 2139 catch( AccessDeniedException ex) 2140 { 2141 2143 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 2144 logger.debug(" Access denied", ex); 2145 2146 2148 sendFTPResponse(550, "Access denied"); 2149 } 2150 catch (SocketException ex) 2151 { 2152 2154 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 2155 logger.debug(" Error during transfer", ex); 2156 2157 2159 if (m_dataSess != null) 2160 { 2161 getFTPServer().releaseDataSession(m_dataSess); 2162 m_dataSess = null; 2163 } 2164 2165 2168 sendFTPResponse(426, "Data connection closed by client"); 2169 } 2170 catch (DiskFullException ex) 2171 { 2172 2173 2175 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 2176 logger.debug(" Error during transfer", ex); 2177 2178 2180 if (m_dataSess != null) 2181 { 2182 getFTPServer().releaseDataSession(m_dataSess); 2183 m_dataSess = null; 2184 } 2185 2186 2188 sendFTPResponse(451, "Disk full"); 2189 } 2190 catch (Exception ex) 2191 { 2192 2193 2195 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 2196 logger.debug(" Error during transfer", ex); 2197 2198 2201 sendFTPResponse(426, "Error during transmission"); 2202 } 2203 finally 2204 { 2205 2206 2208 if (netFile != null && disk != null && tree != null) 2209 disk.closeFile(this, tree, netFile); 2210 2211 2213 if (is != null) 2214 is.close(); 2215 2216 2218 if (m_dataSess != null) 2219 { 2220 getFTPServer().releaseDataSession(m_dataSess); 2221 m_dataSess = null; 2222 } 2223 } 2224 } 2225 2226 2233 protected final void procDeleteFile(FTPRequest req) throws IOException 2234 { 2235 2236 2238 if (isLoggedOn() == false) 2239 { 2240 sendFTPResponse(500, ""); 2241 return; 2242 } 2243 2244 2246 if (req.hasArgument() == false) 2247 { 2248 sendFTPResponse(501, "Syntax error, parameter required"); 2249 return; 2250 } 2251 2252 2254 FTPPath ftpPath = generatePathForRequest(req, true); 2255 if (ftpPath == null) 2256 { 2257 sendFTPResponse(550, "Invalid path specified"); 2258 return; 2259 } 2260 2261 2263 DiskInterface disk = null; 2264 TreeConnection tree = null; 2265 2266 try 2267 { 2268 2269 2271 tree = getTreeConnection(ftpPath.getSharedDevice()); 2272 2273 2275 if (tree == null || tree.hasWriteAccess() == false) 2276 { 2277 2278 2280 sendFTPResponse(550, "Access denied"); 2281 return; 2282 } 2283 2284 2286 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2287 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 2288 2289 if (sts == FileStatus.FileExists) 2290 { 2291 2292 2294 disk.deleteFile(this, tree, ftpPath.getSharePath()); 2295 2296 2299 DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext(); 2300 if (diskCtx.hasChangeHandler()) 2301 diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, ftpPath.getSharePath()); 2302 2303 2305 if (logger.isDebugEnabled() && hasDebug(DBG_FILE)) 2306 logger.debug("Deleted ftp=" 2307 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" 2308 + ftpPath.getSharePath()); 2309 } 2310 else 2311 { 2312 2313 2315 sendFTPResponse(550, "File " 2316 + req.getArgument() + (sts == FileStatus.NotExist ? " not available" : " is a directory")); 2317 return; 2318 } 2319 } 2320 catch (AccessDeniedException ex) 2321 { 2322 2324 if (logger.isDebugEnabled() && hasDebug(DBG_ERROR)) 2325 logger.debug(" Access denied", ex); 2326 2327 2329 sendFTPResponse(550, "Access denied"); 2330 } 2331 catch (Exception ex) 2332 { 2333 sendFTPResponse(450, "File action not taken"); 2334 return; 2335 } 2336 2337 2339 sendFTPResponse(250, "File " + req.getArgument() + " deleted"); 2340 } 2341 2342 2349 protected final void procRenameFrom(FTPRequest req) throws IOException 2350 { 2351 2352 2354 if (isLoggedOn() == false) 2355 { 2356 sendFTPResponse(500, ""); 2357 return; 2358 } 2359 2360 2362 if (req.hasArgument() == false) 2363 { 2364 sendFTPResponse(501, "Syntax error, parameter required"); 2365 return; 2366 } 2367 2368 2370 m_renameFrom = null; 2371 2372 2374 FTPPath ftpPath = generatePathForRequest(req, false, false); 2375 if (ftpPath == null) 2376 { 2377 sendFTPResponse(550, "Invalid path specified"); 2378 return; 2379 } 2380 2381 2383 DiskInterface disk = null; 2384 TreeConnection tree = null; 2385 2386 try 2387 { 2388 2389 2391 tree = getTreeConnection(ftpPath.getSharedDevice()); 2392 2393 2395 if (tree == null || tree.hasWriteAccess() == false) 2396 { 2397 2398 2400 sendFTPResponse(550, "Access denied"); 2401 return; 2402 } 2403 2404 2406 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2407 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 2408 2409 if (sts != FileStatus.NotExist) 2410 { 2411 2412 2415 m_renameFrom = ftpPath; 2416 2417 2419 if (logger.isDebugEnabled() && hasDebug(DBG_FILE)) 2420 logger.debug("RenameFrom ftp=" 2421 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" 2422 + ftpPath.getSharePath()); 2423 } 2424 else 2425 { 2426 2427 2429 sendFTPResponse(550, "File " 2430 + req.getArgument() + (sts == FileStatus.NotExist ? " not available" : " is a directory")); 2431 return; 2432 } 2433 } 2434 catch (Exception ex) 2435 { 2436 sendFTPResponse(450, "File action not taken"); 2437 return; 2438 } 2439 2440 2442 sendFTPResponse(350, "File " + req.getArgument() + " OK"); 2443 } 2444 2445 2452 protected final void procRenameTo(FTPRequest req) throws IOException 2453 { 2454 2455 2457 if (isLoggedOn() == false) 2458 { 2459 sendFTPResponse(500, ""); 2460 return; 2461 } 2462 2463 2465 if (req.hasArgument() == false) 2466 { 2467 sendFTPResponse(501, "Syntax error, parameter required"); 2468 return; 2469 } 2470 2471 2473 if (m_renameFrom == null) 2474 { 2475 sendFTPResponse(550, "Rename from not set"); 2476 return; 2477 } 2478 2479 2481 FTPPath ftpPath = generatePathForRequest(req, true, false); 2482 if (ftpPath == null) 2483 { 2484 sendFTPResponse(550, "Invalid path specified"); 2485 return; 2486 } 2487 2488 2490 if (m_renameFrom.getShareName().compareTo(ftpPath.getShareName()) != 0) 2491 { 2492 sendFTPResponse(550, "Cannot rename across shares"); 2493 return; 2494 } 2495 2496 2498 DiskInterface disk = null; 2499 TreeConnection tree = null; 2500 2501 try 2502 { 2503 2504 2506 tree = getTreeConnection(ftpPath.getSharedDevice()); 2507 2508 2510 if (tree == null || tree.hasWriteAccess() == false) 2511 { 2512 2513 2515 sendFTPResponse(550, "Access denied"); 2516 return; 2517 } 2518 2519 2521 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2522 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 2523 2524 if (sts == FileStatus.NotExist) 2525 { 2526 2527 2529 disk.renameFile(this, tree, m_renameFrom.getSharePath(), ftpPath.getSharePath()); 2530 2531 2534 DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext(); 2535 if (diskCtx.hasChangeHandler()) 2536 diskCtx.getChangeHandler().notifyRename(m_renameFrom.getSharePath(), ftpPath.getSharePath()); 2537 2538 2540 if (logger.isDebugEnabled() && hasDebug(DBG_FILE)) 2541 logger.debug("RenameTo ftp=" 2542 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" 2543 + ftpPath.getSharePath()); 2544 } 2545 else 2546 { 2547 2548 2550 sendFTPResponse(550, "File " 2551 + req.getArgument() + (sts == FileStatus.NotExist ? " not available" : " is a directory")); 2552 return; 2553 } 2554 } 2555 catch (Exception ex) 2556 { 2557 sendFTPResponse(450, "File action not taken"); 2558 return; 2559 } 2560 finally 2561 { 2562 2563 2565 m_renameFrom = null; 2566 } 2567 2568 2570 sendFTPResponse(250, "File renamed OK"); 2571 } 2572 2573 2580 protected final void procCreateDirectory(FTPRequest req) throws IOException 2581 { 2582 2583 2585 if (isLoggedOn() == false) 2586 { 2587 sendFTPResponse(500, ""); 2588 return; 2589 } 2590 2591 2593 if (req.hasArgument() == false) 2594 { 2595 sendFTPResponse(501, "Syntax error, parameter required"); 2596 return; 2597 } 2598 2599 2601 FTPPath ftpPath = generatePathForRequest(req, false, false); 2602 if (ftpPath == null) 2603 { 2604 sendFTPResponse(550, "Invalid path " + req.getArgument()); 2605 return; 2606 } 2607 2608 2610 DiskInterface disk = null; 2611 TreeConnection tree = null; 2612 NetworkFile netFile = null; 2613 2614 try 2615 { 2616 2617 2619 tree = getTreeConnection(ftpPath.getSharedDevice()); 2620 2621 2623 if (tree == null || tree.hasWriteAccess() == false) 2624 { 2625 2626 2628 sendFTPResponse(550, "Access denied"); 2629 return; 2630 } 2631 2632 2634 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2635 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 2636 2637 if (sts == FileStatus.NotExist) 2638 { 2639 2640 2642 FileOpenParams params = new FileOpenParams(ftpPath.getSharePath(), FileAction.CreateNotExist, 2643 AccessMode.ReadWrite, FileAttribute.NTDirectory); 2644 2645 disk.createDirectory(this, tree, params); 2646 2647 2649 DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext(); 2650 2651 if (diskCtx.hasChangeHandler()) 2652 diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, ftpPath.getSharePath()); 2653 2654 2656 if (logger.isDebugEnabled() && hasDebug(DBG_DIRECTORY)) 2657 logger.debug("CreateDir ftp=" 2658 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" 2659 + ftpPath.getSharePath()); 2660 } 2661 else 2662 { 2663 2664 2666 sendFTPResponse(450, sts == FileStatus.FileExists ? "File exists with that name" 2667 : "Directory already exists"); 2668 return; 2669 } 2670 } 2671 catch (Exception ex) 2672 { 2673 sendFTPResponse(450, "Failed to create directory"); 2674 return; 2675 } 2676 2677 2679 sendFTPResponse(250, ftpPath.getFTPPath()); 2680 } 2681 2682 2689 protected final void procRemoveDirectory(FTPRequest req) throws IOException 2690 { 2691 2692 2694 if (isLoggedOn() == false) 2695 { 2696 sendFTPResponse(500, ""); 2697 return; 2698 } 2699 2700 2702 if (req.hasArgument() == false) 2703 { 2704 sendFTPResponse(501, "Syntax error, parameter required"); 2705 return; 2706 } 2707 2708 2710 FTPPath ftpPath = generatePathForRequest(req, false); 2711 if (ftpPath == null) 2712 { 2713 sendFTPResponse(550, "Invalid path " + req.getArgument()); 2714 return; 2715 } 2716 2717 2722 if (ftpPath.isRootPath() || ftpPath.isRootSharePath()) 2723 { 2724 sendFTPResponse(550, "Access denied, cannot delete directory in root"); 2725 return; 2726 } 2727 2728 2730 DiskInterface disk = null; 2731 TreeConnection tree = null; 2732 NetworkFile netFile = null; 2733 2734 try 2735 { 2736 2737 2739 tree = getTreeConnection(ftpPath.getSharedDevice()); 2740 2741 2743 if (tree == null || tree.hasWriteAccess() == false) 2744 { 2745 2746 2748 sendFTPResponse(550, "Access denied"); 2749 return; 2750 } 2751 2752 2754 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2755 int sts = disk.fileExists(this, tree, ftpPath.getSharePath()); 2756 2757 if (sts == FileStatus.DirectoryExists) 2758 { 2759 2760 2762 disk.deleteDirectory(this, tree, ftpPath.getSharePath()); 2763 2764 2767 DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext(); 2768 if (diskCtx.hasChangeHandler()) 2769 diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, ftpPath.getSharePath()); 2770 2771 2773 if (logger.isDebugEnabled() && hasDebug(DBG_DIRECTORY)) 2774 logger.debug("DeleteDir ftp=" 2775 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", path=" 2776 + ftpPath.getSharePath()); 2777 } 2778 else 2779 { 2780 2781 2784 sendFTPResponse(550, sts == FileStatus.FileExists ? "File exists with that name" 2785 : "Directory does not exist"); 2786 return; 2787 } 2788 } 2789 catch (Exception ex) 2790 { 2791 sendFTPResponse(550, "Failed to delete directory"); 2792 return; 2793 } 2794 2795 2797 sendFTPResponse(250, "Directory deleted OK"); 2798 } 2799 2800 2807 protected final void procModifyDateTime(FTPRequest req) throws IOException 2808 { 2809 2810 2812 sendFTPResponse(550, "Not implemented yet"); 2813 } 2814 2815 2822 protected final void procFileSize(FTPRequest req) throws IOException 2823 { 2824 2825 2827 if (isLoggedOn() == false) 2828 { 2829 sendFTPResponse(500, ""); 2830 return; 2831 } 2832 2833 2835 if (req.hasArgument() == false) 2836 { 2837 sendFTPResponse(501, "Syntax error, parameter required"); 2838 return; 2839 } 2840 2841 2843 FTPPath ftpPath = generatePathForRequest(req, true); 2844 if (ftpPath == null) 2845 { 2846 sendFTPResponse(500, "Invalid path"); 2847 return; 2848 } 2849 2850 2852 DiskInterface disk = null; 2853 TreeConnection tree = null; 2854 2855 try 2856 { 2857 2858 2860 tree = getTreeConnection(ftpPath.getSharedDevice()); 2861 2862 2864 disk = (DiskInterface) ftpPath.getSharedDevice().getInterface(); 2865 2866 2868 FileInfo finfo = disk.getFileInformation(this, tree, ftpPath.getSharePath()); 2869 2870 if (finfo == null) 2871 { 2872 sendFTPResponse(550, "File " + req.getArgument() + " not available"); 2873 return; 2874 } 2875 2876 2878 sendFTPResponse(213, "" + finfo.getSize()); 2879 2880 2882 if (logger.isDebugEnabled() && hasDebug(DBG_FILE)) 2883 logger.debug("File size ftp=" 2884 + ftpPath.getFTPPath() + ", share=" + ftpPath.getShareName() + ", size=" + finfo.getSize()); 2885 } 2886 catch (Exception ex) 2887 { 2888 sendFTPResponse(550, "Error retrieving file size"); 2889 } 2890 } 2891 2892 2899 protected final void procStructure(FTPRequest req) throws IOException 2900 { 2901 2902 2904 if (req.hasArgument() && req.getArgument().equalsIgnoreCase("F")) 2905 sendFTPResponse(200, "OK"); 2906 2907 2909 sendFTPResponse(504, "Obsolete"); 2910 } 2911 2912 2919 protected final void procMode(FTPRequest req) throws IOException 2920 { 2921 2922 2924 if (req.hasArgument() && req.getArgument().equalsIgnoreCase("S")) 2925 sendFTPResponse(200, "OK"); 2926 2927 2929 sendFTPResponse(504, "Obsolete"); 2930 } 2931 2932 2939 protected final void procAllocate(FTPRequest req) throws IOException 2940 { 2941 2942 2944 sendFTPResponse(202, "Obsolete"); 2945 } 2946 2947 2959 protected final Vector <FileInfo> listFilesForPath(FTPPath path, boolean nameOnly, boolean hidden) 2960 { 2961 2962 2964 if (path == null) 2965 return null; 2966 2967 2969 Vector <FileInfo> files = new Vector <FileInfo>(); 2970 2971 if (path.hasSharedDevice() == false) 2972 { 2973 2974 2977 SharedDeviceList shares = null; 2978 if ( getClientInformation().isGuest()) 2979 shares = getDynamicShareList(); 2980 else 2981 shares = getShareList(); 2982 2983 if (shares != null) 2984 { 2985 2986 2988 Enumeration <SharedDevice> enm = shares.enumerateShares(); 2989 2990 while (enm.hasMoreElements()) 2991 { 2992 2993 2995 SharedDevice shr = enm.nextElement(); 2996 2997 2999 if (nameOnly == false) 3000 { 3001 3002 3005 FileInfo finfo = new FileInfo(shr.getName(), 0L, FileAttribute.Directory); 3006 files.add(finfo); 3007 } 3008 else 3009 files.add(new FileInfo(shr.getName(), 0L, FileAttribute.Directory)); 3010 } 3011 } 3012 } 3013 else 3014 { 3015 3016 3018 String searchPath = path.getSharePath(); 3019 3020 if (path.isDirectory()) 3021 searchPath = path.makeSharePathToFile("*"); 3022 3023 3025 TreeConnection tree = new TreeConnection(path.getSharedDevice()); 3026 3027 3029 DiskInterface disk = null; 3030 SearchContext ctx = null; 3031 3032 int searchAttr = FileAttribute.Directory + FileAttribute.Normal; 3033 if (hidden) 3034 searchAttr += FileAttribute.Hidden; 3035 3036 try 3037 { 3038 disk = (DiskInterface) path.getSharedDevice().getInterface(); 3039 ctx = disk.startSearch(this, tree, searchPath, searchAttr); 3040 } 3041 catch (Exception ex) 3042 { 3043 } 3044 3045 3047 if (ctx != null) 3048 { 3049 3050 3052 while (ctx.hasMoreFiles()) 3053 { 3054 3055 3057 if (nameOnly) 3058 { 3059 3060 3062 files.add(new FileInfo(ctx.nextFileName(), 0L, 0)); 3063 } 3064 else 3065 { 3066 3067 3069 FileInfo finfo = new FileInfo(); 3070 3071 if (ctx.nextFileInfo(finfo) == false) 3072 break; 3073 if (finfo.getFileName() != null) 3074 files.add(finfo); 3075 } 3076 } 3077 } 3078 } 3079 3080 3082 return files; 3083 } 3084 3085 3090 protected final SharedDeviceList getShareList() 3091 { 3092 3093 3095 if (m_shares == null) 3096 { 3097 3098 3100 SharedDeviceList shares = getFTPServer().getShareMapper().getShareList(getFTPServer().getServerName(), 3101 this, false); 3102 3103 3105 m_shares = new SharedDeviceList(); 3106 Enumeration enm = shares.enumerateShares(); 3107 3108 while (enm.hasMoreElements()) 3109 { 3110 3111 3113 SharedDevice shr = (SharedDevice) enm.nextElement(); 3114 3115 3117 if (shr instanceof DiskSharedDevice) 3118 m_shares.addShare(shr); 3119 } 3120 3121 3125 if (getServer().hasAccessControlManager()) 3126 { 3127 3128 3130 AccessControlManager aclMgr = getServer().getAccessControlManager(); 3131 3132 3134 m_shares = aclMgr.filterShareList(this, m_shares); 3135 } 3136 } 3137 3138 3140 return m_shares; 3141 } 3142 3143 3151 protected final TreeConnection getTreeConnection(SharedDevice share) 3152 { 3153 3154 3156 if (share == null) 3157 return null; 3158 3159 3161 TreeConnection tree = m_connections.findConnection(share.getName()); 3162 if (tree == null) 3163 { 3164 3165 3167 tree = new TreeConnection(share); 3168 if ( share.isTemporary() == false) 3169 m_connections.addConnection(tree); 3170 3171 3173 if (getServer().hasAccessControlManager()) 3174 { 3175 3176 3178 AccessControlManager aclMgr = getServer().getAccessControlManager(); 3179 3180 int access = aclMgr.checkAccessControl(this, share); 3181 if (access != AccessControl.Default) 3182 tree.setPermission(access); 3183 } 3184 } 3185 3186 3188 return tree; 3189 } 3190 3191 3197 private final DiskSharedDevice createHomeDiskShare(ClientInfo client) 3198 { 3199 3201 if ( client.hasHomeFolder() == false) 3202 { 3203 3205 NodeService nodeService = getServer().getConfiguration().getNodeService(); 3206 PersonService personService = getServer().getConfiguration().getPersonService(); 3207 TransactionService transService = getServer().getConfiguration().getTransactionService(); 3208 3209 3211 UserTransaction tx = transService.getUserTransaction(); 3212 NodeRef homeSpaceRef = null; 3213 3214 try 3215 { 3216 tx.begin(); 3217 homeSpaceRef = (NodeRef) nodeService.getProperty( personService.getPerson(client.getUserName()), 3218 ContentModel.PROP_HOMEFOLDER); 3219 client.setHomeFolder( homeSpaceRef); 3220 tx.commit(); 3221 } 3222 catch (Throwable ex) 3223 { 3224 try 3225 { 3226 tx.rollback(); 3227 } 3228 catch (Exception ex2) 3229 { 3230 logger.error("Failed to rollback transaction", ex2); 3231 } 3232 3233 if(ex instanceof RuntimeException ) 3234 { 3235 throw (RuntimeException )ex; 3236 } 3237 else 3238 { 3239 throw new RuntimeException ("Failed to get home folder", ex); 3240 } 3241 } 3242 } 3243 3244 3246 DiskInterface diskDrv = getServer().getConfiguration().getDiskInterface(); 3247 DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder()); 3248 3249 3251 diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304)); 3252 3253 3255 return new DiskSharedDevice( client.getUserName(), diskDrv, diskCtx, SharedDevice.Temporary); 3256 } 3257 3258 3261 public void run() 3262 { 3263 3264 try 3265 { 3266 3267 3269 if (logger.isDebugEnabled() && hasDebug(DBG_STATE)) 3270 logger.debug("FTP session started"); 3271 3272 3274 m_in = new InputStreamReader (m_sock.getInputStream()); 3275 m_out = new OutputStreamWriter (m_sock.getOutputStream()); 3276 3277 m_inbuf = new char[512]; 3278 m_outbuf = new StringBuffer (256); 3279 3280 3282 sendFTPResponse(220, "FTP server ready"); 3283 3284 3286 long startTime = 0L; 3287 long endTime = 0L; 3288 3289 3291 FTPRequest ftpReq = new FTPRequest(); 3292 3293 3295 int rdlen = -1; 3296 String cmd = null; 3297 3298 while (m_sock != null) 3299 { 3300 3301 3303 rdlen = m_in.read(m_inbuf); 3304 3305 3308 if (rdlen == -1) 3309 { 3310 closeSession(); 3311 continue; 3312 } 3313 3314 3316 if (rdlen > 0) 3317 { 3318 while (rdlen > 0 && m_inbuf[rdlen - 1] == '\r' || m_inbuf[rdlen - 1] == '\n') 3319 rdlen--; 3320 } 3321 3322 3324 cmd = new String (m_inbuf, 0, rdlen); 3325 3326 3328 if (logger.isDebugEnabled() && hasDebug(DBG_TIMING)) 3329 startTime = System.currentTimeMillis(); 3330 3331 if (logger.isDebugEnabled() && hasDebug(DBG_PKTTYPE)) 3332 logger.debug("Cmd " + ftpReq); 3333 3334 3336 ftpReq.setCommandLine(cmd); 3337 m_reqCount++; 3338 3339 switch (ftpReq.isCommand()) 3340 { 3341 3342 3344 case FTPCommand.User: 3345 procUser(ftpReq); 3346 break; 3347 3348 3350 case FTPCommand.Pass: 3351 procPassword(ftpReq); 3352 break; 3353 3354 3356 case FTPCommand.Quit: 3357 procQuit(ftpReq); 3358 break; 3359 3360 3362 case FTPCommand.Type: 3363 procType(ftpReq); 3364 break; 3365 3366 3368 case FTPCommand.Port: 3369 procPort(ftpReq); 3370 break; 3371 3372 3374 case FTPCommand.Pasv: 3375 procPassive(ftpReq); 3376 break; 3377 3378 3380 case FTPCommand.Rest: 3381 procRestart(ftpReq); 3382 break; 3383 3384 3386 case FTPCommand.Retr: 3387 procReturnFile(ftpReq); 3388 3389 3391 m_restartPos = 0; 3392 break; 3393 3394 3396 case FTPCommand.Stor: 3397 procStoreFile(ftpReq); 3398 break; 3399 3400 3402 case FTPCommand.Pwd: 3403 case FTPCommand.XPwd: 3404 procPrintWorkDir(ftpReq); 3405 break; 3406 3407 3409 case FTPCommand.Cwd: 3410 case FTPCommand.XCwd: 3411 procChangeWorkDir(ftpReq); 3412 break; 3413 3414 3416 case FTPCommand.Cdup: 3417 case FTPCommand.XCup: 3418 procCdup(ftpReq); 3419 break; 3420 3421 3423 case FTPCommand.List: 3424 procList(ftpReq); 3425 break; 3426 3427 3429 case FTPCommand.Nlst: 3430 procNList(ftpReq); 3431 break; 3432 3433 3435 case FTPCommand.Dele: 3436 procDeleteFile(ftpReq); 3437 break; 3438 3439 3441 case FTPCommand.Rnfr: 3442 procRenameFrom(ftpReq); 3443 break; 3444 3445 3447 case FTPCommand.Rnto: 3448 procRenameTo(ftpReq); 3449 break; 3450 3451 3453 case FTPCommand.Mkd: 3454 case FTPCommand.XMkd: 3455 procCreateDirectory(ftpReq); 3456 break; 3457 3458 3460 case FTPCommand.Rmd: 3461 case FTPCommand.XRmd: 3462 procRemoveDirectory(ftpReq); 3463 break; 3464 3465 3467 case FTPCommand.Size: 3468 procFileSize(ftpReq); 3469 break; 3470 3471 3473 case FTPCommand.Mdtm: 3474 procModifyDateTime(ftpReq); 3475 break; 3476 3477 3479 case FTPCommand.Syst: 3480 procSystemStatus(ftpReq); 3481 break; 3482 3483 3485 case FTPCommand.Stat: 3486 procServerStatus(ftpReq); 3487 break; 3488 3489 3491 case FTPCommand.Help: 3492 procHelp(ftpReq); 3493 break; 3494 3495 3497 case FTPCommand.Noop: 3498 procNoop(ftpReq); 3499 break; 3500 3501 3503 case FTPCommand.Stru: 3504 procStructure(ftpReq); 3505 break; 3506 3507 3509 case FTPCommand.Mode: 3510 procMode(ftpReq); 3511 break; 3512 3513 3515 case FTPCommand.Allo: 3516 procAllocate(ftpReq); 3517 break; 3518 3519 3521 default: 3522 if (ftpReq.isCommand() != FTPCommand.InvalidCmd) 3523 sendFTPResponse(502, "Command " 3524 + FTPCommand.getCommandName(ftpReq.isCommand()) + " not implemented"); 3525 else 3526 sendFTPResponse(502, "Command not implemented"); 3527 break; 3528 } 3529 3530 3532 if (logger.isDebugEnabled() && hasDebug(DBG_TIMING)) 3533 { 3534 endTime = System.currentTimeMillis(); 3535 long duration = endTime - startTime; 3536 if (duration > 20) 3537 logger.debug("Processed cmd " 3538 + FTPCommand.getCommandName(ftpReq.isCommand()) + " in " + duration + "ms"); 3539 } 3540 3541 3543 try 3544 { 3545 3547 endTransaction(); 3548 } 3549 catch ( Exception ex) 3550 { 3551 3553 if ( logger.isDebugEnabled()) 3554 logger.debug("Error committing transaction", ex); 3555 } 3556 3557 } } 3559 catch (SocketException ex) 3560 { 3561 3562 3564 if (logger.isErrorEnabled() && hasDebug(DBG_STATE)) 3565 logger.error("Socket closed by remote client"); 3566 } 3567 catch (Exception ex) 3568 { 3569 3570 3572 if (isShutdown() == false) 3573 { 3574 logger.debug(ex); 3575 } 3576 } 3577 finally 3578 { 3579 3581 if ( hasUserTransaction()) 3582 { 3583 try 3584 { 3585 getUserTransaction().rollback(); 3586 } 3587 catch (Exception ex) 3588 { 3589 logger.warn("Failed to rollback transaction", ex); 3590 } 3591 } 3592 } 3593 3594 3596 closeSession(); 3597 3598 3600 if (hasDebug(DBG_STATE)) 3601 logger.debug("Server session closed"); 3602 } 3603} | Popular Tags |