jellyfin/Emby.Common.Implementations/IO/SharpCifs/Smb/Dfs.cs
2017-06-21 02:46:57 -04:00

394 lines
14 KiB
C#

// 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.IO;
using SharpCifs.Util;
using SharpCifs.Util.Sharpen;
namespace SharpCifs.Smb
{
public class Dfs
{
internal class CacheEntry
{
internal long Expiration;
internal Hashtable Map;
internal CacheEntry(long ttl)
{
if (ttl == 0)
{
ttl = Ttl;
}
Expiration = Runtime.CurrentTimeMillis() + ttl * 1000L;
Map = new Hashtable();
}
}
internal static LogStream Log = LogStream.GetInstance();
internal static readonly bool StrictView
= Config.GetBoolean("jcifs.smb.client.dfs.strictView", false);
internal static readonly long Ttl
= Config.GetLong("jcifs.smb.client.dfs.ttl", 300);
internal static readonly bool Disabled
= Config.GetBoolean("jcifs.smb.client.dfs.disabled", false);
internal static CacheEntry FalseEntry = new CacheEntry(0L);
internal CacheEntry Domains;
internal CacheEntry Referrals;
/// <exception cref="SharpCifs.Smb.SmbAuthException"></exception>
public virtual Hashtable GetTrustedDomains(NtlmPasswordAuthentication auth)
{
if (Disabled || auth.Domain == "?")
{
return null;
}
if (Domains != null && Runtime.CurrentTimeMillis() > Domains.Expiration)
{
Domains = null;
}
if (Domains != null)
{
return Domains.Map;
}
try
{
UniAddress addr = UniAddress.GetByName(auth.Domain, true);
SmbTransport trans = SmbTransport.GetSmbTransport(addr, 0);
CacheEntry entry = new CacheEntry(Ttl * 10L);
DfsReferral dr = trans.GetDfsReferrals(auth, string.Empty, 0);
if (dr != null)
{
DfsReferral start = dr;
do
{
string domain = dr.Server.ToLower();
entry.Map.Put(domain, new Hashtable());
dr = dr.Next;
}
while (dr != start);
Domains = entry;
return Domains.Map;
}
}
catch (IOException ioe)
{
if (Log.Level >= 3)
{
Runtime.PrintStackTrace(ioe, Log);
}
if (StrictView && ioe is SmbAuthException)
{
throw (SmbAuthException)ioe;
}
}
return null;
}
/// <exception cref="SharpCifs.Smb.SmbAuthException"></exception>
public virtual bool IsTrustedDomain(string domain, NtlmPasswordAuthentication auth)
{
Hashtable domains = GetTrustedDomains(auth);
if (domains == null)
{
return false;
}
domain = domain.ToLower();
return domains.Get(domain) != null;
}
/// <exception cref="SharpCifs.Smb.SmbAuthException"></exception>
public virtual SmbTransport GetDc(string domain, NtlmPasswordAuthentication auth)
{
if (Disabled)
{
return null;
}
try
{
UniAddress addr = UniAddress.GetByName(domain, true);
SmbTransport trans = SmbTransport.GetSmbTransport(addr, 0);
DfsReferral dr = trans.GetDfsReferrals(auth, "\\" + domain, 1);
if (dr != null)
{
DfsReferral start = dr;
IOException e = null;
do
{
try
{
addr = UniAddress.GetByName(dr.Server);
return SmbTransport.GetSmbTransport(addr, 0);
}
catch (IOException ioe)
{
e = ioe;
}
dr = dr.Next;
}
while (dr != start);
throw e;
}
}
catch (IOException ioe)
{
if (Log.Level >= 3)
{
Runtime.PrintStackTrace(ioe, Log);
}
if (StrictView && ioe is SmbAuthException)
{
throw (SmbAuthException)ioe;
}
}
return null;
}
/// <exception cref="SharpCifs.Smb.SmbAuthException"></exception>
public virtual DfsReferral GetReferral(SmbTransport trans,
string domain,
string root,
string path,
NtlmPasswordAuthentication auth)
{
if (Disabled)
{
return null;
}
try
{
string p = "\\" + domain + "\\" + root;
if (path != null)
{
p += path;
}
DfsReferral dr = trans.GetDfsReferrals(auth, p, 0);
if (dr != null)
{
return dr;
}
}
catch (IOException ioe)
{
if (Log.Level >= 4)
{
Runtime.PrintStackTrace(ioe, Log);
}
if (StrictView && ioe is SmbAuthException)
{
throw (SmbAuthException)ioe;
}
}
return null;
}
/// <exception cref="SharpCifs.Smb.SmbAuthException"></exception>
public virtual DfsReferral Resolve(string domain,
string root,
string path,
NtlmPasswordAuthentication auth)
{
lock (this)
{
DfsReferral dr = null;
long now = Runtime.CurrentTimeMillis();
if (Disabled || root.Equals("IPC$"))
{
return null;
}
Hashtable domains = GetTrustedDomains(auth);
if (domains != null)
{
domain = domain.ToLower();
Hashtable roots = (Hashtable)domains.Get(domain);
if (roots != null)
{
SmbTransport trans = null;
root = root.ToLower();
CacheEntry links = (CacheEntry)roots.Get(root);
if (links != null && now > links.Expiration)
{
//Sharpen.Collections.Remove(roots, root);
roots.Remove(root);
links = null;
}
if (links == null)
{
if ((trans = GetDc(domain, auth)) == null)
{
return null;
}
dr = GetReferral(trans, domain, root, path, auth);
if (dr != null)
{
int len = 1 + domain.Length + 1 + root.Length;
links = new CacheEntry(0L);
DfsReferral tmp = dr;
do
{
if (path == null)
{
// TODO: fix this
//tmp.map = links.map;
tmp.Key = "\\";
}
tmp.PathConsumed -= len;
tmp = tmp.Next;
}
while (tmp != dr);
if (dr.Key != null)
{
links.Map.Put(dr.Key, dr);
}
roots.Put(root, links);
}
else
{
if (path == null)
{
roots.Put(root, FalseEntry);
}
}
}
else
{
if (links == FalseEntry)
{
links = null;
}
}
if (links != null)
{
string link = "\\";
dr = (DfsReferral)links.Map.Get(link);
if (dr != null && now > dr.Expiration)
{
//Sharpen.Collections.Remove(links.map, link);
links.Map.Remove(link);
dr = null;
}
if (dr == null)
{
if (trans == null)
{
if ((trans = GetDc(domain, auth)) == null)
{
return null;
}
}
dr = GetReferral(trans, domain, root, path, auth);
if (dr != null)
{
dr.PathConsumed -= 1 + domain.Length + 1 + root.Length;
dr.Link = link;
links.Map.Put(link, dr);
}
}
}
}
}
if (dr == null && path != null)
{
if (Referrals != null && now > Referrals.Expiration)
{
Referrals = null;
}
if (Referrals == null)
{
Referrals = new CacheEntry(0);
}
string key = "\\" + domain + "\\" + root;
if (path.Equals("\\") == false)
{
key += path;
}
key = key.ToLower();
//ListIterator<object> iter = new ListIterator<object>(referrals.map.Keys.GetEnumerator(), 0);
foreach (var current in Referrals.Map.Keys)
{
string _key = (string)current;
int klen = _key.Length;
bool match = false;
if (klen == key.Length)
{
match = _key.Equals(key);
}
else
{
if (klen < key.Length)
{
match = _key.RegionMatches(false, 0, key, 0, klen) && key[klen] == '\\';
}
}
if (match)
{
dr = (DfsReferral)Referrals.Map.Get(_key);
}
}
}
return dr;
}
}
internal virtual void Insert(string path, DfsReferral dr)
{
lock (this)
{
int s1;
int s2;
string server;
string share;
string key;
if (Disabled)
{
return;
}
s1 = path.IndexOf('\\', 1);
s2 = path.IndexOf('\\', s1 + 1);
server = Runtime.Substring(path, 1, s1);
share = Runtime.Substring(path, s1 + 1, s2);
key = Runtime.Substring(path, 0, dr.PathConsumed).ToLower();
int ki = key.Length;
while (ki > 1 && key[ki - 1] == '\\')
{
ki--;
}
if (ki < key.Length)
{
key = Runtime.Substring(key, 0, ki);
}
dr.PathConsumed -= 1 + server.Length + 1 + share.Length;
if (Referrals != null && (Runtime.CurrentTimeMillis() + 10000) > Referrals.Expiration)
{
Referrals = null;
}
if (Referrals == null)
{
Referrals = new CacheEntry(0);
}
Referrals.Map.Put(key, dr);
}
}
}
}