1 package org.metricshub.winrm.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.hierynomus.security.bc.BCSecurityProvider;
24 import com.hierynomus.smbj.SMBClient;
25 import com.hierynomus.smbj.SmbConfig;
26 import com.hierynomus.smbj.auth.AuthenticationContext;
27 import com.hierynomus.smbj.connection.Connection;
28 import com.hierynomus.smbj.session.Session;
29 import com.hierynomus.smbj.share.DiskShare;
30 import java.io.IOException;
31 import java.nio.file.Path;
32 import java.util.List;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.TimeoutException;
36 import java.util.concurrent.atomic.AtomicInteger;
37 import org.metricshub.winrm.Utils;
38 import org.metricshub.winrm.WindowsRemoteExecutor;
39 import org.metricshub.winrm.WindowsTempShare;
40 import org.metricshub.winrm.exceptions.WinRMException;
41 import org.metricshub.winrm.exceptions.WindowsRemoteException;
42 import org.metricshub.winrm.service.WinRMEndpoint;
43 import org.metricshub.winrm.service.WinRMService;
44 import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
45
46 public class SmbTempShare extends WindowsTempShare implements AutoCloseable {
47
48 private final WinRMEndpoint winRMEndpoint;
49 private final SMBClient smbClient;
50 private final Connection connection;
51 private final Session session;
52 private final DiskShare diskShare;
53
54
55
56
57
58
59
60
61
62
63
64
65
66 private SmbTempShare(
67 final WinRMService winRMService,
68 final WinRMEndpoint winRMEndpoint,
69 final SMBClient smbClient,
70 final Connection connection,
71 final Session session,
72 final DiskShare diskShare,
73 final String shareNameOrUnc,
74 final String remotePath
75 ) {
76 super(winRMService, shareNameOrUnc, remotePath);
77 this.winRMEndpoint = winRMEndpoint;
78 this.smbClient = smbClient;
79 this.connection = connection;
80 this.session = session;
81 this.diskShare = diskShare;
82 }
83
84 private static final ConcurrentHashMap<WinRMEndpoint, SmbTempShare> CONNECTIONS_CACHE = new ConcurrentHashMap<>();
85
86 private final AtomicInteger useCount = new AtomicInteger(1);
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public static SmbTempShare createInstance(
104 final WinRMEndpoint winRMEndpoint,
105 final long timeout,
106 final Path ticketCache,
107 final List<AuthenticationEnum> authentications
108 ) throws IOException, WinRMException, TimeoutException {
109 Utils.checkNonNull(winRMEndpoint, "winRMEndpoint");
110 Utils.checkNonNull(winRMEndpoint.getPassword(), "password");
111 Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
112
113 try {
114 return CONNECTIONS_CACHE.compute(
115 winRMEndpoint,
116 (key, smb) -> {
117 if (smb == null) {
118 WinRMService winRMService = null;
119 SMBClient smbClient = null;
120 Connection connection = null;
121 Session session = null;
122 DiskShare diskShare = null;
123
124 try {
125 winRMService = WinRMService.createInstance(winRMEndpoint, timeout, ticketCache, authentications);
126
127 final WindowsTempShare windowsTempShare = getOrCreateShare(
128 winRMService,
129 timeout,
130 (w, r, s, t) -> {
131 try {
132 shareRemoteDirectory(w, r, s, t);
133 } catch (final TimeoutException | WindowsRemoteException e) {
134 throw new RuntimeException(e);
135 }
136 }
137 );
138
139 final SmbConfig smbConfig = SmbConfig
140 .builder()
141 .withSecurityProvider(new BCSecurityProvider())
142 .withTimeout(timeout, TimeUnit.SECONDS)
143 .build();
144
145 final AuthenticationContext authenticationContext = new AuthenticationContext(
146 winRMEndpoint.getUsername(),
147 winRMEndpoint.getPassword(),
148 winRMEndpoint.getDomain()
149 );
150
151 smbClient = createSmbClient(smbConfig);
152 connection = smbClient.connect(winRMEndpoint.getHostname());
153 session = connection.authenticate(authenticationContext);
154 diskShare = (DiskShare) session.connectShare(windowsTempShare.getShareName());
155
156 return new SmbTempShare(
157 winRMService,
158 winRMEndpoint,
159 smbClient,
160 connection,
161 session,
162 diskShare,
163 windowsTempShare.getUncSharePath(),
164 windowsTempShare.getRemotePath()
165 );
166 } catch (final RuntimeException e) {
167 closeResources(winRMService, smbClient, connection, session, diskShare);
168
169 throw e;
170 } catch (final Exception e) {
171 closeResources(winRMService, smbClient, connection, session, diskShare);
172
173 throw new RuntimeException(e);
174 }
175 } else {
176 synchronized (smb) {
177 smb.incrementUseCount();
178
179 return smb;
180 }
181 }
182 }
183 );
184 } catch (final RuntimeException e) {
185 final Throwable cause = e.getCause();
186
187 if (cause instanceof IOException) {
188 throw (IOException) cause;
189 }
190
191 if (cause instanceof TimeoutException) {
192 throw (TimeoutException) cause;
193 }
194
195 if (cause instanceof WindowsRemoteException) {
196 throw (WinRMException) cause;
197 }
198
199 throw e;
200 }
201 }
202
203 private static void closeResources(
204 final WinRMService winRMService,
205 final SMBClient smbClient,
206 final Connection connection,
207 final Session session,
208 final DiskShare diskShare
209 ) {
210 try {
211 if (diskShare != null) {
212 diskShare.close();
213 }
214
215 if (session != null) {
216 session.close();
217 }
218
219 if (connection != null) {
220 connection.close();
221 }
222 } catch (final IOException ioe) {
223 throw new RuntimeException(ioe);
224 }
225
226 if (smbClient != null) {
227 smbClient.close();
228 }
229
230 if (winRMService != null) {
231 winRMService.close();
232 }
233 }
234
235 int getUseCount() {
236 return useCount.get();
237 }
238
239 void incrementUseCount() {
240 useCount.incrementAndGet();
241 }
242
243
244
245
246 boolean isConnected() {
247 return getUseCount() > 0;
248 }
249
250
251
252
253 public void checkConnectedFirst() {
254 if (!isConnected()) {
255 throw new IllegalStateException("This instance has been closed and a new one must be created.");
256 }
257 }
258
259 @Override
260 public synchronized void close() throws IOException {
261 if (useCount.decrementAndGet() == 0) {
262 CONNECTIONS_CACHE.remove(winRMEndpoint);
263
264 if (diskShare != null) {
265 diskShare.close();
266 }
267
268 if (session != null) {
269 session.close();
270 }
271
272 if (connection != null) {
273 connection.close();
274 }
275
276 if (smbClient != null) {
277 smbClient.close();
278 }
279
280 ((WinRMService) getWindowsRemoteExecutor()).close();
281 }
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295
296 private static void shareRemoteDirectory(
297 final WindowsRemoteExecutor windowsRemoteExecutor,
298 final String remotePath,
299 final String shareName,
300 final long timeout
301 ) throws TimeoutException, WindowsRemoteException {
302 final String command = String.format(
303 "net share %s=%s /grant:%s,Full",
304 shareName,
305 remotePath,
306 windowsRemoteExecutor.getUsername()
307 );
308
309 windowsRemoteExecutor.executeCommand(command, null, null, timeout);
310 }
311
312 static SMBClient createSmbClient(final SmbConfig smbConfig) {
313 return new SMBClient(smbConfig);
314 }
315 }