package com.f5.tmui.locallb.handler.workspace; import com.f5.form.ShellCommandValidator; import com.f5.log.F5Logger; import com.f5.model.db.DBConnection; import com.f5.tmui.util.FolderUtils; import com.f5.tmui.util.Syscall; import com.f5.tmui.util.Syscall.CallException; import com.f5.tmui.util.Syscall.Result; import com.f5.util.F5Exception; import com.f5.util.NLSEngine; import com.f5.util.SHA1; import com.f5.util.User; import com.f5.util.WebUtils; import com.f5.view.web.pagerenderer.Html; import com.f5.view.web.pagerenderer.Link; import com.f5.view.web.pagerenderer.TableRow; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Scanner; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.json.simple.JSONObject; public class WorkspaceUtils { public static final String CHMOD_COMMAND = "/bin/chmod"; public static final String CHOWN_COMMAND = "/bin/chown"; public static final String FILE_GROUP = "sdm"; public static final String FILE_MODE = "664"; public static final String JSON_CHILDREN = "children"; public static final String JSON_DIRECTORY = "dir"; public static final String JSON_FILE = "file"; private static final String ilxWorkspacesDir = "/var/ilx/workspaces/"; private static final String pluginsDir = "/var/sdm/plugin_store/plugins/"; private static final Set whitelistDirSet = new HashSet(Arrays.asList("/var/ilx/workspaces/", "/var/sdm/plugin_store/plugins/")); private static final List WHITELISTED_QUERIES = Arrays.asList("locallb.irule.ilx.select_plugin_path"); private static final List WHITELISTED_TMSH_MODULES = Arrays.asList("ilx"); private static final int OPERATION_IDX = 0; private static final int MODULE_IDX = 2; private static final String TMUI_DUBBUF_NAME = "Tmui-Dubbuf"; public static boolean csrfValidated(String bufForm, String timenow, String bufHeader) { return bufHeader != null && bufForm != null && timenow != null && bufForm.equals(SHA1.hash(bufHeader + timenow)); } public static JSONObject runTmshCommand(String command, HttpServletRequest request) { F5Logger logger = (F5Logger)F5Logger.getLogger(WorkspaceUtils.class); JSONObject resultObject = new JSONObject(); String output = ""; String error = ""; if (!csrfValidated(request.getHeader("_bufvalue"), request.getHeader("_timenow"), request.getHeader("Tmui-Dubbuf"))) { logger.warn("Invalid user token - token provided by user is not authorized"); resultObject.put("output", output); resultObject.put("error", NLSEngine.getString("ilx.workspace.error.InvalidUserToken")); return resultObject; } else { if ("POST".equalsIgnoreCase(request.getMethod())) { String[] cmdArray = command.split(" "); String operation = cmdArray[0]; String module = cmdArray[2]; if (!ShellCommandValidator.checkForBadShellCharacters(command) && (operation.equals("create") || operation.equals("delete") || operation.equals("list") || operation.equals("modify")) && WHITELISTED_TMSH_MODULES.contains(module)) { try { String[] args = new String[]{command}; Result result = Syscall.callElevated(Syscall.TMSH, args); output = result.getOutput(); error = result.getError(); } catch (CallException var11) { logger.error(NLSEngine.getString("ilx.workspace.error.TmshCommandFailed") + ": " + var11.getMessage()); error = var11.getMessage(); } } else { error = NLSEngine.getString("ilx.workspace.error.RejectedTmshCommand"); } } else { error = NLSEngine.getString("ilx.workspace.error.InvalidMethod"); } resultObject.put("output", output); resultObject.put("error", error); return resultObject; } } private static void listDirectoryRecursive(File dir, JsonArray parent) { File[] list = dir.listFiles(); Arrays.sort(list); File[] arr$ = list; int len$ = list.length; for(int i$ = 0; i$ < len$; ++i$) { File file = arr$[i$]; JsonObject dirObj; if (file.isDirectory()) { dirObj = new JsonObject(); dirObj.addProperty("dir", file.getName()); parent.add(dirObj); JsonArray children = new JsonArray(); dirObj.add("children", children); listDirectoryRecursive(file, children); } else { dirObj = new JsonObject(); dirObj.addProperty("file", file.getName()); parent.add(dirObj); } } } public static JSONObject listDirectory(String directoryPath) throws Exception { JSONObject resultObject = new JSONObject(); File directory = new File(directoryPath); if (directory.exists()) { JsonObject listObj = new JsonObject(); listObj.addProperty("dir", directory.getName()); JsonArray children = new JsonArray(); listObj.add("children", children); listDirectoryRecursive(directory, children); resultObject.put("output", listObj); } return resultObject; } public static JSONObject readFile(String fileName) throws FileNotFoundException { JSONObject resultObject = new JSONObject(); File file = new File(fileName); StringBuilder fileContents = new StringBuilder((int)file.length()); Scanner scanner = new Scanner(new BufferedReader(new FileReader(file))); String lineSeparator = System.getProperty("line.separator"); JSONObject var6; try { while(scanner.hasNextLine()) { fileContents.append(scanner.nextLine() + lineSeparator); } resultObject.put("output", fileContents.toString()); var6 = resultObject; } finally { scanner.close(); } return var6; } public static JSONObject saveFile(HttpServletRequest request) throws IOException { F5Logger logger = (F5Logger)F5Logger.getLogger(WorkspaceUtils.class); PrintWriter writer = null; JSONObject resultObject = new JSONObject(); label75: { JSONObject var4; try { String content; try { if (csrfValidated(request.getHeader("_bufvalue"), request.getHeader("_timenow"), request.getHeader("Tmui-Dubbuf"))) { String fileName = WebUtils.getProperty(request, "fileName"); content = WebUtils.getProperty(request, "content"); writer = new PrintWriter(new FileWriter(fileName)); writer.println(content); String[] chmodCmd = new String[]{"/bin/chmod", "664", fileName}; Runtime.getRuntime().exec(chmodCmd); String[] chownCmd = new String[]{"/bin/chown", ":sdm", fileName}; Runtime.getRuntime().exec(chownCmd); break label75; } logger.warn("Invalid user token - token provided by user is not authorized"); resultObject.put("error", NLSEngine.getString("ilx.workspace.error.InvalidUserToken")); var4 = resultObject; } catch (IOException var12) { content = NLSEngine.getString("ilx.workspace.error.ErrorWritingFile") + ": " + var12.getMessage(); logger.error(content); throw var12; } catch (SecurityException var13) { content = NLSEngine.getString("ilx.workspace.error.ErrorWritingFile") + ": " + var13.getMessage(); logger.error(content); throw var13; } } finally { if (writer != null) { writer.close(); } } return var4; } resultObject.put("output", "Success"); return resultObject; } public static void addArrayItemsToRow(ArrayList list, TableRow row, String linkBase) { Iterator iterator = list.iterator(); String pluginName = (String)iterator.next(); Link link = new Link(linkBase + pluginName, FolderUtils.getLeafName(pluginName)); Link newLink; for(Link parentEle = link; iterator.hasNext(); parentEle = newLink) { pluginName = (String)iterator.next(); Html comma = new Html(","); parentEle.setChildRowElement(comma); newLink = new Link(linkBase + pluginName, FolderUtils.getLeafName(pluginName)); comma.setChildRowElement(newLink); } row.addChainedRowElement(link); } public static String archiveArgPath(String partition, String file) { return "/" + partition + "/" + file; } public static String archiveRealPath(String partition, String file) { return "/var/ilx/workspaces/" + partition + "/archive/" + file; } public static JSONObject dbQuery(String queryName, String objName, String columnName) throws SQLException, F5Exception { if (!WHITELISTED_QUERIES.contains(queryName)) { throw new F5Exception("Illegal query: " + queryName); } else { JSONObject resultObject = new JSONObject(); JSONObject var6; try { if (!DBConnection.isAllocated()) { DBConnection.allocate(); } ResultSet rs = DBConnection.execute(queryName, new Object[]{objName}); String result = ""; if (rs != null && rs.next()) { result = rs.getString(columnName); } resultObject.put("output", result); var6 = resultObject; } catch (SQLException var15) { throw var15; } finally { try { if (DBConnection.isAllocated()) { DBConnection.deallocate(); } } catch (SQLException var14) { throw var14; } } return var6; } } public static boolean isFileWhitelisted(String fileName) throws IOException { F5Logger log = (F5Logger)F5Logger.getLogger(WorkspaceUtils.class); boolean isWhitelisted = false; File file = new File(fileName); String canonFilename = file.getCanonicalPath(); Path canonPath = Paths.get(canonFilename); log.debug("Input filename " + fileName + " has canon name " + canonFilename); if (!Files.isDirectory(canonPath.getParent(), new LinkOption[0])) { log.debug("Directory for file " + canonFilename + " does not exist; failing"); throw new FileNotFoundException("Dir path to file " + fileName + " does not exist."); } else { Path realDirPath = canonPath.getParent().toRealPath(); Iterator i$ = whitelistDirSet.iterator(); while(i$.hasNext()) { String whitelistDir = (String)i$.next(); Path whitelistDirPath = Paths.get(whitelistDir); log.debug("Checking if " + canonFilename + " lies under directory " + whitelistDir); if (realDirPath.startsWith(whitelistDirPath)) { log.debug(" > " + canonFilename + " is whitelisted under " + whitelistDir); isWhitelisted = true; break; } } log.debug(canonFilename + " is " + (isWhitelisted ? "" : "not ") + "a whitelisted file"); return isWhitelisted; } } public static boolean isUserAuthorized(User user) { switch(user.getRawRoleId()) { case 0: case 20: case 100: case 510: return true; default: return false; } } public static boolean userCanAccessPartition(User user, String fileName, boolean checkUserPartitionPermission) throws IOException { F5Logger log = (F5Logger)F5Logger.getLogger(WorkspaceUtils.class); File file = new File(fileName); String canonFilename = file.getCanonicalPath(); Path canonPath = Paths.get(canonFilename); log.debug("Input filename " + fileName + " has canon name " + canonFilename); String partition = null; int delimiterIndex; if (canonFilename.startsWith("/var/ilx/workspaces/")) { delimiterIndex = canonFilename.indexOf(47, "/var/ilx/workspaces/".length()); if (delimiterIndex < 0) { log.error(canonFilename + " is a file with no partition. Failing."); return false; } partition = canonFilename.substring("/var/ilx/workspaces/".length(), delimiterIndex); } else { if (!canonFilename.startsWith("/var/sdm/plugin_store/plugins/")) { log.error("Filename " + canonFilename + " is not in a whitelisted directory"); return false; } delimiterIndex = canonFilename.indexOf(58, "/var/sdm/plugin_store/plugins/".length() + 1); if (delimiterIndex < 0) { log.error(canonFilename + " is a file with no partition. Failing."); return false; } partition = canonFilename.substring("/var/sdm/plugin_store/plugins/".length() + 1, delimiterIndex); } List allowedPartitions = user.getAllowedPartitions(); log.debug(canonFilename + " lies in partition " + partition + "; this is" + (allowedPartitions.contains(partition) ? "" : " not") + " a permitted partition from user's partitions of " + allowedPartitions.toString()); if (!allowedPartitions.contains(partition)) { return false; } else if (checkUserPartitionPermission) { HashMap allRoles = user.getAllRoles(); log.debug(user.getUsername() + " has roles " + allRoles.toString()); int partitionRole = true; int partitionRole; if (allRoles.containsKey("[All]")) { partitionRole = (Integer)allRoles.get("[All]"); } else { if (!allRoles.containsKey(partition)) { log.debug(user.getUsername() + " has no role for partition " + partition); return false; } partitionRole = (Integer)allRoles.get(partition); } log.debug(user.getUsername() + " has role " + User.getRoleName(partitionRole) + " on partition " + partition); boolean isSuperAdmin = partitionRole == 0; boolean isAdminReadOnly = partitionRole == 20; boolean isManager = partitionRole == 100; boolean isIRuleManager = partitionRole == 510; return isSuperAdmin || isAdminReadOnly || isManager || isIRuleManager; } else { return true; } } }