/// <summary> /// Authenticates a socket before accepting into /// a permanent connection (it's connection attempt /// may yet be rejected.) /// </summary> /// <param name="socketObj">The object to cast into a socket to query.</param> public void Authenticate(Object socketObj) { Socket s = (Socket)socketObj; int rconConId = this.NextRconID; //Don't bother sending CreateRootUser this ID. The socket if ( rconConId == -1 ) return; //doesn't exist for long enough for us to care. But it's important that it's there. if ( rconUsers == null ) { CreateRootUser( s ); return; } StringBuilder sb = new StringBuilder(); sb.AppendFormat( "<{0}.{1}@{2}>", System.Diagnostics.Process.GetCurrentProcess().Id, DateTime.Now.ToString( "ddmmyyhhmmss" ), System.Environment.UserDomainName ); string authmsg = "authenticate " + sb.ToString(); int offset = 0; SocketError errorCode; do { try { offset += s.Send( IRCProtocol.Ascii.GetBytes( authmsg ), offset, authmsg.Length - offset, SocketFlags.None, out errorCode ); } catch ( SocketException ) { s.Close(); return; //Give up. They can reconnect. } } while ( offset < authmsg.Length ); if ( errorCode != SocketError.Success ) { s.Close(); return; } //Get Auth response. byte[] recvBuf = new byte[rconfig.SocketBufferSize]; offset = s.Receive( recvBuf, 0, rconfig.SocketBufferSize, SocketFlags.None, out errorCode ); if ( offset == 0 || errorCode != SocketError.Success ) { s.Close(); return; } string authReply = IRCProtocol.Ascii.GetString( recvBuf, 0, offset ); //Parse into name/hash and verify both for correctness. string[] unameAndHash = authReply.Split( ' ' ); if ( unameAndHash.Length != 2 ) { s.Close(); return; } //Verify username. string username = unameAndHash[0]; Nullable<RconUserFile.RconUser> rc = rconUsers.GetUser(username); if ( rc == null ) { s.Close(); return; } //Verify their hash. string theirHash = unameAndHash[1]; string pass = rc.Value.Password; HMACMD5 hmac = new HMACMD5( IRCProtocol.Ascii.GetBytes( pass ) ); hmac.Initialize(); hmac.TransformFinalBlock( IRCProtocol.Ascii.GetBytes( sb.ToString() ), 0, theirHash.Length ); string ourHash = RconUserFile.GetHashFromDigest( hmac.Hash ); if ( !ourHash.Equals( theirHash ) ) { s.Close(); return; } authmsg = "success"; offset = 0; do { try { offset += s.Send( IRCProtocol.Ascii.GetBytes( authmsg ), offset, authmsg.Length - offset, SocketFlags.None, out errorCode ); } catch ( SocketException ) { s.Close(); return; //Give up. They can reconnect. } } while ( offset < authmsg.Length ); if ( errorCode != SocketError.Success ) { s.Close(); return; } //DO IT MAD AMOUNTS OF ARRAY LOOKUPS FOR NO REASON. L2TEMP VARIABLE PLZ rconConnections[rconConId] = new SocketPipe( s, rconConId, 30000, 5000, 0 ); rconConnections[rconConId].OnReceive += new SocketPipe.ReceiveData( OnReceive ); rconConnections[rconConId].OnDisconnect += new SocketPipe.NoParams( OnDisconnect ); Thread t = new Thread( new ThreadStart( rconConnections[rconConId].ConstantPump ) ); t.Start(); //Start sending anything we can :D rconConnections[rconConId].ConstantSiphon(); //Consume current thread generated by ConstantAccept. }
/// <summary> /// Creates a server from a ServerConfig with a parameter /// to provide an interface for logging. /// </summary> /// <param name="config">The configuration to build the Server from.</param> /// <param name="logFunction">The function to call to log text for the application.</param> public Server(Configuration.ServerConfig config, Project2QService.WriteLogFunction logFunction) { //Instantiate and load databases uc = new UserCollection(); cc = new ChannelCollection(); uc.LoadRegisteredUsers( "userdb\\" + config.Name + ".udb" ); //Rip up this little guy to help us out :D currentHost = new IRCHost(); currentIP = null; this.authmode = !File.Exists( "userdb\\" + config.Name + ".udb" ); this.writeLogFunction = logFunction; //Assign a Server ID this.serverId = Server.NextServerId; if ( this.serverId == -1 ) throw new OverflowException( "Too many servers created." ); servers[serverId] = this; //Save the configuration. this.config = config; //Tie default static handlers together for this instance of IRCEvents. irce = new IRCEvents(); //Initialize the socket pipe before the modules. Modules are scary. state = State.Disconnected; socketPipe = new SocketPipe( this.serverId, config.RetryTimeout, config.OperationTimeout, config.SendInhibit, config.SocketBufferSize ); //Default values for now, get them from config later plz. socketPipe.OnDisconnect += new SocketPipe.NoParams( this.OnDisconnect ); socketPipe.OnReceive += new SocketPipe.ReceiveData( this.OnReceive ); }