Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| /** | |
| * Copyright (c) 2009--2014 Red Hat, Inc. | |
| * | |
| * This software is licensed to you under the GNU General Public License, | |
| * version 2 (GPLv2). There is NO WARRANTY for this software, express or | |
| * implied, including the implied warranties of MERCHANTABILITY or FITNESS | |
| * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 | |
| * along with this software; if not, see | |
| * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. | |
| * | |
| * Red Hat trademarks are not licensed under GPLv2. No permission is | |
| * granted to use or replicate Red Hat trademarks that are incorporated | |
| * in this software or its documentation. | |
| */ | |
| package com.redhat.rhn.manager.configuration; | |
| import com.redhat.rhn.common.conf.Config; | |
| import com.redhat.rhn.common.conf.ConfigDefaults; | |
| import com.redhat.rhn.common.validator.ValidatorError; | |
| import com.redhat.rhn.common.validator.ValidatorResult; | |
| import java.util.regex.Matcher; | |
| import java.util.regex.Pattern; | |
| /** | |
| * ConfigurationValidation | |
| * | |
| * Holds methods for validating a variety of configuration-related fields/values | |
| * | |
| * @version $Rev$ | |
| */ | |
| public class ConfigurationValidation { | |
| private ConfigurationValidation() { } | |
| /** | |
| * Validate incoming content. This attempts to do macro-substitution and complains | |
| * bitterly if it runs into problems: | |
| * | |
| * <ul> | |
| * <li>Can't find a function-name between the delimiters | |
| * <li>Don't like the function-name between the delimiters | |
| * <li>Don't like the arguments passed to the function-name between the delimiters | |
| * </ul> | |
| * | |
| * Returns an error list. An element is a Map with keys "key", "arg0", "arg1", "arg2". | |
| * The map values are used to I18N the resulting error message. | |
| * | |
| * @param content content of a TEXT config-file | |
| * @param macroStart start macro | |
| * @param macroEnd end macro | |
| * @return ValidatorResult. These will be reasons | |
| * why this content didn't pass. if result.isEmpty() - everything is OK | |
| */ | |
| public static ValidatorResult validateContent(String content, | |
| String macroStart, String macroEnd) { | |
| ValidatorResult result = new ValidatorResult(); | |
| // If no-file or macros aren't in the file, we're ok | |
| if (content == null || content.length() == 0) { | |
| return result; | |
| } | |
| boolean hasStart = content.indexOf(macroStart) >= 0; | |
| boolean hasEnd = content.indexOf(macroEnd) >= 0; | |
| // If no macros, we're done too | |
| if (!hasStart && !hasEnd) { | |
| return result; | |
| } | |
| // Macros might contain special reg-ex chars - escape them | |
| String escStart = ConfigurationValidation.regexEscape(macroStart); | |
| String escEnd = ConfigurationValidation.regexEscape(macroEnd); | |
| // Start-delim followed by zero or more whitespace followed by zero or more | |
| // characters followed by zero or more whitespace followed by end-delim | |
| String findMacroStr = escStart + "(.*?)" + escEnd; | |
| // One or more chars NOT parentheses$1, | |
| // followed by zero or one "( any-chars$3 ) $2", | |
| // followed by zero or one "= any-chars$5 $4" | |
| String macroStr = "([^()]+)(\\((.*?)\\))?\\s*(=(.*))?"; | |
| Pattern findMacro = Pattern.compile(findMacroStr, | |
| Pattern.MULTILINE + Pattern.DOTALL); | |
| Pattern macroPattern = Pattern.compile(macroStr, Pattern.DOTALL); | |
| Matcher matchMacro = findMacro.matcher(content); | |
| while (matchMacro.find()) { | |
| String seq = matchMacro.group(1).trim(); | |
| if (seq.length() == 0) { | |
| // Empty macro - skip | |
| continue; | |
| } | |
| Matcher parts = macroPattern.matcher(seq); | |
| if (parts.matches()) { | |
| String name = parts.group(1); | |
| String args = parts.group(3); | |
| // String deflt = parts.group(5); | |
| // Can't find a function-name | |
| if (name == null || name.trim().length() == 0) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.content.no-macro-name", seq)); | |
| } | |
| // Function-name doesn't look like one we understand | |
| else if (!name.startsWith("rhn.system.")) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.content.bad-macro-name", | |
| name.trim())); | |
| } | |
| // Arg-content must be word, whitespace values, or hyphens | |
| String regex = Config.get().getString( | |
| ConfigDefaults.CONFIG_MACRO_ARGUMENT_REGEX, "[\\w\\s-:]*"); | |
| if (args != null && !args.trim().matches(regex)) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.content.bad-arg-content", | |
| name.trim(), args.trim())); | |
| } | |
| } | |
| else { | |
| // Something truly odd happened - complain bitterly | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.content.bad-macro", | |
| matchMacro.group(0))); | |
| } | |
| } | |
| return result; | |
| } | |
| /** | |
| * Validate config-file pathname. The rules are pretty basic: | |
| * | |
| * <ul> | |
| * <li>MUST start with '/' | |
| * <li>CANNOT end with a '/' | |
| * <li>CANNOT be relative - no '..' anywhere | |
| * </ul> | |
| * That's it. | |
| * @param path pathname to be validated | |
| * @return a Validator Result. | |
| */ | |
| public static ValidatorResult validatePath(String path) { | |
| ValidatorResult result = new ValidatorResult(); | |
| if (path == null || path.length() == 0) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.path.empty", path)); | |
| return result; | |
| } | |
| if (!path.startsWith("/")) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.path.no-starting-slash", path)); | |
| } | |
| if (path.endsWith("/")) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.path.has-ending-slash", path)); | |
| } | |
| if (path.indexOf("..") != -1) { | |
| result.addError(new ValidatorError( | |
| "configmanager.filedetails.path.has-relative-dirs", path)); | |
| } | |
| return result; | |
| } | |
| /** | |
| * Validate a user- or group-ID. Tests that it's a valid Linux u/gid | |
| * (positive int) | |
| * @param in string to be tested | |
| * @return true if valid, false otherwise | |
| */ | |
| public static boolean validateUGID(String in) { | |
| boolean valid = false; | |
| try { | |
| int i = Integer.parseInt(in); | |
| valid = (i > 0); | |
| } | |
| catch (Exception e) { | |
| valid = false; | |
| } | |
| return valid; | |
| } | |
| /** | |
| * Validate a user- or group-NAME. Tests that it's a valid Linux name | |
| * (starts w/alpha, followed by alphanumeric_-) | |
| * @param in string to be tested | |
| * @return true if valid, false otherwise | |
| */ | |
| public static boolean validateUserOrGroup(String in) { | |
| return (in != null && in.matches("^[a-zA-Z0-9_][a-zA-Z0-9_\\-]*$")); | |
| } | |
| /** | |
| * Escape a string that is going to be used to build a regex expression | |
| * @param inStr string of interest | |
| * @return string with non-whitespace and non-word characters escaped | |
| */ | |
| static String regexEscape(String inStr) { | |
| StringBuilder buff = new StringBuilder(""); | |
| for (int i = 0; i < inStr.length(); i++) { | |
| if (!inStr.substring(i, i + 1).matches("[\\s\\w]")) { | |
| buff.append("\\").append(inStr.charAt(i)); | |
| } | |
| else { | |
| buff.append(inStr.charAt(i)); | |
| } | |
| } | |
| return buff.toString(); | |
| } | |
| } |