/** * [DFS Root referral request] Issue a DFS root referral request, as specified in section 3.1.4.2, * providing "ROOT", the first path component, UserCredentials, MaxOutputSize, and Path as parameters. * The processing of the referral response and/or error is as specified in section 3.1.5.4.3, which will update the ReferralCache * on success. On DFS root referral request success, go to step 7. * On DFS root referral request failure: * 1. If the immediately preceding processing step was step 5.2.3, this is a domain name or path. Go to step 13. * 2. If processing of this I/O request encountered a ReferralCache hit, or one of its DFS referral requests succeeded * (as would have occurred in the case of a previous Interlink - see step 11 - or a domain root referral, * when entering from step 5), the path is in a DFS namespace. Go to step 14. * 3. The path is not a DFS path and no further processing is required. Go to step 12. */ private DFSPath step6(Session session, ResolveState state) throws DFSException { logger.trace("DFS[6]: {}", state); ReferralResult result = sendDfsReferralRequest(DfsRequestType.ROOT, state.path.getPathComponents().get(0), session, state.path); if (NtStatus.isSuccess(result.status)) { return step7(session, state, result.referralCacheEntry); } if (state.resolvedDomainEntry) { // Came from 5.2.3 return step13(session, state, result); } if (state.isDFSPath) { return step14(session, state, result); } return step12(state); }
private String resolve(Session session, String uncPath) throws PathResolveException { logger.info("Starting DFS resolution for {}", uncPath); DFSPath dfsPath = new DFSPath(uncPath); ResolveState state = new ResolveState(dfsPath); DFSPath resolved = step1(session, state); return resolved.toPath(); }
/** * Step 4: [ReferralCache hit, unexpired TTL, RootOrLink=link] * 1. If the second component of the path is "SYSVOL" or "NETLOGON" go to step 3. * 2. Check the Interlink element of the ReferralCache entry. * - If Interlink is set in the ReferralCache entry,then the TargetHint is in another DFS namespace. Go to step 11. * - If Interlink is not set in the ReferralCache entry then the TargetHint is not in another DFS namespace. Go to step 3. */ private DFSPath step4(Session session, ResolveState state, ReferralCache.ReferralCacheEntry lookup) throws DFSException { logger.trace("DFS[4]: {}", state); if (state.path.isSysVolOrNetLogon()) { return step3(session, state, lookup); } if (lookup.isInterlink()) { return step11(session, state, lookup); } return step3(session, state, lookup); }
/** * Step 10: [sysvol referral request] Issue a sysvol referral request, as specified in * section 3.1.4.2, providing 'SYSVOL', the DCHint DC of the DomainCache entry that * corresponds to the domain name in the first path component, UserCredentials, MaxOutputSize, * and Path as parameters. The processing of the referral response and/or error is as * specified in section 3.1.5.4.4, which will update the ReferralCache on success. * If the referral request is successful, go to step 3; otherwise, go to step 13. */ private DFSPath step10(Session session, ResolveState state, DomainCache.DomainCacheEntry domainCacheEntry) throws DFSException { logger.trace("DFS[10]: {}", state); ReferralResult r = sendDfsReferralRequest(DfsRequestType.SYSVOL, domainCacheEntry.getDCHint(), session, state.path); if (NtStatus.isSuccess(r.status)) { return step3(session, state, r.referralCacheEntry); } return step13(session, state, r); }
/** * Step 9: [ReferralCache hit, expired TTL, RootOrLink=link] The link referral request is issued to a DFS root target of the namespace. * Find the root ReferralCache entry corresponding to the first two path components, noting that this will already be in the cache due * to processing that resulted in acquiring the expired link ReferralCache entry. Issue a DFS link referral request, * as specified in section 3.1.4.2, providing "LINK", TargetHint of the root ReferralCache entry, UserCredentials, MaxOutputSize, and Path * as parameters, and process the DFS referral response and/or error as specified in section 3.1.5.4.3, which will update the ReferralCache * on success. * <p> * If the DFS Link referral request fails, set the failure status to the last error that occurred and go to step 14. Otherwise: * 1. If the RootOrLink of the refreshed ReferralCache entry indicates DFS root targets, go to step 3. * 2. If the RootOrLink of the refreshed ReferralCache entry indicates DFS link targets, go to step 4. */ @SuppressWarnings("PMD.UnusedFormalParameter") private DFSPath step9(Session session, ResolveState state, ReferralCache.ReferralCacheEntry lookup) throws DFSException { logger.trace("DFS[9]: {}", state); DFSPath rootPath = new DFSPath(state.path.getPathComponents().subList(0, 2)); ReferralCache.ReferralCacheEntry rootReferralCacheEntry = referralCache.lookup(rootPath); if (rootReferralCacheEntry == null) { throw new IllegalStateException("Could not find referral cache entry for " + rootPath); } ReferralResult result = sendDfsReferralRequest(DfsRequestType.LINK, rootReferralCacheEntry.getTargetHint().getTargetPath(), session, state.path); if (!NtStatus.isSuccess(result.status)) { return step14(session, state, result); } if (result.referralCacheEntry.isRoot()) { return step3(session, state, result.referralCacheEntry); } return step4(session, state, result.referralCacheEntry); }
state.hostName = potentialDomain; state.resolvedDomainEntry = false; return step6(session, state); ReferralResult result = sendDfsReferralRequest(DfsRequestType.DC, bootstrapDC, session, state.path); // TODO if (!NtStatus.isSuccess(result.status)) { return step13(session, state, result); return step10(session, state, domainCacheEntry); return step6(session, state);
private ReferralResult handleReferralResponse(DfsRequestType type, SMB2IoctlResponse response, DFSPath originalPath) throws Buffer.BufferException { ReferralResult result = new ReferralResult(response.getHeader().getStatusCode()); if (result.status == NtStatus.STATUS_SUCCESS.getValue()) { SMB2GetDFSReferralResponse resp = new SMB2GetDFSReferralResponse(originalPath.toPath()); resp.read(new SMBBuffer(response.getOutputBuffer())); switch (type) { case DC: handleDCReferralResponse(result, resp); break; case DOMAIN: throw new UnsupportedOperationException(DfsRequestType.DOMAIN + " not used yet."); case SYSVOL: case ROOT: case LINK: handleRootOrLinkReferralResponse(result, resp); break; default: throw new IllegalStateException("Encountered unhandled DFS RequestType: " + type); } } return result; }
@Override public SmbPath resolve(Session session, SmbPath smbPath) throws PathResolveException { SmbPath target = SmbPath.parse(resolve(session, smbPath.toUncPath())); if (!smbPath.equals(target)) { logger.info("DFS resolved {} -> {}", smbPath, target); return target; } return wrapped.resolve(session, smbPath); }
public SMBClient(SmbConfig config, SMBEventBus bus) { this.config = config; this.bus = bus; bus.subscribe(this); this.pathResolver = new SymlinkPathResolver(PathResolver.LOCAL); if (config.isDfsEnabled()) { this.pathResolver = new DFSPathResolver(this.pathResolver); } }
private ReferralResult getReferral(DfsRequestType type, Share share, DFSPath path) throws TransportException, Buffer.BufferException { SMB2GetDFSReferralRequest req = new SMB2GetDFSReferralRequest(path.toPath()); SMBBuffer buffer = new SMBBuffer(); req.writeTo(buffer); Future<SMB2IoctlResponse> ioctl = share.ioctlAsync(FSCTL_DFS_GET_REFERRALS, true, new BufferByteChunkProvider(buffer)); SMB2IoctlResponse response = Futures.get(ioctl, TransportException.Wrapper); return handleReferralResponse(type, response, path); }
private ReferralResult sendDfsReferralRequest(DfsRequestType type, String hostName, Session session, DFSPath path) throws DFSException { // The client MUST initiate a server session with the SMB server, as specified in [MS-CIFS] section 3.4.4.7, // by passing HostName and UserCredentials as input parameters and receiving an opaque ClientGenericContext, // as specified in [MS-CIFS] section 3.4. // The client MUST search for an existing Session and TreeConnect to any share on the server identified by // ServerName for the user identified by UserCredentials. If no Session and TreeConnect are found, the client // MUST establish a new Session and TreeConnect to IPC$ on the target server as described in section 3.2.4.2 // using the supplied ServerName and UserCredentials Session dfsSession = session; if (!hostName.equals(session.getConnection().getRemoteHostname())) { AuthenticationContext auth = session.getAuthenticationContext(); Connection oldConnection = session.getConnection(); Connection connection; try { connection = oldConnection.getClient().connect(hostName); // TODO } catch (IOException e) { throw new DFSException(e); } dfsSession = connection.authenticate(auth); } try (Share dfsShare = dfsSession.connectShare("IPC$")) { return getReferral(type, dfsShare, path); } catch (Buffer.BufferException | IOException e) { throw new DFSException(e); } }
/** * Step 9: [ReferralCache hit, expired TTL, RootOrLink=link] The link referral request is issued to a DFS root target of the namespace. * Find the root ReferralCache entry corresponding to the first two path components, noting that this will already be in the cache due * to processing that resulted in acquiring the expired link ReferralCache entry. Issue a DFS link referral request, * as specified in section 3.1.4.2, providing "LINK", TargetHint of the root ReferralCache entry, UserCredentials, MaxOutputSize, and Path * as parameters, and process the DFS referral response and/or error as specified in section 3.1.5.4.3, which will update the ReferralCache * on success. * <p> * If the DFS Link referral request fails, set the failure status to the last error that occurred and go to step 14. Otherwise: * 1. If the RootOrLink of the refreshed ReferralCache entry indicates DFS root targets, go to step 3. * 2. If the RootOrLink of the refreshed ReferralCache entry indicates DFS link targets, go to step 4. */ @SuppressWarnings("PMD.UnusedFormalParameter") private DFSPath step9(Session session, ResolveState state, ReferralCache.ReferralCacheEntry lookup) throws DFSException { logger.trace("DFS[9]: {}", state); DFSPath rootPath = new DFSPath(state.path.getPathComponents().subList(0, 2)); ReferralCache.ReferralCacheEntry rootReferralCacheEntry = referralCache.lookup(rootPath); if (rootReferralCacheEntry == null) { throw new IllegalStateException("Could not find referral cache entry for " + rootPath); } ReferralResult result = sendDfsReferralRequest(DfsRequestType.LINK, rootReferralCacheEntry.getTargetHint().getTargetPath(), session, state.path); if (!NtStatus.isSuccess(result.status)) { return step14(session, state, result); } if (result.referralCacheEntry.isRoot()) { return step3(session, state, result.referralCacheEntry); } return step4(session, state, result.referralCacheEntry); }
state.hostName = potentialDomain; state.resolvedDomainEntry = false; return step6(session, state); ReferralResult result = sendDfsReferralRequest(DfsRequestType.DC, bootstrapDC, session, state.path); // TODO if (!NtStatus.isSuccess(result.status)) { return step13(session, state, result); return step10(session, state, domainCacheEntry); return step6(session, state);
/** * Step 10: [sysvol referral request] Issue a sysvol referral request, as specified in * section 3.1.4.2, providing 'SYSVOL', the DCHint DC of the DomainCache entry that * corresponds to the domain name in the first path component, UserCredentials, MaxOutputSize, * and Path as parameters. The processing of the referral response and/or error is as * specified in section 3.1.5.4.4, which will update the ReferralCache on success. * If the referral request is successful, go to step 3; otherwise, go to step 13. */ private DFSPath step10(Session session, ResolveState state, DomainCache.DomainCacheEntry domainCacheEntry) throws DFSException { logger.trace("DFS[10]: {}", state); ReferralResult r = sendDfsReferralRequest(DfsRequestType.SYSVOL, domainCacheEntry.getDCHint(), session, state.path); if (NtStatus.isSuccess(r.status)) { return step3(session, state, r.referralCacheEntry); } return step13(session, state, r); }
private ReferralResult handleReferralResponse(DfsRequestType type, SMB2IoctlResponse response, DFSPath originalPath) throws Buffer.BufferException { ReferralResult result = new ReferralResult(response.getHeader().getStatusCode()); if (result.status == NtStatus.STATUS_SUCCESS.getValue()) { SMB2GetDFSReferralResponse resp = new SMB2GetDFSReferralResponse(originalPath.toPath()); resp.read(new SMBBuffer(response.getOutputBuffer())); switch (type) { case DC: handleDCReferralResponse(result, resp); break; case DOMAIN: throw new UnsupportedOperationException(DfsRequestType.DOMAIN + " not used yet."); case SYSVOL: case ROOT: case LINK: handleRootOrLinkReferralResponse(result, resp); break; default: throw new IllegalStateException("Encountered unhandled DFS RequestType: " + type); } } return result; }
@Override public SmbPath resolve(Session session, SmbPath smbPath) throws PathResolveException { SmbPath target = SmbPath.parse(resolve(session, smbPath.toUncPath())); if (!smbPath.equals(target)) { logger.info("DFS resolved {} -> {}", smbPath, target); return target; } return wrapped.resolve(session, smbPath); }
public SMBClient(SmbConfig config, SMBEventBus bus) { this.config = config; this.bus = bus; bus.subscribe(this); this.pathResolver = new SymlinkPathResolver(PathResolver.LOCAL); if (config.isDfsEnabled()) { this.pathResolver = new DFSPathResolver(this.pathResolver); } }
private ReferralResult getReferral(DfsRequestType type, Share share, DFSPath path) throws TransportException, Buffer.BufferException { SMB2GetDFSReferralRequest req = new SMB2GetDFSReferralRequest(path.toPath()); SMBBuffer buffer = new SMBBuffer(); req.writeTo(buffer); Future<SMB2IoctlResponse> ioctl = share.ioctlAsync(FSCTL_DFS_GET_REFERRALS, true, new BufferByteChunkProvider(buffer)); SMB2IoctlResponse response = Futures.get(ioctl, TransportException.Wrapper); return handleReferralResponse(type, response, path); }
private ReferralResult sendDfsReferralRequest(DfsRequestType type, String hostName, Session session, DFSPath path) throws DFSException { // The client MUST initiate a server session with the SMB server, as specified in [MS-CIFS] section 3.4.4.7, // by passing HostName and UserCredentials as input parameters and receiving an opaque ClientGenericContext, // as specified in [MS-CIFS] section 3.4. // The client MUST search for an existing Session and TreeConnect to any share on the server identified by // ServerName for the user identified by UserCredentials. If no Session and TreeConnect are found, the client // MUST establish a new Session and TreeConnect to IPC$ on the target server as described in section 3.2.4.2 // using the supplied ServerName and UserCredentials Session dfsSession = session; if (!hostName.equals(session.getConnection().getRemoteHostname())) { AuthenticationContext auth = session.getAuthenticationContext(); Connection oldConnection = session.getConnection(); Connection connection; try { connection = oldConnection.getClient().connect(hostName); // TODO } catch (IOException e) { throw new DFSException(e); } dfsSession = connection.authenticate(auth); } try (Share dfsShare = dfsSession.connectShare("IPC$")) { return getReferral(type, dfsShare, path); } catch (Buffer.BufferException | IOException e) { throw new DFSException(e); } }
/** * [DFS Root referral request] Issue a DFS root referral request, as specified in section 3.1.4.2, * providing "ROOT", the first path component, UserCredentials, MaxOutputSize, and Path as parameters. * The processing of the referral response and/or error is as specified in section 3.1.5.4.3, which will update the ReferralCache * on success. On DFS root referral request success, go to step 7. * On DFS root referral request failure: * 1. If the immediately preceding processing step was step 5.2.3, this is a domain name or path. Go to step 13. * 2. If processing of this I/O request encountered a ReferralCache hit, or one of its DFS referral requests succeeded * (as would have occurred in the case of a previous Interlink - see step 11 - or a domain root referral, * when entering from step 5), the path is in a DFS namespace. Go to step 14. * 3. The path is not a DFS path and no further processing is required. Go to step 12. */ private DFSPath step6(Session session, ResolveState state) throws DFSException { logger.trace("DFS[6]: {}", state); ReferralResult result = sendDfsReferralRequest(DfsRequestType.ROOT, state.path.getPathComponents().get(0), session, state.path); if (NtStatus.isSuccess(result.status)) { return step7(session, state, result.referralCacheEntry); } if (state.resolvedDomainEntry) { // Came from 5.2.3 return step13(session, state, result); } if (state.isDFSPath) { return step14(session, state, result); } return step12(state); }