1 /*
   2  * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import jdk.test.lib.process.OutputAnalyzer;
  25 import jdk.test.lib.process.ProcessTools;
  26 import jdk.test.lib.Platform;
  27 
  28 import java.io.BufferedWriter;
  29 import java.io.IOException;
  30 import java.nio.charset.Charset;
  31 import java.nio.file.FileSystem;
  32 import java.nio.file.FileSystems;
  33 import java.nio.file.Files;
  34 import java.nio.file.Path;
  35 import java.nio.file.attribute.PosixFilePermission;
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.Collections;
  39 import java.util.HashSet;
  40 import java.util.List;
  41 import java.util.Set;
  42 
  43 /**
  44  * Change file permission for out-of-the-box management an do test used by
  45  * PasswordFilePermissionTest and SSLConfigFilePermissionTest tests
  46  *
  47  * @author Taras Ledkov
  48  */
  49 public abstract class AbstractFilePermissionTest {
  50     private final String TEST_CLASS_PATH = System.getProperty("test.class.path");
  51     protected final String TEST_CLASSES = System.getProperty("test.classes");
  52     protected final FileSystem FS = FileSystems.getDefault();
  53     private int MAX_GET_FREE_PORT_TRIES = 10;
  54 
  55     protected final Path libDir = FS.getPath(TEST_CLASSES, "lib");
  56     protected final Path mgmt = libDir.resolve("management.properties");
  57     private final String mp = "-Dcom.sun.management.config.file=" + mgmt.toFile().getAbsolutePath();
  58     private final String className = "Dummy";
  59     private int failures = 0;
  60 
  61     protected final Path file2PermissionTest;
  62 
  63     protected AbstractFilePermissionTest(String fileName2PermissionTest) {
  64         this.file2PermissionTest = libDir.resolve(fileName2PermissionTest);
  65 
  66         try {
  67             MAX_GET_FREE_PORT_TRIES = Integer.parseInt(System.getProperty("test.getfreeport.max.tries", "10"));
  68         } catch (NumberFormatException ex) {
  69             ex.printStackTrace();
  70         }
  71     }
  72 
  73 
  74     public static void createFile(Path path, String... content) throws IOException {
  75         if (Files.exists(path) && Files.isRegularFile(path)) {
  76             try {
  77                 Files.delete(path);
  78             } catch (Exception ex) {
  79                 System.out.println("WARNING: " + path.toFile().getAbsolutePath() + " already exists - unable to remove old copy");
  80                 ex.printStackTrace();
  81             }
  82         }
  83 
  84         try (BufferedWriter bw = Files.newBufferedWriter(path, Charset.defaultCharset())) {
  85             for (String str : content) {
  86                 bw.write(str, 0, str.length());
  87                 bw.newLine();
  88             }
  89         }
  90     }
  91 
  92     public boolean skipTest() {
  93         if ((TEST_CLASSES == null) || ("".equals(TEST_CLASSES))) {
  94             System.out.println("Test is designed to be run from jtreg only");
  95             return true;
  96         }
  97 
  98         if (!Platform.isLinux() && !Platform.isSolaris()) {
  99             System.out.println("Test not designed to run on this operating system, skipping...");
 100             return true;
 101         }
 102         return false;
 103     }
 104 
 105     protected abstract void testSetup() throws IOException;
 106 
 107     public void runTest(String[] args) throws Exception {
 108 
 109         if (skipTest()) {
 110             return;
 111         }
 112 
 113         Files.deleteIfExists(mgmt);
 114         Files.deleteIfExists(file2PermissionTest);
 115         libDir.toFile().mkdir();
 116 
 117         testSetup();
 118 
 119         try {
 120             test1();
 121             test2();
 122 
 123             if (failures == 0) {
 124                 System.out.println("All test(s) passed");
 125             } else {
 126                 throw new Error(String.format("%d test(s) failed", failures));
 127             }
 128         } finally {
 129             resetPasswordFilePermission();
 130         }
 131     }
 132 
 133     /**
 134      * Test 1 - SSL config file is secure - VM should start
 135      */
 136     private void test1() throws Exception {
 137         final Set<PosixFilePermission> perms_0700 = new HashSet<>();
 138         perms_0700.add(PosixFilePermission.OWNER_WRITE);
 139         perms_0700.add(PosixFilePermission.OWNER_READ);
 140         perms_0700.add(PosixFilePermission.OWNER_EXECUTE);
 141         Files.setPosixFilePermissions(file2PermissionTest, perms_0700);
 142 
 143         if (doTest() != 0) {
 144             ++failures;
 145         }
 146     }
 147 
 148     /**
 149      * Test 1 - SSL config file is secure - VM should start
 150      */
 151     private void test2() throws Exception {
 152         final Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file2PermissionTest);
 153         perms.add(PosixFilePermission.OTHERS_READ);
 154         perms.add(PosixFilePermission.OTHERS_EXECUTE);
 155         Files.setPosixFilePermissions(file2PermissionTest, perms);
 156 
 157         if (doTest() == 0) {
 158             ++failures;
 159         }
 160     }
 161 
 162     private int doTest() throws Exception {
 163 
 164         for (int i = 0; i < MAX_GET_FREE_PORT_TRIES; ++i) {
 165             final String pp = "-Dcom.sun.management.jmxremote.port=" + jdk.test.lib.Utils.getFreePort();
 166 
 167             List<String> command = new ArrayList<>();
 168             Collections.addAll(command, jdk.test.lib.Utils.getTestJavaOpts());
 169             command.add(mp);
 170             command.add(pp);
 171             command.add("-cp");
 172             command.add(TEST_CLASSES);
 173             command.add(className);
 174 
 175 
 176             ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
 177                     command.toArray(new String[command.size()]));
 178 
 179             System.out.println("test cmdline: " + Arrays.toString(processBuilder.command().toArray()).replace(",", ""));
 180             OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
 181 
 182             System.out.println("test output:");
 183             System.out.println(output.getOutput());
 184 
 185             if ((output.getExitValue() == 0)  ||
 186                 !output.getOutput().contains("Exception thrown by the agent : " +
 187                         "java.rmi.server.ExportException: Port already in use")) {
 188                 return output.getExitValue();
 189             }
 190         }
 191 
 192         return -1;
 193     }
 194 
 195     private void resetPasswordFilePermission() throws Exception {
 196         final Set<PosixFilePermission> perms_0777 = new HashSet<>();
 197         Arrays.asList(PosixFilePermission.values()).stream().forEach(p -> {
 198             perms_0777.add(p);
 199         });
 200         Files.setPosixFilePermissions(file2PermissionTest, perms_0777);
 201     }
 202 }