| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 | // 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  USAusing System;using System.Collections.Generic;using System.IO;using System.Net;using SharpCifs.Netbios;using SharpCifs.Util.Sharpen;namespace SharpCifs.Smb{	public sealed class SmbSession	{		private static readonly string LogonShare = Config.GetProperty("jcifs.smb.client.logonShare"			, null);		private static readonly int LookupRespLimit = Config.GetInt("jcifs.netbios.lookupRespLimit"			, 3);		private static readonly string Domain = Config.GetProperty("jcifs.smb.client.domain"			, null);		private static readonly string Username = Config.GetProperty("jcifs.smb.client.username"			, null);		private static readonly int CachePolicy = Config.GetInt("jcifs.netbios.cachePolicy"			, 60 * 10) * 60;		internal static NbtAddress[] DcList;		internal static long DcListExpiration;		internal static int DcListCounter;		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		private static NtlmChallenge Interrogate(NbtAddress addr)		{			UniAddress dc = new UniAddress(addr);			SmbTransport trans = SmbTransport.GetSmbTransport(dc, 0);			if (Username == null)			{				trans.Connect();                if (SmbTransport.LogStatic.Level >= 3)				{                    SmbTransport.LogStatic.WriteLine("Default credentials (jcifs.smb.client.username/password)"						 + " not specified. SMB signing may not work propertly." + "  Skipping DC interrogation."						);				}			}			else			{				SmbSession ssn = trans.GetSmbSession(NtlmPasswordAuthentication.Default					);				ssn.GetSmbTree(LogonShare, null).TreeConnect(null, null);			}			return new NtlmChallenge(trans.Server.EncryptionKey, dc);		}		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		/// <exception cref="UnknownHostException"></exception>		public static NtlmChallenge GetChallengeForDomain()		{			if (Domain == null)			{				throw new SmbException("A domain was not specified");			}			lock (Domain)			{				long now = Runtime.CurrentTimeMillis();				int retry = 1;				do				{					if (DcListExpiration < now)					{						NbtAddress[] list = NbtAddress.GetAllByName(Domain, 0x1C, null, 							null);						DcListExpiration = now + CachePolicy * 1000L;						if (list != null && list.Length > 0)						{							DcList = list;						}						else						{							DcListExpiration = now + 1000 * 60 * 15;                            if (SmbTransport.LogStatic.Level >= 2)							{                                SmbTransport.LogStatic.WriteLine("Failed to retrieve DC list from WINS");							}						}					}					int max = Math.Min(DcList.Length, LookupRespLimit);					for (int j = 0; j < max; j++)					{						int i = DcListCounter++ % max;						if (DcList[i] != null)						{							try							{								return Interrogate(DcList[i]);							}							catch (SmbException se)							{                                if (SmbTransport.LogStatic.Level >= 2)								{                                    SmbTransport.LogStatic.WriteLine("Failed validate DC: " + DcList[i]);                                    if (SmbTransport.LogStatic.Level > 2)									{                                        Runtime.PrintStackTrace(se, SmbTransport.LogStatic);									}								}							}							DcList[i] = null;						}					}					DcListExpiration = 0;				}				while (retry-- > 0);				DcListExpiration = now + 1000 * 60 * 15;			}			throw new UnknownHostException("Failed to negotiate with a suitable domain controller for "				 + Domain);		}		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		/// <exception cref="UnknownHostException"></exception>		public static byte[] GetChallenge(UniAddress dc)		{			return GetChallenge(dc, 0);		}		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		/// <exception cref="UnknownHostException"></exception>		public static byte[] GetChallenge(UniAddress dc, int port)		{			SmbTransport trans = SmbTransport.GetSmbTransport(dc, port);			trans.Connect();			return trans.Server.EncryptionKey;		}		/// <summary>		/// Authenticate arbitrary credentials represented by the		/// <tt>NtlmPasswordAuthentication</tt> object against the domain controller		/// specified by the <tt>UniAddress</tt> parameter.		/// </summary>		/// <remarks>		/// Authenticate arbitrary credentials represented by the		/// <tt>NtlmPasswordAuthentication</tt> object against the domain controller		/// specified by the <tt>UniAddress</tt> parameter. If the credentials are		/// not accepted, an <tt>SmbAuthException</tt> will be thrown. If an error		/// occurs an <tt>SmbException</tt> will be thrown. If the credentials are		/// valid, the method will return without throwing an exception. See the		/// last <a href="../../../faq.html">FAQ</a> question.		/// <p>		/// See also the <tt>jcifs.smb.client.logonShare</tt> property.		/// </remarks>		/// <exception cref="SmbException"></exception>		public static void Logon(UniAddress dc, NtlmPasswordAuthentication auth)		{			Logon(dc, -1, auth);		}		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		public static void Logon(UniAddress dc, int port, NtlmPasswordAuthentication auth			)		{			SmbTree tree = SmbTransport.GetSmbTransport(dc, port).GetSmbSession(auth).GetSmbTree				(LogonShare, null);			if (LogonShare == null)			{				tree.TreeConnect(null, null);			}			else			{				Trans2FindFirst2 req = new Trans2FindFirst2("\\", "*", SmbFile.AttrDirectory);				Trans2FindFirst2Response resp = new Trans2FindFirst2Response();				tree.Send(req, resp);			}		}		internal int ConnectionState;		internal int Uid;		internal List<object> Trees;		private UniAddress _address;		private int _port;		private int _localPort;		private IPAddress _localAddr;		internal SmbTransport transport;		internal NtlmPasswordAuthentication Auth;		internal long Expiration;		internal string NetbiosName;		internal SmbSession(UniAddress address, int port, IPAddress localAddr, int localPort			, NtlmPasswordAuthentication auth)		{			// Transport parameters allows trans to be removed from CONNECTIONS			this._address = address;			this._port = port;			this._localAddr = localAddr;			this._localPort = localPort;			this.Auth = auth;			Trees = new List<object>();			ConnectionState = 0;		}		internal SmbTree GetSmbTree(string share, string service)		{			lock (this)			{				SmbTree t;				if (share == null)				{					share = "IPC$";				}				/*for (IEnumeration e = trees.GetEnumerator(); e.MoveNext(); )				{					t = (SmbTree)e.Current;					if (t.Matches(share, service))					{						return t;					}				}*/			    foreach (var e in Trees)			    {                    t = (SmbTree)e;                    if (t.Matches(share, service))                    {                        return t;                    }			    }				t = new SmbTree(this, share, service);				Trees.Add(t);				return t;			}		}		internal bool Matches(NtlmPasswordAuthentication auth)		{			return this.Auth == auth || this.Auth.Equals(auth);		}		internal SmbTransport Transport()		{			lock (this)			{				if (transport == null)				{					transport = SmbTransport.GetSmbTransport(_address, _port, _localAddr, _localPort, null						);				}				return transport;			}		}		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		internal void Send(ServerMessageBlock request, ServerMessageBlock response)		{			lock (Transport())			{				if (response != null)				{					response.Received = false;				}				Expiration = Runtime.CurrentTimeMillis() + SmbConstants.SoTimeout;				SessionSetup(request, response);				if (response != null && response.Received)				{					return;				}				if (request is SmbComTreeConnectAndX)				{					SmbComTreeConnectAndX tcax = (SmbComTreeConnectAndX)request;					if (NetbiosName != null && tcax.path.EndsWith("\\IPC$"))					{						tcax.path = "\\\\" + NetbiosName + "\\IPC$";					}				}				request.Uid = Uid;				request.Auth = Auth;				try				{					transport.Send(request, response);				}				catch (SmbException se)				{					if (request is SmbComTreeConnectAndX)					{						Logoff(true);					}					request.Digest = null;					throw;				}			}		}		/// <exception cref="SharpCifs.Smb.SmbException"></exception>		internal void SessionSetup(ServerMessageBlock andx, ServerMessageBlock andxResponse			)		{			lock (Transport())			{				NtlmContext nctx = null;				SmbException ex = null;				SmbComSessionSetupAndX request;				SmbComSessionSetupAndXResponse response;				byte[] token = new byte[0];				int state = 10;				while (ConnectionState != 0)				{					if (ConnectionState == 2 || ConnectionState == 3)					{						// connected or disconnecting						return;					}					try					{						Runtime.Wait(transport);					}					catch (Exception ie)					{						throw new SmbException(ie.Message, ie);					}				}				ConnectionState = 1;				// trying ...				try				{					transport.Connect();					if (transport.Log.Level >= 4)					{						transport.Log.WriteLine("sessionSetup: accountName=" + Auth.Username + ",primaryDomain="							 + Auth.Domain);					}					Uid = 0;					do					{						switch (state)						{							case 10:							{								if (Auth != NtlmPasswordAuthentication.Anonymous && transport.HasCapability(SmbConstants									.CapExtendedSecurity))								{									state = 20;									break;								}								request = new SmbComSessionSetupAndX(this, andx, Auth);								response = new SmbComSessionSetupAndXResponse(andxResponse);								if (transport.IsSignatureSetupRequired(Auth))								{									if (Auth.HashesExternal && NtlmPasswordAuthentication.DefaultPassword != NtlmPasswordAuthentication										.Blank)									{										transport.GetSmbSession(NtlmPasswordAuthentication.Default).GetSmbTree(LogonShare											, null).TreeConnect(null, null);									}									else									{										byte[] signingKey = Auth.GetSigningKey(transport.Server.EncryptionKey);										request.Digest = new SigningDigest(signingKey, false);									}								}								request.Auth = Auth;								try								{									transport.Send(request, response);								}								catch (SmbAuthException sae)								{									throw;								}								catch (SmbException se)								{									ex = se;								}								if (response.IsLoggedInAsGuest && Runtime.EqualsIgnoreCase("GUEST", Auth.									Username) == false && transport.Server.Security != SmbConstants.SecurityShare &&									 Auth != NtlmPasswordAuthentication.Anonymous)								{									throw new SmbAuthException(NtStatus.NtStatusLogonFailure);								}								if (ex != null)								{									throw ex;								}								Uid = response.Uid;								if (request.Digest != null)								{									transport.Digest = request.Digest;								}								ConnectionState = 2;								state = 0;								break;							}							case 20:							{								if (nctx == null)								{                                    bool doSigning = (transport.Flags2 & SmbConstants.Flags2SecuritySignatures										) != 0;									nctx = new NtlmContext(Auth, doSigning);								}                                if (SmbTransport.LogStatic.Level >= 4)								{                                    SmbTransport.LogStatic.WriteLine(nctx);								}								if (nctx.IsEstablished())								{									NetbiosName = nctx.GetNetbiosName();									ConnectionState = 2;									state = 0;									break;								}								try								{									token = nctx.InitSecContext(token, 0, token.Length);								}								catch (SmbException se)								{									try									{										transport.Disconnect(true);									}									catch (IOException)									{									}									Uid = 0;									throw;								}								if (token != null)								{									request = new SmbComSessionSetupAndX(this, null, token);									response = new SmbComSessionSetupAndXResponse(null);									if (transport.IsSignatureSetupRequired(Auth))									{										byte[] signingKey = nctx.GetSigningKey();										if (signingKey != null)										{											request.Digest = new SigningDigest(signingKey, true);										}									}									request.Uid = Uid;									Uid = 0;									try									{										transport.Send(request, response);									}									catch (SmbAuthException sae)									{										throw;									}									catch (SmbException se)									{										ex = se;										try										{											transport.Disconnect(true);										}										catch (Exception)										{										}									}									if (response.IsLoggedInAsGuest && Runtime.EqualsIgnoreCase("GUEST", Auth.										Username) == false)									{										throw new SmbAuthException(NtStatus.NtStatusLogonFailure);									}									if (ex != null)									{										throw ex;									}									Uid = response.Uid;									if (request.Digest != null)									{										transport.Digest = request.Digest;									}									token = response.Blob;								}								break;							}							default:							{								throw new SmbException("Unexpected session setup state: " + state);							}						}					}					while (state != 0);				}				catch (SmbException se)				{					Logoff(true);					ConnectionState = 0;					throw;				}				finally				{					Runtime.NotifyAll(transport);				}			}		}		internal void Logoff(bool inError)		{			lock (Transport())			{				if (ConnectionState != 2)				{					// not-connected					return;				}				ConnectionState = 3;				// disconnecting				NetbiosName = null;                foreach (SmbTree t in Trees)			    {			        t.TreeDisconnect(inError);			    }                if (!inError && transport.Server.Security != SmbConstants.SecurityShare)				{					SmbComLogoffAndX request = new SmbComLogoffAndX(null);					request.Uid = Uid;					try					{						transport.Send(request, null);					}					catch (SmbException)					{					}					Uid = 0;				}				ConnectionState = 0;				Runtime.NotifyAll(transport);			}		}		public override string ToString()		{			return "SmbSession[accountName=" + Auth.Username + ",primaryDomain=" + Auth.Domain				 + ",uid=" + Uid + ",connectionState=" + ConnectionState + "]";		}	}}
 |