diff options
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs')
| -rw-r--r-- | Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs | 977 |
1 files changed, 977 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs new file mode 100644 index 000000000..800d6d9bc --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SmbTransport.cs @@ -0,0 +1,977 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using SharpCifs.Netbios; +using SharpCifs.Util; +using SharpCifs.Util.Sharpen; +using SharpCifs.Util.Transport; + +namespace SharpCifs.Smb +{ + public class SmbTransport : Transport + { + internal static readonly byte[] Buf = new byte[0xFFFF]; + + internal static readonly SmbComNegotiate NegotiateRequest = new SmbComNegotiate( + ); + + internal static LogStream LogStatic = LogStream.GetInstance(); + + internal static Hashtable DfsRoots = null; + + + internal static SmbTransport GetSmbTransport(UniAddress address, int port + ) + { + lock (typeof(SmbTransport)) + { + return GetSmbTransport(address, port, SmbConstants.Laddr, SmbConstants.Lport, null); + } + } + + internal static SmbTransport GetSmbTransport(UniAddress address, int port + , IPAddress localAddr, int localPort, string hostName) + { + lock (typeof(SmbTransport)) + { + SmbTransport conn; + + lock (SmbConstants.Connections) + { + if (SmbConstants.SsnLimit != 1) + { + conn = + SmbConstants.Connections.FirstOrDefault( + c => + c.Matches(address, port, localAddr, localPort, hostName) && + (SmbConstants.SsnLimit == + 0 || c.Sessions.Count < SmbConstants.SsnLimit)); + + if (conn != null) + { + return conn; + } + + } + + conn = new SmbTransport(address, port, localAddr, localPort); + SmbConstants.Connections.Insert(0, conn); + } + return conn; + } + } + + internal class ServerData + { + internal byte Flags; + + internal int Flags2; + + internal int MaxMpxCount; + + internal int MaxBufferSize; + + internal int SessionKey; + + internal int Capabilities; + + internal string OemDomainName; + + internal int SecurityMode; + + internal int Security; + + internal bool EncryptedPasswords; + + internal bool SignaturesEnabled; + + internal bool SignaturesRequired; + + internal int MaxNumberVcs; + + internal int MaxRawSize; + + internal long ServerTime; + + internal int ServerTimeZone; + + internal int EncryptionKeyLength; + + internal byte[] EncryptionKey; + + internal byte[] Guid; + + internal ServerData(SmbTransport enclosing) + { + this._enclosing = enclosing; + } + + private readonly SmbTransport _enclosing; + } + + internal IPAddress LocalAddr; + + internal int LocalPort; + + internal UniAddress Address; + + internal SocketEx Socket; + + internal int Port; + + internal int Mid; + + internal OutputStream Out; + + internal InputStream In; + + internal byte[] Sbuf = new byte[512]; + + internal SmbComBlankResponse Key = new SmbComBlankResponse(); + + internal long SessionExpiration = Runtime.CurrentTimeMillis() + SmbConstants.SoTimeout; + + internal List<object> Referrals = new List<object>(); + + internal SigningDigest Digest; + + internal List<SmbSession> Sessions = new List<SmbSession>(); + + internal ServerData Server; + + internal int Flags2 = SmbConstants.Flags2; + + internal int MaxMpxCount = SmbConstants.MaxMpxCount; + + internal int SndBufSize = SmbConstants.SndBufSize; + + internal int RcvBufSize = SmbConstants.RcvBufSize; + + internal int Capabilities = SmbConstants.Capabilities; + + internal int SessionKey = 0x00000000; + + internal bool UseUnicode = SmbConstants.UseUnicode; + + internal string TconHostName; + + internal SmbTransport(UniAddress address, int port, IPAddress localAddr, int localPort + ) + { + Server = new ServerData(this); + this.Address = address; + this.Port = port; + this.LocalAddr = localAddr; + this.LocalPort = localPort; + } + + internal virtual SmbSession GetSmbSession() + { + lock (this) + { + return GetSmbSession(new NtlmPasswordAuthentication(null, null, null)); + } + } + + internal virtual SmbSession GetSmbSession(NtlmPasswordAuthentication auth) + { + lock (this) + { + SmbSession ssn; + long now; + + ssn = Sessions.FirstOrDefault(s => s.Matches(auth)); + if (ssn != null) + { + ssn.Auth = auth; + return ssn; + } + + if (SmbConstants.SoTimeout > 0 && SessionExpiration < (now = Runtime.CurrentTimeMillis())) + { + SessionExpiration = now + SmbConstants.SoTimeout; + + foreach (var session in Sessions.Where(s => s.Expiration < now)) + { + session.Logoff(false); + } + } + ssn = new SmbSession(Address, Port, LocalAddr, LocalPort, auth); + ssn.transport = this; + Sessions.Add(ssn); + return ssn; + } + } + + internal virtual bool Matches(UniAddress address, int port, IPAddress localAddr, + int localPort, string hostName) + { + if (hostName == null) + { + hostName = address.GetHostName(); + } + return (TconHostName == null || Runtime.EqualsIgnoreCase(hostName, TconHostName)) && address.Equals(this.Address) && (port == -1 || port == this.Port + || (port == 445 && this.Port == 139)) && (localAddr == this.LocalAddr || (localAddr + != null && localAddr.Equals(this.LocalAddr))) && localPort == this.LocalPort; + } + + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + internal virtual bool HasCapability(int cap) + { + try + { + Connect(SmbConstants.ResponseTimeout); + } + catch (IOException ioe) + { + throw new SmbException(ioe.Message, ioe); + } + return (Capabilities & cap) == cap; + } + + internal virtual bool IsSignatureSetupRequired(NtlmPasswordAuthentication auth) + { + return (Flags2 & SmbConstants.Flags2SecuritySignatures) != 0 && Digest == + null && auth != NtlmPasswordAuthentication.Null && NtlmPasswordAuthentication.Null + .Equals(auth) == false; + } + + /// <exception cref="System.IO.IOException"></exception> + internal virtual void Ssn139() + { + Name calledName = new Name(Address.FirstCalledName(), 0x20, null + ); + do + { + Socket = new SocketEx(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (LocalAddr != null) + { + Socket.Bind2(new IPEndPoint(LocalAddr, LocalPort)); + } + + Socket.Connect(new IPEndPoint(IPAddress.Parse(Address.GetHostAddress()), 139), SmbConstants.ConnTimeout); + Socket.SoTimeOut = SmbConstants.SoTimeout; + + Out = Socket.GetOutputStream(); + In = Socket.GetInputStream(); + SessionServicePacket ssp = new SessionRequestPacket(calledName, NbtAddress.GetLocalName + ()); + Out.Write(Sbuf, 0, ssp.WriteWireFormat(Sbuf, 0)); + if (Readn(In, Sbuf, 0, 4) < 4) + { + try + { + //Socket.`Close` method deleted + //Socket.Close(); + Socket.Dispose(); + } + catch (IOException) + { + } + throw new SmbException("EOF during NetBIOS session request"); + } + switch (Sbuf[0] & 0xFF) + { + case SessionServicePacket.PositiveSessionResponse: + { + if (Log.Level >= 4) + { + Log.WriteLine("session established ok with " + Address); + } + return; + } + + case SessionServicePacket.NegativeSessionResponse: + { + int errorCode = In.Read() & 0xFF; + switch (errorCode) + { + case NbtException.CalledNotPresent: + case NbtException.NotListeningCalled: + { + //Socket.`Close` method deleted + //Socket.Close(); + Socket.Dispose(); + break; + } + + default: + { + Disconnect(true); + throw new NbtException(NbtException.ErrSsnSrvc, errorCode); + } + } + break; + } + + case -1: + { + Disconnect(true); + throw new NbtException(NbtException.ErrSsnSrvc, NbtException.ConnectionRefused + ); + } + + default: + { + Disconnect(true); + throw new NbtException(NbtException.ErrSsnSrvc, 0); + } + } + } + while ((calledName.name = Address.NextCalledName()) != null); + throw new IOException("Failed to establish session with " + Address); + } + + /// <exception cref="System.IO.IOException"></exception> + private void Negotiate(int port, ServerMessageBlock resp) + { + lock (Sbuf) + { + if (port == 139) + { + Ssn139(); + } + else + { + if (port == -1) + { + port = SmbConstants.DefaultPort; + } + // 445 + Socket = new SocketEx(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + if (LocalAddr != null) + { + Socket.Bind2(new IPEndPoint(LocalAddr, LocalPort)); + } + + Socket.Connect(new IPEndPoint(IPAddress.Parse(Address.GetHostAddress()), port), SmbConstants.ConnTimeout); + Socket.SoTimeOut = SmbConstants.SoTimeout; + Out = Socket.GetOutputStream(); + In = Socket.GetInputStream(); + } + if (++Mid == 32000) + { + Mid = 1; + } + NegotiateRequest.Mid = Mid; + int n = NegotiateRequest.Encode(Sbuf, 4); + Encdec.Enc_uint32be(n & 0xFFFF, Sbuf, 0); + if (Log.Level >= 4) + { + Log.WriteLine(NegotiateRequest); + if (Log.Level >= 6) + { + Hexdump.ToHexdump(Log, Sbuf, 4, n); + } + } + Out.Write(Sbuf, 0, 4 + n); + Out.Flush(); + if (PeekKey() == null) + { + throw new IOException("transport closed in negotiate"); + } + int size = Encdec.Dec_uint16be(Sbuf, 2) & 0xFFFF; + if (size < 33 || (4 + size) > Sbuf.Length) + { + throw new IOException("Invalid payload size: " + size); + } + Readn(In, Sbuf, 4 + 32, size - 32); + resp.Decode(Sbuf, 4); + if (Log.Level >= 4) + { + Log.WriteLine(resp); + if (Log.Level >= 6) + { + Hexdump.ToHexdump(Log, Sbuf, 4, n); + } + } + } + } + + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + public virtual void Connect() + { + try + { + base.Connect(SmbConstants.ResponseTimeout); + } + catch (TransportException te) + { + throw new SmbException("Failed to connect: " + Address, te); + } + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override void DoConnect() + { + SmbComNegotiateResponse resp = new SmbComNegotiateResponse(Server); + try + { + Negotiate(Port, resp); + } + catch (ConnectException) + { + Port = (Port == -1 || Port == SmbConstants.DefaultPort) ? 139 : SmbConstants.DefaultPort; + Negotiate(Port, resp); + } + if (resp.DialectIndex > 10) + { + throw new SmbException("This client does not support the negotiated dialect."); + } + if ((Server.Capabilities & SmbConstants.CapExtendedSecurity) != SmbConstants.CapExtendedSecurity && Server + .EncryptionKeyLength != 8 && SmbConstants.LmCompatibility == 0) + { + throw new SmbException("Unexpected encryption key length: " + Server.EncryptionKeyLength + ); + } + TconHostName = Address.GetHostName(); + if (Server.SignaturesRequired || (Server.SignaturesEnabled && SmbConstants.Signpref)) + { + Flags2 |= SmbConstants.Flags2SecuritySignatures; + } + else + { + Flags2 &= 0xFFFF ^ SmbConstants.Flags2SecuritySignatures; + } + MaxMpxCount = Math.Min(MaxMpxCount, Server.MaxMpxCount); + if (MaxMpxCount < 1) + { + MaxMpxCount = 1; + } + SndBufSize = Math.Min(SndBufSize, Server.MaxBufferSize); + Capabilities &= Server.Capabilities; + if ((Server.Capabilities & SmbConstants.CapExtendedSecurity) == SmbConstants.CapExtendedSecurity) + { + Capabilities |= SmbConstants.CapExtendedSecurity; + } + // & doesn't copy high bit + if ((Capabilities & SmbConstants.CapUnicode) == 0) + { + // server doesn't want unicode + if (SmbConstants.ForceUnicode) + { + Capabilities |= SmbConstants.CapUnicode; + } + else + { + UseUnicode = false; + Flags2 &= 0xFFFF ^ SmbConstants.Flags2Unicode; + } + } + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override void DoDisconnect(bool hard) + { + try + { + foreach (var ssn in Sessions) + { + ssn.Logoff(hard); + } + + Out.Close(); + In.Close(); + + //Socket.`Close` method deleted + //Socket.Close(); + Socket.Dispose(); + } + finally + { + Digest = null; + Socket = null; + TconHostName = null; + } + + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override void MakeKey(ServerMessageBlock request) + { + if (++Mid == 32000) + { + Mid = 1; + } + request.Mid = Mid; + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override ServerMessageBlock PeekKey() + { + int n; + do + { + if ((n = Readn(In, Sbuf, 0, 4)) < 4) + { + return null; + } + } + while (Sbuf[0] == 0x85); + if ((n = Readn(In, Sbuf, 4, 32)) < 32) + { + return null; + } + if (Log.Level >= 4) + { + Log.WriteLine("New data read: " + this); + Hexdump.ToHexdump(Log, Sbuf, 4, 32); + } + for (; ; ) + { + if (Sbuf[0] == 0x00 && Sbuf[1] == 0x00 && + Sbuf[4] == 0xFF && + Sbuf[5] == 'S' && + Sbuf[6] == 'M' && + Sbuf[7] == 'B') + { + break; + } + for (int i = 0; i < 35; i++) + { + Sbuf[i] = Sbuf[i + 1]; + } + int b; + if ((b = In.Read()) == -1) + { + return null; + } + Sbuf[35] = unchecked((byte)b); + } + Key.Mid = Encdec.Dec_uint16le(Sbuf, 34) & 0xFFFF; + return Key; + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override void DoSend(ServerMessageBlock request) + { + lock (Buf) + { + ServerMessageBlock smb = request; + int n = smb.Encode(Buf, 4); + Encdec.Enc_uint32be(n & 0xFFFF, Buf, 0); + if (Log.Level >= 4) + { + do + { + Log.WriteLine(smb); + } + while (smb is AndXServerMessageBlock && (smb = ((AndXServerMessageBlock)smb).Andx + ) != null); + if (Log.Level >= 6) + { + Hexdump.ToHexdump(Log, Buf, 4, n); + } + } + Out.Write(Buf, 0, 4 + n); + } + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal virtual void DoSend0(ServerMessageBlock request) + { + try + { + DoSend(request); + } + catch (IOException ioe) + { + if (Log.Level > 2) + { + Runtime.PrintStackTrace(ioe, Log); + } + try + { + Disconnect(true); + } + catch (IOException ioe2) + { + Runtime.PrintStackTrace(ioe2, Log); + } + throw; + } + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override void DoRecv(Response response) + { + ServerMessageBlock resp = (ServerMessageBlock)response; + resp.UseUnicode = UseUnicode; + resp.ExtendedSecurity = (Capabilities & SmbConstants.CapExtendedSecurity) == SmbConstants.CapExtendedSecurity; + lock (Buf) + { + Array.Copy(Sbuf, 0, Buf, 0, 4 + SmbConstants.HeaderLength); + int size = Encdec.Dec_uint16be(Buf, 2) & 0xFFFF; + if (size < (SmbConstants.HeaderLength + 1) || (4 + size) > RcvBufSize) + { + throw new IOException("Invalid payload size: " + size); + } + int errorCode = Encdec.Dec_uint32le(Buf, 9) & unchecked((int)(0xFFFFFFFF)); + if (resp.Command == ServerMessageBlock.SmbComReadAndx && (errorCode == 0 || errorCode + == unchecked((int)(0x80000005)))) + { + // overflow indicator normal for pipe + SmbComReadAndXResponse r = (SmbComReadAndXResponse)resp; + int off = SmbConstants.HeaderLength; + Readn(In, Buf, 4 + off, 27); + off += 27; + resp.Decode(Buf, 4); + int pad = r.DataOffset - off; + if (r.ByteCount > 0 && pad > 0 && pad < 4) + { + Readn(In, Buf, 4 + off, pad); + } + if (r.DataLength > 0) + { + Readn(In, r.B, r.Off, r.DataLength); + } + } + else + { + Readn(In, Buf, 4 + 32, size - 32); + resp.Decode(Buf, 4); + if (resp is SmbComTransactionResponse) + { + ((SmbComTransactionResponse)resp).Current(); + } + } + if (Digest != null && resp.ErrorCode == 0) + { + Digest.Verify(Buf, 4, resp); + } + if (Log.Level >= 4) + { + Log.WriteLine(response); + if (Log.Level >= 6) + { + Hexdump.ToHexdump(Log, Buf, 4, size); + } + } + } + } + + /// <exception cref="System.IO.IOException"></exception> + protected internal override void DoSkip() + { + int size = Encdec.Dec_uint16be(Sbuf, 2) & 0xFFFF; + if (size < 33 || (4 + size) > RcvBufSize) + { + In.Skip(In.Available()); + } + else + { + In.Skip(size - 32); + } + } + + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + internal virtual void CheckStatus(ServerMessageBlock req, ServerMessageBlock resp + ) + { + resp.ErrorCode = SmbException.GetStatusByCode(resp.ErrorCode); + switch (resp.ErrorCode) + { + case NtStatus.NtStatusOk: + { + break; + } + + case NtStatus.NtStatusAccessDenied: + case NtStatus.NtStatusWrongPassword: + case NtStatus.NtStatusLogonFailure: + case NtStatus.NtStatusAccountRestriction: + case NtStatus.NtStatusInvalidLogonHours: + case NtStatus.NtStatusInvalidWorkstation: + case NtStatus.NtStatusPasswordExpired: + case NtStatus.NtStatusAccountDisabled: + case NtStatus.NtStatusAccountLockedOut: + case NtStatus.NtStatusTrustedDomainFailure: + { + throw new SmbAuthException(resp.ErrorCode); + } + + case NtStatus.NtStatusPathNotCovered: + { + if (req.Auth == null) + { + throw new SmbException(resp.ErrorCode, null); + } + DfsReferral dr = GetDfsReferrals(req.Auth, req.Path, 1); + if (dr == null) + { + throw new SmbException(resp.ErrorCode, null); + } + SmbFile.Dfs.Insert(req.Path, dr); + throw dr; + } + + case unchecked((int)(0x80000005)): + { + break; + } + + case NtStatus.NtStatusMoreProcessingRequired: + { + break; + } + + default: + { + throw new SmbException(resp.ErrorCode, null); + } + } + if (resp.VerifyFailed) + { + throw new SmbException("Signature verification failed."); + } + } + + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + internal virtual void Send(ServerMessageBlock request, ServerMessageBlock response + ) + { + Connect(); + request.Flags2 |= Flags2; + request.UseUnicode = UseUnicode; + request.Response = response; + if (request.Digest == null) + { + request.Digest = Digest; + } + try + { + if (response == null) + { + DoSend0(request); + return; + } + if (request is SmbComTransaction) + { + response.Command = request.Command; + SmbComTransaction req = (SmbComTransaction)request; + SmbComTransactionResponse resp = (SmbComTransactionResponse)response; + req.MaxBufferSize = SndBufSize; + resp.Reset(); + try + { + BufferCache.GetBuffers(req, resp); + req.Current(); + if (req.MoveNext()) + { + SmbComBlankResponse interim = new SmbComBlankResponse(); + Sendrecv(req, interim, SmbConstants.ResponseTimeout); + if (interim.ErrorCode != 0) + { + CheckStatus(req, interim); + } + req.Current(); + } + else + { + MakeKey(req); + } + lock (this) + { + response.Received = false; + resp.IsReceived = false; + try + { + ResponseMap.Put(req, resp); + do + { + DoSend0(req); + } + while (req.MoveNext() && req.Current() != null); + long timeout = SmbConstants.ResponseTimeout; + resp.Expiration = Runtime.CurrentTimeMillis() + timeout; + while (resp.MoveNext()) + { + Runtime.Wait(this, timeout); + timeout = resp.Expiration - Runtime.CurrentTimeMillis(); + if (timeout <= 0) + { + throw new TransportException(this + " timedout waiting for response to " + req); + } + } + if (response.ErrorCode != 0) + { + CheckStatus(req, resp); + } + } + catch (Exception ie) + { + if (ie is SmbException) + { + throw; + } + else + { + throw new TransportException(ie); + } + } + finally + { + //Sharpen.Collections.Remove<Hashtable, SmbComTransaction>(response_map, req); + ResponseMap.Remove(req); + } + } + } + finally + { + BufferCache.ReleaseBuffer(req.TxnBuf); + BufferCache.ReleaseBuffer(resp.TxnBuf); + } + } + else + { + response.Command = request.Command; + Sendrecv(request, response, SmbConstants.ResponseTimeout); + } + } + catch (SmbException se) + { + throw; + } + catch (IOException ioe) + { + throw new SmbException(ioe.Message, ioe); + } + CheckStatus(request, response); + } + + public override string ToString() + { + return base.ToString() + "[" + Address + ":" + Port + "]"; + } + + internal virtual void DfsPathSplit(string path, string[] result) + { + int ri = 0; + int rlast = result.Length - 1; + int i = 0; + int b = 0; + int len = path.Length; + do + { + if (ri == rlast) + { + result[rlast] = Runtime.Substring(path, b); + return; + } + if (i == len || path[i] == '\\') + { + result[ri++] = Runtime.Substring(path, b, i); + b = i + 1; + } + } + while (i++ < len); + while (ri < result.Length) + { + result[ri++] = string.Empty; + } + } + + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + internal virtual DfsReferral GetDfsReferrals(NtlmPasswordAuthentication auth, string + path, int rn) + { + SmbTree ipc = GetSmbSession(auth).GetSmbTree("IPC$", null); + Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse(); + ipc.Send(new Trans2GetDfsReferral(path), resp); + if (resp.NumReferrals == 0) + { + return null; + } + if (rn == 0 || resp.NumReferrals < rn) + { + rn = resp.NumReferrals; + } + DfsReferral dr = new DfsReferral(); + string[] arr = new string[4]; + long expiration = Runtime.CurrentTimeMillis() + Dfs.Ttl * 1000; + int di = 0; + for (; ; ) + { + dr.ResolveHashes = auth.HashesExternal; + dr.Ttl = resp.Referrals[di].Ttl; + dr.Expiration = expiration; + if (path.Equals(string.Empty)) + { + dr.Server = Runtime.Substring(resp.Referrals[di].Path, 1).ToLower(); + } + else + { + DfsPathSplit(resp.Referrals[di].Node, arr); + dr.Server = arr[1]; + dr.Share = arr[2]; + dr.Path = arr[3]; + } + dr.PathConsumed = resp.PathConsumed; + di++; + if (di == rn) + { + break; + } + dr.Append(new DfsReferral()); + dr = dr.Next; + } + return dr.Next; + } + + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + internal virtual DfsReferral[] __getDfsReferrals(NtlmPasswordAuthentication auth, + string path, int rn) + { + SmbTree ipc = GetSmbSession(auth).GetSmbTree("IPC$", null); + Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse(); + ipc.Send(new Trans2GetDfsReferral(path), resp); + if (rn == 0 || resp.NumReferrals < rn) + { + rn = resp.NumReferrals; + } + DfsReferral[] drs = new DfsReferral[rn]; + string[] arr = new string[4]; + long expiration = Runtime.CurrentTimeMillis() + Dfs.Ttl * 1000; + for (int di = 0; di < drs.Length; di++) + { + DfsReferral dr = new DfsReferral(); + dr.ResolveHashes = auth.HashesExternal; + dr.Ttl = resp.Referrals[di].Ttl; + dr.Expiration = expiration; + if (path.Equals(string.Empty)) + { + dr.Server = Runtime.Substring(resp.Referrals[di].Path, 1).ToLower(); + } + else + { + DfsPathSplit(resp.Referrals[di].Node, arr); + dr.Server = arr[1]; + dr.Share = arr[2]; + dr.Path = arr[3]; + } + dr.PathConsumed = resp.PathConsumed; + drs[di] = dr; + } + return drs; + } + } +} |
