1/*
2 * Copyright (c) 2008, 2013, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.nio.fs;
27
28import static sun.nio.fs.WindowsNativeDispatcher.*;
29import static sun.nio.fs.WindowsConstants.*;
30
31/**
32 * Security related utility methods.
33 */
34
35class WindowsSecurity {
36    private WindowsSecurity() { }
37
38    // opens process token for given access
39    private static long openProcessToken(int access) {
40        try {
41            return OpenProcessToken(GetCurrentProcess(), access);
42        } catch (WindowsException x) {
43            return 0L;
44        }
45    }
46
47    /**
48     * Returns the access token for this process with TOKEN_DUPLICATE access
49     */
50    static final long processTokenWithDuplicateAccess =
51        openProcessToken(TOKEN_DUPLICATE);
52
53    /**
54     * Returns the access token for this process with TOKEN_QUERY access
55     */
56    static final long processTokenWithQueryAccess =
57        openProcessToken(TOKEN_QUERY);
58
59    /**
60     * Returned by enablePrivilege when code may require a given privilege.
61     * The drop method should be invoked after the operation completes so as
62     * to revert the privilege.
63     */
64    static interface Privilege {
65        void drop();
66    }
67
68    /**
69     * Attempts to enable the given privilege for this method.
70     */
71    static Privilege enablePrivilege(String priv) {
72        final long pLuid;
73        try {
74            pLuid = LookupPrivilegeValue(priv);
75        } catch (WindowsException x) {
76            // indicates bug in caller
77            throw new AssertionError(x);
78        }
79
80        long hToken = 0L;
81        boolean impersontating = false;
82        boolean elevated = false;
83        try {
84            hToken = OpenThreadToken(GetCurrentThread(),
85                                     TOKEN_ADJUST_PRIVILEGES, false);
86            if (hToken == 0L && processTokenWithDuplicateAccess != 0L) {
87                hToken = DuplicateTokenEx(processTokenWithDuplicateAccess,
88                    (TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE));
89                SetThreadToken(0L, hToken);
90                impersontating = true;
91            }
92
93            if (hToken != 0L) {
94                AdjustTokenPrivileges(hToken, pLuid, SE_PRIVILEGE_ENABLED);
95                elevated = true;
96            }
97        } catch (WindowsException x) {
98            // nothing to do, privilege not enabled
99        }
100
101        final long token = hToken;
102        final boolean stopImpersontating = impersontating;
103        final boolean needToRevert = elevated;
104
105        return new Privilege() {
106            @Override
107            public void drop() {
108                if (token != 0L) {
109                    try {
110                        if (stopImpersontating)
111                            SetThreadToken(0L, 0L);
112                        else if (needToRevert)
113                            AdjustTokenPrivileges(token, pLuid, 0);
114                    } catch (WindowsException x) {
115                        // should not happen
116                        throw new AssertionError(x);
117                    } finally {
118                        CloseHandle(token);
119                    }
120                }
121            }
122        };
123    }
124
125    /**
126     * Check the access right against the securityInfo in the current thread.
127     */
128    static boolean checkAccessMask(long securityInfo, int accessMask,
129        int genericRead, int genericWrite, int genericExecute, int genericAll)
130        throws WindowsException
131    {
132        int privileges = TOKEN_QUERY;
133        long hToken = OpenThreadToken(GetCurrentThread(), privileges, false);
134        if (hToken == 0L && processTokenWithDuplicateAccess != 0L)
135            hToken = DuplicateTokenEx(processTokenWithDuplicateAccess,
136                privileges);
137
138        boolean hasRight = false;
139        if (hToken != 0L) {
140            try {
141                hasRight = AccessCheck(hToken, securityInfo, accessMask,
142                    genericRead, genericWrite, genericExecute, genericAll);
143            } finally {
144                CloseHandle(hToken);
145            }
146        }
147        return hasRight;
148    }
149
150}
151