1/*
2 * Copyright (c) 2013, 2014, 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
24import jdk.testlibrary.OutputAnalyzer;
25import jdk.testlibrary.ProcessTools;
26import jdk.test.lib.Platform;
27
28import java.io.BufferedWriter;
29import java.io.IOException;
30import java.nio.charset.Charset;
31import java.nio.file.FileSystem;
32import java.nio.file.FileSystems;
33import java.nio.file.Files;
34import java.nio.file.Path;
35import java.nio.file.attribute.PosixFilePermission;
36import java.util.ArrayList;
37import java.util.Arrays;
38import java.util.HashSet;
39import java.util.List;
40import java.util.Set;
41
42/**
43 * Change file permission for out-of-the-box management an do test used by
44 * PasswordFilePermissionTest and SSLConfigFilePermissionTest tests
45 *
46 * @author Taras Ledkov
47 */
48public abstract class AbstractFilePermissionTest {
49    private final String TEST_CLASS_PATH = System.getProperty("test.class.path");
50    protected final String TEST_CLASSES = System.getProperty("test.classes");
51    protected final FileSystem FS = FileSystems.getDefault();
52    private int MAX_GET_FREE_PORT_TRIES = 10;
53
54    protected final Path libDir = FS.getPath(TEST_CLASSES, "lib");
55    protected final Path mgmt = libDir.resolve("management.properties");
56    private final String mp = "-Dcom.sun.management.config.file=" + mgmt.toFile().getAbsolutePath();
57    private final String className = "Dummy";
58    private int failures = 0;
59
60    protected final Path file2PermissionTest;
61
62    protected AbstractFilePermissionTest(String fileName2PermissionTest) {
63        this.file2PermissionTest = libDir.resolve(fileName2PermissionTest);
64
65        try {
66            MAX_GET_FREE_PORT_TRIES = Integer.parseInt(System.getProperty("test.getfreeport.max.tries", "10"));
67        } catch (NumberFormatException ex) {
68            ex.printStackTrace();
69        }
70    }
71
72
73    public static void createFile(Path path, String... content) throws IOException {
74        if (Files.exists(path) && Files.isRegularFile(path)) {
75            try {
76                Files.delete(path);
77            } catch (Exception ex) {
78                System.out.println("WARNING: " + path.toFile().getAbsolutePath() + " already exists - unable to remove old copy");
79                ex.printStackTrace();
80            }
81        }
82
83        try (BufferedWriter bw = Files.newBufferedWriter(path, Charset.defaultCharset())) {
84            for (String str : content) {
85                bw.write(str, 0, str.length());
86                bw.newLine();
87            }
88        }
89    }
90
91    public boolean skipTest() {
92        if ((TEST_CLASSES == null) || ("".equals(TEST_CLASSES))) {
93            System.out.println("Test is designed to be run from jtreg only");
94            return true;
95        }
96
97        if (!Platform.isLinux() && !Platform.isSolaris()) {
98            System.out.println("Test not designed to run on this operating system, skipping...");
99            return true;
100        }
101        return false;
102    }
103
104    protected abstract void testSetup() throws IOException;
105
106    public void runTest(String[] args) throws Exception {
107
108        if (skipTest()) {
109            return;
110        }
111
112        Files.deleteIfExists(mgmt);
113        Files.deleteIfExists(file2PermissionTest);
114        libDir.toFile().mkdir();
115
116        testSetup();
117
118        try {
119            test1();
120            test2();
121
122            if (failures == 0) {
123                System.out.println("All test(s) passed");
124            } else {
125                throw new Error(String.format("%d test(s) failed", failures));
126            }
127        } finally {
128            resetPasswordFilePermission();
129        }
130    }
131
132    /**
133     * Test 1 - SSL config file is secure - VM should start
134     */
135    private void test1() throws Exception {
136        final Set<PosixFilePermission> perms_0700 = new HashSet<>();
137        perms_0700.add(PosixFilePermission.OWNER_WRITE);
138        perms_0700.add(PosixFilePermission.OWNER_READ);
139        perms_0700.add(PosixFilePermission.OWNER_EXECUTE);
140        Files.setPosixFilePermissions(file2PermissionTest, perms_0700);
141
142        if (doTest() != 0) {
143            ++failures;
144        }
145    }
146
147    /**
148     * Test 1 - SSL config file is secure - VM should start
149     */
150    private void test2() throws Exception {
151        final Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file2PermissionTest);
152        perms.add(PosixFilePermission.OTHERS_READ);
153        perms.add(PosixFilePermission.OTHERS_EXECUTE);
154        Files.setPosixFilePermissions(file2PermissionTest, perms);
155
156        if (doTest() == 0) {
157            ++failures;
158        }
159    }
160
161    private int doTest() throws Exception {
162
163        for (int i = 0; i < MAX_GET_FREE_PORT_TRIES; ++i) {
164            final String pp = "-Dcom.sun.management.jmxremote.port=" + jdk.testlibrary.Utils.getFreePort();
165
166            List<String> command = new ArrayList<>();
167            command.addAll(jdk.testlibrary.Utils.getVmOptions());
168            command.add(mp);
169            command.add(pp);
170            command.add("-cp");
171            command.add(TEST_CLASSES);
172            command.add(className);
173
174
175            ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
176                    command.toArray(new String[command.size()]));
177
178            System.out.println("test cmdline: " + Arrays.toString(processBuilder.command().toArray()).replace(",", ""));
179            OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
180
181            System.out.println("test output:");
182            System.out.println(output.getOutput());
183
184            if ((output.getExitValue() == 0)  ||
185                !output.getOutput().contains("Exception thrown by the agent : " +
186                        "java.rmi.server.ExportException: Port already in use")) {
187                return output.getExitValue();
188            }
189        }
190
191        return -1;
192    }
193
194    private void resetPasswordFilePermission() throws Exception {
195        final Set<PosixFilePermission> perms_0777 = new HashSet<>();
196        Arrays.asList(PosixFilePermission.values()).stream().forEach(p -> {
197            perms_0777.add(p);
198        });
199        Files.setPosixFilePermissions(file2PermissionTest, perms_0777);
200    }
201}
202