/// <summary> /// update the connection isSigningActive, combination of the client's MessageSigningPolicy and the /// connection's ServerSigningState. /// </summary> /// <param name = "connection">the target connection to update </param> /// <returns>the combination result </returns> internal void UpdateSigningActive(SmbClientConnection connection) { if (connection == null) { return; } switch (smbClient.Capability.ClientSignState) { case SignState.REQUIRED: MergeClientRequiredState(connection); break; case SignState.ENABLED: MergeClientEnableState(connection); break; case SignState.DISABLED_UNLESS_REQUIRED: MergeClientDisalbedUnlessRequiredState(connection); break; case SignState.DISABLED: MergeClientDisabledState(connection); break; default: break; } }
/// <summary> /// Deep copy constructor. if need to copy the connection instance, you must call the Clone method. its sub /// class inherit from this, and need to provide more features. /// </summary> /// <param name="session">the session to get the opentable</param> /// <param name="treeconnect">the treeconnect to copy from</param> protected SmbClientTreeConnect(SmbClientSession session, SmbClientTreeConnect treeconnect) : base(treeconnect) { this.session = session; this.maximalShareAccessRights = treeconnect.maximalShareAccessRights; this.guestMaximalShareAccessRights = treeconnect.guestMaximalShareAccessRights; this.connection = treeconnect.connection; }
/// <summary> /// get the session in current connection /// </summary> /// <param name="sessionUid">the id of session</param> /// <returns>the session object</returns> public SmbClientSession GetSession(ushort sessionUid) { SmbClientConnection connection = Connection; if (connection == null) { return null; } return new SmbClientSession(GetSession(connection.ConnectionId, sessionUid)); }
/// <summary> /// Deep copy constructor. if need to copy the connection instance, you must call the Clone method. its sub /// class inherit from this, and need to provide more features. /// </summary> protected SmbClientConnection(SmbClientConnection connection) : base(connection) { lock (connection) { this.GssApi = connection.GssApi; if (connection.SecurityBlob != null) { this.SecurityBlob = new byte[connection.SecurityBlob.Length]; Array.Copy(connection.SecurityBlob, this.SecurityBlob, connection.SecurityBlob.Length); } } }
/// <summary> /// merge the server sign state when client is disabled-unless-required. /// </summary> /// <param name = "connection">the target connection to update </param> private void MergeClientDisalbedUnlessRequiredState(SmbClientConnection connection) { switch (connection.ServerSigningState) { case SignState.REQUIRED: connection.IsSigningActive = true; break; case SignState.ENABLED: case SignState.DISABLED_UNLESS_REQUIRED: case SignState.DISABLED: connection.IsSigningActive = false; break; } }
/// <summary> /// merge the server sign state when client is enable. /// </summary> /// <param name = "connection">the target connection to update </param> private void MergeClientEnableState(SmbClientConnection connection) { switch (connection.ServerSigningState) { case SignState.REQUIRED: case SignState.ENABLED: connection.IsSigningActive = true; break; case SignState.DISABLED_UNLESS_REQUIRED: case SignState.DISABLED: connection.IsSigningActive = false; break; default: break; } }
/// <summary> /// get the file in current connection /// </summary> /// <param name="fid">the id of file</param> /// <returns>the file object</returns> public SmbClientOpen GetOpenFile(ushort fid) { SmbClientConnection connection = Connection; if (connection == null) { return null; } ReadOnlyCollection<CifsClientPerOpenFile> files = GetOpenFiles(connection.ConnectionId); foreach (CifsClientPerOpenFile file in files) { if (file.FileHandle == fid) { return new SmbClientOpen(file); } } return null; }
/// <summary> /// get the treeconnect in current connection /// </summary> /// <param name="tid">the id of treeconnect</param> /// <returns>the treeconnect object</returns> public SmbClientTreeConnect GetTreeConnect(ushort tid) { SmbClientConnection connection = Connection; if (connection == null) { return null; } ReadOnlyCollection<CifsClientPerTreeConnect> treeconnects = GetTreeConnects(connection.ConnectionId); foreach (CifsClientPerTreeConnect treeconnect in treeconnects) { if (treeconnect.TreeId == tid) { return new SmbClientTreeConnect(GetSession((ushort)treeconnect.SessionId), treeconnect); } } return null; }
private bool SmbUpdateContextWithResponsePacket(SmbClientConnection connection, SmbPacket response) { if (response == null) { return false; } int connectionId = connection.ConnectionId; SmbHeader smbHeader = response.SmbHeader; // only process the response packet. if (response.PacketType != SmbPacketType.BatchedResponse && response.PacketType != SmbPacketType.SingleResponse) { return false; } // packet status SmbStatus packetStatus = (SmbStatus)smbHeader.Status; // filter error packet if (packetStatus != SmbStatus.STATUS_SUCCESS && packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED && packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW) { return false; } // process each special command switch (smbHeader.Command) { #region Negotiate Response case SmbCommand.SMB_COM_NEGOTIATE: // implicit ntlm, decode using cifs sdk. if (!smbClient.Capability.IsSupportsExtendedSecurity) { return false; } // down cast to negotiate response packet. SmbNegotiateResponsePacket negotiate = response as SmbNegotiateResponsePacket; // set negotiate flag connection.NegotiateSent = true; #region update security mode SecurityModes securityModes = negotiate.SmbParameters.SecurityMode; if (SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED == (securityModes & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) { connection.ServerSigningState = SignState.ENABLED; } else if (SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED == (securityModes & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) { connection.ServerSigningState = SignState.REQUIRED; } else { connection.ServerSigningState = SignState.DISABLED; } if (SecurityModes.NEGOTIATE_USER_SECURITY == (securityModes & SecurityModes.NEGOTIATE_USER_SECURITY)) { connection.UsesSharePasswords = false; } else { connection.UsesSharePasswords = true; } if (SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS == (securityModes & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS)) { connection.IsClientEncryptPasswords = true; } else { connection.IsClientEncryptPasswords = false; } // update IsSignActive using the combination of the client's // MessageSigningPolicy and the connection's ServerSigningState smbClient.Context.UpdateSigningActive(connection); #endregion #region update server capabilities connection.ServerCapabilities = (Capabilities)negotiate.SmbParameters.Capabilities; if (Capabilities.CAP_INFOLEVEL_PASSTHRU == (connection.ServerCapabilities & Capabilities.CAP_INFOLEVEL_PASSTHRU)) { smbClient.Capability.IsUsePassThrough = true; } #endregion #region update maxbuffersize connection.MaxBufferSize = negotiate.SmbParameters.MaxBufferSize; #endregion this.AddOrUpdateConnection(connection); break; #endregion #region Session Setup Response case SmbCommand.SMB_COM_SESSION_SETUP_ANDX: // implicit ntlm, decode using cifs sdk. if (!smbClient.Capability.IsSupportsExtendedSecurity) { return false; } // the session to operation on. SmbClientSession session = null; // down-case the packet SmbSessionSetupAndxResponsePacket packet = response as SmbSessionSetupAndxResponsePacket; // if session exists, use it. if (this.GetSession(connectionId, smbHeader.Uid) != null) { session = new SmbClientSession(this.GetSession(connectionId, smbHeader.Uid)); } else { session = new SmbClientSession(); } // if success, update context and session key. if (packetStatus == SmbStatus.STATUS_SUCCESS) { // if spng, the SessionKey is null and the SecurityBlob from server contains data // in this situation, need to initialize the SecurityBlob of server to generate the SessionKey if (connection.GssApi.SessionKey == null && packet.SecurityBlob != null && packet.SecurityBlob.Length > 0) { connection.GssApi.Initialize(packet.SecurityBlob); } // get session key and store in the context session.SessionKey = connection.GssApi.SessionKey; // reset the gss api of connection connection.GssApi = null; // reset the securityblob when success packet.SecurityBlob = null; } // update the security blob from server connection.SecurityBlob = packet.SecurityBlob; this.AddOrUpdateConnection(connection); // update session session.SessionUid = smbHeader.Uid; session.ConnectionId = connectionId; this.AddOrUpdateSession(session); break; #endregion default: return false; } return true; }
/// <summary> /// to set up Netbios session with server, and add the connection into context. /// </summary> /// <param name="server">the server NetBios Name.</param> /// <param name="client">the local NetBios Name.</param> /// <param name="bufferSize">the size of buffer used for receiving data.</param> /// <param name="maxSessions">the max sessions supported by the transport.</param> /// <param name="maxNames"> /// the max Netbios names used to initialize the NCB. It is only used in NetBios transport. /// </param> /// <returns>the Identity of the connection. if connected, is the session number /// of the Netbios session; otherwise -1.</returns> /// <exception cref="System.ArgumentNullException">the server and client must not be null.</exception> public virtual void Connect(string server, string client, int bufferSize, int maxSessions, int maxNames) { if (server == null) { throw new ArgumentNullException("server"); } if (client == null) { throw new ArgumentNullException("client"); } NetbiosTransportConfig transportConfig = new NetbiosTransportConfig(); transportConfig.Type = StackTransportType.Netbios; transportConfig.Role = Role.Client; transportConfig.BufferSize = bufferSize; transportConfig.MaxSessions = maxSessions; transportConfig.MaxNames = maxNames; transportConfig.RemoteNetbiosName = server; transportConfig.LocalNetbiosName = client + new Random().Next(); this.transport = new TransportStack(transportConfig, new SmbClientDecodePacket(this).DecodePacket); int connectionId = (int)this.transport.Connect(); this.ConnectionId = connectionId; SmbClientConnection connection = new SmbClientConnection(); connection.ConnectionId = connectionId; connection.ConnectionState = StackTransportState.ConnectionEstablished; connection.ServerNetbiosName = server; connection.ClientNetbiosName = client; this.Context.AddOrUpdateConnection(connection); // set the transport type this.capability.TransportType = TransportType.NetBIOS; }
private bool SmbUpdateContextWithResponsePacket(SmbClientConnection connection, SmbPacket response) { if (response == null) { return false; } int connectionId = connection.ConnectionId; SmbHeader smbHeader = response.SmbHeader; // only process the response packet. if (response.PacketType != SmbPacketType.BatchedResponse && response.PacketType != SmbPacketType.SingleResponse) { return false; } // packet status SmbStatus packetStatus = (SmbStatus)smbHeader.Status; // filter error packet if (packetStatus != SmbStatus.STATUS_SUCCESS && packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED && packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW) { return false; } // process each special command switch (smbHeader.Command) { #region Negotiate Response case SmbCommand.SMB_COM_NEGOTIATE: // implicit ntlm, decode using cifs sdk. if (!smbClient.Capability.IsSupportsExtendedSecurity) { return false; } // down cast to negotiate response packet. SmbNegotiateResponsePacket negotiate = response as SmbNegotiateResponsePacket; // set negotiate flag connection.NegotiateSent = true; #region update security mode SecurityModes securityModes = negotiate.SmbParameters.SecurityMode; if (SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED == (securityModes & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) { connection.ServerSigningState = SignState.ENABLED; } else if (SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED == (securityModes & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) { connection.ServerSigningState = SignState.REQUIRED; } else { connection.ServerSigningState = SignState.DISABLED; } if (SecurityModes.NEGOTIATE_USER_SECURITY == (securityModes & SecurityModes.NEGOTIATE_USER_SECURITY)) { connection.UsesSharePasswords = false; } else { connection.UsesSharePasswords = true; } if (SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS == (securityModes & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS)) { connection.IsClientEncryptPasswords = true; } else { connection.IsClientEncryptPasswords = false; } // update IsSignActive using the combination of the client's // MessageSigningPolicy and the connection's ServerSigningState smbClient.Context.UpdateSigningActive(connection); #endregion #region update server capabilities connection.ServerCapabilities = (Capabilities)negotiate.SmbParameters.Capabilities; if (Capabilities.CAP_INFOLEVEL_PASSTHRU == (connection.ServerCapabilities & Capabilities.CAP_INFOLEVEL_PASSTHRU)) { smbClient.Capability.IsUsePathThrough = true; } #endregion #region update maxbuffersize connection.MaxBufferSize = negotiate.SmbParameters.MaxBufferSize; #endregion this.AddOrUpdateConnection(connection); break; #endregion #region Session Setup Response case SmbCommand.SMB_COM_SESSION_SETUP_ANDX: // implicit ntlm, decode using cifs sdk. if (!smbClient.Capability.IsSupportsExtendedSecurity) { return false; } // the session to operation on. SmbClientSession session = null; // down-case the packet SmbSessionSetupAndxResponsePacket packet = response as SmbSessionSetupAndxResponsePacket; // if session exists, use it. if (this.GetSession(connectionId, smbHeader.Uid) != null) { session = new SmbClientSession(this.GetSession(connectionId, smbHeader.Uid)); } else { session = new SmbClientSession(); } // if success, update context and session key. if (packetStatus == SmbStatus.STATUS_SUCCESS) { // if spng, the SessionKey is null and the SecurityBlob from server contains data // in this situation, need to initialize the SecurityBlob of server to generate the SessionKey if (connection.GssApi.SessionKey == null && packet.SecurityBlob != null && packet.SecurityBlob.Length > 0) { connection.GssApi.Initialize(packet.SecurityBlob); } // get session key and store in the context session.SessionKey = connection.GssApi.SessionKey; // reset the gss api of connection connection.GssApi = null; // reset the securityblob when success packet.SecurityBlob = null; } // update the security blob from server connection.SecurityBlob = packet.SecurityBlob; this.AddOrUpdateConnection(connection); // update session session.SessionUid = smbHeader.Uid; session.ConnectionId = connectionId; this.AddOrUpdateSession(session); break; #endregion default: return false; } return true; }
/// <summary> /// merge the server sign state when client is required. /// </summary> /// <param name = "connection">the target connection to update </param> private void MergeClientRequiredState(SmbClientConnection connection) { switch (connection.ServerSigningState) { case SignState.REQUIRED: case SignState.ENABLED: case SignState.DISABLED_UNLESS_REQUIRED: connection.IsSigningActive = true; break; case SignState.DISABLED: break; default: break; } }
/// <summary> /// Deep copy constructor. if need to copy the connection instance, you must call the Clone method. its sub /// class inherit from this, and need to provide more features. /// </summary> protected SmbClientSession(SmbClientSession session) : base(session) { this.connection = session.connection; this.sessionKeyState = session.sessionKeyState; }
/// <summary> /// to set up the tcp connection, and add the connection into context. Exception will be thrown if failed to /// set up connection with server. /// </summary> /// <param name = "serverName">the server name or server ip address to connect to </param> /// <param name = "serverPort">the port of server to connect to </param> /// <param name = "ipVersion">the ipversion to connect to server </param> /// <param name = "bufferSize">the buffer size of transport </param> /// <exception cref="InvalidOperationException"> /// Failed to get the IP address of SMB server in SmbClient(). /// </exception> public virtual void Connect(string serverName, int serverPort, IpVersion ipVersion, int bufferSize) { // initialize the config for transport SocketTransportConfig config = new SocketTransportConfig(); config.Role = Role.Client; config.Type = StackTransportType.Tcp; config.BufferSize = bufferSize; // init remote address of config #region Lookup the ip address from server name. IPHostEntry ipHostEntry = Dns.GetHostEntry(serverName); if (ipHostEntry != null) { foreach (IPAddress address in ipHostEntry.AddressList) { if (ipVersion != IpVersion.Ipv4 && address.AddressFamily == AddressFamily.InterNetworkV6) { config.LocalIpAddress = IPAddress.IPv6Any; config.RemoteIpAddress = address; break; } else if (ipVersion != IpVersion.Ipv6 && address.AddressFamily == AddressFamily.InterNetwork) { config.LocalIpAddress = IPAddress.Any; config.RemoteIpAddress = address; break; } else { continue; } } } if (config.RemoteIpAddress == null) { throw new InvalidOperationException("Failed to get the IP address of SMB server in SmbClient()."); } #endregion // init remote port config.RemoteIpPort = serverPort; // init local address of config config.LocalIpAddress = IPAddress.Any; config.LocalIpPort = 0; // init transport this.transport = new TransportStack(config, new SmbClientDecodePacket(this).DecodePacket); // connect to server. object endPointIdentity = this.transport.Connect(); // initialize the connection SmbClientConnection connection = new SmbClientConnection(); connection.ConnectionId = this.Context.GetConnectionID(endPointIdentity as IPEndPoint); connection.ConnectionState = StackTransportState.ConnectionEstablished; connection.MaxBufferSize = (uint)bufferSize; // update the context this.cifsClient.Context.AddOrUpdateConnection(connection); // update the connection id, to identity the connection instance. this.ConnectionId = connection.ConnectionId; // set the transport type this.capability.TransportType = TransportType.TCP; }