1 package org.metricshub.wmi.shares;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import com.sun.jna.Native;
24 import com.sun.jna.platform.win32.Advapi32;
25 import com.sun.jna.platform.win32.Advapi32Util;
26 import com.sun.jna.platform.win32.COM.WbemcliUtil;
27 import com.sun.jna.platform.win32.COM.util.Factory;
28 import com.sun.jna.platform.win32.Kernel32;
29 import com.sun.jna.platform.win32.LMAccess;
30 import com.sun.jna.platform.win32.LMShare;
31 import com.sun.jna.platform.win32.LMShare.SHARE_INFO_502;
32 import com.sun.jna.platform.win32.Netapi32;
33 import com.sun.jna.platform.win32.Win32Exception;
34 import com.sun.jna.platform.win32.WinDef.DWORD;
35 import com.sun.jna.platform.win32.WinNT;
36 import com.sun.jna.platform.win32.WinNT.ACCESS_ALLOWED_ACE;
37 import com.sun.jna.platform.win32.WinNT.ACL;
38 import com.sun.jna.platform.win32.WinNT.PSID;
39 import com.sun.jna.platform.win32.WinNT.SECURITY_DESCRIPTOR;
40 import com.sun.jna.platform.win32.WinNT.WELL_KNOWN_SID_TYPE;
41 import com.sun.jna.ptr.IntByReference;
42 import java.util.concurrent.ConcurrentHashMap;
43 import java.util.concurrent.TimeoutException;
44 import java.util.concurrent.atomic.AtomicInteger;
45 import org.metricshub.wmi.Utils;
46 import org.metricshub.wmi.WmiHelper;
47 import org.metricshub.wmi.exceptions.WindowsRemoteException;
48 import org.metricshub.wmi.exceptions.WmiComException;
49 import org.metricshub.wmi.wbem.WmiWbemServices;
50 import org.metricshub.wmi.windows.remote.WindowsRemoteExecutor;
51 import org.metricshub.wmi.windows.remote.share.WindowsTempShare;
52
53
54
55
56
57 public class WinTempShare extends WindowsTempShare implements AutoCloseable {
58
59 private static final int CONNECTION_MAX = 10;
60 private static final String SHARE_DESCRIPTION = "Share created by Metricshub to store results of commands";
61 private static final int SUCCESS = 0;
62 private static final int ALREADY_EXIST = 2118;
63
64 private static final Factory FACTORY = new Factory();
65 private static final WindowsScriptHostNetworkInterface WSH = FACTORY.createObject(
66 WindowsScriptHostNetworkInterface.class
67 );
68
69 private static final ConcurrentHashMap<String, WinTempShare> CONNECTIONS_CACHE = new ConcurrentHashMap<>();
70
71
72 private final String hostname;
73
74
75 private final AtomicInteger useCount = new AtomicInteger(1);
76
77
78
79
80
81
82
83
84
85
86 WinTempShare(final WmiWbemServices wmiWbemServices, final String shareNameOrUnc, final String remotePath) {
87 super(wmiWbemServices, shareNameOrUnc, remotePath);
88 this.hostname = wmiWbemServices.getHostname();
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public static WinTempShare getInstance(
105 final String hostname,
106 final String username,
107 final char[] password,
108 final long timeout
109 ) throws TimeoutException, WmiComException {
110 Utils.checkNonNull(hostname, "hostname");
111 Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
112
113 try {
114 return CONNECTIONS_CACHE.compute(
115 hostname.toLowerCase(),
116 (h, winTempShare) -> {
117 if (winTempShare == null) {
118 WmiWbemServices wmiWbemServices = null;
119
120 try {
121
122 final String networkResource = WmiHelper.createNetworkResource(hostname, WbemcliUtil.DEFAULT_NAMESPACE);
123 wmiWbemServices = WmiWbemServices.getInstance(networkResource, username, password);
124
125
126 final WindowsTempShare share = getOrCreateShare(
127 wmiWbemServices,
128 timeout,
129 (w, r, s, t) -> {
130 try {
131 shareRemoteDirectory(w, r, s, t);
132 } catch (final WindowsRemoteException e) {
133
134 throw new RuntimeException(e);
135 }
136 }
137 );
138
139
140 getWindowsScriptHostNetwork()
141 .mapNetworkDrive(
142 Utils.EMPTY,
143 share.getUncSharePath(),
144 false,
145 username,
146 password == null ? null : String.valueOf(password)
147 );
148
149 return new WinTempShare(
150 (WmiWbemServices) share.getWindowsRemoteExecutor(),
151 share.getUncSharePath(),
152 share.getRemotePath()
153 );
154 } catch (final RuntimeException e) {
155 if (wmiWbemServices != null) {
156 wmiWbemServices.close();
157 }
158
159 throw e;
160 } catch (final Exception e) {
161 if (wmiWbemServices != null) {
162 wmiWbemServices.close();
163 }
164
165
166 throw new RuntimeException(e);
167 }
168 } else {
169
170 synchronized (winTempShare) {
171
172 winTempShare.incrementUseCount();
173
174
175 return winTempShare;
176 }
177 }
178 }
179 );
180 } catch (final RuntimeException e) {
181 final Throwable cause = e.getCause();
182 if (cause != null) {
183 if (cause instanceof TimeoutException) {
184 throw (TimeoutException) cause;
185 } else if (cause instanceof WmiComException) {
186 throw (WmiComException) cause;
187 } else if (cause instanceof InterruptedException) {
188 throw new TimeoutException(cause.getClass().getSimpleName() + ": " + cause.getMessage());
189 }
190 }
191
192 throw e;
193 }
194 }
195
196 @Override
197 public synchronized void close() {
198 if (useCount.decrementAndGet() == 0) {
199 CONNECTIONS_CACHE.remove(hostname.toLowerCase());
200
201 ((WmiWbemServices) getWindowsRemoteExecutor()).close();
202
203
204 getWindowsScriptHostNetwork().removeNetworkDrive(getUncSharePath(), true, false);
205 }
206 }
207
208
209
210
211 public boolean isConnected() {
212 return useCount.get() > 0;
213 }
214
215
216
217
218 public void checkConnectedFirst() {
219 if (!isConnected()) {
220 throw new IllegalStateException("This instance has been closed and a new one must be created.");
221 }
222 }
223
224
225
226
227
228
229
230
231
232
233
234 private static void shareRemoteDirectory(
235 final WindowsRemoteExecutor wmiWbemServices,
236 final String remotePath,
237 final String shareName,
238 final long timeout
239 ) throws WmiComException {
240 final SECURITY_DESCRIPTOR securityDescriptor = initializeSecurityDescriptor();
241
242 final SHARE_INFO_502 shareInfo502 = new SHARE_INFO_502();
243 shareInfo502.shi502_netname = shareName;
244 shareInfo502.shi502_type = LMShare.STYPE_DISKTREE;
245 shareInfo502.shi502_remark = SHARE_DESCRIPTION;
246 shareInfo502.shi502_permissions = LMAccess.ACCESS_ALL;
247 shareInfo502.shi502_max_uses = CONNECTION_MAX;
248 shareInfo502.shi502_current_uses = 0;
249 shareInfo502.shi502_path = remotePath;
250 shareInfo502.shi502_passwd = null;
251 shareInfo502.shi502_reserved = 0;
252 shareInfo502.shi502_security_descriptor = securityDescriptor.getPointer();
253
254
255 shareInfo502.write();
256
257 final IntByReference parmErr = new IntByReference(0);
258 final int result = Netapi32.INSTANCE.NetShareAdd(
259 wmiWbemServices.getHostname(),
260 502,
261 shareInfo502.getPointer(),
262 parmErr
263 );
264 if (result != SUCCESS && result != ALREADY_EXIST) {
265 final Exception e = new Win32Exception(result);
266 throw new WmiComException(e, e.getMessage());
267 }
268 }
269
270
271
272
273
274
275
276
277
278
279 private static SECURITY_DESCRIPTOR initializeSecurityDescriptor() throws WmiComException {
280 final PSID pSidSystem = createSID(WELL_KNOWN_SID_TYPE.WinLocalSystemSid);
281
282 final PSID pSidAdministrator = createSID(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid);
283
284 final int sidSysLength = Advapi32.INSTANCE.GetLengthSid(pSidSystem);
285 final int sidAdminLength = Advapi32.INSTANCE.GetLengthSid(pSidAdministrator);
286 int cbAcl = Native.getNativeSize(ACL.class, null);
287 cbAcl += Native.getNativeSize(ACCESS_ALLOWED_ACE.class, null);
288 cbAcl += (sidSysLength - DWORD.SIZE);
289 cbAcl += Native.getNativeSize(ACCESS_ALLOWED_ACE.class, null);
290 cbAcl += (sidAdminLength - DWORD.SIZE);
291 cbAcl = Advapi32Util.alignOnDWORD(cbAcl);
292 final ACL pAcl = new ACL(cbAcl);
293
294 checkWin32Result(Advapi32.INSTANCE.InitializeAcl(pAcl, cbAcl, WinNT.ACL_REVISION));
295
296 checkWin32Result(Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_ALL, pSidSystem));
297
298 checkWin32Result(
299 Advapi32.INSTANCE.AddAccessAllowedAce(pAcl, WinNT.ACL_REVISION, WinNT.GENERIC_ALL, pSidAdministrator)
300 );
301
302 final SECURITY_DESCRIPTOR securityDescriptor = new SECURITY_DESCRIPTOR(64 * 1024);
303
304 checkWin32Result(
305 Advapi32.INSTANCE.InitializeSecurityDescriptor(securityDescriptor, WinNT.SECURITY_DESCRIPTOR_REVISION)
306 );
307
308 checkWin32Result(Advapi32.INSTANCE.SetSecurityDescriptorDacl(securityDescriptor, true, pAcl, false));
309
310 return securityDescriptor;
311 }
312
313
314
315
316
317
318
319
320 private static PSID createSID(final int wellKnownSidTypeAlias) throws WmiComException {
321 final PSID pSid = new PSID(WinNT.SECURITY_MAX_SID_SIZE);
322 final IntByReference cbSid = new IntByReference(WinNT.SECURITY_MAX_SID_SIZE);
323
324 checkWin32Result(Advapi32.INSTANCE.CreateWellKnownSid(wellKnownSidTypeAlias, null, pSid, cbSid));
325 return pSid;
326 }
327
328
329
330
331
332
333
334
335 private static void checkWin32Result(final boolean result) throws WmiComException {
336 if (!result) {
337 final Exception e = new Win32Exception(Kernel32.INSTANCE.GetLastError());
338 throw new WmiComException(e, e.getMessage());
339 }
340 }
341
342 int getUseCount() {
343 return useCount.get();
344 }
345
346 void incrementUseCount() {
347 useCount.incrementAndGet();
348 }
349
350 static WindowsScriptHostNetworkInterface getWindowsScriptHostNetwork() {
351 return WSH;
352 }
353 }